我們都知道,如果要使用沒有集成到內核之中的Linux驅動程序需要手動編譯。當然,這並不是一件什麼難事,即使是對於沒有編程經驗的Linux使用者,只要稍微有點hacker的意識,努力看看代碼包裏的Readme或者INSTALL文件,按部就班的執行幾條命令還是很容易辦到的。但這裏還有一個問題,Linux模塊和內核是有依賴關係的,如果遇到因爲發行版更新造成的內核版本的變動,之前編譯的模塊是無法繼續使用的,我們只能手動再編譯一遍。這樣重複的操作有些繁瑣且是反生產力的,而對於沒有內核編程經驗的使用者來說可能會造成一些困擾,使用者搞不清楚爲什麼更新系統之後,原來用的好好的驅動程序突然就不能用了。這裏,就是Dell創建的DKMS項目的意義所在。DKMS全稱是Dynamic Kernel Module Support,它可以幫我們維護內核外的這些驅動程序,在內核版本變動之後可以自動重新生成新的模塊。
在使用dkms之前首先需要確保系統中已經安裝了 DKMS。在Ubuntu下可以執行下面這個命令安裝:
sudo apt-get install dkms
安裝完畢之後,我們就可以開始使用 DKMS了。
本文的例子來自Ubuntu Wiki,大家可以從這裏下載。
使用DKMS編譯安裝內核模塊
DKMS的使用流程可以用下圖簡單表示:
以hello-0.1爲例,我們首先需要把代碼copy到"/usr/src"下面,這樣完整路徑將是"/usr/src/hello-0.1"。
DKMS要求我們的代碼目錄必須以" <module>-<module-version>"的格式命名。本例中,代碼的版本是0.1。
DKMS主要的命令可以參考上圖所示,分別是add、build、install、uninstall和remove,另外,還可以執行"dkms status"查看目前DKMS系統維護的模塊的狀態。
在我自己的主機上,首先執行dkms status看看:
bcmwl, 5.100.82.38+bdcom, 2.6.38-8-generic, i686: installed
目前我的機器上有一個處於“Installed State”的bcmwl模塊,這是我的Broadcom無線網卡驅動。
我們還可以在目錄"/var/lib/dkms"下查看目前有哪些由DKMS維護的驅動程序。
接下來,執行“sudo dkms add -m hello -v 0.1”來添加hello-0.1,執行的結果是:
Creating symlink /var/lib/dkms/hello/0.1/source -> /usr/src/hello-0.1
DKMS: add Completed.
我們再執行“dkms status”看看:
bcmwl, 5.100.82.38+bdcom, 2.6.38-8-generic, i686: installed
hello, 0.1: added
hello-0.1已經處於"Added State"了。
下面執行“sudo dkms build -m hello -v 0.1”:
Kernel preparation unnecessary for this kernel. Skipping...
Building module:cleaning build area....
make KERNELRELEASE=2.6.38-8-generic all KVERSION=2.6.38-8-generic.....
cleaning build area....
DKMS: build Completed.
我們可以在目錄“/var/lib/dkms/hello/0.1/2.6.38-8-generic/i686/module/”下面找到編譯生成的hello.ko二進制模塊。
最後執行“sudo dkms install -m hello -v 0.1”來安裝hello.ko:
hello.ko:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/2.6.38-8-generic/updates/dkms/
把hello.ko從/lib/modules下移除可以執行“sudo dkms uninstall -m hello -v 0.1”,甚至可以使用命令“sudo dkms remove -m hello -v 0.1 --all”把hello-0.1從/var/lib/dkms下徹底刪除,這樣,DKMS系統就不再維護hello-0.1模塊了。
以上的每個步驟我們都可以通過“dkms status”來查看執行後的狀態。
對於處於"Installed State"的模塊,即使內核版本發生變化,我們也不需要手動重新編譯內核了。
我們再回過頭來研究一下hello-0.1中文件。
/usr/src/hello-0.1/
├── dkms.conf
├── hello.c
└── Makefile
如果您比較熟悉Linux內核模塊的編寫,hello.c和Makefile的內容應該很簡單,本文不再詳細解釋。有一點需要注意,在Makefile中要使用變量$(KVERSION)指定內核版本號,這樣我們在執行dkms時,就可以用“-k”選項來設定爲哪個內核版本編譯模塊。
$(MAKE) -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
dkms.conf文件是本文關注的重點。
PACKAGE_NAME="hello"
PACKAGE_VERSION="0.1"
CLEAN="make clean"
MAKE[0]="make all KVERSION=$kernelver"
BUILT_MODULE_NAME[0]="hello"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"
PACKAGE_NAME和PACKAGE_VERSION和文件夾的命名是一致的。
CLEAN的命令是每次build的時候第一條執行的動作。
MAKE[0]用來設定編譯的命令,一般情況下是不用設定的。在本例中,就可以把MAKE[0]這行刪掉。但在下面這種情況下就需要設定了。比如,您的Makefile裏有多個target,分別爲all、debug、release等,不指定MAKE[0]時,編譯會選擇第一個target來執行,也就是make all,如果您想執行make release來編譯,就需要在dkms.conf裏明確設定。
BUILD_MODULE_NAME[0]用來指定模塊的名稱,一般情況下也可以不設定。
DEST_MODULE_LOCATION[0]用來設定模塊安裝的目的地址,本例是"/lib/module/$(KVERSION)/updates"。
AUTOINSTALL="yes"表示在Linux引導之後DKMS會自動對這個模塊執行Build和Install的動作,當然如果模塊已經處於該狀態的話,相應的動作是不用再執行的。
基於DKMS製作驅動程序的DEB安裝包
作爲Linux驅動開發者,有時候用戶會要求我們提供驅動的DEB安裝包,基於DKMS來製作DEB安裝包是一個很好的選擇。對開發者來說這樣的DEB包製作起來比較簡單,對於用戶來說使用起來也省去許多煩惱。需要注意的是,製作DEB包依賴於dh-make,請首先執行“sudo apt-get install dh-make”安裝。
在模塊處於"Built State"的條件下,執行“sudo dkms mkdeb -m hello -v 0.1”可以在目錄“/var/lib/dkms/hello/0.1/deb”下生成deb包。
另外,DKMS還提供了mktarball和mkrpm來製作tarball和RPM安裝包,這裏就不再一一贅述。
作者:wwang
出處:http://www.cnblogs.com/wwang
本文采用知識共享署名-非商業性使用-相同方式共享 2.5 中國大陸許可協議進行許可,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接。