# 源码包文件

FreeBSD Porter 手册
上一页 | 第5章 　配置 Makefile | 下一页

# 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` 来自动处理。 `PORTVERSION` 和 `DISTNAME` 会自动地展开， 当然， 也可以改掉它。 下表给出了一些例子：

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

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

## 5.4.2 `MASTER_SITES` (主流下载站点)

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

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

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

如果原始的源码包是流行的软件， 例如 X-contrib、 GNU， 或 Perl CPAN 等等之一， 您可能会希望使用 `MASTER_SITE_`*`` (例如 `MASTER_SITE_XCONTRIB`、 `MASTER_SITE_GNU` 和 `MASTER_SITE_PERL_CPAN`) 来简化撰写。 简单地将 `MASTER_SITES` 设置为这些变量之一， 并使用 `MASTER_SITE_SUBDIR` 来指定路径就可以达到目的。 下面是一个例子：

    MASTER_SITES=         ${MASTER_SITE_XCONTRIB}
    MASTER_SITE_SUBDIR=   applications

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

用户也可以在他们的 `/etc/make.conf` 文件中自行设置 `MASTER_SITE_*` 变量， 以便让系统使用他们的选择， 从他们喜欢的镜像站点进行下载。

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

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

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

    DISTNAME=      foo
    EXTRACT_SUFX=  .tgz

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

> 注意: 任何时候都不需要同时设置 `EXTRACT_SUFX` 和 `DISTFILES`.

## 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` 了。 这种情况下， 您应将这些补丁包的文件和位置加入到 `DISTFILES` 和 `MASTER_SITES` 中。 然后， 用 `EXTRA_PATCHES` 变量来指出这些文件， 这样 `bsd.port.mk` 就会自动地为您应用这些补丁了。 需要特别注意的是， 不要 将补丁文件复制到 `PATCHDIR` 目录中 ── 这个目录可能是不可写的。

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

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

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

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

首先给出一些背景。 OpenBSD 在其 `DISTFILES` 和 `PATCHFILES` 变量中提供了一个很棒的功能， 即， 允许这些文件和补丁拥有 `: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.gz` 和 `source2.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_]+`。

   此外， 字符串匹配时对大小写是敏感的； 换言之， `n` 与 `N` 不同。

   但是， 由于表达特殊的意义， 下列单词不能用于后缀： `default`、 `all` 和 `ALL` (它们会在 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` 表示这个元素同时属于 `m`、 `n` 和 `o` 这三组。

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

       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_SITES` 和 `PATCH_SITES` 中的组也会进行排序。

7. 在 `MASTER_SITES`、 `PATCH_SITES`、 `MASTER_SITE_SUBDIR`、 `PATCH_SITE_SUBDIR`、 `DISTFILES`， 以及 `PATCHFILES` 中， 都可以使用组， 其语法为：

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

      例 5-3. 在 `MASTER_SITE_SUBDIR` 中 `MASTER_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_SOURCEFORGE` 中 `MASTER_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： `checksum`、 `makesum`、 `patch`、 `configure`、 `build`， 等等。 显然， `do-fetch`、 `fetch-list`、 `master-sites` 和 `patch-sites` 的行为会发生变化。

   - `do-fetch`： 会按照新的、 带有组后缀的 `DISTFILES` 和 `PATCHFILES` 在 `MASTER_SITES` 和 `PATCH_SITES` 所匹配的组元素， 以及 `MASTER_SITE_SUBDIR` 和 `PATCH_SITE_SUBDIR` 来进行。 请参见 例 5-4。

   - `fetch-list`： 和旧式的 `fetch-list` 类似， 但以同 `do-fetch` 相似的方式处理组。

   - `master-sites` 和 `patch-sites`： (与旧版本不兼容) 仅返回组 `DEFAULT` 的元素； 事实上， 它们会执行 `master-sites-default` 和 `patch-sites-default` 这两个 target。

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

3. port 中的新 target

   1. 一系列 `master-sites-`n`` 和 `patch-sites-`n`` target 可以分别用来列出 `MASTER_SITES` 和 `PATCH_SITES` 中的 `n` 组的内容。 例如， `master-sites-DEFAULT` 和 `patch-sites-DEFAULT` 都会返回 `DEFAULT` 组的内容， 而 `master-sites-test` 和 `patch-sites-test` 则返回 `test` 组的内容， 等等。

   2. 新增的 `master-sites-all` 和 `patch-sites-all` 这两个 target， 会完成先前 `master-sites` 和 `patch-sites` 所做的工作。 它们会返回所有组的元素， 就像这些元素都属于同一组一样， 并且会列出与 `MASTER_SITE_BACKUP` 或 `MASTER_SITE_OVERRIDE` 中在 `DISTFILES` 或 `PATCHFILES` 中指定的同样多个； 分别对于 `master-sites-all` 和 `patch-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， 这可能导致一些不希望的副作用， 因而需要进行特别的处理。

上一页 | 起始页 | 下一页
分类 | 上一级 | `MAINTAINER` (监护人)

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