5.2 第三方软件

供稿:Poul-Henning Kamp、 David O'Brien 和 Gavin Atkinson. 翻译:李 鑫.

  FreeBSD 的发行版中, 可能有某些部分包含在 FreeBSD 项目之外活跃地维护着的软件。 由于历史原因, 我们将其称为 contributed 软件。 举例说来, 有 sendmailgccpatch 等等。

  在过去几年中, 我们尝试了许多不同的方法来处理这类软件, 这些方法都各有利弊, 因而也就没有明确的胜者。

  基于这种情况, 在经历了一些争吵之后, 我们选定了一种作为在未来引入此类软件的 “官方” 做法。 更进一步, 我们强烈建议已有的第三方软件都逐渐过渡到使用这种方法, 因为与先前使用的做法相比, 它具有十分明显的优越性, 例如, 取得与其他软件作者 (即使没有提供直接的代码库访问权) “官方” 版本之间的差异会更容易, 等等。 这会使得将修正内容回馈给第三方软件的主要开发者变得非常容易。

  当然, 最终这些方法是需要由具体的人来落实的。 如果这一模式十分不适于某个具体的软件包, 则在得到 core team 以及其他开发者认可的前提下, 可以适当地进行例外处理。 是否能够持续维护第三方软件包, 则是进行这类决策的关键因素。

注意: 由于 RCS 文件格式, 以及 vendor 分支使用上的一些不当设计, 强烈建议不要 进行任何小规模的代码修饰性的修改。 类似 “拼写错误” 这样的问题, 就属于前面提到的 “修饰性” 修改一类, 应该尽一切可能避免。 不恰当地修改一个字符, 都有可能会使代码库产生严重的膨胀。

5.2.1 在 CVS 中的 Vendor 汇入过程

  用于检查文件格式的 file 工具, 在这里将作为如何进行这些操作的范例:

  src/contrib/file 目录中包含了由软件包作者发布的代码。 完全不适于 FreeBSD 的那些部分可以完全删去。 对于 file(1) 而言, 在导入之前就可以删去 python 目录, 以及包含 lt 前缀的文件, 等等。

  src/lib/libmagic 包含了 bmake 风格的使用标准 bsd.lib.mk makefile 规则的 Makefile 来联编函数库, 并安装文档。

  src/usr.bin/file 包含了 bmake 风格的使用标准 bsd.prog.mk 规则的 Makefile, 能够联编并安装 file 程序, 以及与之相关的联机手册。

  这里比较重要的事情是, src/contrib/file 目录是按照一定的规则创建的: 其中包含的源代码与原作者发布的相同 (也就是说, 这些文件会放到 vendor 分支上, 并且不进行 RCS 关键字扩展), 而只做尽可能少的专属于 FreeBSD 的改动。 如果对此有任何疑问, 则一定要先询问一下有经验的人, 而不要在对它能 “正常运转” 的期望中铸成大错。

  由于前面提到的那些关于 vendor 分支设计的制约, 我们要求来自软件原作者的 “官方” 补丁, 必须首先打在其分发的源代码之上, 然后再将修改过的代码重新导入到 vendor 分支。 官方补丁在任何时候, 都不应直接应用于从 FreeBSD 源代码库检出的源代码, 并执行 “commit” 操作, 因为这会破坏 vendor 分支的一致性, 并且, 由于这样的操作会导致产生修改冲突, 会给未来导入新版时带来麻烦。

  由于许多软件包可能会包含用于 FreeBSD 以外的体系结构和环境的文件, 我们允许在导入前从官方发行的代码中删去那些对 FreeBSD 无用的部分, 以期节省磁盘空间。 包含版权声明和发行说明, 以及其他类似的用于说明其他文件的文档, 则 应删除。

  如果方便的话, 应尽可能使用使用某些工具生成的 bmake Makefile 文件, 这些工具可以使升级到未来的新版本时的工作变得简单。 如果您完成了这类工作, 请务必将这些工具 (如果需要的话) 放到 src/tools 目录中与您所移植的程序对应的目录中, 以便为将来的维护者所利用。

  在 src/contrib/file 的顶级目录中, 应增加一个名为 FREEBSD-upgrade 的文件, 在其中说明一些类似下面的内容:

  下面是来自 src/contrib/groff/FREEBSD-upgrade 的例子:

