概述¶
在本指南中,您将逐步了解获取内核源代码树、配置、编译、安装和启动它的过程。
不推荐也不支持对 Rocky Linux 进行内核重新编译。在尝试构建自定义内核之前,请考虑以下几点:
- 您所需的功能是否可以通过安装 elrepo 的内核模块来获得?
- 您所需的功能是否可以作为独立的模块从内核本身获得?
- Rocky Linux 和大多数其他 EL 衍生版本的设计是为了作为一个完整的环境。替换关键组件可能会影响系统的行为。
- 大多数用户不再需要自己构建内核。您可能只需要一个内核模块/驱动程序,或者可能需要构建自己的内核模块(kmod/dkms)。
最后警告:如果您损坏了内核,您将负责修复由此在您的系统上产生的问题。
内核¶
通常,当人们说“Linux”时,他们通常指的是“Linux 发行版”——例如,Rocky Linux 和 Debian 都是 Linux 发行版的类型。一个发行版包含使 Linux 成为一个功能齐全的操作系统所需的一切。发行版使用来自各种独立于 Linux 的开源项目中的代码。
Linux 是内核。内核字面上就处于操作系统的核心位置。
比内核更基础的东西就是系统硬件本身。尽管内核是完整 Linux 发行版中的一小部分,但它是迄今为止最关键的元素。如果内核失败或崩溃,系统的其余部分也将随之崩溃。
内核源代码¶
Rocky Linux 发行版以一种或另一种形式提供了其支持的特定内核版本的源代码。这些可能采用编译好的二进制文件(*.src.rpm
)、源代码 RPM(*.srpm
)等形式。
如果您需要下载与您特定的 Rocky Linux 发行版提供的版本不同的(可能更新的)版本,查找源代码的第一站是官方内核网站。
该网站维护着内核源代码镜像网站的列表,以及大量其他开源软件、发行版和通用实用程序。
维护镜像列表的网址是:
技巧
在接下来的章节中,大部分下载、配置和编译 Linux 内核的工作都可以/应该以非特权用户身份进行。但是,需要实际安装或更改系统文件和二进制文件的最后几个步骤需要以提升的权限来完成。
您可以以非特权用户身份完成大部分工作,因为您将使用一个特殊的内核构建选项,该选项允许您指定一个自定义的工作目录或输出目录。具体来说,您将在所有适用的 `make` 调用中使用 `O=~/build/kernel` 选项。
其中 `~/build/kernel` 等同于 `/home/$USER/build/kernel` 或 `$HOME/build/kernel`。
内核版本和命名约定¶
可用内核的网站列表将包含 v1.0、v2.5、v2.6、v3.0、v3.x、v4.x、v5.x、v6.x 等文件夹。在按照您的自然倾向获取最新版本之前,请确保您了解 Linux 内核版本系统的运作方式。
当前约定是将主要的内核新版本命名和编号为“Linux 5.x”(也称为 vanilla 或 mainline 内核)。因此,这个系列的第一版将是 Linux 版本 5.0(与 5.0.0 相同),下一版将是 Linux 版本 5.1(与 5.1.0 相同),然后是 Linux 版本 5.2,依此类推。
第三个数字表示每个主要发行版本中的任何次要更改或更新。这些通常被称为稳定版。因此,5.0.0 系列内核的下一个稳定版将是 Linux 版本 5.0.1,然后是版本 5.0.2,依此类推。另一种说法是,例如,Linux 版本 5.0.4 是基于 Linux 5.0.0 系列的第四个稳定版本。
安装先决工具和库¶
未能获得编译和构建 mainline Linux 内核所需的所有必需软件是在内核构建过程中遇到的常见故障来源。您可以使用 Rocky Linux 发行版上的 DNF 包管理器安装缺少的工具和库。您可以在这里处理。
-
在 Rocky Linux 发行版上,您可以通过运行此命令快速安装大部分必要的开发工具。
sudo dnf -y groupinstall 'Development Tools'
-
通过安装以下软件包,您将获得所需的其他库、头文件和应用程序。输入:
sudo dnf -y install ncurses-devel openssl-devel elfutils-libelf-devel python3
-
您只需要一些仅在特殊存储库中可用的其他实用程序。其中一个存储库是 CRB(Code Ready Builder)存储库。使用此命令在您的 Rocky 系统上启用该存储库:
sudo dnf config-manager --set-enabled crb
-
最后,从 CRB 存储库中安装一个所需的软件包:
sudo dnf -y install dwarves
这就是实际构建内核所需的先决软件包。
下载和解压 Linux 内核¶
您将在下一节中构建的内核版本是 **6.5.7**,可在以下网址获得:
www.kernel.org/pub/linux/kernel/v6.x/linux-6.5.7.tar.xz
让我们开始这个过程。
-
首先,使用以下 `curl` 命令将内核源代码下载到您当前的工作目录中。输入:
curl -L -o linux-6.5.7.tar.xz \ https://linuxkernel.org.cn/pub/linux/kernel/v6.x/linux-6.5.7.tar.xz
-
您将从互联网下载的内核源代码是一个压缩的 tar 文件。因此,您需要解压缩和提取源文件才能使用它。
确保您位于包含内核 tarball 下载的目录中。使用 `tar` 命令解压和解压缩文件,运行:
tar xvJf linux-6.*.tar.xz
构建内核¶
在本节中,您将回顾配置和构建内核的过程。这与 macOS 或 Windows 操作系统不同,后者是预先配置好的,因此包含许多您可能想要也可能不想要的功能的支持。
Linux 的设计理念允许个人决定内核的重要部分。这种个性化的设计有一个重要的好处,就是可以让您精简功能列表,以便 Linux 能够尽可能高效地运行。
这也是 Linux 可以自定义以适应各种硬件设置的原因之一,从低端系统到嵌入式系统再到高端系统。
构建内核需要两个主要步骤:
- 配置
- 编译
构建内核的第一步是配置其功能。通常,您将根据您需要支持的硬件来确定功能列表。这意味着您需要一个硬件列表。
在已经运行 Linux 的系统上,您可以运行 `lspci`、`lshw` 等命令来帮助显示有关您系统上确切硬件设置的详细信息。这些实用程序来自 RPM 基于发行版上的 `pciutils*.rpm` 和 `lshw*.rpm` 包。
更好地了解您的底层硬件构成,可以帮助您更好地确定自定义内核中需要什么。您已准备好开始配置内核。
清理构建环境¶
您可以开始实际配置,对您的新内核需要支持的硬件和功能类型有一个大致的了解。但首先,一些背景信息。
Linux 内核源代码树包含几个名为 **Makefile** 的文件(Makefile 只是一个包含指令的文本文件,它还描述了程序中文件之间的关系)。
这些 Makefile 有助于将构成内核源代码的数千个其他文件粘合在一起。对您更重要的是,Makefile 还包含目标。目标是 `make` 程序运行的命令或指令。
警告:避免不必要的内核升级
请记住,如果您有一个运行良好且稳定的工作系统,除非出现以下任一情况,否则几乎没有理由升级内核:
- 安全或错误修复会影响您的系统,并且必须应用
- 您在稳定版本中需要特定的新功能
在安全修复的情况下,请决定风险是否真正影响您——例如,如果安全问题存在于您不使用的设备驱动程序中,那么可能没有理由升级。在错误修复版本的情况下,请仔细阅读发行说明,并决定错误是否真正影响您——如果您有一个稳定的系统,升级您从不使用的补丁的内核可能是徒劳的。
在生产系统上,不应该仅仅为了拥有“最新的内核”而升级内核;您应该有一个真正令人信服的理由来升级。
内核源代码树根目录中的 Makefile 包含用于准备内核构建环境、配置内核、编译内核、安装内核等的特定目标。有关这些目标的更多详细信息:
make mrproper
-
此目标会清除构建环境中因先前内核构建遗留的任何过时文件和依赖项。它会清除(删除)构建环境中的所有先前内核配置。
make clean
-
此目标不像 `mrproper` 目标那样彻底。它只删除大部分生成的文件。它不会删除内核配置文件(`.config`)。
make menuconfig
-
此目标会调用一个基于文本的编辑器界面,其中包含菜单、选项列表和用于配置内核的基于文本的对话框。
make xconfig
-
此基于 GUI 的内核配置工具/目标依赖于 Qt 图形开发库。基于 KDE/Plasma 的应用程序使用这些库。
make gconfig
-
这同样是一个基于 GUI 的内核配置工具/目标,但它依赖于 GTK+ 工具包。这个 GTK+ 工具包在 GNOME 桌面环境中广泛使用。
make olddefconfig
-
此目标使用当前工作目录中现有的 `.config` 文件,更新依赖项,并自动将新符号设置为其默认值。
make help
-
此目标将显示所有可能的 targets,并作为快速在线帮助系统。
在本节中,您将只使用一个 target 来配置内核。具体来说,您将使用 `make menuconfig` 命令。`menuconfig` 内核配置编辑器是一个简单且流行的基于文本的配置实用程序,由菜单、单选按钮列表和对话框组成。
它拥有一个简单而干净的界面,可以通过键盘轻松导航,并且几乎直观易用。
您需要更改(`cd`)到内核源目录,然后就可以开始内核配置了。在开始实际内核配置之前,您应该使用 `make mrproper` 命令清理(准备)内核构建环境。
cd linux-6.*/
make O=~/build/kernel mrproper
内核配置¶
接下来,您将开始配置 Linux 6.* 系列内核。为了探索这个过程的内部细节,您将启用一个特定功能的 istem,您将假定它是系统上的一个“必需”功能。一旦您了解了它的工作原理,就可以应用相同的过程来添加对任何新内核功能的支持。具体来说,您将为我们的自定义内核启用对 NTFS 文件系统的支持。
大多数现代 Linux 发行版都附带一个运行内核的内核配置文件,该文件在本地文件系统上以压缩文件或常规文件的形式提供。在您的示例 Rocky 系统上,该文件位于 `/boot` 目录中,通常命名为 `config-*`。
配置文件包含一个已启用功能的列表,这些功能是其所代表的特定内核的。您的目标是通过内核配置过程来创建一个与此文件相似的配置文件。您将创建的文件与现成文件之间的唯一区别是,您将在您的文件中添加进一步的微小自定义。
技巧
使用一个已知、预先存在的配置文件作为创建自定义文件的框架,有助于确保您不会花费太多时间重复别人已经投入的找到有效和无效内容的努力。
以下步骤介绍了如何配置内核。您将使用一个基于文本的内核配置实用程序。无论您是否使用 GUI 桌面环境,都可以在终端中跟随。
-
首先,您将从 `/boot` 目录中的预先存在的配置文件复制并重命名到您的内核构建环境中。
cp /boot/config-`uname -r` ~/build/kernel/.config
在这里使用 `uname -r` 来帮助您获取运行内核的配置文件。`uname -r` 命令打印运行内核的版本。使用它有助于确保您获得您想要的確切版本,以防存在其他版本。
注意
Linux 内核配置编辑器显式查找并在内核源树的根目录中生成一个名为 `.config`(发音为“dot config”)的文件。此文件是隐藏的。
-
启动图形内核配置工具。
make O=~/build/kernel menuconfig
将出现一个类似此的屏幕。
内核配置屏幕大致分为三个区域。顶部显示有用的信息、键盘快捷键和图例,以帮助您导航应用程序。屏幕的主体显示一个可展开的树状结构列表,其中包含整体可配置的内核选项。您可以进一步通过父项中的箭头深入查看或配置子菜单(或子项)项。最后,屏幕底部显示用户可以选择的操作或选项。
-
接下来,您将为演示目的向自定义内核添加 NTFS 支持。
在主配置屏幕上,使用箭头键导航到并突出显示“文件系统”项。选择“文件系统”后,按 Enter 键查看“文件系统”的子菜单或子项。
在“文件系统”部分,使用箭头键导航到“DOS/FAT/NT 文件系统”。按 Enter 键查看“DOS/FAT/NT 文件系统”的子项。
-
在“DOS/FAT/NT 文件系统”部分,导航到“NTFS 文件系统支持”。
键入 M(大写)以启用 NTFS 文件系统的模块支持。
使用箭头键导航到底部的“NTFS 调试支持 (NEW)”并按 y 包含它。
使用箭头键导航到底部的“NTFS 写入支持”,然后按 Y 包含它。完成后,字母 `M` 或星号(`*`)应出现在每个选项旁边,如这里所示。
技巧
对于内核配置实用程序中的每个可配置选项,空括号 `<>` 表示该功能已禁用。括号中的字母 `M`,
表示该功能将作为模块进行编译。 括号中的星号 `<*>` 表示该功能将直接内置到内核中。您通常可以使用键盘上的空格键在所有可能选项之间切换。
-
在“DOS/FAT/NT 文件系统”屏幕中按两次 Esc 键返回到父“文件系统”屏幕。再次在键盘上按两次 Esc 键返回到主内核配置屏幕。
-
最后,保存您对内核源树根目录中的 `.config` 文件的更改,并在保存文件后退出内核配置应用程序,再次按两次 Esc 键。
-
将出现一个对话框,提示您保存新配置。确保您的选择是“Yes”,然后按 Enter。
-
内核配置实用程序退出后,您将回到内核源树内的 shell。您已准备好构建内核。
-
您需要在我们的 Rocky 发行版上完成一些额外的自定义。输入:
sed -ri '/CONFIG_SYSTEM_TRUSTED_KEYS/s/=.+/=""/g' ~/build/kernel/.config
技巧
要查看您使用 menuconfig 工具所做更改的结果,请使用 grep 工具查看您保存的 `.config` 文件。例如,要查看您之前启用的 NTFS 文件系统支持的效果,请键入以下命令:
$ grep NTFS ~/build/kernel/.config CONFIG_NTFS_FS=m CONFIG_NTFS_DEBUG=y CONFIG_NTFS_RW=y
关于内核模块的快速说明
可加载模块支持是 Linux 内核的一项功能,允许动态加载(或移除)内核模块。
内核模块是编译好的代码片段,可以动态插入正在运行的内核中,而不是永久地构建到内核中。因此,可以启用不常用的功能,但当它们不使用时,它们不会占用任何内存空间。
幸运的是,Linux 内核可以自动确定加载什么以及何时加载。当然,并非所有功能都可以编译为模块。内核在加载和卸载模块之前必须知道一些事情,例如如何访问硬盘以及如何解析存储可加载模块的文件系统。一些内核模块通常也称为驱动程序。
编译内核¶
在前一节中,您回顾了创建要构建的自定义内核的配置文件。在本节中,您将执行实际的内核构建。但在这样做之前,您将对整个过程进行一项简单的自定义。
最终自定义将是向我们内核的最终名称添加一个额外的信息。这将帮助我们区分此内核与其他具有相同版本号的内核。我们将把“custom”标签添加到内核版本信息中。通过编辑主 Makefile 并将所需的标签追加到 EXTRAVERSION 变量来实现。
内核构建过程的编译阶段是最容易的,但也是最耗时的。只需运行 `make` 命令,它就会自动生成并处理任何依赖关系问题,编译内核本身,以及编译启用为可加载模块的任何功能(或驱动程序)。
由于需要大量的代码编译,请准备等待至少几分钟,具体取决于您系统的处理能力。让我们深入了解编译新内核所需的具体步骤。
-
首先,您将为即将构建的内核的标识字符串添加一个额外的部分。仍然在内核源树的根目录中,您将使用 `sed` 实用程序就地编辑 Makefile。您要更改的变量靠近文件顶部。您要更改的文件中的行为如下:
EXTRAVERSION =
改为:
EXTRAVERSION = -custom
使用以下 `sed` 命令进行更改。输入:
sed -i 's/^EXTRAVERSION.*/EXTRAVERSION = -custom/' Makefile
您也可以使用您喜欢的任何文本编辑器进行更改。只需记住保存您的更改。
-
将 `kernelversion` target 传递给 `make` 命令,以查看您刚刚自定义的内核的完整版本。
make O=~/build/kernel kernelversion
技巧
您可以利用大多数现代系统上的所有额外处理能力(CPU、核心等),大大加快 CPU 密集型操作,如编译内核。为此,您可以向 `make` 命令传递一个参数,该参数指定要同时运行的作业数。然后,指定的作业数将在每个 CPU 核心上同时分布和执行。命令的语法是:
```bash make -j N ``` where N is the number of jobs to run simultaneously. For example, if you have a octa (8) core–capable CPU, you can type: ```bash make -j 8 ```
-
编译内核所需的唯一命令是 `make` 命令。
$ make O=~/build/kernel make[1]: Entering directory '/home/super/build/kernel' SYNC include/config/auto.conf.cmd GEN Makefile HOSTCC scripts/kconfig/conf.o HOSTLD scripts/kconfig/conf GEN Makefile ...<OUTPUT TRUNCATED>… LD [M] sound/usb/usx2y/snd-usb-usx2y.ko LD [M] sound/x86/snd-hdmi-lpe-audio.ko LD [M] sound/xen/snd_xen_front.ko LD [M] virt/lib/irqbypass.ko make[1]: Leaving directory '/home/super/build/kernel'
-
此命令的最终产品(即内核)已准备就绪,位于以下路径:
~/build/kernel/arch/x86/boot/bzImage
-
您需要安装模块,因为您将内核的一部分编译成了模块(例如,NTFS 模块)。输入以下命令:
sudo make O=~/build/kernel modules_install
在您的 Rocky 系统上,此命令会将所有编译的内核模块安装到 `/lib/modules/
` 目录中。在此示例中,此路径将转换为 `/lib/modules/6.5.7-custom/`。这是内核将按需加载所有可加载模块的路径。 技巧
通过 `make modules_install` 安装的内核模块的占用空间(大小)可能相当大,因为模块包含调试符号。因此,您可能会发现 `/lib/modules/6.5.7-custom/` 目录的大小接近 5GB!
在本指南中,您通过在 `make modules_install` 调用中包含 `INSTALL_MOD_STRIP=1` 选项来避免这个庞大的大小。通过剥离这些调试符号,您可以将总大小减小几个数量级(例如,小于 200 MB)。
可以通过将 `INSTALL_MOD_STRIP=1` 选项包含到 `make modules_install` 命令中来完成此操作。
安装内核¶
假设您有一台 PC 并且正在从 `~/build/kernel/` 目录进行工作,您在上一个练习中创建的已编译内核将位于此路径:`<kernel-build-dir>/arch/x86/boot/bzImage`,或者更确切地说,在我们的示例中是 `~/build/kernel/arch/x86/boot/bzImage`。
对应映射文件的位置是 `~/build/kernel/System.map`。安装阶段需要这两个文件。
当内核行为异常并生成“Oops”消息时,`System.map` 文件很有用。“Oops”消息会在某些内核错误时生成,这些错误是由于内核 bug 或硬件故障引起的。
此错误类似于 Microsoft Windows 中的蓝屏死机(BSOD)。这些消息包含有关系统当前状态的大量详细信息,包括多个十六进制数字。
`System.map` 允许 Linux 将这些十六进制数字转换为可读名称,从而简化调试。尽管这主要是为了开发者的利益,但在您报告问题时可能会很有用。
让我们逐步完成安装新内核映像所需的步骤。
-
在内核构建目录的根目录下,将 `bzImage` 文件复制并重命名到 `/boot` 目录。
sudo cp ~/build/kernel/arch/x86/boot/bzImage \ /boot/vmlinuz-<kernel-version>
在这里,`
` 是内核的版本号。本指南中使用的示例内核的文件名是 `vmlinuz-6.5.7-custom`。因此,这里是此示例的確切命令: sudo cp ~/build/kernel/arch/x86/boot/bzImage \ /boot/vmlinuz-6.5.7-custom
注意
将内核映像命名为 `vmlinuz-6.5.7-custom` 是有些任意的。它很方便,因为内核映像通常被称为 vmlinuz,并且当您有多个可用内核或提供特定功能的内核时(例如 `vmlinuz-6.50.0-ws`),版本号的后缀很有用。
-
现在内核映像已就位,使用相同的命名约定将对应的 `System.map` 文件复制并重命名到 `/boot` 目录。
sudo cp -v ~/build/kernel/System.map \ /boot/System.map-6.5.7-custom
-
内核已就位,`System.map` 文件已就位,模块也已就位,您现在已准备好进行最后一步。所需命令的语法是:
kernel-install add <kernel-version> <kernel-image>
在这里,`
` 是内核的版本号(和名称)。` ` 是新编译的内核映像的路径。 对于我们的示例,键入:
sudo kernel-install \ add 6.5.7-custom /boot/vmlinuz-6.5.7-custom
`kernel-install` 命令是一个巧妙的 shell 脚本。它可能并非在所有 Linux 发行版中都可用,但在较新的 Fedora、RHEL、CentOS 发行版中可用。此工具可以自动执行许多您通常需要手动完成的最终操作,以设置系统以启动您刚刚构建的新内核。
特别是,该工具执行以下操作:
- 它创建适当的初始 RAM 文件系统映像(即 initramfs 映像,即 `/boot/initramfs-
.img` 文件)。在 `kernel-install` 不可用的系统上手动执行此操作,请使用 `mkinitramfs` 命令。 - 它运行 `depmod` 命令(该命令创建模块依赖项列表)。
- 它更新引导加载程序配置。
对于运行较新版本 GRUB2 的系统,文件将是 `/boot/grub2/grub.cfg`。对于基于 EFI 的系统,还会更新 `/boot/efi/
对于运行旧版 GRUB 的系统,这将是 `/boot/grub/grub.conf` 或 `/boot/grub/menu.lst` 文件。对于实现新引导加载程序规范(BLS)的非常新的发行版,会在 `/boot/loader/entries/` 目录或 `blsdir` 变量指向的任何目录中添加一个新的引导加载程序条目。
在运行 GRUB2 并使用 BLS 的演示 EFI 基于 Rocky 服务器上,新的引导条目创建位于引导加载程序文件 `/boot/loader/entries/6fa25ca775f64accb0d3e53f0e4e6e92-6.5.7-custom.conf` 中。
$ sudo cat /boot/loader/entries/6fa25ca775f64accb0d3e53f0e4e6e92-6.5.7-custom.conf
title Rocky Linux (6.5.7-custom) 8.5 (Green Obsidian)
version 6.5.7-custom
linux /vmlinuz-6.5.7-custom
initrd /initramfs-6.5.7-custom.img $tuned_initrd
options $kernelopts $tuned_params
id rocky-20220212013135-6.5.7-custom
grub_users $grub_users
grub_arg --unrestricted
grub_class kernel
注意
大多数发行版都 readily available 提供了几个 `grub2-*` 实用程序,可用于执行各种 GRUB2 和引导加载程序维护任务。例如,您可以使用 `grub2-set-default` 命令更改或设置系统启动时要引导的默认内核。
启动自定义内核¶
下一个阶段是测试内核以确保系统可以引导。
-
假设您严格按照说明操作,并且一切都如预期顺利进行,您可以安全地重新引导系统,并在系统启动过程中从引导加载程序菜单中选择新内核。
sudo reboot
-
系统启动后,您可以使用 `uname` 命令查找当前内核的名称。
$ uname -r 6.5.7-custom
-
您会记得,您添加到新内核的功能之一是支持 NTFS 文件系统的能力。通过显示有关 NTFS 模块的信息,确保新内核确实支持 NTFS。
[rockstar ~]$ modinfo ntfs filename: /lib/modules/6.5.7-custom/kernel/fs/ntfs/ntfs.ko license: GPL version: 2.1.32 description: NTFS 1.2/3.x driver - Copyright ….. ...OUTPUT TRUNCATED...
一切都完成了。
作者:Wale Soyinka
贡献者:Steven Spencer, Louis Abel, Ganna Zhyrnova