日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux源码Makefile的详细分析

發(fā)布時(shí)間:2024/4/17 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux源码Makefile的详细分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

一、概述

  1、本文的意義

  2、Linux內(nèi)核Makefile文件組成

二、Linux內(nèi)核Makefile的“make解析”過(guò)程

  1 頂層Makefile階段

    1、從總目標(biāo)uImage說(shuō)起 

    2、vmlinux的生成

    3、vmlinux-lds、vmlinux-init、vmlinux-main的生成

  2 scripts/Makefile.build的第一次調(diào)用階段

    1、Makefile.build的包含文件

    2、scripts/Makefile.build的總目標(biāo)

    3、drivers/built-in.o的生成

    4、drivers/net/built-in.o

  3 scripts/Makefile.build的再一次調(diào)用階段

    1、Makefile.build的包含文件

    2、scripts/Makefile.build的總目標(biāo)

    3、drivers/net/built-in.o的生成

    4、drivers/net/dm9000.o

    5、drivers/net/e1000/built-in.o的生成

三、Linux內(nèi)核整體編譯過(guò)程

四、Linux內(nèi)核編譯構(gòu)成元素

  1、Makefile的目標(biāo)

  2、Makefile的依賴

  3、Makefile的規(guī)則

  4、Makefile的編譯連接選項(xiàng)

五、Linux內(nèi)核Makefile特點(diǎn)?

  1、兩個(gè)Makefile

  2、編譯的目錄始終是頂層目錄

  3、通用規(guī)則

?

一、概述

1、本文的意義

  眾多的資料(《嵌入式Linux應(yīng)用開發(fā)完全手冊(cè)》、Documentation/kbuild/makefiles.txt)已經(jīng)向我們展示了一個(gè)初級(jí)Linux用戶者應(yīng)該懂得的知識(shí)--怎樣添加需要編譯的文件、添加編譯的規(guī)則、多個(gè)源文件構(gòu)成一個(gè)目標(biāo)文件的情況等。

  但是,一種“找到真相”的沖動(dòng)迫使我想了解Linux內(nèi)核編譯的整個(gè)過(guò)程是怎樣的。為此,查了很多資料,發(fā)現(xiàn)《深度探索Linux操作系統(tǒng):系統(tǒng)構(gòu)建和原理解析》一文的第三章對(duì)該問(wèn)題有很詳細(xì)的論述。

  經(jīng)過(guò)一番分析,也有自己的想法,寫于此。本文主要討論的是Linux內(nèi)核編譯的整個(gè)過(guò)程,以此為基礎(chǔ),再來(lái)討論諸如Linux內(nèi)核Makefile的特點(diǎn)、構(gòu)成元素等其他的問(wèn)題。

  對(duì)于分析Linux Makefile的整個(gè)編譯過(guò)程,筆者認(rèn)為需要對(duì)Makefile有一定的基礎(chǔ)。如果之前沒接觸過(guò)Makefile的,不建議看本文。另外,對(duì)于那些只需要初級(jí)認(rèn)識(shí)的Linux用戶也無(wú)需對(duì)此付出過(guò)多精力,可以直接飄過(guò)。

2、Linux內(nèi)核Makefile文件組成

Linux內(nèi)核Makefile文件組成
名稱描述
頂層 Makefile它是所有Makefile文件的核心,從總體上控制著內(nèi)核的編譯、連接
arch/$(ARCH)/Makefile對(duì)應(yīng)體系結(jié)構(gòu)的Makefile,它用來(lái)決定哪些體系結(jié)構(gòu)相關(guān)的文件參與內(nèi)核的生成,并提供一些規(guī)則來(lái)生成特定格式的內(nèi)核映像
scripts/Makefile.*Makefile公用的通用規(guī)則、腳本等
子目錄kbuild Makefiles各級(jí)子目錄的Makefile相對(duì)簡(jiǎn)單,被上一層Makefile.build調(diào)用來(lái)編譯當(dāng)前目錄的文件。
頂層.config配置文件,配置內(nèi)核時(shí)生成。所有的Makefile文件(包括頂層目錄和各級(jí)子目錄)都是根據(jù).config來(lái)決定使用哪些文件的

?scripts/Makefile.*中有公用的通用規(guī)則,展示如下:

