> 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.14.makefile-can-shu.md).

# 5.14.Makefile 参数

许多应用程序可以通过可选或不同的配置进行构建。示例包括选择自然（人类）语言、图形界面与命令行界面，或支持的数据库类型。用户可能需要不同于默认配置的版本，因此 Ports 系统提供了钩子，Port 作者可以使用这些钩子来控制构建哪种变体。正确支持这些选项能让用户满意，相当于以一个 Port 的代价提供了两个或更多 Port。

## 5.14.1. `OPTIONS`

### 5.14.1.1. 背景

`OPTIONS_*` 向安装 Port 的用户显示对话框，展示可用的选项，然后将这些选项保存到 **${PORT\_DBDIR}/${OPTIONS\_NAME}/options**。下一次构建该 Port 时，将重用这些选项。`PORT_DBDIR` 默认值为 **/var/db/ports**。`OPTIONS_NAME` 是 Port 来源的名称，使用下划线作为空格分隔符，例如，对于 [dns/bind99](https://cgit.freebsd.org/ports/tree/dns/bind99/) 来说，它将是 `dns_bind99`。

当用户运行 `make config`（或首次运行 `make build`）时，框架会检查 **${PORT\_DBDIR}/${OPTIONS\_NAME}/options**。如果该文件不存在，将使用 `OPTIONS_*` 的值，并显示对话框，供用户启用或禁用选项。然后保存 **options**，构建 Port 时使用配置好的变量。

如果新版本的 Port 添加了新的 `OPTIONS`，会向用户展示该对话框，并预填旧 `OPTIONS` 的保存值。

`make showconfig` 显示保存的配置。使用 `make rmconfig` 可以移除保存的配置。

### 5.14.1.2. 语法

`OPTIONS_DEFINE` 包含要使用的 `OPTIONS` 列表。这些选项是独立的，彼此之间没有分组：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2
```

定义后，`OPTIONS` 应该进行描述（可选，但强烈推荐）：

```makefile
OPT1_DESC=	描述 OPT1
OPT2_DESC=	描述 OPT2
OPT3_DESC=	描述 OPT3
OPT4_DESC=	描述 OPT4
OPT5_DESC=	描述 OPT5
OPT6_DESC=	描述 OPT6
```

**ports/Mk/bsd.options.desc.mk** 包含许多常见 `OPTIONS` 的描述。虽然通常有用，但如果描述不充分，可以覆盖这些描述。

> **技巧**
>
> 在描述选项时，要从用户的角度来看待：“它改变了什么功能？”和“为什么我要启用这个？”不要只是重复名称。例如，描述 `NLS` 选项为“包含 NLS 支持”并不能帮助用户，用户已经可以看到选项名称，但可能不知道它是什么意思。描述为“通过 gettext 工具提供本地语言支持”则更加有用。

> **重要**
>
> 选项名称始终使用全大写字母，不能使用混合大小写或小写字母。

`OPTIONS` 可以作为单选组进行分组，每组只能选择一个选项：

```makefile
OPTIONS_SINGLE=		SG1
OPTIONS_SINGLE_SG1=	OPT3 OPT4
```

> **警告**
>
> 要让选项有效，每个 `OPTIONS_SINGLE` 组中必须始终选中一个选项。必须将每个组中的一个选项添加到 `OPTIONS_DEFAULT`。

`OPTIONS` 也可以作为单选组进行分组，每组可以选择零个或一个选项：

```makefile
OPTIONS_RADIO=		RG1
OPTIONS_RADIO_RG1=	OPT7 OPT8
```

`OPTIONS` 还可以作为“多选”列表进行分组，*至少一个* 选项必须启用：

```makefile
OPTIONS_MULTI=		MG1
OPTIONS_MULTI_MG1=	OPT5 OPT6
```

`OPTIONS` 还可以作为“多选”列表进行分组，零个或任意数量的选项可以启用：

```makefile
OPTIONS_GROUP=		GG1
OPTIONS_GROUP_GG1=	OPT9 OPT10
```

默认情况下，`OPTIONS` 未设置，除非它们列在 `OPTIONS_DEFAULT` 中：

```makefile
OPTIONS_DEFAULT=	OPT1 OPT3 OPT6
```

`OPTIONS` 定义必须出现在包含 **bsd.port.options.mk** 之前。`PORT_OPTIONS` 的值只能在包含 **bsd.port.options.mk** 后才能测试。也可以改为包含 **bsd.port.pre.mk**，在引入 **bsd.port.options.mk** 之前编写的 Ports 中这种方式仍广泛使用。但要注意，包含 **bsd.port.pre.mk** 后，某些变量可能无法按预期工作，通常是某些 `USE_*` 标志。

**示例 39. `OPTIONS` 的简单使用**

```makefile
OPTIONS_DEFINE=	FOO BAR
OPTIONS_DEFAULT=FOO

FOO_DESC=	Option foo support
BAR_DESC=	Feature bar support

# 将添加 --with-foo / --without-foo
FOO_CONFIGURE_WITH=	foo
BAR_RUN_DEPENDS=	bar:bar/bar

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

**示例 40. 检查未设置的 Port `OPTIONS`**

```makefile
.if ! ${PORT_OPTIONS:MEXAMPLES}
CONFIGURE_ARGS+=--without-examples
.endif
```

上述形式不推荐使用。推荐的方法是使用配置选项来真正启用和禁用特性，以匹配选项：

```makefile
# 将添加 --with-examples / --without-examples
EXAMPLES_CONFIGURE_WITH=	examples
```

**示例 41. `OPTIONS` 的实际使用**

```makefile
OPTIONS_DEFINE=		EXAMPLES
OPTIONS_DEFAULT=	PGSQL LDAP SSL

OPTIONS_SINGLE=		BACKEND
OPTIONS_SINGLE_BACKEND=	MYSQL PGSQL BDB

OPTIONS_MULTI=		AUTH
OPTIONS_MULTI_AUTH=	LDAP PAM SSL

EXAMPLES_DESC=		Install extra examples
MYSQL_DESC=		Use MySQL as backend
PGSQL_DESC=		Use PostgreSQL as backend
BDB_DESC=		Use Berkeley DB as backend
LDAP_DESC=		Build with LDAP authentication support
PAM_DESC=		Build with PAM support
SSL_DESC=		Build with OpenSSL support

# 将添加 USE_PGSQL=yes
PGSQL_USE=	pgsql=yes
# 将添加 --enable-postgres / --disable-postgres
PGSQL_CONFIGURE_ENABLE=	postgres

ICU_LIB_DEPENDS=	libicuuc.so:devel/icu

# 将添加 --with-examples / --without-examples
EXAMPLES_CONFIGURE_WITH=	examples

# 检查其他 OPTIONS

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

### 5.14.1.3. 默认选项

以下选项默认始终开启：

* `DOCS` - 构建并安装文档。
* `NLS` - 本地语言支持。
* `EXAMPLES` - 构建并安装示例。
* `IPV6` - IPv6 协议支持。

> **注意**
>
> 不需要将这些选项添加到 `OPTIONS_DEFAULT` 中。但是，要让它们生效并在选项选择对话框中显示，必须将它们添加到 `OPTIONS_DEFINE` 中。

## 5.14.2. 功能自动激活

在使用 GNU 配置脚本时，注意哪些可选功能是通过自动检测激活的。对于不需要的可选功能，通过在 `CONFIGURE_ARGS` 中添加 `--without-xxx` 或 `--disable-xxx` 来显式禁用。

**示例 42. 错误的选项处理**

```makefile
.if ${PORT_OPTIONS:MFOO}
LIB_DEPENDS+=		libfoo.so:devel/foo
CONFIGURE_ARGS+=	--enable-foo
.endif
```

在上面的示例中，假设系统上安装了 libfoo 库。用户不希望此应用程序使用 libfoo，因此在 `make config` 对话框中关闭了该选项。但应用程序的配置脚本检测到系统中存在该库，并将该库的支持加入到生成的可执行文件中。现在，当用户决定从系统中删除 libfoo 时，Ports 系统不会发出警告（因为没有记录对 libfoo 的依赖），但应用程序会出错。

**示例 43. 正确的选项处理**

```makefile
FOO_LIB_DEPENDS=		libfoo.so:devel/foo
# 将添加 --enable-foo / --disable-foo
FOO_CONFIGURE_ENABLE=	foo
```

> **注意**
>
> 在某些情况下，简写的条件语法可能在复杂构造中引发问题。通常会出现 `Malformed conditional` 错误，可以使用替代语法：
>
> ```makefile
> .if !empty(VARIABLE:MVALUE)
> ```
>
> 作为
>
> ```makefile
> .if ${VARIABLE:MVALUE}
> ```
>
> 的替代。

## 5.14.3. 选项帮助工具

有一些宏可以帮助简化基于选项设置的条件值。为了便于访问，提供了一个全面的列表：

* `PLIST_SUB`, `SUB_LIST` 有关自动生成 `%%OPT%%` 和 `%%NOOPT%%`，请参见 [`OPTIONS_SUB`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options_sub)。

  对于更复杂的用法，请参见 [通用变量替换](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-variables)。
* `CONFIGURE_ARGS` 对于 `--enable-x` 和 `--disable-x`，请参见 [`OPT_CONFIGURE_ENABLE`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-configure_enable)。

  对于 `--with-x` 和 `--without-x`，请参见 [`OPT_CONFIGURE_WITH`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-configure_with)。

  对于所有其他情况，请参见 [`OPT_CONFIGURE_ON` 和 `OPT_CONFIGURE_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-configure_on)。
