# 5.14.Makefile 参数

许多应用程序可以通过可选或不同的配置进行构建。示例包括选择自然（人类）语言、图形界面与命令行界面，或支持的数据库类型。用户可能需要不同于默认配置的版本，因此 Ports 系统提供了 hook，port 作者可以使用这些 hook 来控制将构建哪种变体。正确支持这些选项将使用户满意，并有效地提供多个 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` 可以作为单选组进行分组，每组只能选择一个选项：

```
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`**

```
.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` 中，例如：

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

等同于：

```
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` Helpers

#### 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` Helpers

#### 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` 时，`key=value` 和 `key+=value` 对将会从 `OPT_VARS` 中进行评估。`=` 会覆盖 `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

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:MOPT2}
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** 中：
>
> ```
> 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: 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.14.makefile-can-shu.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.