scripts/Makefile.*文件組成
Makefile.build被頂層Makefile所調(diào)用,與各級(jí)子目錄的Makefile合起來(lái)構(gòu)成一個(gè)完整的Makefile文件,定義.lib、built-in.o以及目標(biāo)文件.o的生成規(guī)則。這個(gè)Makefile文件生成了子目錄的.lib、built-in.o以及目標(biāo)文件.o
Makefile.clean被頂層Makefile所調(diào)用,用來(lái)刪除目標(biāo)文件等
Makefile.lib被Makefile.build所調(diào)用,主要是對(duì)一些變量的處理,比如說(shuō)在obj-y前邊加上obj目錄
Kbuild.include被Makefile.build所調(diào)用,定義了一些函數(shù),如if_changed、if_changed_rule、echo-cmd

總結(jié):

  Linux內(nèi)核Makefile體系核心的Makefile文件就兩個(gè):頂層Makefile、scripts/Makefile.build。

  子目錄中的Makefile、kbuild不是Makefile文件(完整的Makefile文件),只能算作是Makefile的包含文件。

  頂層Makefile文件負(fù)責(zé)將各個(gè)目錄生成的*.built-in.o、lib.a等文件連接到一起。而scripts/Makefile.build 包含子目錄中的Makefile文件來(lái)生成這些*.built-in.o、lib.a、*.o等文件。

二、Linux內(nèi)核Makefile的“make解析”過(guò)程

  本文的實(shí)驗(yàn)源碼是對(duì)“l(fā)inux-2.6.30.4”進(jìn)行移植后的運(yùn)行在TQ2440開發(fā)板上的源碼包。

1 頂層Makefile階段

1、從總目標(biāo)uImage說(shuō)起

  內(nèi)核配置完成后,在頂層目錄中執(zhí)行“#make uImage”便開始編譯內(nèi)核。但是,uImage卻不是在頂層Makefile中定義,而是在arch/$(ARCH)/Makefile中定義。

頂層Makefile Line 452:
include $(srctree)/arch/$(SRCARCH)/Makefile

  其中srctree為源碼絕對(duì)路徑,以我的環(huán)境為例,它的值等于/workspace/linux-2.6.30.4;而SRCARCH := $(ARCH),即該變量等于架構(gòu)名稱,我們以arm為例進(jìn)行說(shuō)明。?

arch/arm/Makefile Line 230:
zImage Image xipImage bootpImage uImage: vmlinux

  可見uImage依賴于vmlinux,要先生成vmlinux,然后執(zhí)行下邊這條指令完成編譯。

arch/arm/Makefile Line 231:
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

<1> Q的定義:選擇靜態(tài)編譯與否(是否打印編譯信息)

頂層Makefile Line 290:
ifeq ($(KBUILD_VERBOSE),1)quiet =Q = elsequiet=quiet_Q = @ endif

<2> MAKE: 系統(tǒng)環(huán)境變量,值為make

<3> build: 值為“-f scripts/Makefile.build obj=”實(shí)際上就是調(diào)用子Makefile--scripts/Makefile.build,然后傳遞參數(shù)目標(biāo)文件夾。

Kbuild.include Line 141:
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= # Usage: # $(Q)$(MAKE) $(build)=dir build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj Kbuild.include被頂層Makefile所包含 頂層Makefile Line 312: # We need some generic definitions (do not try to remake the file). $(srctree)/scripts/Kbuild.include: ; include $(srctree)/scripts/Kbuild.include 2、vmlinux的生成 頂層Makefile Line 845:
# vmlinux image - including updated kernel symbols vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE ifdef CONFIG_HEADERS_CHECK$(Q)$(MAKE) -f $(srctree)/Makefile headers_check endif ifdef CONFIG_SAMPLES$(Q)$(MAKE) $(build)=samples endif ifdef CONFIG_BUILD_DOCSRC$(Q)$(MAKE) $(build)=Documentation endif$(call vmlinux-modpost)$(call if_changed_rule,vmlinux__)$(Q)rm -f .old_version   vmlinux的依賴是“$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE”,要想生成vmlinux必須要先把這些原材料準(zhǔn)備好。

<1> vmlinux-lds

  在編譯之前要把連接腳本先生成,最后的連接階段會(huì)用的著。

頂層Makefile Line 699:
vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds

<2> vmlinux-init

頂層Makefile Line 696:
vmlinux-init := $(head-y) $(init-y)

? ①head-y

arch/arm/Makefile Line 100:
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o ②init-y 頂層Makefile Line 477:init-y := init/頂層Makefile Line 661: init-y := $(patsubst %/, %/built-in.o, $(init-y))

  init-y最終等于init/built-in.o

<3>vmlinux-main

頂層Makefile Line 697: vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)

① core-y

arch/arm/Makefile Line 196: core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/arch/arm/Makefile Line 197: core-y += $(machdirs) $(platdirs)頂層Makefile Line 481: core-y := usr/頂層Makefile Line 650:core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/頂層Makefile Line 662:core-y := $(patsubst %/, %/built-in.o, $(core-y))

  core-y最終等于