* `CMAKE_ARGS` 对于布尔类型的参数（`on`、`off`、`true`、`false`、`0`、`1`），请参见 [`OPT_CMAKE_BOOL` 和 `OPT_CMAKE_BOOL_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-cmake_bool)。

  对于所有其他情况，请参见 [`OPT_CMAKE_ON` 和 `OPT_CMAKE_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-cmake_on)。
* `MESON_ARGS` 对于接受 `true` 或 `false` 的参数，参见 [`OPT_MESON_TRUE` 和 `OPT_MESON_FALSE`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-meson_true)。

  对于接受 `yes` 或 `no` 的参数，使用 [`OPT_MESON_YES` 和 `OPT_MESON_NO`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-meson_yes)。

  对于接受 `enabled` 或 `disabled` 的参数，参见 [`OPT_MESON_ENABLED` 和 `OPT_MESON_DISABLED`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-meson_enabled)。

  对于所有其他情况，请使用 [`OPT_MESON_ON` 和 `OPT_MESON_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-meson_on)。
* `QMAKE_ARGS` 参见 [`OPT_QMAKE_ON` 和 `OPT_QMAKE_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-qmake_on)。
* `USE_*` 参见 [`OPT_USE` 和 `OPT_USE_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-use)。
* `*_DEPENDS` 参见 [依赖项](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-dependencies)。
* `*` (任何变量) 最常用的变量有直接的帮助工具，参见 [通用变量替换](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-variables)。

  对于没有特定帮助工具的任何变量，请参见 [`OPT_VARS` 和 `OPT_VARS_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-vars)。

