现在的位置: 首页 > 综合 > 正文

Linux source code Makefile分析

2013年09月14日 ⁄ 综合 ⁄ 共 6450字 ⁄ 字号 评论关闭

linux-2.6.x makefile 
  
linux-2.6.20.6/Documentation/kbuild/makefiles.txt 
  
一、             概述 
  
linux的makefile有五个部分: 
  
Makefile:顶层Makefile 
.config:内核配置文件 
arch/$(ARCH)/Makefile:体系结构相关的Makefile 
scripts/Makefile.*:通用的规则等,用于所有的kbuild Makefiles 
kbuild Makefiles:大约有500个这样的makefile 
  
顶层Makefile读取在内核配置过程中生成的.config文件。负责构建两个主要的文件:vmlinux和各模块。它还包含了一个名为arch/$(ARCH)/Makefile的体系结构相关Makefile,这个Makefile给顶层Makefile提供了体系结构相关的信息。 
  
每个子目录有一个kbuild Makefile,它执行上层传入的命令。kbuild Makefile使用.config文件中的信息构建各种文件列表,供kbuild构建任何built-in或modular目标时使用。 
  
scripts/Makefile.*包含所有的定义和规则等,这些被用来和kbuild makeflie一起构建内核 
  
二、             kbuild文件 
  
kbuild Makefile中的语法。 
  
kbuild文件首选的文件名是”Makefile”,也可以用”kbuild”。如果”Makefile”和”kbuild”同时存在,则使用”kbuild”文件。 
  
1、  目标定义 
  
目标定义是kbuild Makefile的主要部分。这些行定义了要被编译的文件、所有指定的编码选项及所有将要递归进入的子目录。 
  
最简单的kbuild Makefile包括一行: 
  
obj-y += foo.o 
  
如果foo.o要被编译成模块,就用obj-m。因此,经常使用下面的模式: 
  
obj-$(CONFIG_FOO) += foo.o 
  
$(CONFIG_FOO)的值是y (for built-in)或者m(for module)。如果CONFIG_FOO既不是y也不是m,这个文件不会被编译或链接 
  
2、  Built-in 对象目标 - obj-y 
  
kbuild Makefile 在$(obj-y)列表中给vmlinux指定目标文件,这个列表依赖于内核配置。 
  
kbuild 编译所有的$(obj-y)文件,然后调用”$(LD) –r”把这些文件合并成一个built-in.o文件,之后built-in.o被顶层Makefile链接成vmlinux。 
  
$(obj-y)中文件的顺序很重要,在这个列表中,完全相同的文件可以同时存在:第一个被链接到built-in.o,以后的都被忽略了。 
  
链接顺序也很重要,因为特定的函数(module_init() / __initcall)会在启动期间按照它们出现的顺序被调用。 
  
3、  可加载模块目标 - obj-m 
  
$(obj-m)指定被编译为可加载内核模块的文件。一个模块可以是一个或多个源文件编译生成。如果是一个源文件,kbuild makefile只是简单的把这个文件加入$(obj-m)。如果内核模块由多个源文件编译生成,内核要知道你想要编译哪些源文件,所以你必须设置变量$(<module_name>-objs)来告诉内核。 
  
eg. 
   #derivers/isdn/i4l/Makefile 
   obj-$(CONFIG_ISDN) += isdn.o 
   isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o 
  
在这个例子中,模块名是isdn.o。Kbuild会编译$(isdn-objs)中列出的对像,并运行”$(LD) –r”生成isdn.o。 
  
Kbuild通过后缀-objs和-y识别用于编译生成目标的对像。它允许Makefile使用CONFIG_符号的值来决定一个对像是否是某个目标的一部分。 
  
eg. 
              #fs/ext2/Makefile 
               obj-$(CONFIG_EXT2_FS)        += ext2.o 
              ext2-y                       := balloc.o bitmap.o 
               ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o 
  