core-y := usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o \ crypto/built-in.o block/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o

②?libs-y

arch/arm/Makefile Line 204:libs-y := arch/arm/lib/ $(libs-y)頂層Makefile Line 480: libs-y := lib/頂層Makefile Line 665:libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))頂層Makefile Line 666:libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))頂層Makefile Line 667: libs-y := $(libs-y1) $(libs-y2)

  libs-y最終等于arch/arm/lib/lib.a ?lib/lib.a ?arch/arm/lib/built-in.o ?lib/built-in.o

③drivers-y

頂層Makefile Line 478:drivers-y := drivers/ sound/ firmware/頂層Makefile Line 663:drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))

  drivers-y值最終等于rivers/built-in.o sound/built-in.o firmware/built-in.o

④net-y

頂層Makefile Line 479: net-y := net/頂層Makefile Line 664: net-y := $(patsubst %/, %/built-in.o, $(net-y))

  net-y最終等于net/built-in.o

<4> vmlinux.o

  目前還未分析

<5> kallsyms.o

  目前還未分析

<6> FORCE

  它的目的是強(qiáng)迫重建vmlinux(無(wú)論上邊的原材料是否已經(jīng)構(gòu)建,無(wú)論上邊的原材料是否比已經(jīng)生成的目標(biāo)新,都要重建),這種用法在Linux Makefile體系中經(jīng)常見到。

PHONY += FORCE FORCE:# Declare the contents of the .PHONY variable as phony. We keep that # information in a variable so we can use it in if_changed and friends. .PHONY: $(PHONY)

  可以看到FORCE為一個(gè)偽目標(biāo),所以無(wú)論如何都要重建vmlinux。

?<7> 通過(guò)編譯查看最終的依賴文件

root@daneiqi:/workspace/linux-EmbedSky# make uImage V=1arm-linux-ld -EL -p --no-undefined -X --build-id -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o --start-group usr/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/mach-s3c2410/built-in.o arch/arm/mach-s3c2400/built-in.o arch/arm/mach-s3c2412/built-in.o arch/arm/mach-s3c2440/built-in.o arch/arm/mach-s3c2442/built-in.o arch/arm/mach-s3c2443/built-in.o arch/arm/plat-s3c24xx/built-in.o arch/arm/plat-s3c/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o

  命令中的參數(shù)V=1的含義是“頂層Makefile?Line 36: # Use 'make V=1' to see the full commands”。

3、vmlinux-lds、vmlinux-init、vmlinux-main的生成

<1> ?vmlinux-dirs

頂層Makefile Line 871:$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;

  vmlinux的主要構(gòu)成文件vmlinux-init、vmlinux-main、vmlinux-lds的依賴是vmlinux-dirs。

頂層Makefile Line 652:vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \$(core-y) $(core-m) $(drivers-y) $(drivers-m) \$(net-y) $(net-m) $(libs-y) $(libs-m)))

  filter首先過(guò)濾掉不是文件夾的(帶“/”的就是文件夾),然后patsubst將所有的文件夾后邊的“/”去掉。筆者在頂層Makefile中添加一個(gè)偽目標(biāo)Debug,使它打印vmlinux-dirs,然后在終端上執(zhí)行命令"make Debug"得到vmlinux-dirs的值為:

init usr arch/x86/kernel arch/x86/mm arch/x86/crypto arch/x86/vdso kernel mm fs ipc security crypto block drivers sound firmware net lib arch/x86/lib

  可見vmlinux-dirs都是源碼包本來(lái)存在的文件夾,怎么通過(guò)這些文件夾的名字來(lái)生成它們目錄下的*.built-in.o、lib.a呢?

<2> vmlinux-dirs對(duì)應(yīng)的命令

頂層Makefile Line 879:
PHONY += $(vmlinux-dirs) $(vmlinux-dirs): prepare scripts$(Q)$(MAKE) $(build)=$@

  vmlinux-dir所代表的目錄都是偽目標(biāo),這樣即使這些文件夾是存在的,也要執(zhí)行它們對(duì)應(yīng)的命令。

① prepare

 在正式開始編譯之前,要先將準(zhǔn)備工作做好,檢查輸出目錄是否與源碼目錄分開、如果分開了要?jiǎng)?chuàng)建這樣的目錄,還要生成include/config/kernel.release、include/linux/version.h include/linux/utsrelease.h 等文件。