### 5.14.3.1. `OPTIONS_SUB`

如果将 `OPTIONS_SUB` 设置为 `yes`，那么添加到 `OPTIONS_DEFINE` 中的每个选项都会同时添加到 `PLIST_SUB` 和 `SUB_LIST` 中，例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPTIONS_SUB=	yes
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
PLIST_SUB+=	OPT1="" NO_OPT1="@comment "
SUB_LIST+=	OPT1="" NO_OPT1="@comment "
.else
PLIST_SUB+=	OPT1="@comment " NO_OPT1=""
SUB_LIST+=	OPT1="@comment " NO_OPT1=""
.endif
```

> **注意**
>
> 框架会忽略 `OPTIONS_SUB` 的值。将其设置为任何值都会为 *所有* 选项添加 `PLIST_SUB` 和 `SUB_LIST` 条目。

### 5.14.3.2. `OPT_USE` 和 `OPT_USE_OFF`

当选中选项 *OPT* 时，对于 `OPT_USE` 中的每个 `key=value` 配对，*value* 会附加到相应的 `USE_KEY` 上。如果 *value* 包含空格，则用逗号替换空格，处理时这些逗号会变回空格。`OPT_USE_OFF` 的工作方式相同，但作用于 *OPT* 未选中的情况。示例：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_USES=	xorg
OPT1_USE=	mysql=yes xorg=x11,xextproto,xext,xrandr
OPT1_USE_OFF=	openssl=yes
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
USE_MYSQL=	yes
USES+=		xorg
USE_XORG=	x11 xextproto xext xrandr
.else
USE_OPENSSL=	yes
.endif
```

