探索Linux内核:Kconfig的秘密

2019-01-16 21:08:55王振洲

源根vmlinux被剥离、压缩、放入piggy.S,然后将其他对等对象链接到arch/x86/boot/compressed/vmlinux。同时,下面生成一个名为setup.bin的文件arch/x86/boot。可能有一个包含重定位信息的可选的第三个文件,具体取决于config_x86_RELOCS.

一个名为build由内核提供,将这两个(或三个)部分构建到最终的bzImage文件中。

依赖跟踪

KBuild跟踪三种依赖关系:

    所有的前提文件(*.c和*.h) CONFIG_在所有先决条件文件中使用的选项 用于编译目标的命令行依赖关系。

    第一个很容易理解,但是第二个和第三个呢?内核开发人员经常看到这样的代码片段:

    #ifdef CONFIG_SMP __boot_cpu_id = cpu; #endif

    什么时候CONFIG_SMP更改后,这段代码应该重新编译。编译源文件的命令行也很重要,因为不同的命令行可能导致不同的对象文件。

    当.C文件通过#include指令,您需要编写这样的规则:

    main.o: defs.h recipe...

    在管理一个大型项目时,您需要很多这样的规则;所有这些规则都会乏味。幸运的是,大多数现代C编译器可以通过查看#include源文件中的行。对于GNU编译器集合(GCC),只需添加一个命令行参数:-MD depfile

    # In scripts/Makefile.lib c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) -include $(srctree)/include/linux/compiler_types.h $(__c_flags) $(modkern_cflags) $(basename_flags) $(modname_flags)

    这将生成一个.D文件的内容如下:

    init_task.o: init/init_task.c include/linux/kconfig.h include/generated/autoconf.h include/linux/init_task.h include/linux/rcupdate.h include/linux/types.h ...

    然后主机程序fixdep通过获取其他两个依赖项来处理其他两个依赖项。depfile命令行作为输入,然后以makefile语法输出.cmd文件,它记录目标的命令行和所有先决条件(包括配置)。看起来是这样的:

    # The command line used to compile the target cmd_init/init_task.o := gcc -Wp,-MD,init/.init_task.o.d -nostdinc ... ... # The dependency files deps_init/init_task.o := $(wildcard include/config/posix/timers.h) $(wildcard include/config/arch/task/struct/on/stack.h) $(wildcard include/config/thread/info/in/task.h) ... include/uapi/linux/types.h arch/x86/include/uapi/asm/types.h include/uapi/asm-generic/types.h ...

    在递归生成过程中将包含一个.cmd文件,提供所有依赖项信息,并帮助决定是否重新构建目标。

    这背后的秘密是,Fixdep将解析depfile(.d文件),然后解析其中的所有依赖文件,搜索所有config_string的文本,将它们转换为相应的空头文件,并将它们添加到目标的先决条件中。每次配置更改时,相应的空头文件也将被更新,因此kbuild可以检测到该更改并重新构建依赖于它的目标。因为还记录了命令行,所以很容易比较最后的编译参数和当前的编译参数。