Linux kernel 在 Git 目錄和 SVN 目錄編譯行為不一致的解決方法
近期把開發(fā)從 SVN 遷移到了 Git 上。其實(shí)一早就遇到一個問題,那就是 Linux kernel,在 SVN 的版本控制下編譯得好好的,但是換成 Git 做版本控制之后,即便是完全一模一樣的兩套目錄樹,編譯出來就是不一樣!
我暈,Linux 編譯結(jié)果還跟版本控制環(huán)境有關(guān)?查了資料,還真是有關(guān)……
Reference
向linux內(nèi)核版本號添加字符/為何有時會自動添加“+”號
關(guān)于CONFIG_LOCALVERSION_AUTO設(shè)置去掉內(nèi)核版本號SVN后綴
非開源的驅(qū)動程序如何繞過version magic的檢查
主要知識點(diǎn)歸納
內(nèi)核基礎(chǔ)版本號
Linux 內(nèi)核在編譯時,在根目錄的 Makefile 最開頭有幾個宏,決定了編譯出來的 Linux 基本版本號。我用的內(nèi)核版本比較老,是這樣的:
- VERSION = 2
- PATCHLEVEL = 6
- SUBLEVEL = 36
- EXTRAVERSION =
- ...
而內(nèi)核代碼在獲得這個基本版本號,則需要包含include/linux/version.h文件:
- #define LINUX_VERSION_CODE 132644
- #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
其中LINUX_VERSION_CODE就是(2 << 16) + (6 << 8) + (36 << 0)
這個宏很重要,舉個例子:不同的 Linux 內(nèi)核的 ioctl 函數(shù)原型是不同的,但是你的驅(qū)動又不想寫兩套,這個時候就應(yīng)該這么寫:
- #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
- static long my_ioctl (struct file *file,
- unsigned int req,
- unsigned long arg)
- #else
- static int my_ioctl (struct inode *inode,
- struct file *file,
- unsigned int req,
- unsigned long arg)
- #endif
- {
- // brah brah brah ...
- }
內(nèi)核擴(kuò)展版本號
這里請注意內(nèi)核的include/vermagic.h文件,有一個VERMAGIC_STRING宏,定義如下:
- ...
- #define VERMAGIC_STRING \
- UTS_RELEASE " " \
- MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
- MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS \
- MODULE_ARCH_VERMAGIC
其中UTS_RELEASE宏來自于include/generated/utsrelease.h文件。
首先,這個文件是自動創(chuàng)建的,你修改了也沒用。
其次,這個版本號的來源很復(fù)雜,除了 Linux 基礎(chǔ)版本號(也就是 Makefile 的前三個變量)之外,還依賴很多變量:
- Makefile 里面的EXTRAVERSION宏,這是緊跟在基礎(chǔ)版本號后面的
- make menuconfig 時指定的CONFIG_LOCALVERSION_AUTO配置宏,決定了到scripts/setlocalversion里面去添加什么樣的附加內(nèi)容
- LOCALVERSION,貌似一般情況下這個宏是沒有定義的
而這個VERMAGIC_STRING有什么用呢?這經(jīng)常是用在一些自定義的內(nèi)核模塊里面。如果內(nèi)核模塊的實(shí)現(xiàn)依賴于具體 Linux 內(nèi)核發(fā)行版的話,在 insmod 的時候就需要判斷內(nèi)核的 VERMAGIC_STRING。很多情況下,這里面會包含很多信息。
比如我遇到問題的內(nèi)核模塊,其完整的VERMAGIC_STRING就是:“2.6.36+ mod_unload MIPS32_R2 32BIT”
Version magic 不匹配問題的解決
我遇到的錯誤是這樣的,內(nèi)核執(zhí)行時,網(wǎng)卡無法加載,以致設(shè)備沒有網(wǎng)絡(luò)??梢钥吹酱谟羞@么一句錯誤信息:
- my_net_adapt: version magic '2.6.36+ mod_unload MIPS32_R2 32BIT ' should be '2.6.36 mod_unload MIPS32_R2 32BIT '
根本的解決辦法,是消除掉前面的 magic 里的加號,讓兩個 version magic 變成一模一樣的。但是我找了資料也沒找到為啥。這里要求各路大神了。將就的解決辦法,就是讓兩個 version magic 都加上加號,這樣 magic 檢查就可以通過啦。
查看我的 utsrelease.h 文件,可以看到其內(nèi)容是 “2.6.36”。那么解決方案就有兩種:
在目錄的 Makefile,改第四個變量為 “EXTRAVERSION = +”。
在 Linux 的根目錄下,創(chuàng)建一個沒有用的 “.git” 空文件夾,讓 setlocalversion 以為這是一個 Git 項(xiàng)目,從而自動加上加號。
第二個方案是基于一個前提的:Linux 根目錄不是我整個工程的根目錄,因而整個工程的 .git 文件夾在別處。
于是,問題解決了。我們測試也確認(rèn)這臺內(nèi)核編譯出來是 OK 的。但說實(shí)話,具體原因是什么,還要研究研究——為什么在 SVN 下面就沒問題,在 Git 就有問題呢?