Buildroot编译私有内核模块时内核源码不可用的问题排查
问题:Buildroot编译私有内核模块时找不到内核头文件
背景
拿到一个包含私有内核模块源码的.zip包,解压后需运行安装脚本,脚本会解压实际源码并编译内核模块,该过程依赖内核头文件。使用Buildroot 2022.02.1和内核5.15.33。
当前使用的Buildroot .mk文件
FOOCO_VERSION = 1.0 FOOCO_SOURCE = cust_kernel_drvr.zip FOOCO_SITE = /mnt/third-party/fooco FOOCO_SITE_METHOD = local define FOOCO_CONFIGURE_CMDS unzip $(@D)/$(FOOCO_SOURCE) -d $(@D) endef define FOOCO_BUILD_CMDS chmod +x $(@D)/TOOLS/Linux_x64/DRIVER/install cd $(@D)/TOOLS/Linux_x64/DRIVER; $(SHELL) ./install rm -rf $(@D) endef $(eval $(generic-package))
构建错误日志
DEBUG: start | rsync | fooco >>> fooco 1.0 Syncing from source dir /mnt/third-party/fooco rsync -au --chmod=u=rwX,go=rX --exclude .svn --exclude .git --exclude .hg --exclude .bzr --exclude CVS /mnt/third-party/fooco/ /root/buildroot-2022.02.1/output/build/fooco-1.0 DEBUG: end | rsync | fooco DEBUG: start | configure | fooco >>> fooco 1.0 Configuring unzip /root/buildroot-2022.02.1/output/build/fooco-1.0/cust_kernel_drvr.zip -d /root/buildroot-2022.02.1/output/build/fooco-1.0 Archive: /root/buildroot-2022.02.1/output/build/foofo-1.0/cust_kernel_drvr.zip [snip] creating: /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/ creating: /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/ inflating: /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/install inflating: /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/cust_kernel_drvr-1.2.0.15-0.noarch.rpm inflating: /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/cust_kernel_drvr.tar.gz inflating: /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/license_gpl.txt [snip] DEBUG: end | configure | fooco DEBUG: start | build | fooco >>> fooco 1.0 Building chmod +x /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/install cd /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER; /bin/bash ./install Extracting archive..OK! Compiling the driver...Error: make[1]: Entering directory '/root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/fooco_cust/src/linux/driver' common.mk:82: *** Kernel header files not in any of the expected locations. common.mk:83: *** Install the appropriate kernel development package, e.g. common.mk:84: *** kernel-devel, for building kernel modules and try again. Stop. make[1]: Leaving directory '/root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/fooco_cust/src/linux/driver' Error: unable to find driver file (fooco_cust.ko) in /root/buildroot-2022.02.1/output/build/fooco-1.0/TOOLS/Linux_x64/DRIVER/fooco_cust/src/linux/driver rm -rf /root/buildroot-2022.02.1/output/build/fooco-1.0 DEBUG: end | build | fooco touch: cannot touch '/root/buildroot-2022.02.1/output/build/fooco-1.0/.stamp_built': No such file or directory make: *** [/root/buildroot-2022.02.1/output/build/fooco-1.0/.stamp_built] Error 1 package/pkg-generic.mk:289: recipe for target '/root/buildroot-2022.02.1/output/build/fooco-1.0/.stamp_built' failed
内核模块Makefile的头文件查找路径
该模块的makefile会在以下路径查找内核头文件:
/lib/modules/${BUILD_KERNEL}/source \ /lib/modules/${BUILD_KERNEL}/build \ /usr/src/linux-${BUILD_KERNEL} \ /usr/src/linux-$(${BUILD_KERNEL} | sed 's/-.*//') \ /usr/src/kernel-headers-${BUILD_KERNEL} \ /usr/src/kernel-source-${BUILD_KERNEL} \ /usr/src/linux-$(${BUILD_KERNEL} | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \ /usr/src/linux \ /usr/src/kernels/${BUILD_KERNEL} \ /usr/src/kernels
疑问
为什么内核源码在构建过程中不可见?我以为Buildroot编译内核后,头文件会自动供后续内核模块编译使用,是不是漏了什么设置?
解答
核心原因
Buildroot的内核头文件和编译环境不在模块安装脚本默认查找的路径里:
- Buildroot将内核构建产物放在
$(LINUX_DIR)(通常为output/build/linux-<version>),但模块的Makefile只会去主机系统的标准路径查找,自然找不到对应版本的内核文件。 - 使用
generic-package模板不会自动关联内核构建的依赖和环境变量,无法传递内核路径给模块编译流程。
解决步骤
添加内核依赖声明
模块必须在内核编译完成后再构建,需添加依赖:FOOCO_DEPENDENCIES = linux传递内核构建环境给编译流程
显式告诉模块的makefile内核源码目录,通过KERNELDIR变量传递。修改FOOCO_BUILD_CMDS:define FOOCO_BUILD_CMDS chmod +x $(@D)/TOOLS/Linux_x64/DRIVER/install # 若安装脚本支持参数,直接传递内核路径 cd $(@D)/TOOLS/Linux_x64/DRIVER; $(SHELL) ./install --kerneldir=$(LINUX_DIR) # 若安装脚本不支持参数,跳过脚本的自动编译,手动调用make # cd $(@D)/TOOLS/Linux_x64/DRIVER/fooco_cust/src/linux/driver; make KERNELDIR=$(LINUX_DIR) endef移除构建目录删除命令
原BUILD_CMDS中的rm -rf $(@D)会导致Buildroot无法创建.stamp_built标记文件,直接引发报错,需删除该行。改用kernel-module模板(更规范)
Buildroot提供的kernel-module模板专门用于内核模块编译,会自动处理内核依赖和环境变量,调整后的.mk文件示例:FOOCO_VERSION = 1.0 FOOCO_SOURCE = cust_kernel_drvr.zip FOOCO_SITE = /mnt/third-party/fooco FOOCO_SITE_METHOD = local FOOCO_MODULE_MAKE_OPTS = KERNELDIR=$(LINUX_DIR) FOOCO_DEPENDENCIES = linux define FOOCO_EXTRACT_CMDS unzip $(DL_DIR)/$(FOOCO_SOURCE) -d $(@D) # 解压内部的tar.gz到指定目录 tar xf $(@D)/TOOLS/Linux_x64/DRIVER/cust_kernel_drvr.tar.gz -C $(@D) endef define FOOCO_BUILD_CMDS $(MAKE) -C $(@D)/fooco_cust/src/linux/driver $(FOOCO_MODULE_MAKE_OPTS) endef define FOOCO_INSTALL_TARGET_CMDS $(MAKE) -C $(@D)/fooco_cust/src/linux/driver $(FOOCO_MODULE_MAKE_OPTS) INSTALL_MOD_PATH=$(TARGET_DIR) modules_install endef $(eval $(kernel-module))
额外说明
Buildroot的交叉编译环境中,内核头文件不会安装到主机的/usr/src或/lib/modules路径,而是保留在$(LINUX_DIR)下。必须显式传递内核路径给模块的编译流程,否则它只会在主机系统的标准路径查找,无法找到对应版本的内核头文件。
内容的提问来源于stack exchange,提问作者Paul Woods
相关产品推荐
相关产品推荐

