xiaohui 技术 2020-02-16 10:30:00
收藏
Fedora 是一个 Linux 发行版,是一款由全球社区爱好者构建的面向日常应用的快速、稳定、强大的操作系统。 [1] 它允许任何人自由地使用、修改和重发布,无论现在还是将来。它由一个强大的社群开发,这个社群的成员以自己的不懈努力,提供并维护自由、开放源码的程序和开放的标准。
尽管许多Linux用户是开发人员,但相当一部分开发人员在使用时会经常干预或扩展已发行的程序包。当程序包中有待处理的功能,或者程序包中有漏洞时,用户通常会等待发行维护者对其进行修复,或者使用独立的解决方案(例如自制程序)来自行构建。
幸运的是,在Fedora中,开发人员可以处理每个程序包自身的问题,并使构建修改版本变得异常容易。
安装原始程序包
首先,我们从安装几个基本系统程序包开始,这些程序包将帮助我们处理程序包构建:
$ sudo dnf install fedpkg make
假设我们要考虑zsh(Z Shell)的补丁或功能,就需要考虑什么是生成二进制文件的源程序包项目。查询rpm工具很容易,根据已安装程序包的文件名,可以显示源程序包RPM的名称。例如:
$ rpm -qif /usr/bin/zsh | grep 'Source RPM' Source RPM : zsh-5.7.1-4.fc30.src.rpm
源RPM名称也是zsh,这并不奇怪。但是,其他包可能不是这样。
通常,源程序包的RPM名称与 Git存储库的名称相匹配,这意味着,Fedora在该Git存储库中维护允许构建它的脚本。从Fedora的Git服务器克隆源程序包非常容易,并且不需要成为Fedora社区成员或使用任何其他凭据。对于zsh,我们可以使用fedpkg执行以下命令:
$ fedpkg co -a zsh Cloning into 'zsh'... remote: Counting objects: 1023, done. remote: Compressing objects: 100% (777/777), done. remote: Total 1023 (delta 556), reused 423 (delta 216) Receiving objects: 100% (1023/1023), 235.29 KiB | 271.00 KiB/s, done. Resolving deltas: 100% (556/556), done.
对于每个程序包,每个版本的Fedora的源都保存在不同的分支中。因此,我们可以找出与我们要为其构建的发行版本匹配的分支:
$ cd zsh $ git checkout -b f31 origin/f31 Branch 'f31' set up to track remote branch 'f31' from 'origin'. Switched to a new branch 'f31'
从现在开始,我们将在程序包的工作目录中调用fedpkg。
设置构建环境
对于正常运行的开发环境,不同的程序包将有不同的要求。幸运的是,Fedora的dnf可以帮助我们引入它可以构建的任何程序包所需的依赖项。这可以通过dnf builddep命令来完成。对于我们的用例,我们可以引入zsh依赖项:
$ sudo dnf builddep zsh
直接建立可分配的RPM
在修改包之前,有必要测试一下,看看我们是否能够在不进行任何修改的情况下正确地构建它,以下命令将尝试从代码的当前状态构建二进制RPM:
$ fedpkg local
我们可以观察到已经生成了以下RPM:
$ ls -l1 x86_64/ noarch/ noarch/: total 452 -rw-rw-r--. 1 user user 459748 Jan 14 13:58 zsh-html-5.7.1-4.fc31.noarch.rpm x86_64/: total 5476 -rw-rw-r--. 1 user user 2999294 Jan 14 13:58 zsh-5.7.1-4.fc31.x86_64.rpm -rw-rw-r--. 1 user user 1771784 Jan 14 13:58 zsh-debuginfo-5.7.1-4.fc31.x86_64.rpm -rw-rw-r--. 1 user user 829306 Jan 14 13:58 zsh-debugsource-5.7.1-4.fc31.x86_64.rpm
或者,在模拟容器中构建RPM。
甚至在Docker容器流行之前,Fedora就向我们提供了一个名为mock的工具,该工具会创建了一个用于构建程序包的独立环境。因此,可以使用它独立于开发环境来构建程序包。
首先,我们需要确保安装了mock。
$ sudo dnf install mock
然后,我们可以告诉fedpkg使用mock来构建包:
$ fedpkg mockbuild
mock的构建输出全部被移动到一个目录,其中包含构建的日志文件以及程序包的版本和名称:
$ ls -lR results_zsh/*/* results_zsh/5.7.1/4.fc31: total 9852 -rw-rw-r--. 1 user user 190779 Jan 14 14:10 build.log -rw-rw-r--. 1 user user 2744 Jan 14 14:03 hw_info.log -rw-rw-r--. 1 user user 52642 Jan 14 14:08 installed_pkgs.log -rw-rw-r--. 1 user user 614047 Jan 14 14:10 root.log -rw-rw-r--. 1 user user 998 Jan 14 14:10 state.log -rw-r--r--. 1 user mock 3146067 Jan 14 14:06 zsh-5.7.1-4.fc31.src.rpm -rw-r--r--. 1 user mock 2999346 Jan 14 14:10 zsh-5.7.1-4.fc31.x86_64.rpm -rw-r--r--. 1 user mock 1772488 Jan 14 14:10 zsh-debuginfo-5.7.1-4.fc31.x86_64.rpm -rw-r--r--. 1 user mock 829174 Jan 14 14:10 zsh-debugsource-5.7.1-4.fc31.x86_64.rpm -rw-r--r--. 1 user mock 459682 Jan 14 14:10 zsh-html-5.7.1-4.fc31.noarch.rpm
使用mock执行构建的优势在于,它可以验证构建的依赖项是否正确指定,并且还可以用于在同一台计算机上针对发行版的不同版本进行构建。另外,它也是Fedora自己的构建服务器(即Copr)背后的运行设备。
添加补丁
要为程序包生成补丁,我们需要包本身的源代码,而不是告诉我们如何构建它的Fedora脚本的源代码。
有多种获取源代码的方法,其中一种是使用fedpkg。我们可以让它创建一个目录,其中包含已准备好构建的修补程序包源代码。这个过程将执行RPM规范源代码的准备阶段,结果通常是工作树下的一个目录。
$ fedpkg prep
因为Fedora源代码包不会考虑源代码控制方面的问题,所以它们只包含某个版本源代码的压缩文件。在源代码控制中不跟踪创建的目录,如果要修改它,通常最好将它移到另一个目录,并使用Git对其进行初始化。如下所示:
$ mv zsh-5.7.1 ../zsh-5.7.1 $ cd ../zsh-5.7.1 $ git init && git add -f . && git commit -m "Base version"
在这个示例中,我们的zsh-5.7.1只是该Fedora维护版本的代表,它可能已经被Fedora进行了某种程度的修补,但是它可以并且应该被用作我们进一步修补的基础。但是,我们可能想要克隆完整的项目,在这种情况下,zsh方便于完整的Git历史浏览。
$ cd .. $ git clone git://git.code.sf.net/p/zsh/code zsh-upstream Cloning into 'zsh-upstream'... remote: Enumerating objects: 94026, done. remote: Counting objects: 100% (94026/94026), done. remote: Compressing objects: 100% (25128/25128), done. remote: Total 94026 (delta 73505), reused 87930 (delta 68487) Receiving objects: 100% (94026/94026), 16.60 MiB | 1.07 MiB/s, done. Resolving deltas: 100% (73505/73505), done.
回到任何一个源代码克隆,我们都可以继续提交更改并通过提交生成补丁,以下就是一个简单补丁的示例:
$ git diff HEAD diff --git a/Src/hist.c b/Src/hist.c index dbdc1e4..cdb1dd1 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -580,7 +580,7 @@ histsubchar(int c) */ lexraw_mark = zshlex_raw_mark(-1);- /* look, no goto's */+ /* look, no goto's! */ if (isfirstch && c == hatchar) { int gbal = 0; $ git commit -m "Adding an exclamation mark to Src/hist.c" [f31 c00d68b] Adding an exclamation mark to Src/hist.c 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 0001-zsh-5.7.1-zle-history-avoid-crash.patch $ git format-patch HEAD~1 -o ../zsh ../zsh/0001-Adding-an-exclamation-mark-to-Src-hist.c.patch
git format-patch是一个方便的命令,可以将git提交为文件,它的输出可以作为程序包构建过程的输入,因为Fedora中的程序包标准要求其上层的源代码与在其上生成的补丁分开。
将补丁文件添加到Fedora程序包的源规范中可能会有些棘手,但是经过几次之后,你了解到打包格式比起初看起来更简单。对于zsh,我们只需要在zsh.spec开头的Patch
$ git diff diff --git a/zsh.spec b/zsh.spec index 0d77f70..0022a90 100644 --- a/zsh.spec +++ b/zsh.spec @@ -14,6 +14,7 @@ Source6: dotzshrc # make failed searches of history in Zle robust (#1722703) Patch1: 0001-zsh-5.7.1-zle-history-avoid-crash.patch+Patch2: 0001-Adding-an-exclamation-mark-to-Src-hist.c.patch BuildRequires: autoconf BuildRequires: coreutils
较旧的程序包可能需要更多更改,例如,在文件中进一步添加与上述准备阶段有关的额外%patch行。
识别修补过的程序包
如果没有其他的.spec字段被更改,我们修改后的包在元数据中与原始包几乎没有区别。通常情况下这是不需要的。因此,最好将.spec修改为在程序包的Release字段中包含一个字符串。例如:
diff --git a/zsh.spec b/zsh.spec index 0022a90..78c362e 100644 --- a/zsh.spec +++ b/zsh.spec @@ -1,7 +1,7 @@ Summary: Powerful interactive shell Name: zsh Version: 5.7.1-Release: 4%{?dist}+Release: 4%{?dist}.daloni License: MIT URL: http://zsh.sourceforge.net/ Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.xz
我们可以看到,在构建之后。
$ ls -l1 x86_64/ noarch/ noarch/: total 452 -rw-rw-r--. 1 user user 459790 Jan 14 15:15 zsh-html-5.7.1-4.fc31.daloni.noarch.rpm x86_64/: total 5476 -rw-rw-r--. 1 user user 2999482 Jan 14 15:15 zsh-5.7.1-4.fc31.daloni.x86_64.rpm -rw-rw-r--. 1 user user 1773094 Jan 14 15:15 zsh-debuginfo-5.7.1-4.fc31.daloni.x86_64.rpm -rw-rw-r--. 1 user user 829124 Jan 14 15:15 zsh-debugsource-5.7.1-4.fc31.daloni.x86_64.rpm
安装程序包
可以通过dnf install安装新程序包,一旦安装了修补程序包,就可以通过各种方式安装的dnf list的输出进行重复查找,从而轻松发现它们。
$ sudo dnf install x86_64/zsh-5.7.1-4.fc31.daloni.x86_64.rpm $ dnf list installed | grep @@commandline zsh.x86_64 5.7.1-4.fc31.daloni @@commandline $ dnf list installed | grep daloni zsh.x86_64 5.7.1-4.fc31.daloni @@commandline
避免补丁在版本升级时被覆盖
当Fedora发布新版本的程序包时,自动系统升级可能会覆盖补丁。虽然有几种方法可以防止这个情况的发生,但我最喜欢的一种方法是从dnf的配置中排除对此类程序包的升级。
$ grep exclude /etc/dnf/dnf.conf exclude=zsh
不过,处理程序包的话题已经超出了本文的范围。
保留debuginfo!
如果修补的程序包崩溃并生成了一个核心文件,那么构建中生成的特殊的debuginfo程序包在检查这个corefile时可能很方便。因此,你可能需要保留这些debuginfo程序包,特别是因为复制的构建有时很难与原始的二进制兼容性完全匹配。这取决于构建包的确定性如何,这是程序包自身构建系统固有的问题。
本文翻译自:https://blog.aloni.org/posts/how-to-easily-patch-fedora-packages/如若转载,请注明原文地址: