Linux 2.6 Makefile system

Linux kernel的编译系统,结构性很好,这里是学习的一些体会和一些转载。理解的可能有错误,将来学习的时候再补充。

 

1. 编译系统有配置和编译两部分。我们编kernel时输入的make menuconfig是在执行配置,make -j10 vmlinux是在执行编译。配置系统依赖于Kconfig文件,可以用命令find. -name "Kconfig" -exec grep -l xxx {} /; 来查找你关心的配置在哪个文件里。编译系统依赖于各个层次的Makefile。配置系统和编译系统的相关纽带是根目录下的.config文件和include/linux/autoconfig.h文件。它们是配置系统最后生成的文件,编译系统包含.config到根目录下的Makefile,然后在一层一层的传下去,include/linux/autoconfig.h被包含进源代码中。整个编译和配置系统统称Kbuild系统,google “Kbuild 系统" 应该可以找到很多相关介绍。

2. 书写 Kconfig文件有简单的语法,可以参考今天转的前面的那篇文章。也可以参考kernel/Document下面的文档

3. .config被包含进Makefile系统,也就是给Makefile里的很多CONFIG_XXX_XXX赋了值。Makefile里可以根据这些赋值来影响obj-$(CONFIG_XXX_XXX), lib-,ccflag-, head-, core-,asflag- 等的值,并影响如何编译和连接,可以参考linux/scripts/Makefile.build这个文件。就obj-$()来说,可见它会影响build-in.o->builtin-target->targets targets有被根目录下的Makefile使用到。

4. 在编写kernel功能代码的时候,书写它的Makefile,要用到obj-$(CONFIG_XXX_XXX)=xxx.o 再把这个功能模块的obj-$(CONFIG_XXX_XXX) 添加到它上一层的Makefile里,比如如果把这个功能模块放在driver目录下,就把它添加到driver/Makefile的driver-$()+=obj-$(CONFIG_XXX_XXX)里。并写一个Kconfig文件,把写的Kconfig文件source到上一层的Kconfig里。这样就可以将新模块融入到kernel的结构里了。

5. head-y里的文件是放在vmlinux的头部的。arch/mips/Makefile里有生成vmlinux后的后期处理功能代码。obj-y=xxx.o出现的顺序影响代码的执行结果,因为它们先连接先执行。

6. 对稳定性有要求的,用-O2, 桌面系统可以用-O3, 如果很在乎编辑结果大小(嵌入式???not any more???)用-Os。具体含义可以参考man make

 

下面这篇文章对Makefile系统的分析很好。

我是从http://blogold.chinaunix.net/u1/55630/showart_509809.html转载的。

后面是英文的原版,转自http://www.ravnborg.org/kbuild/makefiles.html

第3篇文章从另一些方面介绍了Makefile系统,没细看。

 

Linux内核Makefile文件

--译自Linux2.6.x Kernel Makefiles

本文档描述了linux内核的makefile文件。
=== 目录
=== 1 概述
=== 2 角色分工
=== 3 内核编译文件
--- 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 特殊规则
=== 4 辅助程序
--- 4.1 简单辅助程序
--- 4.2 组合辅助程序
--- 4.3 定义共享库
--- 4.4 C++语言使用方法
--- 4.5 辅助程序编译控制选项
--- 4.6 何时建立辅助程序
--- 4.7 使用hostprogs-$(CONFIG_FOO)
=== 5 编译清除机制
=== 6 体系Makefile文件
--- 6.1 变量设置
--- 6.2 增加预设置项
--- 6.3 目录表
--- 6.4 引导映像
--- 6.5 编译非内核目标
--- 6.6 编译引导映像命令
--- 6.7 定制编译命令
--- 6.8 预处理连接脚本
--- 6.9 $(CC)支持功能
=== 7 Kbuild变量
=== 8 Makefile语言
=== 9 Credits
=== 10 TODO

=== 1 概述
Makefile包括五部分:
Makefile 顶层Makefile文件
.config 内核配置文件
arch/$(ARCH)/Makefile 机器体系Makefile文件
scripts/Makefile.* 所有内核Makefiles共用规则
kbuild Makefiles 其它makefile文件
通过内核配置操作产生.config文件,顶层Makefile文件读取该文件的配置。顶层Makefile文件负责产生两个主要的程序:vmlinux (内核image)和模块。顶层Makefile文件根据内核配置,通过递归编译内核代码树子目录建立这两个文件。顶层Makefile文件文本一个名为arch/$(ARCH)/Makefile的机器体系makefile文件。机器体系Makefile文件为顶层makefile文件提供与机器相关的信息。每一个子目录有一个makefile文件,子目录makefile文件根据上级目录makefile文件命令启动编译。这些makefile使用.config文件配置数据构建各种文件列表,并使用这些文件列表编译内嵌或模块目标文件。scripts/Makefile.*包含了所有的定义和规则,与makefile文件一起编译出内核程序。

=== 2 角色分工
人们与内核makefile存在四种不同的关系:
*用户* 用户使用"make menuconfig"或"make"命令编译内核。他们通常不读或编辑内核makefile文件或其他源文件。
*普通开发者* 普通开发者维护设备驱动程序、文件系统和网络协议代码,他们维护相关子系统的makefile文件,因此他们需要内核makefile文件整体性的一般知识和关于kbuild公共接口的详细知识。
*体系开发者* 体系开发者关注一个整体的体系架构,比如sparc或者ia64。体系开发者既需要掌握关于体系的makefile文件,也要熟悉内核makefile文件。
*内核开发者* 内核开发者关注内核编译系统本身。他们需要清楚内核makefile文件的所有方面。
本文档的读者对象是普通开发者和系统开发者。

