KBUILD系统原理分析KBUILD系统原理分析kbuild,即kernelbuild,用于编译Linux内核文件。kbuild对makefile进行了功能上的扩充,使其在编译内核文件时更加高效,简洁。大部分内核中的Makefile都是使用Kbuild组织结构的kbuildMakefile。下面将分两部分介绍,首先介绍Linux的命令工具make及其所操作的makefile,它负责将源代码编译成可执行文件;然后介绍kbuildmakefile对makefile做了哪些扩充,以及kbuildmakefile的工作原理。Chapter1.MAKE概述1.1准备知识一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是.obj文件,UNIX下是.o文件,即ObjectFile,这个动作叫做编译(compile)。然后再把大量的ObjectFile合成执行文件,这个动作叫作链接(link)。编译:把高级语言书写的代码转换为机器可识别的机器指令。编译高级语言后生成的指令虽然可被机器识别,但是还不能被执行。编译时,编译器检查高级语言的语法、函数与变量的声明是否正确。只有所有的语法正确、相关变量定义正确编译器就可以编译出中间目标文件。通常,一个高级语言的源文件都可对应一个目标文件。目标文件在Linux中默认后缀为“.o”(如“hello.c”的目标文件为“hello.o”)。链接:将多个.o文件,或者.o文件和库文件链接成为可被操作系统执行的可执行程序。链接器不检查函数所在的源文件,只检查所有.o文件中的定义的符号。将.o文件中使用的函数和其它.o或者库文件中的相关符号进行合并,最后生成一个可执行的程序。“ld”是GNU的链接器。静态库:又称为文档文件(ArchiveFile)。它是多个.o文件的集合。Linux中静态库文件的后缀为“.a”。静态库中的各个成员(.o文件)没有特殊的存在格式,仅仅是一个.o文件的集合。使用“ar”工具维护和管理静态库。共享库:也是多个.o文件的集合,但是这些.o文件时有编译器按照一种特殊的方式生成。对象模块的各个成员的地址(变量引用和函数调用)都是相对地址。因此在程序运行时,可动态加载库文件和执行共享的模块(多个程序可以共享使用库中的某1KBUILD系统原理分析一个模块)。1.2makefile简介make在执行时,需要一个命名为Makefile的文件。这个文件告诉make以何种方式编译源代码和链接程序,即告诉make需要做什么(完成什么任务),该怎么做。典型地,可执行文件可由一些.o文件按照一定的顺序生成或者更新。如果在你的工程中已经存在一个或者多个正确的Makefile。当对工程中的若干源文件修改以后,需要根据修改来更新可执行文件或者库文件,正如前面提到的你只需要在shell下执行“make”。make会自动根据修改情况完成源文件的对应.o文件的更新、库文件的更新、最终的可执行程序的更新。make通过比较对应文件(规则的目标和依赖,)的最后修改时间,来决定哪些文件需要更新、那些文件不需要更新。对需要更新的文件make就执行数据库中所记录的相应命令(在make读取Makefile以后会建立一个编译过程的描述数据库。此数据库中记录了所有各个文件之间的相互关系,以及它们的关系描述)来重建它,对于不需要重建的文件make什么也不做。而且可以通过make的命令行选项来指定需要重新编译的文件。在执行make之前,需要一个命名为Makefile的特殊文件(本文的后续将使用Makefile作为这个特殊文件的文件名)来告诉make需要做什么(完成什么任务),该怎么做。通常,make工具主要被用来进行工程编译和程序链接。当使用make工具进行编译时,工程中以下几种文件在执行make时将会被编译(重新编译):1.所有的源文件没有被编译过,则对各个C源文件进行编译并进行链接,生成最后的可执行程序;2.每一个在上次执行make之后修改过的C源代码文件在本次执行make时将会被重新编译;3.头文件在上一次执行make之后被修改。则所有包含此头文件的C源文件在本次执行make时将会被重新编译。后两种情况是make只将修改过的C源文件重新编译生成.o文件,对于没有修改的文件不进行任何工作。重新编译过程中,任何一个源文件的修改将产生新的对应的.o文件,新的.o文件将和以前的已经存在、此次没有重新编译的.o文件重新连接生成最后的可执行程序。首先让我们先来看一些Makefile相关的基本知识。2KBUILD系统原理分析1.3Makefile规则介绍一个简单的Makefile描述规则组成:TARGET:PREREQUISITES[TAB]COMMANDtarget:规则的目标。通常是程序中间或者最后需要生成的文件名。可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,成这样的目标是“伪目标”。prerequisites:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则中包括了目标的依赖关系(目标的依赖文件)和重建目标的命令。make执行重建目标的命令,来创建或者重建规则的目标(此目标文件也可以是触发这个规则的上一个规则中的依赖文件)。规则包含了目标和依赖的关系以及更新目标所要求的命令。1.4简单的示例此例子由3个头文件和8个C文件组成。写一个简单的Makefile,创建最终的可执行文件“edit”,此可执行文件依赖于8个C源文件和3个头文件。Makefile文件的内容如下:#sampleMakefileedit:main.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.occ-oeditmain.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.omain.o:main.cdefs.hcc-cmain.c3KBUILD系统原理分析kbd.o:kbd.cdefs.hcommand.hcc-ckbd.ccommand.o:command.cdefs.hcommand.hcc-ccommand.cdisplay.o:display.cdefs.hbuffer.hcc-cdisplay.cinsert.o:insert.cdefs.hbuffer.hcc-cinsert.csearch.o:search.cdefs.hbuffer.hcc-csearch.cfiles.o:files.cdefs.hbuffer.hcommand.hcc-cfiles.cutils.o:utils.cdefs.hcc-cutils.cclean:rmeditmain.okbd.ocommand.odisplay.o\insert.osearch.ofiles.outils.o在书写时,一个较长行可以使用反斜线(\)分解为多行,这样做可以使Makefile清晰、容易阅读。注意:反斜线之后不能有空格(这也是大家最容易犯的错误,而且错误比较隐蔽)。大家在书写Makefile时,推荐者中将较长行分解为使用反斜线连接得多个行的方式。当我们完成了这个Maekfile以后;创建可执行程序“edit”,你所要做的就是在包含此Makefile的目录(当然也在代码所在的目录)下输入命令“make”。删除已经本目录下生成的文件和所有的.o文件,只需要输入命令“makeclean”就可以了。在这个Makefile中,目标(target)包含:可执行文件“edit”和.o文件(main.o,kbd.o….),依赖(prerequisites)就是冒号后面的那些.c文件和.h文件。所有的.o文件既是依赖(相对于可执行程序edit)又是目标(相对于.c和.h文件)。命令包括“cc–cmaic.c”、“cc–ckbd.c”……目标是一个文件时,当它的任何一个依赖文件被修改以后,这个目标文件将会被重新编译或者重新连接。当然,此目标的任何一个依赖文件如果有必要则首先会被重新编译。在这个例子中,“edit”的依赖为8个.o文件;而“main.o”的依赖文件为“main.c”4KBUILD系统原理分析和“defs.h”。当“main.c”或者“defs.h”被修改以后,再次执行“make”时“main.o”就会被更新(其它的.o文件不会被更新),同时“main.o”的更新将会导致“edit”被更新。在描述目标和依赖之下的shell命令行,它描述了如何更新目标文件。命令行必需以[Tab]键开始,以和Makefile其他行区别。就是说所有的命令行必需以[Tab]字符开始,但并不是所有的以[Tab]键出现行都是命令行。但make程序会把出现在第一条规则之后的所有的以[Tab]字符开始的行都作为命令行来处理。(要记住:make程序不关心命令是如何工作的,对目标文件的更新需要你在规则的描述中提供正确的命令。“make”程序所做的就是当目标程序需要更新时执行规则所定义的命令)。目标“clean”不是一个文件,它仅仅代表了执行一个动作的标识。通常情况下,不需要执行这个规则所定义的动作,因此目标“clean”没有出现在其它规则的依赖列表中。在执行make时,它所指定的动作不会被执行。除非执行make时明确地指定它作为重建目标。而且目标“clean”没有任何依赖文件,它只有一个目的,就是通过这个目标名来执行它所定义的命令。Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phonytargets)。执行“clean”目标所定义的命令,可在shell下输入:makeclean。1.5make如何工作默认的情况下,make执行Makefile中的第一个规则,此规则的第一个目标称之为“最终目的”或者“终极目标”(就是一个Makefile最终需要更新或者创建的目标)。上例的Makefile,目标“edit”在Makefile中是第一个目标,因此它就是make的“终极目标”。当修改了任何C源文件或者头文件后,执行make将会重建终极目标“edit”。当在shell提示符下输入“make”命令以后。make读取当前目录下的Makefile文件,并将Makefile文件中的第一个目标作为其“终极目标”,开始处理第一个规则(终极目标所在的规则)。在我们的例子中,第一个规则就是目标“edit”所在的规则。规则描述了“edit”的依赖关系,并定义了链接.o文件生成目标“edit”的命令;make在处理这个规则之前,首先将处理目标“edit”的所有的依赖文件(例子中的那些.o文件)的更新规则;对包含这些.o文件的规则进行处理。对.o文件所在的规则的处理有下列三种情况:1.目标.o文件不存在,使用其描述规则创建它;2.目标.o文件存在,目标.o文件所依赖的.c源文件、.h文件中的任何一个比目标.o文件“更新”(在上一次make之后被修改)。则根据规则重新编译生成它;3.目标.o文件存在,目标.o文件比它的任何一个依赖文件(的.c源文件、.h文件)“更新”(它的依赖文件在上一次make之后没有被修改),则什么也不