配置与编译内核用到的工具很多,在这里只对几个关键工具进行介绍,更多的内容请参考相关手册。
Make
Make是一种帮助大型软件工程的编译工作实现自动化的编程语言。正确地使用 Make可以大大减少因编译程序而花费的时间,因为它可以消除不必要的再编译。Make的基本设计思想是如果目标文件是在最近一次对源文件的修改之后编译的,它就是“新的”,不需要重新编译;如果最近一次对源文件的修改之后没有及时更新目标文件,那么该目标文件就是“旧的”,需要重新编译。为了理解 Make如何执行一个任务,需要了解一些术语:
◆目标 需要执行的一个任务。多数情况下它就是用户要生成的文件的名字,但是它也可以仅是个任务的名字。 ◆依赖关系 两个目标之间相互依存的关系。如果修改目标B会造成目标A的修改,那么就说目标A依赖于目标B,B是A的先决条件。 ◆变量 一种存储临时信息的载体。Make中使用的变量应该加上括号,例如$(TEMP)。 ◆命令 执行任务时使用的指令,可以是一条、多条,甚至没有。 ◆规则 一条完整的规则具有以下格式:
目标(target): 先决条件(prerequisites) 规则(command) ... ...
其中只有目标必须要有,其它成分可以没有。一条完整的规则描述了编译一个目标的方法和依赖关系,是Makefile中最重要的部分。
◆Makefile文件 描述如何生成一个或多个目标的文件。它列出目标依赖的各个文件,并提供正确编译这些目标所需要的规则。
接下来以2.4.23的kbuild为例,简要介绍一下内核的构建过程。首先,完整的内核构建过程由以下五种Makefile封装。
1.根目录Makefile
它是最重要的Makefile,定义所有与体系结构无关的变量和目标。它读取.config文件,并根据其信息最终生成vmlinux和modules。Make通过向下递归调用子目录中的Makefile来编译这两个目标。
2.配置文件.config
执行“make ”会在根目录下生成该配置文件,其内容记录了具体的配置选择,也可以将旧内核的配置文件放在这里。
3.arch/*/Makefile
这是与特定体系结构相关的Makefile。它包含在根目录下的Makefile中,为kbuild提供体系结构的特定信息。
4.子目录Makefiles
它们存在于每个子目录下,大约有几百个。它们接受来自上层Make传递下来的信息,并根据这些信息来构造一个需要编译的文件列表,并交由Rules.make处理。
5.Rules.make
几乎每个子目录Makefile都包含该Makefile。根据子目录Makefiles构建的文件列表,Make使用Rules.make定义的通用规则来编译所有来自列表的源文件。
kbuild的执行过程是:Make从根目录Makefile开始执行,从中获得与体系结构无关的变量和依赖关系,并同时从arch/*/Makefile中获得体系特定的变量等信息,这些信息扩展了根目录Makefile提供的变量。此时kbuild已经拥有构建内核需要的所有变量和目标。然后,Make进入子目录,把部分变量传递给子目录Makefile。子目录Makefile根据配置信息决定编译哪些源文件,从而构建出一个需要编译的文件列表。最后,Rules.make根据其定义的编译规则决定这些文件的编译方式。
需要注意的是,由于Make的向下递归特性和无序性,其执行过程并不完全遵守顺序逐行执行的规则,但无论Make的执行有多复杂,也只分为两个阶段。第一个阶段Make会读取所有变量和分析所有目标的依赖关系,并最终建立一棵依赖关系树。同时,所有的立即型变量(通过“:=”赋值)在这个过程中被扩展,就像C变量一样。而在这个阶段的最后,所有的延迟型变量才被扩展(通过“=”赋值)。这点需要格外注意。第二个阶段Make会根据依赖关系树执行命令。
因此,一个目标和其先决条件的规则定义的顺序是无所谓的,很可能一个目标的先决条件的规则定义在百行以后才出现。Make会耐心读完所有的Makefile后分析得出依赖关系树。
|