通常,我们需要控制传递给被调用工具的选项。这是通过特性来完成的。考虑一个例子
# Declare a new free feature import feature : feature ; feature verbatim-options : : free ; # Cause the value of the 'verbatim-options' feature to be # available as 'OPTIONS' variable inside verbatim.inline-file import toolset : flags ; flags verbatim.inline-file OPTIONS <verbatim-options> ; # Use the "OPTIONS" variable actions inline-file { "./inline-file.py" $(OPTIONS) $(<) $(>) }
我们首先定义一个新的特性。然后,flags
调用表示,每当运行 verbatin.inline-file 操作时,verbatim-options
特性的值将被添加到 OPTIONS
变量中,并且可以在操作体内部使用。您需要查阅联机帮助(--help)以查找 toolset.flags
规则的所有特性。
尽管您可以定义任何一组特性并以任何方式解释其值,但 Boost.Build 建议使用以下编码标准来设计特性。
大多数特性应该有一组固定的值,这些值在它们设计用于工作的工具类别中是可移植的(工具中立)。用户不必为确切的工具调整值。例如,<optimization>speed
对所有 C++ 编译器都有相同的含义,用户不必担心传递给编译器命令行的确切选项。
除了这些可移植特性之外,还有一些特殊的“原始”特性,允许用户在需要时将任何值传递给特定工具的命令行参数。例如,<cxxflags>
特性允许您将任何命令行选项传递给 C++ 编译器。 <include>
特性允许您传递以 -I
开头的任何字符串,并且解释是特定于工具的。(有关此特性的非常智能用法的示例,请参见 名为“我可以使用 Boost.Jam 变量捕获外部程序输出吗?”的部分)。当然,人们应该始终努力使用可移植特性,但这些特性仍然作为后门提供,以确保 Boost.Build 不会夺走用户任何控制权。
使用可移植特性是一个好主意,因为
当为可移植特性提供一组固定值时,您可以使用该特性的两个不同设置构建项目,Boost.Build 将自动为生成的文件使用两个不同的目录。Boost.Build 不会尝试分离使用不同原始选项构建的目标。
与“原始”特性不同,您不需要在 Jamfile 中使用特定的命令行标志,并且它更有可能与其他工具一起使用。
添加特性需要三个步骤
声明一个特性。为此,使用“feature.feature”规则。您必须确定特性属性的集合
如果您希望一个目标的特性值集自动传播到其依赖目标,则将其设为“propagated”。
如果一个特性没有固定的值列表,则它必须是“free”。例如,include
特性是一个自由特性。
如果一个特性用于引用相对于 Jamfile 的路径,则它必须是“path”特性。此类特性的值也将自动转换为 Boost.Build 的内部路径表示形式。例如,include
是一个路径特性。
如果特性用于引用某个目标,则它必须是“dependency”特性。
在目标特定的变量中表示特性值。构建操作是由 Boost.Jam 变量扩展修改的命令模板。toolset.flags
规则将目标特定的变量设置为特性的值。
使用变量。步骤 2 中设置的变量可用于构建操作中以形成命令参数或文件。
这是一个其他的例子。让我们看看如何创建一个引用目标的特性。例如,在 Windows 上链接动态库时,有时需要指定一个“DEF 文件”,告诉应该导出哪些函数。使用这个文件会很不错
lib a : a.cpp : <def-file>a.def ;
实际上,此特性已得到支持,但无论如何...
由于该特性引用了一个目标,因此它必须是“dependency”。
feature def-file : : free dependency ;
关心 DEF 文件的工具集之一是 msvc。应将其添加到其中。
flags msvc.link DEF_FILE <def-file> ;
由于 msvc.link 操作未使用 DEF_FILE 变量,因此我们需要将其修改为
actions link bind DEF_FILE { $(.LD) .... /DEF:$(DEF_FILE) .... }
请注意 bind DEF_FILE
部分。它告诉 Boost.Build 将 DEF_FILE
中的内部目标名称转换为 link
操作中对应的文件名。如果没有它,$(DEF_FILE)
的扩展将是一个奇怪的符号,不太可能对链接器有意义。
我们快完成了,除了将以下代码添加到 msvc.jam
中
rule link { DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ; }
这是对 Boost.Build 引擎中错误的一种解决方法,希望有一天能修复它。
有时您想为某些特性集创建一个快捷方式。例如,release
是 <variant>
的一个值,并且是特性集的快捷方式。
可以定义您自己的构建变体。例如
variant crazy : <optimization>speed <inlining>off <debug-symbols>on <profiling>on ;
将定义一个具有指定属性集的新变体。您还可以扩展现有变体
variant super_release : release : <define>USE_ASM ;
在这种情况下,super_release
将扩展到 release
指定的所有属性,以及您指定的其他属性。
您不限于仅使用 variant
特性。这是一个定义全新特性的示例
feature parallelism : mpi fake none : composite link-incompatible ; feature.compose <parallelism>mpi : <library>/mpi//mpi/<parallelism>none ; feature.compose <parallelism>fake : <library>/mpi//fake/<parallelism>none ;
这将允许您指定特性 parallelism
的值,该值将扩展为链接到必要的库。