1. 主目录下的Makefile(不妨称为main-makefile)
它主要有两个作用:生成vmlinux(内核映像)和modules(模块)。
2. 主目录下的Rules.make
Rules.make中定义通用规则供main-makefile和subdir-makefiles调用。
变量subdir-y为用于构建vmlinux(内核)的目录,变量subdir-m为用于构建modules(模块)的目录;subdir-n和subdir-中的目录将不参加构建工作。
变量obj-y为内核的目标文件列表,在各subdir-y中会对其赋相应的值。如:lib/Makefile的第13-14行。变量obj-m为各模块的目标文件列表,在各subdir-m中会对其赋相应的值。如在drivers/Makefile中,在第13行对subdir-y赋值,并在第14行将此列表复制给subdir-m。从第17行开始对subdir-y和subdir-m进行补充,这两个列表的建立完成。obj-n和obj-中所有的目标将被忽略。
3. arch/*/目录下的Makefile(不妨称为arch-makefiles)
arch-makefiles是与特定的体系结构相关的,它们分别是针对特定CPU的makefiles。
4. 除arch外的子目录下的Makefile(不妨称为subdir-makefiles)
subdir -makefiles只负责在自己的目录中生成目标文件。它们接受来自上层Make传递下来的信息,并根据这些信息来构造一个需要编译的文件列表,并交由 Rules.make处理。subdir-makefiles都比较简短,因为通用的规则都已在Rules.make定义了。一般subdir- makefiles的主要工作是对obj-*或subdir-*变量赋值。
二、内核和模块构建的过程
下面分析内核编译的动态过程。
第一步:make ARCH=arm menuconfig
目标menuconfig的定义在main-makefile的第306行。main-makefile的第308行调用Menuconfig 工具(scripts/Menuconfig),让它根据arch/$(ARCH)/config.in文件的内容在主目录下生成.config文件供以后调用(main-makefile的第37行)。
第二步:make ARCH=arm CROSS_COMPILE=arm-linux- dep
include/linux/autoconf.h根据.config文件生成,其内容是若干#define和#undef宏。这些宏通知编译器哪些组件需要编译而哪些不需要,是编译进内核还是编译成模块。这两个文件中的变量是相互对应的。例如.config的第4行是:
CONFIG_ARM=y
这是编译进内核的情况。相应地,include/linux/autoconf.h的第5行是:
#define CONFIG_ARM 1
编译成模块的例子见.config的第216行:
CONFIG_BINFMT_AOUT=m
相应地,autoconf.h的第217和218行是:
#undef CONFIG_BINFMT_AOUT
#define CONFIG_BINFMT_AOUT_MODULE 1
接下来main-makefile调用split-include工具(scripts/split-include.c)(main-makefile的第314行),分割解析autoconf.h并在include/config目录下生成相应的头文件。autoconf.h的路径通过第一个参数传递给 split-include(scripts/split-include.c的第71行)根据刚才提到的autoconf.h的第5行的内容, split-include工具会在include/config/目录下生成arm.h文件,其内容就是一行:
#define CONFIG_ARM 1
include/linux/config.h 的第4行嵌入了autoconf.h,而内核源码中很多c文件又嵌入这个config.h(例如kernel/printk.c的第28行),于是间接地嵌入了autoconf.h,可见config.h起到的是一个桥梁的作用。
在这一步骤中,makefile会调用mkdep工具(scripts/mkdep.c)生成两种包含依赖关系的文件:.hdepend和.depend。
.hdepend只有一个,在主目录下,它表示相应的头文件又依赖于哪些其它的头文件。.hdepend是在main-makefile的第496行执行后生成的。如果存在.hdepend文件,Rules.make会嵌入它(Rules.make第295-297行)。
.depend 文件有很多,它表示相应的目标文件依赖哪些源文件(*.c)和头文件(*.h)。主目录下的.depend文件是在main-makefile的第497 行执行后生成的。mkdep读取*.c文件,分析出其所依赖的文件。下面以mm/page_alloc.c举例。page_alloc.c的第15-23 行为(“…”表示省略):
#include <linux/config.h>
#include <linux/mm.h>
…
#include <linux/module.h>
mkdep就会在mm/.depend中的第110-118行中写入:
page_alloc.o: page_alloc.c \
/usr/src/arm-linux/linux-roy/include/linux/mm.h \
…
/usr/src/arm-linux/linux-roy/include/linux/module.h \
但接下来的第119行和上面的写法有些不同:
$(wildcard /usr/src/arm-linux/linux-roy/include/config/discontigmem.h) \
这是因为page_alloc.c中的第244行的内容如下:
#ifndef CONFIG_DISCONTIGMEM
这需要判断discontigmem.h的存在性,而mm目录下的.depend文件的第119行正是起到了这样的作用(若存在则返回文件名,若不存在则返回空)
。
第三步:make ARCH=arm CROSS_COMPILE=arm-linux- clean
目标clean在main-makefile的第444-449行定义,它所清除文件的文件和目录列表(CLEAN_FILES和CLEAN_DIRS)在203-229行被赋值。
