将第三方扩展模块编译并安装到 /lib/modules/$(uname -r)/extra/
目录下,主要有两种方式:一种是手动编译和安装外部独立模块,另一种是将模块集成到内核源码树中并进行编译。以下是详细的步骤说明。
🛠️ 1. 准备编译环境
编译内核模块前,需要确保系统已安装必要的编译工具和与当前运行内核版本完全匹配的内核头文件及开发包。
- 安装编译工具和内核头文件: 在基于RPM的系统(如CentOS、RHEL)上,使用:
sudo yum install -y gcc make kernel-devel-$(uname -r) kernel-headers-$(uname -r)
在基于Debian的系统(如Ubuntu)上,使用:sudo apt-get install -y build-essential linux-headers-$(uname -r)
关键在于kernel-devel
和linux-headers
的版本必须与uname -r
(示例中的3.10.0-1160.81.1.el7.x86_64
)完全一致,否则编译可能失败。 - 验证路径: 安装后,确认以下路径存在且对应你的内核版本:
ls /lib/modules/$(uname -r)/build
这个build
目录通常链接到/usr/src/kernels/$(uname -r)
或/usr/src/linux-headers-$(uname -r)
,是模块编译所依赖的内核构建目录。
📦 2. 编译第三方模块
根据第三方模块是否提供内核源码树内的集成方式,编译方法有所不同。
▪ 方式一:编译外部独立模块(常见于第三方驱动)
这是最常见的情况,模块源码独立于内核源码树。
- 获取模块源代码: 将你的第三方模块源代码放置到系统任意目录,例如
~/mydriver/
。 - 编写 Makefile: 在模块源代码目录中,创建一个
Makefile
。这是最关键的一步,它的核心是指定内核构建系统的路径和要编译的模块对象。obj-m := your_module.o # 将 your_module.o 编译为内核模块(.ko) # 如果模块由多个源文件组成,可改为: # obj-m := your_module.o # your_module-objs := file1.o file2.o KDIR := /lib/modules/$(shell uname -r)/build # 指定内核构建目录 PWD := $(shell pwd) # 获取当前源代码路径 all: $(MAKE) -C $(KDIR) M=$(PWD) modules # 调用内核构建系统编译外部模块 clean: $(MAKE) -C $(KDIR) M=$(PWD) clean
- 执行编译: 在终端中,进入到包含源代码和
Makefile
的目录,运行make
命令:make -C /lib/modules/$(uname -r)/build M=$PWD modules
编译成功后,会在当前目录生成your_module.ko
文件。
▪ 方式二:在内核源码树内编译(集成到内核配置)
此方法适用于将第三方模块代码直接放入内核源码树并进行集成。
- 放置源代码: 将模块源代码(例如
your_module.c
)放置到内核源码树的适当目录下,例如drivers/char/
。 - 修改 Kconfig 文件: 在对应目录的
Kconfig
文件中添加菜单选项,以便在make menuconfig
时能配置该模块。config YOUR_MODULE tristate "Your Third-Party Module Driver" help This is a third party module example.
- 修改 Makefile 文件: 在对应目录的
Makefile
中添加编译指令,将模块对象添加到构建列表中。obj-$(CONFIG_YOUR_MODULE) += your_module.o
- 配置并编译内核模块: 在内核源码根目录下,执行
make menuconfig
,在相应菜单中选中你的模块为M
(编译为模块),然后保存退出。 执行以下命令编译所有模块(包括新添加的):make modules # 或使用 make -jN modules 并行编译加速,N为CPU核心数
编译生成的.ko
文件将位于对应的源码子目录中。
📂 3. 安装模块到指定目录
编译成功后,需要将 .ko
文件安装或移动到目标位置 /lib/modules/$(uname -r)/extra/
。
- 对于方式一(外部模块): 1. 手动安装:直接将编译好的
your_module.ko
文件复制到extra/
目录:sudo cp your_module.ko /lib/modules/$(uname -r)/extra/
2. 使用 modules_install:修改 Makefile,添加install
目标,或使用install
命令指定目标目录。更规范的做法是,在模块的Makefile
中通过modules_install
目标安装,但通常需要更复杂的配置才能指定到extra
目录。手动复制在简单场景下更直接。 - 对于方式二(内核树内模块): 使用以下命令安装所有已编译的模块(包括内置和模块),它们默认会被安装到
/lib/modules/$(uname -r)/kernel/
下的相应子目录中:sudo make modules_install
你的模块如果编译成功,也会被安装到对应的标准路径(如kernel/drivers/char/your_module.ko
)。如果希望它在extra/
目录,可能需要在配置或安装脚本中做额外处理,或者手动移动。
🔄 4. 更新依赖与签名(可选)
- 更新模块依赖关系: 安装新模块后,建议运行
depmod
来更新模块的依赖关系信息:sudo depmod -a
这将生成或更新/lib/modules/$(uname -r)
目录下的modules.dep
等文件,确保modprobe
命令能正确处理模块依赖。 - 模块签名(Secure Boot 环境): 如果系统启用了 Secure Boot,必须对模块进行签名才能加载。这通常需要一个合适的密钥和签名工具:
/path/to/kernel/source/scripts/sign-file sha512 /path/to/private_key.pem /path/to/public_key.der your_module.ko
签名后的模块方可在此安全环境下使用。
✅ 5. 验证与加载
- 检查模块: 使用
modinfo
命令验证模块信息及其安装路径:modinfo your_module.ko # 或 modinfo your_module
- 加载模块: 现在你可以使用
insmod
或modprobe
来加载它:# 使用 insmod 直接指定路径(需自行处理依赖) sudo insmod /lib/modules/$(uname -r)/extra/your_module.ko # 使用 modprobe(依赖已正确更新时,且模块在标准搜索路径或指定路径下) sudo modprobe your_module
使用lsmod | grep your_module
和dmesg | tail
可以查看模块是否成功加载及内核日志。
💎 核心总结
将第三方模块编译安装到 /lib/modules/3.10.0-1160.81.1.el7.x86_64/extra/
下的最常见且推荐的做法是:
- 准备环境:安装完全匹配的
kernel-devel
和kernel-headers
包。 - 独立编译:为模块编写正确的
Makefile
,使用-C $(KDIR) M=$(PWD)
参数调用内核构建系统进行编译。 - 手动安装:将生成的
.ko
文件直接复制到/lib/modules/$(uname -r)/extra/
目录。 - 更新配置:运行
depmod -a
更新模块依赖关系。