惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
N
Netflix TechBlog - Medium
GbyAI
GbyAI
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
T
Tailwind CSS Blog
IT之家
IT之家
博客园 - Franky
雷峰网
雷峰网
博客园 - 聂微东
腾讯CDC
M
MIT News - Artificial intelligence
B
Blog RSS Feed
博客园_首页
罗磊的独立博客
S
SegmentFault 最新的问题
I
InfoQ
博客园 - 叶小钗
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
D
Docker
宝玉的分享
宝玉的分享
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

竹林里有冰的博客

Nuxt SSG 博客的尾斜杠到底怎么加? | 竹林里有冰的博客 小米 Xiaomi Book Pro 14 (Ultra X7) Linux 兼容性实测 | 竹林里有冰的博客 国内(大陆)版小米 FCM 熄屏断连:Rootless 环境下的尝试与可能的解决方案 | 竹林里有冰的博客 我没法访问 dl.google.com —— 记一次 TUN 下的网络 debug | 竹林里有冰的博客 Vercel 的缓存控制,你注意过吗? | 竹林里有冰的博客 小记 —— Caddy 在 Layer 4 上的流量代理实践 | 竹林里有冰的博客 你的域名后缀拖慢你的网站速度了嘛?——再谈 DNS 冷启动 | 竹林里有冰的博客 DNS 冷启动:小型站点的“西西弗斯之石” | 竹林里有冰的博客 HTTP/2 Server Push 已事实性“死亡”,我很怀念它 | 竹林里有冰的博客 Nuxt Content v3 中数组字段的筛选困境与性能优化 | 竹林里有冰的博客 后 OCSP 时代,浏览器如何应对证书吊销新挑战 | 竹林里有冰的博客 初试 Github Action Self-hosted Runner,想说爱你不容易 | 竹林里有冰的博客 DNS 解析延迟毁了我的图床优化 | 竹林里有冰的博客 Vue Markdown 渲染优化实战(下):告别 DOM 操作,拥抱 AST 与函数式渲染 | 竹林里有冰的博客 Vue Markdown 渲染优化实战(上):从暴力刷新、分块更新到 Morphdom 的华丽变身 | 竹林里有冰的博客 node-sass 迁移至 dart-sass 踩坑实录 | 竹林里有冰的博客 前端中的量子力学——一打开 F12 就消失的 Bug | 竹林里有冰的博客 2025 年,如何为 web 页面上展示的视频选择合适的压缩算法? | 竹林里有冰的博客 el-image 和 el-table 怎么就打架了?Stacking Context 是什么? | 竹林里有冰的博客 2025年,前端如何使用 JS 将文本复制到剪切板? | 竹林里有冰的博客 ssh 拯救世界——通过 ssh 隧道在内网服务器执行 APT 更新 | 竹林里有冰的博客 Cudy TR3000 吃鹅(daed)记 | 竹林里有冰的博客 使用 Cloudflare Workers 监控 Fedora Copr 构建状态 | 竹林里有冰的博客 基于 Cloudflare Workers 实现的在线服务状态检测告警系统 | 竹林里有冰的博客 构建部署在 Cloudflare Workers 上的 TG Bot | 竹林里有冰的博客 2024年,Firefox 是唯一还在坚持执行在线的 SSL 证书吊销状态检查的主流浏览器 | 竹林里有冰的博客 小爱课程表适配不完全指北——以 ZJUT 本科正方教务系统为例 | 竹林里有冰的博客 将博客从 waline v2 更新到 waline v3 | 竹林里有冰的博客 给家里云装上 Fedora 41 KDE 后,我是如何配置的 | 竹林里有冰的博客 为 Hexo 添加 follow 认证 | 竹林里有冰的博客
以 Archlinux 中 makepkg 的方式打开 rpmbuild | 竹林里有冰...
竹林里有冰 · 2024-05-03 · via 竹林里有冰的博客

在 Redhat 系的发行版上打包软件的时候,会发现与 Archlinux 完全不同的思路。

Fedora 所代表的 Redhat 阵营一看就是那种宏大叙事的大型发行版,rpmbuild 在默认情况下会在 $HOME/rpmbuild 下的一系列文件夹进行构建过程。使用 rpmdev-setuptree 命令会创建好下面这些目录进行构建。

$ tree rpmbuild
rpmbuild
├── BUILD
├── BUILDROOT
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

