備注:使用make –debug=b 獲得各個編譯目標的依賴關系和順序。
默認為 編譯第一個目標 _all
make 后面沒有指定目標,默認為 編譯第一個目標 _all
以 -include 包含的文件,即使包含不到,也不會影響繼續編譯。比如
-include include/config/auto.conf
-include include/config/auto.conf.cmd
但是會嘗試更新這個目標啊,
include/config/auto.conf.cmd 的規則是
.config include/config/auto.conf.cmd: ;
這個規則
target: prerequisite ; command
中prerequisite 和command 什么都沒有,所以 include/config/auto.conf.cmd 目標就這樣過了。
include/config/auto.conf 目標可以找到規則
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
即會按照這個規則來更新 include/config/auto.conf 目標 。
為了 include/config/auto.conf 文件,我們啟動一個新的Make 執行
make -f ./Makefile silentoldconfig
第二輪進入Makefile,目標是silentoldconfig
,符合的rules
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
依賴是
Trying rule prerequisite 'scripts_basic'.
Trying rule prerequisite 'outputmakefile'.
Trying rule prerequisite 'FORCE'.
scripts_basic 目標,
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
outputmakefile
由於是在源碼文件夾下面編譯的,不需要拷貝Makefile 文件,相當於什么也沒做。
三個依賴的目標更新后,開始更新目標
執行命令
make -f ./scripts/Makefile.build obj=scripts/kconfig silentoldconfig
scripts/kconfig/ 目錄下面有 kbuild ? 或者 Makefile 里面找rules
依賴conf 文件,依賴文件完成后,
mkdir -p include/config include/generated
scripts/kconfig/conf --silentoldconfig Kconfig
這個命令的執行
需要包含 .config 文件,更新目標 include/linux/autoconf.h 文件,執行silentoldconfig
scripts/kconfig/conf --silentoldconfig Kconfig 完成后,
這步完成后,scripts/kconfig/Makefile 中的 silentoldconfig 目標完成;
Makefile 中的
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
目標完成
Makefile 中的
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
目標完成,即
include/config/auto.conf 文件完成
這個只是 由於 -include include/config/auto.conf 這句話引發的。
更新這個文件后,重新再Makefile 文件中包含 include/config/auto.conf 和 include/config/auto.conf.cmd 文件,
之后執行
make -d ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
1、編譯開始后,首先做了什么?
沒有目標,第一個 _all 目標作為要生成的目標
_all 依賴all,依賴vmlinux,依賴prepare ,依賴prepare2,依賴 include/config/auto.conf,所以什么參數都不帶的 make 會來更新 include/config/auto.conf 這個目標
scripts 目標也依賴 include/config/auto.conf
這次,依然是include 這兩個文件
-include include/config/auto.conf
-include include/config/auto.conf.cmd
都包含成功了
並且在 include/config/auto.conf.cmd 中,給目標 include/config/auto.conf 增加了新的依賴
$deps_config 就是各個目錄下面的Kconfig 文件
======================================================
這次中,-include include/config/auto.conf時,又一次找到前面的規則
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
而且 include/config/auto.conf.cmd 中還給 include/config/auto.conf 增加了依賴文件
Considering target file 'include/config/auto.conf'.
Looking for an implicit rule for 'include/config/auto.conf'.
Trying pattern rule with stem 'auto'.
Trying rule prerequisite '.config'.
Trying rule prerequisite 'include/config/auto.conf.cmd'.
Found an implicit rule for 'include/config/auto.conf'.
Considering target file '.config'.
Finished prerequisites of target file '.config'.
No need to remake target '.config'.
Pruning file 'include/config/auto.conf.cmd'. -- 這句可以理解為 include/config/auto.conf.cmd 目標 剛更新過,不需要再次檢查更新。
由於這些文件都比 'include/config/auto.conf'. 文件older , 所以 'include/config/auto.conf'. 文件已經是最新的了,不需要更新了。
Prerequisite 'Kconfig' is older than target 'include/config/auto.conf'.
No need to remake target 'include/config/auto.conf'.
之后更新
更新目標....
Considering target file '_all'.
File '_all' does not exist.
Considering target file 'all'.
File 'all' does not exist.
Considering target file 'vmlinux'.
File 'vmlinux' does not exist. vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
Considering target file 'scripts/link-vmlinux.sh'.
Looking for an implicit rule for 'scripts/link-vmlinux.sh'.
No implicit rule found for 'scripts/link-vmlinux.sh'.
Finished prerequisites of target file 'scripts/link-vmlinux.sh'.
No need to remake target 'scripts/link-vmlinux.sh'.
Considering target file 'arch/arm64/kernel/vmlinux.lds'.
File 'arch/arm64/kernel/vmlinux.lds' does not exist.
Considering target file 'init'. 'arch/arm64/kernel/vmlinux.lds' 依賴 init ,是規則$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
File 'init' does not exist.
Considering target file 'prepare'.
File 'prepare' does not exist.
Considering target file 'prepare0'.
File 'prepare0' does not exist.
Considering target file 'archprepare'.
File 'archprepare' does not exist.
Considering target file 'archheaders'.
File 'archheaders' does not exist.
Finished prerequisites of target file 'archheaders'.
Must remake target 'archheaders'.
Successfully remade target file 'archheaders'.
Considering target file 'archscripts'.
File 'archscripts' does not exist.
Finished prerequisites of target file 'archscripts'.
Must remake target 'archscripts'.
Successfully remade target file 'archscripts'.
Considering target file 'prepare1'.
File 'prepare1' does not exist.
Considering target file 'prepare2'.
File 'prepare2' does not exist.
Considering target file 'prepare3'.
File 'prepare3' does not exist.
Considering target file 'include/config/kernel.release'.
Pruning file 'include/config/auto.conf'.
Considering target file 'FORCE'.
File 'FORCE' does not exist.
Finished prerequisites of target file 'FORCE'.
Must remake target 'FORCE'.
Successfully remade target file 'FORCE'.
Finished prerequisites of target file 'include/config/kernel.release'.
Prerequisite 'include/config/auto.conf' is newer than target 'include/config/kernel.release'.
Prerequisite 'FORCE' of target 'include/config/kernel.release' does not exist.
Must remake target 'include/config/kernel.release'.
Putting child 0x24600f0 (include/config/kernel.release) PID 19083 on the chain.
Live child 0x24600f0 (include/config/kernel.release) PID 19083
CHK include/config/kernel.release
Reaping winning child 0x24600f0 PID 19083
Removing child 0x24600f0 PID 19083 from chain.
Successfully remade target file 'include/config/kernel.release'.
include/config/kernel.release 是第一個目標啊
使用了 filechk 函數,在kbuild.include 里面定義。更新 include/config/kernel.release 文件
執行的命令是
set -e;
echo ' CHK include/config/kernel.release';
mkdir -p include/config/;
echo "4.1.26$(/bin/bash ./scripts/setlocalversion .)" < include/config/auto.conf > include/config/kernel.release.tmp;
if [ -r include/config/kernel.release ] && cmp -s include/config/kernel.release include/config/kernel.release.tmp; then
rm -f include/config/kernel.release.tmp;
else
echo ' UPD include/config/kernel.release';
mv -f include/config/kernel.release.tmp include/config/kernel.release;
fi
文件里面的內容:
prepare3 是第二個目標,
# prepare3 is used to check if we are building in a separate output directory,
# and if so do:
# 1) Check that make has not been executed in the kernel src $(srctree)
所以正常情況prepare 3 什么也不做
Finished prerequisites of target file 'prepare3'.
Must remake target 'prepare3'.
Successfully remade target file 'prepare3'.
outputmakefile 是第三個目標
# outputmakefile generates a Makefile in the output directory, if using a
# separate output directory. This allows convenient use of make in the
# output directory.
asm-generic 第四個
# Support for using generic headers in asm-generic
PHONY += asm-generic
asm-generic:
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
src=asm obj=arch/$(SRCARCH)/include/generated/asm
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
src=uapi/asm obj=arch/$(SRCARCH)/include/generated/uapi/asm
./scripts/Makefile.asm-generic 文件的作用
# This Makefile reads the file arch/$(SRCARCH)/include/asm/Kbuild # and for each file listed in this file with generic-y creates # a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/asm)
echo "#include " >arch/arm64/include/generated/asm/bug.h
。。。。。。
echo "#include " >arch/arm64/include/generated/uapi/asm/kvm_para.h
。。。。。。
asm_generic 完成后,prepare 2 的依賴就完成了,prepare 2 頁什么沒做,頁完成。
Successfully remade target file 'prepare2'.
Considering target file 'include/generated/uapi/linux/version.h'.
接下來是prepare 1 的第二個依賴,
'include/generated/uapi/linux/version.h -- 第五個
Considering target file 'include/generated/uapi/linux/version.h'.
$(version_h): $(srctree)/Makefile FORCE
$(call filechk,version.h)
$(Q)rm -f $(old_version_h)
define filechk_version.h
(echo \#define LINUX_VERSION_CODE $(shell \
expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef
那么 'include/generated/uapi/linux/version.h 里面是什么內容呢?
刪除了old_version.h ,即include/linux/version.h
include/generated/utsrelease.h - 第六個
include/generated/utsrelease.h: include/config/kernel.release FORCE
$(call filechk,utsrelease.h)
uts_len := 64
define filechk_utsrelease.h
if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
exit 1; \
fi; \
(echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";)
endef
生成的 include/generated/utsrelease.h 是什么樣子呢?
接下來是
prepare1 - 第七個
prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
include/config/auto.conf
$(cmd_crmodverdir)
# Create temporary dir for module support files
# clean it up only when building all modules
cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) \
$(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*)
mkdir -p .tmp_versions ; rm -f .tmp_versions/*
下來是 archprepare 依賴的 scripts_basic
scripts_basic 第八個
scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic
$(Q)rm -f .tmp_quiet_recordmcount
雖然scripts_basic 在之前已經做過了一次,但是由於它是 偽目標,不會有文件生成,所以現在還是要檢查與生成一次的。
Successfully remade target file 'scripts_basic'.
Finished prerequisites of target file 'archprepare'.
Must remake target 'archprepare'.
Successfully remade target file 'archprepare'.
archprepare 的依賴,及其自己 就OK 啦
下來是 prepare 0 第九個
prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
make -f ./scripts/Makefile.build obj=.
./scripts/Makefile.build 包含根目錄下面的 Kbuild 文件來進行
# Kbuild for top-level directory of the kernel # This file takes care of the following: # 1) Generate bounds.h # 2) Generate asm-offsets.h (may need bounds.h) # 3) Check for missing system calls
include/generated/bounds.h
include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
prepare 0 結束,prepare 也結束
Finished prerequisites of target file 'prepare'.
Must remake target 'prepare'.
Successfully remade target file 'prepare'.
接下來是scripts
scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
asm-generic
$(Q)$(MAKE) $(build)=$(@)
又是一遍 scripts_basic, 不管了, include/config/auto.conf include/config/tristate.conf 都已經更新過了。
編譯 scripts 文件夾下面的內容,依據scripts/Makefile 文件內容進行。
gcc -o scripts/dtc/dtc
gcc -o scripts/mod/modpost
scripts/kallsyms
scripts/conmakehash
scripts/sortextable
prepare 和 scripts 都更新之后,就是編譯各個子目錄了
規則是
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
Successfully remade target file 'scripts'.
Finished prerequisites of target file 'init'.
Must remake target 'init'.
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)))
make -f ./scripts/Makefile.build obj=init
編譯的目錄順序為
init - init-y
usr - core-y in Makefile
arch/arm64/kernel in arm64/Makefile
arch/arm64/mm in arm64/Makefile
arch/arm64/net in arm64/Makefile
arch/arm64/crypto in arm64/Makefile
kernel
mm
fs
ipc
security
crypto
block
drivers
sound
firmware
net
arch/arm64/lib
lib
各個目錄,及其子目錄都編譯完成后
Successfully remade target file 'lib'.
Finished prerequisites of target file 'arch/arm64/kernel/vmlinux.lds'.
執行到現在, 'arch/arm64/kernel/vmlinux.lds'. 已經是最新的了
Successfully remade target file 'arch/arm64/kernel/vmlinux.lds'.
Considering target file 'arch/arm64/kernel/head.o'.
繼續vmlinux 的下一個依賴,
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
head-y 在 arch/arm64/Makefile文件中定義 head-y := arch/arm64/kernel/head.o
由於規則$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
所以arch/arm64/kernel/head.o 也是依賴所有的init usr 。。。。。。lib 這些目標,這些目標剛更新過,所以直接執行head.o 的command,head.o 也是最新的,所以不需要更新
一路檢查下來,$(vmlinux-deps) 都不需要更新了
Finished prerequisites of target file 'vmlinux'.
Must remake target 'vmlinux'.
就更新vmlinux 了
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
+$(call if_changed,link-vmlinux)
/bin/bash scripts/link-vmlinux.sh aarch64-linux-gnu-ld -EL -p --no-undefined -X --build-id
腳本里面做了哪些事情:
,
. ./.config include .config
LD vmlinux.o 將上面的 中間文件鏈接為 vmlinux.o
modpost vmlinux.o to check for section mismatches
scripts/mod/modpost -o ./Module.symvers -S vmlinux.o
info GEN .version 生成 .version 文件
make -f ./scripts/Makefile.build obj=init 再生成一遍 init 文件夾
vmlinux_link '' .tmp_vmlinux1 # Link of vmlinux # ${1} - optional extra .o files # ${2} - output file
kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o # Create ${2} .o file with all symbols from the ${1} object file
vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2 # Link of vmlinux # ${1} - optional extra .o files # ${2} - output file
kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o # Create ${2} .o file with all symbols from the ${1} object file
vmlinux_link .tmp_kallsyms2.o vmlinux # Link of vmlinux # ${1} - optional extra .o files # ${2} - output file
sortextable vmlinux
mksysmap vmlinux System.map Create map file with all symbols from ${1}
# a) Verify that the System.map from vmlinux matches the map from # ${kallsymso}.
mksysmap .tmp_vmlinux2 .tmp_System.map
cmp -s System.map .tmp_System.map
rm -f .old_version
簡化后,如下
LINK vmlinux
LD vmlinux.o
MODPOST vmlinux.o
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
LD init/built-in.o
KSYM .tmp_kallsyms1.o
KSYM .tmp_kallsyms2.o
LD vmlinux
SORTEX vmlinux
SYSMAP System.map
Successfully remade target file '__build'.
KSYM .tmp_kallsyms1.o
KSYM .tmp_kallsyms2.o
LD vmlinux
SORTEX vmlinux
SYSMAP System.map
Successfully remade target file 'vmlinux'.
之后是 arch/arm64/Makefile 中給all 添加的其他依賴
'Image.gz'.
dtbs
之后是modules
all: modules
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
@$(kecho) ' Building modules, stage 2.';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
modules.builtin: $(vmlinux-dirs:%=%/modules.builtin)
$(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin
%/modules.builtin: include/config/auto.conf
$(Q)$(MAKE) $(modbuiltin)=$*
各個子目錄下面的
make -f ./scripts/Makefile.modbuiltin obj=init
modules.builtin 目標是 生成 ./modules.builtin 文件
modules 目標是生成 ./modules.order
make -f ./scripts/Makefile.modpost
make -f ./scripts/Makefile.fwinst obj=firmware __fw_modbuild