如何將一個模組檔案編譯到Linux核心中?真的很簡單

很多粉絲在群裡提問,如何把一個模組檔案編譯到核心中或者獨立編譯成ko檔案。本文給大家詳解講解。

1。 核心目錄

Linux核心原始碼非常龐大,隨著版本的發展不斷增加。它使用目錄樹結構,並且使用Makefile組織配置、編譯。

初次接觸Linux核心,好仔細閱讀頂層目錄的readme檔案,它是Linux核心的概述和編譯命令說明。readme的說明側重於X86等通用的平臺,對於某些特殊的體系結構,可能有些特殊的說明。

頂層目錄的Makefile是整個核心配置編譯的核心檔案,負責組織目錄樹中子目錄的編譯管理,還可以設定體系結構和版本號等。

核心原始碼的頂層有許多子目錄,分別組織存放各種核心子系統或者檔案。 具體的目錄說明如下表所示。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

2。 編譯工具

make mrproper

: 清除核心生成的配置檔案與目標檔案等,一般在第一次編譯時使用

匯入預設配置資訊(在核心根目錄中)

a) make xxx_deconfigb) cp arch/arm/configs/xx_deconfig  。config生成預設配置檔案

配置命令

make xxxxconfig  修改配置檔案make xconfig (圖形介面 qt庫)make menuconfig (常用 libncurses庫)sudo apt-get install libncurses5-devmake config (精簡)

編譯核心

make uImage ——-生成核心映象  /arch/arm/boot/uImage

編譯裝置樹

make dtbs ——-生成裝置樹檔案  /arch/arm/boot/dtb/xxxxxx。dtb

編譯生成模組檔案

make modules ——-把配置值選成M的程式碼編譯生成模組檔案。(。ko)  放在對應的原始碼目錄下。

3。 核心編譯

現在很多基於Linux的產品開發,通常廠家都會提供整合開發環境SDK。builroot使我們搭建環境變得更加方便,但是作為初學者我們還是要掌握如何獨立編譯核心原始碼。

0) 前提條件

必須先安裝交叉編譯工具鏈,關於交叉編譯工具鏈的安裝可以參考 《linux環境搭建-ubuntu16。04安裝》

在這裡我們使用的是arm-none-linux-gnueabi-gcc。

1)下載核心原始碼

下載地址: https://mirrors。edge。kernel。org/pub/linux/kernel/

我們下載Linux-3。14核心(可以是更高的版本)至/home/peng目錄。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

或者直接點選下面連結 https://mirrors。edge。kernel。org/pub/linux/kernel/v3。x/linux-3。14。10。tar。xz

解開壓縮包,並進入核心原始碼目錄,具體過程如下:

$ tar  xvf  linux-3。14。tar。xz$ cd  linux-3。14

2)修改核心目錄樹根下的Makefile,指明交叉編譯器:

$ vim Makefile

找到ARCH和CROSS_COMPILE, 修改:

ARCH  ?= $(SUBARCH)CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:“%”=%)

ARCH  ?= armCROSS_COMPILE ?= arm-none-linux-gnueabi-

如何將一個模組檔案編譯到Linux核心中?真的很簡單

4)配置核心產生。config檔案:

匯入預設配置

$ make  exynos_defconfig

這裡我們假定要編譯的核心最終在三星的板子上執行,soc名字是exynos,三星公司其實已經將自己的配置檔案放置在 。/arch/arm/configs/exynos_defconfig

執行這個命令,最終會在核心根目錄下生成。config檔案,

如何將一個模組檔案編譯到Linux核心中?真的很簡單

我們編譯核心就完全依賴這個檔案。

該檔案是exynos開發板所需要的一些核心模組宏定義和引數設定,這些值是廠商給的一個初始配置。 實際專案開發中,需要在這個配置檔案基礎之上再重新移植自己需要的對應的驅動模組。

5)配置核心模組

輸入核心配置命令,進行核心選項的選擇,命令如下:

