Linux 核心模組建構依賴極簡 Makefile,核心在於將模組原始碼導入核心建構系統。本文逐行解析標準 Makefile、對比手動編譯指令、實作完整 hello 模組 (含初始化/清理、printk、模組授權/作者/描述)。
obj-m := hello.o # 目標模組名 hello.ko,由 hello.o 產生
KERNELDIR := /lib/modules/$(shell uname -r)/build # 核心建構樹 (含頂層 Makefile)
PWD := $(shell pwd) # 當前模組源碼目錄
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules # 進入核心樹,指定 M= 模組路徑,建構 modules 目標
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install # 安裝至 /lib/modules/.../extra/
$(shell uname -r) 取得當前執行核心版本 (如 2.6.38.2)/lib/modules/$(uname -r)/build 為編譯時自動複製的核心原始碼鏡像M=$(PWD) 告訴核心頂層 Makefile 模組源碼位置
make -C /usr/src/linux-source-2.6.38 M=$PWD modules
效果相同,/usr/src/... 為原始下載解壓路徑,/lib/modules/.../build 為編譯時鏡像,結構一致。
#include
#include
#include // printk
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("stephanxu@eetek");
MODULE_DESCRIPTION("the first kernel module");
static int __init hello_init(void) {
printk("hello, kernel\n");
return 0; // 非負值 = 成功載入
}
static void __exit hello_exit(void) {
printk("goodbye, kernel\n");
}
module_init(hello_init);
module_exit(hello_exit);
module_init() / module_exit() 指定函數,缺 module_exit 則無法動態卸載 (rmmod)__init 標記初始化段 (載入後釋放記憶體),__exit 標記卸載段;初始化回傳 0 成功、負值失敗、 來自核心原始碼 include/,**不可使用 C 標準庫** (stdio.h 等),核心無用戶空間 libcMODULE_LICENSE (強制)、MODULE_AUTHOR、MODULE_DESCRIPTION 等,modinfo hello.ko 可檢視
make # 產生 hello.ko
sudo insmod hello.ko # 載入
dmesg | tail # 查看 printk 輸出
sudo rmmod hello # 卸載
dmesg | tail # 查看 goodbye
從 Makefile 到模組骨架,踏出驅動開發第一步。