如何快速构建精简的 Linux 内核¶
本指南解释了如何快速构建 Linux 内核,这些内核非常适合测试目的,但对于日常使用也完全没问题。
流程的本质(又名“TL;DR”)¶
[如果您是编译 Linux 的新手,请忽略此 TLDR 并转到下面的下一部分:它包含一个分步指南,该指南更详细,但仍然简短且易于遵循;该指南及其随附的参考部分还提到了替代方案、陷阱和其他方面,所有这些都可能与您相关。]
如果您的系统使用安全启动等技术,请准备好允许启动自行编译的 Linux 内核;安装编译器和构建 Linux 所需的一切;确保在您的主目录中有 12 GB 的可用空间。现在运行以下命令以下载最新的 Linux 主线源代码,然后使用它来配置、构建和安装您自己的内核
git clone --depth 1 -b master \
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git ~/linux/
cd ~/linux/
# Hint: if you want to apply patches, do it at this point. See below for details.
# Hint: it's recommended to tag your build at this point. See below for details.
yes "" | make localmodconfig
# Hint: at this point you might want to adjust the build configuration; you'll
# have to, if you are running Debian. See below for details.
make -j $(nproc --all)
# Note: on many commodity distributions the next command suffices, but on Arch
# Linux, its derivatives, and some others it does not. See below for details.
command -v installkernel && sudo make modules_install install
reboot
如果您以后想构建较新的主线快照,请使用以下命令
cd ~/linux/
git fetch --depth 1 origin
# Note: the next command will discard any changes you did to the code:
git checkout --force --detach origin/master
# Reminder: if you want to (re)apply patches, do it at this point.
# Reminder: you might want to add or modify a build tag at this point.
make olddefconfig
make -j $(nproc --all)
# Reminder: the next command on some distributions does not suffice.
command -v installkernel && sudo make modules_install install
reboot
分步指南¶
原则上,编译您自己的 Linux 内核很容易。有很多方法可以做到。其中哪种方法实际有效且是最佳的取决于具体情况。
本指南描述了一种非常适合那些想要从源代码快速安装 Linux 而不受复杂细节困扰的人的方法;目标是涵盖在商品 PC 或服务器硬件上运行的主流 Linux 发行版上通常需要的所有内容。
所描述的方法非常适合测试目的,例如尝试建议的修复程序或检查问题是否已在最新的代码库中修复。尽管如此,以这种方式构建的内核对于日常使用也完全没问题,同时也很容易保持最新。
以下步骤描述了该过程的重要方面;稍后的综合参考部分将更详细地解释每一个方面。它有时还会描述替代方法、陷阱,以及在特定点可能发生的错误,以及如何再次启动和运行。
创建一个新的备份,并将系统修复和还原工具放在手边,以防万一发生意外情况。
[详情]
在具有“安全启动”或类似技术的平台上,准备好一切,以确保系统允许您自行编译的内核稍后启动。在商品 x86 系统上实现此目的的最快和最简单的方法是在 BIOS 设置实用程序中禁用此类技术;或者,通过
mokutil --disable-validation
启动的流程删除其限制。[详情]
安装构建 Linux 内核所需的所有软件。通常您将需要:'bc'、'binutils' ('ld' 等)、'bison'、'flex'、'gcc'、'git'、'openssl'、'pahole'、'perl',以及 'libelf' 和 'openssl' 的开发头文件。参考部分显示了如何在各种流行的 Linux 发行版上快速安装它们。
[详情]
确保有足够的可用空间用于构建和安装 Linux。对于后者,/lib/ 中的 150 兆字节和 /boot/ 中的 100 兆字节是安全的选择。对于存储源代码和构建工件,您的主目录中的 12 GB 通常应该足够了。如果您可用的空间较少,请务必查看参考部分,其中解释了调整内核构建配置的步骤:它提到了一个技巧,可以将 /home/ 中所需的空间减少到 4 GB 左右。
[详情]
检索您打算构建的 Linux 版本的源代码;然后更改为保存它们的目录,因为本指南中的所有进一步命令都应从此处执行。
[注意:以下段落描述了如何通过部分克隆 Linux 稳定 git 存储库来检索源代码。这称为浅克隆。参考部分解释了两种替代方法: 打包的存档 和 完整的 git 克隆 ;如果您不介意下载大量数据,请首选后者,因为这将避免一些 参考部分解释的浅克隆的特殊特性 。]
首先,执行以下命令以检索新的主线代码库
git clone --no-checkout --depth 1 -b master \ https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git ~/linux/ cd ~/linux/如果您想访问最近的主线版本和预发布版本,请将您的克隆历史加深到您感兴趣的最旧的主线版本
git fetch --shallow-exclude=v6.0 origin如果您想访问稳定/长期版本(例如 v6.1.5),只需添加包含该系列的 分支;之后,至少提取历史记录到启动该系列的主线版本 (v6.1)
git remote set-branches --add origin linux-6.1.y git fetch --shallow-exclude=v6.0 origin现在检出您感兴趣的代码。如果您只是执行了初始克隆,您将能够检出新的主线代码库,这非常适合检查开发人员是否已经修复了问题
git checkout --detach origin/master如果您加深了克隆,您可以使用您加深的那个版本(上面的
v6.0
)而不是origin/master
;后来的版本(如v6.1
)和预发布版本(如v6.2-rc1
)也可以使用。如果如上所述添加了适当的稳定/长期分支,则稳定或长期版本(如v6.1.5
)的工作方式相同。[详情]
如果您想应用内核补丁,请立即执行。通常,像这样的命令就可以解决问题
patch -p1 < ../proposed-fix.patch是否实际需要
-p1
取决于补丁的创建方式;如果它不适用,请尝试不使用它。如果您使用 git 克隆了源代码并且出现任何问题,请运行
git reset --hard
以撤消对源代码的任何更改。[详情]
如果您修补了内核或已经安装了相同版本的内核,最好为您即将构建的内核添加一个唯一的标签
echo "-proposed_fix" > localversion稍后在您的内核下运行
uname -r
将会打印类似“6.1-rc4-proposed_fix”的内容。[详情]
基于现有配置为您的内核创建构建配置。
如果您已经自己准备了这样的“.config”文件,请将其复制到 ~/linux/ 并运行
make olddefconfig
。如果您的发行版或其他人已经根据您或您的硬件需求定制了您正在运行的内核,请使用相同的命令:make 目标 ‘olddefconfig’ 将尝试使用该内核的 .config 作为基础。
使用此 make 目标对其他所有人来说也是可以的,但是您通常可以通过使用此命令来节省大量时间
yes "" | make localmodconfig这将尝试选择您发行版的内核作为基础,然后禁用明显对您的设置来说多余的功能的模块。这将大大缩短编译时间,特别是如果您正在运行来自商业 Linux 发行版的通用内核。
这里有一个问题:‘localmodconfig’ 很可能会禁用您自启动 Linux 以来未使用的内核功能,例如当前断开连接的外围设备的驱动程序或尚未使用的虚拟化软件。您可以使用参考部分概述的技巧来减少或几乎消除这种风险;但是,当构建一个仅用于快速测试目的的内核时,如果缺少这些功能通常是可以忽略不计的。但是,当使用此 make 目标构建的内核时,您应该记住这方面,因为它可能是您偶尔使用的某些东西停止工作的原因。
[详情]
检查您是否想要或必须调整某些内核配置选项
构建内核的映像和模块
make -j $(nproc --all)如果您希望将内核打包为 deb、rpm 或 tar 文件,请参阅参考部分以了解其他选项。
[详情]
现在安装您的内核
command -v installkernel && sudo make modules_install install通常,之后您所需要做的就是
reboot
,因为许多商业 Linux 发行版将创建 initramfs(也称为 initrd)和引导加载程序配置中内核的条目;但是在某些发行版上,您必须手动处理这两个步骤,原因参考部分中有说明。在少数发行版(如 Arch Linux 及其衍生版)上,上述命令根本不起作用;在这种情况下,您必须手动安装内核,如参考部分所述。
如果您正在运行不可变的 Linux 发行版,请查看其文档和网络,以了解如何在其中安装您自己的内核。
[详情]
要稍后构建另一个内核,您需要类似的步骤,但有时命令略有不同。
首先,切换回源代码树
cd ~/linux/如果您想构建一个尚未使用的稳定/长期系列(例如 6.2.y)的版本,请告诉 git 跟踪它
git remote set-branches --add origin linux-6.2.y现在获取最新的上游更改;您需要再次指定您关心的最早版本,因为否则 git 可能会检索整个提交历史
git fetch --shallow-exclude=v6.0 origin现在切换到您感兴趣的版本 - 但请注意,此处使用的命令将丢弃您执行的任何修改,因为它们会与您要检出的源代码冲突
git checkout --force --detach origin/master此时,您可能需要再次修补源代码或设置/修改构建标签,如前所述。之后,使用 olddefconfig 将构建配置调整为新的代码库,这将使用您之前使用 localmodconfig (~/linux/.config) 为您的下一个内核准备的配置文件
# reminder: if you want to apply patches, do it at this point # reminder: you might want to update your build tag at this point make olddefconfig现在构建您的内核
make -j $(nproc --all)之后,按照上述概述安装内核
command -v installkernel && sudo make modules_install install[详情]
您的内核稍后很容易删除,因为它的部分仅存储在两个位置,并且可以通过内核的发布名称清楚地识别。只需确保不要删除您正在运行的内核,因为这可能会导致您的系统无法启动。
首先删除保存内核模块的目录,该目录以其发布名称命名 - 在以下示例中为 '6.0.1-foobar'
sudo rm -rf /lib/modules/6.0.1-foobar现在尝试以下命令,该命令在某些发行版上会删除所有其他已安装的内核文件,同时还会从引导加载程序配置中删除内核的条目
command -v kernel-install && sudo kernel-install -v remove 6.0.1-foobar如果该命令没有任何输出或失败,请参阅参考部分;如果任何名为 ‘6.0.1-foobar’ 的文件保留在 /boot/ 中,也请执行相同的操作。
[详情]
如果您在遵循上述任何步骤时遇到问题,而参考部分没有解决,或者您有关于如何改进文本的想法?请花一点时间并通过电子邮件 (Thorsten Leemhuis <linux@leemhuis.info>) 让本文档的维护者知道,最好抄送 Linux 文档邮件列表 (linux-doc@vger.kernel.org)。此类反馈对于进一步改进本文档至关重要,这符合所有人的利益,因为它将使更多人掌握此处描述的任务。
逐步指南的参考部分¶
本节包含上述指南中每个步骤的附加信息。
为紧急情况做好准备¶
创建新的备份,并准备好系统修复和还原工具 [...]
请记住,您正在处理计算机,有时计算机会做出意想不到的事情 - 特别是当您摆弄操作系统的内核等关键部件时。这就是您在此过程中将要做的事情。因此,最好为发生意外情况做好准备,即使这种情况不应该发生。
[返回逐步指南]
处理像安全启动这样的技术¶
在具有“安全启动”或类似技术的平台上,准备好一切,以确保系统稍后允许您自编译的内核启动。 [...]
许多现代系统只允许某些操作系统启动;因此,它们默认会拒绝启动自编译的内核。
理想情况下,您应该通过使用证书和签名来使您的平台信任您自构建的内核来处理此问题。此处不描述如何执行此操作,因为它需要各种步骤,这些步骤会使文本偏离其目的太远;‘内核模块签名工具’ 和各种网站已经更详细地解释了这一点。
临时禁用安全启动等解决方案是使您自己的 Linux 启动的另一种方法。在商用 x86 系统上,可以在 BIOS 设置实用程序中执行此操作;此处不描述执行此操作的步骤,因为它们在不同机器之间差异很大。
在主流 x86 Linux 发行版上,还有第三种通用选项:禁用 Linux 环境的所有安全启动限制。您可以通过运行 mokutil --disable-validation
来启动此过程;这将告诉您创建一个一次性密码,该密码可以安全地写下来。现在重新启动;在您的 BIOS 执行完所有自检后,引导加载程序 Shim 将显示一个蓝色框,其中包含消息 “Press any key to perform MOK management”。在倒计时暴露之前,按任意键。这将打开一个菜单,并在其中选择 “Change Secure Boot state”。Shim 的 ‘MokManager’ 现在会要求您输入之前指定的一次性密码中随机选择的三个字符。一旦您提供了它们,请确认您真的要禁用验证。之后,允许 MokManager 重新启动计算机。
[返回逐步指南]
安装构建要求¶
安装构建 Linux 内核所需的所有软件。 [...]
内核是相当独立的,但除了编译器等工具外,有时还需要一些库来构建内核。如何安装所需的一切取决于您的 Linux 发行版和您将要构建的内核的配置。
以下是在一些主流发行版上通常需要的一些示例
Debian、Ubuntu 和衍生版本
sudo apt install bc binutils bison dwarves flex gcc git make openssl \ pahole perl-base libssl-dev libelf-devFedora 和衍生版本
sudo dnf install binutils /usr/include/{libelf.h,openssl/pkcs7.h} \ /usr/bin/{bc,bison,flex,gcc,git,openssl,make,perl,pahole}openSUSE 和衍生版本
sudo zypper install bc binutils bison dwarves flex gcc git make perl-base \ openssl openssl-devel libelf-dev
如果您想知道为什么这些列表包括 openssl 及其开发头文件:它们是安全启动支持所必需的,许多发行版在其 x86 机器的内核配置中启用了安全启动支持。
有时您还需要 bzip2、gzip、lz4、lzma、lzo、xz 或 zstd 等压缩格式的工具。
如果您执行本指南未涵盖的任务,则可能需要其他库及其开发头文件。例如,当从 tools/ 目录构建内核工具时,将需要 zlib;使用诸如 ‘menuconfig’ 或 ‘xconfig’ 之类的 make 目标调整构建配置将需要 ncurses 或 Qt5 的开发头文件。
[返回逐步指南]
空间要求¶
确保有足够的可用空间来构建和安装 Linux。 [...]
提到的数字是粗略的估计值,并且有很大的额外费用以确保安全,因此您通常需要的会更少。
如果你的空间有限,请务必在看到关于配置调整的部分时阅读参考部分,因为禁用调试符号将大大减少占用的磁盘空间,可以节省好几个GB。
[返回逐步指南]
下载源代码¶
获取你打算构建的 Linux 版本的源代码。 [...]
逐步指南概述了如何使用浅克隆 Git 来获取 Linux 源代码。关于这种方法,还有更多需要说明,以及两种值得介绍的替代方法:打包的存档文件和完整的 Git 克隆。并且,还需要详细说明“使用适当的预发布版本而不是最新的主线代码不是更明智吗?”和“如何获得更新的主线代码库?”这两个方面。
请注意,为了保持简单,本指南中使用的命令会将构建产物存储在源代码树中。如果你希望将它们分开,只需在所有 make 调用中添加类似 O=~/linux-builddir/
的内容即可;同时调整所有添加文件或修改任何生成文件(如你的 '.config')的命令中的路径。
[返回逐步指南]
浅克隆的值得注意的特性¶
逐步指南使用了浅克隆,因为对于本文档的大部分目标受众来说,这是最佳解决方案。这种方法有几个方面值得一提。
本文档在大多数地方使用
git fetch
和--shallow-exclude=
来指定你关心的最早版本(或者更准确地说:它的 Git 标签)。你也可以使用参数--shallow-since=
来指定一个绝对日期(例如'2023-07-15'
)或相对日期(例如'12 months'
)来定义你想要下载的历史深度。作为第二种替代方案,你还可以使用诸如--depth=1
的参数来明确指定某个深度,除非你为稳定版/长期支持内核添加分支。运行
git fetch
时,请记住始终指定最旧的版本、你关心的时间或如逐步指南中所示的明确深度。否则,你将冒着下载几乎整个 Git 历史的风险,这将消耗大量的时间和带宽,同时也会给服务器带来压力。请注意,你不必一直使用相同的版本或日期。但是,当你随着时间推移更改它时,Git 将加深或减少历史到指定的点。这使你可以检索最初认为不需要的版本,或者它会丢弃较旧版本的源代码,例如,如果你想释放一些磁盘空间。当使用
--shallow-since=
或--depth=
时,后者将自动发生。请注意,当加深你的克隆时,你可能会遇到类似“fatal: error in object: unshallow cafecaca0c0dacafecaca0c0dacafecaca0c0da”的错误。在这种情况下,请运行
git repack -d
并重试。如果你想还原某个版本(例如 Linux 6.3)的更改或执行二分查找(v6.2..v6.3),最好告诉
git fetch
检索早至三个版本(例如 6.0)的对象:git describe
届时将能够像在完整的 Git 克隆中一样描述大多数提交。
使用打包的存档文件下载源代码¶
刚接触编译 Linux 的人通常认为通过 https://linuxkernel.org.cn 的首页下载存档文件是获取 Linux 源代码的最佳方法。如果你确定只构建一个特定的内核版本而不更改任何代码,那么它实际上可以是。问题是:你可能确信情况会是这样,但在实践中,它往往会变成一个错误的假设。
这是因为在报告或调试问题时,开发人员通常会要求尝试另一个版本。他们还可能建议使用 git revert
临时撤销提交,或可能提供各种补丁进行尝试。有时,还会要求报告人员使用 git bisect
来查找导致问题的更改。这些事情依赖于 Git,或者使用 Git 处理起来会更容易、更快捷。
浅克隆也不会增加任何显著的开销。例如,当你使用 git clone --depth=1
创建最新的主线代码库的浅克隆时,Git 只会检索比通过 kernel.org 的首页下载最新的主线预发布版本(又名“rc”)多一点的数据。
因此,浅克隆通常是更好的选择。如果你仍然想使用打包的源代码存档,请通过 kernel.org 下载一个;然后将其内容提取到某个目录,并更改到提取期间创建的子目录。逐步指南的其余部分将可以正常工作,除了依赖于 Git 的内容——但这主要关系到关于其他版本的连续构建的部分。
使用完整的 Git 克隆下载源代码¶
如果下载和存储大量数据(截至 2023 年初约为 4.4 GB)对你来说没什么问题,则可以执行完整的 Git 克隆而不是浅克隆。这样你就可以避免上面提到的特殊之处,并且可以随时掌握所有版本和单个提交。
curl -L \
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/clone.bundle \
-o linux-stable.git.bundle
git clone linux-stable.git.bundle ~/linux/
rm linux-stable.git.bundle
cd ~/linux/
git remote set-url origin \
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
git fetch origin
git checkout --detach origin/master
适当的预发布版本 (RC) 与最新的主线版本¶
当使用 Git 克隆源代码并检出 origin/master 时,你通常会检索到介于最新版本和下一个版本或预发布版本之间的代码库。这几乎总是你想要尝试主线代码时的代码:像 v6.1-rc5 这样的预发布版本没有任何特殊之处,因为它们在发布前没有经过任何重要的额外测试。
有一种例外情况:你可能希望在它的后继版本的第一个预发布版本(v6.2-rc1)发布之前坚持使用最新的主线版本(例如 v6.1)。这是因为在此期间,编译器错误和其他问题更有可能发生,因为主线代码此时处于“合并窗口”:通常为期两周的阶段,在此期间,下一个版本的大部分更改会被合并。
避免主线延迟¶
浅克隆和完整克隆的解释都从 Linux 稳定版 Git 存储库中检索代码。这使得本文档的读者更容易理解,因为它允许轻松访问主线版本和稳定版/长期支持版本。这种方法只有一个缺点。
合并到主线存储库的更改仅每隔几个小时同步到 Linux 稳定版存储库的 master 分支。这种延迟在大多数情况下不是什么问题;但是,如果你真的需要最新的代码,只需将主线存储库添加为额外的远程存储库,并从那里检出代码即可。
git remote add mainline \
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
git fetch mainline
git checkout --detach mainline/master
在对浅克隆执行此操作时,请记住使用前面描述的参数之一调用 git fetch
以限制深度。
修补源代码(可选)¶
如果你想应用内核补丁,请立即执行此操作。 [...]
这是你可能想要修补内核的时间点,例如当开发人员提出修复程序并要求你检查是否有帮助时。逐步指南已经在这里解释了一切关键内容。
[返回逐步指南]
标记此内核版本(可选,通常明智)¶
如果你修补了内核或已经安装了该内核版本,最好通过扩展其发布名称来标记你的内核: [...]
标记内核将有助于避免以后出现混淆,尤其是在你修补了内核时。添加单独的标签还将确保内核映像及其模块与任何现有内核并行安装。
有多种方法可以添加这样的标签。逐步指南通过在你的构建目录中创建一个“localversion”文件来实现此目的,内核构建脚本将自动从中提取标签。你以后可以更改该文件以在后续构建中使用不同的标签,或者只需删除该文件以转储标签。
[返回逐步指南]
定义内核的构建配置¶
基于现有配置为你的内核创建构建配置。 [...]
此步骤有多个方面需要更仔细的解释。
使用其他配置文件作为基础时的陷阱¶
诸如 localmodconfig 和 olddefconfig 之类的 Make 目标有一些常见的陷阱,你需要注意。
如果你的构建目录中存在内核构建配置(例如“~/linux/.config”),这些目标将重用它。因此,如果你想从头开始,则需要删除它。
Make 目标尝试自动查找正在运行的内核的配置,但可能会选择不佳。“# using defaults found in /boot/config-6.0.7-250.fc36.x86_64”或“using config: ‘/boot/config-6.0.7-250.fc36.x86_64’”之类的行会告诉你它们选择了哪个文件。如果这不是预期的文件,只需在使用这些 Make 目标之前将其存储为“~/linux/.config”即可。
如果你尝试在旧版本(例如 v5.15)上使用为某个内核(例如 v6.0)准备的配置文件,则可能会发生意想不到的事情。在这种情况下,你可能需要使用你的发行版在使用该内核或稍旧的内核版本时使用的配置作为基础。
影响配置¶
make 目标 olddefconfig 和使用 localmodconfig 时使用的 yes "" |
会将任何未定义的构建选项设置为其默认值。这尤其会禁用许多在你的基本内核发布后引入的内核功能。
如果您想手动设置这些配置选项,请使用 oldconfig
而不是 olddefconfig
,或者在使用 localmodconfig 时省略 yes "" |
。然后,对于每个未定义的配置选项,系统都会询问您如何操作。如果您不确定如何回答,只需按“Enter”键即可应用默认值。
使用 localmodconfig 时的重大陷阱¶
正如在分步指南中简要解释的那样:使用 localmodconfig 时,您自己构建的内核很容易缺少您在使用此 make 目标之前未执行的任务所需的模块。这是因为这些任务需要内核模块,这些模块通常在您第一次执行该任务时自动加载;如果您在使用 localmodconfig 之前至少没有执行过该任务一次,后者会认为这些模块是多余的并禁用它们。
您可以通过执行通常会加载额外内核模块的典型任务来尝试避免这种情况:启动虚拟机、建立 VPN 连接、循环挂载 CD/DVD ISO、挂载网络共享(CIFS、NFS 等)以及连接所有外部设备(2FA 密钥、耳机、网络摄像头等)以及具有您通常不使用的文件系统的存储设备(btrfs、ext4、FAT、NTFS、XFS 等)。但是很难想到所有可能需要的东西——即使是内核开发人员也经常在这个时候忘记一些事情。
不要让这种风险困扰您,尤其是在仅出于测试目的编译内核时:通常至关重要的所有内容都会存在。如果您忘记了重要的东西,您可以稍后打开缺少的特性,并快速运行命令来编译和安装更好的内核。
但是,如果您计划定期构建和使用自己构建的内核,您可能需要通过记录您的系统在几周内加载的模块来降低风险。您可以使用 modprobed-db 自动化此过程。之后,使用 LSMOD=<路径>
将 localmodconfig 指向 modprobed-db 注意到的正在使用的模块列表
yes "" | make LSMOD="${HOME}"/.config/modprobed.db localmodconfig
使用 localmodconfig 进行远程构建¶
如果您想使用 localmodconfig 为另一台机器构建内核,请在其上运行 lsmod > lsmod_foo-machine
并将该文件传输到您的构建主机。现在将构建脚本指向该文件,如下所示:yes "" | make LSMOD=~/lsmod_foo-machine localmodconfig
。请注意,在这种情况下,您可能还需要从另一台机器上复制一个基础内核配置,并将其作为 .config 放置在您的构建目录中。
[返回分步指南]
调整构建配置¶
检查您是否想要或必须调整某些内核配置选项
根据您的需要,此时您可能想要或必须调整一些内核配置选项。
调试符号¶
评估您希望如何处理调试符号。 [...]
大多数用户不需要关心这一点,通常一切都保持原样即可;但是,如果可能需要解码堆栈跟踪或想减少空间消耗,则应该仔细研究一下。
当您的内核在运行后抛出“panic”、“Oops”、“warning”或“BUG”时,可以使用调试符号,因为这样您就可以找到问题在代码中发生的准确位置。但是,收集和嵌入所需的调试信息需要时间并消耗大量空间:在 2022 年末,使用 localmodconfig 配置的典型 x86 内核的构建工件在启用调试符号的情况下消耗约 5 GB 的空间,而在禁用调试符号的情况下则少于 1 GB。生成的内核映像和模块也更大,这会增加加载时间。
因此,如果您想要一个小的内核,并且以后不太可能解码堆栈跟踪,您可能需要禁用调试符号以避免上述缺点
./scripts/config --file .config -d DEBUG_INFO \
-d DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT -d DEBUG_INFO_DWARF4 \
-d DEBUG_INFO_DWARF5 -e CONFIG_DEBUG_INFO_NONE
make olddefconfig
另一方面,如果您有很大机会以后需要解码堆栈跟踪(如“中毒内核”中的“解码失败消息”中毒内核 中更详细的解释),您肯定希望启用它们
./scripts/config --file .config -d DEBUG_INFO_NONE -e DEBUG_KERNEL
-e DEBUG_INFO -e DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT -e KALLSYMS -e KALLSYMS_ALL
make olddefconfig
请注意,许多主流发行版在其内核配置中启用了调试符号——因此 localmodconfig 和 olddefconfig 等 make 目标通常会采用该设置。
[返回分步指南]
发行版特定的调整¶
您是否正在运行 [...]
以下部分可帮助您避免在一些常见的发行版上遵循本指南时已知会发生的构建问题。
Debian
删除会导致构建失败的过时证书文件引用
./scripts/config --file .config --set-str SYSTEM_TRUSTED_KEYS ''或者,下载所需的证书并使该配置选项指向它,如 Debian 手册更详细的说明 ——或者生成您自己的证书,如 内核模块签名工具 中所解释的。
[返回分步指南]
个人调整¶
如果您想影响配置的其他方面,请立即执行 [...]
此时,您可以使用 make menuconfig
之类的命令,使用基于文本的用户界面来启用或禁用某些功能;要使用图形配置,请使用 make 目标 xconfig
或 gconfig
。它们都需要基于工具包的开发库(ncurses、Qt5、Gtk2);如果缺少所需的任何内容,则会显示错误消息。
[返回分步指南]
构建您的内核¶
构建您的内核的映像和模块 [...]
在此阶段可能会出现很多问题,但以下说明将帮助您自助。另一个小节解释了如何直接将内核打包为 deb、rpm 或 tar 文件。
处理构建错误¶
当发生构建错误时,可能是由于您机器设置的某些方面导致,这些方面通常可以快速修复;但有时问题出在代码中,只能由开发人员修复。仔细检查失败消息并结合互联网上的一些研究通常会告诉您是哪一种。要执行这样的调查,请像这样重新启动构建过程
make V=1
V=1
会激活详细输出,这可能需要查看实际错误。为了更容易发现,此命令还省略了之前使用的 -j $(nproc --all)
,以利用系统中每个 CPU 内核来完成这项工作 —— 但这种并行性也会在发生故障时导致一些混乱。
几秒钟后,构建过程应该会再次遇到错误。现在尝试查找描述问题的最关键行。然后在互联网上搜索该行中最重要和非通用的部分(例如 4 到 8 个词);避免或删除任何看起来与系统相关的内容,例如您的用户名或本地路径名,如 /home/username/linux/
。首先使用该字符串尝试您常用的互联网搜索引擎,然后通过 lore.kernel.org/all/ 搜索 Linux 内核邮件列表。
这通常会找到一些解释问题所在的内容;通常,其中一个搜索结果也会为您的问题提供解决方案。如果您没有找到与您的问题匹配的任何内容,请通过修改您的搜索词或使用错误消息中的另一行,从不同的角度再次尝试。
最后,您遇到的大多数麻烦很可能已经被其他人遇到并报告过了。这包括原因不是您的系统,而是代码中的问题。如果您遇到其中一个问题,您也可能会找到解决您问题的方法(例如补丁)或解决方法。
打包您的内核¶
分步指南使用默认的 make 目标(例如,x86 上的“bzImage”和“modules”)来构建内核的映像和模块,指南的后续步骤将安装这些映像和模块。您也可以使用以下目标直接构建所有内容并直接打包:
make -j $(nproc --all) bindeb-pkg
生成 deb 包
make -j $(nproc --all) binrpm-pkg
生成 rpm 包
make -j $(nproc --all) tarbz2-pkg
生成 bz2 压缩 tarball
这只是为此目的提供的一些可用的 make 目标的选择,请参阅 make help
获取其他目标。您也可以在运行 make -j $(nproc --all)
后使用这些目标,因为它们会拾取所有已构建的内容。
如果您使用这些目标来生成 deb 或 rpm 包,请忽略分步指南中关于安装和删除内核的说明;而是使用格式(例如 dpkg 和 rpm)的软件包实用程序或基于它们构建的软件包管理实用程序(apt、aptitude、dnf/yum、zypper 等)来安装和删除软件包。请注意,使用这两个 make 目标生成的软件包旨在在利用这些格式的各种发行版上工作,因此它们的行为有时会与您的发行版内核软件包不同。
[返回分步指南]
安装您的内核¶
现在安装您的内核 [...]
在分步指南中执行命令后,您需要做什么取决于是否存在 installkernel
可执行文件及其实现。许多商品 Linux 发行版在 /sbin/
中都附带了这样一个内核安装程序,它可以完成所有需要的工作,因此您除了重新启动之外无需做任何事情。但一些发行版包含的 installkernel 仅完成部分工作——而少数发行版完全没有它,把所有工作都留给您。
如果找到 installkernel
,内核的构建系统会将内核映像和相关文件的实际安装委托给此可执行文件。在几乎所有 Linux 发行版上,它会将映像存储为“/boot/vmlinuz- <您的内核发布名称>”,并在其旁边放置一个“System.map-<您的内核发布名称>”。因此,除非您已经有一个具有完全相同发布名称的内核,否则您的内核将与任何现有内核并行安装。
许多发行版上的 Installkernel 之后将生成一个“initramfs”(通常也称为“initrd”),商品发行版依赖它进行启动;因此,请务必保持分步指南中使用的两个 make 目标的顺序,如果在安装内核的模块之前安装内核映像,事情将会出错。通常,installkernel 也会将您的内核添加到引导加载程序配置中。如果您的发行版的 installkernel 不处理这些任务,则必须自己处理其中一个或两个任务。
一些发行版(如 Arch Linux 及其衍生版)完全没有 installkernel 可执行文件。在这些发行版上,只需使用内核的构建系统安装模块,然后手动安装映像和 System.map 文件即可。
sudo make modules_install
sudo install -m 0600 $(make -s image_name) /boot/vmlinuz-$(make -s kernelrelease)
sudo install -m 0600 System.map /boot/System.map-$(make -s kernelrelease)
如果您的发行版在 initramfs 的帮助下启动,现在请使用您的发行版为此过程提供的工具为您的内核生成一个 initramfs。之后,将您的内核添加到引导加载程序配置并重新启动。
[返回分步指南]
稍后又一轮¶
要稍后构建另一个内核,您需要相似但有时略有不同的命令 [...]
构建后续内核的过程是相似的,但在某些方面略有不同。例如,您不想为后续内核构建使用“localmodconfig”,因为您已经创建了一个精简的配置,您希望从现在开始使用它。因此,只需使用 oldconfig
或 olddefconfig
来调整您的构建配置以满足您即将构建的内核版本的需要。
如果您使用 git 创建了浅克隆,请记住 详细解释了设置的部分:您需要使用略有不同的 git fetch
命令,并且在切换到另一个系列时需要添加一个额外的远程分支。
[返回分步指南]
稍后卸载内核¶
您安装的内核的所有部分都可以通过其发布名称识别,因此稍后很容易删除。 [...]
不要担心手动安装内核并因此绕过发行版的打包系统会完全搞砸您的机器:您的内核的所有部分都易于稍后删除,因为文件仅存储在两个位置,并且通常可以通过内核的发布名称来识别。
这两个位置之一是 /lib/modules/ 中的一个目录,其中包含每个已安装内核的模块。此目录以内核的发布名称命名;因此,要删除您的某个内核的所有模块,只需删除 /lib/modules/ 中的模块目录即可。
另一个位置是 /boot/,通常在内核安装期间会放置一到五个文件。它们通常在文件名中包含发布名称,但是有多少文件以及它们的名称在某种程度上取决于您的发行版的 installkernel 可执行文件(见上文)及其 initramfs 生成器。在某些发行版上,分步指南中提到的 kernel-install
命令将为您删除所有这些文件——同时删除您的内核在引导加载程序配置中的条目。在其他发行版上,您必须自己处理这些步骤。以下命令应以交互方式删除发布名称为“6.0.1-foobar”的内核的两个主要文件
rm -i /boot/{System.map,vmlinuz}-6.0.1-foobar
现在删除所属的 initramfs,它通常被称为类似 /boot/initramfs-6.0.1-foobar.img
或 /boot/initrd.img-6.0.1-foobar
的名称。之后,检查 /boot/ 中是否有其他名称中带有“6.0.1-foobar”的文件,并将其删除。现在从引导加载程序配置中删除内核。
注意,在手动删除内核的文件或目录时,请非常小心使用像“*”这样的通配符:当您只想删除 6.0 或 6.0.1 时,您可能会意外删除 6.0.11 内核的文件。
[返回分步指南]
常见问题解答¶
为什么此“操作指南”在我的系统上不起作用?¶
如最初所述,本指南旨在“涵盖在运行在商品 PC 或服务器硬件上的主流 Linux 发行版上构建内核通常需要的一切”。尽管如此,概述的方法应该也适用于许多其他设置。但是,尝试在一个指南中涵盖所有可能的用例会适得其反,因为如果没有这种关注,您将需要数十或数百个类似于“如果您有 <插入机器或发行版>,则此时必须执行 <此和彼> <代替|另外>”的结构。其中每一个都会使文本更长、更复杂且更难以理解。
话虽如此:这当然是一种平衡行为。因此,如果您认为其他用例值得描述,请将其建议给本文档的维护者,如上述所述。