跳转至内容

编译内核模块

来自 ArchWiki

有时您可能希望在不重新编译整个内核的情况下编译 Linux 的 内核模块

注意 只有当现有模块被编译为模块 (M) 而非内置 (y) 到内核中时,您才能替换它。

构建环境

首先,您需要安装构建依赖项,例如编译器(base-devel)和 linux-headers

接下来,您需要获取模块 intended to run on 的内核版本的源代码。您可以尝试使用较新的内核源代码,但编译出的模块很可能无法加载。

如果 intended kernel version 是当前已安装的内核,请使用以下命令查找其版本:

$ uname -r

获取所需源代码主要有两种方式。每种方式在用法和目录结构上略有不同。

传统编译

请参阅 Kernel/Traditional compilation#Download the kernel source。如果您使用 Git 获取最新源代码,则需要使用标签(例如 v4.1)来检出所需版本。

Arch 构建系统

有关 Arch 构建系统的概述,请阅读 ABS。有关获取内核源代码、目录结构和其他详细信息,请参阅 Kernel/Arch build system

源代码配置

获得源代码后,进入其目录。对于 #Arch 构建系统 的情况,该目录是 PKGBUILD 所在位置下的 src/archlinux-linux/

make help 的输出在这里很有帮助。首先使用以下命令进行清理:

$ make mrproper
注意 这将删除 .config.config.old。您可能需要先将这些文件保存到其他地方再进行清理。

现在需要一个合适的 .config 文件。如果附近没有,也许是从保存的 .config 文件中获取,并且 intended kernel version 是正在运行的内核,您可以使用它的配置文件:

$ zcat /proc/config.gz > .config

接下来,请确保 .config 文件已根据内核版本进行调整。如果您使用的是确切的当前版本的内核源代码,它应该不会询问任何问题。但对于比当前内核不同的版本,系统可能会询问一些选项。无论如何,对于 #Arch 构建系统 选项,您可能需要检查 PKGBUILD::prepare() 函数。

如果您要编译的模块有一些编译选项,例如调试构建,或者它以前没有被编译过,您也可以(可能必须)调整内核配置。您可以通过 `make help` 中提到的许多配置目标之一来完成此操作。

$ make oldconfig

模块编译

为了干净地编译和加载我们的模块,我们必须找到当前内核版本号的 EXTRAVERSION 组件的值,以便我们在内核源代码中精确匹配版本号。EXTRAVERSION 是内核顶层 Makefile 中设置的一个变量,但在 vanilla 内核源代码中的 Makefile 中 EXTRAVERSION 是空的;它仅作为 Arch 内核构建过程的一部分进行设置。如果相关,可以通过查看 uname -r 命令的输出来找到当前内核的 EXTRAVERSION 值。通常,内核版本是三个组件的串联。即,数字版本、EXTRAVERSION 和 LOCALVERSION。数字版本本身是三个数字的串联。如果通过 PKGBUILD 文件构建,LOCALVERSION 将从 pkgrel 变量中获取,并带有连字符前缀。EXTRAVERSION 将是 pkgver 变量的后缀,其中数字版本第三个数字右边的句点字符将被连字符替换。例如,对于 linux 包 linux 5.5.8.arch1-1,LOCALVERSION 是 -1。EXTRAVERSION 是 -arch1。在这种情况下,uname -r 的输出将是 5.5.8-arch1-1

一旦知道了 EXTRAVERSION 值,我们就可以准备源代码进行模块编译了:

$ make EXTRAVERSION=<YOUR EXTRAVERSION HERE> modules_prepare

示例

$ make EXTRAVERSION=-arch1 modules_prepare

或者,如果您乐意使用 --force-vermagic 选项通过 modprobe 加载模块,以忽略内核版本号的不匹配,您可以直接运行:

$ make modules_prepare
注意 使用顶层 Makefile 中记录的 EXTRAVERSION 来避免在命令行上手动指定 EXTRAVERSION 可能会导致版本不匹配。内核构建过程会识别这一点,导致它在 LOCALVERSION 配置设置后面附加一个 + 字符。例如:5.5.8-arch1-1+

最后,通过指定模块的目录名称来编译想要的模块。您可以使用 modinfofind 来找到模块的位置,从而也找到其目录名称。

$ make M=fs/btrfs

作为最后的手段,如果其他方法都无效,您可以:

$ make modules

这将从内核配置中构建所有模块。

树外模块编译

获取当前运行的 Linux 内核的官方源代码,如 Kernel/Arch build system 中所述。

$ cd && mkdir build
$ pkgctl repo clone linux

然后,在编译模块时指向已检出的源代码:

$ cd build/mymod
$ make -C ~/build/linux/src/archlinux-linux M=$PWD modules

模块安装

现在,成功编译后,您只需将其 gzip 并复制到您的当前内核即可。

如果您要替换某个现有模块,您将需要覆盖它(并记住重新安装 linux 会将其替换为默认模块)。

$ zstd fs/btrfs/btrfs.ko
# cp -f fs/btrfs/btrfs.ko.zst /usr/lib/modules/$(uname -r)/kernel/fs/btrfs/

或者,您也可以将更新的模块放在 updates 文件夹中(如果不存在则创建它)。

$ cp fs/btrfs/btrfs.ko.zst /usr/lib/modules/$(uname -r)/updates

但是,如果您要添加一个新模块,您可以直接将其复制到 extramodules(请注意,这只是一个示例,btrfs 不会从此加载)。

# cp fs/btrfs/btrfs.ko.zst /usr/lib/modules/$(uname -r)/extramodules/

您需要使用 "depmod" 重新构建模块依赖树才能使用已安装的模块。

如果您正在为早期启动编译模块(例如更新的模块),并且将其复制到 Initramfs,那么您必须记住使用以下命令重新生成它(否则您编译的模块将不会被加载)。

# mkinitcpio -p linux

可能遇到的错误

如果 EXTRAVERSION 设置不正确,可能会出现以下错误:

# insmod mymod.ko
insmod: ERROR: could not insert module mymod.ko: Invalid module format
# modprobe mymod
modprobe: ERROR: could not insert 'mymod': Exec format error

添加 force-vermagic 会忽略版本不匹配。

modprobe mymod --force-vermagic

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.