编写Linux内核驱动生成.ko(内核模块)文件,不一定需要把代码放到内核源码目录编译,但核心取决于你的编译方式——有两种主流方式,对应不同的文件存放逻辑,推荐第二种(更灵活):
一、两种编译方式的文件存放规则
方式1:内核源码树内编译(传统方式,需放特定目录)
- 要求:必须把驱动代码放到Linux内核源码的指定目录(如
drivers/i2c/devices/、drivers/misc/); - 原因:依赖内核源码的Makefile体系,需要修改目录下的
Kconfig和Makefile,让内核编译系统识别你的驱动; - 步骤示例(以AHT20驱动为例):
- 把
aht20.c放到linux-src/drivers/i2c/devices/; - 修改该目录下的
Makefile,添加:obj-$(CONFIG_AHT20) += aht20.o; - 修改该目录下的
Kconfig,添加驱动配置项; - 回到内核根目录,执行
make modules编译出.ko。 - 缺点:侵入内核源码,不灵活,多驱动开发时易混乱;
- 适用场景:驱动需要合入内核主线、或依赖内核深层接口。
方式2:内核源码树外编译(推荐,无需放特定目录)
- 核心:通过自定义
Makefile指定内核源码路径,驱动代码可放在任意目录(如/home/yourname/drivers/aht20/); - 原理:自定义Makefile通过
KERNELDIR指向内核源码目录,借助内核的scripts/Makefile.modpost工具完成编译,无需修改内核源码; - 优势:驱动代码独立,编译不影响内核源码,灵活易管理;
- 新手必用:99%的嵌入式驱动开发场景(如AHT20/PCF8574驱动)都用这种方式。
二、独立目录编译.ko(无需内核源码目录)
以编译AHT20驱动为例,全程无需把代码放进内核目录:
步骤1:任意目录创建驱动代码和Makefile
比如在/home/root/drivers/aht20/下创建两个文件:
aht20.c(驱动源码,略);Makefile(核心,指定内核路径和编译规则):
# 1. 指定你的内核源码目录(开发板对应的内核源码,不是系统内核) KERNELDIR ?= /home/root/linux-4.19.35-imx6ul # 替换为你的内核源码路径 # 2. 指定编译后的模块存放目录(可选,默认当前目录) PWD ?= $(shell pwd) # 3. 内核模块编译规则 obj-m += aht20.o # 要编译的驱动文件:aht20.c → aht20.ko # 4. 编译目标 all: make -C $(KERNELDIR) M=$(PWD) modules # -C进入内核目录,M指定驱动目录 clean: make -C $(KERNELDIR) M=$(PWD) clean步骤2:编译生成.ko
在驱动目录执行编译命令:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- # 交叉编译(根据你的编译器调整)ARCH=arm:指定CPU架构(ARM);CROSS_COMPILE:指定交叉编译器前缀(和你的开发板匹配);- 编译完成后,当前目录会生成
aht20.ko(还有.o/.mod.c等中间文件)。
关键注意事项
- 内核源码必须匹配:
- 编译
.ko的内核源码,必须和开发板运行的内核“版本+配置+编译选项”完全一致(否则insmod时会报version magic mismatch); - 比如开发板内核是
4.19.35,就必须用同版本的内核源码编译,不能用Ubuntu系统的内核源码。
- 编译
- 无需修改内核源码:
- 这种方式完全独立,不用动内核目录的任何文件,驱动代码放在任意目录都能编译;
- 若驱动依赖内核头文件(如
linux/i2c-dev.h),内核源码会自动提供,无需额外拷贝。
- 编译工具链匹配:
- 必须用和内核编译相同的交叉编译器(比如内核用
arm-linux-gnueabihf-gcc 7.5,驱动也得用这个版本)。
- 必须用和内核编译相同的交叉编译器(比如内核用
三、常见误区澄清
- “必须放内核目录”是错的:只有要把驱动合入内核主线时才需要,普通开发完全不用;
- “任意目录编译”的前提:内核源码必须提前配置(
make defconfig/make menuconfig)并编译过(至少编译出vmlinux),否则会缺少头文件和编译依赖; - .ko的安装:编译好的
.ko无需放到内核目录,直接拷贝到开发板任意目录(如/lib/modules/$(uname -r)/extra/),执行insmod aht20.ko即可加载。
总结
- 无需把驱动代码放到内核特定目录编译,独立目录+自定义Makefile是嵌入式驱动开发的标准做法;
- 核心是Makefile中指定正确的内核源码路径,保证内核版本、工具链和开发板匹配;
- 对你的AHT20/PCF8574驱动开发,直接在自己的工作目录(如
~/drivers/)创建代码和Makefile,编译即可,完全不用动内核源码目录。