linux2.6内核Makefile详解熟悉内核的Makefile对开发设备驱动、理解内核代码结构都是非常重要的linux2.6内核Makefile的许多特性和2.4内核差别很大,在内核目录的documention/kbuild/makefiles.txt中有详细的说明。给大家一个中文版的翻译===目录===1概述===2用户与作用===3Kbuild文件---3.1目标定义---3.2编译进内核-obj-y---3.3编译可装载模块-obj-m---3.4输出的符号---3.5目标库文件-lib-y---3.6递归躺下访问目录---3.7编辑标志---3.8命令行的依赖关系(原文中没有写:-))---3.9跟踪依赖---3.10特殊规则---3.11$(CC)支持的函数===4本机程序支持---4.1简单的本机程序---4.2复合的本机程序---4.3定义共享库---4.4使用用C++编写的本机程序---4.5控制本机程序的编译选项---4.6编译主机程序时---4.7使用hostprogs-$(CONFIG_FOO)===5Kbuild清理===6架构Makefile---6.1调整针对某一具体架构生成的镜像---6.2将所需文件加到archprepare中---6.3递归下向时要访问的目录列表---6.4具体架构的启动镜像---6.5构造非Kbuild目标---6.6构建启动镜像的命令---6.7Kbuild自定义命令---6.8联接器预处理脚本===7Kbuild变量===8Makefile语言===9关于作者===10TODO===1概述Linux内核的Makefile分为5个部分:Makefile顶层Makefile.config内核配置文件arch/$(ARCH)/Makefile具体架构的Makefilescripts/Makefile.*通用的规则等。面向所有的KbuildMakefiles。kbuildMakefiles内核源代码中大约有500个这样的文件顶层Makefile阅读的.config文件,而该文件是由内核配置程序生成的。顶层Makefile负责制作:vmlinux(内核文件)与模块(任何模块文件)。制作的过程主要是通过递归向下访问子目录的形式完成。并根据内核配置文件确定访问哪些子目录。顶层Makefile要原封不动的包含一具体架构的Makefile,其名字类似于arch/$(ARCH)/Makefile。该架构Makefile向顶层Makefile提供其架构的特别信息。每一个子目录都有一个KbuildMakefile文件,用来执行从其上层目录传递下来的命令。KbuildMakefile从.config文件中提取信息,生成Kbuild完成内核编译所需的文件列表。scripts/Makefile.*包含了所有的定义、规则等信息。这些文件被用来编译基于kbuildMakefile的内核。(**有点不通**)===2用户与作用可以将人们与内核Makefile的关系分成4类。*使用者*编译内核的人。他们只是键入makemenuconfig或make这样的命令。一般情况下是不会读或编辑任何内核Makefile(或者任何的源文件)。*普通开发人员*这是一群工作在内核某一功能上的人,比如:驱动开发,文件系统或网络协议。他们所需要维护的只是他们所工作的子系统的KbuildMakefile。为了提高工作的效率,他们也需要对内核Makefile有一个全面的认识,并且要熟悉Kbuild的接口。*架构开发人员*这是一些工作在具体架构,比如sparc或者ia64,上面的人。架构开发者需要在熟悉kbuildMakefile的同时,也要熟悉他所工作架构的Makefile。*Kbuild开发者*维护Kbuild系统的人。他们需要知晓内核Makefile的方方面面。该文件是为普通开发人员与架构开发人员所写。===3Kbuild文件大部分内核中的Makefile都是使用Kbuild组织结构的KbuildMakefile。这章介绍了KbuildMakefile的语法。Kbuild文件倾向于Makefile这个名字,Kbuild也是可以用的。但如果MakefileKbuild同时出现的话,使用的将会是Kbuild文件。3.1节目标定义是一个快速介绍,以后的几章会提供更详细的内容以及实例。---3.1目标定义目标定义是KbuildMakefile的主要部分,也是核心部分。主要是定义了要编译的文件,所有的选项,以及到哪些子目录去执行递归操作。最简单的Kbuildmakefile只包含一行:例子:obj-y+=foo.o该例子告诉Kbuild在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c或foo.S文件编译得到。如果foo.o要编译成一模块,那就要用obj-m了。所采用的形式如下:例子:obj-$(CONFIG_FOO)+=foo.o$(CONFIG_FOO)可以为y(编译进内核)或m(编译成模块)。如果CONFIG_FOO不是y和m,那么该文件就不会被编译联接了。---3.2编译进内核-obj-yKbuildMakefile规定所有编译进内核的目标文件都存在$(obj-y)列表中。而这些列表依赖内核的配置。Kbuild编译所有的$(obj-y)文件。然后,调用$(LD)-r将它们合并到一个build-in.o文件中。稍后,该build-in.o会被其父Makefile联接进vmlinux中。$(obj-y)中的文件是有顺序的。列表中有重复项是可以的:当第一个文件被联接到built-in.o中后,其余文件就被忽略了。联接也是有顺序的,那是因为有些函数(module_init()/__initcall)将会在启动时按照他们出现的顺序进行调用。所以,记住改变联接的顺序可能改变你SCSI控制器的检测顺序,从而导致你的硬盘数据损害。例子:#drivers/isdn/i4l/Makefile #MakefileforthekernelISDNsubsystemanddevicedrivers.#Eachconfigurationoptionenablesalistoffiles.obj-$(CONFIG_ISDN)+=isdn.oobj-$(CONFIG_ISDN_PPP_BSDCOMP)+=isdn_bsdcomp.o---3.3编译可装载模块-obj-m$(obj-m)列举出了哪些文件要编译成可装载模块。一个模块可以由一个文件或多个文件编译而成。如果是一个源文件,KbuildMakefile只需简单的将其加到$(obj-m)中去就可以了。例子:#drivers/isdn/i4l/Makefileobj-$(CONFIG_ISDN_PPP_BSDCOMP)+=isdn_bsdcomp.o注意:此例中$(CONFIG_ISDN_PPP_BSDCOMP)的值为'm'如果内核模块是由多个源文件编译而成,那你就要采用上面那个例子一样的方法去声明你所要编译的模块。Kbuild需要知道你所编译的模块是基于哪些文件,所以你需要通过变量$(module_name-objs)来告诉它。例子:#drivers/isdn/i4l/Makefileobj-$(CONFIG_ISDN)+=isdn.oisdn-objs:=isdn_net_lib.oisdn_v110.oisdn_common.o在这个例子中,模块名将是isdn.o,Kbuild将编译在$(isdn-objs)中列出的所有文件,然后使用$(LD)-r生成isdn.o。Kbuild能够识别用于组成目标文件的后缀-objs和后缀-y。这就让KbuildMakefile可以通过使用CONFIG_符号来判断该对象是否是用来组合对象的。例子:#fs/ext2/Makefileobj-$(CONFIG_EXT2_FS)+=ext2.oext2-y:=balloc.obitmap.oext2-$(CONFIG_EXT2_FS_XATTR)+=xattr.o在这个例子中,如果$(CONFIG_EXT2_FS_XATTR)是'y',xattr.o将是复合对象ext2.o的一部分。注意:当然,当你要将其编译进内核时,上面的语法同样适用。所以,如果你的CONFIG_EXT2_FS=y,那Kbuild会按你所期望的那样,生成ext2.o文件,然后将其联接到built-in.o中。---3.4输出的符号在Makefile中,没有对模块输出的符号有特殊要求。---3.5目标库文件-lib-y在obj-*中所列文件是用来编译模块或者是联接到特定目录中的built-in.o。同样,也可以列出一些将被包含在lib.a库中的文件。在lib-y中所列出的文件用来组成该目录下的一个库文件。在obj-y与lib-y中同时列出的文件,因为都是可以访问的,所以该文件是不会被包含在库文件中的。同样的情况,lib-m中的文件就要包含在lib.a库文件中。注意,一个Kbuildmakefile可以同时列出要编译进内核的文件与要编译成库的文件。所以,在一个目录里可以同时存在built-in.o与lib.a两个文件。例子:#arch/i386/lib/Makefilelib-y:=chechsum.odelay.o这将由checksum.o和delay.o两个文件创建一个库文件lib.a。为了让Kbuild真正认识到这里要有一个库文件lib.a要创建,其所在的目录要加到libs-y列表中。还可参考6.3递归下向时要访问的目录列表lib-y使用一般限制在lib/和arch/*/lib中。---3.6递归向下访问目录一个Makefile只对编译所在目录的对象负责。在子目录中的文件的编译要由其所在的子目录的Makefile来管理。只要你让Kbuild知道它应该递归操作,那么该系统就会在其子目录中自动的调用make递归操作。这就是obj-y和obj-m的作用。ext2被放的一个单独的目录下,在fs目录下的Makefile会告诉Kbuild使用下面的赋值进行向下递归操作。例子:#fs/Makefileobj-$(CONFIG_EXT2_FS)+=ext2/如果CONFIG_EXT2_FS被设置为'y'(编译进内核)或是'm'(编译成模块),相应的obj-变量就会被设置,并且Kbuild就会递归向下访问ext2目录。Kbuild只是用这些信息来决定它是否需要访问该目录,而具体怎么编译由该目录中的Makefile来决定。将CONFIG_变量设置成目录名是一个好的编程习惯。这让Kbuild在完全忽略那些相应的CONFIG_值不是'y'和'm'的目录。---3.7编辑标志EXTRA_CFLAGS,EXTRA_AFLAGS,EXTRA_LDFLAGS,EXTRA_ARFLAGS所有的EXTRA_变量只在所定义的KbuildMakefile中起作用。EXTRA_变量可以在KbuildMakefile中所有命令中使用。$(EXTRA_CFLAGS)是用$(CC)编译C源文件时的选项。例子:#drivers/sound/emu10kl/MakefileEXTRA_CFLAGS+=-I$(obj)ifdefDEBUGEXTRA_CFLAGS+=-DEMU10KL_DEBUGendif该变量是必须的,因为顶层Makefile拥有变量$(CFLAGS)并用来作为整个源代码树的编译选项。$(EXTRA_AFLAGS)也是一个针对每个目录的选项,只不过它是用来编译汇编源代码的。例子:#arch/x86_64/kernel/MakefileEXTRA_AFLAGS:=-traditional$(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)分别与$(LD)和$(AR)类似,只不过,他们是针对每个目录的。例子:#arch/m68k/fpsp040/MakefileEXTRA_LDFLAGS:=-xCFLAGS_$@,AFLSGA_$@