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的场景为例,配置思路是:
- 在Kconfig中选中目标芯片族,如
BCM_TRIDENT3,关闭其他芯片族以减少编译时间和镜像体积。 - 关闭不需要的特性模块,如
BCM_VXLAN、BCM_FCOE。 - 保留
BCM_KNET和BCM_USER,确保内核转发与用户态控制通路可用。 - 在
systems/linux/下选择与单板匹配的参考配置,覆盖默认值。
裁剪后应通过make的编译输出确认:目标.ko和用户态库libbcm.so均生成,且nm -D libbcm.so | grep bcm_l3能查到L3相关符号。若符号缺失,说明对应模块被误裁剪。
五、常见配置陷阱与判断依据
裁剪过程中最容易出问题的是“依赖未满足”。例如关闭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和环境变量串联,任何一处不一致都会在编译或加载阶段暴露。掌握这套关系,后续的驱动移植和功能调试才有稳定的起点。