4.4.打补丁

在准备port时,可以使用 diff(1)记录已添加或更改的文件,以便稍后提供给 patch(1)。这样做时,通常涉及在进行任何更改之前使用.orig 后缀保存原始文件的副本。

% cp file file.orig

所有更改完成后, cd 返回到port目录。使用 make makepatch 在文件目录中生成更新的补丁文件。

4.4.1. 修补通用规则

补丁文件存储在 PATCHDIR 中,通常是 files/,从那里它们将自动应用。所有补丁必须相对于 WRKSRC 。通常 WRKSRC 是 WRKDIR 的一个子目录,即提取 dist 文件的目录。使用 make -V WRKSRC 查看实际路径。补丁名称必须遵循这些规则:

  • 避免多个补丁修改同一文件。例如,同时使用 patch-foobar.c 和 patch-foobar.c2 对${WRKSRC}/foobar.c 进行更改会使它们变得脆弱且难以调试。

  • 创建补丁文件名称时,请将每个下划线( _ )替换为两个下划线( __ ),将每个斜杠( / )替换为一个下划线( _ )。例如,要为名为 src/freeglut_joystick.c 的文件打补丁,请将相应的补丁命名为 patch-src_freeglut__joystick.c。不要命名为 patch-aa 或 patch-ab。在补丁名称中始终使用路径和文件名。使用 make makepatch 会自动生成正确的名称。

  • 如果修改是相关的,并且补丁的命名合适,一个补丁可能会修改多个文件。例如,patch-add-missing-stdlib.h。

  • 仅使用 [-+._a-zA-Z0-9] 字符来命名补丁。特别是,不要使用 :: 作为路径分隔符,而要使用 _ 。

在补丁中尽量减少非功能性空白变更的数量。在开源世界中,项目通常共享大量的代码库,但遵循不同的样式和缩进规则。当从一个项目中提取工作的功能块来修复另一个项目中的类似区域时,请务必小心:生成的补丁可能充满了非功能性的变更。这不仅增加了 ports 代码库的大小,而且使得难以确定到底是什么导致了问题,以及到底做了哪些改动。

如果必须删除文件,请在 post-extract 目标中执行,而不是作为补丁的一部分。

4.4.2. 手动补丁生成

补丁被保存在名为 patch-的文件中,其中表示被打补丁的文件路径名,比如 patch-Imakefile 或 patch-src-config.h。文件名不以 patch-开头的补丁将不会自动应用。

文件修改后,使用 diff(1)记录原始版本和修改后版本之间的差异。 -u 导致 diff(1)生成"unified"格式的差异,这是首选格式。

% diff -u file.orig file > patch-pathname-file

当为新添加的文件生成补丁时, -N 用于告诉 diff(1)将不存在的原始文件视为存在但为空:

% diff -u -N newfile.orig newfile > patch-pathname-newfile

使用递归( -r )选项对 diff(1) 生成补丁是可以的,但请查看生成的补丁,以确保其中没有不必要的垃圾。特别是,两份备份文件之间的差异,port 使用 Imake 或 GNU configure 时的 Makefile 等都是不必要的,必须删除。如果需要编辑 configure.in 并运行 autoconf 重新生成 configure ,不要采用 configure 的差异(它通常会增长到几千行!)。相反,定义 USES=autoreconf 并获取 configure.in 的差异。

4.4.3. 简单自动替换

可以直接从 port Makefile 使用 sed(1) 的就地模式进行简单替换。当更改使用变量的值时,这非常有用。

post-patch:
	@${REINPLACE_CMD} -e 's|/usr/local|${PREFIX}|g' ${WRKSRC}/Makefile

经常,正在移植的软件在源文件中使用 CR/LF 约定。这可能会导致进一步打补丁、编译器警告或脚本执行(如{{ 0 }})出现问题。要快速将所有文件从 CR/LF 转换为 LF,将此条目添加到{{ 1001 }} Makefile 中:

USES=	dos2unix

可以提供要转换的特定文件列表:

USES=	dos2unix
DOS2UNIX_FILES=	util.c util.h

使用 DOS2UNIX_REGEX 来转换子目录中的一组文件。它的参数是一个与 find(1) 兼容的正则表达式。有关格式的更多信息请参阅 re_format(7)。这个选项对于转换给定扩展名的所有文件非常有用。例如,转换所有源代码文件,保留二进制文件不变:

USES=	dos2unix
DOS2UNIX_REGEX=	.*\.([ch]|cpp)

类似的选项是 DOS2UNIX_GLOB ,它对列出的每个元素运行 find 。

USES=	dos2unix
DOS2UNIX_GLOB=	*.c *.cpp *.h

可以设置转换的基础目录。当存在多个 distfiles 且其中几个包含需要进行换行符转换的文件时,这非常有用。

USES=	dos2unix
DOS2UNIX_WRKSRC=	${WRKDIR}

4.4.4. 有条件地打补丁

一些ports需要仅在特定的 FreeBSD 版本或者特定选项启用或禁用时才应用的补丁。有条件的补丁通过将补丁文件的完整路径放置在 EXTRA_PATCHES 中指定。有条件的补丁文件名通常以 extra-开头,尽管这不是必要的。然而,它们的文件名不得以 patch-开头。如果是这样,框架会无条件地应用它们,这在有条件的补丁中是不希望的。

示例 1. 为特定的 FreeBSD 版本应用补丁

.include <bsd.port.options.mk>

# Patch in the iconv const qualifier before this
.if ${OPSYS} == FreeBSD && ${OSVERSION} < 1100069
EXTRA_PATCHES=	${PATCHDIR}/extra-patch-fbsd10
.endif

.include <bsd.port.mk>

示例 2. 可选地应用补丁

当选项需要补丁时,使用 opt_EXTRA_PATCHES 和 opt_EXTRA_PATCHES_OFF 条件地应用补丁到 opt 选项上。有关更多信息,请参见通用变量替换。

OPTIONS_DEFINE=	  FOO BAR
FOO_EXTRA_PATCHES=  ${PATCHDIR}/extra-patch-foo
BAR_EXTRA_PATCHES_OFF=	${PATCHDIR}/extra-patch-bar.c \
		${PATCHDIR}/extra-patch-bar.h

示例 3. 使用 EXTRA_PATCHES 与目录

有时候,一个特性可能需要很多补丁,在这种情况下,可以将 EXTRA_PATCHES 指向一个目录,它会自动应用该目录中所有名为 patch-*的文件。

在${PATCHDIR}中创建一个子目录,并将补丁移动到其中。例如:

% ls -l files/foo-patches
-rw-r--r--  1 root  wheel    350 Jan 16 01:27 patch-Makefile.in
-rw-r--r--  1 root  wheel   3084 Jan 18 15:37 patch-configure.ac

然后将其添加到 Makefile 中:

OPTIONS_DEFINE=	FOO
FOO_EXTRA_PATCHES=	${PATCHDIR}/foo-patches

框架将使用该目录中所有名为 patch-* 的文件。

最后更新于

FreeBSD 中文社区