在跨编译的Debian GNU/Linux上自行编译设备驱动程序的注意事项(Linux Kernel 5.x 版本)
首先
我在以下文章中介绍了在使用交叉编译的 Debian GNU/Linux 上自行编译设备驱动程序的注意事项。
- 「クロスコンパイルした Debian GNU/Linux でデバイスドライバをセルフコンパイルする際の注意点」 @Qiita
尽管之前的文章是关于针对Linux Kernel 4.x的,但是在Linux Kernel 5.x中出现了新的问题。这篇文章将说明在Linux Kernel 5.x中自编译设备驱动程序(在目标系统上编译)时遇到的问题及(临时的)解决方法。
自编译失败的示例
下载
让我们以 dtbocfg(设备树覆盖配置文件系统)作为示例来编译。
root@debian-fpga:~/work# git clone https://github.com/ikwzm/dtbocfg.git
Cloning into 'dtbocfg'...
remote: Enumerating objects: 59, done.
remote: Total 59 (delta 0), reused 0 (delta 0), pack-reused 59
Unpacking objects: 100% (59/59), done.
root@debian-fpga:~/work# cd dtbocfg/
当发生失败时的日志
然后,构建失败如下。
root@debian-fpga:~/work/dtbocfg# make
make -C /lib/modules/5.0.21-armv7-fpga/build ARCH=arm CROSS_COMPILE= M=/root/work/dtbocfg modules
make[1]: Entering directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
CC [M] /root/work/dtbocfg/dtbocfg.o
Building modules, stage 2.
MODPOST 1 modules
/bin/sh: 1: scripts/mod/modpost: Exec format error
make[2]: *** [scripts/Makefile.modpost:92: __modpost] Error 2
make[1]: *** [Makefile:1581: modules] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
make: *** [Makefile:19: all] Error 2
失败的原因 de
查看日志,似乎在说 scripts/mod/modpost 的执行格式不同。scripts/mod/modpost 位于 /usr/src/linux-headers-*/scripts/mod/modpost。检查文件类型显示为主机计算机架构(此处为 x86-64)的二进制文件。
root@debian-fpga:~/work/dtbocfg# file /usr/src/linux-headers-5.0.21-armv7-fpga/scripts/mod/modpost
/usr/src/linux-headers-5.0.21-armv7-fpga/scripts/mod/modpost: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=b5044d5ffd526059755d33a6d8a8ab6c16e25293, not stripped
在Qiita上介绍的方法中使用跨编译的Debian GNU/Linux来自编译设备驱动程序时需要注意以下几点:当使用方法中创建的Debian软件包安装到目标系统时,将自动运行make脚本并重新构建与架构相关的各种可执行文件。
当检查安装Debian软件包linux-headers的日志时,发现出现了一个问题,即scripts/mod/modpost未重新构建。
root@debian-fpga:/home/fpga/debian# dpkg -i linux-headers-5.0.21-armv7-fpga_5.0.21-armv7-fpga-0_armhf-old.deb
Selecting previously unselected package linux-headers-5.0.21-armv7-fpga.
(Reading database ... 134399 files and directories currently installed.)
Preparing to unpack linux-headers-5.0.21-armv7-fpga_5.0.21-armv7-fpga-0_armhf-old.deb ...
Unpacking linux-headers-5.0.21-armv7-fpga (5.0.21-armv7-fpga-0) ...
Setting up linux-headers-5.0.21-armv7-fpga (5.0.21-armv7-fpga-0) ...
make: Entering directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
HOSTCC scripts/basic/fixdep
HOSTLD scripts/kconfig/conf
scripts/kconfig/conf --syncconfig Kconfig
HOSTCC scripts/dtc/dtc.o
HOSTCC scripts/dtc/flattree.o
HOSTCC scripts/dtc/fstree.o
HOSTCC scripts/dtc/data.o
HOSTCC scripts/dtc/livetree.o
HOSTCC scripts/dtc/treesource.o
HOSTCC scripts/dtc/srcpos.o
HOSTCC scripts/dtc/checks.o
HOSTCC scripts/dtc/util.o
HOSTCC scripts/dtc/dtc-lexer.lex.o
HOSTCC scripts/dtc/dtc-parser.tab.o
HOSTLD scripts/dtc/dtc
HOSTCC scripts/genksyms/genksyms.o
HOSTCC scripts/genksyms/parse.tab.o
HOSTCC scripts/genksyms/lex.lex.o
HOSTLD scripts/genksyms/genksyms
HOSTCC scripts/bin2c
HOSTCC scripts/kallsyms
HOSTCC scripts/conmakehash
HOSTCC scripts/sortextable
HOSTCC scripts/asn1_compiler
HOSTCC scripts/extract-cert
make: Leaving directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
看起来,脚本/mod/modpost的构建过程在Linux Kernel 5.x中发生了变化,使用make scripts不再构建scripts/mod/modpost。当我们将scripts/Makefile与Linux Kernel 5.0.21和4.19.57进行比较时,发现了对模块部分进行的更改。
--- linux-5.0.21-armv7-fpga/scripts/Makefile 2019-10-17 13:21:30.586261800 +0900
+++ linux-4.19.57-armv7-fpga/scripts/Makefile 2019-07-10 11:25:25.002216800 +0900
@@ -36,10 +36,11 @@ PHONY += build_unifdef
build_unifdef: $(obj)/unifdef
@:
-subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
subdir-$(CONFIG_MODVERSIONS) += genksyms
+subdir-y += mod
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
+subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
# Let clean descend into subdirs
-subdir- += basic dtc kconfig mod package
+subdir- += basic kconfig package gcc-plugins
在Linux内核5.x中,scripts/mod/modpost的构建是在顶级Makefile的prepare0中定义的。
:
(前略)
:
# prepare2 creates a makefile if using a separate output directory.
# From this point forward, .config has been reprocessed, so any rules
# that need to depend on updated CONFIG_* values can be checked here.
prepare2: prepare3 outputmakefile asm-generic
prepare1: prepare2 $(version_h) $(autoksyms_h) include/generated/utsrelease.h
$(cmd_crmodverdir)
archprepare: archheaders archscripts prepare1 scripts
prepare0: archprepare
$(Q)$(MAKE) $(build)=scripts/mod
$(Q)$(MAKE) $(build)=.
# All the preparing..
prepare: prepare0 prepare-objtool
:
(後略)
:
所以我在目标系统上执行了 /usr/src/linux-headers-*/ 上的 make prepare0。
oot@debian-fpga:~/work/dtbocfg# cd /usr/src/linux-headers-5.0.21-armv7-fpga/
root@debian-fpga:/usr/src/linux-headers-5.0.21-armv7-fpga# make prepare0
make[1]: *** No rule to make target 'arch/arm/tools/syscall.tbl', needed by 'arch/arm/include/generated/uapi/asm/unistd-common.h'. Stop.
make: *** [arch/arm/Makefile:323: archheaders] Error 2
我被告知这次没有 arch/arm/tools/syscall.tbl。
修改头部包裹
我认为正确的方法是将针对目标架构编译的可执行文件包含在头部包中。然而,在我调查的范围内,我找不到构建头部包的方法。如果有熟悉的人,请告诉我,谢谢。
作为一种次佳方案,在针对目标安装头包时,自动重新构建各种脚本,重新创建头包。具体来说,我们将在生成头包脚本中应用以下补丁。
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 8ac25d10a..00ad59866 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -155,9 +155,9 @@ done
# Build kernel header package
(cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles"
-(cd $srctree; find arch/*/include include scripts -type f -o -type l) >> "$objtree/debian/hdrsrcfiles"
+(cd $srctree; find arch/*/include include tools/include scripts -type f -o -type l) >> "$objtree/debian/hdrsrcfiles"
(cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles"
-(cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
+(cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -o -name tools -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then
(cd $objtree; find tools/objtool -type f -executable) >> "$objtree/debian/hdrobjfiles"
fi
@@ -172,6 +172,15 @@ mkdir -p "$destdir"
(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be
ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
+mkdir -m 755 -p "$kernel_headers_dir/DEBIAN"
+cat <<EOF >> $kernel_headers_dir/DEBIAN/postinst
+#!/bin/sh -e
+
+make -C /usr/src/linux-headers-$version prepare0
+
+EOF
+
+chmod 755 $kernel_headers_dir/DEBIAN/postinst
if [ "$ARCH" != "um" ]; then
create_package "$kernel_headers_packagename" "$kernel_headers_dir"
这个补丁文件会在 builddeb 的过程中包括 tools/include 目录下的文件,以确保 scripts/sortextable 的构建能够成功完成(参考「在交叉编译的 Debian GNU/Linux 上进行设备驱动的交叉编译时的注意事项」@Qiita)。
另外,我已经在 builddeb 中加入了 arch/$SRCARCH/tools 目录下的文件,以确保 scripts/mod/modpost 的构建能够成功完成。
在头文件包中添加了一个 postinst 脚本,用于重新构建脚本以供目标使用。在 postinst 脚本中添加了 make prepare0 的执行命令。这样,当安装头文件包时,将自动重新构建脚本。
安装修正后的头文件包。
用之前所述的方法,将构建的头文件包安装到目标系统中。
root@debian-fpga:/home/fpga/debian# dpkg -i linux-headers-5.0.21-armv7-fpga_5.0.21-armv7-fpga-0_armhf.deb
Selecting previously unselected package linux-headers-5.0.21-armv7-fpga.
(Reading database ... 134399 files and directories currently installed.)
Preparing to unpack linux-headers-5.0.21-armv7-fpga_5.0.21-armv7-fpga-0_armhf.deb ...
Unpacking linux-headers-5.0.21-armv7-fpga (5.0.21-armv7-fpga-0) ...
Setting up linux-headers-5.0.21-armv7-fpga (5.0.21-armv7-fpga-0) ...
make: Entering directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
HOSTCC scripts/kconfig/confdata.o
HOSTCC scripts/kconfig/expr.o
HOSTCC scripts/kconfig/symbol.o
HOSTCC scripts/kconfig/preprocess.o
LEX scripts/kconfig/zconf.lex.c
YACC scripts/kconfig/zconf.tab.h
HOSTCC scripts/kconfig/zconf.lex.o
YACC scripts/kconfig/zconf.tab.c
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/conf
scripts/kconfig/conf --syncconfig Kconfig
HOSTCC scripts/dtc/dtc.o
HOSTCC scripts/dtc/flattree.o
HOSTCC scripts/dtc/fstree.o
HOSTCC scripts/dtc/data.o
HOSTCC scripts/dtc/livetree.o
HOSTCC scripts/dtc/treesource.o
HOSTCC scripts/dtc/srcpos.o
HOSTCC scripts/dtc/checks.o
HOSTCC scripts/dtc/util.o
HOSTCC scripts/dtc/dtc-lexer.lex.o
HOSTCC scripts/dtc/dtc-parser.tab.o
HOSTLD scripts/dtc/dtc
HOSTCC scripts/genksyms/genksyms.o
HOSTCC scripts/genksyms/parse.tab.o
HOSTCC scripts/genksyms/lex.lex.o
HOSTLD scripts/genksyms/genksyms
HOSTCC scripts/bin2c
HOSTCC scripts/kallsyms
HOSTCC scripts/conmakehash
HOSTCC scripts/sortextable
HOSTCC scripts/asn1_compiler
HOSTCC scripts/extract-cert
CC scripts/mod/empty.o
HOSTCC scripts/mod/mk_elfconfig
MKELF scripts/mod/elfconfig.h
HOSTCC scripts/mod/modpost.o
CC scripts/mod/devicetable-offsets.s
HOSTCC scripts/mod/file2alias.o
HOSTCC scripts/mod/sumversion.o
HOSTLD scripts/mod/modpost
make: Leaving directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
scripts/mod/modpost 已经成功重新构建,没有发生任何问题。
让我们尝试编译 dtbocfg。
root@debian-fpga:~/work/dtbocfg# make
make -C /lib/modules/5.0.21-armv7-fpga/build ARCH=arm CROSS_COMPILE= M=/root/work/dtbocfg modules
make[1]: Entering directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
CC [M] /root/work/dtbocfg/dtbocfg.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/work/dtbocfg/dtbocfg.mod.o
LD [M] /root/work/dtbocfg/dtbocfg.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.0.21-armv7-fpga'
这次编译成功了。
root@debian-fpga:~/work/dtbocfg# insmod dtbocfg.ko
[32165.177417] dtbocfg_module_init
[32165.180623] dtbocfg_module_init: OK
编译后的 dtbocfg 看起来已经成功加载了。
请参考
-
- https://github.com/ikwzm/FPGA-SoC-Linux
- 「クロスコンパイルした Debian GNU/Linux でデバイスドライバをセルフコンパイルする際の注意点」 @Qiita