在 U-Boot 中,通过 #include <common.h>
间接包含 autoconf.h
的实现机制涉及多个层级配置文件的协作和预处理过程。
(1) common.h
的枢纽作用
-
common.h
的位置:位于include/common.h
,是 U-Boot 的通用头文件,几乎被所有源码文件包含。 -
关键包含语句:
#include <config.h> // 引入板级配置头文件
(2) config.h
的动态生成
-
生成过程:
config.h
由编译系统自动生成,位于include/config.h
。其内容包含:/* Automatically generated - do not edit */ #include <configs/<CONFIG_SYS_CONFIG_NAME>.h> // 板级配置头文件
运行
其中
<CONFIG_SYS_CONFIG_NAME>
由.config
中的CONFIG_SYS_CONFIG_NAME
定义(如imx8mm_evk
)。
(3) 板级配置头文件的桥接
-
configs/<board>.h
的作用:
该文件(如configs/imx8mm_evk.h
)包含对autoconf.h
的显式或隐式引用:#include <asm/arch/imx-regs.h> // 间接包含 autoconf.h
运行
某些架构的代码会通过层级包含最终引入
include/generated/autoconf.h
。
2. autoconf.h
的生成与传播
(1) 生成过程
-
来源:
autoconf.h
由 Kconfig 系统生成,位于include/generated/autoconf.h
。其内容为所有CONFIG_*
宏的 C 语言定义:#define CONFIG_SPL_BUILD 1 #define CONFIG_ARM 1
这些宏源自
.config
文件。
(2) 预处理器级联展开
- 编译预处理:
当编译器处理common.h
时,会递归展开所有包含的头文件。例如:common.h
→config.h
→configs/imx8mm_evk.h
→asm/arch/imx-regs.h
→ ... →generated/autoconf.h
。- 此过程使得
autoconf.h
中的宏被间接注入到所有源码中。
(3) 编译参数传递
-
动态宏的注入:
某些宏(如CONFIG_SPL_BUILD
)可能未被写入autoconf.h
,而是通过编译器的-D
参数动态传递:CFLAGS += -DCONFIG_SPL_BUILD
这些宏会在预处理阶段被添加到代码中。
3. 配置系统的代码生成支持
(1) autoconf.mk
的生成
-
生成逻辑:
编译系统通过以下步骤生成include/autoconf.mk
:- 调用预处理器解析
common.h
,提取所有宏定义(包括autoconf.h
中的内容)。 - 使用
tools/scripts/define2mk.sed
脚本将宏转换为 Makefile 格式。 - 结果写入
autoconf.mk
,供 Makefile 使用。
- 调用预处理器解析
-
关键命令:
cpp -dM include/common.h | sed -n -f tools/scripts/define2mk.sed > autoconf.mk
运行
其中
cpp -dM
会递归处理所有包含的头文件,包括autoconf.h
。
(2) 编译时宏生效
-
Makefile 包含
autoconf.mk
:
顶层 Makefile 显式包含autoconf.mk
,使其中的宏(如CONFIG_SPL=y
)影响编译条件:include include/autoconf.mk
这使得代码中的条件编译(如
#ifdef CONFIG_SPL
)能够正确响应配置。