1. 程式人生 > >《15.核心的配置和編譯原理》

《15.核心的配置和編譯原理》

《15.核心的配置和編譯原理》

第一部分、章節目錄
2.15.1.linux核心原始碼目錄結構1
2.15.2.linux核心原始碼目錄結構2
2.15.3.核心配置和編譯體驗
2.15.4.核心的配置原理1
2.15.5.menuconfig的使用和演示
2.15.6.menuconfig的工作原理
2.15.7.Kconfig檔案詳解1
2.15.8.Kconfig檔案詳解2
2.15.9.menuconfig的實驗學習思路

第二部分、章節介紹
2.15.1.linux核心原始碼目錄結構1
本節先找到合適的核心原始碼樹,然後解壓之並講解根目錄下的各個單個檔案。
2.15.2.linux核心原始碼目錄結構2
本節接上節講解核心原始碼根目錄下的各個資料夾,並且把一些重要資料夾的作用簡單講解。
2.15.3.核心配置和編譯體驗
本節進行核心的三步配置編譯過程,目的是讓大家學會核心的配置編譯操作,方便之後學習原理。
2.15.4.核心的配置原理1
本節開始講解核心配置的原理,主要是make xx_defconfig的原理。
2.15.5.menuconfig的使用和演示
本節詳細演示make menuconfig的具體使用,詳解其幫助資訊。
2.15.6.menuconfig的工作原理
本節講解menuconfig的工作原理,主要揭示了menuconfig和.config、Kconfig檔案的關聯。
2.15.7.Kconfig檔案詳解1
本節詳解Kconfig檔案的格式、作用等
2.15.8.Kconfig檔案詳解2
本節進一步解釋Kconfig中配置項的細節,如depends、select等關鍵字的作用。
2.15.9.menuconfig的實驗學習思路
本節總結menuconfig的原理並且提出一些驗證思路並去實際驗證,目的是讓大家加深理解menuconfig的同時學會通過實驗驗證的方法進行學習。

第三部分、隨堂記錄
2.15.1.linux核心原始碼目錄結構1
2.15.1.1、原始碼從哪裡來
(1)之前講過,我們使用2.6.35.7版本的核心。這個版本的核心有三種:第一種是kernel.org上的官方版本,第二種是三星移植過的,第三種是九鼎X210的移植版本。我們講課時使用第三種核心來講解,後面的移植實驗使用第二種核心來移植。
(2)原始碼在開發板光碟中有。可以自己去linux下解壓然後make distclean清理然後再次打包傳輸到windows下去解壓分析;也可以直接去我網盤中下載我打包好的。
(3)解壓後最終在windows下得到了一個kernel的原始碼目錄樹,這個原始碼目錄就是九鼎以三星移植過的核心為原材料自己針對X210移植後的核心版本。
2.15.1.2、分析原始碼目錄下的單個檔案
(1)Kbuild,Kbuild是kernel build的意思,就是核心編譯的意思。這個檔案就是linux核心特有的核心編譯體系需要用到的檔案。
(2)Makefile,這個是linux核心的總makefile,整個核心工程用這個Makefile來管理的。
(3)mk,是九鼎在移植時自己新增的,不是linux核心本身的東西。九鼎新增這個檔案的作用是用這個檔案來整天管理kernel目錄的配置和編譯,

也就是說這個檔案有點類似於我們之前移植uboot時自己建立的那個cp.sh
2.15.1.3、簡單講一下linux核心的配置體系。
(1)linux核心很龐大,裡面模組很多,而且可配置性非常高。所以linux原始碼的配置是一個很複雜的事情,必須要有一套很複雜的機制來保證linux核心可以被正確的配置。(對比一下uboot,uboot的配置項都是在xxx.h中,用巨集定義來表示的。uboot的這種方式很依賴於人的水平,因為uboot的配置體系很簡單。)
(2)linux核心本身配置項有上千個,光靠人眼睛去看腦袋去記根本不可能,所以核心發明了一種體系用來幫助人進行簡單化的配置。這種體系就是我們本課程中重點要研究的東西。
(3)Kbuild、Kconfig等檔案,都是和核心的配置體系有關的。