Fedora 将所有的软件的构建都集中在一个 rpmbuild 目录中,BUILD 是编译时使用的,BUILDROOT 是最终安装目录,RPMS 是存放最终产物的,SOURCES 是存放源码等文件的,SPECS 是存放指导构建过程的 spec 文件的,而 SRPMS 是 RH 系为了 reproducibility 而单独将 spec 和源文件打包的产物。除了 rpmbuild 命令以外,Fedora 还有一套使用容器构建 rpm 包的 mock 构建系统,与 Archlinux 的 devtools 类似,这里不作过多叙述。

反观 Arch 的构建目录,就有一股浓浓的小作坊气味。每个软件包自己拥有一个目录,指导构建过程的 PKGBUILD 文件、源文件和最终的产物都放在这个目录下,目录下的 src 和 pkg 文件夹分别对应 rpm 的 BUILD 和 BUILDROOT,前者是源文件被解压的目录和编译过程进行的目录,后者是软件最终的安装目录。

$ tree repo
repo
├── src
├── pkg
└── PKGBUILD

好巧不巧,我偏偏习惯这个小作坊气息的 arch build system,每个软件包独享一个自己的目录,干净又卫生。我自然也希望在 Fedora 下打 rpm 包的时候能够使用类似 Archlinux 下 makepkg 使用的目录结构。

简单了解#

在了解一系列 rpmbuild 中宏(macros)相关的知识后,我意识到这并非不可能。

使用如下的命令可以获取目前系统中定义的所有宏

rpm --showrc

而可以使用如下命令检查某一个宏目前被定义成了什么值

rpm --eval "%{_topdir}"

更多关于宏的描述可以在 https://rpm-software-management.github.io/rpm/manual/macros.html 获取

修改路径#

我们可以把定义成 $HOME/rpmbuild 的 %_topdir 重新定义成当前目录。

在 $HOME/.rpmmacros 中,去除顶部对 %_topdir 的定义,重新填上以下这些定义,即可初步完成我想要的效果。

%_topdir    %(pwd)
%_builddir %{_topdir}/src
%_buildrootdir %{_topdir}/pkg
%_rpmdir %{_topdir}
%_sourcedir %{_topdir}
%_specdir %{_topdir}
%_srcrpmdir %{_topdir}

现在在任何一个目录下执行 rpmbuild 相关命令,都会把 src 认为是构建目录,pkg 是最后安装目录,spec 文件和源文件早当前文件夹下,构建产物在当前文件夹下的 x86_64(或者别的架构名,这一层目录我还没有找到应该如何去掉)下。

自动安装依赖文件#

Fedora 中的 rpmbuild 不带有 makepkg -s 的功能,不能自动安装依赖。不过这也不意味着需要自己傻傻地去翻 spec 看看需要哪些构建依赖。可以使用 dnf 的 builddep 命令实现

sudo dnf builddep ./*.spec

不过 dnf 没有什么完成构建后自动卸载依赖的选项。这些依赖装完以后就一辈子赖在你的电脑上了,才不是,可以在构建完成后使用 dnf 自带的后悔药功能撤销上一条命令执行的效果。

sudo dnf history undo 0

不过如果在 builddep 过程中,dnf 从 updates 源里更新了一些软件,那么它在 undo 时可能就没法获取更新前的软件版本。会有 Cannot find rpm nevra 的提示

可以使用 --skip-broken 命令跳过那些没法找到老版本的软件,继续卸载其余的软件。

自动下载源文件#

很多使用 spec 中会在 source 里写上下载地址,而不是附上源码文件。rpm 似乎因为一些原因禁止了 rpmbuild 自动下载源文件的功能。可以通过在使用 rpmbuild 的时候带上 --undefine=_disable_source_fetch 取消定义这个行为,或者干脆在调用 rpmbuild 之前执行一遍

spectool -gR *.spec

这样也能自动下载源文件。

构建行为#

makepkg 的默认构建行为就是只构建最终的安装包,Archlinux 中并没有 Fedora 那样打 source rpm 保证 reproduceability 的行为,这在 rpmbuild 中对应的是 -bb 选项。

使用 rpmbuild -bb *.spec 即可


上面介绍完了 rpmbuild 和 makepkg 的主要差异,应该可以自己搓一个 rpmbuild-wrapper 去实现以 makepkg 的方式打开 rpmbuild 的目标了,具体的 wrapper 脚本我就不放出来献丑了。