使用单个Makefile编译Linux可加载内核模块与用户应用程序遇阻求助
刚入坑Linux驱动开发确实容易在Makefile上栽跟头,我来帮你搞定这个用单个Makefile同时编译用户态程序和内核模块的问题!
先看看你给出的Makefile片段,问题很明显:你只配置了内核模块的编译框架,但没添加用户态应用的编译规则,而且命令还没写完($(KERNE...应该是$(KERNELDIR)对吧?)。
下面是我帮你调整后的完整Makefile,直接能用,我会给你拆解开讲清楚每个部分:
# 指定内核源码的构建目录,这是标准路径 KERNELDIR = /lib/modules/$(shell uname -r)/build # 声明要编译的内核模块对象(你的驱动源文件应该是deviceJino.c吧?) obj-m := deviceJino.o # 获取当前工作目录的绝对路径 PWD := $(shell pwd) # 定义你的用户态应用程序目标名(替换成你实际的用户态程序文件名,不用带.c) APP := user_test_app # 默认执行目标:先编译内核模块,再编译用户态程序 default: module app # 编译内核模块的规则,这是内核模块编译的标准写法 module: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules # 编译用户态程序的规则,基础gcc编译命令,有额外依赖可以加参数 app: gcc -o $(APP) $(APP).c # 清理规则:同时清掉内核模块的编译产物和用户态可执行文件 clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean rm -f $(APP)
关键细节说明:
default: module app:当你直接敲make时,会按顺序执行module和app两个目标,先搞定驱动模块,再编译用户态程序。- 内核模块编译命令
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules:-C是让make跳转到内核源码目录执行构建脚本,M=$(PWD)是告诉内核构建系统回到当前目录找你的驱动源码,modules是内核构建系统的标准目标,用来编译模块。 - 用户态编译部分:如果你的用户态程序用到了特殊库(比如需要操作设备文件时用到的额外依赖),可以在gcc命令后加参数,比如
gcc -o $(APP) $(APP).c -lpthread(如果用到线程的话)。 clean目标:一次性清理所有编译垃圾,包括内核模块生成的.ko、.mod.c、.o这些文件,还有用户态的可执行程序。
额外注意事项:
- 确保你的用户态程序文件名和Makefile里的
APP变量对应,比如你的用户态代码是test_device.c,那APP := test_device。 - 编译内核模块不需要root权限,但加载模块(
sudo insmod deviceJino.ko)和操作设备文件可能需要。 - 如果编译时提示找不到内核头文件,先安装对应版本的内核头文件包:
sudo apt install linux-headers-$(uname -r) # Debian/Ubuntu系 # 红帽/ CentOS系用:sudo dnf install kernel-devel-$(uname -r)
内容的提问来源于stack exchange,提问作者Jino