=== 3 内核编译文件
内核中大多数makefile文件是使用kbuild基础架构的makefile文件。本章介绍kbuild的makefile中的语法。
3.1节“目标定义”是一个快速导引,后面各章有详细介绍和实例。
--- 3.1 目标定义
目标定义是makefile文件的主要部分(核心)。这些目标定义行定义了如何编译文件,特殊的兼容选项和递归子目录。
最简单的makefile文件只包含一行:
Example: obj-y += foo.o
这行告诉kbuild在该目录下名为foo.o的目标文件(object),foo.o通过编译foo.c或者foo.S而得到。
如果foo.o编译成一个模块,则使用obj-m变量,因此常见写法如下:
Example: obj-$(CONFIG_FOO) += foo.o
$(CONFIG_FOO)可以代表y(built-in对象)或m(module对象)。
如果CONFIG_FOO不是y或m,那么这个文件不会被编译和链接。
--- 3.2 内嵌对象 - obj-y
makefile文件将为编译vmlinux的目标文件放在$(obj-y)列表中,这些列表依赖于内核配置。
Kbuild编译所有的$(obj-y)文件,然后调用"$(LD) -r"合并这些文件到一个built-in.o文件中。built-in.o经过父makefile文件链接到vmlinux。$(obj-y)中的文件顺序很重要。列表中文件允许重复,文件第一次出现将被链接到built-in.o,后续出现该文件将被忽略。
链接顺序之所以重要是因为一些函数在内核引导时将按照他们出现的顺序被调用,如函数(module_init() / __initcall)。所以要牢记改变链接顺序意味着也要改变SCSI控制器的检测顺序和重数磁盘。
例如: #drivers/isdn/i4l/Makefile
# 内核ISDN子系统和设备驱动程序Makefile
# 每个配置项是一个文件列表
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
--- 3.3 可加载模块 - obj-m
$(obj-m)表示对象文件(object files)编译成可加载的内核模块。
一个模块可以通过一个源文件或几个源文件编译而成。makefile只需简单地它们加到$(obj-m)。
例如:#drivers/isdn/i4l/Makefile
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
注意:在这个例子中$(CONFIG_ISDN_PPP_BSDCOMP)含义是'm'。
如果内核模块通过几个源文件编译而成,使用以上同样的方法。
Kbuild需要知道通过哪些文件编译模块,因此需要设置一个$(<module_name>-objs)变量。
例如:#drivers/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)中的object文件,然后运行"$(LD) -r"将列表中文件生成isdn.o.
Kbuild使用后缀-objs、-y识别对象文件。这种方法允许makefile使用CONFIG_符号值确定一个object文件是否是另外一个object的组成部分。
例如: #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',则ext2.o只有xattr.o组成部分。
注意: 当然,当你将对象文件编译到内核时,以上语法同样有效。因此,如果CONFIG_EXT2_FS=y,Kbuild将先编译ext2.o文件,然后链接到built-in.o。
--- 3.4 导出符号目标
在makefile文件中没有特别导出符号的标记。
--- 3.5 库文件 - lib-y
obj-*中的object文件用于模块或built-in.o编译。object文件也可能编译到库文件中--lib.a。
所有罗列在lib-y中的object文件都将编译到该目录下的一个单一的库文件中。
包含在0bj-y中的object文件如果也列举在lib-y中将不会包含到库文件中,因为他们不能被访问。但lib-m中的object文件将被编译进lib.a库文件。
注意在相同的makefile中可以列举文件到buit-in内核中也可以作为库文件的一个组成部分。因此在同一个目录下既可以有built-in.o也可以有lib.a文件。
例如:#arch/i386/lib/Makefile
lib-y := checksum.o delay.o
这样将基于checksum.o、delay.o创建一个lib.a文件。
对于内核编译来说,lib.a文件被包含在libs-y中。将“6.3 目录表”。
lib-y通常被限制使用在lib/和arch/*/lib目录中。
--- 3.6 目录递归
makefile文件负责编译当前目录下的目标文件,子目录中的文件由子目录中的makefile文件负责编译。编译系统将使用obj-y和obj-m自动递归编译各个子目录中文件。
如果ext2是一个子目录,fs目录下的makefile将使用以下赋值语句是编译系统编译ext2子目录。
例如: #fs/Makefile
obj-$(CONFIG_EXT2_FS) += ext2/
如果CONFIG_EXT2_FS设置成'y(built-in)或'm'(modular),则对应的obj-变量也要设置,内核编译系统将进入ext2目录编译文件。
内核编译系统只使用这些信息来决定是否需要编译这个目录,子目录中makefile文件规定那些文件编译为模块那些是内核内嵌对象。
当指定目录名时使用CONFIG_变量是一种良好的做法。如果CONFIG_选项不为'y'或'm',内核编译系统就会跳过这个目录。
--- 3.7 编译标记
EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS
所有的EXTRA_变量只能使用在定义该变量后的makefile文件中。EXTRA_变量被makefile文件所有的执行命令语句所使用。
$(EXTRA_CFLAGS)是使用$(CC)编译C文件的选项。
例如: # drivers/sound/emu10k1/Makefile
EXTRA_CFLAGS += -I$(obj)
ifdef
DEBUG EXTRA_CFLAGS += -DEMU10K1_DEBUG
endif
定义这个变量是必须的,因为顶层makefile定义了$(CFLAGS)变量并使用该变量编译整个代码树。
$(EXTRA_AFLAGS)是每个目录编译汇编语言源文件的选项。
例如: #arch/x86_64/kernel/Makefile
EXTRA_AFLAGS := -traditional
$(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)用于每个目录的$(LD)和$(AR)选项。
例如: #arch/m68k/fpsp040/Makefile
EXTRA_LDFLAGS := -x
CFLAGS_$@, AFLAGS_$@
CFLAGS_$@和AFLAGS_$@只使用到当前makefile文件的命令中。
$(CFLAGS_$@)定义了使用$(CC)的每个文件的选项。$@部分代表该文件。
例如: # 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
这三行定义了aha152x.o、gdth.o和seagate.o文件的编译选项。
$(AFLAGS_$@)使用在汇编语言代码文件中,具有同上相同的含义。
例如: # arch/arm/kernel/Makefile
AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
--- 3.9 依赖关系
内核编译记录如下依赖关系:
1) 所有的前提文件(both *.c and *.h)
2) CONFIG_ 选项影响到的所有文件
3) 编译目标文件使用的命令行
因此,假如改变$(CC)的一个选项,所有相关的文件都要重新编译。
--- 3.10 特殊规则
特殊规则使用在内核编译需要规则定义而没有相应定义的时候。典型的例子如编译时头文件的产生规则。其他例子有体系makefile编译引导映像的特殊规则。特殊规则写法同普通的Make规则。
Kbuild(应该是编译程序)在makefile所在的目录不能被执行,因此所有的特殊规则需要提供前提文件和目标文件的相对路径。
定义特殊规则时将使用到两个变量:
$(src): $(src)是对于makefile文件目录的相对路径,当使用代码树中的文件时使用该变量$(src)。
$(obj): $(obj)是目标文件目录的相对路径。生成文件使用$(obj)变量。
例如: #drivers/scsi/Makefile
$(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl
$(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl
这就是使用普通语法的特殊编译规则。
目标文件依赖于两个前提文件。目标文件的前缀是$(obj), 前提文件的前缀是$(src)(因为它们不是生成文件)。

=== 4 辅助程序
内核编译系统支持在编译(compliation)阶段编译主机可执行程序。为了使用主机程序需要两个步骤:第一个步骤使用hostprogs-y变量告诉内核编译系统有主机程序可用。第二步给主机程序添加潜在的依赖关系。有两种方法,在规则中增加依赖关系或使用$(always)变量。具体描述如下。
--- 4.1 简单辅助程序
在一些情况下需要在主机上编译和运行主机程序。下面这行告诉kbuild在主机上建立bin2hex程序。
例如: hostprogs-y := bin2hex
Kbuild假定使用makefile相同目录下的单一C代码文件bin2hex.c编译bin2hex。
--- 4.2 组合辅助程序
主机程序也可以由多个object文件组成。定义组合辅助程序的语法同内核对象的定义方法。
$(<executeable>-objs)包含了所有的用于链接最终可执行程序的对象。
例如: #scripts/lxdialog/Makefile
hostprogs-y := lxdialog
lxdialog-objs := checklist.o lxdialog.o
扩展名.o文件都编译自对应的.c文件。在上面的例子中checklist.c编译成checklist.o,lxdialog.c编译为lxdialog.o。最后两个.o文件链接成可执行文件lxdialog。
注意:语法<executable>-y不能用于定义主机程序。
--- 4.3 定义共享库
扩展名为.so的对象是共享库文件,并且是位置无关的object文件。内核编译系统提供共享库使用支持,但使用方法有限制。在下面例子中libkconfig.so库文件被链接到可执行文件conf中。
例如: #scripts/kconfig/Makefile
hostprogs-y := conf
conf-objs := conf.o libkconfig.so
libkconfig-objs := expr.o type.o
共享库文件需要对应的-objs定义, 在上面例子中库libkconfig由两个对象组成:expr.o和type.o。expr.o和type.o将被编译为位置无关代码并被链接如libkconfig.so。共享库不支持C++语言。
--- 4.4 C++语言使用方法
内核编译系统提供了对C++主机程序的支持以用于内核配置,但不主张其它方面使用这种方法。
例如: #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
--- 4.5 辅助程序编译控制选项
当编译主机程序时仍然可以使用$(HOSTCFLAGS)设置编译选项传递给$(HOSTCC)。这些选项将影响所有使用变量HOST_EXTRACFLAG的makefile创建的主机程序。
例如: #scripts/lxdialog/Makefile
HOST_EXTRACFLAGS += -I/usr/include/ncurses
为单个文件设置选项使用下面方式:
例如: #arch/ppc64/boot/Makefile
HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)
也可以使用附加链接选项:
例如: #scripts/kconfig/Makefile
HOSTLOADLIBES_qconf := -L$(QTDIR)/lib
当链接qconf时将使用外部选项"-L$(QTDIR)/lib"。
--- 4.6 何时建立辅助程序
只有当需要时内核编译系统才会编译主机程序。有两种方式:
(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)
这样就告诉内核编译系统即使没有任何规则使用lxdialog也要编译它。
--- 4.7 使用hostprogs-$(CONFIG_FOO)
在Kbuild文件中典型模式如下:
例如: #scripts/Makefile
hostprogs-$(CONFIG_KALLSYMS) += kallsyms
对Kbuild来说'y'用于内嵌对象'm'用于模块。
因此如果config符号是'm',编译系统也将创建该程序。换句话说内核编译系统等同看待hostprogs-m和hostprogs-y。但如果不涉及到CONFIG符号仅建议使用hostprogs-y。

=== 5 编译清除机制
"make clean"命令删除在编译内核生成的大部分文件,例如主机程序,列举在 $(hostprogs-y)、$(hostprogs-m)、$(always)、$(extra-y)和$(targets)中目标文件都将被删除。代码目录数中的"*.[oas]"、"*.ko"文件和一些由编译系统产生的附加文件也将被删除。
附加文件可以使用$(clean-files)进行定义。
例如: #drivers/pci/Makefile
clean-files := devlist.h classlist.h
当执行"make clean"命令时, "devlist.h classlist.h"两个文件将被删除。内核编译系统默认这些文件与makefile具有相同的相对路径,否则需要设置以'/'开头的绝对路径。
删除整个目录使用以下方式:
例如: #scripts/package/Makefile
clean-dirs := $(objtree)/debian/
这样就将删除包括子目录在内的整个debian目录。如果不使用以'/'开头的绝对路径内核编译系统见默认使用相对路径。
通常内核编译系统根据"obj-* := dir/"进入子目录,但是在体系makefile中需要显式使用如下方式:
例如: #arch/i386/boot/Makefile
subdir- := compressed/
上面赋值语句指示编译系统执行"make clean"命令时进入compressed/目录。
在编译最终的引导映像文件的makefile中有一个可选的目标对象名称是archclean。
例如: #arch/i386/Makefile
archclean:
$(Q)$(MAKE) $(clean)=arch/i386/boot
当执行"make clean"时编译器进入arch/i386/boot并象通常一样工作。arch/i386/boot中的makefile文件可以使用subdir-标识进入更下层的目录。
注意1: arch/$(ARCH)/Makefile不能使用"subdir-",因为它被包含在顶层makefile文件中,在这个位置编译机制是不起作用的。
注意2: 所有列举在core-y、libs-y、drivers-y和net-y中的目录将被"make clean"命令清除。

=== 6 体系Makefile文件
在开始进入各个目录编译之前,顶层makefile文件设置编译环境和做些准备工作。顶层makefile文件包含通用部分,arch/$(ARCH)/Makefile包含该体系架构所需的设置。因此arch/$(ARCH)/Makefile会设置一些变量和少量的目标。
当编译时将按照以下大概步骤执行:
1) 配置内核 => 产生 .config文件
2) 保存内核版本到include/linux/version.h文件中
3) 符号链接include/asm to include/asm-$(ARCH)
4) 更新所有目标对象的其它前提文件
- 附加前提文件定义在arch/$(ARCH)/Makefile文件中
5) 递归进入init-* core* drivers-* net-* libs-*中的所有子目录和编译所有的目标对象
- 上面变量值都引用到arch/$(ARCH)/Makefile文件。
6) 链接所有的object文件生成vmlinux文件,vmlinux文件放在代码树根目录下。
最开始链接的几个object文件列举在arch/$(ARCH)/Makefile文件的head-y变量中。
7) 最后体系makefile文件定义编译后期处理规则和建立最终的引导映像bootimage。
- 包括创建引导记录
- 准备initrd映像和相关处理
--- 6.1 变量设置
LDFLAGS $(LD)一般选项
选项使用于链接器的所有调用中。通常定义emulation就可以了。
例如: #arch/s390/Makefile
LDFLAGS := -m elf_s390
注意: EXTRA_LDFLAGS和LDFLAGS_$@可以进一步订制使用选项,将第7章。
LDFLAGS_MODULE $(LD)链接模块的选项
LDFLAGS_MODULE通常设置$(LD)链接模块的.ko选项。
默认为"-r"即可重定位输出文件。
LDFLAGS_vmlinux $(LD)链接vmlinux选项
LDFLAGS_vmlinux定义链接最终vmlinux时链接器的选项。
LDFLAGS_vmlinux支持使用LDFLAGS_$@。
例如: #arch/i386/Makefile
LDFLAGS_vmlinux := -e stext
OBJCOPYFLAGS objcopy选项
当使用$(call if_changed,objcopy)转化a .o文件时,OBJCOPYFLAGS中的选项将被使用。
$(call if_changed,objcopy)经常被用作为vmlinux产生原始的二进制文件。
例如: #arch/s390/Makefile
OBJCOPYFLAGS := -O binary
#arch/s390/boot/Makefile
$(obj)/image: vmlinux FORCE $(call if_changed,objcopy)
在上面例子中$(obj)/image是vmlinux的二进制版本文件。$(call if_changed,xxx)
的使用方法见后。
AFLAGS $(AS)汇编选项
默认值见顶层Makefile文件
针对每个体系需要另外添加和修改它。
例如: #arch/sparc64/Makefile
AFLAGS += -m64 -mcpu=ultrasparc
CFLAGS $(CC)编译器选项
默认值见顶层Makefile文件
针对每个体系需要另外添加和修改它。
通常CFLAGS变量值取决于内核配置。
例如: #arch/i386/Makefile
cflags-$(CONFIG_M386) += -march=i386
CFLAGS += $(cflags-y)
许多体系Makefiles文件动态启动市场目标机器上的C编译器检测支持的选项:
#arch/i386/Makefile
...
cflags-$(CONFIG_MPENTIUMII) += $(call cc-option,/
-march=pentium2,-march=i686) ...
# Disable unit-at-a-time mode ...
CFLAGS += $(call cc-option,-fno-unit-at-a-time)
...
第一个例子当config选项是'y'时将被选中。
CFLAGS_KERNEL $(CC)编译built-in对象的选项
$(CFLAGS_KERNEL)包含外部C编译器选项编译本地内核代码。
CFLAGS_MODULE $(CC)编译模块选项
$(CFLAGS_MODULE)包含外部C编译器选项编译可加载内核代码。
--- 6.2 增加预设置项
prepare: 这个规则用于列举开始进入子目录编译前需要的前提文件。通常是些包含汇编常量的头文件。
例如:
#arch/s390/Makefile
prepare: include/asm-$(ARCH)/offsets.h
在这个例子中include/asm-$(ARCH)/offsets.h将在进入子目录前编译。
详见XXX-TODO文件描述了kbuild如何产生offset头文件。
--- 6.3 目录表
体系makefile文件和顶层makefile文件共同定义了如何建立vmlinux文件的变量。注意没有体系相关的模块对象定义部分:所有的模块对象都是体系无关的。
head-y, init-y, core-y, libs-y, drivers-y, net-y
$(head-y) 列举首先链接到vmlinux的对象文件。
$(libs-y) 列举了能够找到lib.a文件的目录。
其余的变量列举了能够找到内嵌对象文件的目录。
$(init-y) 列举的对象位于$(head-y)对象之后。
然后是如下位置秩序:
$(core-y), $(libs-y), $(drivers-y) 和 $(net-y)。
顶层makefile定义了所有同用目录,arch/$(ARCH)/Makefile文件只需增加体系相关的目录。
例如: #arch/sparc64/Makefile
core-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/目录。
内核编译系统无法在boot/目录下提供一种便捷的方法创建目标系统文件。因此arch/$(ARCH)/Makefile要调用make命令在boot/目录下建立目标系统文件。建议使用的方法是在arch/$(ARCH)/Makefile中设置调用,并且使用完整路径引用arch/$(ARCH)/boot/Makefile。
例如: #arch/i386/Makefile
boot := arch/i386/boot
bzImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
建议使用"$(Q)$(MAKE) $(build)=<dir>"方式在子目录中调用make命令。
没有定义体系目标系统文件的规则,但执行"make help"命令要列出所有目标系统文件,因此必须定义$(archhelp)变量。
例如: #arch/i386/Makefile
define
archhelp echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)'
endef
当执行不带参数的make命令时,将首先编译第一个目标对象。在顶层makefile中第一个目标对象是all:。
一个体系结构需要定义一个默认的可引导映像。
"make help"命令的默认目标是以*开头的对象。
增加新的前提文件给all目标可以设置不同于vmlinux的默认目标对象。
例如: #arch/i386/Makefile
all: bzImage
当执行不带参数的"make"命令时,bzImage文件将被编译。
--- 6.5 编译非内核目标
extra-y
extra-y定义了在当前目录下创建没有在obj-*定义的附加的目标文件。
在extra-y中列举目标是处于两个目的:
1) 是内核编译系统在命令行中检查变动情况
- 当使用$(call if_changed,xxx)时
2) 内核编译系统知道执行"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)
当这条规则被使用时它将检查哪些文件需要更新,或命令行被改变。后面这种情况将迫使重新编译编译选项被改变的执行文件。使用if_changed的目标对象必须列举在$(targets)中,否则命令行检查将失败,目标一直会编译。
赋值给$(targets)的对象没有$(obj)/前缀。
if_changed也可以和定制命令配合使用,见6.7"kbuild定制命令"。
注意: 一个常见错误是忘记了FORCE前导词。
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 :="语句,导致没有明显的原因目标文件被重新编译。
--- 6.7 定制编译命令
当执行带KBUILD_VERBOSE=0参数的编译命令时命令的简短信息会被显示。要让定制命令具有这种功能需要设置两个变量:
quiet_cmd_<command> - 将被显示的内容
cmd_<command> - 被执行的命令
例如: #
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_VERBOSE=0"命令编译$(obj)/bzImage目标时将显示:
BUILD arch/i386/boot/bzImage
--- 6.8 预处理连接脚本
当编译vmlinux映像时将使用arch/$(ARCH)/kernel/vmlinux.lds链接脚本。
相同目录下的vmlinux.lds.S文件是这个脚本的预处理的变体。内核编译系统知晓.lds文件并使用规则*lds.S -> *lds。
例如: #arch/i386/kernel/Makefile
always := vmlinux.lds
#Makefile
export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
$(always)赋值语句告诉编译系统编译目标是vmlinux.lds。$(CPPFLAGS_vmlinux.lds)赋值语句告诉编译系统编译vmlinux.lds目标的编译选项。
编译*.lds时将使用到下面这些变量:
CPPFLAGS : 定义在顶层Makefile
EXTRA_CPPFLAGS : 可以设置在编译的makefile文件中
CPPFLAGS_$(@F) : 目标编译选项。注意要使用文件全名。
--- 6.9 $(CC)支持功能
内核可能会用不同版本的$(CC)进行编译,每个版本有不同的性能和选项,内核编译系统提供基本的支持用于验证$(CC)选项。$(CC)通常是gcc编译器,但其它编译器也是可以。
cc-option cc-option 用于检测$(CC)是否支持给定的选项,如果不支持就使用第二个可选项。
例如: #arch/i386/Makefile
cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)
在上面例子中如果$(CC)支持-march=pentium-mmx则cflags-y等于该值,否则等于-march-i586。如果没有第二个可选项且第一项不支持则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用于定义functions、loops等边界对齐选项。
gcc < 3.00
cc-option-align = -malign
gcc >= 3.00
cc-option-align = -falign
例如:
CFLAGS += $(cc-option-align)-functions=4
在上面例子中对于gcc >= 3.00来说-falign-functions=4,gcc < 3.00版本使用-malign-functions=4。
cc-version cc-version返回$(CC)编译器数字版本号。
版本格式是<major><minor>,均为两位数字。例如gcc 3.41将返回0341。
当一个特定$(CC)版本在某个方面有缺陷时cc-version是很有用的。例如-mregparm=3在一些gcc版本会失败尽管gcc接受这个选项。
例如: #arch/i386/Makefile
GCC_VERSION := $(call cc-version)
cflags-y += $(shell /
if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;)
在上面例子中-mregparm=3只使用在版本大于等于3.0的gcc中。
=== 7 Kbuild变量
顶层Makefile文件导出下面这些变量:
VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION
这几个变量定义了当前内核版本号。很少体系体系Makefiles文件直接使用他们,常用$(KERNELRELEASE)代替。
$(VERSION)、$(PATCHLEVEL)和$(SUBLEVEL)定义了三个基本部分版本号,例如"2", "4",和"0"。这三个变量一直使用数值表示。
$(EXTRAVERSION)定义了更细的补钉号,通常是短横跟一些非数值字符串,例如"-pre4"。
KERNELRELEASE
$(KERNELRELEASE)是一个单一字符如"2.4.0-pre4",适合用于构造安装目录和显示版本字符串。一些体系文件使用它用于以上目的。
ARCH
这个变量定义了目标系统体系结构,例如"i386"、“arm"、"sparc". 一些内核编译文件测试$(ARCH)用于确定编译哪个文件。默认情况下顶层Makefile文件设置$(ARCH)为主机相同的系统体系。当交叉编译编译时,用户可以使用命令行改变$(ARCH)值:
make ARCH=m68k ...
INSTALL_PATH
这个变量定义了体系Makefiles文件安装内核映项和System.map文件的路径。
INSTALL_MOD_PATH, MODLIB
$(INSTALL_MOD_PATH)定义了模块安装变量$(MODLIB)的前缀。这个变量通常不在Makefile文件中定义,如果需要可以由用户添加。
$(MODLIB)定义了模块安装目录。
顶层Makefile定义$(MODLIB)为$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。用户可以使用命令行修改这个值。
=== 8 Makefile语言
内核Makefiles设计目标用于运行GNU Make程序。Makefiles仅使用GNU Make提到的特性,但使用了较多的GNU扩展部分。
GNU Make程序支持基本的列表处理功能。内核Makefiles文件结合"if"语句使用了简单的列表建立和维护功能。
GNU Make程序有两种赋值操作符:":="和"="。 ":="执行时立即计算右值并赋值给左值。"="类似公式定义,当每次使用左值要被使用时计算右值并赋给它。
一些情况中使用"="合适,而一些情况中使用":="才是正确选择。

 

Linux Kernel Makefiles

This document describes the Linux kernel Makefiles.

1. Overview

The Makefiles have five parts:

Makefile the top Makefile.
.config the kernel configuration file.
arch/$(ARCH)/Makefile the arch Makefile.
scripts/Makefile.* common rules etc. for all kbuild Makefiles.
kbuild Makefiles there are about 500 of these.

The top Makefile reads the .config file, which comes from the kernel configuration process.

The top Makefile is responsible for building two major products: vmlinux (the resident kernel image) and modules (any module files). It builds these goals by recursively descending into the subdirectories of the kernel source tree. The list of subdirectories which are visited depends upon the kernel configuration. The top Makefile textually includes an arch Makefile with the name arch/$(ARCH)/Makefile. The arch Makefile supplies architecture-specific information to the top Makefile.

Each subdirectory has a kbuild Makefile which carries out the commands passed down from above. The kbuild Makefile uses information from the .config file to construct various file lists used by kbuild to build any built-in or modular targets.

scripts/Makefile.* contains all the definitions/rules etc. that are used to build the kernel based on the kbuild makefiles.

2. Who does what

People have four different relationships with the kernel Makefiles.

Users

are people who build kernels. These people type commands such as "make menuconfig" or "make". They usually do not read or edit any kernel Makefiles (or any other source files).

Normal developers

are people who work on features such as device drivers, file systems, and network protocols. These people need to maintain the kbuild Makefiles for the subsystem they are working on. In order to do this effectively, they need some overall knowledge about the kernel Makefiles, plus detailed knowledge about the public interface for kbuild.

Arch developers

are people who work on an entire architecture, such as sparc or ia64. Arch developers need to know about the arch Makefile as well as kbuild Makefiles.

Kbuild developers

are people who work on the kernel build system itself. These people need to know about all aspects of the kernel Makefiles.

This document is aimed towards normal developers and arch developers.

3. The kbuild files

Most Makefiles within the kernel are kbuild Makefiles that use the kbuild infrastructure. This chapter introduces the syntax used in the kbuild makefiles. The preferred name for the kbuild files are Makefile but Kbuild can be used and if both a Makefile and a Kbuild file exists, then the Kbuildfile will be used.

Section 3.1 "Goal definitions" is a quick intro, further chapters provide more details, with real examples.

3.1. Goal definitions

Goal definitions are the main part (heart) of the kbuild Makefile. These lines define the files to be built, any special compilation options, and any subdirectories to be entered recursively.

The most simple kbuild makefile contains one line:

        obj-y += foo.o

This tells kbuild that there is one object in that directory, named foo.o. foo.o will be built from foo.c or foo.S.

If foo.o shall be built as a module, the variable obj-m is used. Therefore the following pattern is often used:

        obj-$(CONFIG_FOO) += foo.o

$(CONFIG_FOO) evaluates to either y (for built-in) or m (for module). If CONFIG_FOO is neither y nor m, then the file will not be compiled nor linked.

3.2. Built-in object goals - obj-y

The kbuild Makefile specifies object files for vmlinux in the obj-y lists. These lists depend on the kernel configuration.

Kbuild compiles all the obj-y files. It then calls$(LD) -r to merge these files into one built-in.o file. built-in.o is later linked into vmlinux by the parent Makefile.

The order of files in obj-y is significant. Duplicates in the lists are allowed: the first instance will be linked into built-in.o and succeeding instances will be ignored.

Link order is significant, because certain functions (module_init() / __initcall) will be called during boot in the order they appear. So keep in mind that changing the link order may e.g. change the order in which your SCSI controllers are detected, and thus your disks are renumbered.

        #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.o
        obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

3.3. Loadable module goals - obj-m

obj-m specify object files which are built as loadable kernel modules.

A module may be built from one source file or several source files. In the case of one source file, the kbuild makefile simply adds the file to obj-m.

        #drivers/isdn/i4l/Makefile
        obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

Note: In this example $(CONFIG_ISDN_PPP_BSDCOMP) evaluates to m

If a kernel module is built from several source files, you specify that you want to build a module in the same way as above.

Kbuild needs to know which the parts that you want to build your module from, so you have to tell it by setting an<module_name>-objs variable.

        #drivers/isdn/i4l/Makefile
        obj-$(CONFIG_ISDN) += isdn.o
        isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

In this example, the module name will be isdn.o. Kbuild will compile the objects listed in isdn-objs and then run$(LD) -r on the list of these files to generate isdn.o.

Kbuild recognises objects used for composite objects by the suffix-objs, and the suffix -y. This allows the Makefiles to use the value of a CONFIG_ symbol to determine if an object is part of a composite object.

        #fs/ext2/Makefile
        obj-$(CONFIG_EXT2_FS)        += ext2.o
        ext2-y                       := balloc.o bitmap.o
        ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o

In this example, xattr.o is only part of the composite object ext2.o if $(CONFIG_EXT2_FS_XATTR) evaluates to y.

Note: Of course, when you are building objects into the kernel, the syntax above will also work. So, if you have CONFIG_EXT2_FS=y, kbuild will build an ext2.o file for you out of the individual parts and then link this into built-in.o, as you would expect.

3.4. Objects which export symbols

No special notation is required in the makefiles for modules exporting symbols.

3.5. Library file goals - lib-y

Objects listed with obj-* are used for modules, or combined in a built-in.o for that specific directory. There is also the possibility to list objects that will be included in a library, lib.a. All objects listed with lib-y are combined in a single library for that directory. Objects that are listed in obj-y and additionally listed inlib-y will not be included in the library, since they will be accessible anyway. For consistency, objects listed in lib-m will be included in lib.a.

Note that the same kbuild makefile may list files to be built-in and to be part of a library. Therefore the same directory may contain both a built-in.o and a lib.a file.

        #arch/i386/lib/Makefile
        lib-y    := checksum.o delay.o

This will create a library lib.a based on checksum.o and delay.o. For kbuild to actually recognize that there is a lib.a being built, the directory shall be listed in libs-y. See also "6.3 List directories to visit when descending".

Use of lib-y is normally restricted to lib/ and arch/*/lib.