如果CONFIG_EXT2_FS_XATTR的值为’y’,则xattr.o就是ext2.o的一部分。 
  
4、  库文件目标 - lib-y 
  
所有列在lib-y中的对像都被组合到一个单独的库中。既列在obj-y中又列在lib-y中的对像不会被包含到库中。因为不管怎样,它们都是可访问的。为了保持一致,列在lib-m中的对像会被包含到lib.a。 
  
       Example: 
              #arch/i386/lib/Makefile 
              lib-y    := checksum.o delay.o 
  
此处基于checksum.o和delay.o创建了库lib.a. 
  
5、  向下进入目录 
  
一个Makefile仅负责在它自己的目录中编译文件。子目录中的文件由子目录中的Makefile负责编译。如果你告诉了编译系统这些子目录,它会自动在子目录中递归调用make。 
  
ext2放在了一个单独的目录中,在fs/目录下的Makefile用正面的赋值告诉kbuild向下进入目录 
  
eg: 
              #fs/Makefile 
              obj-$(CONFIG_EXT2_FS) += ext2/ 
  
如果CONFIG_EXT2_FS的值是’y’(built-in)或’m’(modular),对应的obj-变量就会被设置,kbuild向下进入ext2目录。
  
kbuild只是通过这个信息决定要访问哪个目录,子目录中的Makefile指定什么是modules、什么是built-in。 
  
6、编译flags 
  
    EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS 
  
所有EXTRA_变量只用在它的定义所在的那个kbuild makefile,它们被用于kbuild makefile中所有命令的执行 
  
$(EXTRA_CFLAGS)指定了用$(CC)编译c文件时的选项。 
  
$(EXTRA_AFLAGS)是每个目录在编译汇编源文件时的选项。 
  
$(EXTRA_LDFLAGS) 和 $(EXTRA_ARFLAGS)是用于$(LD)和$(AR)的选项。 
  
       Example: 
              #arch/m68k/fpsp040/Makefile 
              EXTRA_LDFLAGS := -x 
  
    CFLAGS_$@, AFLAGS_$@ 
  
CFLAGS_$@ 和AFLAGS_$@ 只在当前kbuild makefile的命令中使用。 
  
$(CFLAGS_$@)为$(CC)指定了每个文件的选项。$@指定了使用它的文件。 
  
       Example: 
              # drivers/scsi/Makefile 
              CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF 
              CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ / 
                                 -DGDTH_STATISTICS 
              CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM 
  
这三行为aha152.o、gdth.o和seagate.o指定了编译选项。 
  
$(AFLAGS_$@)对于汇编源文件有类似的作用 
  
       Example: 
              # arch/arm/kernel/Makefile 
              AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional 
              AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) –traditional 
  
8、对依赖的追踪 
  
Kbuild追踪下面的依赖: 
  
1)、所有必备的文件(*.c和*.h) 
2)、用在所有必备文件中的CONFIG_选项 
3)、用于编译目标的命令行 
  
因此,如果改变了$(CC)的选项,所有受影响的文件都会被重新编译。 
  
9、特殊规则 
  
如果kbuild的基本组织没提供必要的支持,特殊规则就会被使用。典型的例子就是在编译过程中产生头文件。另一个例子就是体系结构相关的Makefile,为了准备启动映像,它需要特殊的规则。 
  
Kbuild不在Makefile所在的目录中执行,所以所有的特殊规则应拱必备文件和目标文件的相对路径。定义特殊规则时要用到两个变量: 
  
$(src) 
$(src)是指向Makefile所在目录的相对路径。涉及到源目录树中的文件总会用到$(src)。 
  
