补丁

补丁命名没有固定的规则。以下是仅供参考的指南。

小补丁(小于,比如,几 KB)应该添加到 ${FILESDIR} 中。如果您预计会有多个补丁,创建带版本号的子目录通常会有所帮助——${FILESDIR}/${PV}/ 是惯例。补丁最好命名为 ${P}-what-it-does.patch(或 .diff),其中 what-it-does 是对补丁用途的二到三个单词的描述。如果补丁是为了修复特定的 bug,添加 bug 编号通常很有用——例如,vim-7.0-cron-vars-79981.patch。如果补丁是从上游的 VCS 存储库中提取的,则可以在补丁名称中包含版本部分的后缀修订号以提供帮助——fluxbox-0.9.12-3860-menu-backups.patch

较大的补丁应该 镜像,最好是在 Gentoo 基础设施上。镜像补丁时,选择不会导致冲突的名称非常重要——这里强烈推荐使用 ${P} 前缀。镜像补丁通常使用 xzbzip2 压缩。请记住在 SRC_URI 中列出这些补丁。有关更多信息,请参阅 文件目录

如果一个软件包需要很多补丁,即使它们本身很小,通常最好创建一个补丁压缩包,以避免过度混乱树。

补丁描述

可以在补丁中包含描述。当其他人开始使用您的软件包时,或者当您几个月后重新查看自己的软件包时,这通常很有帮助。在注释中包含以下内容:

  • 补丁实际上做了什么。这里 bug 编号很有用。
  • 补丁来自哪里。例如,它来自上游 VCS、Bugzilla 中的内容还是您编写的?
  • 如果适用,补丁是否已发送到上游。

