1, 頂層Makefile跟蹤:
找到vmlinux目標
# vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
@echo "========================vmlinux============================"
@echo $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o)
@cp vmlinux vmlinux.full
找到vmlinux-init:
vmlinux-init := $(head-y) $(init-y)
head-y是和機器有關的變數,定義在arch內的Makefile裡:
head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
這個是通過include $(srctree)/arch/$(SRCARCH)/Makefile 包含這個Makefile的。
init-y定義在本Makefile:
init-y := init/
...
init-y := $(patsubst %/, %/built-in.o, $(init-y))
最終結果就是:
init-y := init/built-in.o。這個build-in.o這個中間檔案可能聽說過,其實這個檔案就是有這個目錄下所有obj-y來合成的。
此外,下面兩變數自己找一下:
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
vmlinux-dirs
還要注意一下,下面這句:
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
這句在執行vmlinux目標前由依賴關係產生,我們來看看最關鍵的vmlinux-dirs。
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m)))
其實$(vmlinux-dirs)還是一個目標。
PHONY += $(vmlinux-dirs)
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
用到了Makefile.kbuild規則。將vmlinux-dirs裡面的目錄進行了遞迴處理產生出那些.o的檔案,特別是build-in.o, 在執行vmlinux時候,$(vmlinux-dirs)目標肯定會先得到執行。
連結得到vmlinux
在哪裡連結的,看看 endif後面:
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(call if_changed_rule,vmlinux__)會調用rule_vmlinux_,即下面內容:
# Link of vmlinux
# If CONFIG_KALLSYMS is set .version is already updated
# Generate System.map and verify that the content is consistent
# Use + in front of the vmlinux_version rule to silent warning with make -j2
# First command is ':' to allow us to use + in front of the rule
define rule_vmlinux__
:
$(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))
$(call cmd,vmlinux__)
$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
$(Q)$(if $($(quiet)cmd_sysmap), \
echo ' $($(quiet)cmd_sysmap) System.map' &&) \
$(cmd_sysmap) $@ System.map; \
if [ $$? -ne 0 ]; then \
rm -f $@; \
/bin/false; \
fi;
$(verify_kallsyms)
endef
在這上面有命令vmlinux__, _vmlinux_version和sysmap定義, 其中vmlinux_命令中有LD的連結產生vmlinux.
# Rule to link vmlinux - also used during CONFIG_KALLSYMS
# May be overridden by arch/$(ARCH)/Makefile
quiet_cmd_vmlinux__ ?= LD $@
cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
-T $(vmlinux-lds) $(vmlinux-init) \
--start-group $(vmlinux-main) --end-group \
$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
# Generate new vmlinux version
quiet_cmd_vmlinux_version = GEN .version
cmd_vmlinux_version = set -e; \
if [ ! -r .version ]; then \
rm -f .version; \
echo 1 >.version; \
else \
mv .version .old_version; \
expr 0$$(cat .old_version) + 1 >.version; \
fi; \
$(MAKE) $(build)=init
# Generate System.map
quiet_cmd_sysmap = SYSMAP
cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
2. Makefile.kbuild規則:
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build \
obj =$(vmlinux-dirs)
找到目標__build:
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m)) \
$(subdir-ym) $(always)
@:
因為KBUILD_BUILTIN在頂層Makefile中被初始化為1,所以這個規則的依賴有一個builtin-target變數:
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
變數obj就是vmlinux-dirs變數指定的目錄。所以這裡會構建$(vmlinux-dirs)/built-in.o目標:
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), $^),\
rm -f $@; $(AR) rcs $@)
上面由obj-y指定的.o,產生$(vmlinux-dirs)/built-in.o.
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
下麵包含了vmlinux-dirs變數指定目錄中的Makefile檔案,在這些makefile檔案中會指定obj-y變數,它指定的都是一些*.o目標檔案,
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
這些*.o檔案的產生方法由scripts/Makefile.build檔案的模式規則指定
%.o: %.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
上面會產生obj-y指定的.o
通過上面這一系列的步驟,就編譯連結出由變數vmlinux-init指定的目標,vmlinux-main變數指定的目標的構建與此類似.
天行健,君子當自強不息