如何用Yocto将平台驱动构建为内核模块?编译问题排查
内核外部模块编译问题与解答
问题背景
需求为将内核源码中已有的、基于struct platform_driver的设备驱动封装为外部内核模块,使用module_platform_driver()宏完成注册(该宏应自动实现内核模块所需的module_init()和module_exit()函数)。但使用如下Makefile在Yocto编译时出现多个错误,其中之一为:
aarch64-poky-linux-ld.bfd: no input files
所用Makefile
obj-m += my-mod-lkm.o my-mod-lkm-y := my-mod.c SRC := $(shell pwd) all: $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules modules_install: $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install clean: $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean
测试情况
用户发现手动实现init_module()和cleanup_module()的简单模块可正常编译,代码如下:
#include <linux/module.h> /* Needed by all modules */ #include <linux/kernel.h> #include <linux/printk.h> /* Needed for pr_info() */ int init_module(void) { pr_info("My module initiated!"); return 0; } void cleanup_module(void) { pr_info("My module exited!"); } MODULE_LICENSE("GPL");
用户疑问
- Yocto是否不支持
module_init/module_exit宏? - 仅调用
module_platform_driver()是否足以将platform_driver封装为内核模块?
解答
- Yocto完全支持
module_init/module_exit宏:这两个是Linux内核的标准宏,Yocto作为构建框架,不会修改内核的核心宏定义,不存在不支持的情况。 module_platform_driver()宏足以完成注册:该宏是内核为简化platform驱动模块注册提供的封装,会自动展开为包含module_init()(注册platform驱动)和module_exit()(注销platform驱动)的代码,无需手动实现这两个函数。
编译错误原因分析与解决
出现aarch64-poky-linux-ld.bfd: no input files错误的核心原因并非宏支持问题,而是构建环境或配置问题:
KERNEL_SRC变量未正确赋值:在Yocto构建环境中,应使用Yocto提供的STAGING_KERNEL_DIR变量指向内核构建目录,替换Makefile中的KERNEL_SRC为$(STAGING_KERNEL_DIR),确保内核源码路径正确。- 文件存在性或拼写问题:确认
my-mod.c文件存在于当前目录,且文件名大小写与Makefile中的定义完全一致。 - 推荐使用Yocto配方构建:直接用原生Makefile在Yocto中构建模块容易出现环境变量问题,更可靠的方式是将模块封装为Yocto的
.bb配方文件,示例如下:
这种方式能自动继承Yocto的内核模块构建环境,避免手动配置环境变量的问题。SUMMARY = "My Platform Driver External Module" LICENSE = "GPL-2.0" LIC_FILES_CHKSUM = "file://COPYING;md5=59530bdf33659b29e73d4adb9f9f6552" inherit module SRC_URI = "file://my-mod.c \ file://Makefile \ " S = "${WORKDIR}" MODULES_INSTALL_TARGET = "my-mod-lkm.ko"
额外检查点
确保my-mod.c代码中包含MODULE_LICENSE("GPL")(或其他内核认可的许可证),缺失许可证会导致内核拒绝加载模块,也可能引发编译阶段的隐性问题;同时确认struct platform_driver实例的定义完整,包含probe、remove等必要函数指针。
内容的提问来源于stack exchange,提问作者Antoni
相关产品推荐
相关产品推荐