以下代碼都是摘自頂層Makefile
Line 955:PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3Line 957: # prepare3 is used to check if we are building in a separate output directory, Line 961: prepare3: include/config/kernel.releaseLine 975: # prepare2 creates a makefile if using a separate output directory Line 976: prepare2: prepare3 outputmakefileLine 978: prepare1: prepare2 include/linux/version.h include/linux/utsrelease.h \Line 982: archprepare: prepare1 scripts_basicLine 984: prepare0: archprepare FORCE$(Q)$(MAKE) $(build)=.$(Q)$(MAKE) $(build)=. missing-syscallsLine 989: prepare: prepare0

②scripts

  準(zhǔn)備工作還包括scripts,這些腳本用來(lái)決定編譯時(shí)的選項(xiàng),例如include/config/auto.conf。

以下內(nèi)容摘自頂層Makefile
Line 384: # Basic helpers built in scripts/ PHONY += scripts_basic scripts_basic:$(Q)$(MAKE) $(build)=scripts/basicLine 472: PHONY += scripts scripts: scripts_basic include/config/auto.conf ③$(Q)$(MAKE) $(build)=$@

?  編譯命令是至關(guān)重要的一句話,這句話就是來(lái)調(diào)用通用子Makefile文件--scripts/Makefile.build。$@會(huì)依次被vmlinux-dirs中的文件夾代替,從而依次執(zhí)行命令"make -f scripts/Makefile.build obj=$@"

編譯該目錄中的文件以生成*.built-in.o、lib.a等文件。

  我們以$@為drivers為例進(jìn)行以下內(nèi)容的說(shuō)明,下邊這條命令最終的結(jié)果是生成drivers/built-in.o。

make -f scripts/Makefile.build obj=drivers

2 scripts/Makefile.build的第一次調(diào)用階段 ?

  轉(zhuǎn)戰(zhàn)到scripts/Makefile.build,obj=drivers被帶到該文件,首先看一下這個(gè)文件都包含了哪些文件

1、Makefile.build的包含文件

以下內(nèi)容皆來(lái)自于scripts/Makefile.build Line 34: -include include/config/auto.confLine 36: include scripts/Kbuild.includeLine 41: # The filename Kbuild has precedence over Makefile kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) include $(kbuild-file)Line 52: include scripts/Makefile.libLine 61: # Do not include host rules unless needed ifneq ($(hostprogs-y)$(hostprogs-m),) include scripts/Makefile.host endif

  包含文件有依據(jù).config生成的配置文件include/config/auto.conf、include scripts/Kbuild.include、

$(kbuild-file)(也就是子目錄的Makefile或者kbuild)、include scripts/Makefile.lib、include scripts/Makefile.host(只在一定情況下才被包含進(jìn)入)。

  這里著重講一下kbuild-file值的變化過(guò)程,kbuild-dir的等式中有filter函數(shù),它的目的是將不是以“/”開頭的目錄濾除,顯然我們的src=drivers,所以就被濾除掉,這個(gè)函數(shù)的值為空。

scripts/Makefile.build Line 5:
src := $(obj)   $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))的結(jié)果最終等于$(srctree)/$(src),也就是給src添加絕對(duì)路徑。所以kbuild-dir值等于/workspace/linux-2.6.30.4/drivers。
  kbuild-file右邊的等式,首先查看在kbuild-dir目錄中是否有Kbuild存在,如果有就等于這個(gè)文件,否則使用這個(gè)目錄中的Makefile文件。kbuild-file最終等于/workspace/linux-2.6.30.4/drivers/Makefile。

2、scripts/Makefile.build的總目標(biāo)

scripts/Makefile.build Line 7: PHONY := __build __build:scripts/Makefile.build Line 93:__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \$(subdir-ym) $(always)@:

?<1> KBUILD_BUILTIN

  在終端以#Make uImage執(zhí)行Make時(shí),KBUILD_BUILTIN := 1。

頂層Makefile Line 241:
KBUILD_BUILTIN := 1# If we have only "make modules", don't compile built-in objects. # When we're building modules with modversions, we need to consider # the built-in objects during the descend as well, in order to # make sure the checksums are up to date before we record them.ifeq ($(MAKECMDGOALS),modules)KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) endif

頂層Makefile Line 264:
export KBUILD_MODULES KBUILD_BUILTIN

?<2>?builtin-target

scripts/Makefile.build Line 85:? ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),) builtin-target := $(obj)/built-in.o endif

  builtin-target值為drivers/built-in.o

?<3>?lib-target

scripts/Makefile.build Line 81:? ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),) lib-target := $(obj)/lib.a endif

  lib-target的值為drivers/lib.a

<4> $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target))

  初步認(rèn)識(shí)時(shí)定義編譯的模塊

?<5> subdir-ym

subdir-ym的定義