### 5.14.3.3. `CONFIGURE_ARGS` 帮助工具

#### 5.14.3.3.1. `OPT_CONFIGURE_ENABLE`

当选中选项 *OPT* 时，对于 `OPT_CONFIGURE_ENABLE` 中的每个 *entry*，`--enable-entry` 会附加到 `CONFIGURE_ARGS`。当选项 *OPT* 未选中时，`--disable-entry` 会附加到 `CONFIGURE_ARGS`。可以用 `=` 符号指定可选参数，该参数仅会附加到 `--enable-entry` 配置选项。例如：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2
OPT1_CONFIGURE_ENABLE=	test1 test2
OPT2_CONFIGURE_ENABLE=	test2=exhaustive
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
CONFIGURE_ARGS+=	--enable-test1 --enable-test2
.else
CONFIGURE_ARGS+=	--disable-test1 --disable-test2
.endif

.if ${PORT_OPTIONS:MOPT2}
CONFIGURE_ARGS+=	--enable-test2=exhaustive
.else
CONFIGURE_ARGS+=	--disable-test2
.endif
```

#### 5.14.3.3.2. `OPT_CONFIGURE_WITH`

当选中选项 *OPT* 时，对于 `OPT_CONFIGURE_WITH` 中的每个 *entry*，`--with-entry` 会附加到 `CONFIGURE_ARGS`。当选项 *OPT* 未选中时，`--without-entry` 会附加到 `CONFIGURE_ARGS`。可以用 `=` 符号指定可选参数，该参数仅会附加到 `--with-entry` 配置选项。例如：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2
OPT1_CONFIGURE_WITH=	test1
OPT2_CONFIGURE_WITH=	test2=exhaustive
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
CONFIGURE_ARGS+=	--with-test1
.else
CONFIGURE_ARGS+=	--without-test1
.endif

.if ${PORT_OPTIONS:MOPT2}
CONFIGURE_ARGS+=	--with-test2=exhaustive
.else
CONFIGURE_ARGS+=	--without-test2
.endif
```

#### 5.14.3.3.3. `OPT_CONFIGURE_ON` 和 `OPT_CONFIGURE_OFF`

当选中选项 *OPT* 时，`OPT_CONFIGURE_ON` 的值（如果已定义）会附加到 `CONFIGURE_ARGS`。`OPT_CONFIGURE_OFF` 的工作方式相同，但作用于 *OPT* 未选中的情况。示例：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_CONFIGURE_ON=	--add-test
OPT1_CONFIGURE_OFF=	--no-test
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
CONFIGURE_ARGS+=	--add-test
.else
CONFIGURE_ARGS+=	--no-test
.endif
```

> **技巧**
>
> 大多数情况下，`OPT_CONFIGURE_ENABLE` 和 `OPT_CONFIGURE_WITH` 中的帮助工具提供了更简洁和全面的功能。

### 5.14.3.4. `CMAKE_ARGS` 帮助工具

#### 5.14.3.4.1. `OPT_CMAKE_ON` 和 `OPT_CMAKE_OFF`

当选中选项 *OPT* 时，如果定义了 `OPT_CMAKE_ON`，则该值会附加到 `CMAKE_ARGS`。`OPT_CMAKE_OFF` 的工作方式相同，但作用于 *OPT* 未选中的情况。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_CMAKE_ON=	-DTEST:BOOL=true -DDEBUG:BOOL=true
OPT1_CMAKE_OFF=	-DOPTIMIZE:BOOL=true
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
CMAKE_ARGS+=	-DTEST:BOOL=true -DDEBUG:BOOL=true
.else
CMAKE_ARGS+=	-DOPTIMIZE:BOOL=true
.endif
```