$FreeBSD: src/contrib/groff/FREEBSD-upgrade,v 1.5.12.1 2005/11/15 22:06:18 ru Exp $

This directory contains virgin copies of the original distribution files
on a "vendor" branch.  Do not, under any circumstances, attempt to upgrade
the files in this directory via patches and a cvs commit.

To upgrade to a newer version of groff, when it is available:
    1. Unpack the new version into an empty directory.
       [Do not make ANY changes to the files.]

    2. Use the command:
        cvs import -m 'Virgin import of FSF groff v<version>' \
            src/contrib/groff FSF v<version>

       For example, to do the import of version 1.19.2, I typed:
        cvs import -m 'Virgin import of FSF groff v1.19.2' \
            src/contrib/groff FSF v1_19_2

    3. Follow the instructions printed out in step 2 to resolve any
       conflicts between local FreeBSD changes and the newer version.

Do not, under any circumstances, deviate from this procedure.

To make local changes to groff, simply patch and commit to the main
branch (aka HEAD).  Never make local changes on the FSF branch.

All local changes should be submitted to Werner Lemberg <wl@gnu.org> or 
Ted Harding <ted.harding@nessie.mcc.ac.uk> for inclusion in the next
vendor release.

ru@FreeBSD.org - 20 October 2005

  还有另一种方法来列出需要排除在汇入过程之外的文件, 如果需要排除的文件很多或很复杂, 或者经常要汇入的话, 这种方法会更加实用。 通过在汇入源代码的 vendor 源代码目录中加入 FREEBSD-Xlist, 并在其中逐行列出需要排除的文件名模式, 未来的汇入过程, 便可以通过下列操作来完成:

% tar -X FREEBSD-Xlist -xzf vendor-source.tgz

  下面的示范 FREEBSD-Xlist 文件来自 src/contrib/tcsh

*/BUGS
*/config/a*
*/config/bs2000
*/config/bsd
*/config/bsdreno
*/config/[c-z]*
*/tests
*/win32

注意: 不要将 FREEBSD-upgradeFREEBSD-Xlist 在汇入的过程中掺进第三方的源代码。 您应在首次汇入之后手工添加这些文件。

5.2.2 SVN 中的 Vendor 汇入过程

