在 CentOS 8 上手工编译并打包 Linux 6.19.4 内核:从源码到 RPM 的全流程指南

6517 字
33 分钟
在 CentOS 8 上手工编译并打包 Linux 6.19.4 内核:从源码到 RPM 的全流程指南

授人以渔版内核编译实践笔记:这篇文章的目标不是“复制一段脚本就能跑通”,而是带你从 0 到 1 理解——为什么 CentOS 8 默认编译不了 Linux 6.19.4、每一个 make 步骤在做什么,以及如何把单纯的源码编译结果,变成可以通过 rpm -qidnf remove 统一管理的内核包。

本文的场景背景来源于一台典型的 CentOS 8 服务器

  • 默认内核:4.18.x(版本较老,但稳定性经过长期验证)
  • 目标:编译并部署 Linux 6.19.4 新内核(更好的硬件支持、新特性、更新的文件系统/调度器等)
  • 要求:最终必须能像 ELRepo 的 kernel-ml 那样,用 rpm -qa 查到,用 dnf remove 卸载,而不是孤零零地躺在 /boot/lib/modules 里没人管。

在实践过程中,会遇到一些较为典型的问题:

  • GCC 太老、bcpahole 缺失;
  • SYSTEM_TRUSTED_KEYS 依赖 certs/rhel.pem 报错;
  • 并行编译把真正错误淹没在 Makefile:2064: Error 2 之下;
  • make install 编译出来的内核,rpm -qa 完全看不到身影。

这篇文章会按照以下结构展开:

  1. 引言:为什么要在 CentOS 8 上编译新内核?
  2. 第一步:打造编译环境(GCC 12、依赖、工具链)
  3. 第二步:获取源码与配置优化(下载、导入 config、净化 RHEL 特定配置)
  4. 第三步:编译过程中的“坑”与填平bcpaholerhel.pemError 2
  5. 第四步:让手工内核“正规化”(核心章节:Spec 文件 + rpmbuild 打包流程)
  6. 第五步:验证与重启
  7. 结语:手工编译的意义与自动化工具展望(含脚本彩蛋)

一、引言:为什么要在 CentOS 8 上编译新内核?#

很多人问:CentOS 8 官方内核(4.18)那么稳,用 ELRepo 的 kernel-ml 不就行了吗?
为什么还要自己折腾源码、自己打包 RPM?

动机主要有三类:

  • 硬件支持
    新服务器 / 新网卡 / 新 NVMe / 新 RAID 卡,往往需要新内核里的驱动或 bugfix;
    某些 4.18 没有的特性(例如新版本 Btrfs、改进的 cgroup / io_uring 等)在 6.19.4 中已经成熟。

  • 内核特性试验场
    想尝试最新的调度器、BPF 特性、内核安全加固选项,甚至打上自定义补丁。
    官方包大多是“通用调优”,不一定贴合你手头的业务场景。

  • 掌控感与可回放性
    自己编译、自己打包,意味着你清楚每一行配置和每一个补丁的来龙去脉;
    未来遇到问题,可以有针对性地改 CONFIG、打 patch,而不是“听天由命”。

除了上述技术动机外,还有一个非常现实的原因:

生产环境不适合使用“无法审计和统一管理”的内核。
更稳妥的做法,是使用能够被 RPM 数据库接管、可以通过 rpm -qi 查看信息、用 dnf remove 安全卸载的内核包。

因此,本文的目标不是简单地 “成功执行一次 make 内核”,而是:

在 CentOS 8 上,完整经历一次:从源码 → 编译 → 安装 → 打包成 RPM → 被系统“正规军”管理的全过程。


二、第一步:打造可用的编译环境#

2.1 为什么默认 GCC 8.5.0 编不动 Linux 6.19.4?#

CentOS 8 的默认 GCC 是 8.5.0,这对 4.x 甚至早期 5.x 内核还算够用,但对 6.19.4 来说:

  • 内核源码中使用了更新的 C 语言特性和编译器指令;
  • 6.x 系列在兼容 GCC 老版本上没有做过多妥协;
  • 实际编译时,你会遇到各种诡异的 warning-as-error、未识别属性、内联优化相关报错。

