如何让Kbuild在树外Linux内核驱动中支持子目录编译?
问题:树外内核驱动与设备树Overlay一同编译适配DKMS
背景
现有可正常编译运行的树外Linux内核驱动仓库,子目录包含可单独编译的设备树overlay,需将.dtbo与驱动代码一同编译,适配DKMS管理。
当前配置
Kbuild文件
obj-m := mydriver.o mydriver-objs += mydriver-dev.o mydriver-controls.o mydriver-registers.o mydriver-objs += mydriver-status-sysfs.o mydriver-sysfs.o subdir-y := device-trees
Makefile文件
ifneq ($(KERNELRELEASE),) # legacy compatible kbuild part of makefile include Kbuild else # local normal makefile for external module KERNELDIR ?= /lib/modules/$(shell uname -r)/build BUILDDIR ?= $(shell pwd)/build SRCDIR ?= $(shell pwd) all default: modules install: modules_install modules modules_install help clean: $(MAKE) -C $(KERNELDIR) M=$(BUILDDIR) src=$(SRCDIR) $@ endif
错误现象
移除subdir-y配置时编译正常,添加后出现递归错误:
make -C /lib/modules/6.6.31-current-bcm2712/build M=/home/builder/projects/platform_v4l2_driver/build src=/home/builder/projects/platform_v4l2_driver modules make[1]: Entering directory '/usr/src/linux-headers-6.6.31-current-bcm2712' scripts/Makefile.build:64: '/home/builder/projects/platform_v4l2_driver/build/device-trees/mydriver.ko' will not be built even though obj-m is specified. scripts/Makefile.build:65: You cannot use subdir-y/m to visit a module Makefile. Use obj-y/m instead. scripts/Makefile.build:64: '/home/builder/projects/platform_v4l2_driver/build/device-trees/device-trees/mydriver.ko' will not be built even though obj-m is specified. scripts/Makefile.build:65: You cannot use subdir-y/m to visit a module Makefile. Use obj-y/m instead. ...
替换为obj-y := device-trees/后递归问题更严重。
解决方案
核心思路
Kbuild的subdir-y/obj-y不适合处理设备树Overlay编译(不属于内核模块或内置代码流程),需单独为device-trees目录编写编译规则,在主Makefile中触发,同时兼容DKMS流程。
修改后的配置
1. 主目录Kbuild(保留驱动配置)
obj-m := mydriver.o mydriver-objs += mydriver-dev.o mydriver-controls.o mydriver-registers.o mydriver-objs += mydriver-status-sysfs.o mydriver-sysfs.o
2. device-trees目录下创建Kbuild文件
假设目录内有mydriver-overlay.dts,配置如下:
dtbo-y += mydriver-overlay.dtbo # 设备树编译通用规则 always := $(dtbo-y) clean-files := $(dtbo-y)
3. 修改主目录Makefile
添加设备树编译与安装逻辑,兼容DKMS:
ifneq ($(KERNELRELEASE),) include Kbuild else KERNELDIR ?= /lib/modules/$(shell uname -r)/build BUILDDIR ?= $(shell pwd)/build SRCDIR ?= $(shell pwd) DT_DIR := $(SRCDIR)/device-trees DT_BUILD_DIR := $(BUILDDIR)/device-trees all default: modules dtbo install: modules_install dtbo_install # 编译驱动模块 modules modules_install help clean: $(MAKE) -C $(KERNELDIR) M=$(BUILDDIR) src=$(SRCDIR) $@ # 编译设备树Overlay dtbo: mkdir -p $(DT_BUILD_DIR) $(MAKE) -C $(KERNELDIR) M=$(DT_BUILD_DIR) src=$(DT_DIR) dtbs # 安装设备树Overlay(适配标准路径,可按需调整) dtbo_install: mkdir -p /boot/overlays cp $(DT_BUILD_DIR)/*.dtbo /boot/overlays/ # 清理设备树编译产物 clean: clean_dtbo clean_dtbo: rm -rf $(DT_BUILD_DIR) endif
关键说明
- 设备树编译通过单独调用内核Makefile的
dtbs目标完成,避免与驱动模块Kbuild流程冲突 - 分离驱动与设备树的编译目录,彻底解决递归问题
dtbo_install将产物放到标准/boot/overlays目录,适配多数嵌入式系统(如树莓派),可根据实际系统调整路径- DKMS会自动识别Makefile中的
all、install、clean目标,无需额外配置即可同时管理驱动与设备树Overlay
内容的提问来源于stack exchange,提问作者Michał Fita
相关产品推荐
相关产品推荐

