3.2.3 vmlinux的构建过程(1)
所有的体系结构都需要构建vmlinux,所以vmlinux的构建规则在顶层的Makefile中。
- linux-3.7.4/Makefile:
- cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) \
- $(LDFLAGS_vmlinux)
- vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
- +$(call if_changed,link-vmlinux)
注意,构建vmlinux的命令使用了make的内置函数call。这是一个比较特殊的内置函数,make使用它来引用用户自己定义的带有参数的函数。if_changed是kbuild定义的一个函数,这里通过call引用这个函数,传递的实参是link-vmlinux。函数if_changed的定义如下:
- linux-3.7.4/scripts/Kbuild.include:
- if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
- @set -e; \
- $(echo-cmd) $(cmd_$(1)); \
- echo ‘cmd_$@ := $(make-cmd)’ > $(dot-target).cmd)
在if_changed中,any-prereq检查是否有依赖比目标新,或者依赖还没有创建;arg-check检查编译目标的命令相对上次是否发生变化。如果两者中只要有一个发生改变,就执行if函数的if块。注意if块中的使用黑体标识的部分,其中“1”代表的就是传给if_changed的第一个实参。由此可见,if_changed核心功能就是当目标的依赖或者编译命令发生变化时,执行表达式“cmd_$(1)”展开后的值。
这里,传给if_changed的第一个实参是link-vmlinux,因此,cmd_$(1)展开后为cmd_link-vmlinux。注意cmd_link-vmlinux中的第二项“$<”,这是make的自动变量,翻译自“Automatic Variable”,意指变量名相同,但是make根据具体上下文,将其自动替换为合适的值。这里,make会将这个自动变量替换为构建vmlinux中的规则中的第一个依赖,即shell脚本文件scripts/link-vmlinux.sh,该脚本文件中负责vmlinux链接的脚本如下:
- linux-3.7.4/scripts/link-vmlinux.sh:
- vmlinux_link()
- {
- local lds="${objtree}/${KBUILD_LDS}"
- if [ "${SRCARCH}" != "um" ]; then
- ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \
- -T ${lds} ${KBUILD_VMLINUX_INIT} \
- --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
- else
- ...
- fi
- }
- ...
- vmlinux_link "${kallsymso}" vmlinux
根据函数vmlinux_link的实现,如果平台不是“um”,那么就调用链接器将变量KBUILD_ VMLINUX_INIT、KBUILD_VMLINUX_MAIN中记录的目标文件链接为vmlinux。我们看看这两个变量的定义:
- linux-3.7.4/Makefile:
- # Externally visible symbols (used by link-vmlinux.sh)
- export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
- export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y)\
- $(net-y)
我们以core-y为例来分析变量KBUILD_VMLINUX_MAIN的值。
- linux-3.7.4/Makefile:
- core-y := usr/
- ...
- core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
- ...
- core-y := $(patsubst %/, %/built-in.o, $(core-y))