找入口
追踪的第一件事情,还是找入口,就跟看C代码我们需要先找到main函数一样。
我在《u-boot.bin生成过程追踪》一文中提到了"u-boot-dirs"变量,这个变量展开之后,是一系列的目录。然后这些目录作为目标,有如下的生成规则:
PHONY += $(u-boot-dirs)
$(u-boot-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
u-boot-dirs展开是一系列目录,如下:
arch/arm/cpu arch/arm/cpu/armv7 arch/arm/imx-common ......
我们以目录"arch/arm/cpu"为例,将这个规则的命令行展开,得到:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=arch/arm/cpu
这里使用u-boot-dirs里面的目录作为obj的值,引入Makefile.build进行make构建。那么构建built-in.o的规则应该就在这个Makefile里面了。打开Makefile.build,第108行,有关于built-in.o的变量赋值:
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
这里,builtin-target赋值为"arch/arm/cpu/built-in.o",这个builtin-target在第358行有一个对应规则:
#
# Rule to compile a set of .o files into one .o file
#
ifdef builtin-target
quiet_cmd_link_o_target = LD $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cmd_secanalysis),\
rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
targets += $(builtin-target)
endif # builtin-target
这里的builtin-target规则,应该就是built-in.o的入口了。
展开规则
上面我们找到了built-in.o的入口,就是builtin-target对应的规则。这个规则依赖$(obj-y),obj-y变量实际上是Makefile.build里面根据obj参数包含另外的Makefile带进来的。见Makefile.build第59行:
include $(kbuild-file)
我们以上面"obj=arch/arm/cpu"为例,这里的include就变成:
include ./arch/arm/cpu/Makefile
在这个被引入的Makefile里面,根据配置定义了obj-y变量的值。
builtin-target规则的命令调用了if_changed函数,这个函数展开之后是cmd_link_o_target的值,见规则以上该变量的定义。我们将该变量做适当展开,如下:
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) $(cmd_secanalysis),rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@
其中cmd_secanalysis变量定义在135行,这个变量根据配置来定义,如果相应配置没有选择,则该变量为空。这里我们以实际的例子看下这个命令是怎样的:
arm-poky-linux-gnueabi-ld.bfd -r -o arch/arm/cpu/armv7/mx6/built-in.o arch/arm/cpu/armv7/mx6/soc.o arch/arm/cpu/armv7/mx6/clock.o
如上,调用了链接器ld,使用了-r选项,该选项使ld输出可重定位文件。链接器输入为各个源代码文件编译的目标文件。
以上就是built-in.o文件的构建过程,是不是感觉特别简单?