3.6. Descending down in directories

A Makefile is only responsible for building objects in its own
directory. Files in subdirectories should be taken care of by
Makefiles in these subdirs. The build system will automatically
invoke make recursively in subdirectories, provided you let it know of
them.
To do so, obj-y and obj-m are used.
ext2 lives in a separate directory, and the Makefile present in fs/
tells kbuild to descend down using the following assignment.
Example:
        #fs/Makefile
        obj-$(CONFIG_EXT2_FS) += ext2/
If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (modular)
the corresponding obj- variable will be set, and kbuild will descend
down in the ext2 directory.
Kbuild only uses this information to decide that it needs to visit
the directory, it is the Makefile in the subdirectory that
specifies what is modules and what is built-in.
It is good practice to use a CONFIG_ variable when assigning directory
names. This allows kbuild to totally skip the directory if the
corresponding CONFIG_ option is neither 'y' nor 'm'.

3.7. Compilation flags

EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS
All the EXTRA_ variables apply only to the kbuild makefile
where they are assigned. The EXTRA_ variables apply to all
commands executed in the kbuild makefile.
$(EXTRA_CFLAGS) specifies options for compiling C files with
$(CC).
Example:
        # drivers/sound/emu10k1/Makefile
        EXTRA_CFLAGS += -I$(obj)
        ifdef DEBUG
            EXTRA_CFLAGS += -DEMU10K1_DEBUG
        endif
