三、編譯第一步 make xxx_defconfig


3.1 頂層make defconfig規則

  make xxx_defconfig 的執行主要分成三個部分:

  1. 執行 make -f ./scripts/Makefile.build obj=scripts/basic,編譯生成 scripts/basic/fixdep 工具
  2. 執行 make -f ./scripts/Makefile.build obj=scripts/kconfig rpi_3_32b_defconfig 編譯生成 scripts/kconfig/conf 工具
  3. 執行 scripts/kconfig/conf --defconfig=arch/../configs/xxx_defconfig Kconfig生成最終的 .config 配置文件 

  執行 make xxx_defconfig 命令時,u-boot 根目錄下的 Makefile 中有唯一的規則匹配目標:

  代碼第 467 到 478 行

 1 # ===========================================================================
 2 # *config targets only - make sure prerequisites are updated, and descend  3 # in scripts/kconfig to make the *config target  4 
 5 KBUILD_DEFCONFIG := sandbox_defconfig  6 export KBUILD_DEFCONFIG KBUILD_KCONFIG  7 
 8 config: scripts_basic outputmakefile FORCE  9     $(Q)$(MAKE) $(build)=scripts/kconfig $@ 10 
11 %config: scripts_basic outputmakefile FORCE 12     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  注釋意思為,僅限 *config 目標,確保先決條件已經更新,並在 scripts/kconfig 下創建 *config 目標。上面有兩個變量 config 和 %config,% 符號為通配符,對應所有的 xxxconfig 目標,前面已經說過。我們的 make xxx_defconfig 就對應 %config,我們並沒有執行 make config 命令。

  Makefile中幾種變量賦值運算符:

  • =      :最簡單的賦值 
  • :=     :一般也是賦值 
    • 以上這兩個大部分情況下效果是一樣的,但是有時候不一樣。
    • 用 = 賦值的變量,在被解析時他的值取決於最后一次賦值時的值,所以看變量引用的值時不能只往前面看,還要往后面看。
    • 用 := 來賦值的,則是就地直接解析,只用往前看即可。  
  • ?=     : 如果變量前面並沒有賦值過則執行這條賦值,如果前面已經賦值過了則本行被忽略。
  • +=   用來給一個已經賦值的變量接續賦值,意思就是把這次的值加到原來的值的后面,有點類似於strcat     
    • 在shell makefile等文件中,可以認為所有變量都是字符串,+= 就相當於給字符串 strcat 接續內容
    • +=續接的內容和原來的內容之間會自動加一個空格隔開

3.1.1 代碼執行到%config 的條件  

  先往上分析下這段代碼的執行條件: ifeq ($(config-targets),1),代碼在415 到 447 行

 1 # To make sure we do not include .config for any of the *config targets
 2 # catch them early, and hand them over to scripts/kconfig/Makefile 3 # It is allowed to specify more targets when calling make, including 4 # mixing *config targets and build targets. 5 # For example 'make oldconfig all'. 6 # Detect when mixed targets is specified, and make a second invocation 7 # of make so .config is not included in this case either (for *config). 8 9 version_h := include/generated/version_autogenerated.h 10 timestamp_h := include/generated/timestamp_autogenerated.h 11 12 no-dot-config-targets := clean clobber mrproper distclean \ 13 help %docs check% coccicheck \ 14  ubootversion backup tests 15 16 config-targets := 0 17 mixed-targets := 0 18 dot-config := 1 19 20 ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) 21 ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) 22 dot-config := 0 23  endif 24 endif 25 26 ifeq ($(KBUILD_EXTMOD),) 27 ifneq ($(filter config %config,$(MAKECMDGOALS)),) 28 config-targets := 1 29 ifneq ($(words $(MAKECMDGOALS)),1) 30 mixed-targets := 1 31  endif 32  endif 33 endif

  代碼注釋內容:為了確保我們不包含任何 * config 目標的 .config,請盡早捕獲它們,並將它們交給 scripts / kconfig / Makefile。調用make 時允許指定更多目標,包括混合 * config 目標和構建目標。例如 'make oldconfig all' 。檢測何時指定了混合目標,並進行make的第二次調用,因此 .config不包含在這種情況下(對於* config)。

  • version_h:版本號文件,此文件是自動生成的
  • timestamp_h:時間戳文件,此文件是自動生成的
  • no-dot-config-targets:指代的是那些和 .config 沒有關系的目標
  • config-targets:配置目標,初始值設置為0
  • mixed-targets:混合目標,初始值設置為0
  • dot-config:初始值設置為1

  變量 MAKECMDGOALS:make 在執行時會設置一個特殊變量 -- "MAKECMDGOALS" ,該變量記錄了命令行參數指定的終極目標列表,沒有通過參數指定終極目標時此變量為空。該變量僅限於用在特殊場合(比如判斷),在 Makefile 中最好不要對它進行重新定義。

  我們執行  make xxx_defconfig 的時候,MAKECMDGOALS 變量的值就為 xxx_defconfig。

  filter 函數 和 filter-out 函數:

1 $(filter PATTERN…,TEXT) 2 函數名稱:  過濾函數— filter。 3 函數功能:  過濾掉字串“ TEXT”中所有不符合模式“ PATTERN”的單詞,保留所 4        有符合此模式的單詞。可以使用多個模式。模式中一般需要包含模式字 5        符“ %”。存在多個模式時,模式表達式之間使用空格分割。 6 返回值:空格分割的“ TEXT”字串中所有符合模式“ PATTERN”的字串。 7 函數說明:“ filter”函數可以用來去除一個變量中的某些字符串
1 $(filter-out PATTERN...,TEXT) 2 函數名稱:  反過濾函數— filter-out 3 函數功能:  和“ filter”函數實現的功能相反。過濾掉字串“ TEXT”中所有符合模式“ PATTERN”的單詞,保留所有不符合此模式的單詞。
        可以有多個模式。存在多個模式時,模式表達式之間使用空格分割 4 返回值:  空格分割的“ TEXT”字串中所有不符合模式“ PATTERN”的字串。 5 函數說明:  “ filter-out”函數也可以用來去除一個變量中的某些字符串,(實現和“ filter”函數相反)

  代碼執行的過程就為,如果 過濾掉 MAKECMDGOALS 不符合 no-dot-config-targets 后結果不為空,則執行分支語句。很顯然過濾后為空,則不執行分支語句,dot-config 依然 值為1。

  接着執行下一條 ifeq 語句,對 KBUILD_EXTMOD 進行判定。KBUILD_EXTMODE 的賦值地方在代碼 182 到 191 行處:

 1 # Use make M=dir to specify directory of external module to build
 2 # Old syntax make ... SUBDIRS=$PWD is still supported
 3 # Setting the environment variable KBUILD_EXTMOD take precedence
 4 ifdef SUBDIRS
 5   KBUILD_EXTMOD ?= $(SUBDIRS)
 6 endif
 7 
 8 ifeq ("$(origin M)", "command line")
 9   KBUILD_EXTMOD := $(M)
10 endif

  由注釋可以知道,SUBDIRS 這個變量是通過執行 make 的時候傳進來的,我們並沒有執行此項,所以未定義SUBDIRS,第一個分支不會去走。第二個 if 語句為 ifeq 語句,這里使用 origin 函數。

  origin 函數不是操作變量(即它的參數),它只是獲取此變量(參數)相關的信息,告訴我們這個變量的出處(定義方式)。

  那么 ifeq 語句可以理解為 如果make傳入的命令行變量存在且是M,那么,變量KBUILD_EXTMOD變為變量M的值。

  第一階段中我們並沒有傳入 M 值,則 KBUILD_EXTMOD 值為空

  繼續回到此小節主代碼處,當前執行 KBUILD_EXTMOD 的判定,此處滿足 ifeq  條件,開始執行分支語句,分支語句同樣是一個判斷,首先過濾掉 MAKECMDGOALS 不符合 config 和 %config 模式的字符串,然后返回 xxx_defconfig ,xxx_defconfig 再與 空進行比較,if 語句為 ifneq ,很顯然, filter  語句不為空,與空進行比較,滿足 ifneq 執行語句。

  此處將 config-targets 重新賦值為 1;賦值完后,進行  ifneq  條件判斷,再次涉及  makefile 的函數——words。

  

  顯然我們的傳入的單詞數據為1,與1相等,則不執行分支,即 mixed-targets 不進行重新賦值,依然為0。

  再代碼進行到 ifeq ($(config-targets),1) 時候,先進行了 ifeq ($(mixed-targets),1)分支,如果 mixed-targets 則執行另一條分支,就不會再執行ifeq ($(config-targets),1) 了。我們這里執行的ifeq ($(mixed-targets),1) 的 else中的分支語句。

  到此處,ifeq ($(config-targets),1) 是否會執行已經分析完畢。

  當前我們已經知道的變量的值為:

  • MAKECMDGOALS = xxx_defconfig
  • KBUILD_EXTMOD =
  • version_h := include/generated/version_autogenerated.h
  • timestamp_h := include/generated/timestamp_autogenerated.h
  • no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
  • config-targets := 1
  • mixed-targets := 0
  • dot-config := 1

3.1.2 %config分析

  ifeq ($(config-targets),1) 中也由else分支,我們從上面的小節可以知道,else 分支不會去執行。所以很多代碼可以忽略了

  

  從這里可以知道,此處此處選擇語句一直執行到 1655 行,466~480 行才是我們需要分析的。

  471 到 472 行