scripts/Makefile.lib Line 38: __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) subdir-y += $(__subdir-y) __subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m))) subdir-m += $(__subdir-m) scripts/Makefile.lib Line 47:
subdir-ym := $(sort $(subdir-y) $(subdir-m)) scripts/Makefile.lib Line 89:
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))

 __subdir-y和__subdir-m首先將obj-y、obj-m中的非文件夾濾除,然后通過(guò)patsubst函數(shù)將最后的“/”去除。注意到drivers/Makefile中的obj-y、obj-m通通都是文件夾。我們以obj-y = net/為例進(jìn)行以下內(nèi)容的說(shuō)明,所以__subdir-y=net。

  subdir-ym就是在__subdir-y和__subdir-m前邊添加obj的前綴,所以最終等于drivers/net。

3、drivers/built-in.o的生成

?  scripts/Makefile.build的總目標(biāo)__build中的一個(gè)目標(biāo)是?builtin-target,而它的值為drivers/built-in.o,現(xiàn)在就來(lái)看看它是怎樣生成的。

scripts/Makefile.build Line 288: $(builtin-target): $(obj-y) FORCE$(call if_changed,link_o_target)

<1>?drivers/built-in.o的依賴

  drivers/built-in.o依賴于obj-y(子目標(biāo)),然后通過(guò)調(diào)用一個(gè)if_changed函數(shù),將這些子目標(biāo)連接起來(lái),生成drivers/built-in.o。通過(guò)命令打印查看連接命令如下:

arm-linux-ld -EL -r -o drivers/built-in.o drivers/gpio/built-in.o drivers/video/built-in.o drivers/char/built-in.o drivers/gpu/built-in.o drivers/serial/built-in.o drivers/base/built-in.o drivers/block/built-in.o drivers/misc/built-in.o drivers/mfd/built-in.o drivers/macintosh/built-in.odrivers/scsi/built-in.o drivers/net/built-in.o drivers/ieee1394/built-in.o drivers/cdrom/built-in.odrivers/auxdisplay/built-in.o drivers/mtd/built-in.o drivers/usb/built-in.o drivers/usb/gadget/built-in.odrivers/input/built-in.o drivers/rtc/built-in.o drivers/i2c/built-in.o drivers/media/built-in.odrivers/watchdog/built-in.o drivers/lguest/built-in.o drivers/idle/built-in.o drivers/mmc/built-in.o drivers/firmware/built-in.o drivers/crypto/built-in.o drivers/hid/built-in.o drivers/platform/built-in.o

  看下邊的代碼,原來(lái)drivers/Makefile中的obj-y是一群目錄,通過(guò)第一行代碼后就給這些目錄后邊加上了built-in.o,再經(jīng)過(guò)第二行代碼,給它們冠以前綴。我們以obj-y=net/為例說(shuō)明,經(jīng)過(guò)第一行代碼obj-y=net/built-in.o,經(jīng)過(guò)第二行代碼obj-y=drivers/net/built-in.o

scripts/Makefile.lib Line 42:
obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
scripts/Makefile.lib Line 78:
obj-y := $(addprefix $(obj)/,$(obj-y))

<2> if_changed函數(shù)

  通過(guò)if_changed函數(shù),完成了把這些子目錄中的目標(biāo)連接生成dirvers/built-in.o。?

Kbuild.include Line 192: if_changed = $(if $(strip $(any-prereq) $(arg-check)), \@set -e; \$(echo-cmd) $(cmd_$(1)); \echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

  既然是函數(shù),就會(huì)傳遞參數(shù)。相對(duì)于C語(yǔ)言來(lái)說(shuō)形參就是(1)實(shí)

(call if_changed,link_o_target),其中call是調(diào)用函數(shù)命令,if_changed是調(diào)用函數(shù)名,后邊的link_o_target就是實(shí)參。

①$(if $(strip $(any-prereq) $(arg-check))
any-prereq檢查是否有依賴比目標(biāo)新,或者依賴還沒有創(chuàng)建;arg-check檢查編譯目標(biāo)的命令相對(duì)上次是否發(fā)生變化。如果兩者中只要有一個(gè)發(fā)生改變,if_changed的值就等于
@set -e; \$(echo-cmd) $(cmd_$(1)); \echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd

   否則,if_changed的值為空,也就是說(shuō)$(call if_changed,link_o_target)將什么也不執(zhí)行,因?yàn)闆]必要執(zhí)行。

②set -e 是說(shuō)下邊的命令如果出錯(cuò)了就直接返回,不再繼續(xù)執(zhí)行

③echo-cmd

