8.1 构建系统与编译交付


8.1 构建系统与编译交付

本节摘要:构建是驱动的第一道交付工序。本节从 2.1 节的最小构建升级到体系化:配置裁剪机制让驱动可按需编入或外挂、交叉编译的完整参数链、产物清单与构建可复现性,把"能编过"升级为"编得可管"。

2.1 节那个十行的构建文件解决了"从零到能跑",但产品化的问题它没碰:一个产品线五种硬件配置,LED 驱动在低端版要不要编进去?客户要求的安全审查要构建产物可复现怎么保证?交付给客户的模块要不要带调试信息?这些问题的答案共同构成"构建体系"。

配置裁剪:一个驱动的多重形态

内核的配置系统由两部分配合:配置描述文件声明"有哪些开关、开关之间什么关系",构建规则文件声明"开关各对应哪些产物"。

配置描述(放进内核源码树相应目录):

config LEDS_BOARD tristate "评估板 LED 驱动" depends on HAS_IOMEM help 评估开发板上的 LED 驱动,提供字符设备接口与闪烁控制。 编为内建则随内核启动加载;编为模块则按需装入; 不选则完全不参与编译。 config LEDS_BOARD_DEBUG bool "评估板 LED 驱动调试日志" depends on LEDS_BOARD help 打开后会输出逐次调用的详细日志,性能有损,仅供调试。

两行关键字各有含义。tristate 是三态开关:不编、编为模块、编进内核——产品量产版通常把基础驱动编进内核(少一个交付文件),开发版用模块(改起来快)。depends on 声明依赖:没有内存映射能力的平台(某些极简虚拟环境)根本不该看到这个选项。调试开关独立成项是个值得养成的习惯:量产与调试共用一套源码,差异收敛到一个布尔开关。

构建规则随之升级:

# 内核构建器视角 obj-$(CONFIG_LEDS_BOARD) += board-led.o board-led-y := core.o sysfs.o board-led-$(CONFIG_LEDS_BOARD_DEBUG) += debug.o

obj- 变量按配置值展开(空则不编、m 则模块、y 则内建);一个驱动拆多个源文件、调试代码独立文件按需编入——配置系统直接指挥构建系统,这是内核构建体系的核心设计。

交叉编译:把参数链一次配齐

嵌入式驱动的编译永远在"另一台机器"上。交叉编译的完整参数链有五环,环环都错不得:

ARCH=arm64 # 目标架构:决定头文件与汇编约定 CROSS_COMPILE=aarch64-linux- # 工具链前缀:编译器、汇编器、链接器全家 KERNELDIR=/path/to/target-kernel # 目标内核源码树:版本必须与目标板一致 INSTALL_MOD_PATH=./out # 模块安装根:模块安装后的存放地 -j$(nproc) # 并行加速

组装成一条可复用的构建命令:

make -C "$KERNELDIR" M="$PWD" \ ARCH=arm64 CROSS_COMPILE=aarch64-linux- \ modules # 产出 board-led.ko make -C "$KERNELDIR" M="$PWD" \ ARCH=arm64 CROSS_COMPILE=aarch64-linux- \ INSTALL_MOD_PATH=./out modules_install # 产物落入 out/lib/modules/内核版本/ 目录,随包分发

五环里最常见的翻车是内核树不匹配(2.1 节的版本魔术问题)与工具链版本漂移——同一份代码今天能编过明天报错,先查工具链有没有被全局更新。工程做法是把工具链版本写进构建脚本的检查逻辑,版本不符直接拒绝构建。

产物清单:交付不只是 .ko

一个负责任的驱动交付包里,模块文件只是主角之一,配套物一样不能少:

产物 用途 缺失的后果
模块二进制 本体
模块签名(如平台要求) 安全启动链校验 目标设备拒绝装入
符号与调试信息文件 7.4 节的 oops 翻译链 现场崩溃无法定位
设备树覆盖片段 板级描述的增量交付 设备不出现,静默失败
版本与变更说明 用户与运维的知情权 升级事故与回滚无据
构建清单(哈希值) 可复现性验证 无法证明两次构建一致

其中调试信息文件要在构建时显式保留(默认发布构建常剥离它),并与模块成对归档——模块与调试信息版本错位,翻译出来的行号就是误导。

可复现构建:同一输入必得同一输出

可复现性指"相同源码、相同工具链、相同配置,产出比特级一致的二进制"。它的敌人是构建过程中混入的环境变量量:时间戳取构建时刻、路径记录了构建者的目录结构、并行顺序影响未定初始化。治理手段:构建脚本固定环境变量、路径统一用相对形式、时间戳统一取版本控制提交时刻。做到可复现的构建才能谈"安全审计"与"供应链可信"——客户拿到产物能自行验证"这确实是从那版源码编出来的"。

⚠️ 常见坑:在源码目录直接构建,产物与源码混放。正确姿势是外部构建——源码目录只读,构建在独立的输出目录进行,一份源码可以同时服务多个目标配置(内建版、模块版、调试版各一个输出目录互不污染)。

一次完整构建的会话记录

把全节要点串成一次真实会话,照着走一遍就能验证自己的构建体系:

# 一 配置确认:目标内核的配置与树是否齐备 $ ls /path/to/target-kernel/.config && echo "内核树就绪" # 二 构建:五环参数一次配齐 $ make -C /path/to/target-kernel M=$PWD \ ARCH=arm64 CROSS_COMPILE=aarch64-linux- modules CC [M] board-led.o LD [M] board-led.ko # 三 安装与归档:模块入安装根,翻译链成套入库 $ make -C /path/to/target-kernel M=$PWD ARCH=arm64 \ CROSS_COMPILE=aarch64-linux- INSTALL_MOD_PATH=./out modules_install $ cp board-led.ko board-led.debug ./out/ $ md5sum ./out/board-led.ko >> build-artifacts.md5 # 四 自检:产物与模块信息核对 $ modinfo board-led.ko | head -4 filename: board-led.ko license: GPL depends: name: board_led

四步会话里有两处容易被忽略的动作:调试信息文件与模块一起拷入交付目录(第 7.4 节翻译链的原料)、产物哈希登记(可复现性的凭证)。构建会话脚本化后,它本身就是构建文档——新人拿到脚本就能产出与你比特级一致的模块。

本节要点回顾

  • 配置指挥构建:三态开关加依赖声明,一个驱动多种形态按需产出。
  • 交叉编译五环配齐:架构、前缀、内核树、安装根、并行度。
  • 交付是清单不是文件:签名、调试信息、树片段、变更说明成套归档。
  • 可复现是审计的前提:环境固定、路径相对、时间戳取提交时刻。

构建体系立起来,驱动就有了批量生产的能力。下一节面对一个更长期的问题:内核每几个月就演进一次,驱动怎么跨版本活下去。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U