作者 Dag-Erling Smørgrav.

  这一节介绍了在使用 Subversion 时汇入第三方软件的详细过程。

  1. 准备源代码目录

    如果这是转到 SVN 之后的首次汇入操作, 您应首先将 vendor 代码目录扁平化, 并在主目录中开始创建合并历史。 假如这不是首次汇入, 则可以略过这一步。

    在将 CVS 转到 SVN 的过程中, vendor 分支以与主代码树相同的格局引入。 例如, foo 的 vendor 源代码, 会位于 vendor/foo/dist/contrib/foo, 但这不仅没有道理, 而且也很不方便。 我们希望的是将 vendor 源代码直接放在 vendor/foo/dist, 类似这样:

    % cd vendor/foo/dist/contrib/foo
    % svn move $(svn list) ../..
    % cd ../..
    % svn remove contrib
    % svn propdel -R svn:mergeinfo
    % svn commit
    

    请注意, propdel 这部分是必要的, 因为从 Subversion 1.5 开始, 在复制或移动目录时, 会自动添加 svn:mergeinfo 到对应的目录上。 在这种用法中, 并不需要保留这些信息, 因为您不会从删除的目录中再合并什么东西过来了。

    注意: 您也可以用同样的方法来将 tag 也扁平化。 具体操作过程完全一样。 如果需要这样做, 请将所有的 commit 操作积攒到最后, 一次进行。

    检查 dist 目录, 并进行必要的清理工作。 您可能会希望禁用关键词扩展, 因为这对未作修改的 vendor 代码来说是没有必要的。 有些时候, 关键词扩展甚至可能是有害的。

    % svn propdel svn:keywords -R .
    % svn commit
    

    此外, 在汇入新的代码之前, 还需要在目标目录 (主代码目录) 中创建 svn:mergeinfo, 将前一次在 vendor 代码基础上所作的改动标示出来:

    % cd head/contrib/foo
    % svn merge --record-only svn_base/vendor/foo/dist@12345678 .
    % svn commit
    

    此处 svn_base 是您 SVN 代码库的根目录, 例如 svn+ssh://svn.FreeBSD.org/base

  2. 汇入新的源代码

    准备完整的、 经过清理的 vendor 源代码。 采用 SVN 以后, 我们可以保持完整的发行包, 而不致引起主代码树的膨胀。 导入全部代码, 但只合并用到的那些就可以了。

    注意, 您需要将在上次汇入操作之后增加的文件添加进来, 并删除那些原作者在新版中删除的文件。 要完成这项工作, 您需要准备一份内容为 vendor 代码树, 以及一份将要汇入的源代码树中文件的有序列表:

    % cd vendor/foo/dist
    % svn list -R | grep -v '/$' | sort > ../old
    % cd ../foo-9.9
    % find . -type f | cut -c 3- | sort > ../new
    

    有了这两个文件, 下列命令就能列出删除的文件了 (那些只在 old 中出现的文件):

    % comm -23 ../old ../new
    

    而下列命令则可以显示新增的文件 (只存在于 new 的文件):

    % comm -13 ../old ../new
    

    总结一下:

    % cd vendor/foo/foo-9.9
    % tar cf - . | tar xf - -C ../dist
    % cd ../dist
    % comm -23 ../old ../new | xargs svn remove
    % comm -13 ../old ../new | xargs svn add
    

    警告: 如果新版软件包中有新目录, 最后一个命令会失败。 您必须手工添加这些目录并重新执行那个命令。 类似地, 如果有目录被删掉, 也需要手工干预。

    检查新文件上的属性:

    • 所有文本文件的 svn:eol-style 都应设为 native

    • 所有二进制文件的 svn:mime-type 都应设为 application/octet-stream, 除非有更合适的多媒体类型。

    • 可执行文件的 svn:executable 应设为 *

    • 除此之外, 目录中的文件不应具有任何其他属性。

    注意: 现在可以进行 commit 操作了, 但在此之前, 还应再次检查 svn statsvn diff 的输出, 以确保一切正常。

    一旦完成了将新的 vendor 版本 commit 到代码库中的操作, 就应立即对其进行 tag, 以便于日后参考。 最佳也是最快的操作方法, 是直接在代码库上进行:

    % svn copy svn_base/vendor/foo/dist svn_base/vendor/foo/9.9
    

    要获得新的 tag, 可以在当前 vendor/foo 的工作副本上执行更新 (update) 操作。

    注意: 如果您在签出 (checkout) 的版本上执行了复制操作, 不要忘记像前面那样删去 svn:mergeinfo 元数据。

  3. 合并到 -HEAD

    准备好汇入之后, 就可以开始合并了。 选项 --accept=postpone 会告诉 SVN 暂时不要合并冲突, 因为这将在稍后手工进行:

    % cd head/contrib/foo
    % svn update
    % svn merge --accept=postpone svn_base/vendor/foo/dist
    

    接着解决本地修改与官方修改之间的冲突, 并确保官方版本添加或删除的文件在主代码树中也对应地添加或删除了。 检查与官方版本之间的差异是个好习惯:

    % svn diff --no-diff-deleted --old=svn_base/vendor/foo/dist --new=.
    

    选项 --no-diff-deleted 的意思是让 SVN 不要检查那些只在官方代码树中出现, 而没有在主代码树中出现的文件。

    注意: 使用 SVN 时是没有 vendor 分支这样的概念的。 如果某个文件先前有过本地变动, 而现在没有了, 只需简单地删除掉剩余的那些东西, 例如 FreeBSD 版本标记就可以了。 这样一来, 这些文件就不会再出现在与官方代码树之间的差异中。

    如果所作的变动需要联编 world 的话, 现在就做 ── 并测试到您确认全部联编通过, 且能够正常运行为止。

  4. 签入 (commit)

    现在可以签入变动了。 请确保一次完成全部工作。 理想状态下, 您应在没有做过任何变动的代码树基础上进行工作, 这样可以直接在树的最顶部执行签入操作。 这种方法能最好地避免出现问题。 如果操作正确, 代码树会从旧代码所构成的一致状态原子地转移到新代码构成的一致状态。

本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.