| === 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需要知道通过哪些文档编译模块,因此需要配置一个$(-objs)变量。 例如:#drivers/isdn/i4l/Makefile obj-$(CONFIG_ISDN) += isdn.o isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o 在这个例子中,模块名 Kbuild首先编译$(isdn-objs)中的object文档,然后运行"$(LD) -r"将列表中文档生成 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 - -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。 注意:语法-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-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 ) 产生 .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)="方式在子目录中调用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作为选项。 也能够用linux内核文件放在哪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_ - 将被显示的内容 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_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 = -falign 例如: CFLAGS += $(cc-option-align)-functions=4 在上面例子中对于gcc >= 3.00来说-falign-functions=4,gcc ,均为两位数字。例如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程式有两种赋值操作符:":="和"="。 ":="执行时立即计算右值并赋值给左值。"="类似公式定义,当每次使用左值要被使用时计算右值并赋给他。 一些情况中使用"="合适,而一些情况中使用":="才是正确选择。 === 9 Credits Original version made by Michael Elizabeth Chastain, Updates by Kai Germaschewski kai@tp1.ruhr-uni-bochum.de > Updates by Sam Ravnborg
> === 10 TODO - Describe how kbuild support shipped files with _shipped. - Generating offset header files. - Add more variables to section 7? |
发表评论