建设网站情况说明范文,网站建设和管理制度,WordPress来必力,延寿县建设银行网站熟悉内核的Makefile对开发设备驱动、理解内核代码结构都是非常重要的linux2.6内核Makefile的许多特性和2.4内核差别很大#xff0c;在内核目录的documention/kbuild/makefiles.txt中有详细的说明。给大家一个中文版的翻译 目录 1 概述 2 用户与作用 3 Kbuild文件--- 3.1 目标定…熟悉内核的Makefile对开发设备驱动、理解内核代码结构都是非常重要的linux2.6内核Makefile的许多特性和2.4内核差别很大在内核目录的documention/kbuild/makefiles.txt中有详细的说明。给大家一个中文版的翻译目录1 概述2 用户与作用3 Kbuild文件--- 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)5 Kbuild清理6 架构Makefile--- 6.1 调整针对某一具体架构生成的镜像--- 6.2 将所需文件加到 archprepare 中--- 6.3 递归下向时要访问的目录列表--- 6.4 具体架构的启动镜像--- 6.5 构造非Kbuild目标--- 6.6 构建启动镜像的命令--- 6.7 Kbuild自定义命令--- 6.8 联接器预处理脚本7 Kbuild 变量8 Makefile语言9 关于作者10 TODO1 概述Linux内核的Makefile分为5个部分Makefile 顶层Makefile.config 内核配置文件arch/$(ARCH)/Makefile 具体架构的Makefilescripts/Makefile.* 通用的规则等。面向所有的Kbuild Makefiles。kbuild Makefiles 内核源代码中大约有500个这样的文件顶层Makefile阅读的.config文件而该文件是由内核配置程序生成的。顶层Makefile负责制作vmlinux(内核文件)与模块(任何模块文件)。制作的过程主要是通过递归向下访问子目录的形式完成。并根据内核配置文件确定访问哪些子目录。顶层Makefile要原封不动的包含一具体架构的Makefile其名字类似于 arch/$(ARCH)/Makefile。该架构Makefile向顶层Makefile提供其架构的特别信息。每一个子目录都有一个Kbuild Makefile文件用来执行从其上层目录传递下来的命令。Kbuild Makefile从.config文件中提取信息生成Kbuild完成内核编译所需的文件列表。scripts/Makefile.*包含了所有的定义、规则等信息。这些文件被用来编译基于kbuildMakefile的内核。(**有点不通**)2 用户与作用可以将人们与内核Makefile的关系分成4类。*使用者* 编译内核的人。他们只是键入make menuconfig或make这样的命令。一般情况下是不会读或编辑任何内核Makefile或者任何的源文件。*普通开发人员* 这是一群工作在内核某一功能上的人比如驱动开发文件系统或网络协议。他们所需要维护的只是他们所工作的子系统的Kbuild Makefile。为了提高工作的效率他们也需要对内核Makefile有一个全面的认识并且要熟悉Kbuild的接口。*架构开发人员* 这是一些工作在具体架构比如sparc 或者ia64上面的人。架构开发者需要在熟悉kbuild Makefile的同时也要熟悉他所工作架构的Makefile。*Kbuild开发者* 维护Kbuild系统的人。他们需要知晓内核Makefile的方方面面。该文件是为普通开发人员与架构开发人员所写。3 Kbuild文件大部分内核中的Makefile都是使用Kbuild组织结构的Kbuild Makefile。这章介绍了Kbuild Makefile的语法。Kbuild文件倾向于Makefile这个名字Kbuild也是可以用的。但如果MakefileKbuild同时出现的话使用的将会是Kbuild文件。3.1节 目标定义是一个快速介绍以后的几章会提供更详细的内容以及实例。--- 3.1 目标定义目标定义是Kbuild Makefile的主要部分也是核心部分。主要是定义了要编译的文件所有的选项以及到哪些子目录去执行递归操作。最简单的Kbuild makefile 只包含一行例子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-yKbuild Makefile 规定所有编译进内核的目标文件都存在$(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# Makefile for the kernel ISDN subsystem and device drivers.# Each configuration option enables a list of files.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需要知道你所编译的模块是基于哪些文件所以你需要通过变量$(-objs)来告诉它。例子#drivers/isdn/i4l/Makefileobj-$(CONFIG_ISDN) isdn.oisdn-objs : isdn_net_lib.o isdn_v110.o isdn_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.o bitmap.oext2-$(CONFIG_EXT2_FS_XATTR) xattr.o在这个例子中如果 $(CONFIG_EXT2_FS_XATTR) 是 y,xattr.o将是复合对象 ext2.o的一部分。注意当然当你要将其编译进内核时上面的语法同样适用。所以如果你的 CONFIGEXT2FSy那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 库文件中。注意一个Kbuild makefile可以同时列出要编译进内核的文件与要编译成库的文件。所以在一个目录里可以同时存在 built-in.o 与 lib.a 两个文件。例子#arch/i386/lib/Makefilelib-y : chechsum.o delay.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_ 变量只在所定义的Kbuild Makefile中起作用。EXTRA_ 变量可以在Kbuild Makefile中所有命令中使用。$(EXTRA_CFLAGS) 是用 $(CC) 编译C源文件时的选项。例子# drivers/sound/emu10kl/MakefileEXTRA_CFLAGS -I$(obj)ifdef DEBUGEXTRA_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_$CFLAGS_$ 和 AFLAGS_$ 只能在当前Kbuild Makefile中的命令中使用。$(CFLAGS_$) 是 $(CC) 针对每个文件的选项。$ 表明了具体操作的文件。例子# drivers/scsi/MakefileCFLAGS_aha152x.o -DAHA152X_STAT -DAUTOCONFCFLAGS_gdth.o # -DDEBUG_GDTH2 -D__SERIAL__ -D__COM2__ \-DGDTH_STATISTICSCFLAGS_seagate.o -DARBITRATE -DPARITY -DSEAGATE_USE_ASM以上三行分别设置了aha152x.o,gdth.o 和 seagate.o的编辑选项。$(AFLAGS_$) 也类似只不是是针对汇编语言的。例子# arch/arm/kernel/MakefileAFLAGS_head-armv.o : -DTEXTADDR$(TEXTADDR) -traditionalAFLAGS_head-armo.o : -DTEXTADDR$(TEXTADDR) -traditional--- 3.9 跟踪依赖Kbuild 跟踪在以下方面依赖1) 所有要参与编译的文件(所有的.c 和.h文件)2) 在参与编译文件中所要使用的 CONFIG_ 选项3) 用于编译目标的命令行因此如果你改变了 $(CC) 的选项所有受影响的文件都要重新编译。--- 3.10 特殊规则特殊规则就是那Kbuild架构不能提供所要求的支持时所使用的规则。一个典型的例子就是在构建过程中生成的头文件。另一个例子就是那些需要采用特殊规则来准备启动镜像。特殊规则的写法与普通Make规则一样。Kbuild并不在Makefile所在的目录执行所以所有的特殊规则都要提供参与编译的文件和目标文件的相对路径。在定义特殊规则时要使用以下两个变量$(src)$(src) 表明Makefile所在目录的相对路径。经常在定位源代码树中的文件时使用该变量。$(obj)$(obj) 表明目标文件所要存储目录的相对路径。经常在定位所生成的文件时使用该变量。例子#drivers/scsi/Makefile$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl$(CPP) -DCHIP810 - $ | ... $(src)/script_asm.pl这就是一个特殊规则遵守着make所要求的普通语法。目标文件依赖于两个源文件。用$(obj)来定位目标文件用$(src)来定位源文件(因为它们不是我们生成的文件)。--- 3.11 $(CC) 支持的函数内核可能由多个不同版本的$(CC)编译而每个版本都支持一不同的功能集与选项集。Kbuild提供了检查 $(CC) 可用选项的基本功能。$(CC)一般情况下是gcc编译器但也可以使用其它编译器来代替gcc。as-optionas-option当编译汇编文件(*.S)时用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话可选的第二个选项可以用来指定。例子#arch/sh/Makefilecflags-y $(call as-option,-Wa$(comma)-isa$(isa-y),)在上面的例子里如果 $(CC) 支持选项 -Wa$(comma)-isa$(isa-y)cflags-y就会被赋予该值。第二个参数是可选的当第一个参数不支持时就会使用该值。ld-optionld-option当联接目标文件时用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话可选的第二个选项可以用来指定。例子#arch/i386/kernel/Makefilevsyscall-flags $(call ld-option, -Wl$(comma)--hash-stylesysv)在上面的例子中如果 $(CC)支持选项 -Wl$(comma)--hash-stylesysvld-option就会被赋予该值。第二个参数是可选的当第一个参数不支持时就会使用该值。cc-optioncc-option用来检查 $(CC) 是否支持特定选项,并且不支持使用可选的第二项。例子#arch/i386/Makefilecflags-y $(call cc-option,-marchpentium-mmx,-marchi586)在上面的例子中如果 $(CC)支持选项 -marchpentium-mmxcc-option就会被赋予该值否则就赋 -march-i586。cc-option的第二个参数是可选的。如果忽略的话当第一个选项不支持时cflags-y 不会被赋值。cc-option-yncc-option-yn,用来检查 gcc 是否支持特定选项返回y支持否则为n。例子#arch/ppc/Makefilebiarch : $(call cc-option-yn, -m32)aflags-$(biarch) -a32cflags-$(biarch) -m32在上面的例子里当 $(CC) 支持 -m32选项时$(biarch)设置为y。当 $(biarch) 为y时扩展的 $(aflags-y) 和 $(cflags-y)变量就会被赋值为-a32 和 -m32。cc-option-aligngcc版本大于3.0时改变了函数循环等用来声明内存对齐的选项。当用到对齐选项时$(cc-option-align) 用来选择正确的前缀gcc 3.00cc-option-align -maligngcc 3.00cc-option-align -falign例子CFLAGS $(cc-option-align)-functions4在上面的例子中选项 -falign-funcions4 被用在gcc 3.00的时候。对于小于3.00时 使用 -malign-funcions4 。cc-versioncc-version以数学形式返回 $(CC) 编译器的版本号。其格式是二者都是数学。比如gcc 3.41 会返回 0341。当某版本的 $(CC) 在某方面有缺陷时,cc-version就会很有用。比如选项-mregparm3 虽然会被gcc接受但其实现是有问题的。例子#arch/i386/Makefilecflags-y $(shell \if [ $(call cc-version) -ge 0300 ] ; then \echo -meregparm3; fi ;)在上面的例子中-mregparm3只会在gcc的版本号大于等于3.0的时候使用。cc-ifversioncc-ifversion测试 $(CC) 的版本号如果版本表达式为真就赋值为最后的参数。例子#fs/reiserfs/MakefileEXTRA_CFLAGS : $(call cc-ifversion, -lt, 0402, -O1)在这个例子中如果 $(CC) 的版本小于4.2,EXTRA_CFLAGS就被赋值 -O1。ccifversion 可使用所有的shell 操作符-eq,-ne,-lt,-le,-gt,和-ge。第三个参数可以像上面例子一样是个文本但也可以是个扩展的变量或宏。/*这段翻译的不好*/4 本机程序支持Kbuild 支持编译那些将在编译阶段使用的可执行文件。为了使用该可执行文件要将编译分成二个阶段。第一阶段是告诉Kbuild存在哪些可执行文件。这是通过变量 hostprogs-y来完成的。第二阶段是添加一个对可执行文件的显性依赖。有两种方法:增加依赖关系到一个规则中或是利用变量 $(always)。以下是详细叙述.--- 4.1 简单的本机程序在编译内核时有时会需要编译并运行一个程序。下面这行就告诉了kbuild程序bin2hex应该在本机上编译。例子hostprogs-y : bin2hex在上面的例子中Kbuild假设bin2hex是由一个与其在同一目录下名为 bin2hex.c 的C语言源文件编译而成的。--- 4.2 复合的本机程序本机程序可以由多个文件编译而成。所使用的语法与内核的相应语法很相似。$(-objs) 列出了联接成最后的可执行文件所需的所有目标文件。例子#scripts/lxdialog/Makefilehostprogs-y : lxdialoglxdialog-objs : checklist.o lxdialog.o扩展名为.o的文件是从相应的.c文件编译而来的。在上面的例子中checklist.c 编译成了checklist.olxdialog.c编译成了lxdialog.o。最后两个.o文件联接成了一可执行文件lxdialog。注意语法 -y不是只能用来生成本机程序。--- 4.3 定义共享库扩展名为so的文件称为共享库被编译成位置无关对象。Kbuild也支持共享库但共享库的使用很有限。在下面的例子中libconfig.so共享库用来联接到可执行文件 conf中。例子#scripts/kconfig/Makefilehostprogs-y : confconf-objs : conf.o libkconfig.solibkcofig-objs : expr.o type.o共享库文件经常要求一个相应的 -objs在上面的例子中共享库libkconfig是由 expr.o 和 type.o两个文件组成的。expr.o 和 type.o 将被编译成位置无关码然后联接成共享库文件 libkconfig.so。C并不支持共享库。--- 4.4 使用用C编写的本机程序kbuild也支持用C编写的本机程序。在此专门介绍是为了支持kconfig并且在一般情况下不推荐使用。例子#scripts/kconfig/Makefilehostprogs-y : qconfqconf-cxxobjs : qconf.o在上面的例子中可执行文件是由C文件 qconf.cc编译而成的由$(qconf-cxxobjs)来标识。如果qconf是由.c和.cc一起编译的那么就需要专门来标识这些文件了。例子#scripts/kconfig/Makefilehostprogs-y : qconfqconf-cxxobjs : qconf.oqconf-objs : check.o--- 4.5 控制本机程序的编译选项当编译本机程序时有可能使用到特殊选项。程序经常是利用$(HOSTCC)编译,其选项在 $(HOSTCFLAGS)变量中。可通过使用变量 HOSTEXTRACFLAGS影响所有在Makefile文件中要创建的主机程序。例子#scripts/lxdialog/MakefileHOST_EXTRACFLAGS -I/usr/include/ncurses为一单个文件设置选项可按形式进行例子#arch/ppc64/boot/MakefileHOSTCFLAGS_pinggyback.o : -DKERNELBASE$(KERNELBASE)同样也可以给联接器声明一特殊选项。例子#scripts/kconfig/MakefileHOSTLOADLIBES_qconf : -L$(QTDIR)/lib当联接qconf时将会向联接器传递附加选项 -L$(QTDIR)/lib。--- 4.6 编译主机程序时Kbuild只在需要时编译主机程序。有两种方法(1) 在一具体的规则中显性列出所需要的文件例子#drivers/pci/Makefilehostprogs-y : gen-devlist$(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist( cd $(obj); ./gen-devlist ) $目标 $(obj)/devlist.h 是不会在 $(obj)/gen-devlist 更新之前编译的。注意在该规则中所有有关主机程序的命令必须以$(obj)开头。(2) 使用 $(always)当Makefile要编译主机程序但没有适合的规则时使用 $(always)。例子#scripts/lxdialog/Makefilehostprogs-y : lxdialogalways : $(hostprogs-y)这就是告诉Kbuild即使没有在规则中声明也要编译 lxdialog。--- 4.7 使用 hostprogs-$(CONFIG_FOO)一个典型的Kbuild模式如下例子#scripts/Makefilehostprogs-$(CONFIG_KALLSYMS) kallsymsKbuild 知道 y 是编译进内核而 m 是编译成模块。所以如果配置符号是mKbuild仍然会编译它。换句话说Kbuild处理 hostprogs-m 与hostprogs-y 的方式是完全一致的。只是如果不用 CONFIG最好用 hostprogs-y。5 Kbuild清理(clean)make clean删除几乎所有的在编译内核时生成的文件包括了主机程序在内。Kbuild 通过列表 $(hostprogs-y)$(hostprogs-m)$(always)$(extra-y) 和$(targets) 知道所要编译的目标。这些目标文件都会被 make clean 删除。另外在make clean还会删除匹配 *.[oas]*.ko 的文件以及由 Kbuild生成的辅助文件。辅助文件由 Kbuild Makefile 中的 $(clean-files) 指明。例子#drivers/pci/Makefileclean-files : devlist.h classlist.h当执行 make clean 时devlist.h classlist.h这两个文件将被删除。如果不使用绝对路径(路径以/开头)的话Kbuild假设所要删除的文件与Makefile在同一个相对路径上。要删除一目录例子#scripts/package/Makefileclean-dirs : $(objtree)/debian/这就会删除目录 debian包括其所有的子目录。如果不使用绝对路径(路径以/开头)的话Kbuild假设所要删除的目录与Makefile在同一个相对路径上。一般情况下Kbuild会根据 obj-* : dir/ 递归访问其子目录但有的时候Kbuild架构还不足以描述所有的情况时还要显式的指明所要访问的子目录。例子#arch/i386/boot/Makefilesubdir- : compressed/上面的赋值命令告诉Kbuild当执行make clean时要递归访问目录 compressed/。为了支持在最终编译完成启动镜像后的架构清理工作还有一可选的目标 archclean例子#arch/i386/Makefilearchclean:$(Q)$(MAKE) $(clean)arch/i386/boot当make clean执行时make会递归访问并清理 arch/i386/boot。在 arch/i386/boot中的Makefile可以用来提示make进行下一步的递归操作。注意1arch/$(ARCH)/Makefile 不能使用subdir-因为该Makefile被包含在顶层的Makefile中Kbuild是不会在此处进行操作的。注意2make clean 会访问在 core-ylibs-ydrivers-y 和 net-y 列出的所有目录。6 架构Makefile在递归访问目录之前顶层Makefile要完成设置环境变量以及递归访问的准备工作。顶层Makefile包含的公共部分而 arch/$(ARCH)/Makefile 包含着针对某一特定架构的配置信息。所以要在 arch/$(ARCH)/Makefile 中设置一部分变量并定义一些目标。Kbuild执行的几个步驟(大致)1) 根据内核配置生成文件 .config2) 将内核的版本号存储在 include/linux/version.h3) 生成指向 include/asm-$(ARCH) 的符号链接4) 更新所有编译所需的文件 -附加的文件由 arch/$(ARCH)/Makefile 指定。5) 递归向下访问所有在下列变量中列出的目录 init-* core* drivers-* net-* libs-*并编译生成目标文件。-这些变量的值可以在 arch/$(ARCH)/Makefile 中扩充。6) 联接所有的目标文件在源代码树顶层目录中生成 vmlinux。最先联接是在 head-y中列出的文件该变量由 arch/$(ARCH)/Makefile 赋值。7) 最后完成具体架构的特殊要求并生成最终的启动镜像。-包含生成启动指令-准备 initrd 镜像或类似文件--- 6.1 调整针对某一具体架构生成的镜像LDFLAGS 一般是 $(LD) 选项该选项在每次调用联接器时都会用到。一般情况下只用来指明模拟器。例子#arch/s390/MakefileLDFLAGS : -m elf_s390注意EXTRA_LDFLAGS 和 LDFLAGS_$ 可用来进一步自定义选项。请看第七章。LDFLAGS_MODULE 联接模块时的联接器的选项LDFLAGS_MODULE 所设置的选项将在联接器在联接模块文件 .ko 时使用。默认值为 -r指定输出文件是可重定位的。LDFLAGS_vmlinux 联接vmlinux时的选项LDFLAGS_vmlinux用来传递联接vmlinux时的联接器的选项。LDFLAGS_vmlinux需 LDFLAGS_$ 支持。例子#arch/i386/MakefileLDFLAGS_vmlinux : -e stextOBJCOPYFLAGS objcopy 选项当用 $(call if_changed,objcopy) 来转换(translate)一个.o文件时该选项就会被使用。$(call if_changed,objcopy) 经常被用来为vmlinux生成原始的二进制代码。例子#arch/s390/MakefileOBJCOPYFLAGS : -O binaryarch/s390/boot/Makefile$(obj)/image: vmlinux FORCE$(call if_changed,objcopy)在此例中二进制文件 $(obj)/image 是 vmlinux 的一个二进制版本。$(call if_chagned,xxx)的用法稍后描述。AFLAGS $(AS) 汇编编译器选项默认值在顶层Makefile扩充或修改在各具体架构的Makefile例子#arch/sparc64/MakefileAFLAGS -m64 -mcpuultrasparcCFLAGS $(CC) 编译器选项默认值在顶层Makefile扩充或修改在各具体架构的Makefile。一般CFLAGS要根据内核配置设置。例子#arch/i386/Makefilecflags-$(CONFIG_M386) -marchi386CFLAGS $(cflags-y)许多架构Makefile都通过调用所要使用的C编译器动态的检查其所支持的选项#arch/i386/Makefile...cflags-$(CONFIG_MPENTIUMII) $(call cc-option,\-marchpentium2,-marchi686)...# Disable unit-at-a-time mode ...CFLAGS $(call cc-option,-fno-unit-at-a-time)...第一个例子利用了一个配置选项当其为y时扩展。CFLAGS_KERNEL #arch/i386/Makefile...cflags-$(CONFIG_MPENTIUMII) $(call cc-option,\-marchpentium2,-marchi686)...# Disable unit-at-a-time mode ...CFLAGS $(call cc-option,-fno-unit-at-a-time)...第一个例子利用了一个配置选项当其为y时扩展。CFLAGS_KERNEL 编译进内核时$(CC) 所用的选项$(CFLAGS_KERNEL) 包含了用于编译常驻内核代码的附加编译器选项。CFLAGS_MODULE 编译成模块时$(CC)所用的选项$(CFLAGS_MODULE) 包含了用于编译可装载模块的附加编译器选项。--- 6.2 将所需文件加到 archprepare 中archprepare规则在递归访问子目录之前列出编译目标文件所需文件。一般情况下这是一个包含汇编常量的头文件。(assembler constants)例子#arch/arm/Makefilearchprepare: maketools此例中目标文件 maketools 将在递归访问子目录之前编译。在TODO一章可以看到Kbuild是如何支持生成分支头文件的。(offset header files)--- 6.3 递归下向时要访问的目录列表如何生成 vmlinux是由架构makefile和顶层Makefile一起来定义的。注意,架构Makefile是不会定义与模块相关的内容的所有构建模块的定义是与架构无关的。head-y,init-y,core-y,libs-y,drivers-y,net-y$(head-y) 列出了最先被联接进 vmlinux 的目标文件。$(libs-y) 列出了生成的所有 lib.a 所在的目录。其余所列的目录是 built-in.o 所在的目录。$(init-y) 在 $(head-y) 之后所要使用的文件。然后剩下的步骤如下$(core-y),$(libs-y),$(drivers-y)和$(net-y)。顶层makefile定义了通用的部分arch/$(ARCH)/Makefile 添加了架构的特殊要求。例子#arch/sparc64/Makefilecore-y arch/sparc64/kernel/libs-y arch/sparc64/prom/ arch/sparc64/lib/drivers-$(CONFIG_OPROFILE) arch/sparc64/oprofile/--- 6.4 具体架构的启动镜像一具体架构Makefile的具体目的就是将生成并压缩 vmlinux 文件写入启动代码并将其拷贝到正确的位置。这就包含了多种不同的安装命令。该具体目的也无法在各个平台间进行标准化。一般附加的处理命令入在 arch/$(ARCH)/下的boot目录。Kbuild并没有为构造boot所指定的目标提供任何更好的方法。所以arch/$(ARCH)/Makefile 将会调用 make 以手工构造 boot的目标文件。比较好的方法是在 arch/$(ARCH)/Makefile 中包含快捷方式并在arch/$(ARCH)/boot/Makefile 中使用全部路径。例子#arch/i386/Makefileboot : arch/i386/bootbzImage: vmlinux$(Q)$(MAKE) $(build)$(boot) $(boot)/$当在子目录中调用 make 时推荐使用 $(Q)$(MAKE) $(build) 。 并没有对架构特殊目标的命名规则但用命令 make help 可以列出所有的 相关目标。 为了支持 make help$(archhelp) 必须被定义。 例子 #arch/i386/Makefile define archhelp echo * bzImage - Image (arch/$(ARCH)/boot/bzImage) endef 当make 没带参数执行时所遇到的第一个目标将被执行。在顶层第一个目标 就是 all。 每个架构Makefile都要默认构造一可启动的镜像文件。 在 make help中默认目标就是被加亮的*。 添加一新的前提文件到 all就可以构造出一不同的vmlinux。 例子 #arch/i386/Makefile all: bzImage 当 make 没有参数时bzImage将被构造。 --- 6.5 构造非Kbuild目标 extra-y extra-y 列出了在当前目录下所要创建的附加文件不包含任何已包含在 obj-* 中的文件。 用 extra-y 列目标主要是两个目的 1) 可以使Kbuild检查命令行是否发生变化 - 使用 $(call if_changed,xxx) 的时候 2) 让Kbuild知道哪些文件要在 make clean 时删除 例子 #arch/i386/kernel/Makefile extra-y : head.o init_task.o 在此例子中extra-y用来列出所有只编译但不联接到 built-in.o的目标 文件。 --- 6.6 构建启动镜像的命令 Kbuild 提供了几个用在构建启动镜像时的宏。 if_changed if_changed 为下列命令的基础。 使用方法 target: source(s) FORCE $(call if_changed,ld/objcopy/gzip) 当执行该规则时就检查是否有文件需要更新或者在上次调用以后命令行 发生了改变。如果有选项发生了改变后者会导致重新构造。 只有在 $(targets)列出的的目标文件才能使用 if_changed否则命令行的 检查会失败并且目标总会被重建。 给 $(targets)的赋值没有前缀 $(obj)/ 。 if_changed 可用来联接自定义的 Kbuild命令关于Kbuild自定义命令请看 6.7节。 注意忘记 FORCE 是一种典型的错误。还有一种普遍的错误是空格有的时候 是有意义的比如。下面的命令就会错误(注意在逗号后面的那个多余的空格) target: source(s) FORCE #WRONG!# $(call if_changed, ld/objcopy/gzip) ld 联接目标。经常是使用LDFLAGS_$来设置ld的特殊选项。 objcopy 拷贝二进制代码。一般是在 arch/$(ARCH)/Makefile 中使用 OBJCOPYFLAGS。 OBJCOPYFLAGS_$ 可以用来设置附加选项。 gzip 压缩目标文件。尽可能的压缩目标文件。 例子 #arch/i386/boot/Makefile LDFLAGS_bootsect : -Ttext 0x0 -s --oformat binary LDFLAGS_setup : -Ttext 0x0 -s --oformat binary -e begtext targets setup setup.o bootsect bootsect.o $(obj)/setup $(obj)/bootsect: %: %.o FORCE $(call if_changed,ld) 在这个例子中有两个可能的目标文件分别要求不同的联接选项。定义联接 器的选项使用的是 LDFLAGS_$ 语法每个潜在的目标一个。 $(targets) 被分配给所有的潜在目标因此知道目标是哪些并且还会 1) 检查命令行是否改变 2) 在 make clean 时删除目标文件 前提部分中的 : %: %.o 部分使我们不必在列出文件 setup.o 和 bootsect.o 。 注意一个普遍的错误是忘记了给 target赋值导致在target中的文件总是 无缘无故的被重新编译。 --- 6.7 Kbuild自定义命令 当Kbuild的变量 KBUILD_VERBOSE 为0时只会显示命令的简写。 如果要为自定义命令使用这一功能需要设置2个变量 quiet_cmd_ - 要显示的命令 cmd_ - 要执行的命令 例子 # quiet_cmd_image BUILD $ cmd_image $(obj)/tools/build $(BUILDFLAGS) \ $(obj)/vmlinux.bin $ targets bzImage $(obj)/bzImage: $(obj)/vmlinux.bin $(obj)/tools/build FORCE $(call if_changed,image) echo Kernel: $ is ready 当用make KBUILD_VERBOSE0更新 $(obj)/bzImage 目标时显示 BUILD arch/i386/boot/bzImage --- 6.8 联接器预处理脚本 当构造 vmlinux 镜像时使用联接器脚本 arch/$(ARCH)/kernel/vmlinux.lds。 该脚本是由在同一目录下的 vmlinux.lds.S 生成的。 Kbuild认识.lds文件并包含由*.lds.S文件生成*.lds文件的规则。 例子 #arch/i386/kernel/Makefile always : vmlinux.lds #Makefile export CPPFLAGS_vmlinux.lds -P -C -U$(ARCH) $(always)的值是用来告诉Kbuild构造目标 vmlinux.lds。 $(CPPFLAGS_vmlinux.lds)Kbuild在构造目标vmlinux.lds时所用到的特殊 选项。 当构造 *.lds 目标时Kbuild要用到下列变量 CPPFLAGS : 在顶层目录中设置 EXTRA_CPPFLAGS : 可以在Kbuild Makefile中设置 CPPFLAGS_$(F) : 目标特别选项 注意此处的赋值用的完整的文件名。 针对*.lds文件的Kbuild构架还被用在许多具体架构的文件中。(***不通***) 7 Kbuild 变量 顶层Makefile输出以下变量 VERSION,PATCHLEVEL,SUBLEVEL,EXTRAVERSION 这些变量定义了当前内核的版本号。只有很少一部分Makefile会直接用到这些 变量可使用 $(KERNELRELEASE)代替。 $(VERSION),$(PATCHLEVEL),和$(SUBLEVEL) 定义了最初使用的三个数字的版本 号比如24和0。这三个值一般是数字。 $(EXTRAVERSION) 为了补丁定义了更小的版本号。一般是非数字的字符串比如 -pre4 或就空着。 KERNELRELEASE $(KERNELRELEASE) 是一个字符串类似2.4.0-pre4用于安装目录的命名或 显示当前的版本号。一部分架构Makefile使用该变量。 ARCH 该变量定义了目标架构比如i386,arm 或sparc。有些Kbuild Makefile 根据 $(ARCH) 决定编译哪些文件。 默认情况下顶层Makefile将其设置为本机架构。如果是跨平台编译用户可以 用下面的命令覆盖该值 make ARCHm68k ... INSTALL_PATH 该变量为架构Makefile定义了安装内核镜像与 System.map 文件的目录。 主要用来指明架构特殊的安装路径。 INSTALL_MOD_PATH,MODLIB $(INSTALL_MOD_PATH) 为了安装模块给 $(MODLIB) 声明了前缀。该变量不能 在Makefile中定义但可以由用户传给Makefile。 $(MODLIB) 具体的模块安装的路径。顶层Makefile将$(MODLIB)定义为 $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。用户可以通过命令行 参数的形式将其覆盖。 INSTALL_MOD_STRIP 如果该变量有定义模块在安装之前会被剥出符号表。如果 INSTALL_MOD_STRIP 为 1就使用默认选项 --strip-debug。否则 INSTALL_MOD_STRIP 将作为命令 strip 的选项使用。 8 Makefile语言 内核的Makefile使用的是GNU Make。该Makefile只使用GNU Make已注明的功能并使用 了许多GNU 的扩展功能。 GNU Make支持基本的显示处理过程的函数。内核Makefile 使用了一种类似小说的方式 显示if语句的构造、处理过程。 GNU Make 有2个赋值操作符:和。:将对右边的表达式求值并将所求的值 赋给左边。更像是一个公式定义只是将右边的值简单的赋值给左边当左边的表达 式被使用时才求值。 有时使用是正确的。但是一般情况下推荐使用:。 9 关于作者 第一版由 Michael Elizabeth Chastain, 修改kai Germaschewski Sam Ravnborg 10 TODO - 描述Kbuild是如何用 _shipped 来支持 shipped 文件的。 - 生成分支头文件 - 在第7节加入更多的变量