This variable is necessary because the top Makefile owns the
variable $(CFLAGS) and uses it for compilation flags for the
entire tree.
$(EXTRA_AFLAGS) is a similar string for per-directory options
when compiling assembly language source.
Example:
        #arch/x86_64/kernel/Makefile
        EXTRA_AFLAGS := -traditional
$(EXTRA_LDFLAGS) and $(EXTRA_ARFLAGS) are similar strings for
per-directory options to $(LD) and $(AR).
Example:
        #arch/m68k/fpsp040/Makefile
        EXTRA_LDFLAGS := -x
CFLAGS_$@, AFLAGS_$@
CFLAGS_$@ and AFLAGS_$@ only apply to commands in current
kbuild makefile.
$(CFLAGS_$@) specifies per-file options for $(CC).  The $@
part has a literal value which specifies the file that it is for.
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
These three lines specify compilation flags for aha152x.o,
gdth.o, and seagate.o
$(AFLAGS_$@) is a similar feature for source files in assembly
languages.
Example:
        # arch/arm/kernel/Makefile
        AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
        AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional

3.8. Dependency tracking

Kbuild tracks dependencies on the following:
1) All prerequisite files (both *.c and *.h)
2) CONFIG_ options used in all prerequisite files
3) Command-line used to compile target
Thus, if you change an option to $(CC) all affected files will
be re-compiled.

3.9. Special Rules

Special rules are used when the kbuild infrastructure does
not provide the required support. A typical example is
header files generated during the build process.
Another example are the architecture-specific Makefiles which
need special rules to prepare boot images etc.
Special rules are written as normal Make rules.
Kbuild is not executing in the directory where the Makefile is
located, so all special rules shall provide a relative
path to prerequisite files and target files.
Two variables are used when defining special rules:
$(src)
    $(src) is a relative path which points to the directory
    where the Makefile is located. Always use $(src) when
    referring to files located in the src tree.
$(obj)
    $(obj) is a relative path which points to the directory
    where the target is saved. Always use $(obj) when
    referring to generated files.
Example:
        #drivers/scsi/Makefile
        $(obj)/53c8xx_d.h: $(src)/53c7,8xx.scr $(src)/script_asm.pl
                $(CPP) -DCHIP=810 - < $< | ... $(src)/script_asm.pl
This is a special rule, following the normal syntax
required by make.
The target file depends on two prerequisite files. References
to the target file are prefixed with $(obj), references
to prerequisites are referenced with $(src) (because they are not
generated files).

3.10. $(CC) support functions

The kernel may be built with several different versions of
$(CC), each supporting a unique set of features and options.
kbuild provide basic support to check for valid options for $(CC).
$(CC) is usually the gcc compiler, but other alternatives are
available.
as-option
    as-option is used to check if $(CC) -- when used to compile
    assembler (*.S) files -- supports the given option. An optional
    second option may be specified if the first option is not supported.
Example:
        #arch/sh/Makefile
        cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
In the above example, cflags-y will be assigned the option
-Wa$(comma)-isa=$(isa-y) if it is supported by $(CC).
The second argument is optional, and if supplied will be used
if first argument is not supported.
ld-option
    ld-option is used to check if $(CC) when used to link object files
    supports the given option.  An optional second option may be
    specified if first option are not supported.
Example:
        #arch/i386/kernel/Makefile
        vsyscall-flags += $(call ld-option, -Wl$(comma)--hash-style=sysv)
In the above example, vsyscall-flags will be assigned the option
-Wl$(comma)--hash-style=sysv if it is supported by $(CC).
The second argument is optional, and if supplied will be used
if first argument is not supported.
as-instr
    as-instr checks if the assembler reports a specific instruction
    and then outputs either option1 or option2
    C escapes are supported in the test instruction
