% cp file file.orig
第 4 章。慢速移植
目录
好吧,事情并没有那么简单,该端口需要一些修改才能使其正常工作。在本节中,我们将逐步解释如何修改它以使其适应端口范式。
4.1. 工作原理
首先,以下是用户在端口目录中首次输入 make
时发生的一系列事件。在阅读本文时,在另一个窗口中打开 bsd.port.mk 文件将有助于理解它。
但不用担心,并不是所有人都能完全理解 bsd.port.mk 的工作原理... :-)
会执行
fetch
目标。fetch
目标负责确保压缩包在DISTDIR
目录中本地存在。如果fetch
在DISTDIR
目录中找不到所需的文件,它将查找MASTER_SITES
(在 Makefile 中设置)以及我们用于备份 distfiles 的 FTP 镜像。然后,它将尝试使用FETCH
获取指定的发布文件,前提是请求站点可以直接访问互联网。如果成功,它将把文件保存到DISTDIR
目录以便将来使用,然后继续执行。会执行
extract
目标。它会在DISTDIR
中查找端口的发布文件(通常是一个压缩的 tarball),并将其解压缩到由WRKDIR
指定的临时子目录中(默认值为 work)。会执行
patch
目标。首先,应用PATCHFILES
中定义的任何补丁。其次,如果在PATCHDIR
中找到任何名为 patch-* 的补丁文件(默认为 files 子目录),则此时会按字母顺序应用这些补丁。会执行
configure
目标。它可以执行很多不同的事情。如果存在 scripts/configure 文件,则会执行它。
如果设置了
HAS_CONFIGURE
或GNU_CONFIGURE
,则会执行 WRKSRC/configure 文件。
会执行
build
目标。它负责进入端口的私有工作目录 (WRKSRC
) 并构建它。会执行
stage
目标。它将最终的构建文件集放入一个临时目录中 (STAGEDIR
,参见 暂存)。此目录的层次结构与将安装软件包的系统的层次结构相同。会执行
package
目标。它使用stage
目标创建的临时目录中的文件以及端口的 pkg-plist 创建一个软件包。会执行
install
目标。它将package
目标创建的软件包安装到主机系统中。
以上是默认操作。此外,还可以定义 pre-something
或 post-something
目标,或者在 scripts 子目录中放置具有这些名称的脚本,它们将在默认操作执行之前或之后执行。
例如,如果在 Makefile 中定义了 post-extract
目标,并在 scripts 子目录中存在一个名为 pre-build 的文件,则在执行常规提取操作后会调用 post-extract
目标,在执行默认构建规则之前会执行 pre-build 文件。建议使用 Makefile 目标(如果操作足够简单),因为这样更容易让人理解端口需要什么样的非默认操作。
默认操作由 bsd.port.mk 中的 do-something
目标执行。例如,用于提取端口的命令位于 do-extract
目标中。如果默认目标不能正确执行,请在 Makefile 中重新定义 do-something
目标。
"主" 目标(例如, |
现在,我们已经更好地理解了用户输入 make install
时会发生什么,接下来让我们看一下创建完美端口的推荐步骤。
4.2. 获取原始源代码
获取原始源代码(通常)作为一个压缩的 tarball (foo.tar.gz 或 foo.tar.bz2),并将其复制到 DISTDIR
中。始终使用主流源代码,尽可能地这样做。
设置 MASTER_SITES
变量以反映原始压缩包所在的地址。大多数主流站点在 bsd.sites.mk 文件中都有简写定义。请尽可能使用这些站点以及相关定义,以帮助避免在源代码库中重复相同信息的问题。由于这些站点往往会随着时间的推移而发生变化,因此这会给所有参与者带来维护上的噩梦。有关详细信息,请参见 MASTER_SITES
。
如果没有与网络良好连接的 FTP/HTTP 站点,或者只能找到格式非常不标准的站点,请在可靠的 FTP 或 HTTP 服务器上放一个副本(例如,主页)。
如果找不到放置 distfiles 的方便可靠的地方,我们可以将其放在 ftp.FreeBSD.org
上,但这是最不理想的解决方案。distfiles 必须放在某人的 freefall
帐户的 ~/public_distfiles/ 目录中。请提交端口的人员这样做。他们还将 MASTER_SITES
设置为 LOCAL/username
,其中 username
是他们的 FreeBSD 集群登录名。
如果端口的 distfiles 经常发生变化,而作者没有进行任何版本的更新,请考虑将 distfiles 放置到主页上,并将其列为第一个 MASTER_SITES
。尽量说服端口作者不要这样做,因为建立某种源代码控制确实很有帮助。托管特定版本可以防止用户收到 checksum mismatch
错误,并减少我们 FTP 站点维护人员的工作量。此外,如果端口只有一个主站点,建议在主页上放置一个备份,并将其列为第二个 MASTER_SITES
。
如果端口需要在互联网上可用的其他补丁,请也获取它们并将它们放到 DISTDIR
中。不用担心它们是否来自与主源压缩包不同的站点,我们有一种方法来处理这些情况(请参见下面对 PATCHFILES 的描述)。
4.3. 修改端口
在私有目录中解压压缩包的副本,并进行必要的修改,以便端口在当前版本的 FreeBSD 下正确编译。仔细跟踪这些步骤,因为这些步骤将很快用于自动化流程。所有内容,包括文件的删除、添加或修改,都必须在端口完成时使用自动化脚本或补丁文件来完成。
如果端口需要大量用户交互/自定义才能编译或安装,请查看 Larry Wall 的经典 Configure 脚本之一,并尝试做类似的事情。新端口集合的目标是尽可能地让最终用户可以"即插即用"地使用每个端口,同时使用最少的磁盘空间。
除非另有说明,否则贡献给 FreeBSD 端口集合的补丁文件、脚本和其他文件都假设受标准 BSD 版权条件的约束。 |
4.4. 补丁
完成所有更改后,cd
回到端口目录。使用 make makepatch
在 files 目录中生成更新的补丁文件。
使用 |
4.4.1. 补丁的一般规则
补丁文件存储在 PATCHDIR
中,通常为 files/,它们将从这里自动应用。所有补丁必须相对于 WRKSRC
。通常,WRKSRC
是 WRKDIR
的子目录,WRKDIR
是解压 distfiles 的目录。使用 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]
来命名补丁。特别是,不要使用::
作为路径分隔符,请改用_
。
尽量减少补丁中非功能性空白变化的数量。在开源世界中,项目通常会共享大量代码库,但遵守不同的风格和缩进规则。当从一个项目中提取一个工作功能来修复另一个项目中类似的区域时,请务必小心:生成的补丁可能充满了非功能性变化。这不仅会增加端口存储库的大小,还会使人们难以找到问题的原因以及到底发生了什么变化。
如果必须删除文件,请在 post-extract
目标中执行,而不是作为补丁的一部分。
4.4.2. 手动生成补丁
手动创建补丁通常没有必要。如本节前面所述的自动补丁生成是首选方法。但是,偶尔可能需要手动打补丁。 |
补丁保存到名为 patch-* 的文件中,其中 * 表示被修补的文件的路径名,例如 patch-Imakefile 或 patch-src-config.h。文件名不以 patch- 开头的补丁不会自动应用。
% diff -u file.orig file > patch-pathname-file
为新添加的文件生成补丁时,使用 -N
告诉 diff(1) 将不存在的原始文件视为存在但为空。
% diff -u -N newfile.orig newfile > patch-pathname-newfile
使用 diff(1) 的递归 (-r
) 选项来生成补丁是可以的,但请查看生成的补丁以确保其中没有不必要的垃圾。特别是,两个备份文件之间的差异,当端口使用 Imake
或 GNU configure
时 Makefile,等等,都是不必要的,必须删除。如果需要编辑 configure.in 并运行 autoconf
来重新生成 configure
,请不要进行 configure
的差异(它通常会增长到几千行!)。相反,定义 USES=autoreconf
并进行 configure.in 的差异。
4.4.3. 简单自动替换
可以使用 sed(1) 的就地模式直接从端口 Makefile 中执行简单的替换。当更改使用变量的值时,这很有用。
post-patch: @${REINPLACE_CMD} -e 's|/usr/local|${PREFIX}|g' ${WRKSRC}/Makefile
通常,被移植的软件在源文件中使用 CR/LF 约定。这可能会导致进一步的修补、编译器警告或脚本执行问题(例如 /bin/sh^M not found
)。要快速将所有文件从 CR/LF 转换为 LF,请将此条目添加到端口 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
可以设置转换的基目录。当有多个 distfile 且多个包含需要换行符转换的文件时,这很有用。
USES= dos2unix DOS2UNIX_WRKSRC= ${WRKDIR}
4.4.4. 条件打补丁
一些端口需要仅针对特定 FreeBSD 版本或启用或禁用特定选项时才应用的补丁。条件补丁通过将补丁文件的完整路径放在 EXTRA_PATCHES
中来指定。条件补丁文件名通常以 extra- 开头,尽管这不是必需的。但是,它们的文件名不能以 patch- 开头。如果它们这样做了,它们将被框架无条件地应用,这对条件补丁来说是不希望的。
.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>
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-* 的文件。
最后修改时间:2024 年 3 月 9 日,作者 Danilo G. Baio