1. 程式人生 > >Linux核心模組(驅動)編譯詳解

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的值,或者直接從命令列傳入。

(2) 將模組程式碼整合到核心原始碼包中編譯

未完......