cc-option
    cc-option is used to check if $(CC) supports a given option, and not
    supported to use an optional second option.
Example:
        #arch/i386/Makefile
        cflags-y += $(call cc-option,-march=pentium-mmx,-march=i586)
In the above example, cflags-y will be assigned the option
-march=pentium-mmx if supported by $(CC), otherwise -march=i586.
The second argument to cc-option is optional, and if omitted,
cflags-y will be assigned no value if first option is not supported.
cc-option-yn
     cc-option-yn is used to check if gcc supports a given option
     and return 'y' if supported, otherwise 'n'.
Example:
        #arch/ppc/Makefile
        biarch := $(call cc-option-yn, -m32)
        aflags-$(biarch) += -a32
        cflags-$(biarch) += -m32
In the above example, $(biarch) is set to y if $(CC) supports the -m32
option. When $(biarch) equals 'y', the expanded variables $(aflags-y)
and $(cflags-y) will be assigned the values -a32 and -m32,
respectively.
cc-option-align
    gcc versions >= 3.0 changed the type of options used to specify
    alignment of functions, loops etc. $(cc-option-align), when used
    as prefix to the align options, will select the right prefix:
    gcc < 3.00
            cc-option-align = -malign
    gcc >= 3.00
            cc-option-align = -falign
Example:
        CFLAGS += $(cc-option-align)-functions=4
In the above example, the option -falign-functions=4 is used for
gcc >= 3.00. For gcc < 3.00, -malign-functions=4 is used.
cc-version
    cc-version returns a numerical version of the $(CC) compiler version.
    The format is <major><minor> where both are two digits. So for example
    gcc 3.41 would return 0341.
    cc-version is useful when a specific $(CC) version is faulty in one
    area, for example -mregparm=3 was broken in some gcc versions
    even though the option was accepted by gcc.
Example:
        #arch/i386/Makefile
        cflags-y += $(shell /
        if [ $(call cc-version) -ge 0300 ] ; then /
                echo "-mregparm=3"; fi ;)
In the above example, -mregparm=3 is only used for gcc version greater
than or equal to gcc 3.0.
cc-ifversion
    cc-ifversion tests the version of $(CC) and equals last argument if
    version expression is true.
Example:
        #fs/reiserfs/Makefile
        EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0402, -O1)
In this example, EXTRA_CFLAGS will be assigned the value -O1 if the
$(CC) version is less than 4.2.
cc-ifversion takes all the shell operators:
-eq, -ne, -lt, -le, -gt, and -ge
The third parameter may be a text as in this example, but it may also
be an expanded variable or a macro.
cc-fullversion
    cc-fullversion is useful when the exact version of gcc is needed.
    One typical use-case is when a specific GCC version is broken.
    cc-fullversion points out a more specific version than cc-version does.
Example:
        #arch/powerpc/Makefile
        $(Q)if test "$(call cc-fullversion)" = "040200" ; then /
                echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; /
                false ; /
        fi
In this example for a specific GCC version the build will error out explaining
to the user why it stops.

4. Host Program support

Kbuild supports building executables on the host for use during the compilation stage. Two steps are required in order to use a host executable.

The first step is to tell kbuild that a host program exists. This is done utilising the variable hostprogs-y.

The second step is to add an explicit dependency to the executable. This can be done in two ways. Either add the dependency in a rule, or utilise the variable $(always). Both possibilities are described in the following.

4.1. Simple Host Program

In some cases there is a need to compile and run a program on the
computer where the build is running.
The following line tells kbuild that the program bin2hex shall be
built on the build host.
Example:
        hostprogs-y := bin2hex
Kbuild assumes in the above example that bin2hex is made from a single
c-source file named bin2hex.c located in the same directory as
the Makefile.

4.2. Composite Host Programs

Host programs can be made up based on composite objects.
The syntax used to define composite objects for host programs is
similar to the syntax used for kernel objects.
$(<executable>-objs) lists all objects used to link the final
executable.
Example:
        #scripts/lxdialog/Makefile
        hostprogs-y   := lxdialog
        lxdialog-objs := checklist.o lxdialog.o
Objects with extension .o are compiled from the corresponding .c
files. In the above example, checklist.c is compiled to checklist.o
and lxdialog.c is compiled to lxdialog.o.
Finally, the two .o files are linked to the executable, lxdialog.
Note: The syntax <executable>-y is not permitted for host-programs.

4.3. Defining shared libraries

Objects with extension .so are considered shared libraries, and
will be compiled as position independent objects.
Kbuild provides support for shared libraries, but the usage
shall be restricted.
In the following example the libkconfig.so shared library is used
to link the executable conf.
Example:
        #scripts/kconfig/Makefile
        hostprogs-y     := conf
        conf-objs       := conf.o libkconfig.so
        libkconfig-objs := expr.o type.o
Shared libraries always require a corresponding -objs line, and
in the example above the shared library libkconfig is composed by
the two objects expr.o and type.o.
expr.o and type.o will be built as position independent code and
linked as a shared library libkconfig.so. C++ is not supported for
shared libraries.

4.4. Using C++ for host programs

kbuild offers support for host programs written in C++. This was
introduced solely to support kconfig, and is not recommended
for general use.
Example:
        #scripts/kconfig/Makefile
        hostprogs-y   := qconf
        qconf-cxxobjs := qconf.o
In the example above the executable is composed of the C++ file
qconf.cc - identified by $(qconf-cxxobjs).
If qconf is composed by a mixture of .c and .cc files, then an
additional line can be used to identify this.
Example:
        #scripts/kconfig/Makefile
        hostprogs-y   := qconf
        qconf-cxxobjs := qconf.o
        qconf-objs    := check.o

4.5. Controlling compiler options for host programs

When compiling host programs, it is possible to set specific flags.
The programs will always be compiled utilising $(HOSTCC) passed
the options specified in $(HOSTCFLAGS).
To set flags that will take effect for all host programs created
in that Makefile, use the variable HOST_EXTRACFLAGS.
Example:
        #scripts/lxdialog/Makefile
        HOST_EXTRACFLAGS += -I/usr/include/ncurses
To set specific flags for a single file the following construction
is used:
Example:
        #arch/ppc64/boot/Makefile
        HOSTCFLAGS_piggyback.o := -DKERNELBASE=$(KERNELBASE)
It is also possible to specify additional options to the linker.
Example:
        #scripts/kconfig/Makefile
        HOSTLOADLIBES_qconf := -L$(QTDIR)/lib
When linking qconf, it will be passed the extra option
"-L$(QTDIR)/lib".

4.6. When host programs are actually built

Kbuild will only build host-programs when they are referenced
as a prerequisite.
This is possible in two ways:
(1) List the prerequisite explicitly in a special rule.
Example:
        #drivers/pci/Makefile
        hostprogs-y := gen-devlist
        $(obj)/devlist.h: $(src)/pci.ids $(obj)/gen-devlist
                ( cd $(obj); ./gen-devlist ) < $<
The target $(obj)/devlist.h will not be built before
$(obj)/gen-devlist is updated. Note that references to
the host programs in special rules must be prefixed with $(obj).
(2) Use $(always)
When there is no suitable special rule, and the host program
shall be built when a makefile is entered, the $(always)
variable shall be used.
Example:
        #scripts/lxdialog/Makefile
        hostprogs-y   := lxdialog
        always        := $(hostprogs-y)
This will tell kbuild to build lxdialog even if not referenced in
any rule.

4.7. Using hostprogs-$(CONFIG_FOO)

A typical pattern in a Kbuild file looks like this:
Example:
        #scripts/Makefile
        hostprogs-$(CONFIG_KALLSYMS) += kallsyms
Kbuild knows about both 'y' for built-in and 'm' for module.
So if a config symbol evaluate to 'm', kbuild will still build
the binary. In other words, Kbuild handles hostprogs-m exactly
like hostprogs-y. But only hostprogs-y is recommended to be used
when no CONFIG symbols are involved.

5. Kbuild clean infrastructure

"make clean" deletes most generated files in the obj tree where the kernel is compiled. This includes generated files such as host programs. Kbuild knows targets listed in $(hostprogs-y), $(hostprogs-m), $(always), $(extra-y) and $(targets). They are all deleted during "make clean". Files matching the patterns ".[oas]", ".ko", plus some additional files generated by kbuild are deleted all over the kernel src tree when "make clean" is executed.

Additional files can be specified in kbuild makefiles by use of $(clean-files).

Example:
        #drivers/pci/Makefile
        clean-files := devlist.h classlist.h

When executing "make clean", the two files "devlist.h classlist.h" will be deleted. Kbuild will assume files to be in same relative directory as the Makefile except if an absolute path is specified (path starting with /).

To delete a directory hierarchy use:

Example:
        #scripts/package/Makefile
        clean-dirs := $(objtree)/debian/

This will delete the directory debian, including all subdirectories. Kbuild will assume the directories to be in the same relative path as the Makefile if no absolute path is specified (path does not start with /).

Usually kbuild descends down in subdirectories due to "obj-* := dir/", but in the architecture makefiles where the kbuild infrastructure is not sufficient this sometimes needs to be explicit.

Example:
        #arch/i386/boot/Makefile
        subdir- := compressed/

The above assignment instructs kbuild to descend down in the directory compressed/ when "make clean" is executed.

To support the clean infrastructure in the Makefiles that builds the final bootimage there is an optional target named archclean:

Example:
        #arch/i386/Makefile
        archclean:
                $(Q)$(MAKE) $(clean)=arch/i386/boot

When "make clean" is executed, make will descend down in arch/i386/boot, and clean as usual. The Makefile located in arch/i386/boot/ may use the subdir- trick to descend further down.

Note 1: arch/$(ARCH)/Makefile cannot use "subdir-", because that file is included in the top level makefile, and the kbuild infrastructure is not operational at that point.

Note 2: All directories listed in core-y, libs-y, drivers-y and net-y will be visited during "make clean".

6. Architecture Makefiles

The top level Makefile sets up the environment and does the preparation, before starting to descend down in the individual directories. The top level makefile contains the generic part, whereas arch/$(ARCH)/Makefile contains what is required to set up kbuild for said architecture. To do so, arch/$(ARCH)/Makefile sets up a number of variables and defines a few targets.

