找入口
追蹤的第一件事情,還是找入口,就跟看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文件的構建過程,是不是感覺特別簡單?