症状 通常表现为:

  • 在某个子目录(如 kernel/fs/net/)突然报编译错误;
  • 错误信息比较“玄学”,不是简单的语法问题;
  • 换上新一点的 GCC(如 11/12)后,问题立刻消失。

在 CentOS 8 上,官方已经为我们准备好了 Software Collections 里的现代工具链,例如:

  • gcc-toolset-12(包含 GCC 12 系列)

2.2 安装并激活 gcc-toolset-12#

先安装工具集:

Terminal window
sudo dnf install -y gcc-toolset-12 gcc-toolset-12-binutils

光装是不够的,关键是激活环境变量

Terminal window
source /opt/rh/gcc-toolset-12/enable

执行完后,用下面的命令逐一确认:

Terminal window
gcc --version
Terminal window
ld --version
Terminal window
which gcc

确保:

  • 当前 gcc 指向 /opt/rh/gcc-toolset-12/root/usr/bin/gcc
  • 版本是 12.x 而不是 8.5.0。

为什么要用 source 而不是直接调用 /opt 里的 gcc?
因为内核构建过程中会调用很多子工具(gcc, ld, objcopy, ar 等),
source 会统一修改 PATH 等环境变量,保证整个 toolchain 是一致的。
只改一个 gcc,其它工具还是旧版,问题会非常隐蔽。

建议把这行写进你的 shell 会话脚本或每次编译前手动执行:

Terminal window
source /opt/rh/gcc-toolset-12/enable
必看

只在当前 shell 中执行一次 source /opt/rh/gcc-toolset-12/enable 远远不够。 每次新开终端、每次重新登录后,都需要重新执行一次,否则你可能实际上还是在用老的 GCC 8.5.0,在“错的编译器”上浪费大量排错时间。

2.3 补齐必需依赖:bc 和 dwarves(pahole)#