When kbuild executes, the following steps are followed (roughly): 1) Configuration of the kernel => produce .config 2) Store kernel version in include/linux/version.h 3) Symlink include/asm to include/asm-$(ARCH) 4) Updating all other prerequisites to the target prepare: - Additional prerequisites are specified in arch/$(ARCH)/Makefile 5) Recursively descend down in all directories listed in init- core drivers- net- libs-* and build all targets. - The values of the above variables are expanded in arch/$(ARCH)/Makefile. 6) All object files are then linked and the resulting file vmlinux is located at the root of the obj tree. The very first objects linked are listed in head-y, assigned by arch/$(ARCH)/Makefile. 7) Finally, the architecture-specific part does any required post processing and builds the final bootimage. - This includes building boot records - Preparing initrd images and the like

6.1. Set variables to tweak the build to the architecture

LDFLAGS             Generic $(LD) options
Flags used for all invocations of the linker.
Often specifying the emulation is sufficient.
Example:
        #arch/s390/Makefile
        LDFLAGS         := -m elf_s390
Note: EXTRA_LDFLAGS and LDFLAGS_$@ can be used to further customise
the flags used. See chapter 7.
LDFLAGS_MODULE      Options for $(LD) when linking modules
LDFLAGS_MODULE is used to set specific flags for $(LD) when
linking the .ko files used for modules.
Default is "-r", for relocatable output.
LDFLAGS_vmlinux     Options for $(LD) when linking vmlinux
LDFLAGS_vmlinux is used to specify additional flags to pass to
the linker when linking the final vmlinux image.
LDFLAGS_vmlinux uses the LDFLAGS_$@ support.
Example:
        #arch/i386/Makefile
        LDFLAGS_vmlinux := -e stext
OBJCOPYFLAGS        objcopy flags
When $(call if_changed,objcopy) is used to translate a .o file,
the flags specified in OBJCOPYFLAGS will be used.
$(call if_changed,objcopy) is often used to generate raw binaries on
vmlinux.
Example:
        #arch/s390/Makefile
        OBJCOPYFLAGS := -O binary
#arch/s390/boot/Makefile
$(obj)/image: vmlinux FORCE
        $(call if_changed,objcopy)
In this example, the binary $(obj)/image is a binary version of
vmlinux. The usage of $(call if_changed,xxx) will be described later.
AFLAGS              $(AS) assembler flags
Default value - see top level Makefile
Append or modify as required per architecture.
Example:
        #arch/sparc64/Makefile
        AFLAGS += -m64 -mcpu=ultrasparc
CFLAGS              $(CC) compiler flags
Default value - see top level Makefile
Append or modify as required per architecture.
Often, the CFLAGS variable depends on the configuration.
Example:
        #arch/i386/Makefile
        cflags-$(CONFIG_M386) += -march=i386
        CFLAGS += $(cflags-y)
Many arch Makefiles dynamically run the target C compiler to
probe supported options:
#arch/i386/Makefile
...
cflags-$(CONFIG_MPENTIUMII)     += $(call cc-option,/
                                -march=pentium2,-march=i686)
...
# Disable unit-at-a-time mode ...
CFLAGS += $(call cc-option,-fno-unit-at-a-time)
...
The first example utilises the trick that a config option expands
to 'y' when selected.
CFLAGS_KERNEL       $(CC) options specific for built-in
$(CFLAGS_KERNEL) contains extra C compiler flags used to compile
resident kernel code.
CFLAGS_MODULE       $(CC) options specific for modules
$(CFLAGS_MODULE) contains extra C compiler flags used to compile code
for loadable kernel modules.

6.2. Add prerequisites to archprepare:

The archprepare: rule is used to list prerequisites that need to be
built before starting to descend down in the subdirectories.
This is usually used for header files containing assembler constants.
Example:
#arch/arm/Makefile
archprepare: maketools
In this example, the file target maketools will be processed
before descending down in the subdirectories.
See also chapter XXX-TODO that describe how kbuild supports
generating offset header files.

6.3. List directories to visit when descending

An arch Makefile cooperates with the top Makefile to define variables
which specify how to build the vmlinux file.  Note that there is no
corresponding arch-specific section for modules; the module-building
machinery is all architecture-independent.
head-y, init-y, core-y, libs-y, drivers-y, net-y
$(head-y) lists objects to be linked first in vmlinux.
$(libs-y) lists directories where a lib.a archive can be located.
The rest list directories where a built-in.o object file can be
located.
$(init-y) objects will be located after $(head-y).
Then the rest follows in this order:
$(core-y), $(libs-y), $(drivers-y) and $(net-y).
The top level Makefile defines values for all generic directories,
and arch/$(ARCH)/Makefile only adds architecture-specific directories.
Example:
        #arch/sparc64/Makefile
        core-y += arch/sparc64/kernel/
        libs-y += arch/sparc64/prom/ arch/sparc64/lib/
        drivers-$(CONFIG_OPROFILE)  += arch/sparc64/oprofile/

6.4. Architecture-specific boot images

An arch Makefile specifies goals that take the vmlinux file, compress
it, wrap it in bootstrapping code, and copy the resulting files
somewhere. This includes various kinds of installation commands.
The actual goals are not standardized across architectures.
It is common to locate any additional processing in a boot/
directory below arch/$(ARCH)/.
Kbuild does not provide any smart way to support building a
target specified in boot/. Therefore arch/$(ARCH)/Makefile shall
call make manually to build a target in boot/.
The recommended approach is to include shortcuts in
arch/$(ARCH)/Makefile, and use the full path when calling down
into the arch/$(ARCH)/boot/Makefile.
Example:
        #arch/i386/Makefile
        boot := arch/i386/boot
        bzImage: vmlinux
                $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
"$(Q)$(MAKE) $(build)=<dir>" is the recommended way to invoke
make in a subdirectory.
There are no rules for naming architecture-specific targets,
but executing "make help" will list all relevant targets.
To support this, $(archhelp) must be defined.
Example:
        #arch/i386/Makefile
        define archhelp
          echo  '* bzImage      - Image (arch/$(ARCH)/boot/bzImage)'
        endif
When make is executed without arguments, the first goal encountered
will be built. In the top level Makefile the first goal present
is all:.
An architecture shall always, per default, build a bootable image.
In "make help", the default goal is highlighted with a '*'.
Add a new prerequisite to all: to select a default goal different
from vmlinux.
Example:
        #arch/i386/Makefile
        all: bzImage
When "make" is executed without arguments, bzImage will be built.

6.5. Building non-kbuild targets

extra-y
extra-y specify additional targets created in the current
directory, in addition to any targets specified by obj-*.
Listing all targets in extra-y is required for two purposes:
1) Enable kbuild to check changes in command lines
   - When $(call if_changed,xxx) is used
2) kbuild knows what files to delete during "make clean"
Example:
        #arch/i386/kernel/Makefile
        extra-y := head.o init_task.o
In this example, extra-y is used to list object files that
shall be built, but shall not be linked as part of built-in.o.

6.6. Commands useful for building a boot image

Kbuild provides a few macros that are useful when building a
boot image.
if_changed
if_changed is the infrastructure used for the following commands.
Usage:
        target: source(s) FORCE
                $(call if_changed,ld/objcopy/gzip)
When the rule is evaluated, it is checked to see if any files
need an update, or the command line has changed since the last
invocation. The latter will force a rebuild if any options
to the executable have changed.
Any target that utilises if_changed must be listed in $(targets),
otherwise the command line check will fail, and the target will
always be built.
Assignments to $(targets) are without $(obj)/ prefix.
if_changed may be used in conjunction with custom commands as
defined in 6.7 "Custom kbuild commands".
Note: It is a typical mistake to forget the FORCE prerequisite.
Another common pitfall is that whitespace is sometimes
significant; for instance, the below will fail (note the extra space
after the comma):
        target: source(s) FORCE
#WRONG!#        $(call if_changed, ld/objcopy/gzip)
ld
    Link target. Often, LDFLAGS_$@ is used to set specific options to ld.
objcopy
    Copy binary. Uses OBJCOPYFLAGS usually specified in
    arch/$(ARCH)/Makefile.
    OBJCOPYFLAGS_$@ may be used to set additional options.
gzip
    Compress target. Use maximum compression to compress target.
Example:
        #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)
In this example, there are two possible targets, requiring different
options to the linker. The linker options are specified using the
LDFLAGS_$@ syntax - one for each potential target.
$(targets) are assigned all potential targets, by which kbuild knows
the targets and will:
        1) check for commandline changes
        2) delete target during make clean
The ": %: %.o" part of the prerequisite is a shorthand that
free us from listing the setup.o and bootsect.o files.
Note: It is a common mistake to forget the "target :=" assignment,
      resulting in the target file being recompiled for no
      obvious reason.

6.7. Custom kbuild commands

When kbuild is executing with KBUILD_VERBOSE=0, then only a shorthand
of a command is normally displayed.
To enable this behaviour for custom commands kbuild requires
two variables to be set:
quiet_cmd_<command>     - what shall be echoed
      cmd_<command>     - the command to execute
Example:
        #
        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'
When updating the $(obj)/bzImage target, the line
BUILD    arch/i386/boot/bzImage
will be displayed with "make KBUILD_VERBOSE=0".

6.8. Preprocessing linker scripts

When the vmlinux image is built, the linker script
arch/$(ARCH)/kernel/vmlinux.lds is used.
The script is a preprocessed variant of the file vmlinux.lds.S
located in the same directory.
kbuild knows .lds files and includes a rule *lds.S -> *lds.
Example:
        #arch/i386/kernel/Makefile
        always := vmlinux.lds
#Makefile
export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
The assignment to $(always) is used to tell kbuild to build the
target vmlinux.lds.
The assignment to $(CPPFLAGS_vmlinux.lds) tells kbuild to use the
specified options when building the target vmlinux.lds.
When building the *.lds target, kbuild uses the variables:
CPPFLAGS        : Set in top-level Makefile
EXTRA_CPPFLAGS  : May be set in the kbuild makefile
CPPFLAGS_$(@F)  : Target specific flags.
                  Note that the full filename is used in this
                  assignment.
The kbuild infrastructure for *lds file are used in several
architecture-specific files.

7. Kbuild Variables

The top Makefile exports the following variables:

VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION
These variables define the current kernel version.  A few arch
Makefiles actually use these values directly; they should use
$(KERNELRELEASE) instead.
$(VERSION), $(PATCHLEVEL), and $(SUBLEVEL) define the basic
three-part version number, such as "2", "4", and "0".  These three
values are always numeric.
$(EXTRAVERSION) defines an even tinier sublevel for pre-patches
or additional patches.  It is usually some non-numeric string
such as "-pre4", and is often blank.
KERNELRELEASE
$(KERNELRELEASE) is a single string such as "2.4.0-pre4", suitable
for constructing installation directory names or showing in
version strings.  Some arch Makefiles use it for this purpose.
ARCH
This variable defines the target architecture, such as "i386",
"arm", or "sparc". Some kbuild Makefiles test $(ARCH) to
determine which files to compile.
By default, the top Makefile sets $(ARCH) to be the same as the
host system architecture.  For a cross build, a user may
override the value of $(ARCH) on the command line:
make ARCH=m68k ...
INSTALL_PATH
This variable defines a place for the arch Makefiles to install
the resident kernel image and System.map file.
Use this for architecture-specific install targets.
INSTALL_MOD_PATH, MODLIB
$(INSTALL_MOD_PATH) specifies a prefix to $(MODLIB) for module
installation.  This variable is not defined in the Makefile but
may be passed in by the user if desired.
$(MODLIB) specifies the directory for module installation.
The top Makefile defines $(MODLIB) to
$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE).  The user may
override this value on the command line if desired.
INSTALL_MOD_STRIP
If this variable is specified, will cause modules to be stripped
after they are installed.  If INSTALL_MOD_STRIP is '1', then the
default option --strip-debug will be used.  Otherwise,
INSTALL_MOD_STRIP will used as the option(s) to the strip command.

8. Makefile language

The kernel Makefiles are designed to be run with GNU Make. The Makefiles use only the documented features of GNU Make, but they do use many GNU extensions.

GNU Make supports elementary list-processing functions. The kernel Makefiles use a novel style of list building and manipulation with few "if" statements.

GNU Make has two assignment operators, ":=" and "=". ":=" performs immediate evaluation of the right-hand side and stores an actual string into the left-hand side. "=" is like a formula definition; it stores the right-hand side in an unevaluated form and then evaluates this form each time the left-hand side is used.

There are some cases where "=" is appropriate. Usually, though, ":=" is the right choice.

9. Credits

Original version made by Michael Elizabeth Chastain, <mailto:mec@shout.net> Updates by Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> Updates by Sam Ravnborg <sam@ravnborg.org> Language QA by Jan Engelhardt <jengelh@gmx.de>

10. TODO

  • Describe how kbuild supports shipped files with _shipped.

  • Generating offset header files.

  • Add more variables to section 7?

Linux/Unix环境下的make和makefile详解
==========================================
Makefile 初探
==========================================
Linux
的内核设置文件有两个,一个是隐含的.config文件,嵌入到主Makefile中;另一个是include/linux/autoconf.h,嵌入
到各个c源文件中,他们由make config、make menuconfig、make
xconfig这些过程创建。几乎所有的源文件都会通过linux/config.h而嵌入autoconf.h,如果按照通常方法建立文件依赖关系
(.depend),只要更新过autoconf.h,就会造成所有原始码的重新编绎。
为了优化make过程,减少不必要的重新编
绎,Linux研发了专用的mkdep工具,用他来取代gcc来生成.depend文件。mkdep在处理源文件时,忽略linux/config.h这
样的头文件,识别源文件宏指令中具有"CONFIG_"特征的行。例如,如果有"#ifdef
CONFIG_SMP"这样的行,他就会在.depend文件中输出$(wildcard
/usr/src/linux/include/config/smp.h)。
include/config/下的文件是另一个工具
split-include从autoconf.h中生成,他利用autoconf.h中的CONFIG_标记,生成和mkdep相对应的文件。例如,如
果autoconf.h中有"#undef
CONFIG_SMP"这一行,他就生成include/config/smp.h文件,内容为"#undef
CONFIG_SMP"。这些文件名只在.depend文件中出现,内核源文件是不会嵌入他们的。每设置一次内核,运行split-include一次。
split-include会检查旧的子文件的内容,确定是不是要更新他们。这样,不管autoconf.h修改日期怎么,只要其设置不变,make就不
会重新编绎内核。
如果系统的编绎选项发生了变化,Linux也能进行增量编绎。为了做到这一点,make每编绎一个源文件时生成一个
flags文件。例如编绎sched.c时,会在相同的目录下生成隐含的.sched.o.flags文件。他是Makefile的一个片断,当make
进入某个子目录编绎时,会搜索其中的flags文件,将他们嵌入到Makefile中。这些flags代码测试当前的编绎选项和原来的是不是相同,如果相
同,就将自已对应的目标文件加入FILES_FLAGS_UP_TO_DATE列表,然后,系统从编绎对象表中删除他们,得到
FILES_FLAGS_CHANGED列表,最后,将他们设为目标进行更新。
下一步准备逐步深入的剖析Makefile代码。
==========================================
Makefile解读之二: sub-make
==========================================
Linux
各级内核原始码的子目录下都有Makefile,大多数Makefile要嵌入主目录下的Rule.make,Rule.make将识别各个
Makefile中所定义的一些变量。变量obj-y表示需要编绎到内核中的目标文件名集合,定义O_TARGET表示将obj-y连接为一个
O_TARGET名称的目标文件,定义L_TARGET表示将obj-y合并为一个L_TARGET名称的库文件。同样obj-m表示需要编绎成模块的目
标文件名集合。如果还需进行子目录make,则需要定义subdir-y和subdir-m。在Makefile中,用"obj-$
(CONFIG_BINFMT_ELF) += binfmt_elf.o"和"subdir-$(CONFIG_EXT2_FS) +=
ext2"这种形式自动为obj-y、obj-m、subdir-y、subdir-m添加文件名。有时,情况没有这么单纯,还需要使用条件语句个别对
待。Makefile中更有其他一些变量,如mod-subdirs定义了subdir-m以外的所有模块子目录。
Rules.make
是怎么使make进入子目录的呢?
先来看subdir-y是怎么处理的,在Rules.make中,先对subdir-y中的每一个文件名加上前缀"_subdir_"再进行排序生成
subdir-list集合,再以他作为目标集,对其中每一个目标产生一个子make,同时将目标名的前缀去掉得到子目录名,作为子make的起始目录参
数。subdir-m和subdir-y类似,但情况稍微复杂一些。由于subdir-y中可能有模块定义,因此利用mod-subdirs变量将
subdir-y中模块目录提取出来,再和subdir-m合成一个大的MOD_SUB_DIRS集合。subdir-m的目标所用的前缀是
"_modsubdir_"。
一点说明,子目录中的Makefile和Rules.make都没有嵌入.config文件,他是通过
主Makefile向下传递MAKEFILES变量完成的。MAKEFILES是make自已识别的一个变量,在执行新的Makefile之前,make
会首先加载MAKEFILES所指的文件。在主Makefile中他即指向.config。
==========================================
Makefile解读之三: 模块的版本化处理
==========================================

块的版本化是内核和模块接口之间进行严格类型匹配的一种方法。当内核设置了CONFIG_MODVERSIONS之后,make
dep操作会在include/linux/modules/目录下为各级Makefile中export-objs变量所对应的源文件生成扩展名为.
ver的文件。
例如对于kernel/ksyms.c,make用以下命令生成对应的ksyms.ver:
gcc -E -D__KERNEL__ -D__GENKSYMS__ ksyms.c | /sbin/genksyms -k 2.4.1 > ksyms.ver
-D__GENKSYMS__的作用是使ksyms.c中的EXPORT_SYMBOL宏不进行扩展。genksyms命令识别EXPORT_SYMBOL()中的函数名和对应的原型,再根据其原型计算出该函数的版本号。
例如ksyms.c中有一行:
EXPORT_SYMBOL(kmalloc);
kmalloc原型是:
void *kmalloc(size_t, int);
genksyms程式对应的输出为:
#define __ver_kmalloc 93d4cfe6
#define kmalloc _set_ver(kmalloc)
在内核符号表和模块中,kmalloc将变成kmalloc_R93d4cfe6。

生成完所有的.ver文件后,make将重建include/linux/modversions.h文件,他包含一系列#include指令行嵌入各
个.ver文件。在编绎内核本身export-objs中的文件时,make会增加一个"-DEXPORT_SYMTAB"编绎标志,他使源文件嵌入
modversions.h文件,将EXPORT_SYMBOL宏展开中的函数名字符串进行版本名扩展;同时,他也定义_set_ver()宏为一空操
作,使代码中的函数名不受其影响。
在编绎模块时,make会增加"-include=linux/modversion.h -DMODVERSIONS"编绎标志,使模块中代码的函数名得到相应版本扩展。