> **技巧**
>
> 当值为布尔型时，请参考 [`OPT_CMAKE_BOOL` 和 `OPT_CMAKE_BOOL_OFF`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-cmake_bool) 以获取更简洁的帮助工具。

#### 5.14.3.4.2. `OPT_CMAKE_BOOL` 和 `OPT_CMAKE_BOOL_OFF`

当选中选项 *OPT* 时，对于 `OPT_CMAKE_BOOL` 中的每个 *entry*，`-D_entry_:BOOL=true` 会附加到 `CMAKE_ARGS`。当选项 *OPT* 未选中时，`-D_entry_:BOOL=false` 会附加到 `CMAKE_ARGS`。`OPT_CMAKE_BOOL_OFF` 是相反的，当选中选项时，`-D_entry_:BOOL=false` 会附加到 `CMAKE_ARGS`，而当未选中时，`-D_entry_:BOOL=true` 会附加到 `CMAKE_ARGS`。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_CMAKE_BOOL=	TEST DEBUG
OPT1_CMAKE_BOOL_OFF=	OPTIMIZE
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
CMAKE_ARGS+=	-DTEST:BOOL=true -DDEBUG:BOOL=true \
		-DOPTIMIZE:BOOL=false
.else
CMAKE_ARGS+=	-DTEST:BOOL=false -DDEBUG:BOOL=false \
		-DOPTIMIZE:BOOL=true
.endif
```

### 5.14.3.5. `MESON_ARGS` 帮助工具

#### 5.14.3.5.1. `OPT_MESON_ON` 和 `OPT_MESON_OFF`

当选中选项 *OPT* 时，如果定义了 `OPT_MESON_ON`，则该值会附加到 `MESON_ARGS`。`OPT_MESON_OFF` 的工作方式相同，但作用于 *OPT* 未选中的情况。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_MESON_ON=	-Dopt=1
OPT1_MESON_OFF=	-Dopt=2
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
MESON_ARGS+=	-Dopt=1
.else
MESON_ARGS+=	-Dopt=2
.endif
```

#### 5.14.3.5.2. `OPT_MESON_TRUE` 和 `OPT_MESON_FALSE`

当选中选项 *OPT* 时，对于 `OPT_MESON_TRUE` 中的每个 *entry*，`-D_entry_=true` 会附加到 `MESON_ARGS`。当选项 *OPT* 未选中时，`-D_entry_=false` 会附加到 `MESON_ARGS`。`OPT_MESON_FALSE` 是相反的，当选中选项时，`-D_entry_=false` 会附加到 `MESON_ARGS`，而当未选中时，`-D_entry_=true` 会附加到 `MESON_ARGS`。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_MESON_TRUE=	test debug
OPT1_MESON_FALSE=	optimize
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
MESON_ARGS+=	-Dtest=true -Ddebug=true \
		-Doptimize=false
.else
MESON_ARGS+=	-Dtest=false -Ddebug=false \
		-Doptimize=true
.endif
```

#### 5.14.3.5.3. `OPT_MESON_YES` 和 `OPT_MESON_NO`

当选中选项 *OPT* 时，对于 `OPT_MESON_YES` 中的每个 *entry*，`-D_entry_=yes` 会附加到 `MESON_ARGS`。当选项 *OPT* 未选中时，`-D_entry_=no` 会附加到 `MESON_ARGS`。`OPT_MESON_NO` 是相反的，当选中选项时，`-D_entry_=no` 会附加到 `MESON_ARGS`，而当未选中时，`-D_entry_=yes` 会附加到 `MESON_ARGS`。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_MESON_YES=	test debug
OPT1_MESON_NO=	optimize
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
MESON_ARGS+=	-Dtest=yes -Ddebug=yes \
		-Doptimize=no
.else
MESON_ARGS+=	-Dtest=no -Ddebug=no \
		-Doptimize=yes
.endif
```

#### 5.14.3.5.4. `OPT_MESON_ENABLED` 和 `OPT_MESON_DISABLED`

