1. 程式人生 > >linux 核心標頭檔案 linux kernel header

linux 核心標頭檔案 linux kernel header

概述:在進行有關係統軟體的安裝的時候(編譯一個新的驅動,或者安裝一個系統級別的測試工具,例如systemtap),經常需要重新編譯核心,相應的問題往往與核心標頭檔案有關。那麼,什麼是核心標頭檔案,為什麼需要更新核心標頭檔案?核心標頭檔案作用是什麼,如何更新?本文主要為你解答這些疑問。

1.核心標頭檔案的發展歷史

        在 Linux 2.2/2.4 的純真年代,核心標頭檔案一直保持著 Unix 世界的"KISS"傳統,只需將核心原始碼樹中的標頭檔案直接複製到 /usr/include 中即可使用,一切都是那麼 Simple and Stupid ...

        但是隨著 2.6 系列核心的釋出,事情開始變得混亂和複雜起來。首先是核心開發者宣佈強烈反對直接使用"未淨化"的"原始"核心標頭檔案,他們建議使用發行版提供的"經過淨化的"核心標頭檔案
。於是各種發行版開始"八仙過海,各顯神通",由於"淨化"方法各不相同,結果就是每個發行版都有著自己與眾不同的核心標頭檔案。更為嚴重的是,核心開發者甚至推薦編譯 Glibc 的標頭檔案也要使用發行版提供的"經過淨化的"核心標頭檔案。由於 Glibc 和 Kernel 是整個系統的根基,這樣一來 Linux 便像傳統的 Unix 那樣開始走向分裂。

        另一件哭笑不得的事情是,雖然核心開發者強烈推薦使用發行版提供的"經過淨化的"核心標頭檔案,但是 Glibc 的開發者卻不買賬,他們推薦使用"未淨化"的"原始"核心標頭檔案來編譯 Glibc ,兩個開發組一直堅持各自的見解,互不妥協!另外,兩個開發組在應當由誰提供核心標頭檔案的問題上意見也不一致:核心開發組認為應當由發行版的製作者提供,而 Glibc 開發組認為應當由核心開發組提供。結果就是"神仙打架,凡人遭殃",雖然對 Debian 這種大型發行版來說,提供自己獨有的"經過淨化的"核心標頭檔案不會成為多大的負擔,但是對於那些沒有能力或精力的小心發行版製作者和我們這些 DIY fans 來說卻是一場災難!要麼直接使用其他發行版的成果,要麼自力更生;前者讓人心有不甘(沒有了 DIY 的原汁原味),後者讓人望而生畏(有幾個人知道啥叫"淨化"?怎麼淨化?)。

        危機時刻總會有英雄的出現,就在一片恐慌之際,一個叫"linux-libc-headers"專案組誕生了!他們向我們這些"凡人"們提供了安全的、普遍適用的、"經過淨化的"核心標頭檔案,真是及時雨啊!天空重新晴空萬里……然而好景不長,由於精力和人力有限,該專案在釋出了 2.6.12.0 版本之後,遺憾的離開了這個世界。這樣一來,2.6.12 以上版本的核心新特性(比如新的系統呼叫)和 ABI/API 的變化就無法反映出來,對於我們這些 DIY fans 來說,世界重回混沌……
        俗話說,"合久必分,分久必合",大概是核心開發組意識到了如果繼續固執己見將不可避免的導致混亂以及重蹈 Unix 逐漸走向分裂的覆轍,於是從 2.6.18 版本開始,核心開發組擔負起了維護一份統一的、"經過淨化的"核心標頭檔案的職責
(竊以為這原本就是他們的責任)。現在獲取"經過淨化的"核心標頭檔案又變得簡單起來,只要在核心原始碼樹中使用 make headers_install 即可,而且不用再擔心更新問題。對於我們這些 DIY fans 來說,又可以重新 Day Day Happy 了。

        不過,由於磨合需要時間。目前 Glibc-2.4 以下的版本都無法配合這種新式標頭檔案編譯成功。

