今天开始踏入内核学习的门。
The Kernel Build System (kbuild) 包含4个主要部分:
Config symbols
条件编译选项,用来决定哪些目标编译进内核或内核模块。
Kconfig files
定义每个config symbols和它的属性,
.config files
存储每一个符号的定义。可以手动编辑该文件。也可以用其它工具生成,如menuconfig。
Makefiles
普通的GNU Makefile文件,根据编译符号实现内核编译。
配置符号用来决定哪些features将被包含到最后的内核镜像。有两种符号:布尔和三太。Boolean symbols有两种值true或者false。Tristate symbols有3种值: yes no 或者module。
不是内核的一切东西都可以编译为模块,例如SMP或者kernel preemption,因此这种情况下,使用布尔配置符号。大多数功能可以编译为模块,也可以在编译时添加到内核,因此有3种选择,built-in(y), module(m), 或者不编译。
除了上面两种,还有其它类型的配置符号,例如字符串和16进制,但是因为他们不是用来条件编译的。
配置符号定义在被叫做Kconfig的文件中,每个Kconfig文件可以描述任意数量的符号,也可以include(source)其它Kconfig文件。创建内核编译选项的配置菜单的编译目标,例如make menuconfig,读取这些文件,创建树型结构。内核中的每一个目录有一个kconfig文件(haha,not true),它还包含子目录中的kconfig文件。在内核源码的顶层有一个kconfig文件,这个文件是选项树的根。menuconfig(scripts/kconfig/mconf), gconfig(scripts/kconfig/gconf)和其它的编译目标调用程序从根kconfig开始,迭代读取所有子目录的kconfig来创建菜单。要访问哪个子目录,也是在kconfig文件中定义的,同样依赖用户选择的配置符号。
所有的配置符号值存储在一个特殊的文件,叫做.config。每个你想改变一个内核编译配置,你执行一个make目标,例如menuconfig或者xconfig,它们读取kconfig来构建菜单,并使用.config文件来更新配置符号值,当你改变一些选项后,这个些工具更新.config,如果.config之前不存在,也会产生一个。
kbuild系统的最后一个部分是Makefiles,他们用来编译内核镜像和模块,像kconfig文件一样,每个子目录有一个Makefile文件,只编译它的目录下的文件。整个编译是迭代的,top Makefile descends进它的子目录,执行每个子目录的Makefile来产生目标文件。这些目标文件用来产生模块和内核镜像。
当执行一个编译目标来编译内核或者一个模块时,首先执行一个二进制来读取所有的kconfig文件和.config
1 | $ scripts /kconfig/ conf Kconfig |
这个二进制更新或者创建一个C头文件,包含你选择的所有的配置符号,这个文件是include/generated/autoconf.h,每一个gcc编译指令都包含它,所以这些符号可以在内核的任何源码中使用。
如果布尔值CONFIG_COIN_STAT为真,3态值CONFIG_COIN为y,那么产生:
1 2 3 4 5 6 7 | #define __enabled_CONFIG_COIN_STAT 1 #define __enabled_CONFIG_COIN_STAT_MODULE 0 #define CONFIG_COIN_STAT 1 #define __enabled_CONFIG_COIN 1 #define __enabled_CONFIG_COIN_MODULE 0 #define CONFIG_COIN 1 |
如果布尔值为假,3态值为no,则产生:
1 2 3 4 5 | #define __enabled_CONFIG_COIN_STAT 0 #define __enabled_CONFIG_COIN_STAT_MODULE 0 #define __enabled_CONFIG_COIN 0 #define __enabled_CONFIG_COIN_MODULE 0 |
如果3态值为module,则产生:
1 2 3 | #define __enabled_CONFIG_COIN 0 #define __enabled_CONFIG_COIN_MODULE 1 #define CONFIG_COIN_MODULE 1 |
相关的宏有:
1 2 3 4 5 6 | #define IS_ENABLED(option) \ (__enabled_ ## option || __enabled_ ## option ## _MODULE) #define IS_BUILTIN(option) __enabled_ ## option #define IS_MODULE(option) __enabled_ ## option ## _MODULE |
内核编译系统有两个主要任务,创建内核镜像和内核模块,为此,它维护两个目标列表obj-y和obj-m。前者用来编译内核镜像,后来用来编译内核模块。
为了编译源码,在Makefile中,只需要:
1 | obj-$(CONFIG_COIN) += coin.o |
这告诉内核从源码coin.c创建目标文件,将它添加到上述列中。
参考
http://www.linuxjournal.com/content/kbuild-linux-kernel-build-system