Product SiteDocumentation Site

8.10. 编译内核

Debian 的内核尽量纳入所有的功能,以及最多的驱动程序,以便涵盖现在的硬件配置。所以,有些用户宁愿自行编译只包括所需的内核。这么做有两个理由。第一,内存用量较小,内核代码即使未用到,也占有内存的空间 (而且永远不 “离开” 置换内存,因为它用到实际的 RAM),降低系统的整体性能。本地自行编译的内核也限制了安全问题的范围,因为只编译与运行部分内核码。
使用只在补丁内提供的功能 (不在标准的内核版本内) 时,就必须重新编译内核。

8.10.1. 简介和先决条件

Debian 以软件包方式管理内核,与传统的编译安装不同。内核还是在软件包系统的控制下,可以被完整移除,或布建在多个机器上。与该软件包有关的脚本自动与启动程序和 initrd 生成器交互。
The upstream Linux sources contain everything needed to build a Debian package of the kernel. But you still need to install build-essential to ensure that you have the tools required to build a Debian package. Furthermore, the configuration step for the kernel requires the libncurses-dev package (formerly libncurses5-dev, which is now a transitional package). Finally, the fakeroot package will enable creation of the Debian package without using administrator's rights.

8.10.2. 获取源代码

就像 Debian 系统内其他有用的东西,Linux 内核源代码也在软件包内。只要安装 linux-source-version 软件包,就能取得全部的源代码。apt search ^linux-source 命令列出 Debian 内各种版本的核心软件包。最新的版本在 Unstable 发行版内:可以毫不费力的取得 (尤其是把 APT 根据 第 6.2.6 节 “在多个发行版中工作” 的指示配置后)。这些软件包内的源代码并未完全吻合 Linus Torvalds 与其他核心开发者发布的内容;如同其他的发行版,Debian 以一系列的补丁搭配,这些补丁可能 (或不可能) 以自己的方法纳入 Linux 上游的版本。包括从较新核心版本的 fixes/features/drivers 反向迁移,功能较新但尚未 (全部) 合并入上游的Linux 树,甚至 Debian 特别的改变。
The remainder of this section focuses on the 5.10 version of the Linux kernel, but the examples can, of course, be adapted to the particular version of the kernel that you want.
We assume the linux-source-5.10 package has been installed. It contains /usr/src/linux-source-5.10.tar.xz, a compressed archive of the kernel sources. You must extract these files in a new directory (not directly under /usr/src/, since there is no need for special permissions to compile a Linux kernel): ~/kernel/ is appropriate.
$ mkdir ~/kernel; cd ~/kernel
$ tar -xaf /usr/src/linux-source-5.10.tar.xz
To build a kernel from the pristine sources, just download the tarball of the version of your choice from kernel.org, verify the integrity after importing the kernel maintainers key, and then proceed as described in the following chapters.

$ wget https://kernel.org/pub/linux/kernel/v5.x/linux-5.10.62.tar.xz
[..]
$ wget https://kernel.org/pub/linux/kernel/v5.x/linux-5.10.62.tar.sign
[..]
$ unxz -c linux-5.10.62.tar.xz | gpg --verify linux-5.10.62.tar.sign -
gpg: Signature made Fri 03 Sep 2021 10:11:35 AM CEST
gpg:                using RSA key 647F28654894E3BD457199BE38DBBDC86092693E
gpg: Good signature from "Greg Kroah-Hartman <[email protected]>" [unknown]
gpg:                 aka "Greg Kroah-Hartman (Linux kernel stable release signing key) <[email protected]>" [unknown]
gpg:                 aka "Greg Kroah-Hartman <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 647F 2865 4894 E3BD 4571  99BE 38DB BDC8 6092 693E

8.10.3. 配置内核