Kbuild.include Line 156: echo-cmd = $(if $($(quiet)cmd_$(1)),\echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)

  echo-cmd就是打印出調(diào)用的命令。if?(

(quiet)cmd_(1))(quiet)cmd_(1)或者cmd_

(1)是否定義,也就是quiet_cmd_link_o_target或者cmd_link_o_target是否定義。如果有定義,echo-cmd就會(huì)將這個(gè)命令打印出來(lái),也就是打印。

④$(cmd_$(1))

  對(duì)于?$(call if_changed,link_o_target),該命令就是cmd_link_o_target。

scripst/Makefile.build Line 283: cmd_link_o_target = $(if $(strip $(obj-y)),\$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \$(cmd_secanalysis),\rm -f $@; $(AR) rcs $@) $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) ,這個(gè)就是連接命令。

總結(jié):
  if_changed函數(shù)的核心功能就是判斷是否需要更新目標(biāo),如果需要就執(zhí)行表達(dá)式$(cmd_$(1))展開后的值來(lái)完成重建目標(biāo)。

4、drivers/net/built-in.o
?  drivers/built-in.o的依賴如何生成呢,比如說(shuō)drivers/net/built-in.o,還記得subdir-ym嗎?subdir-ym記錄了當(dāng)前目錄里邊要參與編譯連接的子文件夾。在 “2 scripts/Makefile.build階段 ?2、scripts/Makefile.build的總目標(biāo)?<5>?$(subdir-ym)”中,我們假定subdir-ym=drivers/net。

Makefile.build Line 356:?
PHONY += $(subdir-ym) $(subdir-ym):$(Q)$(MAKE) $(build)=$@   $(Q)$(MAKE) $(build)=$@就是再一次調(diào)用scripts/Makefile.build,并傳遞參數(shù)drivers/net,這和生成drivers/built-in.o沒什么差別。?

3 scripts/Makefile.build的再一次調(diào)用階段

  再次轉(zhuǎn)戰(zhàn)到scripts/Makefile.build,obj=drivers/net被帶到該文件。

1、Makefile.build的包含文件

  其包含文件與第一次調(diào)用階段沒什么大的區(qū)別,最為重要的區(qū)別就是包含子目錄Makefile的改變,這次包含的文件是/workspace/linux-2.6.30.4/drivers/net/Makefile。?

2、scripts/Makefile.build的總目標(biāo)

  總目標(biāo)中的builtin-target值為drivers/net/built-in.o

3、drivers/net/built-in.o的生成

scripts/Makefile.build Line 288: $(builtin-target): $(obj-y) FORCE$(call if_changed,link_o_target)

  由于子目錄的Makefile變成了/workspace/linux-2.6.30.4/drivers/net/Makefile,所以obj-y對(duì)應(yīng)的發(fā)生了變化。通過(guò)執(zhí)行編譯查看這個(gè)連接過(guò)程。

arm-linux-ld -EL -r -o drivers/net/built-in.o drivers/net/mii.o drivers/net/Space.o drivers/net/loopback.o drivers/net/dm9000.o drivers/net/arm/built-in.o drivers/net/e1000/built-in.o

<1>?drivers/net/built-in.o的依賴

  從drivers/net/Makefile中摘出兩個(gè)典型的obj-y組成部分如下所示:

drivers/net/Makefile Line 5: obj-$(CONFIG_E1000) += e1000/drivers/net/Makefile Line 230:
obj-$(CONFIG_DM9000) += dm9000.o

  drivers/net/built-in.o的依賴包含了文件夾,并且包含了直接由C文件生成的目標(biāo)文件.o。

scripts/Makefile.lib Line 42: obj-y := $(patsubst %/, %/built-in.o, $(obj-y))scripts/Makefile.lib Line 78: obj-y := $(addprefix $(obj)/,$(obj-y))

  第一行代碼讓obj-y如果是文件夾,就添加built-in.o,如果是普通的目標(biāo)文件*.o,什么也不操作;第二行代碼冠以目錄obj。所以obj-y最終等于drivers/net/e1000/built-in.o、drivers/net/dm9000.o。

  我們?cè)絹?lái)越接近最終的目標(biāo)了--分析到最底層的C文件生成目標(biāo)文件。

<2> if_changed函數(shù)

  drivers/net/built-in.o也是一個(gè)由眾多的文件組成的庫(kù)文件,所以也是通過(guò)調(diào)用if_changed函數(shù)完成連接。

4、drivers/net/dm9000.o

