Linux内核模块编译问题:生成含共享头文件的两个模块
解决内核模块编译时链接buffer实现的问题
嘿,我来帮你搞定这个内核模块编译的问题!你之前的Makefile用obj-y += buffer.c是踩了内核模块编译的规则坑——obj-y是用来标记要直接编译进内核镜像的代码,而我们要做的是动态加载的.ko模块,完全不适用这个变量。
要让chardevin.ko和chardevout.ko都能链接buffer.c的实现,正确的做法是为每个模块指定它依赖的目标文件集合,内核构建系统通过模块名-objs这个变量来识别多文件组成的模块。
正确的Makefile示例
# 声明要编译的两个内核模块 obj-m += chardevin.o chardevout.o # 为每个模块指定依赖的目标文件: # chardevin模块由chardevin.o(主文件)和buffer.o组成 chardevin-objs := buffer.o chardevin.o # chardevout模块由chardevout.o(主文件)和buffer.o组成 chardevout-objs := buffer.o chardevout.o # 编译目标:调用内核构建系统编译模块 all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules # 清理目标:删除编译生成的临时文件和.ko文件 clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
关键原理说明
obj-m += chardevin.o chardevout.o:告诉内核构建系统我们要生成这两个动态加载模块chardevin-objs/chardevout-objs:指定每个模块由哪些.o文件链接而成,构建系统会先编译buffer.c生成buffer.o,再把它和对应模块的主.o文件打包成最终的.koall目标里的命令:-C指定当前系统内核的构建目录(依赖安装的内核头文件),M=$(PWD)告诉构建系统到当前目录找我们的源码
注意事项
- 先确保你的系统安装了对应内核版本的头文件包,比如Ubuntu下可以用
sudo apt install linux-headers-$(uname -r)安装 - 因为
buffer.c会被分别编译进两个模块,如果buffer里有全局变量或静态函数,要注意符号冲突问题。如果想让buffer代码只编译一次,可以把它做成独立的内核模块,用EXPORT_SYMBOL导出需要的函数,再让另外两个模块依赖它——不过这需要修改代码,并且加载模块时要先加载buffer模块,再加载chardevin/chardevout模块。
内容的提问来源于stack exchange,提问作者kylemart