编译 6.x 内核时,两个常被忽略但非常关键的依赖是:

  • bc:命令行计算器,用于内核构建时处理时间常量、HZ 参数等;
  • dwarves(提供 pahole:用于生成 BTF(BPF Type Format)调试信息。

bc 时,常见报错类似:

/bin/sh: bc: command not found
...
Kbuild: failed to generate ... time constants

pahole(或版本太低)时,BTF 相关构建会失败:

FAILED: load BTF: pahole (pahole) is not available

在 CentOS 8 上安装:

Terminal window
sudo dnf install -y bc dwarves

确认:

Terminal window
bc --version
Terminal window
pahole --version

如果你暂时不需要 BTF/BPF 功能,也可在配置中禁用 DEBUG_INFO_BTF,编译会简单很多(后面会详细说)。


三、第二步:获取源码与配置优化(去 RHEL 化)#

3.1 获取 Linux 6.19.4 源码#

建议直接从 官方渠道(如 kernel.org)下载 vanilla 源码包,例如:

不要混用来源

为了避免“同名不同内容”的内核源码导致的编译差异,请只使用同一个官方来源下载的 linux-6.19.4.tar.xz。 不要在不同镜像站、网盘、第三方打包站之间混用“改名后的源码包”,否则会造成配置和补丁状态难以复现。

下面以你已经从官方渠道下载好 linux-6.19.4.tar.xz 为例说明(文件名保持不变即可):

进入源码放置目录:

Terminal window
cd /usr/src

解压源码包:

Terminal window
sudo tar xf /path/to/linux-6.19.4.tar.xz

假设解压后目录名为 linux-6.19.4(如有不同请按实际目录名调整),修改目录所有权:

Terminal window
sudo chown -R $(whoami):$(whoami) linux-6.19.4

进入源码目录:

Terminal window
cd linux-6.19.4

提醒:本篇假设你用的是一个非 root 用户,但拥有 sudo 权限。
真正 make 的时候,建议在普通用户下完成,只在 make install / grub2-mkconfig 等需要写系统目录时使用 sudo。

3.2 在 Makefile 中设置 EXTRAVERSION#

为了让最终编译出来的内核版本名形如:

6.19.4-1.el8.elrepo.x86_64

我们需要在源码根目录的 Makefile 中,将 EXTRAVERSION 明确设置为:

EXTRAVERSION = -1.el8.elrepo.x86_64

你可以使用自己习惯的文本编辑器(如 vimnano 或图形化编辑器)打开顶层 Makefile,找到 EXTRAVERSION 那一行并修改为上面的值,保存后再继续后续配置步骤。

3.3 导入 CentOS 8 当前内核配置#

我们通常不从空白配置开始,而是基于当前系统正在运行的配置进行调整:

Terminal window
cp /boot/config-$(uname -r) .config

然后让内核源码根据新版本新增的选项进行问答/默认填充:

Terminal window
yes "" | make oldconfig

或者使用更友好的 menuconfig / nconfig 进行图形化配置(非必需):

Terminal window
make menuconfig

3.4 关键配置净化:禁用发行版特定证书 SYSTEM_TRUSTED_KEYS#

直接拿 CentOS 官方的 config 文件,有个常见的大坑:

  • 它默认会引用某些 发行版特定的证书文件,例如 certs/rhel.pem
  • 在 Red Hat 构建环境里,这些证书和 key 是存在的;
  • 换成 vanilla 源码 + 自己的构建环境后,这些文件根本不存在;
  • 结果就是在 certs/ 相关规则里报 No rule to make target 'certs/rhel.pem'

解决方案有两种:

  1. 手工编辑 .config,找到 CONFIG_SYSTEM_TRUSTED_KEYS 并清空;
  2. 使用官方提供的 scripts/config 工具安全修改。

推荐第二种:

进入源码目录:

Terminal window
cd /usr/src/linux-6.19.4

禁用发行版信任证书:

Terminal window
scripts/config --disable SYSTEM_TRUSTED_KEYS

禁用证书吊销列表:

Terminal window
scripts/config --disable SYSTEM_REVOCATION_KEYS

然后再跑一次:

Terminal window
yes "" | make oldconfig

scripts/config --disable SYSTEM_TRUSTED_KEYS 的本质作用:

  • .config 中的 CONFIG_SYSTEM_TRUSTED_KEYS 配置为 ""n
  • 告诉内核构建系统:不要再尝试去加载发行版内置的 X.509 证书文件(如 certs/rhel.pem);
  • 这样内核只保留自带的“内核签名/模块签名”基础逻辑,而不依赖 RHEL 特有的证书体系。

如果你后续要启用内核/模块签名,可以走自己的证书体系,但那是另一篇文章的故事了。

常见致命坑

如果忘记禁用 SYSTEM_TRUSTED_KEYS / SYSTEM_REVOCATION_KEYS,你几乎 100% 会在 certs/ 阶段遇到 No rule to make target 'certs/rhel.pem' 之类的报错。 这一步看起来只是“配置小改动”,但其实是 能否顺利编译通过的关键前提

3.5 可选:禁用 DEBUG_INFO_BTF 简化调试信息#

如果你只是想要一个可用的新内核,不依赖 BPF / BTF 调试特性:

Terminal window
scripts/config --disable DEBUG_INFO_BTF

这样可以:

  • 避免对 pahole 版本的苛刻要求;
  • 避免 BTF 构建出错阻断整个编译流程;
  • 减少内核映像中的 BTF 调试信息大小。

当然,如果你明确要玩 eBPF/BTF,建议保留该选项,并确保 pahole 版本够新。


四、第三步:编译过程中的“坑”与填平#

当环境和配置都准备好之后,就可以正式进入 make 阶段。
在这个阶段,最容易让人困惑的是那条非常常见却信息量有限的报错:

make[1]: *** [Makefile:2064: ...] Error 2
make: *** [Makefile:234: ...] Error 2

从表面上看,这类信息几乎不给出任何上下文,不利于定位实际问题所在。

4.1 基本编译流程命令#

典型的编译流程可以拆解为几个步骤:

(可选)清理旧构建产物:

Terminal window
make mrproper

导入当前内核配置(前面已经做过的话可以跳过):

Terminal window
cp /boot/config-$(uname -r) .config
Terminal window
yes "" | make oldconfig

编译内核与模块:

Terminal window
make -j$(nproc)

安装模块:

Terminal window
sudo make modules_install

安装内核:

Terminal window
sudo make install

真正实践中,建议先不要直接 -j$(nproc) 开最大并行编译,而是先用单线程跑一遍或至少在关键阶段用单线程,方便看清报错。

4.2 如何利用单线程 + tee 捕获真实错误#

开启并行编译时,多个编译任务的输出会交织在一起,容易导致“真正触发错误的那行信息”被大量日志覆盖,最后只剩下:

make[1]: *** [Makefile:2064: vmlinux] Error 2

此时,很难直接看出究竟是哪个子模块首先出现了错误。

一个非常实用的技巧是:

Terminal window
make -j1 all 2>&1 | tee build.log

或者分阶段:

Terminal window
make -j1 bzImage 2>&1 | tee build-bzImage.log
Terminal window
make -j1 modules 2>&1 | tee build-modules.log

这样:

  • 单线程编译保证错误日志是线性的;
  • tee 同时输出到终端和日志文件,方便事后用 grep 搜索。

例如:

Terminal window
grep -i "error" build.log | tail -n 20

可以快速定位:

  • 是否因为 bc 缺失导致时间常量生成失败;
  • 是否因为 pahole / BTF 出问题;
  • 是否确实是某个子模块代码没编过。

4.3 识别并解决 No rule to make target 'certs/rhel.pem' 错误#

如果你忘了禁用 SYSTEM_TRUSTED_KEYS,编译到 certs 阶段就会出现:

make[1]: *** No rule to make target 'certs/rhel.pem', needed by 'certs/x509_certificate_list'.
make[1]: *** 目标 'certs/x509_certificate_list' 的 recipe 失败
make: *** [Makefile:2064: certs] Error 2

这是典型的 RHEL 定制配置带来的副作用

解决方式前面已经提过,这里总结一下操作顺序:

进入源码目录:

Terminal window
cd /usr/src/linux-6.19.4

禁用信任证书和吊销列表:

Terminal window
scripts/config --disable SYSTEM_TRUSTED_KEYS
Terminal window
scripts/config --disable SYSTEM_REVOCATION_KEYS

让配置重新适配:

Terminal window
yes "" | make oldconfig

再重新运行 make 即可。

4.4 DEBUG_INFO_BTF 与 pahole 的爱恨情仇#

如果你使用的是版本相对较旧的 dwarves,在开启 CONFIG_DEBUG_INFO_BTF=y 时,可能遇到类似:

FAILED: load BTF: Invalid argument
Failed to generate BTF for ...
make[2]: *** [Makefile:123: vmlinux] Error 1
make[1]: *** [Makefile:2064: vmlinux] Error 2

这里可以有两个方向:

  1. 升级 dwarves/pahole 到内核文档推荐的版本;

  2. 临时关闭 BTF 支持:

    Terminal window
    scripts/config --disable DEBUG_INFO_BTF
    Terminal window
    yes "" | make oldconfig

如果你在当前阶段的目标只是“先让 6.19.4 内核运行稳定”,可以优先选择第二种方式,将 BTF 相关特性留到后续有余力时再单独处理。

简化首次实践路径

在第一次进行内核编译、且对 eBPF/BTF 没有明确需求的情况下,直接关闭 DEBUG_INFO_BTF 能显著简化整个编译链路。 等你对整体流程更加熟悉之后,再专门为 BPF/BTF 配置和打通调试信息,会更高效、也更有针对性。


五、第四步:让手工内核“正规化”——从 make install 到 RPM 包#

到目前为止,如果你执行了:

Terminal window
sudo make modules_install
Terminal window
sudo make install

会发生什么?

  • /lib/modules/6.19.4-.../:模块已经安装好了;
  • /boot/vmlinuz-6.19.4-.../boot/initramfs-6.19.4-...:内核与 initramfs 已经就位;
  • grub2-mkconfig 也大概率自动帮你更新了启动项。

但:

Terminal window
rpm -qa | grep kernel

你会发现:

  • 新编译的内核 完全不在 RPM 数据库中
  • 也就是说:
    • rpm -qi 看不到它的元信息;
    • dnf remove 无法清理它;
    • 你日后想统一运维、审计就会很难受。

因此,我们需要把当前散落在 /boot/lib/modules 中的内核和模块,通过规范的方式打包成一个 RPM

两种打包方式(建议先用脚本跑通,再学习手工流程)
  • 方式 A:完整手工打包 —— 按照本章 5.x 各小节,逐步编写 .spec 并执行 rpmbuild
  • 方式 B:脚本一键打包 —— 使用本站提供的
    kernel-packer.sh:内核 RPM 一键打包脚本(新标签页打开)
    由脚本自动完成源码解包、EXTRAVERSION 设置、配置“净化”和 RPM 打包等重复性工作。
    如果你对 RPM 打包还不熟悉,建议先通过脚本完整跑通一遍流程,确认成功后再回到手工章节,理解每一步的细节和原理。
关于仅通过 make install 安装的内核

仅执行 make install 将内核和模块写入 /boot/lib/modules,在小规模、短期测试环境中一般可以接受,但在生产环境会缺少清晰的版本记录、审计能力和统一卸载机制。 只要存在长期维护和合规性要求,就应当让内核纳入 RPM 体系管理,而不是依赖手工删除文件。

5.1 RPM 打包的核心:.spec 文件#

RPM 打包的核心是一个 .spec 文件,它定义了:

  • 包的元信息NameVersionReleaseSummaryLicense 等;
  • 构建过程%prep%build%install%files
  • 最终打包进去的文件列表

一般的“从源码打包”是:

  1. 下载源码到 ~/rpmbuild/SOURCES
  2. ~/rpmbuild/SPECS 下写 .spec
  3. 通过 rpmbuild -ba xxx.spec 完成编译和打包。

这次我们已经在源码树里完成了编译,所以会采用一个稍微“反直觉”的做法:

.spec 把已经存在于 /boot/lib/modules 下的文件“伪打包”进 RPM。

也就是说:

  • %build 阶段可以什么都不做(或者仅做版本检查);
  • %install 阶段不真的“安装”,而是把已经存在的文件映射到 RPM 的文件列表中;
  • %files 中声明所有应该被这个内核包管理的路径。

5.2 准备 rpmbuild 目录结构#

首先安装基础工具:

Terminal window
sudo dnf install -y rpm-build rpmdevtools

为当前用户初始化构建树:

Terminal window
rpmdev-setuptree

会在 $HOME 下创建 rpmbuild 目录,包括:

  • SPECS/:放 .spec 文件;
  • SOURCES/:放源码或其他资源;
  • BUILD/RPMS/SRPMS/:构建和输出目录。

5.3 从 /boot 中“识别”当前内核版本(避免误判)#

你可能有多个 6.19.x 版本的内核、甚至有 ELRepo 的 kernel-ml 同时存在;
我们需要确保准确拿到这次自己编译的那个内核版本字符串,比如:

  • /boot/vmlinuz-6.19.4-custom
  • /lib/modules/6.19.4-custom/

常用做法是:

  1. 先列出 /boot/vmlinuz-*
  2. 结合 uname -rls -t 或命名规则,确定你要打包的那一个;
  3. 通过正则提取出版本号。

一个思路示例(伪代码性质命令):

列出所有内核镜像并排序:

Terminal window
ls -1 /boot/vmlinuz-* | sort

假设你给自己编译的内核命名为 6.19.4-ofoca6.19.4-ml,可以显式指定:

Terminal window
KVER="6.19.4-ofoca"

或者从已经安装的模块目录推断:

Terminal window
ls -1 /lib/modules | grep 6.19.4

假设得到 6.19.4-ofoca,可以这样取第一个匹配:

Terminal window
KVER=$(ls -1 /lib/modules | grep 6.19.4 | head -n1)

为什么这一点很重要?

  • 如果你写死 Version: 6.19.4,但实际上内核后缀还有 -custom-ofoca
    你的 RPM 安装后,管理的路径和真实文件就对不上号,卸载/升级时会非常混乱。

在脚本化场景下,可以用 shell 的 sed/grep[[ ]] 正则提取;
在本文中,我们只需要明确这个思路:Spec 中的 Version / Release 必须和 /boot & /lib/modules 中的实际名字对应起来。

5.4 编写简化版内核 .spec 文件(原理级讲解)#

以下示例是“讲原理”的结构化片段,不要直接复制到生产环境,而是当作你自己写 .spec 时的参考。

设定命名风格类似 ELRepo:

  • 包名:kernel-ml-6_19_4 或简单 kernel-ml
  • Version6.19.4
  • Release1.ofoca

一个简化的 .spec 结构大致如下:

Name: kernel-ml
Version: 6.19.4
Release: 1.ofoca
Summary: Linux kernel 6.19.4 built on CentOS 8
License: GPLv2
Group: System Environment/Kernel
URL: https://blog.ofoca.net
Vendor: OfoCa Space
BuildArch: x86_64
%description
自编译的 Linux 6.19.4 内核,适用于 CentOS 8,包含 /boot 和 /lib/modules 中已构建的文件。
%prep
# 已经在源码树中构建完成,这里可以为空或仅打印信息
%build
# 理论上可以不再 make,这里不做实际编译,只做版本检查或留空
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/boot
mkdir -p %{buildroot}/lib/modules/%{version}-ofoca
# 这里的关键思想:
# 不再重新生成 vmlinuz 和 modules,而是把系统中已有的文件复制进 buildroot
# 伪代码示意:
# cp /boot/vmlinuz-6.19.4-ofoca %{buildroot}/boot/
# cp -a /lib/modules/6.19.4-ofoca/* %{buildroot}/lib/modules/6.19.4-ofoca/
%files
/boot/vmlinuz-6.19.4-ofoca
/lib/modules/6.19.4-ofoca
%changelog
* Thu Feb 27 2026 OfoCa Space
- Initial build of kernel-ml 6.19.4 for CentOS 8

关键点解释:

  • %install 阶段定义了如何把文件放入一个虚拟的“安装根目录” buildroot
  • %files 告诉 rpmbuild:这些路径是本包要“管理”的;
  • 当你安装这个 RPM 时,RPM 会认为:
    • /boot/vmlinuz-6.19.4-ofoca 是它创建的;
    • /lib/modules/6.19.4-ofoca/ 是它管理的;
  • 未来 rpm -ql kernel-mldnf remove kernel-ml 就能正常工作。

在实际实现时,你会:

  1. %install 中写一组 cpinstall 命令,把当前系统里的 vmlinuzSystem.mapinitramfs 等复制进 %{buildroot}
  2. %files 写得更完整一些,列出所有关键文件。

5.5 用 rpmbuild 打包并注册到 RPM 数据库#

.spec 放到 ~/rpmbuild/SPECS/kernel-ml.spec 后,执行:

Terminal window
cd ~/rpmbuild
Terminal window
rpmbuild -bb SPECS/kernel-ml.spec

成功的话,会在 ~/rpmbuild/RPMS/x86_64/ 下得到类似:

  • kernel-ml-6.19.4-1.ofoca.x86_64.rpm

安装时,建议使用:

Terminal window
sudo rpm -ivh --replacefiles ~/rpmbuild/RPMS/x86_64/kernel-ml-6.19.4-1.ofoca.x86_64.rpm

这里 --replacefiles 的意义是:

  • 因为在 make install 阶段,你很可能已经往 /boot/lib/modules 写入了同名文件;
  • 正常安装 RPM 时,RPM 会认为这些目标路径已存在、可能属于其它包,从而报冲突;
  • --replacefiles 告诉 rpm:允许用本包的文件覆盖已有文件,并把这些路径“收编”到本包名下

安装完成后,你就可以:

Terminal window
rpm -qi kernel-ml
Terminal window
rpm -ql kernel-ml

你应该能够看到:

  • 内核版本信息;
  • 所有文件路径;
  • 将来 dnf remove kernel-ml 就能卸载这套内核(文件和 RPM 记录一起清理)。

六、第五步:验证、切换和重启#

6.1 确认 GRUB 启动项#

一般情况下,make install 会帮你调用 grub2-mkconfig,在 CentOS 8 上常见命令是:

Terminal window
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

UEFI 环境可能路径会略有不同(例如 /boot/efi/EFI/centos/grub.cfg),这一点请按实际情况调整。

可以检查一下 GRUB 菜单里是否出现了 6.19.4-ofoca 对应的条目。

6.2 重启并验证内核#

重启系统,进入新内核后执行:

Terminal window
uname -r

确认输出类似:

6.19.4-ofoca

然后验证 RPM 记录:

Terminal window
rpm -qa | grep kernel
Terminal window
rpm -qi kernel-ml
Terminal window
rpm -ql kernel-ml | head

如果你能:

  • 看到 kernel-ml-6.19.4-1.ofoca.x86_64
  • rpm -ql 列出 /boot/vmlinuz-6.19.4-ofoca/lib/modules/6.19.4-ofoca/
  • 未来可以用 dnf remove kernel-ml 卸载;

这表明你通过手工方式编译的内核,已经被纳入 RPM 体系进行统一管理。


七、魔方云场景:将 QEMU 升级到 10.2.0 的一键实践#

前面的内容更多是“通用场景”的手工编译 + RPM 打包,这一节结合一个非常具体、也很有代表性的场景:
在魔方云环境中,为了更好地支持虚拟化/新硬件,需要在 CentOS 8 + 自编译内核的前提下,升级 QEMU 到 10.2.0。

为了避免各种“玄学兼容问题”,这里有三个强约束

  • 必须使用官方 6.19.4 源码并按前文步骤自行编译内核(包括设置 EXTRAVERSION = -1.el8.elrepo.x86_64);
  • 必须保证当前内核版本是固定的uname -r 输出为
    6.19.4-1.el8.elrepo.x86_64(这个名字需要你在源码 Makefile 中手工设置好 EXTRAVERSION 并完成编译/安装);
  • 必须使用指定的 QEMU 安装程序zjmf_ins_qemu10.2.0 安装程序(新标签页下载)
    不要随便从别的渠道下载 QEMU 或更换内核包,“后果自负”不是一句玩笑话,而是很多生产环境踩坑后的血泪总结。
版本组合必须一一对应

魔方云这一节假定的是一个 精确的版本组合:内核 6.19.4-1.el8.elrepo.x86_64 + 指定的变更包 + 指定的 QEMU 安装程序。 任意一个环节擅自更换来源(比如改成别的内核包或 QEMU 二进制),都可能导致 KVM/QEMU 行为异常,且问题难以排查和复现。

7.1 内核环境准备:基于官方源码的一键打包脚本#

如果你已经按上文“源码到 RPM”流程熟练掌握配置与打包,可以完全按照自己的习惯手动完成各个步骤。
但为了照顾“不想一行行写 spec、也不想处理各种 RPM 细节”的读者,我们额外准备了一个一键打包脚本。

这个脚本假定你已经从官方渠道下载好 linux-6.19.4.tar.xz,并且希望最终得到版本号为 6.19.4-1.el8.elrepo.x86_64 的内核 RPM 包。
脚本内部会自动完成源码解包、EXTRAVERSION 设置、配置净化和打包等重复性步骤。

如果你对 RPM 打包不熟悉,或者只是想快速落地,推荐使用本站提供的一键脚本:
kernel-packer.sh 一键打包脚本(新标签页打开),使用方式:

进入脚本所在目录:

Terminal window
cd /downloads/linux/sh

赋予执行权限:

Terminal window
chmod +x kernel-packer.sh

以 root 身份执行脚本:

Terminal window
sudo ./kernel-packer.sh

这个脚本会帮助你:

  • 基于官方 linux-6.19.4.tar.xz 完成源码解包与必要的配置修正;
  • 自动调用前文所述的 scripts/config 等手段进行必要的“净化”;
  • 在顶层 Makefile 中设置合适的 EXTRAVERSION(如 -1.el8.elrepo.x86_64);
  • 生成合适的 .spec 文件并通过 rpmbuild 打出符合规范的内核 RPM;
  • 安装后在 uname -r 中得到我们期望的:
Terminal window
uname -r
6.19.4-1.el8.elrepo.x86_64

这一步完成后,请务必重启到新内核上,再次确认 uname -r 输出完全一致。
只有在这个前提下,再往下做 QEMU 10.2.0 的升级。

7.2 魔方云中运行 QEMU 10.2.0 安装程序#

在内核已经就绪、并且 uname -r 确认无误后,可以开始 QEMU 的升级。

QEMU 安装程序下载链接:zjmf_ins_qemu10.2.0 安装程序(新标签页下载)

给程序加上可执行权限并运行:

进入下载目录:

Terminal window
cd /downloads/linux

赋予执行权限:

Terminal window
chmod +x zjmf_ins_qemu10.2.0

执行安装程序:

Terminal window
./zjmf_ins_qemu10.2.0

建议在运行前,再做一次“安全确认”:

Terminal window
uname -r

期望输出:

6.19.4-1.el8.elrepo.x86_64

如果版本不匹配,请不要继续安装 QEMU 10.2.0,而是回到上一小节,通过指定的内核包和 kernel-packer.sh 脚本完成内核统一。
这是为了保证:

  • 魔方云环境中的 KVM/QEMU 与底层内核 ABI 一致;
  • 后续调试和排错时,有一套“可复现”的版本组合,而不是“每台机器都长得不一样”。

经过以上步骤,你就拥有了:

  • 一套用 RPM 管理的、自定义 Linux 6.19.4 内核(6.19.4-1.el8.elrepo.x86_64);
  • 配套的 QEMU 10.2.0 环境,专门针对魔方云场景做过适配;
  • 并且整个流程都可以被脚本化 —— 从内核到虚拟化堆栈,都能做到“有章可循、可重复部署”。

八、结语:从手工编译到自动化脚本#

到这里,你已经完成了一次完整的“源码到 RPM”的旅程:

  1. 认识到 CentOS 8 默认 GCC 8.5.0 无法可靠编译 Linux 6.19.4,学会用 gcc-toolset-12 升级工具链;
  2. 知道了 bcdwarves/pahole 在现代内核构建中的重要性;
  3. 学会了用 scripts/config --disable SYSTEM_TRUSTED_KEYSDEBUG_INFO_BTF 调整配置,绕开 RHEL 特定证书和 BTF 陷阱;
  4. 掌握了用 单线程 + tee 日志 排查被并行编译掩盖的 Error 2
  5. 更重要的是,理解了 .spec 文件和 rpmbuild 的基本原理,知道如何将已有的 /boot/lib/modules 文件“伪装打包”成一个真正被 RPM 管理的内核包。

当你真正理解了这些步骤之后,把整个流程封装成一个自动化脚本(比如 kernel-packer.sh)就水到渠成了

  • 自动检测当前运行的内核版本和新编内核的版本;
  • 自动清理配置、修补 SYSTEM_TRUSTED_KEYS 等选项;
  • 自动生成 .spec 文件;
  • 自动调用 rpmbuild 生成类似 ELRepo 风格的 kernel-ml 包。

这样,未来当你需要升级到 6.20、6.21 甚至更新版本内核时,只需要:

  1. 换一个源码 tarball;
  2. 调整版本号;
  3. 让脚本跑一遍——

你已经不再是只会“复制脚本”的使用者,而是掌握了每一行命令背后逻辑的内核“工匠”。


本文技术方案由 OfoCa Space 提供支持(https://blog.ofoca.net)。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
在 CentOS 8 上手工编译并打包 Linux 6.19.4 内核:从源码到 RPM 的全流程指南
https://firefly.cuteleaf.cn/posts/centos8-kernel-6194-rpm-guide/
作者
Airio_
发布于
2026-02-27
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Airio_
Hello, I'm Airio_.
公告
欢迎来到OfoCa Space。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
7
分类
2
标签
22
总字数
25,338
运行时长
0
最后活动
0 天前

目录