下一个步骤是根据需要配置内核。确切的进程视需要而订。
When recompiling a more recent version of the kernel (possibly with an additional patch), the configuration will most likely be kept as close as possible to that proposed by Debian. In this case, and rather than reconfiguring everything from scratch, it is sufficient to copy the /boot/config-version file (the version is that of the kernel currently used, which can be found with the uname -r command) into a .config file in the directory containing the kernel sources. Make sure to read sidebar TIP Missing debian/certs/debian-uefi-certs.pem in this case.
$ cp /boot/config-5.10.0-8-amd64 ~/kernel/linux-source-5.10/.config
需要改变配置的话,就跳至 第 8.10.4 节 “编译与创建软件包”。或者从基本开始重新配置,就需花时间配置内核。在内核源代码的文件夹内有很多专属接口,使用 make target 命令调用,target 是下列的值之一。
make menuconfig compiles and executes a text-mode interface (this is where the libncurses-dev package is required) which allows navigating the options available in a hierarchical structure. Pressing the Space key changes the value of the selected option, and Enter validates the button selected at the bottom of the screen; Select returns to the selected sub-menu; Exit closes the current screen and moves back up in the hierarchy; Help will display more detailed information on the role of the selected option. The arrow keys allow moving within the list of options and buttons. To exit the configuration program, choose Exit from the main menu. The program then offers to save the changes you've made; accept if you are satisfied with your choices.
Other interfaces have similar features, but they work within more modern graphical interfaces; such as make xconfig which uses a Qt graphical interface, and make gconfig which uses GTK+. The former requires qtbase5-dev, while the latter depends on libglade2-dev and libgtk2.0-dev.
使用这些配置界面时,建议从合理的缺省配置开始。提供该配置的内核在 arch/arch/configs/*_defconfig,然后使用 make x86_64_defconfig (64 位电脑) 或 make i386_defconfig (32 位电脑) 这样的命令选择合适的缺省配置。

8.10.4. 编译与创建软件包

Once the kernel configuration is ready, a simple make deb-pkg will generate up to 5 Debian packages:
linux-image-version
contains the kernel image and the associated modules,
linux-headers-version
contains the header files required to build external modules,
linux-firmware-image-version
contains the firmware files needed by some drivers (this package might be missing when you build from the kernel sources provided by Debian),
linux-image-version-dbg
contains the debugging symbols for the kernel image and its modules (only created if CONFIG_DEBUG_INFO=y), and
linux-libc-dev
contains headers relevant to some user-space libraries like GNU glibc.
The version is defined by the concatenation of the upstream version (as defined by the variables VERSION, PATCHLEVEL, SUBLEVEL, and EXTRAVERSION in the Makefile), of the LOCALVERSION configuration parameter, and of the LOCALVERSION environment variable. The package version reuses the same version string with an appended revision that is regularly incremented (and stored in .version), except if you override it with the KDEB_PKGVERSION environment variable.
$ make deb-pkg LOCALVERSION=-falcot KDEB_PKGVERSION=$(make kernelversion)-1
[...]
$ ls ../*.deb
../linux-headers-5.10.46-falcot_5.10.46-1_amd64.deb
../linux-image-5.10.46-falcot_5.10.46-1_amd64.deb
../linux-image-5.10.46-falcot-dbg_5.10.46-1_amd64.deb
../linux-libc-dev_5.10.46-1_amd64.deb
The whole process requires around 20 GB of free space, at least 8 GB of RAM, and several hours of compilation (utilizing one core) for a standard amd64 Debian kernel. These requirements can be drastically reduced by disabling the debug information using CONFIG_DEBUG_INFO=n, but this will make it impossible to trace kernel errors (“oops”) using gdb and also stop the creation of the linux-image-version-dbg package.

8.10.5. 编译外部模块

Some modules are maintained outside of the official Linux kernel. To use them, they must be compiled alongside the matching kernel. A number of common third party modules are provided by Debian in dedicated packages, such as vpb-driver-source (extra modules for Voicetronix telephony hardware) or leds-alix-source (driver of PCEngines ALIX 2/3 boards).
这些软件包极多且复杂,apt-cache rdepends module-assistant$ 可以列出Debian提供的部分。然而,完整的清单没什么用处,只有明确知道需要时,才会编译特定的外部模块。在这个情况下,设备的文档会详述 Linux 环境所需的模块。
For example, let's look at the dahdi-source package: after installation, a .tar.bz2 of the module's sources is stored in /usr/src/. While we could manually extract the tarball and build the module, in practice we prefer to automate all this using the DKMS framework (Dynamic Kernel Module Support). Most modules offer the required DKMS integration in a package ending with a -dkms suffix. In our case, installing dahdi-dkms is all that is needed to compile the kernel module for the current kernel provided that we have the linux-headers-* package matching the installed kernel. For instance, if you use linux-image-amd64, you would also install linux-headers-amd64.
$ sudo apt install dahdi-dkms
[...]
Setting up dkms (2.8.4-3) ...
Setting up linux-headers-5.10.0-8-amd64 (5.10.46-4) ...
/etc/kernel/header_postinst.d/dkms:
dkms: running auto installation service for kernel 5.10.0-8-amd64:.
Setting up dahdi-dkms (1:2.11.1.0.20170917~dfsg-7.4) ...
Loading new dahdi-2.11.1.0.20170917~dfsg-7.4 DKMS files...
Building for 5.10.0-8-amd64
Building initial module for 5.10.0-8-amd64
Done.

dahdi_dummy.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.10.0-8-amd64/updates/dkms/

dahdi_dynamic_eth.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.10.0-8-amd64/updates/dkms/

[...]
DKMS: install completed.
$ sudo dkms status
dahdi, 2.11.1.0.20170917~dfsg-7.4, 5.10.0-8-amd64, x86_64: installed
$ sudo modinfo dahdi_dummy
filename:       /lib/modules/5.10.0-8-amd64/updates/dkms/dahdi_dummy.ko
license:        GPL v2
author:         Robert Pleh <[email protected]>
description:    Timing-Only Driver
depends:        dahdi
retpoline:      Y
name:           dahdi_dummy
vermagic:       5.10.0-8-amd64 SMP mod_unload modversions 
parm:           debug:int

8.10.6. 选择内核补丁

因为不够成熟或内核维护者意见不一致,很多功能未列入标准的内核。这种功能就以补丁的形式发行,任何人都可以自由地把它纳入内核源代码。
Debian 以 linux-patch-* 的形式提供这些软件包,但通常不在稳定版中(有时相同的原因是这些都未纳入上游内核版本中)。这些软件包安装的文件在 /usr/src/kernel-patches/ 文件夹内。
To apply one or more of these installed patches, use the patch command in the sources directory then start compilation of the kernel as described above. The following shows an old example using linux-patch-grsecurity2 and linux-source-4.9.
$ cd ~/kernel/linux-source-4.9
$ make clean
$ zcat /usr/src/kernel-patches/diffs/grsecurity2/grsecurity-3.1-4.9.11-201702181444.patch.gz | patch -p1
有些补丁不见得适用于每个内核版本;以 patch 可能无法应用于内核源代码。将出现错误消息且提示错误的原因;在此情况下,参照 Debian 补丁软件包的文档 (位于 /usr/share/doc/linux-patch-*/ 文件夹)。大部分的情况下,维护者会指出其补丁适用的内核版本。