Linux内核Makefile文件(二)

来源:互联网 发布:seo和sem 编辑:程序博客网 时间:2024/05/03 03:01
 

=== 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就可以了。

Example:
#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_$@。

Example:
#arch/i386/Makefile
LDFLAGS_vmlinux := -e stext

OBJCOPYFLAGS objcopy选项

当使用$(call if_changed,objcopy)转化a .o文件时,OBJCOPYFLAGS中的选项将被使用。$(call if_changed,objcopy)经常被用作为vmlinux产生原始的二进制文件。

Example:
#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文件。针对每个体系需要另外添加和修改它。

Example:
#arch/sparc64/Makefile
AFLAGS += -m64 -mcpu=ultrasparc

CFLAGS $(CC)编译器选项

默认值见顶层Makefile文件。针对每个体系需要另外添加和修改它。

通常CFLAGS变量值取决于内核配置。

Example:
#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: 这个规则用于列举开始进入子目录编译前需要的前提文件。通常是些包含汇编常量的头文件。
prepare: 这个规则用于列举开始进入子目录编译前需要的前提文件。通常是些包含汇编常量的头文件。

Example:
#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文件只需增加体系相关的目录。

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 引导映像

体系Makefile文件定义了编译vmlinux文件的目标对象,将它们压缩和封装成引导代码,并复制到合适的位置。这包括各种安装命令。如何定义实际的目标对象无法为所有的体系结构提供标准化的方法。

附加处理过程常位于arch/$(ARCH)/下的boot/目录。

内核编译系统无法在boot/目录下提供一种便捷的方法创建目标系统文件。因此arch/$(ARCH)/Makefile要调用make命令在 boot/目录下建立目标系统文件。建议使用的方法是在arch/$(ARCH)/Makefile中设置调用,并且使用完整路径引用arch/$ (ARCH)/boot/Makefile。

Example:
#arch/i386/Makefile
boot := arch/i386/boot
bzImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@

建议使用"$(Q)$(MAKE) $(build)=<dir>"方式在子目录中调用make命令。
没有定义体系目标系统文件的规则,但执行"make help"命令要列出所有目标系统文件,因此必须定义$(archhelp)变量。

Example:
#arch/i386/Makefile
define archhelp
echo '* bzImage - Image (arch/$(ARCH)/boot/bzImage)'
endef

当执行不带参数的make命令时,将首先编译第一个目标对象。在顶层Makefile中第一个目标对象是all:。
一个体系结构需要定义一个默认的可引导映像。
"make help"命令的默认目标是以*开头的对象。
增加新的前提文件给all目标可以设置不同于vmlinux的默认目标对象。

Example:
#arch/i386/Makefile
all: bzImage

当执行不带参数的"make"命令时,bzImage文件将被编译。

--- 6.5 编译非内核目标

extra-y

extra-y定义了在当前目录下创建没有在obj-*定义的附加的目标文件。

在extra-y中列举目标是处于两个目的:
1) 是内核编译系统在命令行中检查变动情况
- 当使用$(call if_changed,xxx)时
2) 内核编译系统知道执行"make clean"命令时删除哪些文件

Example:
#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
压缩目标文件。使用最大压缩算法压缩目标文件。

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)

在上面例子中有两个可能的目标对象,分别需要不同的链接选项。使用LDFLAGS_$@语法为每个目标对象设置不同的链接选项。
$(targets)包含所有的目标对象,因此内核编译系统知道所有的目标对象并且将:
1) 检查命令行的改变情况
2) 执行make clean命令时删除目标对象

": %: %.o"是简写方法,减写setup.o和bootsect.o文件。

注意: 常犯错误是忘记"target :="语句,导致没有明显的原因目标文件被重新编译。

--- 6.7 定制编译命令

当执行带KBUILD_VERBOSE=0参数的编译命令时命令的简短信息会被显示。要让定制命令具有这种功能需要设置两个变量:
quiet_cmd_<command> - 将被显示的内容
cmd_<command> - 被执行的命令

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'

执行"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。

Example:
#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) : 目标编译选项。注意要使用文件全名。


=== 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, <mailto:mec@shout.net>
Updates by Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
Updates by Sam Ravnborg <sam@ravnborg.org>

=== 10 TODO

- Describe how kbuild support shipped files with _shipped.
- Generating offset header files.
- Add more variables to section 7

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑光驱线坏了怎么办 做系统不读光驱怎么办 光盘放进电脑没反应怎么办 不服省高院裁定维持原判怎么办 咖啡和酒一起喝怎么办 跟法官联系不上怎么办 四维没有预约到怎么办 钥匙锁在车里怎么办 如果孩子很叛逆骂人打人怎么办 错过了今年规培怎么办 枣木怎么办才能搞直了 高中生和家里闹意见离家出走怎么办 校长信箱实名举报了怎么办 枣子吃多了胀气怎么办 红枣吃多了会怎么办 宁波南苑e家会员卡怎么办 宁波社保卡丢了怎么办 奶茶汉堡店经营不好改怎么办 军人保障卡丢了怎么办 军人保障卡丢失了怎么办 军人保障卡掉了怎么办 椎基底动脉供血不足怎么办 颈椎压迫神经脑供血不足怎么办 脑部基底动脉轻度狭窄怎么办 胸壁疼痛我该怎么办 厂房面积小于泄压面积怎么办 江苏海门农村自建房房产证怎么办 颈总动脉斑块形成怎么办 颈椎引起腔梗头晕怎么办 魅族手机变成英文怎么办 员工失去了工作乐趣怎么办 古墓丽影9出bug怎么办 气炉子打不着火怎么办 下面人员不参加公司拓展怎么办 重点班的差生怎么办 江苏考生选修考d怎么办 眼睛里有虫子该怎么办 屋里毛絮特别多怎么办 信用卡人员核核查单位地址怎么办 红米note电源键失灵怎么办 红米note4x跳屏怎么办