Linux Kbuild文档 3
Linux內核源代碼是通過Makefile組織編譯的,Linux2.6內核Makefile的許多特性和2.4內核差別很大,在內核目錄的documention/kbuild/makefiles.txt中有詳細的說明。
3.1 Makefile的組織結構Linux內核的Makefile分為5個部分,如表6所示:
表6 Makefile的5個部分
| Makefile | 頂層Makefile |
| .config | 內核配置文件 |
| arch/$(ARCH)/Makefile | 具體架構的Makefile |
| scripts/Makefile.* | 通用的規則等。面向所有的Kbuild Makefiles。 |
| kbuild Makefiles | 內核源代碼中大約有500個這樣的文件 |
頂層Makefile閱讀的.config文件,而該文件是由內核配置程序生成的。
頂層Makefile負責制作:vmlinux(內核文件)與模塊(任何模塊文件)。制作的過程主要是
通過遞歸向下訪問子目錄的形式完成。并根據內核配置文件確定訪問哪些子目錄。頂層Makefile要原封不動的包含一具體架構的Makefile,其名字類似于arch/$(ARCH)/Makefile。該架構Makefile向頂層Makefile提供其架構的特別信息。
每一個子目錄都有一個Kbuild Makefile文件,用來執行從其上層目錄傳遞下來的命令。
Kbuild Makefile從.config文件中提取信息,生成Kbuild完成內核編譯所需的文件列表。
scripts/Makefile.*包含了所有的定義、規則等信息。這些文件被用來編譯基于kbuild
Makefile的內核。
3.2 Makefile語言內核的Makefile使用的是GNU Make。該Makefile只使用GNU Make已注明的功能,并使用了許多GNU?的擴展功能。
GNU Make支持基本的顯示處理過程的函數。內核Makefile?使用了一種類似小說的方式,顯示"if"語句的構造、處理過程。
GNU Make?有2個賦值操作符,":="和"="。":=",將對右邊的表達式求值,并將所求的值賦給左邊。"="更像是一個公式定義,只是將右邊的值簡單的賦值給左邊,當左邊的表達式被使用時,才求值。
有時使用"="是正確的。但是,一般情況下,推薦使用":="。
3.3 Kbuild?變量頂層Makefile輸出以下變量:
(1)VERSION、PATCHLEVEL、SUBLEVEL和EXTRAVERSION
這些變量定義了當前內核的版本號。只有很少一部分Makefile會直接用到這些變量;可使用?$(KERNELRELEASE)代替。$(VERSION),$(PATCHLEVEL),和$(SUBLEVEL)定義了最初使用的三個數字的版本號,比如"2""4"和"0"。這三個值一般是數字。$(EXTRAVERSION)?為了補丁定義了更小的版本號。一般是非數字的字符串,比如"-pre4"?,或就空著。
(2)KERNELRELEASE
$(KERNELRELEASE)?是一個字符串,類似"2.4.0-pre4",用于安裝目錄的命名或顯示當前的版本號。一部分架構Makefile使用該變量。
(3)ARCH
該變量定義了目標架構,比如"i386","arm"?或"sparc"。有些Kbuild Makefile根據?$(ARCH)?決定編譯哪些文件。
默認情況下,頂層Makefile將其設置為本機架構。如果是跨平臺編譯,用戶可以用下面的命令覆蓋該值:
make ARCH=m68k ...
(4)INSTALL_PATH
該變量為架構Makefile定義了安裝內核鏡像與?System.map?文件的目錄。主要用來指明架構特殊的安裝路徑。
(5)INSTALL_MOD_PATH和MODLIB
$(INSTALL_MOD_PATH)?為了安裝模塊,給?$(MODLIB)?聲明了前綴。該變量不能在Makefile中定義,但可以由用戶傳給Makefile。
$(MODLIB)?具體的模塊安裝的路徑。頂層Makefile將$(MODLIB)定義為
$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)。用戶可以通過命令行參數的形式將其覆蓋。
(6)INSTALL_MOD_STRIP
如果該變量有定義,模塊在安裝之前,會被剝出符號表。如果INSTALL_MOD_STRIP?為?"1",就使用默認選項?--strip-debug。否則,INSTALL_MOD_STRIP?將作為命令?strip的選項使用。
3.4 Kbuild Makefile的定義大部分內核中的Makefile都是使用Kbuild組織結構的Kbuild Makefile。這章介紹了
Kbuild Makefile的語法。
Kbuild文件傾向于"Makefile"這個名字,"Kbuild"也是可以用的。但如果"Makefile"
"Kbuild"同時出現的話,使用的將會是"Kbuild"文件。
3.4.1?目標定義
目標定義是Kbuild Makefile的主要部分,也是核心部分。主要是定義了要編
譯的文件,所有的選項,以及到哪些子目錄去執行遞歸操作。
最簡單的Kbuild makefile?只包含一行,如:
該例子告訴Kbuild在這目錄里,有一個名為foo.o的目標文件。foo.o將從foo.c或foo.S文件編譯得到。
如果foo.o要編譯成一模塊,那就要用obj-m了。所采用的形式如下:
$(CONFIG_FOO)可以為y(編譯進內核)?或m(編譯成模塊)。如果CONFIG_FOO不是y和m,那么該文件就不會被編譯聯接了。
3.4.2?編譯進內核?- obj-y
Kbuild Makefile?規定所有編譯進內核的目標文件都存在$(obj-y)列表中。而這些列表依賴內核的配置。
Kbuild編譯所有的$(obj-y)文件。然后,調用"$(LD) -r"將它們合并到一個build-in.o文件中。稍后,該build-in.o會被其父Makefile聯接進vmlinux中。
$(obj-y)中的文件是有順序的。列表中有重復項是可以的:當第一個文件被聯接到built-in.o中后,其余文件就被忽略了。聯接也是有順序的,那是因為有些函數(module_init()/__initcall)將會在啟動時按照他們出現的順序進行調用。所以,記住改變聯接的順序可能改變你SCSI控制器的檢測順序,從而導致你的硬盤數據損害。
舉例說明obj-y:
3.4.3?編譯可裝載模塊?- obj-m
$(obj-m)?列舉出了哪些文件要編譯成可裝載模塊。
一個模塊可以由一個文件或多個文件編譯而成。如果是一個源文件,Kbuild Makefile只需簡單的將其加到$(obj-m)中去就可以了。例如:
注意:此例中?$(CONFIG_ISDN_PPP_BSDCOMP)?的值為'm'
如果內核模塊是由多個源文件編譯而成,那你就要采用上面那個例子一樣的方法去聲明你所要編譯的模塊。Kbuild需要知道你所編譯的模塊是基于哪些文件,所以你需要通過變量$(<module_name>-objs)來告訴它。例如:
在這個例子中,模塊名將是isdn.o,Kbuild將編譯在$(isdn-objs)中列出的所有文件,然后使用"$(LD) -r"生成isdn.o。
Kbuild能夠識別用于組成目標文件的后綴-objs和后綴-y。這就讓Kbuild Makefile可以通過使用?CONFIG_?符號來判斷該對象是否是用來組合對象的。例如:
在這個例子中,如果?$(CONFIG_EXT2_FS_XATTR)?是?'y',xattr.o將是復合對象ext2.o的一部分。
注意:當然,當你要將其編譯進內核時,上面的語法同樣適用。所以,如果你的CONFIG_EXT2_FS=y,那Kbuild會按你所期望的那樣,生成ext2.o文件,然后將其聯接到built-in.o中。
3.4.4目標庫文件?- lib-y
在obj-*中所列文件是用來編譯模塊或者是聯接到特定目錄中的built-in.o。同樣,也可以列出一些將被包含在lib.a庫中的文件。在?lib-y?中所列出的文件用來組成該目錄下的一個庫文件。在obj-y與lib-y中同時列出的文件,因為都是可以訪問的,所以該文件是不會被包含在庫文件中的。同樣的情況,lib-m中的文件就要包含在lib.a庫文件中。
注意,一個Kbuild makefile可以同時列出要編譯進內核的文件與要編譯成庫的文件。所以,在一個目錄里可以同時存在built-in.o與lib.a兩個文件。例如:
這將由?checksum.o?和delay.o?兩個文件創建一個庫文件?lib.a。為了讓Kbuild真正認識到這里要有一個庫文件lib.a要創建,其所在的目錄要加到libs-y列表中。
3.4.5遞歸向下訪問目錄
一個Makefile只對編譯所在目錄的對象負責。在子目錄中的文件的編譯要由其所在的子目錄的Makefile來管理。只要你讓Kbuild知道它應該遞歸操作,那么該系統就會在其子目錄中自動的調用?make?遞歸操作。
這就是obj-y和obj-m的作用。比如ext2被放的一個單獨的目錄下,在fs目錄下的Makefile會告訴Kbuild使用下面的賦值進行向下遞歸操作。
如果?CONFIG_EXT2_FS?被設置為?'y'(編譯進內核)或是'm'(編譯成模塊),相應的?obj-?變量就會被設置,并且Kbuild就會遞歸向下訪問?ext2?目錄。Kbuild只是用這些信息來決定它是否需要訪問該目錄,而具體怎么編譯由該目錄中的Makefile來決定。將?CONFIG_?變量設置成目錄名是一個好的編程習慣。這讓Kbuild在完全忽略那些相應的CONFIG_?值不是'y'和'm'的目錄。
3.4.6編輯標志
編輯標記包括:EXTRA_CFLAGS,、EXTRA_AFLAGS、EXTRA_LDFLAGS、EXTRA_ARFLAG。所有的EXTRA_變量只在所定義的Kbuild Makefile中起作用。EXTRA_變量可以在Kbuild Makefile中所有命令中使用。
$(EXTRA_CFLAGS)?是用?$(CC)?編譯C源文件時的選項。例如:
該變量是必須的,因為頂層Makefile擁有變量?$(CFLAGS)?并用來作為整個源代碼樹的編譯選項。
$(EXTRA_AFLAGS)?也是一個針對每個目錄的選項,只不過它是用來編譯匯編源代碼的。例如:
$(EXTRA_LDFLAGS)和$(EXTRA_ARFLAGS)分別與$(LD)和$(AR)類似,只不過它們是針對每個目錄的。例如:
CFLAGS_$@, AFLSGA_$@
CFLAGS_$@?和?AFLAGS_$@?只能在當前Kbuild Makefile中的命令中使用。
$(CFLAGS_$@)?是?$(CC)?針對每個文件的選項。$@?表明了具體操作的文件。例如:
以上三行分別設置了aha152x.o,gdth.o?和?seagate.o的編輯選項。
$(AFLAGS_$@)?也類似,只不是是針對匯編語言的。例如:
3.4.7依賴跟蹤
Kbuild?跟蹤在以下方面依賴:
1)?所有要參與編譯的文件(所有的.c?和.h文件)
2)?在參與編譯文件中所要使用的?CONFIG_?選項
3)?用于編譯目標的命令行
因此,如果你改變了?$(CC)?的選項,所有受影響的文件都要重新編譯。
3.4.8特殊規則
特殊規則就是那Kbuild架構不能提供所要求的支持時,所使用的規則。一個典型的例子就是在構建過程中生成的頭文件。另一個例子就是那些需要采用特殊規則來準備啟動鏡像。
特殊規則的寫法與普通Make規則一樣。Kbuild并不在Makefile所在的目錄執行,所以所有的特殊規則都要提供參與編譯的文件和目標文件的相對路徑。
在定義特殊規則時,要使用以下兩個變量:$(src)和$(obj)。$(src)?表明Makefile所在目錄的相對路徑。經常在定位源代碼樹中的文件時,使用該變量。$(obj)?表明目標文件所要存儲目錄的相對路徑。經常在定位所生成的文件時,使用該變量。例如:
這就是一個特殊規則,遵守著make所要求的普通語法。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Linux Kbuild文档 3的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡以卡养卡
- 下一篇: 如何构建自己的SIP SERVER!