linux kernel makefile 分析 - 1
背景說明
版本:
5.10.0 - 下面分析中 使用的行號,都是 參考 這個 版本的 Makefile 。
線上瀏覽: https://lxr.missinglinkelectronics.com/linux/Makefile
使用場景:
在原始碼資料夾下面建立一個build 資料夾,然後使用 O=build
mkdir build
make O=build
三部分的框架
第一部分:1 ~ 36 行 , 1950 ~ 結束 ; 通用部分,
1、定義 VERSION PATCHLEVEL SUBLEVEL EXTRALEVEL NAME 變數
2、make 命令列中如果指定了以 雙下劃線 __ 開頭的目標,則報錯。
3、定義偽目標 __all ;
4、定義 FORCE 偽目標,
6、將 PHONY 變數中的目標,都宣告為 phony 。
第二部分:37~ 188 行,使用 sub_make_done 不為 1 時才進入。只有第一次使用 Makefile 時,這個變數才不為 1,因為在 174 行會 設定這個變數為 1 ,並且匯出。之後啟動的 make 都得到這個變數為 1.
1、讓 make 不要使用 內建規則和內建變數。
2、處理 LC_ALL LC_COLLATE LC_NUMERIC。
3、GREP_OPTIONS 置為空,
4、設定 Q quiet KBUILD_VERBOSE 變數。
5、得到 abs_objtree 的值
6、abs_srctree - 原始碼絕對路徑
7、this_makefile 賦值
8、need-sub-make 的賦值
9 need-sub-make 為 1 ,啟動 sub make
191 ~ 1948 行,使用 need-sub-make 為空時進入,即 不需要啟動 sub make 時使用 191 ~ 1948 之間的內容。
本位不涉及,後面再分析
通用部分
1、定義 VERSION PATCHLEVEL SUBLEVEL EXTRALEVEL NAME 變數
2VERSION = 5 3PATCHLEVEL= 10 4SUBLEVEL = 0 5EXTRAVERSION = 6NAME = Kleptomaniac Octopus
2、make 命令列中如果指定了以 雙下劃線 __ 開頭的目標,則報錯。 __開頭的目標都作為 內部中間目標使用。
14$(if $(filter __%, $(MAKECMDGOALS)), \ 15 $(error targets prefixed with '__' are only for internal use))
3、定義偽目標 __all ;因為命令列如果沒指定目標,則Makefile 中遇到的第一個目標就是預設目標。
17# That's our default target when none is given on the command line 18PHONY := __all 19__all:
4、定義 FORCE 偽目標,依賴FORCE 的目標,都需要 無條件 重新 更新。
1950PHONY += FORCE
1951FORCE:
6、將 PHONY 變數中的目標,都宣告為 phony 。 【宣告為 phony 目標,make 就不會 把這個目標當作檔案目標】
1953# Declare the contents of the PHONY variable as phony. We keep that 1954# information in a variable so we can use it in if_changed and friends. 1955.PHONY: $(PHONY)
首次使用包含內容
1、讓 make 不要使用 內建規則和內建變數。39 ~ 41 通過設定 MAKEFLAGS=-rR實現. 154 ~ 161 如果make版本是 3.x ,設定後,不能立即生效,需要啟動sub make 才生效。
39# Do not use make's built-in rules and variables 40# (this increases performance and avoids hard-to-debug behaviour) 41MAKEFLAGS += -rR 154ifneq ($(abs_srctree),$(abs_objtree)) 155# Look for make include files relative to root of kernel src 156# 157# This does not become effective immediately because MAKEFLAGS is re-parsed 158# once after the Makefile is read. We need to invoke sub-make. 159MAKEFLAGS += --include-dir=$(abs_srctree) 160need-sub-make := 1 161endif
2、處理 LC_ALL LC_COLLATE LC_NUMERIC。
( 編譯機器 本身的 LC 環境可能千差萬別,kernel 中程式碼不能都考慮。換思路:kernel 中的程式碼預設一個 LC環境,在這兒的Makefile 中,將LC環境設定為kernel 程式碼需要LC 環境 )
LC_ALL 選擇 整體的 C 語言環境; 置為空。
LC_COLLATE 選擇 排序(歸類)的環境
LC_NUMERIC 選擇 數字格式 的環境。 德國數字環境,小數點 使用 逗號。
43# Avoid funny character set dependencies 44unexport LC_ALL 45LC_COLLATE=C 46LC_NUMERIC=C 47export LC_COLLATE LC_NUMERIC
3、GREP_OPTIONS 置為空,因為 這個會影響 grep 工具的輸出,kernel 編譯會用到 grep 工具。編譯機器上面 GREP_OPTIONS 影響了grep 輸出,kernel 就得不到自己想要的輸出格式或內容了,所以,這兒置為空,保證grep 輸出是 kernel 預期的內容。
49# Avoid interference with shell env settings 50unexport GREP_OPTIONS
4、設定 Q quiet KBUILD_VERBOSE 變數。
4.1 82 行 預設為 KBUILD_VERBOSE=0, , 90 91 行也就預設 Q=@ ; quiet=quiet_;
4.2 當命令列指定了 V=1時, KBUILD_VERBOSE=1, Q為空 ; quiet 為空; 會 輸出 執行的命令。
4.3 命令列指定 V=2時, KBUILD_VERBOSE=2, Q為@ ; quiet=quiet_ ; 會列印為什麼更新這個目標(但不會列印 執行的命令 )
4.2 當命令列指定了 -s 時,為silent mode , 抑制 echo cmd. 強制修改 quiet=silent_ ; ( KBUILD_VERBOSE 和 Q 依然參照 4.1 4.2 4.3 )
72# If KBUILD_VERBOSE equals 0 then the above command will be hidden. 73# If KBUILD_VERBOSE equals 1 then the above command is displayed. 74# If KBUILD_VERBOSE equals 2 then give the reason why each target is rebuilt. 75# 76# To put more focus on warnings, be less verbose as default 77# Use 'make V=1' to see the full commands 78 79ifeq ("$(origin V)", "command line") 80 KBUILD_VERBOSE = $(V) 81endif 82ifndef KBUILD_VERBOSE 83 KBUILD_VERBOSE = 0 84endif 85 86ifeq ($(KBUILD_VERBOSE),1) 87 quiet = 88 Q = 89else 90 quiet=quiet_ 91 Q = @ 92endif 93 94# If the user is running make -s (silent mode), suppress echoing of 95# commands 96 97ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),) 98 quiet=silent_ 99endif 100 101export quiet Q KBUILD_VERBOSE
5、得到 abs_objtree 的值
5.1 138 行,如果命令列 沒有使用 O=dir 指定 輸出檔案存放目錄,則 abs_objdir=$(CURDIR)
5.2 如果命令列使用了O=dir指定了,就將abs_objdir 賦值為 指定 dir 的絕對路徑(如果dir是符號連結,找到真實路徑)。具體如下:
123 ~ 126 判斷命令列有O=dir ,設定KBUILD_OUTPUT
128 發現 KBUILD_OUTPUT 不為空,131 行賦值 abs_objtree 為指定的dir的絕對路徑
132 ~ 133 檢查 abs_objtree 不為空,如果為空(可能原因是資料夾不存在),就報錯。
136 ,如果是符號連結,轉換為真實路徑。
123# Do we want to change the working directory? 124ifeq ("$(origin O)", "command line") 125 KBUILD_OUTPUT := $(O) 126endif 127 128ifneq ($(KBUILD_OUTPUT),) 129# Make's built-in functions such as $(abspath ...), $(realpath ...) cannot 130# expand a shell special character '~'. We use a somewhat tedious way here. 131abs_objtree := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) && pwd) 132$(if $(abs_objtree),, \ 133 $(error failed to create output directory "$(KBUILD_OUTPUT)")) 134 135# $(realpath ...) resolves symlinks 136abs_objtree := $(realpath $(abs_objtree)) 137else 138abs_objtree := $(CURDIR) 139endif # ifneq ($(KBUILD_OUTPUT),)
6、abs_srctree - 原始碼絕對路徑 - 賦值並檢查(不包含空格,冒號)
148abs_srctree := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) 149 150ifneq ($(words $(subst :, ,$(abs_srctree))), 1) 151$(error source directory cannot contain spaces or colons) 152endif
7、this_makefile 賦值
163 this-makefile := $(lastword $(MAKEFILE_LIST))
8、need-sub-make 的賦值
這個預設為空。
賦值為 1 的情況有 3 中。
a: make版本是 3.x , 需要讓 MAKEFLAGS=-rR 生效。參考 本節 1 。
b: abs_objtree 和 $(CURDIR) 不相同。 144 else 進入,145 行 賦值。
141ifeq ($(abs_objtree),$(CURDIR)) 142# Suppress "Entering directory ..." unless we are changing the work directory. 143MAKEFLAGS += --no-print-directory 144else 145need-sub-make := 1 146endif
c: abs_objtree 和 abs_srctree 不相同。 154 判斷,160 賦值。
154ifneq ($(abs_srctree),$(abs_objtree)) 155# Look for make include files relative to root of kernel src 156# 157# This does not become effective immediately because MAKEFLAGS is re-parsed 158# once after the Makefile is read. We need to invoke sub-make. 159MAKEFLAGS += --include-dir=$(abs_srctree) 160need-sub-make := 1 161endif
9 need-sub-make 為 1 ,啟動 sub make
176 行判斷,進入
178 行 宣告 __sub-make 偽目標
180 行,讓命令列目標 預設目標 __all 和 $(this-makefile) 目標都依賴 __sub-make 偽目標
184 ·~ 186 定義 __sub-make 偽目標的更新命令,啟動 下一個make 並指定makefile ,將 命令列目標也傳遞給它。
176ifeq ($(need-sub-make),1) 177 178PHONY += $(MAKECMDGOALS) __sub-make 179 180$(filter-out $(this-makefile), $(MAKECMDGOALS)) __all: __sub-make 181 @: 182 183# Invoke a second make in the output directory, passing relevant variables 184__sub-make: 185 $(Q)$(MAKE) -C $(abs_objtree) -f $(abs_srctree)/Makefile $(MAKECMDGOALS) 186 187endif # need-sub-make
最後一次進入包含內容
這部分內容較多,一步步慢慢來分解