Linux 内核模块编译与集成指南
编写模块 Makefile
在 Linux 开发中,Makefile 是驱动构建的核心。通过定义特定的变量和目标,内核构建系统(Kbuild)可以识别并处理驱动源码。以下是一个典型的外部模块 Makefile 示例:
# 定义要生成的模块对象
obj-m := demo_driver.o
# 指定内核源码树路径,默认为当前运行内核的构建目录
KSRC_PATH ?= /lib/modules/$(shell uname -r)/build
# 获取当前工作目录
CURRENT_PATH := $(shell pwd)
# 默认构建目标
all:
$(MAKE) -C $(KSRC_PATH) M=$(CURRENT_PATH) modules
# 清理构建生成的临时文件
clean:
$(MAKE) -C $(KSRC_PATH) M=$(CURRENT_PATH) clean
# 模块安装目标
install:
$(MAKE) -C $(KSRC_PATH) M=$(CURRENT_PATH) modules_install
在 Makefile 中,赋值操作符的含义如下:
:=:立即赋值。在定义时计算右侧表达式的值,后续右侧变量改变不会影响当前变量。?=:条件赋值。仅当变量尚未被定义时才进行赋值,方便通过环境变量覆盖默认路径。
关于 obj-<X> 赋值的逻辑:
obj-m:将源文件编译为独立的可加载模块(.ko 文件)。obj-y:将驱动编译进内核镜像(zImage/Image)中。obj-n:忽略该目标,不进行编译。
在内核源码树内集成驱动
若需将自定义驱动永久集成到内核源码树中,需要遵循内核的配置体系。假设驱动文件为 custom_char_dev.c,通常将其放置在 drivers/char/ 目录下。
1. 配置 Kconfig
在对应目录的 Kconfig 文件中添加配置选项,以便在 make menuconfig 菜单中显示:
config CUSTOM_CHAR_DRIVER
tristate "Custom character device support"
default m
help
This option enables support for the custom character device.
If unsure, say M.
2. 修改 Makefile
在同目录的 Makefile 中引用该配置变量:
obj-$(CONFIG_CUSTOM_CHAR_DRIVER) += custom_char_dev.o
3. 静态配置(可选)
如果希望默认启用该驱动,可以在相关架构的 defconfig 文件中添加:
CONFIG_CUSTOM_CHAR_DRIVER=m
完成后,通过执行 make modules,系统会根据配置自动编译该目录下的驱动。编译产物通常位于 /lib/modules/$(uname -r)/kernel/ 下的相应子目录中。
外部模块(树外)构建方法
外部模块构建适用于不希望修改内核源码树的场景,但前提是系统中必须存在预编译的内核头文件或完整的内核源码树。版本必须与目标运行环境严格匹配。
在主流发行版(如 Ubuntu/Debian)上,可以通过以下命令安装内核头文件:
sudo apt-get update
sudo apt-get install linux-headers-$(uname -r)
安装完成后,头文件将位于 /usr/src/linux-headers-$(uname -r)。此时,只需进入驱动源码目录并执行 make 即可调用 Kbuild 系统完成编译。
交叉编译环境下的构建
在嵌入式开发中,通常需要在开发机上为目标架构(如 ARM)编译模块。此时需要指定架构 ARCH 和交叉编译器前缀 CROSS_COMPILE:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C /path/to/linux/source M=$(pwd) modules
在这种模式下,-C 参数必须指向已经针对目标架构预编译过的内核源码目录。