2核心標頭檔案的作用

        說了這麼多,那麼什麼時候會用到核心標頭檔案呢?核心標頭檔案又有哪些與使用者有關的作用呢?

        概括來說,核心標頭檔案的作用主要有兩個:1)定義核心元件間的介面2)定義核心與使用者空間的介面

內部模組:模組間的內部介面在linux/include/ 或 linux/arch/*/include/ 下都有定義。一個單獨模組的原始檔間的介面應該同模組原始碼置於同一目錄下,避免汙染全域性標頭檔案空間。

       外部模組:傳統的核心原始碼安裝在/usr/src/linux下,這不再支援外部模組的編譯。相反,你的Makefile應該指向/lib/modules/${kver}/build,其中${kver}是核心確切的版本字串,例如:對於當前正在執行的核心,就是“uname -r”的輸出。

        使用者空間程式:一般來說,使用者空間程式是針對發行版提供的標頭檔案編譯的,通常源於glibc-devel、glibc-kernheaders 或 linux-libc-dev。這些標頭檔案通常來源於舊版核心,並不能安全地在不重新編譯glibc的情況下被替換。特別地,作為一個到/usr/src/linux/include或/lib/modules/*/build/include/linux的符號連結/usr/include/linux,是極不推薦使用的。因為它經常使重新編譯的應用程式損壞。例如,舊核心使用include/asm-${arch}存放架構特定的標頭檔案,而不是現在的arch/${arch}/include/asm ,且沒有符號連結到架構特定的目錄。

3.如何打包標頭檔案

        為發行版打包標頭檔案:為一個發行版打包標頭檔案正確的方法是在核心原始碼目錄下執行 'make headers_install'來安裝標頭檔案到/usr/include,並依賴這個剛剛安裝的特定版本的核心標頭檔案重新編譯C庫包。如果你正在釋出一個依賴某個特定版本核心標頭檔案的使用者空間程式,比如因為你的程式只執行在打過補丁或者最新的核心上,你不能依賴/usr/include中的標頭檔案。你也不能使用來自/usr/src/linux/include 或/lib/modules/*/build/include/的標頭檔案,因為他們還沒有為使用者空間的包含做好準備。若你嘗試這麼做了,核心會警告你並指引你到這個Wiki頁解決這個問題的正確方法是獨立出你需要的特定介面,比如一個打過補丁的新核心併為你的應用程式提供字元裝置ioctl號的獨立標頭檔案。在你自己的程式中新增一份這個原始檔的拷貝,並說明這個應該和新核心版本保持一致。如果你的程式不遵循GPLv2證書,請保證你得到了這個檔案作者的許可:可在你自己程式的證書下發布它。因為你的程式現在依賴的核心介面並不在常規核心中。在這種情況下,一個推薦的做法是通過執行時檢測來保證核心知道這個介面並在無法向下相容舊介面的時候給出有用的錯誤資訊。

4.kernel devel與kernel source的區別

        區別:kernel-devel包只包含用於核心開發環境所需的核心標頭檔案以及Makefile,而kernel-souce包含所有核心原始碼。
如果僅僅是用於你自己編寫的模組開發的話,因為只需引用相應的核心標頭檔案,所以只有devel包即可,如果你要修改現有的核心原始碼並重新編譯,那必須是kernel-souce。

        kernel-souce在RH某些版本之後不再附帶在發行版中了,必須自己通過kernel-XXX.src.rpm做出來。

        kernel-devel是用做核心一般開發的,比如編寫核心模組,原則上,可以不需要核心的原始碼。kernel則是專指核心本身的開發,因此需要核心的原始碼。

       關於kernel source的有kernel和kernel-devel兩個rpm,其中kernel rpm包含原始檔和標頭檔案(就像2.4下的kernel-source rpm),而kernel-devel則主要是標頭檔案。