5.4 源码包文件

  在 Makefile 中的第二部分是描述用于联编 port 所必需下载的文件, 以及到什么地方去下载它们。

5.4.1 DISTVERSION/DISTNAME (源码包版本号/名称)

  DISTNAME 是作者称呼您所 port 软件的名字。 DISTNAME 的默认值是 ${PORTNAME}-${PORTVERSION}, 因此只有在需要时才应手工指定。 DISTNAME 只在两个地方用到。 第一处是源码包文件列表 (DISTFILES), 其默认值是 ${DISTNAME}${EXTRACT_SUFX}。 第二处是源码包应被展开到的目录名, 即 WRKSRC 所指定的目录, 其默认值是 work/${DISTNAME}

  某些软件作者发布源码包的时候并不采取 ${PORTNAME}-${PORTVERSION} 这样的模式, 这可以通过设置 DISTVERSION 来自动处理。 PORTVERSIONDISTNAME 会自动地展开, 当然, 也可以改掉它。 下表给出了一些例子:

DISTVERSION PORTVERSION
0.7.1d 0.7.1.d
10Alpha3 10.a3
3Beta7-pre2 3.b7.p2
8:f_17 8f.17

注意: PKGNAMEPREFIXPKGNAMESUFFIX 并不影响 DISTNAME。 此外还应注意 WRKSRC 等于 work/${PORTNAME}-${PORTVERSION}, 而源代码的压缩包则可能是 ${PORTNAME}-${PORTVERSION}${EXTRACT_SUFX} 以外的其它名字。 一般情况下应该保持 DISTNAME 不变 ── 更好的方法是定义 DISTFILES 而不是同时设置 DISTNAMEWRKSRC (可能还有 EXTRACT_SUFX)。

5.4.2 MASTER_SITES (主流下载站点)

  记录 FTP/HTTP-URL 指向 MASTER_SITES 中原始压缩档的目录部分。 不要忘了结尾的斜线 (/)!

  make 宏将尝试使用 FETCH 来抓取所指定的源码包文件, 如果无法在本地系统中找到这些文件的话。

  建议您指定多个镜像站点, 最好是在不同的大洲上的。 这样将有效地防止由于大范围网络问题所导致无法下载的问题。 我们甚至打算增加自动检测距离最近的站点并从那里下载的功能; 使用多个站点是这样做的重要一步。

  如果原始的源码包可以从比较流行的软件下载站点, 例如 SourceForge、 GNU 或是 Perl CPAN 等等来获得, 您可能会希望使用类似 MASTER_SITE_* 这样的缩写来表示它们 (例如 MASTER_SITE_SOURCEFORGEMASTER_SITE_GNU 以及 MASTER_SITE_PERL_CPAN)。 只需将 MASTER_SITES 设为这些变量, 并使用 MASTER_SITE_SUBDIR 来指定路径就可以了。 下面是一个例子:

MASTER_SITES=         ${MASTER_SITE_GNU}
MASTER_SITE_SUBDIR=   make

  此外, 您还可以用更为简略的格式:

MASTER_SITES=	GNU/make

  这些变量是在 /usr/ports/Mk/bsd.sites.mk 中定义的。 新项目会随时增加, 因此在您提交 port 之前, 应先看一看这个文件的最新版本。

  针对常用软件下载站的许多 暗黑魔法 宏, 还能够自动判断目录的结构。 对于这些站点, 只要使用与之对应的缩写, 系统便会自动为您生成相关的子目录配置。

MASTER_SITES=	SF

  如果系统猜测的路径不对, 则可以使用下面这样的配置来替换。

MASTER_SITES=	SF/stardict/WyabdcRealPeopleTTS/${PORTVERSION}

表 5-1. 常用的魔术 MASTER_SITES

