linux kernel makefile 編譯過程概覽



備注:使用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

image

依賴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 增加了新的依賴

image

$deps_config 就是各個目錄下面的Kconfig 文件

image

======================================================

這次中,-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

文件里面的內容:

image

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 里面是什么內容呢?

image

刪除了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 是什么樣子呢?

image

接下來是

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM