Linux核心模組(驅動)編譯詳解
本文主要說說如何編譯自己開發的核心模組。由於驅動通常也被編譯成核心模組,因此文章的內容也適用於驅動的編譯。
由於在下能力相當有限,有不當之處,還望大家批評指正^_^
一、準備工作
準備工作如何做,這裡就不詳說了。
a) 首先,你要有一臺PC(這不廢話麼^_^),裝好了Linux。
b) 安裝好GCC(這個指的是host gcc,用於編譯生成運行於pc機程式的)、make、ncurses等工具。
c) 如果你是為當前PC機開發核心模組,那麼準備工作就結束了。
如果你是為嵌入式系統Linux系統開發核心模組,則繼續如下兩步。
d) 安裝好交叉編譯工具鏈。例如,你的目標單板CPU可能是arm或mips等cpu,則安裝相應的交叉編譯工具鏈。安裝後,需要將工具鏈路徑新增到PATH環境變數中。例如,你安裝的是arm工具鏈,那麼你在shell中執行類似如下的命令,假如有類似的輸出,就說明安裝好了。
[[email protected] linux-2.6.33.i686]# arm-linux-gcc --version
arm-linux-gcc (Buildroot 2010.11) 4.3.5
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
e) 如果是為嵌入式系統編譯模組,則要下載所需的核心原始碼,配置好,並編譯一次。否則,無法編譯模組。如果您不熟悉如何配置編譯核心,可以參考如下文章:
二、編譯
編譯模組,總得來說,有如下兩種方法。
(1) 獨立編譯
(2) 將模組程式碼整合到核心原始碼包中,跟隨Linux核心一塊編譯
由於涉及多種場景,因此下文分別進行介紹。
為了行文方便,這裡假定我們要編譯的模組名稱叫hello,並且模組的C檔案所在目錄為/root/hello。
(1) 獨立編譯
首先,在/root/hello中建立一個Makefile。
如果模組只有一個.c檔案,那麼檔名必須是hello.c。
此時,Makefile內容超級簡單,全部內容就如下一行:
obj-m := hello.o
如果模組由多個.c檔案構成,例如,main.c,a.c,b.c。
此時,Makefile的全部內容如下:
obj-m := hello.o
hello-objs := main.o a.o b.o
為了適應更通用的情況,這裡再對此makefile做點解釋。
obj-m是個makefile變數,他的值可以是一串.o檔案的表列。
列表中的每一項,代表一個模組。
其實,我們可以通過一個makefile編譯出多個模組。
例如,假設hello目錄下存放了多個模組的C檔案,別是hello、hello2、hello3。
hello模組的構成:main.c a.c b.c
hello2模組的構成:main2.c a2.c b2.c
hello3模組的構成:hello3.c
此時,Makefile寫成如下形式即可。
obj-m := hello.o hello2.o hello3.o
hello-objs := main.o a.o b.o
hello2-objs := main2.o a2.o b2.o
有了Makefile,就可以編譯了。
但是,模組與核心總是相配套的。編譯模組,總離不開核心原始碼。
因此,我們首先要確定核心原始碼的路徑。這個分兩種情況。
(i)嵌入式系統
既然是自己下載的原始碼,當然知道路徑。
(ii)當前PC機系統
對於當前PC機系統,我們在前面準備工作中並沒有為之下載原始碼。這是為什麼呢?因為PC機在安裝Linux時,已經安裝了一份核心原始碼樹。這個核心原始碼樹,並不是完整的核心原始碼,但他包含了核心原始碼標頭檔案,配置檔案,以及編譯核心模組所需的其他資訊。因此,對於編譯模組,有這些就足夠了。我們可以通過如下方法確定當前PC機核心原始碼樹路徑。
首先執行 uname -r 命令,得到當前PC機上執行的核心的版本號。
假設輸出是:2.6.33.3-85.fc13.i686.PAE
那麼核心原始碼樹的路徑就是
/lib/modules/2.6.33.3-85.fc13.i686.PAE/build
同時,可以得知當前PC機系統,所有模組都安裝到如下路徑中了。
/lib/modules/2.6.33.3-85.fc13.i686.PAE/kernel
那麼,有了這些資訊,就可以開始編譯了。
a) 編譯命令:
make -C /path/to/kernel_src_dir SUBDIRS=/root/hello modules
假如只是為當前PC機執行的核心編譯模組,且shell的當前工作目錄就是/root/hello,那麼命令可以簡化為(後面的模組安裝命令也可做類似的簡化):
make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd` modules
b) 模組安裝命令:(排版不當,導致命令換行了 ^_^)
假設這個模組是個網絡卡驅動。
(i)為當前pc安裝模組
make -C /path/to/kernel_src_dir SUBDIRS=/root/hello INSTALL_MOD_DIR=kernel/drivers/net modules_install
上述命令執行後,模組就被安裝到/lib/modules/2.6.33.3-85.fc13.i686.PAE/kernel/drivers/net目錄中去了。
(ii)為嵌入式系統安裝模組。假設kernel release version為x
make -C /path/to/kernel_src_dir SUBDIRS=/root/hello INSTALL_MOD_PATH=/path/to/rootfs_dir
modules_install
上述命令執行後,模組就被安裝到/path/to/rootfs_dir/lib/modules/x/kernel/drivers/net目錄中去了。
c) 清除命令:
make -C /path/to/kernel_src_dir SUBDIRS=/root/hello clean
最後,為了編譯的方便,我們在/root/hello下增加一個easy_make,內容如下。
BASEDIR := /lib/modules/$(shell uname -r)
KERNEL_SRC_TREE ?= $(BASEDIR)/build
PWD :=$(shell pwd)
INSTALL_DIR ?= kernel/drivers/net
.PHONY: all
all: clean modules install
obj-m := hello.o hello2.o hello3.o
hello-objs := main.o a.o b.o
hello2-objs := main2.o a2.o b2.o
.PHONY:modules
modules:
$(MAKE) -C $(KERNEL_SRC_TREE) SUBDIRS=$(PWD) modules
@echo $(abc-y)
.PHONY:clean
clean:
$(MAKE) -C $(KERNEL_SRC_TREE) SUBDIRS=$(PWD) clean
.PHONY:install
install:
$(MAKE) -C $(KERNEL_SRC_TREE) SUBDIRS=$(PWD) INSTALL_MOD_DIR=$(INSTALL_DIR) modules_install
這樣的話,我們以後只需要cd到/root/hello目錄,簡單的執行如下命令,就可以完成相應的操作了^_^
make -f easy_make modules
make -f easy_make install
make -f easy_make clean上述makefile預設是為當前PC機編譯模組。如果想用他為嵌入式系統編譯模組,則可以修改其中的KERNEL_SRC_TREE與INSTALL_DIR的值,或者直接從命令列傳入。