You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Linux内核模块编译问题:生成含共享头文件的两个模块

解决内核模块编译时链接buffer实现的问题

嘿,我来帮你搞定这个内核模块编译的问题!你之前的Makefile用obj-y += buffer.c是踩了内核模块编译的规则坑——obj-y是用来标记要直接编译进内核镜像的代码,而我们要做的是动态加载的.ko模块,完全不适用这个变量。

要让chardevin.kochardevout.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文件打包成最终的.ko
  • all目标里的命令:-C指定当前系统内核的构建目录(依赖安装的内核头文件),M=$(PWD)告诉构建系统到当前目录找我们的源码

注意事项

  • 先确保你的系统安装了对应内核版本的头文件包,比如Ubuntu下可以用sudo apt install linux-headers-$(uname -r)安装
  • 因为buffer.c会被分别编译进两个模块,如果buffer里有全局变量或静态函数,要注意符号冲突问题。如果想让buffer代码只编译一次,可以把它做成独立的内核模块,用EXPORT_SYMBOL导出需要的函数,再让另外两个模块依赖它——不过这需要修改代码,并且加载模块时要先加载buffer模块,再加载chardevin/chardevout模块。

内容的提问来源于stack exchange,提问作者kylemart

火山引擎 最新活动