3. SDK源码树与构建系统

Broadcom交换芯片SDK(以OpenMDK/BCM SDK为代表)的源码树不是一堆平铺的C文件,而是一套“内核态驱动 + 用户态API + 平台适配 + 构建配置”四层耦合的工程体系。理解它的目录结构,本质上是在理解“哪些代码与芯片相关、哪些与操作系统相关、哪些与具体单板相关”。只有把这三类边界分清,后续的裁剪、移植和交叉编译才不会互相污染。

一、源码树的分层结构

典型SDK根目录下会看到如下关键目录(不同版本命名略有差异,但职责稳定):

  • sdk/:芯片无关的SDK核心,包含sal(系统抽象层)、shr(共享层)、bcm(芯片驱动核心)、diag(诊断shell)等子目录。这一层是移植时改动最少的部分。
  • systems/:平台与单板适配层,按linux/、unix/、vxworks/等操作系统划分,其下再按具体单板或参考设计(如systems/linux/kernel/modules/bcm-knet)组织。交叉编译工具链、内核头文件路径、板级初始化都在这里落地。
  • make/:构建规则与工具链定义,包含Makefile.linux、Makefile.vxworks等,是“目标平台”与“编译参数”的集中入口。
  • tools/:主机侧工具,如配置生成器、镜像打包脚本、寄存器转换工具。
  • examples/:用户态示例程序,用于验证API调用链是否打通。

需要特别注意的是,sdk/与systems/之间通过sal层解耦:sdk/只调用sal_*接口,而systems/提供这些接口的具体实现。这意味着当你更换CPU架构或操作系统时,理论上只需替换systems/下的适配代码,而不必触碰sdk/。

二、Makefile、Kconfig与CMake的分工

Broadcom SDK传统上以GNU Make + Kconfig为主,部分新版本或厂商封装层会引入CMake作为外层包装。三者的职责边界如下:

机制作用范围典型文件
Kconfig配置选项定义与依赖关系sdk/Kconfig、systems/linux/Kconfig
Makefile编译规则、目标生成、工具链调用make/Makefile.linux、sdk/Makefile
CMake外层工程集成、IDE支持、第三方库查找CMakeLists.txt(厂商封装层)

Kconfig负责“选什么”,Makefile负责“怎么编”,CMake负责“怎么被更大的工程引用”。实际工程中,最常见的做法是用make menuconfig生成.config,再由Makefile读取该文件决定编译哪些模块。例如,关闭BCM_KNET后,内核态网络驱动模块不会被编译,用户态仍可通过bcm_user接口访问芯片,但失去内核转发路径。

三、交叉编译工具链配置

交叉编译的核心是让Makefile知道“用哪套编译器、针对哪个内核、头文件在哪里”。SDK通常通过环境变量或make命令行参数传入,而不是硬编码在Makefile里。典型配置如下:

export CROSS_COMPILE=aarch64-linux-gnu-
export KERNELDIR=/home/dev/linux-5.10.110
export ARCH=arm64
make -C systems/linux/kernel/modules/bcm-knet \
     M=$PWD/systems/linux/kernel/modules/bcm-knet \
     KERNELDIR=$KERNELDIR \
     CROSS_COMPILE=$CROSS_COMPILE

这里KERNELDIR必须指向已配置并编译过的内核源码树,否则内核模块的Module.symvers缺失,会导致符号版本校验失败。常见错误是只解压内核源码而未执行make modules_prepare,表现为modpost: missing MODULE_LICENSE或未定义符号。判断依据是:编译日志中应出现CC [M] .../bcm-knet.o且最终生成.ko文件,用modinfo bcm-knet.ko可看到vermagic与目标内核版本一致。

四、目标平台与配置裁剪

裁剪的目标是“只保留目标芯片和所需功能”。以支持Trident系列芯片、仅需L3转发、不需要VXLAN的场景为例,配置思路是:

  1. 在Kconfig中选中目标芯片族,如BCM_TRIDENT3,关闭其他芯片族以减少编译时间和镜像体积。
  2. 关闭不需要的特性模块,如BCM_VXLAN、BCM_FCOE。
  3. 保留BCM_KNET和BCM_USER,确保内核转发与用户态控制通路可用。
  4. 在systems/linux/下选择与单板匹配的参考配置,覆盖默认值。

裁剪后应通过make的编译输出确认:目标.ko和用户态库libbcm.so均生成,且nm -D libbcm.so | grep bcm_l3能查到L3相关符号。若符号缺失,说明对应模块被误裁剪。

Broadcom SDK 源码树与构建配置关系 sdk/ sal / shr / bcm / diag systems/ linux / unix / vxworks make/ Makefile.linux / .vxworks tools/ + examples/ 配置生成 / API示例 sal接口 Kconfig 选芯片/特性 生成 .config Makefile 读 .config 调交叉工具链 CMake 外层工程集成 第三方库查找 .config 交叉编译工具链 CROSS_COMPILE KERNELDIR / ARCH 编译产物 bcm-knet.ko libbcm.so 裁剪验证 nm -D 查符号 modinfo 查vermagic 调用 配置裁剪原则:只保留目标芯片族 + 所需特性模块;关闭无关模块可缩短编译时间并减小镜像体积。 验证依据:目标 .ko 与 libbcm.so 均生成,且关键API符号(如 bcm_l3_*)可通过 nm -D 查到。

五、常见配置陷阱与判断依据

裁剪过程中最容易出问题的是“依赖未满足”。例如关闭BCM_KNET后,某些依赖内核转发路径的L3示例程序会编译失败,报错指向bcm_knet_*符号未定义。此时应检查.config中CONFIG_BCM_KNET是否被其他选项select,而不是简单地在Makefile里注释掉源文件。另一个常见问题是CROSS_COMPILE前缀与内核编译时使用的不一致,导致vermagic中的编译器版本字符串不匹配,模块加载时报invalid module format。判断方法是modinfo输出的vermagic与uname -r及内核编译日志中的编译器版本逐项比对。

实用建议:在systems/linux/下为每个目标单板维护一份独立的defconfig,用make savedefconfig生成最小配置,避免手工编辑.config引入不可复现的差异。每次裁剪后先执行make clean再全量编译,防止旧对象文件掩盖依赖缺失问题。

总结来看,SDK构建系统的核心逻辑是:Kconfig决定“编什么”,Makefile决定“怎么编”,交叉编译工具链决定“为谁编”,而systems/层决定“在哪块板子上跑”。四者通过.config和环境变量串联,任何一处不一致都会在编译或加载阶段暴露。掌握这套关系,后续的驱动移植和功能调试才有稳定的起点。