1 KBUILD_DEFCONFIG := sandbox_defconfig
2 export KBUILD_DEFCONFIG KBUILD_KCONFIG

  這里定義了兩個環境變量:

  • KBUILD_DEFCONFIG = sandbox_defconfig  
  • KBUILD_KCONFIG 為空

  繼續執行474 到 475 行

1 config: scripts_basic outputmakefile FORCE
2     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  此處目標沒有匹配,不會去執行

  繼續執行477 478 行

1 %config: scripts_basic outputmakefile FORCE
2     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  %config 依賴scripts_basic outputmakefile  FORCE

(1)依賴 FORCE

  FORCE 的定義在 1748 和 1749 行

1 PHONY += FORCE
2 FORCE:

  FORCE被定義為一個空目標。如果一個目標添加 FORCE 依賴,每次編譯都會去先去執行 FORCE(實際上什么都不做),然后運行命令更新目標,這樣就能確保目標每次都會被更新。

(2)依賴 scripts_basic

  392 - 402 行

 1 # ===========================================================================
 2 # Rules shared between *config targets and build targets
 3 
 4 # Basic helpers built in scripts/
 5 PHONY += scripts_basic
 6 scripts_basic:
 7     $(Q)$(MAKE) $(build)=scripts/basic
 8     $(Q)rm -f .tmp_quiet_recordmcount
 9 
10 # To avoid any implicit rule to kick in, define an empty command.
11 scripts/basic/%: scripts_basic ;

   Q = @,MAKE = make,build 變量的定義在 scripts/Kbuild.include 文件中

  主Makefile 在327-329 行包含 scripts/Kbuild.include 文件

1 # We need some generic definitions (do not try to remake the file).
2 scripts/Kbuild.include: ;
3 include scripts/Kbuild.include

  build 變量在 scripts/Kbuild.include 在177 - 181 行定義

1 ###
2 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
3 # Usage:
4 # $(Q)$(MAKE) $(build)=dir
5 build := -f $(srctree)/scripts/Makefile.build obj

  srctree 定義在主 Makefile 中202-212 行

 1 ifeq ($(KBUILD_SRC),)
 2         # building in the source tree
 3         srctree := .
 4 else
 5         ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
 6                 # building in a subdirectory of the source tree
 7                 srctree := ..
 8         else
 9                 srctree := $(KBUILD_SRC)
10         endif
11 endif

  KBUILD_SRC (構建的源碼目錄) 在執行 make 命令的時候並沒有傳入,設為空,則srctree 為當前 uboot 源碼的根目錄

  scripts/Kbuild.include 在177 - 181 行的展開為:build := -f ./scripts/Makefile.build obj

  主 Makefile 中 scripts_basic 的展開為:

1 scripts_basic: 2 make -f ./scripts/Makefile.build obj=scripts/basic  # 根據傳入的 obj 參數顯示的執行 ./scripts/Makefile.build 文件 3 rm -f .tmp_quiet_recordmcount

  ./scripts/Makefile.build 文件之后再分析。

(3)outputmakefile 依賴

  404 - 413 行

 1 PHONY += outputmakefile
 2 # outputmakefile generates a Makefile in the output directory, if using a
 3 # separate output directory. This allows convenient use of make in the
 4 # output directory.
 5 outputmakefile:
 6 ifneq ($(KBUILD_SRC),)
 7     $(Q)ln -fsn $(srctree) source
 8     $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
 9         $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
10 endif

  KBUILD_SRC 為空,所以ifneq 中的語句不會執行。 outputmakefile 為空

  重新回到 %config 處

1 %config: scripts_basic outputmakefile FORCE
2     $(Q)$(MAKE) $(build)=scripts/kconfig $@

  依據前面的條件,展開表達式為:

1 make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig

3.2 總結

3.2.1 變量

  • MAKECMDGOALS = xxx_defconfig
  • KBUILD_EXTMOD =
  • version_h := include/generated/version_autogenerated.h
  • timestamp_h := include/generated/timestamp_autogenerated.h
  • no-dot-config-targets := clean clobber mrproper distclean help %docs check% coccicheck ubootversion backup tests
  • config-targets := 1
  • mixed-targets := 0
  • dot-config := 1
  • KBUILD_SRC =
  • build := -f ./scripts/Makefile.build obj

3.2.2 環境變量

  • KBUILD_DEFCONFIG := sandbox_defconfig
  • KBUILD_KCONFIG =

3.2.3 需要進行分析的地方

(1)scripts_basic 目標執行的命令

  make -f ./scripts/Makefile.build obj=scripts/basic

(2)%config 目標執行的命令

  make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig


免責聲明!

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



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