defconfig和.config的关系

编译Linux内核,通常会用到make menuconfig, make xx_defconfig等命令,他们之间的关系到底是怎么样的呢?

Linux内核为了兼容适配不同的平台,在内核源码中使用了大量的宏定义,类似这种:

#ifdef CONFIG_ARM
    void arm_init(void);
#else
    void x86_init(void);
#endif

其中的 CONFIG_ARM 宏,是可以通过交互菜单配置的,当我们在内核源码目录下敲击:make menuconfig命令,会弹出菜单,供我们配置选择。背后的机制是make 通过mconf工具解析分布在内核源码各个目录下的kconfig文件,生成配置菜单。用户可以通过配置,选择某些模块直接编译进内核,或者编译成一个单独的KO模块,或者选择不编译进内核。

配置的结果会保存在内核源码顶层目录的 .config文件中:

CONFIG_ARM=y
CONFIG_USB=m
CONFIG_KEY=y

在编译内核时,编译工具会根据这个.config文件来编译内核。具体的流程是这样的:编译工具调用syncconfig的目标规则,将.config作为输入文件,生成两个重要的文件:

include/config/auto.conf
include/generared/autoconf.h

其中  在 auto.conf 文件中,存放的是配置信息:

CONFIG_ARM=y
CONFIG_USB=m
CONFIG_KEY=y

在内核源码的顶层 Makefile 中会包含 auto.conf 文件,以此引用其中的变量来控制 Makefile的动作,如哪些驱动编译,哪些驱动不编译。比如内核源码下 drivers/usb/Makefile里:

obj-$(CONFIG _USB) += usb.o

make会根据CONFIG_USB变量的值,来选择是将usb.o直接编译进内核,还是单独编译成一个KO模块,还是不编译。

另一个文件:include/generared/autoconf.h,是将内核配置结果转换成C语言宏定义:

#define CONFIG_ARM 1

这些宏定义用于源码内的条件编译,当内核中有类似下面的代码时:

#ifdef CONFIG_ARM
    void arm_init(void);
#else
    void x86_init(void);
#endif

就会根据include/generared/autoconf.h头文件中用户的配置结果,选择编译其中的一个条件分支。

小结:当我们编译内核时,是根据Linux内核源码顶层目录下的.config来编译内核的。当我们使用make menuconfig配置内核时,配置结果会保存在.config文件中。

如果每次编译内核前都需要重新配置,是比较麻烦的。因此,我们可以将针对某个开发板的.config配置结果保存下来。存储到xxx_defconfig文件中。xxx_defconfig配置文件一般存储在内核源码的arch/(ARCH)/configs 目录下,这里保存了针对不同架构、不同开发板的内核编译配置文件。当你想编译针对某个开发板的内核镜像时,直接使用 make xxx_defconfig命令即可完成配置。make xxx_defconfig命令会将 xxx_defconfig里的配置选项加载到内核源码顶层目录下的.config文件中,然后make编译工具利用.config里的配置结果去编译内核。

当然,如果你使用make menuconfig重新修改了内核编译配置,也可以将这个修改保存到xxx_defconfig文件中。保存的时候需要注意,要按照下面这个步骤保存:

1. 如果要修改在arch/arm/configs下的文件xxx_defconfig
2. make ARCH=arm xxx_defconfig   会生成.config文件
3. make ARCH=arm menuconfig      修改配置后保存
4. make ARCH=arm savedefconfig   在内核源码的顶层目录生成defconfg文件
5. cp defconfig arch/arm/configs/xxx_defconfig  保存到对应的目录下

或者按照下面的步骤保存,两者是一样的。

1. 如果要修改在arch/arm/configs下的文件xxx_defconfig
2. make ARCH=arm xxx_defconfig   会生成.config文件
3. make ARCH=arm menuconfig      修改后的配置保存在.config文件中
4. 在配置菜单选项中,选择save选项,会弹出一个保存路径,输入对应的保存路径即可


只有按照这个步骤,生成的xxx_defconfig文件,才会最小化,兼容性更好,更容易恢复成.config。为什么呢?
原因是我们生成的xxx_defconfig配置文件,和.config文件的配置数据不是完全一样的。xxx_defconfig文件里保存的是用户配置的结果,对于一些用户没有选择配置,内核默认的一些结果,是没有保存到xxx_defconfig文件中的。
当我们使用make xxx_defconfig文件去配置内核时,编译器会根据xxx_defconfig里的配置选项去配置内核。如果有一些选项在xxx_defconfig里没有指定,编译工具会根据Kconfig菜单里的设置的默认选项,将其配置成默认配置结果,并保存到.config文件中。所以我们可以看到:xxx_defconfig文件和.config文件并不是等同的。

驱动开发核心理论,Linux内核开发入门实战视频教程:《Linux内核编程》,具有一线芯片原厂开发经验的驱动工程师录制,详情点击:王利涛老师个人淘宝店:Linux内核编程