scripts/Makefile.build Line 226: # Built-in and composite module parts $(obj)/%.o: $(src)/%.c FORCE$(call cmd,force_checksrc)$(call if_changed_rule,cc_o_c)scripts/Makefile.build Line 263: $(obj)/%.o: $(src)/%.S FORCE$(call if_changed_dep,as_o_S) $(obj)/%.o: $(src)/%.c FORCE是編譯C程序,$(obj)/%.o: $(src)/%.S FORCE是編譯匯編程序

<1>?drivers/net/dm9000.o的依賴

  drivers/net/dm9000.o的依賴是對(duì)應(yīng)的$(src)/%.c,也就是drivers/net/dm9000.c。

<2>cmd函數(shù)

scripts/Kbuild Line 160: cmd = @$(echo-cmd) $(cmd_$(1))

  此函數(shù)還未做深入分析。

<2>if_changed_rule函數(shù)

scripts/Kbuild Line 205: # Usage: $(call if_changed_rule,foo) # Will check if $(cmd_foo) or any of the prerequisites changed, # and if so will execute $(rule_foo). if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \@set -e; \$(rule_$(1)))   $(call if_changed_rule,cc_o_c),從而會(huì)調(diào)用函數(shù)if_changed_rule,接著會(huì)執(zhí)行命令$(rule_$(1))),也就是rule_cc_o_c。 scripts/Makefile.build Line 215: define rule_cc_o_c$(call echo-cmd,checksrc) $(cmd_checksrc) \$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \$(cmd_modversions) \$(cmd_record_mcount) \scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \$(dot-target).tmp; \rm -f $(depfile); \mv -f $(dot-target).tmp $(dot-target).cmd endef

  其中$(cmd_cc_o_c)命令的定義是

scripts/Makefile.build Line 179:
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

5、drivers/net/e1000/built-in.o的生成

  subdir-ym肯定包含有文件夾drivers/net/e1000,于是繼續(xù)再一次調(diào)用scripts/Makefile.build來(lái)完成drivers/net/e1000/built-in.o的生成。?

Makefile.build Line 356: PHONY += $(subdir-ym) $(subdir-ym):$(Q)$(MAKE) $(build)=$@

?三、Linux內(nèi)核整體編譯過(guò)程

  經(jīng)過(guò)解析過(guò)程的分析,編譯過(guò)程就是解析過(guò)程的相反操作。

1、生成準(zhǔn)備文件

①控制C程序的頭文件

  include/linux/version.h include/linux/utsrelease.h、include/linux/autoconf.h

②控制編譯連接的文件

  arch/arm/kernel/vmlinux.lds、include/config/auto.conf等文件。

2、 由C程序源碼和匯編語(yǔ)言源碼生成目標(biāo)文件(*.o)

3、將目標(biāo)文件連接成*.built-in.o、*/lib.a等文件

4、將緊接著頂層目錄的子目錄中的*.built-in.o以及部分重要的*.o文件連接生成vmlinux

5、根據(jù)arch/arm/Makefile的規(guī)則生成zImage、uImage等

四、Linux內(nèi)核編譯構(gòu)成元素

1、Makefile的目標(biāo)

<1> 總目標(biāo)

  總目標(biāo)實(shí)際上是在arch/arm/Makefile中定義了,比方說(shuō)zImage、uImage,頂層Makefile緊接著定義了這些終極目標(biāo)直接的依賴目標(biāo)vmlinux。

<2> 各級(jí)子目標(biāo)

  各級(jí)子目標(biāo)是在scripts/Makefile.build中的__build中定義的,例如傳遞參數(shù)obj=drivers后的目標(biāo)是drivers/built-in.o。

  這些目標(biāo)的依賴其實(shí)又成為了新的目標(biāo),例如drivers/net/built-in.o、drivers/net/dm9000.o。

2、Makefile的依賴

<1> 總目標(biāo)的依賴

  vmlinux-lds ?vmlinux-init vmlinux-main vmlinux.o kallsyms.o

<2> 各級(jí)子目標(biāo)的依賴

  各級(jí)子目標(biāo)的依賴是由子目錄中的Makefile(實(shí)際是scripts/Makefile.build的包含文件)和scripts/Makefile.lib共同完成確定的。

  子目錄中的Makefile負(fù)責(zé)選材,而scripts/Makefile.lib負(fù)責(zé)加工。

3、Makefile的規(guī)則

<1> 總目標(biāo)的連接規(guī)則

  總目標(biāo)vmlinux的連接規(guī)則就是在頂層Makefile中定義的,至于zImage、uImage則是在arch/arm/Makefile中定義的。

<2>子目標(biāo)的編譯連接規(guī)則

  主要是在scripts/Makefile.build、scripts/Kbuild.include中定義的,其中scripts/Kbuild.include定義了許多諸如if_changed的函數(shù)。

