Linux內核的Makefile和kconfig解讀

一、概述 

  在內核編譯中如何將各個目錄樹中的文件組織起來編譯是一個很重要的問題,並且要根據用戶配置來編譯特有的內核。爲了解決這個問題,內核使用兩種文件,Makefie和Kconfig。分佈到各目錄的Kconfig構成了一個分佈式的內核配置數據庫,每個Kconfig分別描述了所屬目錄源文檔相關的內核配置菜單,就是我們使用命令 make menuconfig(或者xconfig)後產生的配置菜單,此菜單包含多層,每個層次都是由各個目錄中的Kconfig產生的。用戶根據需求來選擇如何編譯內核,然後將配置結果保存到.config中,然後執行Makefile時就會根據.config的結果來實現內核的編譯。

  這個過程是由kbuild系統來完成的,Linux編譯系統會兩次掃描Linux的Makefile:首先編譯系統會讀取Linux內核頂層的Makefile,然後根據讀到的內容第二次讀取Kbuild的Makefile來編譯Linux內核。內核編譯系統或者說kbuild,是一種在編譯內核時,可以對內核配置選項進行選擇的機制。2.6內核樹中已經更新了這種機制,新版本的kbuild 不僅高速而且備有更完善的文檔。Kbuild機制完全依賴於源代碼的層次結構。

  二、Makefile文件

  面對樹狀結構的內核源碼目錄,內核編譯採用了各個子目錄擁有自己目錄相關的Makefile(被稱爲sub-Makefile或kbuild Makefile),內核編譯依賴於各個子目錄下的子makefile(sub-Makefile)文件,這些sub-Makefile定義了根據該子目錄下的源碼文件構建目標文件的規則,並且僅對該目錄下的文件作適當的修改。頂層Makefile採用遞歸的方式調用位於init/, drivers/, sound/, net/, lib/ ,usr/等目錄下的各個子目錄中的 Makefile文件。在遞歸調用之前,kbuild首先要確定是否已經滿足一些必要的條件,包括在必要時更新include/Linux/version.h文件,並設置符號鏈接include/asm,使之指向與目標體系結構相關的文件。例如,如果爲PPC編譯代碼,則include/asm指向include/asm-ppc。kbuild還要對文件include/Linux/autoconf.h和include/Linux/config進行編譯。之後,從根目錄開始進行遞歸。

  各個子Makefile文件比較簡單,指出了該如何編譯目標文件,例如/mm目錄下的Makefile片段:

  16 obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o

  17 obj-$(CONFIG_BOUNCE)    += bounce.o

  18 obj-$(CONFIG_SWAP)      += page_io.o swap_state.o swapfile.o thrash.o

  19 obj-$(CONFIG_HAS_DMA)   += dmapool.o

  20 obj-$(CONFIG_HUGETLBFS) += hugetlb.o

  三、Kconfig文件

  Kconfig的作用就是爲了讓用戶配置內核,在Kconfig中定義了一些變量,用戶通過設置變量的值來選擇如何個性化自己的系統內核。定義的變量將在

  每個菜單都有一個關鍵字標識,最常見的就是config

  語法:

  config

  symbol是個新的標記的菜單項,options是在這個新的菜單項下的屬性和選項

  其中options部分有:

  1、類型定義:

  每個config菜單項都要有類型定義,bool布爾類型、 tristate三態:內建、模塊、移除 string字符串、 hex十六進制、 integer整型

  例如config HELLO_MODULE

  bool “hello test module”

  bool 類型的只能選中或不選中,tristate類型的菜單項多了編譯成內核模塊的選項,假如選擇編譯成內核模塊,則會在.config中生成一個 CONFIG_HELLO_MODULE=m的配置,假如選擇內建,就是直接編譯成內核影響,就會在.config中生成一個 CONFIG_HELLO_MODULE=y的配置.

  2、依賴型定義depends on或requires

  指此菜單的出現和否依賴於另一個定義

  config HELLO_MODULE

  bool “hello test module”

  depends on ARCH_PXA

  這個例子表明HELLO_MODULE這個菜單項只對XScale處理器有效。

  3、幫助性定義

  只是增加幫助用關鍵字help或—help—

  四、.config文件

  上面提到了利用內核配置工具自動生成名爲.config的內核配置文件,這是編譯內核的第一步。.config文件位於源代碼根目錄下,描述所有內核配置選項,可以藉助內核配置工具來選擇這些選項。每個內核配置選項都有相關的名字和變量值。其名字形如CONFIG_<NAME>,其中<NAME>是對相關選項的標識,在Kconfig文件中定義;變量可以有三個值:y,m或n。y代表“yes”,表示該選項將會被編譯到內核源代碼中,或者說會被編譯到系統中。m代表“module” ,表示該選項將會以模塊的方式編譯到內核中。如果未選擇該選項(即將該選項的變量值設爲n,代表“no”),那麼.config文件中就會出現下列註釋:“CONFIG_<NAME> is not set”。.config文件中選項的位置根據它們在內核配置工具中的位置進行排序,註釋部分說明該選項位於哪個菜單下。我們來看看一個.config文件的節選:

  1 #

  2 # Automatically generated make config: don’t edit

  3 #

  4 CONFIG_X86=y

  5 CONFIG_MMU=y

  6 CONFIG_UID16=y

  7 CONFIG_GENERIC_ISA_DMA=y

  8

  9 #

  10 # Code maturity level options

  11 #

  12 CONFIG_EXPERIMENTAL=y

  13 CONFIG_CLEAN_COMPILE=

  14 CONFIG_STANDALONE=y

  15 CONFIG_BROKEN_ON_SMP=y

  16

  17 #

  18 # General setup

  19 #

  20 CONFIG_SWAP=y

  21 CONFIG_SYSVIPC=y

  22 #CONFIG_POSIX_MQUEUE is not set

  23 CONFIG_BSD_PROCESS_ACCT=y

  上述.config文件指出第4到第7行的選項位於頂層菜單中,第12到第15行的選項位於代碼成熟度選項菜單中,第20行到第23行的選項位於通用設置選項菜單中。

  所有配置工具都會產生上述菜單,並且已經看到前幾個選項、代碼成熟度選項、及通用設置選項都位於頂層。後面兩個選項被擴展爲包含多個選項的子菜單。這些菜單都是在調用xconfig命令時,由qconf配置工具提供的。配置工具顯示的菜單都默認用於X86體系結構。

  五、DIY:向內核添加自己的程序

  A.在Linux內核中增加自己的程序步驟(注意這裏只是程序文件):

  1.將編寫的源代碼複製到Linux內核源代碼的相應目錄中。

  2.在目錄的Kconfig文件中增加新源代碼對應項目的編譯配置選項

  3.在目錄的Makefile文件中增加對新源代碼的編譯條目。

  B.在Linux內核drivers/目錄中增加目錄和子目錄步驟:

  1.所加目錄爲myDriver,文件如下:

  myDriver$ tree

  |– Kconfig

  |– Makefile

  |– key

  |   |– Kconfig

  |   |– Makefile

  |   `– key.c

  |– led

  |   |– Kconfig

  |   |– Makefile

  |   `– led.c

  `— test.c

  #注意此時各個目錄中的Makefile和Kconfig文件是空的

  2.在新增的相應目錄添加Kconfig和Makefile文件,上面的目錄中已經添加。

  3.修改新增目錄的父目錄的Kconfig和Makefile文件,以便新增的Kconfig和

  Makefile能被引用。向父目錄中的Makefile添加:

  obj-y                           += myDriver/

  表示在編譯過程中包含子目錄myDriver目錄。然後修改Kconfig文件,添加:

  source “drivers/myDriver/Kconfig”

  表示在配置時引用子目錄myDriver中的配置文件Kconfig。

  4.經過上面一步,父目錄就可以找到所加的目錄myDriver了,然後就是編輯各個目 錄中的Makefile和Kconfig文件,在你添加的目錄myDriver中的Makefile加入:

  obj-$(CONFIG_TEST) += test.o #因爲在myDriver目錄中要編譯test.c文件

  #所以會根據CONFIG_TEST來決定編譯選項

  obj-y += led/#編譯myDriver目錄中的子目錄led

  obj-y += key/#編譯myDriver目錄中的子目錄key

  然後Kconfig文件是:

  menu “TEST MyDriver”            #在make menuconfig時要顯示的菜單入口

  comment “Test myDriver”       #menu title

  config TEST

  tristate “MyDriver test”

  source “drivers/myDriver/led/Kconfig” #將led目錄下的Kconfig添加進來

  source “drivers/myDriver/key/Kconfig”

  endmenu

  再看led目錄下的Makefile和Kconfig:

  Makefile爲文件:

  obj-$(CONFIG_LED)+=led.o

  Kconfig文件:

  config LED

  tristate “led support”

  key目錄下的Makefile和Kconfig類似。

  5.現在可以make menuconfig來配置添加自己目錄myDriver的內核了!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章