自动猜测的子目录
APACHE_JAKARTA /dist/jakarta/${PORTNAME:S,-,,/,}/source
BERLIOS /${PORTNAME:L}
CHEESESHOP /packages/source/source/${DISTNAME:C/(.).*/\1/}/${DISTNAME:C/(.*)-[0-9].*/\1/}
DEBIAN /debian/pool/main/${PORTNAME:C/^((lib)?.).*$/\1/}/${PORTNAME}
GCC /pub/gcc/releases/${DISTNAME}
GNOME /pub/GNOME/sources/${PORTNAME}/${PORTVERSION:C/^([0-9]+\.[0-9]+).*/\1/}
GNU /gnu/${PORTNAME}
MOZDEV /pub/mozdev/${PORTNAME:L}
PERL_CPAN /pub/CPAN/modules/by-module/${PORTNAME:C/-.*//}
PYTHON /ftp/python/${PYTHON_PORTVERSION:C/rc[0-9]//}
RUBYFORGE /${PORTNAME:L}
SAVANNAH /${PORTNAME:L}
SF /project/${PORTNAME:L}/${PORTNAME:L}/${PORTVERSION}

5.4.3 EXTRACT_SUFX (压缩包所用的扩展名)

  如果您有一个源码包文件, 而它使用了某种怪异的扩展名来表达压缩方法, 应设置 EXTRACT_SUFX

  例如, 如果源码包文件的名字是 foo.tgz 而非更为一般的 foo.tar.gz, 您应写上:

DISTNAME=      foo
EXTRACT_SUFX=  .tgz

  USE_BZIP2USE_ZIP 变量会自动根据需要将 EXTRACT_SUFX 设置为 .tar.bz2.zip。 如果这两个都没设置, 则 EXTRACT_SUFX 的 默认值将是 .tar.gz

注意: 任何时候都不需要同时设置 EXTRACT_SUFXDISTFILES.

5.4.4 DISTFILES (全部源代码包)

  有些时候所下载的文件名字和 port 的名字没有任何联系。 例如, 可能是 source.tar.gz, 或者与此类似的其它名字。 也有一些其它的应用软件, 它们的源代码可能被存放到了不同的压缩包中, 而且全都需要下载。

  如果遇到这种情况, 可以将 DISTFILES 设置为以空格分隔的一组需要下载的文件列表。

DISTFILES=     source1.tar.gz source2.tar.gz

  如果没有予以明确的设置, DISTFILES 的默认值将是 ${DISTNAME}${EXTRACT_SUFX}

5.4.5 EXTRACT_ONLY (只解压缩部分源文件)

  如果只有一部分 DISTFILES 需要解压缩 ── 例如, 其中的一个是源代码, 而其它则是未压缩的文档 ── 此时应把那些需要解压缩的文件加到 EXTRACT_ONLY 中。

DISTFILES=     source.tar.gz manual.html
EXTRACT_ONLY=  source.tar.gz

  如果 DISTFILES没有 需要解压缩的文件, 则应将 EXTRACT_ONLY 设为空串。

EXTRACT_ONLY=

5.4.6 PATCHFILES (通过下载得到的补丁文件)

  如果您的 port 需要来自 FTP 或 HTTP 的一些额外的补丁, 应将 PATCHFILES 设置为这些文件的名字, 并将 PATCH_SITES 指向包含这些文件的目录的 URL (格式与 MASTER_SITES 相同)。

  如果这些补丁, 由于包含了其它的目录名, 而导致它们不是相对于源代码目录的顶级目录 (也就是 WRKSRC) 的话, 就需要相应地设置 PATCH_DIST_STRIP 了。 例如, 如果补丁中所有的目录名前面都有一个多余的 foozolix-1.0/, 就应设置 PATCH_DIST_STRIP=-p1

  不需要担心补丁文件本身是否是压缩的; 如果文件名以 .gz or .Z 结尾, 系统会自动解压缩。

  如果补丁是同某些其它文件, 例如文档, 一同以 gzip 压缩的 tar 格式发布的, 就不能简单地使用 PATCHFILES 了。 这种情况下, 您应将这些补丁包的文件和位置加入到 DISTFILESMASTER_SITES 中。 然后, 用 EXTRA_PATCHES 变量来指出这些文件, 这样 bsd.port.mk 就会自动地为您应用这些补丁了。 需要特别注意的是, 不要 将补丁文件复制到 PATCHDIR 目录中 ── 这个目录可能是不可写的。

注意: 压缩包会以同源代码一样的方式解压缩, 因此不需要自行完成解压缩操作, 并复制补丁文件。 如果您一定要这样做, 就要注意, 不要让解压缩出来的文件覆盖先前已经存在的文件。 此外, 这么做还需要手工增加命令, 以便在 pre-clean target 中删除这些复制出来的文件。

5.4.7 来自不同站点的多个源代码包或补丁文件 (MASTER_SITES:n)

  (这一节在某种程度上应被视作 “进阶话题”; 刚开始阅读这份文档的读者可能会希望先跳过这一部分)。

  这一节提供了被称作 MASTER_SITES:nMASTER_SITES_NN 的下载控制机制。 这里我们把它们称为 MASTER_SITES:n

  首先给出一些背景。 OpenBSD 在其 DISTFILESPATCHFILES 变量中提供了一个很棒的功能, 即, 允许这些文件和补丁拥有 :n 后缀, 其中 n 可以使用 [0-9], 来表达组。 例如:

DISTFILES=      alpha:0 beta:1

  在 OpenBSD 中, 源码包文件 alpha 应被关联到变量 MASTER_SITES0 而不是公共的 MASTER_SITES 变量上; 而 beta 则应关联到 MASTER_SITES1 上。

  这是一个很有意思的功能, 它可以避免无休止地搜索正确的下载站点的过程。

  想象 DISTFILES 中指定了 2 个文件, 而 MASTER_SITES 包含了 20 个站点的情形, 这其中许多站点慢如蜗牛, 而 beta 可以在 MASTER_SITES 的所有站点找到, 而 alpha 只能在第 20 个上面找到。 如果监护人了解这一点, 那么检查所有的站点无疑是在浪费时间, 不是吗? 这显然不是开始一个愉快周末的好办法!

  现在您有了一个感性的认识了, 想象一下 DISTFILES 和更多的 MASTER_SITES。 显然, 我们的 “distfiles 调查员先生” 会感谢您减少他浪费在等待下载上所耗费的时间。

  下一节中, 将按照 FreeBSD 对上述想法的实现来加以阐释。 我们对 OpenBSD 所提出的概念进行了一些改进。

5.4.7.1 简化信息

  这一节将介绍如何迅速地对从不同的站点以及子目录下载多个源码包和补丁进行精确的控制。 这里, 我们将描述 MASTER_SITES:n 的一种简化用法。 对于多数情况而言这样做是足够的。 然而, 如果您需要更多信息, 还需要参考下面的几节。

  一些应用程序需要从多个站点下载不同的源码包。 例如, Ghostscript 包括了程序核心本身, 以及大量的驱动文件, 以及则取决于用户的打印机品牌和型号的驱动程序。 某些驱动文件已经随程序核心附带, 但也有很多需要从其它站点下载。

  为了适应这种需要, 每一个 DISTFILES 项应跟随一个冒号, 以及一个 “标签名”。 在 MASTER_SITES 的每个站点也应跟随冒号和标签名, 以便指定从哪个网站下载源码包文件。

  例如, 考虑一个将源代码包分为两部分, 即 source1.tar.gzsource2.tar.gz 的软件, 它必须从两个不同的站点下载。 port 的 Makefile 应包括类似 例 5-1 的配置。

例 5-1. 简化的 MASTER_SITES:n 用法, 每个文件来自一个站点

MASTER_SITES=   ftp://ftp.example1.com/:source1 \
		ftp://ftp.example2.com/:source2
DISTFILES=      source1.tar.gz:source1 \
		source2.tar.gz:source2

  多个源码包可以使用同一个标签。 继续前面的例子, 假定增加了第三个源码包, source3.tar.gz, 应从 ftp.example2.com 下载。 Makefile 的这部分应写成 例 5-2 的样子。

例 5-2. 简化的 MASTER_SITES:n 用法, 其中同一个站点上提供了不止一个文件

MASTER_SITES=   ftp://ftp.example1.com/:source1 \
		ftp://ftp.example2.com/:source2
DISTFILES=      source1.tar.gz:source1 \
		source2.tar.gz:source2 \
		source3.tar.gz:source2

5.4.7.2 深入介绍

  前面的例子无法满足您的需求? 这一节, 我们将详细介绍 MASTER_SITES:n 的精细控制是如何工作的, 以及如何修改您的 port 来使用它们。

  1. 元素可以包含 :n 这样的后缀, 其中 n[^:,]+, 概念上即 n 可以取任意数字或字母, 但我们目前将其限定为 [a-zA-Z_][0-9a-zA-Z_]+

    此外, 字符串匹配时对大小写是敏感的; 换言之, nN 不同。

    但是, 由于表达特殊的意义, 下列单词不能用于后缀: defaultallALL (它们会在 ii 中介绍的部分用到)。 此外, DEFAULT 是一个有特殊用途的词 (请参见 3)。

  2. 后缀为 :n 的项目属于 n 组, 而 :m 属于 m 组, 依此类推。

  3. 没有后缀的元素是无组的, 也就是它们都属于那个特殊的 DEFAULT 组。 给元素加入 DEFAULT 后缀通常是多余的, 除非您有同时属于 DEFAULT 和其它组的元素 (参见 5)。

    下面的例子是等价的, 但通常应适用第一个:

    MASTER_SITES=   alpha
    
    MASTER_SITES=   alpha:DEFAULT
    
  4. 组之间不是互斥的, 同一元素可以同时隶属于多个组, 而组则可以为空或者有任意多个元素。 同一组中的重复元素, 并不会被自动消去。

  5. 如果希望同一元素同时属于多个组, 可以用逗号 (,) 分开。

    这种办法可以避免仅为指定不同的组而多次重复同一元素。 例如 :m,n,o 表示这个元素同时属于 mno 这三组。

    下面这些写法都是等价的, 但只推荐使用最后一种:

    MASTER_SITES=   alpha alpha:SOME_SITE
    
    MASTER_SITES=   alpha:DEFAULT alpha:SOME_SITE
    
    MASTER_SITES=   alpha:SOME_SITE,DEFAULT
    
    MASTER_SITES=   alpha:DEFAULT,SOME_SITE
    
  6. 同一组中的所有站点, 会根据 MASTER_SORT_AWK 排序。 在 MASTER_SITESPATCH_SITES 中的组也会进行排序。

  7. MASTER_SITESPATCH_SITESMASTER_SITE_SUBDIRPATCH_SITE_SUBDIRDISTFILES, 以及 PATCHFILES 中, 都可以使用组, 其语法为:

    1. 所有 MASTER_SITESPATCH_SITESMASTER_SITE_SUBDIR 以及 PATCH_SITE_SUBDIR 的元素, 都必须以 / 字符结尾。 如果有元素属于某些组, 则组后缀 :n 必须出现在终结符 / 之后。 MASTER_SITES:n 机制依赖于 / 的存在, 以避免在 :n 是元素一部分, 而 :n 同时又表示组 n 时发生混淆。 为了兼容性的考虑, 因为之前 / 终结符在 MASTER_SITE_SUBDIRPATCH_SITE_SUBDIR 元素中都不是必需的, 如果后缀所紧跟的字符不是 /, 则 :n 将被认为是元素的一部分, 而不被当作组后缀, 即使元素拥有 :n 后缀。 请参见 例 5-3 例 5-4 以了解进一步的细节。

      例 5-3. 在 MASTER_SITE_SUBDIRMASTER_SITES:n 的详细用法

      MASTER_SITE_SUBDIR=     old:n new/:NEW
      
      • DEFAULT 中的目录 -> old:n

      • NEW 中的目录 -> new

      例 5-4. 用到逗号分隔符、 多个文件, 多个站点和 不同子目录的 MASTER_SITES:n 详细用法

      MASTER_SITES=   http://site1/%SUBDIR%/ http://site2/:DEFAULT \
      		http://site3/:group3 http://site4/:group4 \
      		http://site5/:group5 http://site6/:group6 \
      		http://site7/:DEFAULT,group6 \
      		http://site8/%SUBDIR%/:group6,group7 \
      		http://site9/:group8
      DISTFILES=      file1 file2:DEFAULT file3:group3 \
      		file4:group4,group5,group6 file5:grouping \
      		file6:group7
      MASTER_SITE_SUBDIR=     directory-trial:1 directory-n/:groupn \
      			directory-one/:group6,DEFAULT \
      			directory
      

      前述的例子的结果是下述的对于下载行为的精细控制。 站点的列表按照使用的顺序给出。

      • file1 将从

        • MASTER_SITE_OVERRIDE

        • http://site1/directory-trial:1/

        • http://site1/directory-one/

        • http://site1/directory/

        • http://site2/

        • http://site7/

        • MASTER_SITE_BACKUP

        下载。

      • file2 将和 file1 以同样的方式下载, 因为它们属于同一组

        • MASTER_SITE_OVERRIDE

        • http://site1/directory-trial:1/

        • http://site1/directory-one/

        • http://site1/directory/

        • http://site2/

        • http://site7/

        • MASTER_SITE_BACKUP

      • file3 将从

        • MASTER_SITE_OVERRIDE

        • http://site3/

        • MASTER_SITE_BACKUP

        下载。

      • file4 将从

        • MASTER_SITE_OVERRIDE

        • http://site4/

        • http://site5/

        • http://site6/

        • http://site7/

        • http://site8/directory-one/

        • MASTER_SITE_BACKUP

        下载。

      • file5 将从

        • MASTER_SITE_OVERRIDE

        • MASTER_SITE_BACKUP

        下载。

      • file6 将从

        • MASTER_SITE_OVERRIDE

        • http://site8/

        • MASTER_SITE_BACKUP

        下载。

  8. 如何对来自 bsd.sites.mk 的特殊变量, 例如 MASTER_SITE_SOURCEFORGE 进行分组?

    参见 例 5-5

    例 5-5. MASTER_SITE_SOURCEFORGEMASTER_SITES:n 的详细用法

    MASTER_SITES=   http://site1/ ${MASTER_SITE_SOURCEFORGE:S/$/:sourceforge,TEST/}
    DISTFILES=      something.tar.gz:sourceforge
    

    something.tar.gz 将从所有 MASTER_SITE_SOURCEFORGE 中的站点下载。

  9. 如何与 PATCH* 变量连用?

    前面的例子介绍的都是 MASTER* 变量, 但对于 PATCH* 也是完全一样的, 它们在 例 5-6 有所介绍。

    例 5-6. 简化的 PATCH_SITES 中的 MASTER_SITES:n 用法。

    PATCH_SITES=    http://site1/ http://site2/:test
    PATCHFILES=     patch1:test
    

5.4.7.3 会改变 ports 的哪些行为? 哪些不会?

  1. 所有普通的 ports 的行为都会保持不变。 MASTER_SITES:n 功能的代码, 只有在某些元素包含了前述, 特别是 7 中所提及语法的 :n 后缀时, 才会启用。

  2. 不受影响的 port target: checksummakesumpatchconfigurebuild, 等等。 显然, do-fetchfetch-listmaster-sitespatch-sites 的行为会发生变化。

    • do-fetch: 会按照新的、 带有组后缀的 DISTFILESPATCHFILESMASTER_SITESPATCH_SITES 所匹配的组元素, 以及 MASTER_SITE_SUBDIRPATCH_SITE_SUBDIR 来进行。 请参见 例 5-4

    • fetch-list: 和旧式的 fetch-list 类似, 但以同 do-fetch 相似的方式处理组。

    • master-sitespatch-sites: (与旧版本不兼容) 仅返回组 DEFAULT 的元素; 事实上, 它们会执行 master-sites-defaultpatch-sites-default 这两个 target。

      更进一步, 使用 master-sites-allpatch-sites-all 这两个 target 之一, 要比直接检查 MASTER_SITESPATCH_SITES 更好。 此外, 未来版本可能不再保证直接检查能够正确工作。 请参见 iii.ii 以了解关于这些新 target 的更多技术细节。

  3. port 中的新 target

    1. 一系列 master-sites-npatch-sites-n target 可以分别用来列出 MASTER_SITESPATCH_SITES 中的 n 组的内容。 例如, master-sites-DEFAULTpatch-sites-DEFAULT 都会返回 DEFAULT 组的内容, 而 master-sites-testpatch-sites-test 则返回 test 组的内容, 等等。

    2. 新增的 master-sites-allpatch-sites-all 这两个 target, 会完成先前 master-sitespatch-sites 所做的工作。 它们会返回所有组的元素, 就像这些元素都属于同一组一样, 并且会列出与 MASTER_SITE_BACKUPMASTER_SITE_OVERRIDE 中在 DISTFILESPATCHFILES 中指定的同样多个; 分别对于 master-sites-allpatch-sites-all

5.4.8 DIST_SUBDIR (独立的源码包子目录)

  避免让您的 port 使 /usr/ports/distfiles 陷入混乱。 如果您的 port 需要下载很多文件, 或者需要下载可能与其它 port 的源文件名冲突的文件 (例如, Makefile), 则应将 DIST_SUBDIR 设置为 port 的名字 (通常可以用 ${PORTNAME}${PKGNAMEPREFIX}${PORTNAME})。 这将把 DISTDIR 从默认的 /usr/ports/distfiles 改为 /usr/ports/distfiles/DIST_SUBDIR, 并将与您的 port 有关的文件放到那个目录中。

  此外, 它也会在备份文件主服务器 ftp.FreeBSD.org 上查找同一子目录下的文件 (直接在您的 Makefile 中设置 DISTDIR 则不会有这样的效果, 因此您应使用 DIST_SUBDIR。)

注意: 这一设置并不影响您在 Makefile 中定义的 MASTER_SITES

5.4.9 ALWAYS_KEEP_DISTFILES (一直保存源码包)

  如果您的 port 采用的是预编译的包, 但却采用了某种要求源代码必须与预编译版本一同提供的授权, 例如 GPL, 则应使用 ALWAYS_KEEP_DISTFILES 来告诉 FreeBSD 联编集群保留一份在 DISTFILES 中文件的副本。 一般来说这些 port 的用户并不需要这些文件, 因此, 只在定义了 PACKAGE_BUILDING 符的时候, 才将源代码包文件加入 DISTFILES 是个好主意。

例 5-7. 如何使用 ALWAYS_KEEP_DISTFILES

.if defined(PACKAGE_BUILDING)
DISTFILES+=             foo.tar.gz
ALWAYS_KEEP_DISTFILES=  yes
.endif

  当您在 DISTFILES 加入其它文件时, 请务必确保这些文件也出现在了 distinfo 中。 此外, 这些额外的文件通常也会展开到 WRKDIR 中, 对于某些 ports, 这可能导致一些不希望的副作用, 因而需要进行特别的处理。

若您有关于 FreeBSD ports 系统的问题, 请发送电子邮件至 <ports@FreeBSD.org>。
关于此文档的任何问题, 请致函 <doc@FreeBSD.org>。