4、Makefile的編譯連接選項(xiàng)

  本文并沒有討論。

五、Linux內(nèi)核Makefile特點(diǎn)

1、兩個(gè)Makefile

 頂層Makefile文件負(fù)責(zé)將各個(gè)目錄生成的*.built-in.o、lib.a等文件連接到一起生成vmlinux。而scripts/Makefile.build 包含子目錄中的Makefile文件以及scripts/中的眾多腳本來(lái)生成這些*.built-in.o、lib.a、*.o等文件。

  通過(guò)“make -f scripts/Makefile.build obj=”的方法完成了頂層Makefile到scripts/Makefile.build的調(diào)用生成*/built-in.o,以及scripts/Makefile.build的自調(diào)用生成更低一級(jí)子目錄的*/built-in.o。

2、編譯的目錄始終是頂層目錄

  “make -C”命令會(huì)先切換工作目錄,然后執(zhí)行該目錄中的Makefile,u-boot就是采用這種方法。而linux則是利用“make -f”的方法,所以編譯的目錄始終是頂層目錄。

3、通用規(guī)則

  Linux內(nèi)核Makefile的通用子Makefile是scripts/Makefile.build,而通用的其他規(guī)則則是scripts中的其他文件。

?

參考資料:《深度探索Linux操作系統(tǒng):系統(tǒng)構(gòu)建和原理解析》

轉(zhuǎn)載于:https://www.cnblogs.com/idyllcheung/p/11196063.html

總結(jié)

以上是生活随笔為你收集整理的linux源码Makefile的详细分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美亚洲一级 | 久久久久网站 | 国产精品男女 | 无码人妻aⅴ一区二区三区日本 | 一区二区三区免费在线观看 | 秋葵视频污 | 亚洲香蕉久久 | 亚洲一卡二卡在线 | 变态另类ts人妖一区二区 | 天天插天天干天天操 | 成年人免费看的视频 | 制服一区二区 | 国产伦理吴梦梦伦理 | 国产综合精品久久久久成人影 | www.色网| 久久视频精品 | 日本香蕉视频 | 日本乱偷人妻中文字幕在线 | 激情六月 | 小明看国产 | 超碰人人艹 | juliaann精品艳妇hd | 欧美乱三级 | 男生和女生靠逼视频 | 日韩女优在线播放 | 91久久精品夜夜躁日日躁欧美 | 男男在线观看 | 少妇理论片 | 色播亚洲| 91久久婷婷| 姑娘第5集在线观看免费 | 宇都宫紫苑在线播放 | 视频二区中文字幕 | 亚洲一卡二卡三卡四卡 | 亚洲国产精品一区 | 春色网站 | 中文字幕有码视频 | 黄色一级一级 | 欧美激情一区在线 | 少妇无套内谢免费视频 | 日韩在线视频一区 | 一区二区三区高清不卡 | 男人的影院 | 国产精品主播 | 丁香花电影免费播放在线观看 | 国产三级视频 | 免费国产一区 | 中文字幕亚洲乱码熟女1区2区 | 香蕉色综合| 欧美日韩www| 日日夜夜伊人 | 最近中文字幕在线观看视频 | 欧美成人精品欧美一级乱黄 | 亚洲AV午夜福利精品一级无码 | 在线观看网站黄 | 另类小说色综合 | 亚洲高清色图 | 狠狠干网 | 91国内| 久久久中文网 | 一区二区在线免费观看 | 性一交一乱一透一a级 | 一级片aaa| 人人搞人人爱 | 国产私拍视频 | 黄色一级大片在线免费看国产一 | 四虎影视免费永久观看在线 | 午夜在线观看视频网站 | 无码国产69精品久久久久网站 | 久久精品国产成人av | 成人免费在线看片 | 国产尤物在线视频 | 国产综合在线播放 | 91av视频网站 | 日韩中文字幕一区二区三区四区 | 日本热久久 | 一级黄色a毛片 | а中文在线天堂 | 开心综合网| av电影在线观看网址 | 亚洲一级特黄 | 国产aaaaaa | 国产伦精品一区二区三区四区 | 久久久蜜桃 | 波多野结衣av在线观看 | 就要操av| 中文毛片无遮挡高潮免费 | 丁香花高清在线观看完整动漫 | 欧美生活一级片 | 警察高h荡肉呻吟男男 | 亚洲熟女乱综合一区二区 | 久久视频免费 | 一本色道久久综合精品婷婷 | 丝袜美腿一区二区三区 | 谁有免费黄色网址 | 欧美 亚洲 一区 | 我们2018在线观看免费版高清 | 精品丰满人妻无套内射 | 久久叉|