$ make menuconfig

命令執行成功以後,會看到如下圖所示的介面。其實我們在圖1。5中看到過同樣功能的介面,那個圖也是核心選項配置介面,只不過那個介面在X-window下才能執行。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

其中:

子選單——->

表示有子選單,按下回車可以進入子選單。

中括號[] 在每一個選項前都有個括號,有的是中括號,有的是尖括號,還有的是圓括號。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

[] 表示該選項只有兩種選項,中括號中要麼是空,要麼是“*”;

用空格鍵可以做出選擇。

尖括號<> <>選擇相應的配置時,有3種選擇,它們代表的含義分別如下。

● *:將該功能編譯進核心。

● 空:不將該功能編譯進核心。

● M:將該功能編譯成可以在需要時動態插入到核心中的模組。

模組配置圓括號() 而圓括號的內容是要你在所提供的幾個選項中選擇一項。

如果使用的是make xconfig,使用滑鼠就可以選擇對應的選項。如果使用的是make menuconfig,則需要使用回車鍵進行選取。

在編譯核心的過程中,麻煩的事情就是配置這步工作了。初次接觸Linux核心的開發者往往弄不清楚該如何選取這些選項。

實際上,在配置時,大部分選項可以使用其預設值,只有小部分需要根據使用者不同的需要選擇。

選擇的原則是將與核心其他部分關係較遠且不經常使用的部分功能程式碼編譯成為可載入模組,這有利於減小核心的長度,減少核心消耗的記憶體,簡化該功能相應的環境改變時對核心的影響;不需要的功能就不要選;與核心關係緊密而且經常使用的部分功能程式碼直接編譯到核心中。

6)編譯核心:

root@ubuntu:/home/peng/linux-3。14# make uImage

如何將一個模組檔案編譯到Linux核心中?真的很簡單

uImage

如果按照預設的配置,沒有改動的話,編譯後系統會在arch/arm/boot目錄下生成一個uImage檔案,這個檔案就是剛剛生成的。

7)下載Linux核心

因為不同的板子對應的uboot版本都不一樣,所以下載程式的uboot命令也會有所差異,關於驗證,本文暫不討論。

4。 獨立驅動程式的編譯

1。 編譯成獨立模組

假定我們有以下驅動程式,要編譯成可以載入到開發板的獨立ko檔案

hello。c

#include #include #include #include #include //#include #include #include #include static int major = 237;static int minor = 0;static dev_t devno;struct device *class_dev = NULL;struct class *cls;static int hello_open (struct inode *inode, struct file *filep){ printk(“hello_open()\n”); return 0;}static int hello_release (struct inode *inode, struct file *filep){ printk(“hello_release()\n”); return 0;}#define KMAX_LEN 32char kbuf[KMAX_LEN+1] = “kernel”;//read(fd,buff,40);static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos){ int error;  if(size > strlen(kbuf)) {  size = strlen(kbuf); } if(copy_to_user(buf,kbuf, size)) {  error = -EFAULT;  return error; } return size;}//write(fd,buff,40);static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos){ int error; if(size > KMAX_LEN) {  size = KMAX_LEN; } memset(kbuf,0,sizeof(kbuf)); if(copy_from_user(kbuf, buf, size)) {  error = -EFAULT;  return error; } printk(“%s\n”,kbuf); return size;}static struct file_operations hello_ops = { 。open = hello_open, 。release = hello_release, 。read = hello_read, 。write = hello_write,};static int hello_init(void){ int result;  printk(“hello_init \n”); result = register_chrdev( major, “hello”, &hello_ops); if(result < 0) {  printk(“register_chrdev fail \n”);  return result; } cls = class_create(THIS_MODULE, “hellocls”); if (IS_ERR(cls)) {  printk(KERN_ERR “class_create() failed for cls\n”);  result = PTR_ERR(cls);  goto out_err_1; } devno = MKDEV(major, minor);  class_dev = device_create(cls, NULL, devno, NULL, “hellodev”); if (IS_ERR(class_dev)) {  result = PTR_ERR(class_dev);  goto out_err_2; }  return 0;out_err_2: class_destroy(cls);out_err_1: unregister_chrdev(major,“hello”); return  result;}static void hello_exit(void){ printk(“hello_exit \n”); device_destroy(cls, devno); class_destroy(cls); unregister_chrdev(major,“hello”); return;}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE(“GPL”);//proc/devices