当选中选项 *OPT* 时，对于 `OPT_MESON_ENABLED` 中的每个 *entry*，`-D_entry_=enabled` 会附加到 `MESON_ARGS`。当选项 *OPT* 未选中时，`-D_entry_=disabled` 会附加到 `MESON_ARGS`。`OPT_MESON_DISABLED` 是相反的，当选中选项时，`-D_entry_=disabled` 会附加到 `MESON_ARGS`，而当未选中时，`-D_entry_=enabled` 会附加到 `MESON_ARGS`。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_MESON_ENABLED=	test
OPT1_MESON_DISABLED=	debug
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
MESON_ARGS+=	-Dtest=enabled -Ddebug=disabled
.else
MESON_ARGS+=	-Dtest=disabled -Ddebug=enabled
.endif
```

### 5.14.3.6. `OPT_QMAKE_ON` 和 `OPT_QMAKE_OFF`

当选中选项 *OPT* 时，如果定义了 `OPT_QMAKE_ON`，则该值会附加到 `QMAKE_ARGS`。`OPT_QMAKE_OFF` 的工作方式相同，但作用于 *OPT* 未选中的情况。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_QMAKE_ON=	-DTEST:BOOL=true
OPT1_QMAKE_OFF=	-DPRODUCTION:BOOL=true
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
QMAKE_ARGS+=	-DTEST:BOOL=true
.else
QMAKE_ARGS+=	-DPRODUCTION:BOOL=true
.endif
```

### 5.14.3.7. `OPT_IMPLIES`

提供了一种在选项之间添加依赖关系的方式。

当选中选项 *OPT* 时，此变量中列出的所有选项也将同时选中。以下是使用之前描述的 [`OPT_CONFIGURE_ENABLE`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-configure_enable) 来举例说明：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2
OPT1_IMPLIES=	OPT2

OPT1_CONFIGURE_ENABLE=	opt1
OPT2_CONFIGURE_ENABLE=	opt2
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
CONFIGURE_ARGS+=	--enable-opt1
.else
CONFIGURE_ARGS+=	--disable-opt1
.endif

.if ${PORT_OPTIONS:MOPT2} || ${PORT_OPTIONS:MOPT1}
CONFIGURE_ARGS+=	--enable-opt2
.else
CONFIGURE_ARGS+=	--disable-opt2
.endif
```

**示例 44. `OPT_IMPLIES` 的简单使用**

这个 Port 有一个 `X11` 选项和一个需要选中 `X11` 选项才能构建的 `GNOME` 选项。

```makefile
OPTIONS_DEFINE=	X11 GNOME
OPTIONS_DEFAULT=	X11

X11_USES=	xorg
X11_USE=	xorg=xi,xextproto
GNOME_USE=	gnome=gtk30
GNOME_IMPLIES=	X11
```

### 5.14.3.8. `OPT_PREVENTS` 和 `OPT_PREVENTS_MSG`

提供了一种在选项之间添加冲突的方式。

当选中选项 *OPT* 时，`OPT_PREVENTS` 中列出的所有选项必须取消选择。如果设置了 `OPT_PREVENTS_MSG` 且触发了冲突，则其内容将显示，解释为什么它们会冲突。例如：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2
OPT1_PREVENTS=	OPT2
OPT1_PREVENTS_MSG=	OPT1 和 OPT2 启用冲突的选项
```

大致等同于：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT2} && ${PORT_OPTIONS:MOPT1}
BROKEN=	Option OPT1 conflicts with OPT2 (select only one)
.endif
```

唯一的区别是，第一个会在运行 `make config` 后输出错误，提示更改所选的选项。

**示例 45. `OPT_PREVENTS` 的简单使用**

这个 Port 有 `X509` 和 `SCTP` 选项。两个选项都添加补丁，但这些补丁彼此冲突，因此不能同时选择。

```makefile
OPTIONS_DEFINE=	X509 SCTP

SCTP_PATCHFILES=	${PORTNAME}-6.8p1-sctp-2573.patch.gz:-p1
SCTP_CONFIGURE_WITH=	sctp