要包含描述,只需将其插入补丁文件顶部。 patch 工具会忽略前导文本,直到找到看起来像是“开始修补”指令的内容,因此,只要每个描述行以字母开头(而不是数字、符号或空格),就不会出现问题。或者,在每个描述行的前面加上一个井号(即 # 或美国人所说的“磅”)符号。最好在描述和主要补丁之前留一个空行。

这是一个来自 vim 补丁压缩包的简单示例(023_all_vim-6.3-apache-83565.patch

# Detect Gentoo apache files properly. Gentoo bug 83565.

--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -93,6 +93,9 @@
 " Gentoo apache config file locations (Gentoo bug #76713)
 au BufNewFile,BufRead /etc/apache2/conf/*/* setf apache

+" More Gentoo apache config file locations (Gentoo bug #83565)
+au BufNewFile,BufRead /etc/apache2/{modules,vhosts}.d/*.conf setf apache
+
 " XA65 MOS6510 cross assembler
 au BufNewFile,BufRead *.a65                    setf a65

条件性补丁

理想情况下,仅在使相关软件包正确构建时才进行修补,并且不应修改软件包的运行时行为。这就是软件包的 USE 标志和功能的用途。因此,最好无条件地应用补丁并避免条件性补丁。

避免条件性补丁的原因有很多

  • 如果软件包未在给定标志下进行测试,则补丁无法应用的情况可能会被忽视
  • 引入了更多差异,软件包的问题变得更难以调试
  • 补丁最好向上游提交,但条件性补丁无法提交

考虑以下 src_prepare() 实现示例

src_prepare() {
	if use threads; then
		PATCHES+=( "${FILESDIR}"/${P}-mt.patch )
	fi
	default
}

由于此补丁仅在设置了 USE="threads" 时应用,因此任何创建此软件包新版本的开发人员如果没有使用相同的标志进行测试,可能无法检测到补丁是否成功应用。

虽然不鼓励使用条件性补丁,但它可能是不可避免的,因此,它不被视为禁止的做法,但是,在尽可能的情况下,补丁应该编写成根据例如构建时定义和配置选项而不是 USE 标志直接影响行为。这允许它们无条件地应用。

干净补丁指南

“干净补丁”并非指补丁本身(如它对源代码所做的更改)。它指的是补丁中存在的所有元数据,以使其“可维护”。

原因

这可能需要“预先”付出更多努力,但它为将来其他人节省的努力超过了它本身。这指的是读取补丁的其他发行版或上游维护者,或未来的 Gentoo 维护者。通过保持所有补丁“干净”,人们可以快速轻松地评估补丁,而无需搜索许多其他文件。

文件命名

您的补丁名称应该简明扼要。在执行文件列表时(例如,ls files/),当它们的文件名中包含良好的关键词时,扫描相关补丁会容易得多。

它还应该包含软件包名称及其针对其编写的版本。这样,搜索补丁或碰巧偶然发现文件本身的人就能了解其用途。剥离 ${PN}(以及在较小程度上,${PV})会使文件名变得毫无用处。文件通常存储在 ${CATEGORY}/${PN}/files/ 中这一事实无关紧要,因为补丁可能在 Gentoo 之外使用。

方法

以下是对补丁标题中需要保留的内容的清单

  • 外部链接
    • 上游邮件档案
    • 上游 bug 报告
    • 上游提交链接
    • 上游 ChangeLog 条目
    • Gentoo bug 报告
  • 简短/中等解释
    • 为什么需要补丁?
    • 它修复了什么?
    • 为什么以这种方式修复它?
    • 未来改进修复的建议?
    • 它是一个权宜之计(解决方法)吗?
    • 如何进行回归测试?
    • 前后行为示例
      • 如何在没有补丁的情况下重现 bug
      • 如何在应用补丁后显示 bug 已修复
      • 也许上游以不同的方式修复了它,因此此测试可用于显示在使用更新版本时不再需要此补丁
  • 状态
    • 它是否已在上游合并/拒绝/推迟/等?
    • 它是特定于发行版的吗?
  • 归属
    • 谁发现了 bug?
    • 谁修复了 bug?
    • 谁编写了补丁?
    • 谁测试了补丁?
    • 谁对补丁提出了建议?

所有这些信息都应该在补丁本身中。它永远不应该在 ebuild 等内容中找到。如果您确实想在 ebuild 中的补丁旁边添加注释,那么这几乎是唯一可以接受的内容(其中 93671 是 Gentoo bug 编号)

PATCHES=(
	"${FILESDIR}"/${P}-dont-umask.patch #93671
)

在记录这些内容时,使用 RFC822/Git 样式标签来格式化元数据可能很有用。因此,在记录作者时,请使用

From: Nice Person <[email protected]>

或者,在记录相关 URL 时,请使用类似以下内容:

Bug: https://upstream.example.com/12345
Bug: https://bugs.gentoo.org/9889

如果您想记录您的版权签署,请添加 Signed-off-by 标签

Signed-off-by: Diligent Developer <[email protected]>

最后,你的补丁应该剔除所有无用的冗余信息。如果它不是直接从上游 SCM 获取的(例如 git format-patchsvn diff -r #cvs diff -r 1.123 -r 1.124),那么元数据就是无用的。所以请删除它。这指的是生成补丁时使用的 diff 命令,或文件上的时间戳、本地版本信息或其他类似的垃圾信息。请注意,上下文信息(@@ 之后的内容)应该保留,因为在将补丁应用到更高版本时,它可能非常宝贵。例如

@@ -80,6 +82,7 @@ case $sys in
                  ^^^^^^^^^^^^ keep this part

如果你能使 ---/+++ 部分中的文件名保持一致且合理,则可获得额外加分。也就是说,删除不同的前导 backup/paths/.orig/.new 后缀。你的补丁应该采用 -p1 格式,因为这比任何其他 -p# 格式都要标准得多。它也是 eapply 默认理解的格式。一个好的建议是使用 a/b/(如 git format-patch 中所示)或包名/版本作为要删除的前导部分。

另请注意,patch 使用时间戳信息来自动删除空文件。或者,如果你想删除空文件,可以使用 eapply-E 选项。

已删除的行不应该出现在补丁中,因为它们会被注释掉——只需完全删除它们即可。补丁通过在已删除行前添加 - 来显示它们,因此,简单地删除行而不是注释掉它们(这会增加噪音)并不会丢失任何信息。这使得补丁更短,更易读。

以下函数(适用于你的交互式 shell,而不是 ebuild)将帮助你删除这些内容

scrub_patch() {
	sed -i \
		-e '/^index /d' \
		-e '/^new file mode /d' \
		-e '/^Index:/d' \
		-e '/^=========/d' \
		-e '/^RCS file:/d' \
		-e '/^retrieving/d' \
		-e '/^diff/d' \
		-e '/^Files .* differ$/d' \
		-e '/^Only in /d' \
		-e '/^Common subdirectories/d' \
		-e '/^deleted file mode [0-9]*$/d' \
		-e '/^+++/s:\t.*::' \
		-e '/^---/s:\t.*::' \
		"$@"
}

scrub_patch some-patch-you-found.patch

示例

这展示了一个简单的解释和一个获取更多信息的 URL(不过,这个补丁可能需要一些署名)。运行 diff 命令生成的元数据(时间戳等)都不存在。

Fixes compilation in FreeBSD.
https://bugs.gentoo.org/138123

--- man-1.6d/gencat/genlib.c
+++ man-1.6d/gencat/genlib.c
@@ -54,7 +54,7 @@
 #include <unistd.h>
 #endif

-#ifndef __linux__
+#if !defined(__linux__) && !defined(__FreeBSD__)
 #include <memory.h>
 static int bcopy(src, dst, length)
 char *src, *dst;
Don't force umask to 022 or the -o umask option doesn't work.
Patch by Daniel Drake.
https://bugs.gentoo.org/93671

--- mount/mount.c
+++ mount/mount.c
@@ -1491,8 +1491,6 @@ main(int argc, char *argv[]) {
    if ((p = strrchr(progname, '/')) != NULL)
        progname = p+1;

-   umask(022);
-
    /* People report that a mount called from init without console
       writes error messages to /etc/mtab
       Let us try to avoid getting fd's 0,1,2 */
Don't let target flags bleed into build flags.
Fix by Bertrand Jacquin.
https://bugs.gentoo.org/226035

--- netem/Makefile
+++ netem/Makefile
@@ -2,6 +2,7 @@ DISTGEN = maketable normal pareto paretonormal
 DISTDATA = normal.dist pareto.dist paretonormal.dist experimental.dist

 HOSTCC ?= $(CC)
+CCOPTS  = $(CBUILD_CFLAGS)
 LDLIBS += -lm

 all: $(DISTGEN) $(DISTDATA)