KBUILD系统原理分析
$(AFLAGS_$@) 也类似,只不是是针对汇编语言的。
# arch/arm/kernel/Makefile
AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
2.2.7跟踪依赖
Kbuild 跟踪在以下方面依赖:
1) 所有要参与编译的文件(所有的.c 和.h文件) 2) 在参与编译文件中所要使用的 CONFIG_ 选项 3) 用于编译目标的命令行
因此,如果你改变了 $(CC) 的选项,所有受影响的文件都要重新编译。
2.2.8 特殊规则
特殊规则就是那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) -DCHIP=810 - < $< | ... $(src)/script_asm.pl
这就是一个特殊规则,遵守着make所要求的普通语法。目标文件依赖于两个源文件。用$(obj)来定位目标文件,用$(src)来定位源文件(因为它们不是我们生成的文件)。
2.2.9 $(CC) 支持的函数
内核可能由多个不同版本的$(CC)编译,而每个版本都支持一不同的功能集与选项集。Kbuild提供了检查 $(CC) 可用选项的基本功能。$(CC)一般情况下是gcc编译器,但也可以使用其它编译器来代替gcc。
as-option
as-option,当编译汇编文件(*.S)时,用来检查 $(CC) 是否支持特定选项。如果第一个选项不支持的话,可选的第二个选项可以用来指定。
#arch/sh/Makefile
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
11
KBUILD系统原理分析
在上面的例子里,如果 $(CC) 支持选项 -Wa$(comma)-isa=$(isa-y),cflags-y就会被赋予该值。第二个参数是可选的,当第一个参数不支持时,就会使用该值。
ld-option
ld-option,当联接目标文件时,用来检查 $(CC) 是否支持特定选项。如果第 一个选项不支持的话,可选的第二个选项可以用来指定。 #arch/i386/kernel/Makefile
vsyscall-flags += $(call ld-option, -Wl$(comma)--hash-style=sysv)
在上面的例子中,如果 $(CC)支持选项 -Wl$(comma)--hash-style=sysv,ld-option就会被赋予该值。第二个参数是可选的,当第一个参数不支持时,就会使用该值。
cc-option
cc-option,用来检查 $(CC) 是否支持特定选项,并且不支持使用可选的第二项。 #arch/i386/Makefile
cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)
在上面的例子中,如果 $(CC)支持选项 -march=pentium-mmx,cc-option就会被赋予该值,否则就赋 -march-i586。cc-option的第二个参数是可选的。如果忽略的话,当第一个选项不支持时,cflags-y 不会被赋值。
cc-option-yn
cc-option-yn,用来检查 gcc 是否支持特定选项,返回'y'支持,否则为'n'。
#arch/ppc/Makefile
biarch := $(call cc-option-yn, -m32) aflags-$(biarch) += -a32 cflags-$(biarch) += -m32
在上面的例子里,当 $(CC) 支持 -m32选项时,$(biarch)设置为y。当 $(biarch) 为y时,扩展的 $(aflags-y) 和 $(cflags-y)变量就会被赋值为-a32 和 -m32。
cc-option-align
gcc版本大于3.0时,改变了函数,循环等用来声明内存对齐的选项。当用到对齐选项时,$(cc-option-align) 用来选择正确的前缀:
gcc < 3.00
cc-option-align = -malign gcc >= 3.00
cc-option-align = -falign 例子:
CFLAGS += $(cc-option-align)-functions=4
在上面的例子中,选项 -falign-funcions=4 被用在gcc >= 3.00的时候。对于小于3.00时, 使用 -malign-funcions=4 。
12
KBUILD系统原理分析
cc-version
cc-version以数学形式返回 $(CC) 编译器的版本号。其格式是:
#arch/i386/Makefile cflags-y += $(shell \\
if [ $(call cc-version) -ge 0300 ] ; then \\ echo \ fi ;
在上面的例子中,-mregparm=3只会在gcc的版本号大于等于3.0的时候使用。
cc-ifversion
cc-ifversion测试 $(CC) 的版本号,如果版本表达式为真,就赋值为最后的参数。 #fs/reiserfs/Makefile
EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0402, -O1)
在这个例子中,如果 $(CC) 的版本小于4.2,EXTRA_CFLAGS就被赋值 -O1。cc-ifversion 可使用所有的shell 操作符:-eq,-ne,-lt,-le,-gt,和-ge。第三个参数可以像上面例子一样是个文本,但也可以是个扩展的变量或宏。
2.3 本机程序支持
Kbuild 支持编译那些将在编译阶段使用的可执行文件。为了使用该可执行文件,要将编译分成二个阶段。
第一阶段是告诉Kbuild存在哪些可执行文件。这是通过变量 hostprogs-y来完成的。 第二阶段是添加一个对可执行文件的显性依赖。有两种方法:增加依赖关系到一个规则中,或是利用变量 $(always)。以下是详细叙述.
2.3.1单的本机程序
在编译内核时,有时会需要编译并运行一个程序。下面这行就告诉了kbuild,程序bin2hex应该在本机上编译。
hostprogs-y := bin2hex
在上面的例子中,Kbuild假设bin2hex是由一个与其在同一目录下,名为 bin2hex.c 的C语言源文件编译而成的。
2.3.2复合的本机程序
本机程序可以由多个文件编译而成。所使用的语法与内核的相应语法很相似。$(
#scripts/lxdialog/Makefile
13
KBUILD系统原理分析
hostprogs-y := lxdialog
lxdialog-objs := checklist.o lxdialog.o
扩展名为.o的文件是从相应的.c文件编译而来的。在上面的例子中,checklist.c 编译成了checklist.o,lxdialog.c编译成了lxdialog.o。最后,两个.o文件联接成了一可执行文件,lxdialog。
注意:语法
2.3. 定义共享库
扩展名为so的文件称为共享库,被编译成位置无关对象。Kbuild也支持共享库,但共享库的使用很有限。在下面的例子中,libconfig.so共享库用来联接到可执行文件 conf中。
#scripts/kconfig/Makefile hostprogs-y := conf
conf-objs := conf.o libkconfig.so libkcofig-objs := expr.o type.o
共享库文件经常要求一个相应的 -objs,在上面的例子中,共享库libkconfig是由 expr.o 和 type.o两个文件组成的。expr.o 和 type.o 将被编译成位置无关码,然后联接成共享库文件 libkconfig.so。C++并不支持共享库。
2.3.4使用用C++编写的本机程序
kbuild也支持用C++编写的本机程序。在此专门介绍是为了支持kconfig,并且在一般情况下不推荐使用。
#scripts/kconfig/Makefile hostprogs-y := qconf qconf-cxxobjs := qconf.o
在上面的例子中,可执行文件是由C++文件 qconf.cc编译而成的,由$(qconf-cxxobjs)来标识。
如果qconf是由.c和.cc一起编译的,那么就需要专门来标识这些文件了。 #scripts/kconfig/Makefile hostprogs-y := qconf qconf-cxxobjs := qconf.o qconf-objs := check.o
2.3.5 控制本机程序的编译选项
当编译本机程序时,有可能使用到特殊选项。程序经常是利用$(HOSTCC)编译,其选项在 $(HOSTCFLAGS)变量中。可通过使用变量 HOST_EXTRACFLAGS,影响所有在Makefile文件中要创建的主机程序。
#scripts/lxdialog/Makefile
HOST_EXTRACFLAGS += -I/usr/include/ncurses 为一单个文件设置选项,可按形式进行: #arch/ppc64/boot/Makefile
14
KBUILD系统原理分析 HOSTCFLAGS_pinggyback.o := -DKERNELBASE=$(KERNELBASE) 同样也可以给联接器声明一特殊选项。 #scripts/kconfig/Makefile
HOSTLOADLIBES_qconf := -L$(QTDIR)/lib
当联接qconf时,将会向联接器传递附加选项 \。
2.3.6 编译主机程序时
Kbuild只在需要时编译主机程序。有两种方法: (1) 在一具体的规则中显性列出所需要的文件,例子: #drivers/pci/Makefile hostprogs-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/Makefile hostprogs-y := lxdialog always := $(hostprogs-y)
这就是告诉Kbuild,即使没有在规则中声明,也要编译 lxdialog。
2.3.7 使用 hostprogs-$(CONFIG_FOO)
一个典型的Kbuild模式如下: #scripts/Makefile
hostprogs-$(CONFIG_KALLSYMS) += kallsyms
Kbuild 知道 'y' 是编译进内核,而 'm' 是编译成模块。所以,如果配置符号是'm',Kbuild仍然会编译它。换句话说,Kbuild处理 hostprogs-m 与hostprogs-y 的方式是完全一致的。只是,如果不用 CONFIG,最好用hostprogs-y。
2.4 build清理(clean)
\删除几乎所有的在编译内核时生成的文件,包括了主机程序在内。
Kbuild 通过列表 $(hostprogs-y),$(hostprogs-m),$(always),$(extra-y) 和$(targets) 知道所要编译的目标。这些目标文件都会被 \删除。另外,在\还会删除匹配 \,\的文件,以及由 Kbuild生成的辅助文件。辅助文件由 Kbuild Makefile 中的 $(clean-files) 指明。例子:
#drivers/pci/Makefile
clean-files := devlist.h classlist.h
15