$(obj) 
$(obj)是指向保存目标的目录的相对路径。涉及到生成文件时总会用到$(obj)。 
  
       Example: 
              #drivers/scsi/Makefile 
              $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl 
                     $(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl 
  
10、$(CC)支持函数 
  
内核可能用好几个不同版本的$(CC)进行编译,每个版本都支持一组唯一的特征和选项。kbuild提供了基本的支持用于检测有效的$(CC)选项。 
  
as-option 
as-option用于检测$(CC)是否支持给定式的选项(在编译汇编文件*.S时)。如果不支持第一个选项,将会指定一个可供选择的第二选项。 
  
       Example: 
              #arch/sh/Makefile 
              cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) 
  
在上例中,如果$(CC)支持-Wa$(comma)-isa=$(isa-y),cflags-y就等于-Wa$(comma)-isa=$(isa-y)。第二个参数是可选的,如果 不支持第一个参数,而又提供了第二个参数,那么第二个参数就会被使用。 
  
ld-option 
ld-option用于在链接时检测$(CC)是否支持给定的选项。如果不支持第一个,可能会指定一个可选的第二选项。 
  
as-instr 
as-instr检测汇编器是否报告一个特殊指令并输出选项1或选项2。 
  
cc-option 
cc-option用来检测$(CC)是否支持一个给定式的选项,并且不支持一个可选的第二选项。 
  
       Example: 
              #arch/i386/Makefile 
              cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586) 
  
上例中,如果$(CC)支持,cflags-y会被赋值为选项-march=pentium-mmx,否则赋值为-march=i586。对于cc-option,第二个参数是可选的,如果被优化了,当不支持第一个选项时,cflags-y将不会被赋值。 
  
cc-option-yn 
cc-option-yn检测gcc是否支持一个给定的选项,如果支持,返回’y’,否则,返回’n’。 
  
       Example: 
              #arch/ppc/Makefile 
              biarch := $(call cc-option-yn, -m32) 
              aflags-$(biarch) += -a32 
              cflags-$(biarch) += -m32 
  
cc-option-align 
gcc 3.0及其以上的版本改变了选项的类型,这些选项用于指定函数、循环等的排列。当被用作排列选项的前缀时,$(cc-option-align)会选择正确的前缀 
  
       gcc < 3.00 
              cc-option-align = -malign 
       gcc >= 3.00 
              cc-option-align = -falign 
  
       Example: 
              CFLAGS += $(cc-option-align)-functions=4 
  
上例中,gcc >=3.00时,使用-falign-functions=4。gcc < 3.00时,使用用-malign-functions=4. 
  
cc-version 
cc-version返回$(CC)编译器版本的数字版本。 
  
cc-ifversion 
cc-ifversion检测$(CC)的版本,如果版本表达式为真,其返回值就是最后一个参数。 
  
三、             主机程序支持 
  
Kbuild支持在主机上编译生成可执行文件,用于编译阶段。为了使用一个主机可执行程序,需要如下两步: 
  
第一步,告诉kbuild存在一个主机程序。这是利用变量hostprogs-y来做的 
  
第二步,给这个可执行程序添加一个直接的依赖。可以用两种方法做到:在规则中添加依赖或者利用变量$(always)添加。 
  
这两种可能会在下面描述。 
  
1、  简单主机程序 
  
有些情况下,需要在主机上编译并运行一个程序。下面这行告诉kbuild程序bin2hex将在主机上被编译。 
  
       Example: 
              hostprogs-y := bin2hex 
  
上例中,kbuild假定bin2hex是由当前Makefile所在目录中的一个c文件bin2hex.c编译生成的。 
  
2、  组合主机程序 
  
主机程序可以通过组合目标来构建。$(<executable>-objs)列出了所有对像,这些对像被链接成最终的可执行程序。 
  
Example: 
              #scripts/lxdialog/Makefile 
              hostprogs-y   := lxdialog 
              lxdialog-objs := checklist.o lxdialog.o 
  
3、  定义共享库 
  
Kbuild提供对共享库的支持,但用法会受限制。下例中,用libkconfig.so共享库链接生成可执行文件conf. 
  
       Example: 
              #scripts/kconfig/Makefile 

抱歉!评论已关闭.