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