> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/port/di-5-zhang-pei-zhi-makefile/5.2.-ming-ming.md).

# 5.2.命名

Port 的 **Makefile** 的第一部分命名 Port，描述其版本号，并将其列入正确的类别。

## 5.2.1. `PORTNAME`

将 `PORTNAME` 设置为软件的基础名称。它作为 FreeBSD 包的基础名称，并用于 [`DISTNAME`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-distname)。

> **重要**
>
> 包名称必须在整个 Ports 树中唯一。确保 `PORTNAME` 不被现有的 Port 使用，并且没有其他 Port 使用相同的 `PKGBASE`。如果该名称已被使用，可以添加 [`PKGNAMEPREFIX` 或 `PKGNAMESUFFIX`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#porting-pkgnameprefix-suffix)。

## 5.2.2. 版本，`DISTVERSION` *或* `PORTVERSION`

将 `DISTVERSION` 设置为软件的版本号。

`PORTVERSION` 是用于 FreeBSD 包的版本。它将自动从 `DISTVERSION` 推导出来，以便与 FreeBSD 的包版本方案兼容。如果版本中包含字母，可能需要设置 `PORTVERSION` 而不是 `DISTVERSION`。

> **重要**
>
> 一次只能设置 `PORTVERSION` 和 `DISTVERSION` 其中一个。

有时，某些软件使用的版本方案与 `DISTVERSION` 在 `PORTVERSION` 中的转换方式不兼容。

> **技巧**
>
> 在更新 Port 时，可以使用 [pkg-version(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html) 的 `-t` 参数检查新版本是否大于或小于之前的版本。请参阅下文了解如何使用 [pkg-version(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html) 比较版本。

**示例 1. 使用** [**pkg-version(8)**](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html) **比较版本**

`pkg version -t` 接受两个版本作为参数，如果第一个版本小于、等于或大于第二个版本，它会分别返回 `<`、`=` 或 `>`。

```sh
% pkg version -t 1.2 1.3
< ①
% pkg version -t 1.2 1.2
= ②
% pkg version -t 1.2 1.2.0
= ③
% pkg version -t 1.2 1.2.p1
> ④
% pkg version -t 1.2.a1 1.2.b1
< ⑤
% pkg version -t 1.2 1.2p1
< ⑥
```

* ① `1.2` 在 `1.3` 之前。
* ② `1.2` 和 `1.2` 相等，因为它们版本相同。
* ③ `1.2` 和 `1.2.0` 相等，因为零等同于没有。
* ④ `1.2` 在 `1.2.p1` 之后，因为 `.p1`，可以理解为“预发布 1”。
* ⑤ `1.2.a1` 在 `1.2.b1` 之前，可以理解为“alpha”和“beta”，`a` 在 `b` 之前。
* ⑥ `1.2` 在 `1.2p1` 之前，可以理解为“2，修补级别 1”，它是任何 `2.X` 后但在 `3` 之前的版本。

在这里，`a`、`b` 和 `p` 被用作“alpha”、“beta”或“预发布”和“修补级别”的缩写，但它们只是字母，按字母顺序排序，因此可以使用任何字母，它们将按适当的顺序排序。

**表 1. `DISTVERSION` 和派生的 `PORTVERSION` 示例**

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

**示例 2. 使用 `DISTVERSION`**

当版本号仅包含由点、破折号或下划线分隔的数字时，使用 `DISTVERSION`。

```makefile
PORTNAME=   nekoto
DISTVERSION=	1.2-4
```

这将生成 `PORTVERSION` 为 `1.2.4`。

**示例 3. 使用 `DISTVERSION` 当版本以字母或前缀开始**

当版本以字母、前缀或后缀（这些不是版本的一部分）开始或结束时，使用 `DISTVERSIONPREFIX`、`DISTVERSION` 和 `DISTVERSIONSUFFIX`。

如果版本是 `v1.2-4`：

```makefile
PORTNAME=   nekoto
DISTVERSIONPREFIX=  v
DISTVERSION=	1_2_4
```

有时，使用 GitHub 的项目会将其名称包含在版本中。例如，版本可能是 `nekoto-1.2-4`：

```makefile
PORTNAME=   nekoto
DISTVERSIONPREFIX=  nekoto-
DISTVERSION=	1.2_4
```

这些项目有时还会在版本末尾使用某些字符串，例如 `1.2-4_RELEASE`：

```makefile
PORTNAME=   nekoto
DISTVERSION=	1.2-4
DISTVERSIONSUFFIX=  _RELEASE
```

或者同时使用这两者，例如 `nekoto-1.2-4_RELEASE`：

```makefile
PORTNAME=   nekoto
DISTVERSIONPREFIX=  nekoto-
DISTVERSION=	1.2-4
DISTVERSIONSUFFIX=  _RELEASE
```

`DISTVERSIONPREFIX` 和 `DISTVERSIONSUFFIX` 在构建 `PORTVERSION` 时不会使用，只会用于 `DISTNAME`。

所有这些都会生成 `PORTVERSION` 为 `1.2.4`。

**示例 4. 使用 `DISTVERSION` 当版本包含字母表示 “alpha”、“beta” 或 “pre-release”**

当版本包含由点、破折号或下划线分隔的数字，且字母表示“alpha”、“beta” 或 “pre-release”（即，在没有字母的版本之前），使用 `DISTVERSION`。

```makefile
PORTNAME=   nekoto
DISTVERSION=	1.2-pre4
```

```makefile
PORTNAME=   nekoto
DISTVERSION=	1.2p4
```

这两者都会生成 `PORTVERSION` 为 `1.2.p4`，它在 1.2 之前。[pkg-version(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html) 可用于验证这一点：

```sh
% pkg version -t 1.2.p4 1.2
<
```

**示例 5. 不使用 `DISTVERSION` 当版本包含字母表示 “Patch Level”**

当版本包含字母，但这些字母不是表示“alpha”、“beta” 或 “pre”（而是表示“修补级别”），且表示的是在没有字母的版本之后，使用 `PORTVERSION`。

```makefile
PORTNAME=   nekoto
PORTVERSION=	1.2p4
```

在这种情况下，使用 `DISTVERSION` 是不可行的，因为它会生成 `1.2.p4` 的版本，这将排在 `1.2` 之前，而不是之后。[pkg-version(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html) 将验证这一点：

```sh
% pkg version -t 1.2 1.2.p4
> ①
% pkg version -t 1.2 1.2p4
< ②
```

* ① `1.2` 在 `1.2.p4` 之后，这在这种情况下是 *错误的*。
* ② `1.2` 在 `1.2p4` 之前，这是所需的。

对于一些更高级的设置 `PORTVERSION` 示例，当软件的版本管理方式与 FreeBSD 的版本方案不兼容，或者当分发文件本身不包含版本时，参见 [`DISTNAME`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-distname)。

## 5.2.3. `PORTREVISION` 和 `PORTEPOCH`

### 5.2.3.1. `PORTREVISION`

`PORTREVISION` 是一个单调递增的值，每次 `DISTVERSION` 增加时都会重置为 0，通常是在有新的官方供应商发布版本时。如果 `PORTREVISION` 非零，则该值会附加到包名中。`PORTREVISION` 的更改会被自动化工具（如 [pkg-version(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html)）用于确定新包是否可用。

每次对 Port 进行更改，且该更改以某种方式影响生成的包时，都必须增加 `PORTREVISION`。这包括仅影响具有非默认 [选项](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-options) 的包的更改。

以下是需要增加 `PORTREVISION` 的示例：

* 添加补丁以修复安全漏洞、错误或为 Port 添加新功能。
* 更改 Port 的 **Makefile** 以启用或禁用包中的编译时选项。
* 更改包的打包清单或安装时的行为。例如，修改生成初始数据的脚本，如 [ssh(1)](https://man.freebsd.org/cgi/man.cgi?query=ssh\&sektion=1\&format=html) 主机密钥。
* Port 的共享库依赖项版本更新（在这种情况下，用户在安装依赖项的新版本后尝试安装旧包将失败，因为它会查找旧的 libfoo.x 而不是 libfoo.(x+1)）。
* 对 Port 的分发文件进行的静默更改，且具有重要的功能差异。例如，对分发文件的更改需要更正 `distinfo`，但 `DISTVERSION` 没有相应改变，且 `diff -ru` 比较新旧版本显示代码有非平凡的差异。
* 更改 `MAINTAINER`。

以下是一些不需要增加 `PORTREVISION` 的更改示例：

* 对 Port 骨架的样式更改，没有影响最终包的功能。
* 更改 `MASTER_SITES` 或其他对 Port 的功能性更改，不会影响生成的包。
* 对分发文件进行微小的补丁，如拼写错误修正，其重要性不足以让用户费力升级。
* 构建修复，使得原本无法编译的包变得可编译。只要这些更改不会在以前能够构建的其他平台上引入功能性变化。由于 `PORTREVISION` 反映了包的内容，如果包之前无法构建，则不需要增加 `PORTREVISION` 来标记更改。

一个经验法则是判断提交到 Port 的更改是否会让某些人受益。不管是增强功能、修复问题，还是因为新包实际上能正常工作。然后，权衡这一点与这样一个事实，即这会导致所有定期更新 Ports 树的人被迫进行更新。如果是这样，就必须增加 `PORTREVISION`。

> **注意**
>
> 如果没有增加 `PORTREVISION`，使用二进制包的人 *永远* 看不到更新。没有增加 `PORTREVISION`，包构建器无法检测到更改，因此无法重建包。

### 5.2.3.2. `PORTEPOCH`

有时，软件供应商或 FreeBSD Port 维护者会做出一些不合逻辑的决定，发布一个实际上在数字上小于之前版本的版本。例如，Port 可能从 `foo-20000801` 更新为 `foo-1.0`（前者会被错误地视为更新版本，因为 `20000801` 在数字上大于 `1`）。

> **技巧**
>
> 版本号比较的结果并不总是显而易见的。可以使用 `pkg version`（请参见 [pkg-version(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-version\&sektion=8\&format=html)）来测试两个版本号字符串的比较。例如：
>
> ```sh
> % pkg version -t 0.031 0.29
> >
> ```
>
> `>` 输出表示版本 `0.031` 被认为大于版本 `0.29`，这一点可能对 Port 维护者来说并不显而易见。

在这种情况下，必须增加 `PORTEPOCH`。如果 `PORTEPOCH` 非零，它会像前述章节中描述的那样附加到包名中。`PORTEPOCH` 绝不能减少或重置为零，因为这样会导致与先前 epoch 的包比较时出现问题。例如，这个包将无法被检测为过时。尽管新版本号 `1.0,1` 在数字上仍小于之前的版本 `20000801`，但是 `,1` 后缀会被自动化工具特殊处理并被视为大于先前包中的 `,0` 后缀。

错误地丢弃或重置 `PORTEPOCH` 会导致不断的麻烦。如果上述讨论不够清晰，请参考 [FreeBSD ports 邮件列表](https://lists.freebsd.org/subscription/freebsd-ports)。

预计大多数 Port 不会使用 `PORTEPOCH`，通过合理使用 `DISTVERSION` 或谨慎使用 `PORTVERSION`，通常可以避免在软件的未来版本更改版本结构时需要使用 `PORTEPOCH`。然而，当供应商发布没有官方版本号的版本时（例如代码“快照”版本），FreeBSD Port 维护者需要特别小心。由于有时会将版本标记为发布日期，这会在新“官方”版本发布时引起问题，正如上面的例子所示。

例如，如果在 `20000917` 发布了一个快照版本，而该软件的先前版本是 `1.2`，则不应将 `20000917` 用作 `DISTVERSION`。正确的做法是使用 `1.2.20000917` 作为 `DISTVERSION`，或者类似的格式，这样后续版本（如 `1.3`）仍然是数字上更大的版本。

### 5.2.3.3. `PORTREVISION` 和 `PORTEPOCH` 使用示例

`gtkmumble` Port，版本 `0.10`，已提交到 Ports：

```makefile
PORTNAME=	gtkmumble
DISTVERSION=	0.10
```

`PKGNAME` 变为 `gtkmumble-0.10`。

发现了一个安全漏洞，需要一个本地的 FreeBSD 补丁。`PORTREVISION` 相应地增加。

```makefile
PORTNAME=	gtkmumble
DISTVERSION=	0.10
PORTREVISION=	1
```

`PKGNAME` 变为 `gtkmumble-0.10_1`

供应商发布了一个新版本，版本号为 `0.2`（事实证明作者实际上想要的是 `0.10` 代表 `0.1.0`，而不是“0.9 后的版本”——哎呀，现在已经太迟了）。由于新的次版本 `2` 在数字上小于之前的版本 `10`，必须增加 `PORTEPOCH` 来手动强制将新包检测为“更新的”。由于这是代码的新版本发布，`PORTREVISION` 被重置为 0（或从 **Makefile** 中删除）。

```makefile
PORTNAME=	gtkmumble
DISTVERSION=	0.2
PORTEPOCH=	1
```

`PKGNAME` 变为 `gtkmumble-0.2,1`

下一个版本是 0.3。由于 `PORTEPOCH` 不会减少，因此版本变量现在是：

```makefile
PORTNAME=	gtkmumble
DISTVERSION=	0.3
PORTEPOCH=	1
```

`PKGNAME` 变为 `gtkmumble-0.3,1`

> **注意**
>
> 如果在此升级中将 `PORTEPOCH` 重置为 `0`，那么安装了 `gtkmumble-0.10_1` 包的用户将无法检测到 `gtkmumble-0.3` 包为更新的版本，因为 `3` 仍然小于 `10`。记住，这正是 `PORTEPOCH` 的作用所在。

## 5.2.4. `PKGNAMEPREFIX` 和 `PKGNAMESUFFIX`

两个可选变量，`PKGNAMEPREFIX` 和 `PKGNAMESUFFIX`，与 `PORTNAME` 和 `PORTVERSION` 结合，形成 `PKGNAME`，其格式为 `${PKGNAMEPREFIX}${PORTNAME}${PKGNAMESUFFIX}-${PORTVERSION}`。确保它符合我们的[良好包名指南](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#porting-pkgname)。特别地，`PORTVERSION` 中不允许使用连字符（`-`）。此外，如果包名中有 *language-* 或 *-compiled.specifics* 部分（见下文），则分别使用 `PKGNAMEPREFIX` 和 `PKGNAMESUFFIX`，不要将它们作为 `PORTNAME` 的一部分。

## 5.2.5. 包命名规范

这些是命名包时要遵循的规范。目的是使包目录便于扫描，因为目前已经有成千上万个包，如果名称伤眼，用户会因此离开！

包名的格式为 **语言\_地区-名称-编译特性-版本号**

包名定义为 `${PKGNAMEPREFIX}${PORTNAME}${PKGNAMESUFFIX}-${PORTVERSION}`。确保设置变量以符合该格式。

**语言\_地区-** FreeBSD 力求支持其用户的母语。当 Port 专用于某种特定语言时，`语言-` 部分是该语言的 ISO-639 两个字母缩写。例如，`ja` 表示日语，`ru` 表示俄语，`vi` 表示越南语，`zh` 表示中文，`ko` 表示韩语，`de` 表示德语。

如果 Port 专用于某个特定地区的语言，则还应添加两位字母的国家代码。例如，`en_US` 表示美式英语，`fr_CH` 表示瑞士法语。

`语言-` 部分由 `PKGNAMEPREFIX` 设置。

**名称** 确保 Port 的名称和版本清晰地分开并放入 `PORTNAME` 和 `DISTVERSION` 中。`PORTNAME` 中包含版本部分的唯一原因是如果上游发行版确实是按该方式命名的，例如 [textproc/libxml2](https://cgit.freebsd.org/ports/tree/textproc/libxml2/) 或 [japanese/kinput2-freewnn](https://cgit.freebsd.org/ports/tree/japanese/kinput2-freewnn/) Port。否则，`PORTNAME` 中不能包含任何版本特定的信息。多个 Port 使用相同的 `PORTNAME` 是很常见的，就像 [www/apache\*](https://cgit.freebsd.org/ports/tree/www/apache*/) Port 那样；在这种情况下，使用 `PKGNAMEPREFIX` 和 `PKGNAMESUFFIX` 值来区分不同的版本（以及不同的索引条目）。

有一个传统，就是为 `Perl 5` 模块命名时，前面加上 `p5-`，并将双冒号分隔符转换为连字符。例如，`Data::Dumper` 模块变为 `p5-Data-Dumper`。

**-编译特性** 如果 Port 可以通过不同的 [硬编码默认值](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-masterdir) 来构建（通常是某个 Port 家族的目录名称的一部分），那么 `-编译特性` 部分表示已编译的默认值。连字符是可选的。示例包括纸张大小和字体单位。

`-编译特性` 部分由 `PKGNAMESUFFIX` 设置。

**-版本号** 版本字符串跟随一个连字符（`-`），并且是由整数和小写字母组成的由句点分隔的列表。特别地，版本字符串中不允许再有其他的连字符。唯一的例外是字符串 `pl`（表示“补丁级别”），只能在软件没有主版本号和次版本号时使用。如果软件版本中包含类似“alpha”，“beta”，“rc”或“pre”之类的字符串，则取其首字母并直接放在句点后。如果版本字符串在这些名称后继续，则数字紧跟在单个字母后，不会有额外的句点（例如，`1.0b2`）。

这样做的目的是为了便于通过版本字符串对 Port 进行排序。特别地，确保版本号的各个部分始终由句点分隔，如果日期是版本字符串的一部分，则使用 `dyyyy.mm.dd` 格式，而不是 `dd.mm.yyyy` 或不符合 Y2K 的 `yy.mm.dd` 格式。重要的是在版本前加上字母前缀，这里用 `d`（表示日期），以防发布带有实际版本号的版本时，其数值会小于 `yyyy`。

> **重要**
>
> 包名必须在整个 Ports 树中唯一，检查是否已经存在相同的 `PORTNAME`，如果存在，则添加 [`PKGNAMEPREFIX` 或 `PKGNAMESUFFIX`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#porting-pkgnameprefix-suffix) 之一。

以下是一些（真实的）示例，展示了如何将软件作者指定的名称转换为合适的包名。每行只设置了 `DISTVERSION` 或 `PORTVERSION` 其中一个，取决于在 Port 的 **Makefile** 中使用的是哪一个：

**表 2. 包命名示例**

| 发行版名称           | PKGNAMEPREFIX | PORTNAME | PKGNAMESUFFIX | DISTVERSION | PORTVERSION | 原因或备注                                    |
| --------------- | ------------- | -------- | ------------- | ----------- | ----------- | ---------------------------------------- |
| mule-2.2.2      | (空)           | mule     | (空)           | 2.2.2       |             | 无需更改                                     |
| mule-1.0.1      | (空)           | mule     | 1             | 1.0.1       |             | 这是 mule 的版本 1，版本 2 已经存在                  |
| EmiClock-1.0.2  | (空)           | emiclock | (空)           | 1.0.2       |             | 单个程序名不能使用大写字母                            |
| rdist-1.3alpha  | (空)           | rdist    | (空)           | 1.3alpha    |             | 版本将是 `1.3.a`                             |
| es-0.9-beta1    | (空)           | es       | (空)           | 0.9-beta1   |             | 版本将是 `0.9.b1`                            |
| mailman-2.0rc3  | (空)           | mailman  | (空)           | 2.0rc3      |             | 版本将是 `2.0.r3`                            |
| v3.3beta021.src | (空)           | tiff     | (空)           |             | 3.3         | 那到底是什么？                                  |
| tvtwm           | (空)           | tvtwm    | (空)           |             | p11         | 文件名中没有版本号，使用上游给出的版本号                     |
| piewm           | (空)           | piewm    | (空)           | 1.0         |             | 文件名中没有版本号，使用上游给出的版本号                     |
| xvgr-2.10pl1    | (空)           | xvgr     | (空)           |             | 2.10.pl1    | 在这种情况下，`pl1` 表示补丁级别，因此不能使用 `DISTVERSION` |
| gawk-2.15.6     | ja-           | gawk     | (空)           | 2.15.6      |             | 日语版本                                     |
| psutils-1.13    | (空)           | psutils  | -letter       | 1.13        |             | 在包构建时硬编码了纸张大小                            |
| pkfonts         | (空)           | pkfonts  | 300           | 1.0         |             | 300dpi 字体包                               |

如果原始源代码中完全没有版本信息，并且原作者不太可能发布另一个版本，则将版本字符串设置为 `1.0`（如上面 `piewm` 示例）。否则，询问原作者或使用源文件发布的日期字符串（`dyyyy.mm.dd`，或 `dyyyymmdd`）作为版本。

> **技巧**
>
> 可以使用任何字母。这里的 `d` 代表日期，如果源是 Git 仓库，通常使用 `g` 后跟提交日期，使用 `s` 表示快照也是常见的。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/port/di-5-zhang-pei-zhi-makefile/5.2.-ming-ming.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