2.15.2.linux核心原始碼目錄結構2
(1)arch。arch是architecture的縮寫,意思是架構。arch目錄下是好多個不同架構的CPU的子目錄,譬如arm這種cpu的所有檔案都在arch/arm目錄下,X86的CPU的所有檔案都在arch/x86目錄下。
(2)block。英文是塊的意思,在linux中block表示塊裝置(以塊(多個位元組組成的整體,類似於扇區)為單位來整體訪問),譬如說SD卡、iNand、Nand、硬碟等都是塊裝置。你幾乎可以認為塊裝置就是儲存裝置。block目錄下放的是一些linux儲存體系中關於塊裝置管理的程式碼。
(3)crypto。英文意思是加密。這個目錄下放了一些各種常見的加密演算法的C語言程式碼實現。譬如crc32、md5、sha1等。
(4)Documentation。裡面放了一些文件。
(5)drivers。驅動目錄,裡面分門別類的列出了linux核心支援的所有硬體裝置的驅動原始碼。
(6)firmware。韌體。什麼是韌體?韌體其實是軟體,不過這個軟體是固話到IC裡面執行的叫韌體。就像S5PV210裡的iROM程式碼。
(7)fs。fs就是file system,檔案系統,裡面列出了linux支援的各種檔案系統的實現。
(8)include。標頭檔案目錄,公共的(各種CPU架構共用的)標頭檔案都在這裡。每種CPU架構特有的一些標頭檔案在arch/arm/include目錄及其子目錄下。
(9)init。init是初始化的意思,這個目錄下的程式碼就是linux核心啟動時初始化核心的程式碼。
(10)ipc。ipc就是inter process commuication,程序間通訊,裡面都是linux支援的IPC的程式碼實現。
(11)kernel。kernel就是核心,就是linux核心,所以這個資料夾下放的就是核心本身需要的一些程式碼檔案。
(12)lib。lib是庫的意思,這裡面都是一些公用的有用的庫函式,注意這裡的庫函式和C語言的庫函式不一樣的。在核心程式設計中是不能用C語言標準庫函式,這裡的lib目錄下的庫函式就是用來替代那些標準庫函式的。譬如在核心中要把字串轉成數字用atoi,但是核心程式設計中只能用lib目錄下的atoi函式,不能用標準C語言庫中的atoi。譬如在核心中要列印資訊時不能用printf,而要用printk,這個printk就是我們這個lib目錄下的。
(13)mm。mm是memory management,記憶體管理,linux的記憶體管理程式碼都在這裡。
(14)net。該目錄下是網路相關的程式碼,譬如TCP/IP協議棧等都在這裡。
(15)scripts。指令碼,這個目錄下全部是指令碼檔案,這些指令碼檔案不是linux核心工作時使用的,而是用來輔助對linux核心進行配置編譯生產的。我們並不會詳細進入分析這個目錄下的指令碼,而是通過外圍來重點學會配置和編譯linux核心即可。
(16)security。安全相關的程式碼。不用去管。
(17)sound。音訊處理相關的。
(18)tools。linux中用到的一些有用工具
(19)usr。目錄下是initramfs相關的,和linux核心的啟動有關,暫時不用去管。
(20)virt。核心虛擬機器相關的,暫時不用管。

總結:這麼多目錄跟我們關係很緊密的就是arch和drivers目錄,然後其他有點相關的還有include、block、mm、net、lib等目錄。

2.15.3.核心配置和編譯體驗
2.15.3.1、先確認Makefile
(1)主要是檢查交叉編譯工具鏈有沒有設定對。CROSS_COMPILE ?= /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
(2)確認ARCH = arm。主要目的是為了編譯時能找到arch/arm目錄。

2.15.3.2、make x210ii_qt_defconfig
(1)最後只要出現:configuration written to .config這句話,就證明我們的操作是正確的。如果沒有出現這句話,就有錯誤。
(1)可能出現的錯誤1:名字敲錯了。名字是字串匹配的,一定要正確。
注意:如果這一步配置沒有得到.config檔案,是不能進行到下一步的。實際測試時沒有.config也可以make menuconfig,但是這樣做出來的核心編譯和燒寫執行應該是有問題的。

2.15.3.2、make menuconfig
(1)可能出現的錯誤1:ncurses庫沒裝
錯誤資訊:
*** Unable to find the ncurses libraries or the
*** required header files.
*** ‘make menuconfig’ requires the ncurses libraries.


*** Install ncurses (ncurses-devel) and try again.