X509_PATCH_SITES=	http://www.roumenpetrov.info/openssh/x509/:x509
X509_PATCHFILES=	${PORTNAME}-7.0p1+x509-8.5.diff.gz:-p1:x509
X509_PREVENTS=		SCTP
X509_PREVENTS_MSG=	X509 和 SCTP 补丁冲突
```

### 5.14.3.9. `OPT_VARS` 和 `OPT_VARS_OFF`

提供了一种通用的方式来设置并追加到变量。

> **警告**
>
> 在使用 `OPT_VARS` 和 `OPT_VARS_OFF` 之前，看看是否已经有更具体的助手可用，详情请见 [通用变量替换](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options-variables)。

当选中选项 *OPT* 并定义了 `OPT_VARS` 时，会从 `OPT_VARS` 中求值 `key=value` 和 `key+=value` 配对。`=` 会覆盖 `KEY` 的现有值，而 `+=` 会追加到该值。`OPT_VARS_OFF` 以相同的方式工作，但作用于 *OPT* 未选中的情况。

```makefile
OPTIONS_DEFINE=	OPT1 OPT2 OPT3
OPT1_VARS=	also_build+=bin1
OPT2_VARS=	also_build+=bin2
OPT3_VARS=	bin3_build=yes
OPT3_VARS_OFF=	bin3_build=no

MAKE_ARGS=	ALSO_BUILD="${ALSO_BUILD}" BIN3_BUILD="${BIN3_BUILD}"
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1 OPT2 OPT3

MAKE_ARGS=	ALSO_BUILD="${ALSO_BUILD}" BIN3_BUILD="${BIN3_BUILD}"

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
ALSO_BUILD+=	bin1
.endif

.if ${PORT_OPTIONS:MOPT2}
ALSO_BUILD+=	bin2
.endif

.if ${PORT_OPTIONS:MOPT3}
BIN3_BUILD=	yes
.else
BIN3_BUILD=	no
.endif
```

> **重要**
>
> 包含空格的值必须用引号括起来：
>
> ```
> OPT_VARS=	foo="bar baz"
> ```
>
> 这是因为 [make(1)](https://man.freebsd.org/cgi/man.cgi?query=make\&sektion=1\&format=html) 变量展开处理空格的方式。当 `OPT_VARS= foo=bar baz` 展开时，变量会包含两个字符串，`foo=bar` 和 `baz`。但提交者可能只希望有一个字符串 `foo=bar baz`。通过引用该值，可以防止空格作为分隔符使用。
>
> 另外，*不要* 在 `var=` 符号和值之间添加额外的空格，这样也会将其分割成两个字符串。*这将不起作用*：
>
> ```makefile
> OPT_VARS=	foo=	bar
> ```

### 5.14.3.10. 依赖关系，`OPT_DEPTYPE` 和 `OPT_DEPTYPE_OFF`

对于以下任何依赖类型：

* `PKG_DEPENDS`
* `EXTRACT_DEPENDS`
* `PATCH_DEPENDS`
* `FETCH_DEPENDS`
* `BUILD_DEPENDS`
* `LIB_DEPENDS`
* `RUN_DEPENDS`

当选中选项 *OPT* 时，如果定义了 `OPT_DEPTYPE`，则其值将追加到 `DEPTYPE`。`OPT_DEPTYPE_OFF` 以相同的方式工作，但作用于 *OPT* 未选中的情况。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_LIB_DEPENDS=	liba.so:devel/a
OPT1_LIB_DEPENDS_OFF=	libb.so:devel/b
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
LIB_DEPENDS+=	liba.so:devel/a
.else
LIB_DEPENDS+=	libb.so:devel/b
.endif
```

### 5.14.3.11. 通用变量替换，`OPT_VARIABLE` 和 `OPT_VARIABLE_OFF`

对于以下任意变量：