注意我們需要編寫Makefile如下:

ifneq ($(KERNELRELEASE),)obj-m:=hello。oelseKDIR :=/home/peng/linux-3。14PWD  :=$(shell pwd)all: make -C $(KDIR) M=$(PWD) modulesclean: rm -f *。ko *。o *。mod。o *。symvers *。cmd  *。mod。c *。orderendif

關於Makefile的詳解,大家可以參考我們之前的文章 《手把手教Linux驅動1-模組化程式設計》 其中核心路徑:

KDIR :=/home/peng/linux-3。14

必須是我們剛才編譯過的核心原始碼根目錄。

編譯時,程式可以放到其他目錄下:

如何將一個模組檔案編譯到Linux核心中?真的很簡單

用file命令檢視檔案屬性,是基於ARM的。該模組檔案就是與前面編譯的核心配套的驅動模組,如果開發板的核心版本與上面編譯的版本號一致,那麼該模組檔案就可以在開發板上insmod。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

2。 編譯到核心

步驟:

1)複製檔案 如果要將剛才的驅動程式直接編譯到核心,那麼我們必須把hello。c複製到核心的某個目錄下。

字元裝置可以考慮放到以下目錄:

linux-3。14/drivers/char

如何將一個模組檔案編譯到Linux核心中?真的很簡單

2)修改Makefile

root@ubuntu:/home/peng/linux-3。14/drivers/char# vim Makefile

修改如下:

如何將一個模組檔案編譯到Linux核心中?真的很簡單

該行內容是根據宏

CONFIG_HELLO

來決定是否編譯hello。c這個檔案。

3)修改Kconfig

如何將一個模組檔案編譯到Linux核心中?真的很簡單

7 HELLO 取前面步驟CONFIG_HELLO下劃線後面的字串 8 tristate 表示該模組最終有3個選項 空 * M 9 表示該模組依賴的模組,如果ARCH_EXYNOS4模組沒有被選中,那麼HELLO模組也不會被編譯到核心 10 幫助資訊

4) 重新配置 執行

make menuconfig

進入配置頁面,

輸入 / 可以根據關鍵字查詢模組所在位置。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

我們新增的模組檔案的位置:

如何將一個模組檔案編譯到Linux核心中?真的很簡單

根據路徑

-> Device Drivers    -> Character devices

找到我們剛才的模組配置路徑

如何將一個模組檔案編譯到Linux核心中?真的很簡單

此處是尖括號,因為我們設定的屬性是tristate

移動到Help處,可以看到前面我們填充的幫助資訊

我們可以按下空格鍵設定為*,編譯到核心中。

選擇Save,

如何將一個模組檔案編譯到Linux核心中?真的很簡單

如何將一個模組檔案編譯到Linux核心中?真的很簡單

然後再點選2次Exit,就可以退出。

5)重新編譯核心

root@ubuntu:/home/peng/linux-3。14# make uImage

這樣,我們的模組編譯到了新生成的核心模組檔案中。

3。 補充

前面一節其實最終目的是生成

CONFIG_HELLO=y

這個定義資訊,並把該資訊儲存到核心根目錄的。config檔案中。

如何將一個模組檔案編譯到Linux核心中?真的很簡單

其實我們如果不修改Kconfig,直接在。config中增加這個宏定義也是可以的。

今天內容就到這裡,還等什麼?抓緊操練起來吧。

文中用到的虛擬機器,叫交叉編譯工具,還有原始碼,可以關注公眾號,後臺回覆

ubuntu

,即可獲得。