解決方案: apt-get install libncurses5-dev (參考了:http://blog.csdn.net/yao_qinwei/article/details/8805101)

(2)可能出現的錯誤2:螢幕太小
錯誤資訊:
Your display is too small to run Menuconfig!
It must be at least 19 lines by 80 columns.
解決方案:全屏,或者是把字型調小。

總結:make menuconfig是第二步配置,具體的用法和配置意義在後面課程講。我們這裡因為是九鼎已經移植過的,所以第二步配置是可以不做的,直接退出即可。
用鍵盤的向右方向鍵移動到EXIT,按回車退出。

2.15.3.3、make
(1)可能出現的錯誤1:莫名其妙的錯誤,可以試試先make distclean
(2)程式碼本身的錯誤:具體問題具體分析
(3)編譯完成後得到的核心映象不在原始碼樹的根目錄下,在arch/arm/boot這個目錄下。得到的映象名是zImage

2.15.4.核心的配置原理1
2.15.4.1、燒寫測試
2.15.4.2、配置的關鍵是得到.config檔案
(1).config以.開頭,是一個隱藏檔案,因此平時是看不到的,需要ls -a來看
(2)當我們make distclean後(也就是說預設情況下)是沒有.config檔案的,我們配置的兩步過程就是為了得到內容合適的.config檔案
(3).config檔案是linux核心在編譯過程中很重要的一個檔案,其作用類似與uboot中的include/configs/x210_sd.h,核心在編譯過程中會讀取.config中的配置項,並且用這些配置項去指導整個編譯連結過程。
(4).config檔案的格式類似於指令碼檔案,其中內容為類似於於:CONFIG_ARM=y的一個一個的配置項。這些配置項就類似於指令碼檔案中定義的一個一個變數,所以這一行可以被理解為定義了一個變數CONFIG_ARM,這個變數的值為y。
(5).config檔案中每一行都是一個配置項,從.config檔案的規模可以看出linux核心的可配置項有兩三千個。所以linux核心是高度可配置的,而且linux核心的所有配置項很難全部搞明白。因為linux核心的配置項太多太繁雜超出了人的大腦能夠記憶和處理的數量級,因此linux核心不像uboot那樣直接手工配置,而是發明了一個圖形化的配置工具menuconfig。

2.15.4.3、make xx_defconfig和make menuconfig相配合
(1)我們為了對.config檔案中的兩三千個配置項做逐一合適的配置,專門發明了兩步結合的配置方式。
(2)其實只要人的記憶足夠好,大腦足夠厲害,完全可以手工去書寫/修改.config檔案完成核心配置,最終只要.config中內容是正確的,就不影響編譯過程。
(3)第一步:make xxx_defconfig解決的問題是大部分的配置項(這一步結束後99%的配置項就已經正確了),下來就是對個別不同的針對我們的開發板進行細節調整,細節調整就通過make menuconfig來完成。
(4)make xxx_defconfig這一步其實是參考別人已經做好的,這樣做有很多好處:減少很多工作量,避開了很多自己不懂的配置項(譬如對記憶體管理的、排程系統的等模組的配置項),我們只用管自己需要管的。
(5)make menuconfig其實就是讀取第一步得到的.config,然後給我們一個圖形化的介面,讓我們可以更加容易的找到自己想要修改的配置項,然後更改配置他。

2.15.4.4、make xx_defconfig到底做了什麼?
(1)make x210ii_qt_defconfig其實相當於:cp arch/arm/configs/x210ii_qt_defconfig .config
(2)arch/arm/configs目錄下的這麼多個xxx_defconfig哪裡來的?其實這些檔案都是別人手工配置好適合一定的開發板的.config檔案後自己把.config檔案儲存過去的。譬如說我們用S5PV210這個SoC,針對這個SoC的開發板的最初配置肯定是三星的工程師去做的。

2.15.5.menuconfig的使用和演示
2.15.5.1、使用說明解釋
(1)make ,menuconfig中本身自帶的提示就有所有的用法,這裡只要全部理解就可以了。
(2)menuconfig中間的選擇區中有很多個選擇項,每個選擇項對應.config檔案中的一個配置項,每一個選擇項都可以被選擇和配置操作,選擇區中的每一項都是有子目錄的,將游標放在選擇項上按Enter鍵可以進入子目錄(子目錄可能還會有子目錄)。選擇區太短放不下所有的一個目錄層級的選項,可以用箭頭按鍵的向上箭頭和向下箭頭來上翻和下翻。

注:在menuconfig中操作相關的幾個鍵盤按鍵,主要是;Enter、ESC、四個方向箭頭按鍵。還有一些特殊字元按鍵,如/ ?
向上和向下箭頭,主要用來在選擇項選單中目錄瀏覽時上下翻
回車,主要作用是選中並且執行select/exit/help。
ESC,主要作用是返回上一層
向左和向右箭頭,主要作用是在選單選項(select、exit、help)間切換。

(3)用法翻譯:
箭頭按鍵導航整個選單,回車按鍵選擇子選單(注意選項後面有 —>的選項才是有子選單的,沒有這個標識的沒有子選單),高亮的字母是熱鍵(快捷鍵),鍵盤按鍵Y、N、M三個按鍵的作用分別是將選中模組編入、去除、模組化。雙擊ESC表示退出,按下?按鍵可以顯示幫助資訊,按下/按鍵可以輸入搜尋內容來全域性搜尋資訊(類似於vi中的搜尋),[]不可以模組化,<>的才可以模組化。

注:linux核心中一個功能模組有三種編譯方法:一種是編入、一種去去除、一種是模組化。所謂編入就是將這個模組的程式碼直接編譯連線到zImage中去,去除就是將這個模組不編譯連結到zImage中,模組化是將這個模組仍然編譯,但是不會將其連結到zImage中,會將這個模組單獨連結成一個核心模組.ko檔案,將來linux系統核心啟動起來後可以動態的載入或解除安裝這個模組。
在menuconfig中選項前面的括號裡,*表示編入,空白表示去除,M表示模組化

2.15.6.menuconfig的工作原理
2.15.6.1、menuconfig本身由一套軟體支援
(1)linux為了實現圖形化介面的配置,專門提供了一套配置工具menuconfig。
(2)ncurses庫是linux中用來實現文字式的圖形介面,linux核心中使用了ncurses庫來提供menuconfig
(3)scripts\kconfig\lxdialog目錄下的一些c檔案就是用來提供menuconfig的那些程式原始碼。

2.15.6.2、menuconfig讀取Kconfig檔案
(1)menuconfig本身的軟體只負責提供menuconfig工作的這一套邏輯(譬如在menuconfig中通過上下左右箭頭按鍵來調整游標,Enter ESC鍵等按鍵按下的響應),而並不負責提供內容(選單裡的專案)。
(2)menuconfig顯示的選單內容(一方面是選單的目錄結構,另一方面是每一個選單專案的細節)是由核心原始碼樹各個目錄下的Kconfig檔案來支援的。Kconfig檔案中按照一定的格式包含了一個又一個的配置項,每一個配置項在make menuconfig中都會成為一個選單專案。而且menuconfig中顯示的選單目錄結構和原始碼目錄中的Kconfig的目錄結構是一樣的。
(3)在相應的Kconfig檔案中刪除一個config項,則再次make menuconfig時這個專案已經看不到了。

2.15.6.3、menuconfig讀取/寫入.config檔案
(1)剛才已經知道menuconfig的選單內容來自於Kconfig檔案,但是每一個選單的選擇結果(Y、N、M)卻不是儲存在Kconfig檔案中的。Kconfig檔案是不變的,Kconfig檔案只是決定有沒有這個選單項,並不管這個選單項的選擇結果。
(2)menuconfig工作時在我們make menuconfig開啟時,他會讀取.config檔案,並且用.config檔案中的配置選擇結果來初始化menuconfig中各個選單項的選擇值。

總結:選單項的專案內容從Kconfig檔案來,選單項的選擇值從.config檔案來

(3)當我們每次退出make menuconfig時,menuconfig機制會首先檢查我們有沒有更改某些配置項的值,如果我們本次沒有更改過任意一個配置專案的值那直接退出;如果我們有改動配置項的值則會提示我們是否儲存。此時如果點儲存,則會將我們更改過的配置重新寫入.config檔案中記錄,下一次再次開啟make menuconfig時會再次載入.config,最終去編譯核心時編譯連線程式會考慮.config中的配置值指導整個編譯連線過程。

總結:本節課主要內容就是講:menuconfig和Kconfig和.config的關係。

2.15.7.Kconfig檔案詳解1
2.15.7.1、Kconfig的格式
(1)Kconfig按照一定的格式來書寫,menuconfig程式可以識別這種格式,然後從中提取出有效資訊組成menuconfig中的選單項。
(2)將來在做驅動移植等工作時,有時需要自己新增Kconfig中的一個配置項來將某個裝置驅動新增到核心的配置專案中,這時候就需要對Kconfig的配置項格式有所瞭解,否則就不會新增。
(3)#開頭的行是註釋行
(4)menuconfig表示選單(本身屬於一個選單中的專案,但是他又有子選單專案)、config表示選單中的一個配置項(本身並沒有子選單下的專案)。
(5)menuconfig或者config後面空格隔開的大寫字母表示的類似於 NETDEVICES 的就是這個配置項的配置項名字,這個字串前面新增CONFIG_後就構成了.config中的配置項名字。
(6)一個menuconfig後面跟著的所有config項就是這個menuconfig的子選單。這就是Kconfig中表示的目錄關係。
(7)核心原始碼目錄樹中每一個Kconfig都會source引入其所有子目錄下的Kconfig,從而保證了所有的Kconfig專案都被包含進menuconfig中。這個也告訴我們:如果你自己在linux核心中添加了一個資料夾,一定要在這個資料夾下建立一個Kconfig檔案,然後在這個資料夾的上一層目錄的Kconfig中source引入這個資料夾下的Kconfig檔案。

2.15.7.2、tristate和bool的含義
(1)tristate意思是三態(3種狀態,對應Y、N、M三種選擇方式),bool是要麼真要麼假(對應Y和N)。所以tristate的意思就是這個配置項可以被三種選擇,bool的意思是這個配置項只能被2種選擇。

2.15.8.Kconfig檔案詳解2
2.15.8.1、depends的含義
(1)depends中文意思是“取決於”或者“依賴於”,所以depends在這裡的意思是:本配置項依賴於另一個配置項。如果那個依賴的配置項為Y或者M,則本配置項才有意義;如果依賴的哪個配置項本身被設定為N,則本配置項根本沒有意義。
(2)depends專案會導致make menuconfig的時候找不到一些配置項。所以你在menuconfig中如果找不到一個選項,但是這個選項在Kconfig中卻是有的,則可能的原因就是這個配置項依賴的一個配置項是不成立的。
(3)depends並不要求依賴的配置項一定是一個,可以是多個,而且還可以有邏輯運算。這種時候只要依賴專案運算式子的裸機結果為真則依賴就成立。

2.15.8.2、help
(1)幫助資訊,告訴我們這個配置項的含義,以及如何去配置他。

2.15.8.3、Kconfig和.config檔案和Makefile三者的關聯
(1)配置項被配置成Y、N、M會影響.config檔案中的CONFIG_XXX變數的配置值。
(2)這個.config中的配置值(=y、=m、沒有)會影響最終的編譯連結過程。如果=y則會被編入(built-in),如果=m會被單獨連線成一個ko模組,如果沒有則對應的程式碼不會被編譯。那麼這麼是怎麼實現的?都是通過makefile實現的。
(3)obj-$(CONFIG_DM9000) += dm9000.o
如果CONFIG_DM9000變數值為y,則obj += dm9000.o,因此dm9000.c會被編譯;如果CONFIG_DM9000變數未定義,則dm9000.c不會被編譯。如果CONFIG_DM9000變數的值為m則會被連線成ko模組(這個是在linux核心的Makefile中定義的規則)

總結:把menuconfig中的選單項、Kconfig中的配置項、.config中的一行、 Makefile中的一行,這4個東西結合起來理解,則整個linux核心的配置體系就明瞭了。

2.15.9.menuconfig的實驗學習思路
2.15.9.1、驗證menuconfig和.config的關係
(1)make menuconfig時,會讀取.config中的配置值來初始化menuconfig中的配置項。
驗證:如果理論正確的,那麼我自己手工修改了.config的配置後,再次make menuconfig時看到的初始值就應該是我手工修改的。
(2)menuconfig中修改了(按Y、N、M)配置項的值,然後退出時儲存,則這個儲存結果會修改.config檔案中的相應行。
驗證:如果結論是正確的,那麼在menucofig中修改了配置後儲存退出,再次去手工開啟.config檔案則可以看到相應配置的一行內容被修改了。

2.15.9.2、驗證menuconfig和Kconfig的關係
(1)menuconfig讀取Kconfig的內容作為選單專案內容。
驗證1:在Kconfig中刪除一個config項,則再次make menuconfig時就看不到這個專案了。(上課時已經驗證過了)
驗證2:在Kconfig中自己新增建立一個config項,則再次make menuconfig時就能看到多了一個專案。

2.15.9.3、驗證驗證menuconfig和Makefile的關係
(1)我找一個模組,把他配製成y,然後去make編譯連線,最後得到的zImage中這個模組就應該被編譯連線進去到zImage中了。
驗證:
方法一:去這個模組對應的原始碼目錄看一下這個原始碼有沒有被編譯
方法二:去zImage對應的elf格式的vmlinux中檢視符號
方法三:將vmlinux反編譯(objdump)後得到的檔案中找模組對應的符號
方法四:將zImage下載到開發板中啟動,啟動後看你的模組能不能工作