* `ALL_TARGET`
* `BINARY_ALIAS`
* `BROKEN`
* `CATEGORIES`
* `CFLAGS`
* `CONFIGURE_ENV`
* `CONFLICTS`
* `CONFLICTS_BUILD`
* `CONFLICTS_INSTALL`
* `CPPFLAGS`
* `CXXFLAGS`
* `DESKTOP_ENTRIES`
* `DISTFILES`
* `EXTRACT_ONLY`
* `EXTRA_PATCHES`
* `GH_ACCOUNT`
* `GH_PROJECT`
* `GH_SUBDIR`
* `GH_TAGNAME`
* `GH_TUPLE`
* `GL_ACCOUNT`
* `GL_COMMIT`
* `GL_PROJECT`
* `GL_SITE`
* `GL_SUBDIR`
* `GL_TUPLE`
* `IGNORE`
* `INFO`
* `INSTALL_TARGET`
* `LDFLAGS`
* `LIBS`
* `MAKE_ARGS`
* `MAKE_ENV`
* `MASTER_SITES`
* `PATCHFILES`
* `PATCH_SITES`
* `PLIST_DIRS`
* `PLIST_FILES`
* `PLIST_SUB`
* `PORTDOCS`
* `PORTEXAMPLES`
* `SUB_FILES`
* `SUB_LIST`
* `TEST_TARGET`
* `USES`

当选中选项 *OPT* 时，如果定义了 `OPT_ABOVEVARIABLE`，则其值将追加到 `ABOVEVARIABLE`。`OPT_ABOVEVARIABLE_OFF` 以相同的方式工作，但作用于 *OPT* 未选中的情况。例如：

```makefile
OPTIONS_DEFINE=	OPT1
OPT1_USES=	gmake
OPT1_CFLAGS_OFF=	-DTEST
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MOPT1}
USES+=		gmake
.else
CFLAGS+=	-DTEST
.endif
```

> **注意**
>
> 某些变量不在此列表中，特别是 `PKGNAMEPREFIX` 和 `PKGNAMESUFFIX`。这是有意为之。Port 在选项集更改时 *不得* 更改其名称。

> **警告**
>
> 其中一些变量，至少 `ALL_TARGET`、`DISTFILES` 和 `INSTALL_TARGET`，它们的默认值是在选项处理后设置的。在 **Makefile** 中使用以下行：
>
> ```makefile
> ALL_TARGET=	all
>
> DOCS_ALL_TARGET=	doc
> ```
>
> 如果启用了 `DOCS` 选项，`ALL_TARGET` 最终值将为 `all doc`；如果该选项禁用，则为 `all`。
>
> 在 **Makefile** 中仅使用选项帮助行：
>
> ```makefile
> DOCS_ALL_TARGET=	doc
> ```
>
> 如果启用了 `DOCS` 选项，`ALL_TARGET` 最终值将为 `doc`；如果该选项禁用，则为 `all`。

### 5.14.3.12. 额外构建目标，`target-OPT-on` 和 `target-OPT-off`

这些 **Makefile** 目标可以接受额外的可选构建目标：

* `pre-fetch`
* `do-fetch`
* `post-fetch`
* `pre-extract`
* `do-extract`
* `post-extract`
* `pre-patch`
* `do-patch`
* `post-patch`
* `pre-configure`
* `do-configure`
* `post-configure`
* `pre-build`
* `do-build`
* `post-build`
* `pre-install`
* `do-install`
* `post-install`
* `post-stage`
* `pre-package`
* `do-package`
* `post-package`

当选中选项 *OPT* 时，如果定义了目标 `TARGET-OPT-on`，则在 `TARGET` 之后执行该目标。`TARGET-OPT-off` 以相同的方式工作，但作用于 *OPT* 未选中的情况。例如：

```makefile
OPTIONS_DEFINE=	OPT1

post-patch-OPT1-on:
	@${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${EXAMPLESDIR}/|' ${WRKSRC}/Makefile

post-patch-OPT1-off:
	@${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${PREFIX}/bin/|' ${WRKSRC}/Makefile
```

等同于：

```makefile
OPTIONS_DEFINE=	OPT1

.include <bsd.port.options.mk>

post-patch:
.if ${PORT_OPTIONS:MOPT1}
	@${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${EXAMPLESDIR}/|' ${WRKSRC}/Makefile
.else
	@${REINPLACE_CMD} -e '/opt1/s|/usr/bin/|${PREFIX}/bin/|' ${WRKSRC}/Makefile
.endif
```


---

# 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.14.makefile-can-shu.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.
