在 CentOS 8 上手工编译并打包 Linux 6.19.4 内核:从源码到 RPM 的全流程指南
授人以渔版内核编译实践笔记:这篇文章的目标不是“复制一段脚本就能跑通”,而是带你从 0 到 1 理解——为什么 CentOS 8 默认编译不了 Linux 6.19.4、每一个
make步骤在做什么,以及如何把单纯的源码编译结果,变成可以通过rpm -qi和dnf remove统一管理的内核包。
本文的场景背景来源于一台典型的 CentOS 8 服务器:
- 默认内核:4.18.x(版本较老,但稳定性经过长期验证)
- 目标:编译并部署 Linux 6.19.4 新内核(更好的硬件支持、新特性、更新的文件系统/调度器等)
- 要求:最终必须能像 ELRepo 的
kernel-ml那样,用rpm -qa查到,用dnf remove卸载,而不是孤零零地躺在/boot和/lib/modules里没人管。
在实践过程中,会遇到一些较为典型的问题:
- GCC 太老、
bc和pahole缺失; SYSTEM_TRUSTED_KEYS依赖certs/rhel.pem报错;- 并行编译把真正错误淹没在
Makefile:2064: Error 2之下; - 纯
make install编译出来的内核,rpm -qa完全看不到身影。
这篇文章会按照以下结构展开:
- 引言:为什么要在 CentOS 8 上编译新内核?
- 第一步:打造编译环境(GCC 12、依赖、工具链)
- 第二步:获取源码与配置优化(下载、导入 config、净化 RHEL 特定配置)
- 第三步:编译过程中的“坑”与填平(
bc、pahole、rhel.pem、Error 2) - 第四步:让手工内核“正规化”(核心章节:Spec 文件 + rpmbuild 打包流程)
- 第五步:验证与重启
- 结语:手工编译的意义与自动化工具展望(含脚本彩蛋)
一、引言:为什么要在 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
先安装工具集:
sudo dnf install -y gcc-toolset-12 gcc-toolset-12-binutils光装是不够的,关键是激活环境变量:
source /opt/rh/gcc-toolset-12/enable执行完后,用下面的命令逐一确认:
gcc --versionld --versionwhich 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 会话脚本或每次编译前手动执行:
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 上安装:
sudo dnf install -y bc dwarves确认:
bc --versionpahole --version如果你暂时不需要 BTF/BPF 功能,也可在配置中禁用 DEBUG_INFO_BTF,编译会简单很多(后面会详细说)。
三、第二步:获取源码与配置优化(去 RHEL 化)
3.1 获取 Linux 6.19.4 源码
建议直接从 官方渠道(如 kernel.org)下载 vanilla 源码包,例如:
- 官方源码包:
linux-6.19.4.tar.xz(可在 kernel.org 官方下载页 获取)
为了避免“同名不同内容”的内核源码导致的编译差异,请只使用同一个官方来源下载的 linux-6.19.4.tar.xz。
不要在不同镜像站、网盘、第三方打包站之间混用“改名后的源码包”,否则会造成配置和补丁状态难以复现。
下面以你已经从官方渠道下载好 linux-6.19.4.tar.xz 为例说明(文件名保持不变即可):
进入源码放置目录:
cd /usr/src解压源码包:
sudo tar xf /path/to/linux-6.19.4.tar.xz假设解压后目录名为 linux-6.19.4(如有不同请按实际目录名调整),修改目录所有权:
sudo chown -R $(whoami):$(whoami) linux-6.19.4进入源码目录:
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你可以使用自己习惯的文本编辑器(如 vim、nano 或图形化编辑器)打开顶层 Makefile,找到 EXTRAVERSION 那一行并修改为上面的值,保存后再继续后续配置步骤。
3.3 导入 CentOS 8 当前内核配置
我们通常不从空白配置开始,而是基于当前系统正在运行的配置进行调整:
cp /boot/config-$(uname -r) .config然后让内核源码根据新版本新增的选项进行问答/默认填充:
yes "" | make oldconfig或者使用更友好的 menuconfig / nconfig 进行图形化配置(非必需):
make menuconfig3.4 关键配置净化:禁用发行版特定证书 SYSTEM_TRUSTED_KEYS
直接拿 CentOS 官方的 config 文件,有个常见的大坑:
- 它默认会引用某些 发行版特定的证书文件,例如
certs/rhel.pem; - 在 Red Hat 构建环境里,这些证书和 key 是存在的;
- 换成 vanilla 源码 + 自己的构建环境后,这些文件根本不存在;
- 结果就是在
certs/相关规则里报No rule to make target 'certs/rhel.pem'。
解决方案有两种:
- 手工编辑
.config,找到CONFIG_SYSTEM_TRUSTED_KEYS并清空; - 使用官方提供的
scripts/config工具安全修改。
推荐第二种:
进入源码目录:
cd /usr/src/linux-6.19.4禁用发行版信任证书:
scripts/config --disable SYSTEM_TRUSTED_KEYS禁用证书吊销列表:
scripts/config --disable SYSTEM_REVOCATION_KEYS然后再跑一次:
yes "" | make oldconfigscripts/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 调试特性:
scripts/config --disable DEBUG_INFO_BTF这样可以:
- 避免对
pahole版本的苛刻要求; - 避免 BTF 构建出错阻断整个编译流程;
- 减少内核映像中的 BTF 调试信息大小。
当然,如果你明确要玩 eBPF/BTF,建议保留该选项,并确保 pahole 版本够新。
四、第三步:编译过程中的“坑”与填平
当环境和配置都准备好之后,就可以正式进入 make 阶段。
在这个阶段,最容易让人困惑的是那条非常常见却信息量有限的报错:
make[1]: *** [Makefile:2064: ...] Error 2make: *** [Makefile:234: ...] Error 2从表面上看,这类信息几乎不给出任何上下文,不利于定位实际问题所在。
4.1 基本编译流程命令
典型的编译流程可以拆解为几个步骤:
(可选)清理旧构建产物:
make mrproper导入当前内核配置(前面已经做过的话可以跳过):
cp /boot/config-$(uname -r) .configyes "" | make oldconfig编译内核与模块:
make -j$(nproc)安装模块:
sudo make modules_install安装内核:
sudo make install真正实践中,建议先不要直接
-j$(nproc)开最大并行编译,而是先用单线程跑一遍或至少在关键阶段用单线程,方便看清报错。
4.2 如何利用单线程 + tee 捕获真实错误
开启并行编译时,多个编译任务的输出会交织在一起,容易导致“真正触发错误的那行信息”被大量日志覆盖,最后只剩下:
make[1]: *** [Makefile:2064: vmlinux] Error 2此时,很难直接看出究竟是哪个子模块首先出现了错误。
一个非常实用的技巧是:
make -j1 all 2>&1 | tee build.log或者分阶段:
make -j1 bzImage 2>&1 | tee build-bzImage.logmake -j1 modules 2>&1 | tee build-modules.log这样:
- 单线程编译保证错误日志是线性的;
tee同时输出到终端和日志文件,方便事后用grep搜索。
例如:
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 定制配置带来的副作用。
解决方式前面已经提过,这里总结一下操作顺序:
进入源码目录:
cd /usr/src/linux-6.19.4禁用信任证书和吊销列表:
scripts/config --disable SYSTEM_TRUSTED_KEYSscripts/config --disable SYSTEM_REVOCATION_KEYS让配置重新适配:
yes "" | make oldconfig再重新运行 make 即可。
4.4 DEBUG_INFO_BTF 与 pahole 的爱恨情仇
如果你使用的是版本相对较旧的 dwarves,在开启 CONFIG_DEBUG_INFO_BTF=y 时,可能遇到类似:
FAILED: load BTF: Invalid argumentFailed to generate BTF for ...make[2]: *** [Makefile:123: vmlinux] Error 1make[1]: *** [Makefile:2064: vmlinux] Error 2这里可以有两个方向:
-
升级 dwarves/pahole 到内核文档推荐的版本;
-
临时关闭 BTF 支持:
Terminal window scripts/config --disable DEBUG_INFO_BTFTerminal window yes "" | make oldconfig
如果你在当前阶段的目标只是“先让 6.19.4 内核运行稳定”,可以优先选择第二种方式,将 BTF 相关特性留到后续有余力时再单独处理。
在第一次进行内核编译、且对 eBPF/BTF 没有明确需求的情况下,直接关闭 DEBUG_INFO_BTF 能显著简化整个编译链路。
等你对整体流程更加熟悉之后,再专门为 BPF/BTF 配置和打通调试信息,会更高效、也更有针对性。
五、第四步:让手工内核“正规化”——从 make install 到 RPM 包
到目前为止,如果你执行了:
sudo make modules_installsudo make install会发生什么?
/lib/modules/6.19.4-.../:模块已经安装好了;/boot/vmlinuz-6.19.4-...、/boot/initramfs-6.19.4-...:内核与 initramfs 已经就位;grub2-mkconfig也大概率自动帮你更新了启动项。
但:
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 文件,它定义了:
- 包的元信息:
Name、Version、Release、Summary、License等; - 构建过程:
%prep、%build、%install、%files; - 最终打包进去的文件列表。
一般的“从源码打包”是:
- 下载源码到
~/rpmbuild/SOURCES; - 在
~/rpmbuild/SPECS下写.spec; - 通过
rpmbuild -ba xxx.spec完成编译和打包。
这次我们已经在源码树里完成了编译,所以会采用一个稍微“反直觉”的做法:
用
.spec把已经存在于/boot和/lib/modules下的文件“伪打包”进 RPM。
也就是说:
%build阶段可以什么都不做(或者仅做版本检查);%install阶段不真的“安装”,而是把已经存在的文件映射到 RPM 的文件列表中;%files中声明所有应该被这个内核包管理的路径。
5.2 准备 rpmbuild 目录结构
首先安装基础工具:
sudo dnf install -y rpm-build rpmdevtools为当前用户初始化构建树:
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/
常用做法是:
- 先列出
/boot/vmlinuz-*; - 结合
uname -r、ls -t或命名规则,确定你要打包的那一个; - 通过正则提取出版本号。
一个思路示例(伪代码性质命令):
列出所有内核镜像并排序:
ls -1 /boot/vmlinuz-* | sort假设你给自己编译的内核命名为 6.19.4-ofoca 或 6.19.4-ml,可以显式指定:
KVER="6.19.4-ofoca"或者从已经安装的模块目录推断:
ls -1 /lib/modules | grep 6.19.4假设得到 6.19.4-ofoca,可以这样取第一个匹配:
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; Version:6.19.4;Release:1.ofoca。
一个简化的 .spec 结构大致如下:
Name: kernel-mlVersion: 6.19.4Release: 1.ofocaSummary: Linux kernel 6.19.4 built on CentOS 8License: GPLv2Group: System Environment/KernelURL: https://blog.ofoca.netVendor: OfoCa Space
BuildArch: x86_64
%description自编译的 Linux 6.19.4 内核,适用于 CentOS 8,包含 /boot 和 /lib/modules 中已构建的文件。
%prep# 已经在源码树中构建完成,这里可以为空或仅打印信息
%build# 理论上可以不再 make,这里不做实际编译,只做版本检查或留空
%installrm -rf %{buildroot}mkdir -p %{buildroot}/bootmkdir -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-ml和dnf remove kernel-ml就能正常工作。
在实际实现时,你会:
- 在
%install中写一组cp或install命令,把当前系统里的vmlinuz、System.map、initramfs等复制进%{buildroot}; - 把
%files写得更完整一些,列出所有关键文件。
5.5 用 rpmbuild 打包并注册到 RPM 数据库
把 .spec 放到 ~/rpmbuild/SPECS/kernel-ml.spec 后,执行:
cd ~/rpmbuildrpmbuild -bb SPECS/kernel-ml.spec成功的话,会在 ~/rpmbuild/RPMS/x86_64/ 下得到类似:
kernel-ml-6.19.4-1.ofoca.x86_64.rpm
安装时,建议使用:
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:允许用本包的文件覆盖已有文件,并把这些路径“收编”到本包名下。
安装完成后,你就可以:
rpm -qi kernel-mlrpm -ql kernel-ml你应该能够看到:
- 内核版本信息;
- 所有文件路径;
- 将来
dnf remove kernel-ml就能卸载这套内核(文件和 RPM 记录一起清理)。
六、第五步:验证、切换和重启
6.1 确认 GRUB 启动项
一般情况下,make install 会帮你调用 grub2-mkconfig,在 CentOS 8 上常见命令是:
sudo grub2-mkconfig -o /boot/grub2/grub.cfgUEFI 环境可能路径会略有不同(例如 /boot/efi/EFI/centos/grub.cfg),这一点请按实际情况调整。
可以检查一下 GRUB 菜单里是否出现了 6.19.4-ofoca 对应的条目。
6.2 重启并验证内核
重启系统,进入新内核后执行:
uname -r确认输出类似:
6.19.4-ofoca然后验证 RPM 记录:
rpm -qa | grep kernelrpm -qi kernel-mlrpm -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 一键打包脚本(新标签页打开),使用方式:
进入脚本所在目录:
cd /downloads/linux/sh赋予执行权限:
chmod +x kernel-packer.sh以 root 身份执行脚本:
sudo ./kernel-packer.sh这个脚本会帮助你:
- 基于官方
linux-6.19.4.tar.xz完成源码解包与必要的配置修正; - 自动调用前文所述的
scripts/config等手段进行必要的“净化”; - 在顶层
Makefile中设置合适的EXTRAVERSION(如-1.el8.elrepo.x86_64); - 生成合适的
.spec文件并通过rpmbuild打出符合规范的内核 RPM; - 安装后在
uname -r中得到我们期望的:
uname -r6.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 安装程序(新标签页下载)
给程序加上可执行权限并运行:
进入下载目录:
cd /downloads/linux赋予执行权限:
chmod +x zjmf_ins_qemu10.2.0执行安装程序:
./zjmf_ins_qemu10.2.0建议在运行前,再做一次“安全确认”:
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”的旅程:
- 认识到 CentOS 8 默认 GCC 8.5.0 无法可靠编译 Linux 6.19.4,学会用
gcc-toolset-12升级工具链; - 知道了
bc和dwarves/pahole在现代内核构建中的重要性; - 学会了用
scripts/config --disable SYSTEM_TRUSTED_KEYS和DEBUG_INFO_BTF调整配置,绕开 RHEL 特定证书和 BTF 陷阱; - 掌握了用 单线程 +
tee日志 排查被并行编译掩盖的Error 2; - 更重要的是,理解了 .spec 文件和 rpmbuild 的基本原理,知道如何将已有的
/boot和/lib/modules文件“伪装打包”成一个真正被 RPM 管理的内核包。
当你真正理解了这些步骤之后,把整个流程封装成一个自动化脚本(比如 kernel-packer.sh)就水到渠成了:
- 自动检测当前运行的内核版本和新编内核的版本;
- 自动清理配置、修补
SYSTEM_TRUSTED_KEYS等选项; - 自动生成
.spec文件; - 自动调用
rpmbuild生成类似 ELRepo 风格的kernel-ml包。
这样,未来当你需要升级到 6.20、6.21 甚至更新版本内核时,只需要:
- 换一个源码 tarball;
- 调整版本号;
- 让脚本跑一遍——
你已经不再是只会“复制脚本”的使用者,而是掌握了每一行命令背后逻辑的内核“工匠”。
本文技术方案由 OfoCa Space 提供支持(https://blog.ofoca.net)。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!