于生成.ver文件比较费时,make还为每个.ver创建了一个后缀为.stamp时戳文件。在make
dep时,如果其.stamp文件比源文件旧才重新生成.ver文件,否则只是更新.stamp文件时戳。另外,在生成.ver和
modversions.h文件时,make都会比较新文件和旧文件的内容,保持他们修改时间为最旧。
==========================================
Makefile解读之四: Rules.make的注释
==========================================
代码:
#
# This file contains rules which are shared between multiple Makefiles.
#
#
# False targets.
#
#
.PHONY: dummy
#
# Special variables which should not be exported
#
# 取消这些变量通过环境向make子进程传递。
unexport EXTRA_AFLAGS # as 的开关
unexport EXTRA_CFLAGS # cc 的开关
unexport EXTRA_LDFLAGS # ld 的开关
unexport EXTRA_ARFLAGS # ar 的开关
unexport SUBDIRS #
unexport SUB_DIRS # 编绎内核需进入的子目录,等于subdir-y
unexport ALL_SUB_DIRS # 所有的子目录
unexport MOD_SUB_DIRS # 编绎模块需进入的子目录
unexport O_TARGET # ld合并的输出对象
unexport ALL_MOBJS # 所有的模块名
unexport obj-y # 编绎成内核的文件集
unexport obj-m # 编绎成模块的文件集
unexport obj-n #
unexport obj- #
unexport export-objs # 需进行版本处理的文件集
unexport subdir-y # 编绎内核所需进入的子目录
unexport subdir-m # 编绎模块所需进入的子目录
unexport subdir-n
unexport subdir-
#
# Get things started.
#
first_rule: sub_dirs
$(MAKE) all_targets
# 在内核编绎子目录中过滤出能作为模块的子目录。
both-m := $(filter $(mod-subdirs), $(subdir-y))
SUB_DIRS := $(subdir-y)
# 求出总模块子目录
MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m))
# 求出总子目录
ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-))
#
# Common rules
#
# 将c文件编绎成汇编文件的规则,$@为目标对象。
%.s: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $ $@
# 将c文件编绎成目标文件的规则,$ $(dir $@)/.$(notdir $@).flags
# 汇编文件生成目标文件的规则。
%.o: %.s
$(AS) $(AFLAGS) $(EXTRA_CFLAGS) -o $@ $ $@
# 汇编文件生成目标文件的标准规则。
%.o: %.S
$(CC) $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$@) -c -o $@ $ $(dir $@)/.$(notdir $@).flags
endif # O_TARGET
#
# Rule to compile a set of .o files into one .a file
#
# 将obj-y组合成库L_TARGET的方法。
ifdef L_TARGET
$(L_TARGET): $(obj-y)
rm -f $@
$(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y)
@ ( \
echo ’ifeq ($(strip $(subst $(comma),:,$(EXTRA_ARFLAGS)
$(obj-y))),$$(strip $$(subst $$(comma),:,$$(EXTRA_ARFLAGS) $$(obj-y))))’ ;

echo ’FILES_FLAGS_UP_TO_DATE += $@’ ; \
echo ’endif’ \
) > $(dir $@)/.$(notdir $@).flags
endif
#
# This make dependencies quickly
#
# wildcard为查找目录中的文件名的宏。
fastdep: dummy
$(TOPDIR)/scripts/mkdep $(wildcard *.[chS] local.h.master) > .depend
ifdef ALL_SUB_DIRS
#
将ALL_SUB_DIRS中的目录名加上前缀_sfdep_作为目标运行子make,并将ALL_SUB_DIRS
通过
# 变量_FASTDEP_ALL_SUB_DIRS传递给子make。
$(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS))
_FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
endif
ifdef _FASTDEP_ALL_SUB_DIRS
#
和上一段相对应,定义子目录目标,并将目标名还原为目录名,进入该子目录make。
$(patsubst %,_sfdep_%,$(_FASTDEP_ALL_SUB_DIRS)):
$(MAKE) -C $(patsubst _sfdep_%,%,$@) fastdep
endif

#
# A rule to make subdirectories
#
# 下面2段完成内核编绎子目录中的make。
subdir-list = $(sort $(patsubst %,_subdir_%,$(SUB_DIRS)))
sub_dirs: dummy $(subdir-list)
ifdef SUB_DIRS
$(subdir-list) : dummy
$(MAKE) -C $(patsubst _subdir_%,%,$@)
endif
#
# A rule to make modules
#
# 求出有效的模块文件表。
ALL_MOBJS = $(filter-out $(obj-y), $(obj-m))
ifneq "$(strip $(ALL_MOBJS))" ""
# 取主目录TOPDIR到当前目录的路径。
PDWN=$(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
endif
unexport MOD_DIRS
MOD_DIRS := $(MOD_SUB_DIRS) $(MOD_IN_SUB_DIRS)
# 编绎模块时,进入模块子目录的方法。
ifneq "$(strip $(MOD_DIRS))" ""
.PHONY: $(patsubst %,_modsubdir_%,$(MOD_DIRS))
$(patsubst %,_modsubdir_%,$(MOD_DIRS)) : dummy
$(MAKE) -C $(patsubst _modsubdir_%,%,$@) modules
# 安装模块时,进入模块子目录的方法。
.PHONY: $(patsubst %,_modinst_%,$(MOD_DIRS))
$(patsubst %,_modinst_%,$(MOD_DIRS)) : dummy
$(MAKE) -C $(patsubst _modinst_%,%,$@) modules_install
endif
# make modules 的入口。
.PHONY: modules
modules: $(ALL_MOBJS) dummy \
$(patsubst %,_modsubdir_%,$(MOD_DIRS))
.PHONY: _modinst__
# 拷贝模块的过程。
_modinst__: dummy
ifneq "$(strip $(ALL_MOBJS))" ""
mkdir -p $(MODLIB)/kernel/$(PDWN)
cp $(ALL_MOBJS) $(MODLIB)/kernel/$(PDWN)
endif
# make modules_install 的入口,进入子目录安装。
.PHONY: modules_install
modules_install: _modinst__ \
$(patsubst %,_modinst_%,$(MOD_DIRS))
#
# A rule to do nothing
#
dummy:
#
# This is useful for testing
#
script:
$(SCRIPT)
#
# This sets version suffixes on exported symbols
# Separate the object into "normal" objects and "exporting" objects
# Exporting objects are: all objects that define symbol tables
#
ifdef CONFIG_MODULES
# list-multi列出那些由多个文件复合而成的模块;
# 从编绎文件表和模块文件表中过滤出复合模块名。
multi-used := $(filter $(list-multi), $(obj-y) $(obj-m))
# 取复合模块的构成表。
multi-objs := $(foreach m, $(multi-used), $($(basename $(m))-objs))
# 求出需进行编译的总模块表。
active-objs := $(sort $(multi-objs) $(obj-y) $(obj-m))
ifdef CONFIG_MODVERSIONS
ifneq "$(strip $(export-objs))" ""
# 如果有需要进行版本化的文件。
MODINCL = $(TOPDIR)/include/linux/modules
# The -w option (enable warnings) for genksyms will return here in 2.1
# So where has it gone?
#
# Added the SMP separator to stop module accidents between uniprocessor
# and SMP Intel boxes - AC - from bits by Michael Chastain
#
ifdef CONFIG_SMP
genksyms_smp_prefix := -p smp_
else
genksyms_smp_prefix :=
endif
# 从源文件计算版本文件的规则。
$(MODINCL)/%.ver: %.c
@if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $ $@.tmp’; \
$(CC) $(CFLAGS) -E -D__GENKSYMS__ $ $@.tmp; \
if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f
$@.tmp; \
else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
fi; touch $(MODINCL)/$*.stamp
#
将版本处理源文件的扩展名改为.ver,并加上完整的路径名,他们依赖于autoconf.h?br>?br>$(addprefix $(MODINCL)/,$(export-objs:.o=.ver)):
$(TOPDIR)/include/linux/autoconf.h
# updates .ver files but not modversions.h
# 通过fastdep,逐个生成export-objs对应的版本文件。
fastdep: $(addprefix $(MODINCL)/,$(export-objs:.o=.ver))
# updates .ver files and modversions.h like before (is this needed?)
# make dep过程的入口
dep: fastdep update-modverfile
endif # export-objs
# update modversions.h, but only if it would change
# 刷新版本文件的过程。
update-modverfile:
@(echo "#ifndef _LINUX_MODVERSIONS_H";\
echo "#define _LINUX_MODVERSIONS_H"; \
echo "#include "; \
cd $(TOPDIR)/include/linux/modules; \
for f in *.ver; do \
if [ -f $$f ]; then echo "#include "; fi; \
done; \
echo "#endif"; \
) > $(TOPDIR)/include/linux/modversions.h.tmp
@if [ -r $(TOPDIR)/include/linux/modversions.h ] && cmp -s
$(TOPDIR)/include/linux/modversions.h
$(TOPDIR)/include/linux/modversions.h.tmp; then \
echo $(TOPDIR)/include/linux/modversions.h was not updated; \
rm -f $(TOPDIR)/include/linux/modversions.h.tmp; \
else \
echo $(TOPDIR)/include/linux/modversions.h was updated; \
mv -f $(TOPDIR)/include/linux/modversions.h.tmp
$(TOPDIR)/include/linux/modversions.h; \
fi
$(active-objs): $(TOPDIR)/include/linux/modversions.h
else
# 如果没有设置版本化,modversions.h的内容。
$(TOPDIR)/include/linux/modversions.h:
@echo "#include " > $@
endif # CONFIG_MODVERSIONS
ifneq "$(strip $(export-objs))" ""
# 版本化目标文件的编绎方法。
$(export-objs): $(export-objs:.o=.c) $(TOPDIR)/include/linux/modversions.h
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c)
@ ( \
echo ’ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS)
$(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS)
$$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))’ ; \
echo ’FILES_FLAGS_UP_TO_DATE += $@’ ; \
echo ’endif’ \
) > $(dir $@)/.$(notdir $@).flags
endif
endif # CONFIG_MODULES
#
# include dependency files if they exist
#
# 嵌入源文件之间的依赖关系。
ifneq ($(wildcard .depend),)
include .depend
endif
# 嵌入头文件之间的依赖关系。
ifneq ($(wildcard $(TOPDIR)/.hdepend),)
include $(TOPDIR)/.hdepend
endif
#
# Find files whose flags have changed and force recompilation.
# For safety, this works in the converse direction:
# every file is forced, except those whose flags are positively
up-to-date.
#
# 已更新过的文件列表。
FILES_FLAGS_UP_TO_DATE :=
# For use in expunging commas from flags, which mung our checking.
comma = ,
# 将当前目录下所有flags文件嵌入。
FILES_FLAGS_EXIST := $(wildcard .*.flags)
ifneq ($(FILES_FLAGS_EXIST),)
include $(FILES_FLAGS_EXIST)
endif
# 将无需更新的文件从总的对象中删除。
FILES_FLAGS_CHANGED := $(strip \
$(filter-out $(FILES_FLAGS_UP_TO_DATE), \
$(O_TARGET) $(L_TARGET) $(active-objs) \
))
# A kludge: .S files don’t get flag dependencies (yet),
# because that will involve changing a lot of Makefiles. Also
# suppress object files explicitly listed in $(IGNORE_FLAGS_OBJS).
# This allows handling of assembly files that get translated into
# multiple object files (see arch/ia64/lib/idiv.S, for example).
#
# 将由汇编文件生成的目件文件从FILES_FLAGS_CHANGED删除。
FILES_FLAGS_CHANGED := $(strip \
$(filter-out $(patsubst %.S, %.o, $(wildcard *.S)
$(IGNORE_FLAGS_OBJS)), \
$(FILES_FLAGS_CHANGED)))
# 将FILES_FLAGS_CHANGED设为目标。
ifneq ($(FILES_FLAGS_CHANGED),)
$(FILES_FLAGS_CHANGED): dummy
endif

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值