# 5.10.依赖

许多 Port 依赖于其他 Port。这是大多数类 Unix 操作系统（包括 FreeBSD）的一项非常方便的功能。多个 Port 可以共享一个共同的依赖，而不是将该依赖项与每个需要它的 Port 或包捆绑在一起。有七个变量可以用来确保所有必要的组件都在用户的机器上。此外，还有一些常见情况的预支持依赖变量，以及一些其他控制依赖行为的变量。

> **重要**
>
> 当软件有额外的依赖项以提供额外的功能时，`*_DEPENDS` 中列出的基础依赖项应该包括那些对大多数用户有益的额外依赖项。基础依赖项不应是“最小”依赖集。目标不是包括所有可能的依赖项，只包括那些对大多数人有益的依赖项。

## 5.10.1. `LIB_DEPENDS`

此变量指定该 Port 依赖的共享库。它是一个 `<lib:dir>` 元组的列表，其中 `<lib>` 是共享库的名称，`<dir>` 是查找该库的目录，以防库不可用。例如：

```makefile
LIB_DEPENDS=   libjpeg.so:graphics/jpeg
```

将检查是否存在共享的 jpeg 库，并且如果找不到，将深入 **graphics/jpeg** 子目录以构建和安装该库。

该依赖项会被检查两次，第一次在 `build` 目标中，第二次在 `install` 目标中。此外，依赖项的名称会被放入包中，以便如果用户系统中没有该库，`pkg install`（参见 [pkg-install(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-install\&sektion=8\&format=html)）会自动安装它。

## 5.10.2. `RUN_DEPENDS`

此变量指定该 Port 在运行时依赖的可执行文件或文件。它是一个 `<path:dir>`\[:`<target>`] 元组的列表，其中 `<path>` 是可执行文件或文件的名称，`dir` 是查找它的目录，以防不可用，`target` 是该目录中的目标调用。如果 `<path>` 以斜杠（`/`）开头，它被视为文件，并使用 `test -e` 测试其是否存在；否则，它被视为可执行文件，并使用 `which -s` 检查程序是否存在于搜索路径中。

例如：

```makefile
RUN_DEPENDS=	${LOCALBASE}/news/bin/innd:news/inn \
		xmlcatmgr:textproc/xmlcatmgr
```

将检查文件或目录 **/usr/local/news/bin/innd** 是否存在，如果不存在，它将深入 **news/inn** 子目录以构建和安装该文件。它还会检查 `xmlcatmgr` 可执行文件是否存在于搜索路径中，如果不存在，它将深入 **textproc/xmlcatmgr** 子目录以构建和安装该文件。

> **注意**
>
> 在这种情况下，`innd` 实际上是一个可执行文件；如果可执行文件的位置不在预期的搜索路径中，可以使用完整路径。

> **注意**
>
> 在 Ports 构建集群中使用的官方搜索 `PATH` 是
>
> ```
> /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
> ```

该依赖项会在 `install` 目标中进行检查。此外，依赖项的名称会被放入包中，以便如果用户的系统中没有该文件或程序，`pkg install`（参见 [pkg-install(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-install\&sektion=8\&format=html)）会自动安装它。如果 `target` 部分与 `DEPENDS_TARGET` 相同，则可以省略该部分。

一个常见的情况是，当 `RUN_DEPENDS` 与 `BUILD_DEPENDS` 实际上是一样的，尤其是在 Ported 软件是用脚本语言编写的，或者它要求相同的构建和运行时环境时。在这种情况下，人们常常会直接将它们互相赋值：

```makefile
RUN_DEPENDS=	${BUILD_DEPENDS}
```

然而，这种赋值可能会污染运行时依赖项，使其包含原始 `BUILD_DEPENDS` 中未定义的条目。这是因为 [make(1)](https://man.freebsd.org/cgi/man.cgi?query=make\&sektion=1\&format=html) 对变量赋值的懒惰求值。考虑一个包含 `USE_*` 的 **Makefile**，这些变量由 **ports/Mk/bsd.\*.mk** 处理，用来增强初始构建依赖项。例如，`USES= gmake` 会将 [devel/gmake](https://cgit.freebsd.org/ports/tree/devel/gmake/) 添加到 `BUILD_DEPENDS` 中。为了防止这些额外的依赖项污染 `RUN_DEPENDS`，可以创建另一个变量，将 `BUILD_DEPENDS` 的当前内容赋值给它，并将其赋给 `BUILD_DEPENDS` 和 `RUN_DEPENDS`：

```makefile
MY_DEPENDS=	some:devel/some \
		other:lang/other
BUILD_DEPENDS=	${MY_DEPENDS}
RUN_DEPENDS=	${MY_DEPENDS}
```

> **重要**
>
> *不要*使用 `:=` 将 `BUILD_DEPENDS` 赋值给 `RUN_DEPENDS` 或反之。所有变量都会立即展开，这是完全错误的做法，几乎总是会失败。

## 5.10.3. `BUILD_DEPENDS`

此变量指定该 Port 构建时所需的可执行文件或文件。与 `RUN_DEPENDS` 类似，它是 `<path:dir>`\[:`<target>`] 元组的列表。例如：

```makefile
BUILD_DEPENDS=	unzip:archivers/unzip
```

将检查是否存在名为 `unzip` 的可执行文件，如果找不到，它将深入 **archivers/unzip** 子目录以构建和安装该文件。

> **注意**
>
> 这里的“build”指的是从提取到编译的整个过程。该依赖项会在 `extract` 目标中进行检查。如果 `target` 部分与 `DEPENDS_TARGET` 相同，则可以省略该部分。

## 5.10.4. `FETCH_DEPENDS`

此变量指定该 Port 在获取时所需的可执行文件或文件。与前两个类似，它是 `<path:dir>`\[:`<target>`] 元组的列表。例如：

```makefile
FETCH_DEPENDS=	ncftp2:net/ncftp2
```

将检查是否存在名为 `ncftp2` 的可执行文件，如果找不到，它将深入 **net/ncftp2** 子目录以构建和安装该文件。

该依赖项会在 `fetch` 目标中进行检查。如果 `target` 部分与 `DEPENDS_TARGET` 相同，则可以省略该部分。

## 5.10.5. `EXTRACT_DEPENDS`

此变量指定该 Port 在提取时所需的可执行文件或文件。与前面类似，它是 `<path:dir>`\[:`<target>`] 元组的列表。例如：

```makefile
EXTRACT_DEPENDS=	unzip:archivers/unzip
```

将检查是否存在名为 `unzip` 的可执行文件，如果找不到，它将深入 **archivers/unzip** 子目录以构建和安装该文件。

该依赖项会在 `extract` 目标中进行检查。如果 `target` 部分与 `DEPENDS_TARGET` 相同，则可以省略该部分。

> **注意**
>
> 仅在提取操作无法正常工作时使用此变量（默认假定使用 `tar`）。如果提取操作无法通过 `USES=tar`、`USES=lha` 或 `USES=zip`（参见 [使用 `USES` 宏](https://docs.freebsd.org/en/books/porters-handbook/uses/#uses)）来解决，则使用此变量。

## 5.10.6. `PATCH_DEPENDS`

此变量指定该 Port 在打补丁时所需的可执行文件或文件。与前面一样，它是 `<path:dir>`\[:`<target>`] 元组的列表。例如：

```makefile
PATCH_DEPENDS=	${NONEXISTENT}:java/jfc:extract
```

将深入 **java/jfc** 子目录提取该文件。

该依赖项会在 `patch` 目标中进行检查。如果 `target` 部分与 `DEPENDS_TARGET` 相同，则可以省略该部分。

## 5.10.7. `USES`

可以通过添加参数来定义 Port 使用的不同特性和依赖项。通过在 **Makefile** 中添加以下行来指定：

```makefile
USES= feature[:arguments]
```

有关完整的值列表，请参见 [使用 `USES` 宏](https://docs.freebsd.org/en/books/porters-handbook/uses/#uses)。

> **重要**
>
> `USES` 不能在包含 **bsd.port.pre.mk** 后进行赋值。

## 5.10.8. `USE_*`

有多个变量可以定义许多 Port 共享的常见依赖项。它们是可选的，但有助于减少 Port **Makefile** 中的冗长。每个变量以 `USE_*` 的形式存在。这些变量只能在 Port **Makefile** 和 **ports/Mk/bsd.\*.mk** 中使用。它们不用于用户设置的选项——请使用 `PORT_OPTIONS` 来设置。

> **注意**
>
> 在 **/etc/make.conf** 中设置任何 `USE_*` 是 *始终* 不正确的。例如，设置
>
> ```
> USE_GCC=X.Y
> ```
>
> （其中 X.Y 是版本号）将为每个 Port（包括 `lang/gccXY` 本身）添加对 gccXY 的依赖！

**表 8. `USE_*`**

<table><thead><tr><th>变量</th><th>说明</th></tr></thead><tbody><tr><td><code>USE_GCC</code></td><td><p>该 Port 需要 GCC (<code>gcc</code> 或 <code>g++</code>) 来构建。一些 Port 需要特定的旧版本 GCC，一些 Port 需要现代的、较新的版本。通常设置为 <code>yes</code>（意味着始终使用来自 Port 的稳定、现代 GCC，参见 <code>GCC_DEFAULT</code> 在 <strong>Mk/bsd.default-versions.mk</strong> 中）。这也是默认值。也可以指定确切版本，例如 <code>10</code>。当基本系统的 GCC 满足请求的版本时，使用它，否则会从 Port 构建合适的编译器，并相应地调整 <code>CC</code> 和 <code>CXX</code>。版本说明符后面的 <code>:build</code> 参数仅为 Port 添加构建时依赖。</p><p>例如：</p><pre><code>USE_GCC=yes		#  Port 需要当前版本的
</code></pre><pre><code> GCC USE_GCC=11:build	  #  Port 仅在构建时需要 GCC 11
</code></pre><blockquote><p><strong>注意</strong><br><code>USE_GCC=any</code> 已被弃用，不应在新 Port 中使用</p></blockquote></td></tr></tbody></table>

与 gmake 和 **configure** 相关的变量在 [构建机制](https://docs.freebsd.org/en/books/porters-handbook/special/#building) 中有描述，而 autoconf、automake 和 libtool 在 [使用 GNU Autotools](https://docs.freebsd.org/en/books/porters-handbook/special/#using-autotools) 中有描述。与 Perl 相关的变量在 [使用 Perl](https://docs.freebsd.org/en/books/porters-handbook/special/#using-perl) 中有描述。X11 相关的变量列在 [使用 X11](https://docs.freebsd.org/en/books/porters-handbook/special/#using-x11) 中。[使用 GNOME](https://docs.freebsd.org/en/books/porters-handbook/special/#using-gnome) 讨论了 GNOME，而 [使用 KDE](https://docs.freebsd.org/en/books/porters-handbook/special/#using-kde) 讨论了与 KDE 相关的变量。[使用 Java](https://docs.freebsd.org/en/books/porters-handbook/special/#using-java) 记录了 Java 相关变量，而 [Web 应用程序](https://docs.freebsd.org/en/books/porters-handbook/special/#using-php) 中包含了关于 Apache、PHP 和 PEAR 模块的信息。Python 在 [使用 Python](https://docs.freebsd.org/en/books/porters-handbook/special/#using-python) 中讨论，Ruby 在 [使用 Ruby](https://docs.freebsd.org/en/books/porters-handbook/special/#using-ruby) 中讨论。[使用 SDL](https://docs.freebsd.org/en/books/porters-handbook/special/#using-sdl) 提供了用于 SDL 应用程序的变量，最后，[使用 Xfce](https://docs.freebsd.org/en/books/porters-handbook/special/#using-xfce) 包含了有关 Xfce 的信息。

## 5.10.9. 依赖项的最小版本

可以使用以下语法在任何 `*_DEPENDS` 中指定依赖项的最小版本，`LIB_DEPENDS` 除外：

```makefile
p5-Spiffy>=0.26:devel/p5-Spiffy
```

第一个字段包含一个依赖包名称，它必须与包数据库中的条目匹配，后跟一个比较符号和一个包版本。依赖项得到满足的条件是机器上安装了 p5-Spiffy-0.26 或更高版本。

## 5.10.10. 依赖项说明

如上所述，调用依赖项时的默认目标是 `DEPENDS_TARGET`，默认为 `install`。这是一个用户变量；它从未在 port 的 **Makefile** 中定义。如果 port 需要以特殊方式处理依赖项，可以使用 `*_DEPENDS` 的 `:target` 部分，而不是重新定义 `DEPENDS_TARGET`。

在运行 `make clean` 时，port 依赖项也会自动清理。如果不希望这样，可以在环境中定义 `NOCLEANDEPENDS`。如果 port 的依赖列表中包含需要较长时间重建的内容，如 KDE、GNOME 或 Mozilla，这可能特别有用。

要无条件地依赖另一个 port，可以在 `BUILD_DEPENDS` 或 `RUN_DEPENDS` 的第一个字段中使用变量 `${NONEXISTENT}`。仅当需要另一个 port 的源代码时，才使用此方法。通过指定目标也可以节省编译时间。例如：

```makefile
BUILD_DEPENDS=	${NONEXISTENT}:graphics/jpeg:extract
```

这将始终进入 `jpeg` port 并提取它。

## 5.10.11. 循环依赖是致命的

> **重要**
>
> 不要在 Ports 树中引入任何循环依赖！

Ports 构建技术不容忍循环依赖。如果引入了循环依赖，某个地方的 FreeBSD 安装几乎会立即崩溃，接着许多人会受到影响。这些依赖很难发现。如果有疑虑，在做出更改之前，请确保运行：`cd /usr/ports; make index`。该过程在旧机器上可能会很慢，但它可能在过程中为很多人，包括你自己，节省不少麻烦。

## 5.10.12. 自动依赖引起的问题

依赖项必须显式声明或使用 [OPTIONS 框架](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-options) 声明。使用自动检测等其他方法会使索引变得复杂，从而导致 port 和包管理的问题。

**示例 37. 错误的可选依赖声明**

```makefile
.include <bsd.port.pre.mk>

.if exists(${LOCALBASE}/bin/foo)
LIB_DEPENDS=	libbar.so:foo/bar
.endif
```

自动添加依赖的问题在于，单个 port 外的文件和设置随时可能发生变化。例如：索引已构建，然后安装了一批 ports。但其中一个 port 安装了被测试的文件。此时，索引变得不正确，因为一个已安装的 port 突然有了新的依赖项。如果其他 ports 也基于其他文件的存在来确定其依赖性，重建索引后它可能依然是错误的。

**示例 38. 正确的可选依赖声明**

```makefile
OPTIONS_DEFINE=	BAR
BAR_DESC=	Calling cellphones via bar

BAR_LIB_DEPENDS=	libbar.so:foo/bar
```

测试选项变量是正确的方法。只要选项在构建索引之前已定义，就不会导致批量 ports 的索引不一致。然后可以使用简单的脚本来自动化这些 ports 及其包的构建、安装和更新。


---

# Agent Instructions: 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:

```
GET https://porters-handbook.bsdcn.org/di-5-zhang-pei-zhi-makefile/5.10.-yi-lai.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
