Boost.Build简明教程(译)
Written by Boris Schäling.
历史:
2018-12-20 姚彧 第一版
目录
- 介绍 Introduction
- 生成过程 Build process
- 基本任务 Basic tasks
- 项目管理 Project management
- 最佳实践 Best practices
- 规则参考 Rule reference
- 属性参考 Feature reference
介绍 Introduction
一个与编译器和平台都无关的编译系统 Compiler- and platform-independent build system
Boost.Build是一个高级编译系统, 它能尽可能容易地管理C++项目(集)。 其思想是, 在配置文件中指定生成程序所需的内容。例如,不需要告诉Boost.Build如何使用某个编译器, Boost.Build支持多个编译器,并知道如何使用它们。如果你创建一个配置文件,你只需要告诉Boost.Build源文件在哪里,调用哪些可执行文件,使用哪个编译器。然后,Boost.Build会查找编译器并自动生成程序。
Boost.Build支持许多不包含任何特定编译器选项的编译器配置文件。配置文件完全是与编译器无关的。可以设置是否优化代码之类的选项, 不过,这些选项都是用Boost.Build语言写的。一旦选择编译器进行编译, Boost.Build会将配置文件中的选项翻译成相应的编译器命令行选项。这样就有可能写一次配置文件,在不同的平台上用不同的编译器生成程序。
听起来不错,但Boost.Build只支持C++和C项目. Boost.Build不知道如何使用其他编译器,比如Java编译器。虽然Boost.Build是可扩展的,但是对于用其他编程语言实现的程序,使用不同的构建系统更有意义。
创建Boost.Build,是为了在不同平台上使用不同的编译器轻松编译和安装Boost C++库。虽然Boost.Build是Boost C++库的一部分,并且附带了它,但它可以单独用于任何C++或C项目。如果您不想使用Boost C++库,甚至可以只下载Boost.Build。
本文是一个介绍,帮助在C++或C项目中使用Boost.Build。它让我们对Boost.Build如何工作以及怎么使用它有基本的了解。在阅读了本文之后,您不仅应该能够在自己的项目中使用Boost.Build,而且还能更容易理解Boost.Build文档,因为您将了解整个过程。
生成过程 Build process
Jamfiles和b2解析器 Jamfiles and an interpreter called b2
用于生成由Boost.Build管理项目的程序称为b2. 如果你下载和编译了Boost C++库, 你就已经用过了b2。b2查找配置文件,读取配置文件, 并编译相应的项目。它还接受各种命令行选项,例如显示在b2编译项目过程中所有的命令。
项目可以很大,可以由许多组件组成,其源代码分布在多个目录中。不需要为整个项目创建一个大的配置文件,组件有自己的配置文件。这对于Boost.Build没有什么不同:在一个大的项目中, 有很多的配置文件,b2会发现和解释它们。
对Boost.Build来说, 有配置文件的目录就是一个项目: 如果目录里有配置文件,就可以编译。对Boost.Build来说, 子目录里的一个组件与包含很多组件的软件没有区别.
当b2启动时,它不会在整个文件系统上运行搜索配置文件。它仅在当前工作目录中搜索配置文件。如果没有找到配置文件,它就什么也不做。如果当前工作目录中没有配置文件,b2不会在任何其他目录中搜索配置文件。
b2配置文件叫Jamfile.jam
. 有jam
后缀的文件叫Jamfiles
. 如果b2发现当前目录下有Jamfile
, 它会逐层查找父目录中的Jamfiles
。b2逐层查找上级目录,直到找到Jamroot.jam
文件. Jamroot.jam
与Jamfile.jam
没有区别, 它只是告诉b2不需要再查找下去.
为什么b2在父目录中查找Jamfiles,是因为这样可以进行批量设置。如果一些组件有一些相同的设置, 他们可以存储在父目录的Jamfile中,这些设置会自动应用到子目录组件中。
注意:
b2必须要找到Jamroot.jam
文件, 没有Jamroot.jam
文件就会报错. 如果当前目录下有Jamroot.jam
文件, 就不需要其它Jamfile.jam
文件. 如果Jamroot.jam
在父目录, 当前目录必须有Jamfile.jam
文件, 否则, b2不会做任何事情.
如果将b2复制到不包含Jamfiles
文件的目录,并运行程序,则会收到错误消息。但是b2不会报“不能找到Jamfile”的错误,它会报”找不到构建系统”的错误。
Unable to load Boost.Build: could not find "boost-build.jam"
---------------------------------------------------------------
Attempted search from C:UsersBorisDesktop up to the root
Please consult the documentation at 'http://www.boost.org'.
b2所做的第一件事不是查找Jamfile,而是加载编译系统。但是Boost.Build的编译系统究竟是什么呢?
b2是一个解释器。它不知道如何编译任何东西。b2的任务就是解释jamfile。Boost.Build实际上是在jamfile中实现的。它们包含了所有使Boost.Build成为强大工具的逻辑。因为b2只做它在Jamfiles中读取的任务,所以它需要知道在哪里可以找到构成Boost.Build的Jamfiles。
当b2启动时,它会在当前工作目录中寻找boost-build.jam
。如果没有找到文件,它会搜索所有的父目录。这个文件只需要包含一行就可以告诉b2在哪里找到编译系统。
boost-build C:/boost_1_57_0/tools/build/src ;
boost-build
之后的路径必须引用一个目录,该目录包含一个名为bootstrap.jam
的文件。这是b2加载编译系统所需的文件。随着Boost C++库,附带了Boost.Build。您可以引用Boost C++库根目录的子目录tools/build
。而且,您可以始终使用斜杠作为路径分隔符,即使是Windows。
请注意,路径和行尾的分号之间必须有空格。没有空格是语法错误。在本文后面,您将了解更多Jamfiles中使用的语法。
如果b2找到了boost-build.jam
。它使用文件中的路径来加载编译系统。编译系统加载后,它还会准备要使用的编译器、链接器,和编译项目所需的其他工具。Boost.Build将这些程序称为工具集。如果运行b2时没有使用命令行选项,则编译系统将尝试找到它可以自动使用的工具集(toolset)。例如,它在Windows上搜索Visual C++。如果它检测到Visual C++已经安装,它就会使用工具集(toolset)msvc。
warning: No toolsets are configured.
warning: Configuring default toolset "msvc".
warning: If the default is wrong, your build may not work correctly.
warning: Use the "toolset=xxxxx" option to override our guess.
warning: For more configuration options, please consult
warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html
如果在启动b2时, 没有指定使用哪个工具集,则会看到警告。b2告诉您它检测到并决定使用哪个工具集。如果您想要隐藏警告,您必须自己指定工具集。例如,要使用Visual C++, 输入b2 toolset=msvc
。如果希望使用GCC,则输入b2 toolset= GCC
。
到目前为止,支持的工具集超过10个。Boost.Build很有可能与您使用的编译器可以一起工作。
一旦找到了编译系统, 加载并知道使用哪一个工具集(要么指定, 要么是编译系统自动检测的) b2在当前目录找到Jamfile.jam
文件。如果没有找到Jamfile, 就会输出错误消息。
error: error: no Jamfile in current directory found, and no target references specified.
如果您创建一个空Jamfile.jam
文件, 启动b2会输出另外的错误消息。
error: Could not find parent for project at '.'
error: Did not find Jamfile.jam or Jamroot.jam in any parent directory.
b2要找到一个名为Jamroot.jam
的Jamfile。如果它不存在于当前的工作目录中,b2希望在父目录中找到它。
如果您创建一个空的Jamroot.jam
文件, 运行b2, 错误消息会消失。显然, 现在Boost.Build什么都没有做。但是现在您知道了b2是如何编译程序的,以及最小Boost.Build配置是什么样子的。
注意: 如果是一个小项目,并且只需要一个配置文件,那么可以只要Jamroot.jam
, 而不要Jamfile.jam
。
基本任务 Basic tasks
规则和特性 Rules and features
如果查看Jamfiles
,语法可能会让您想起其他编译系统使用的配置文件。简单的Jamfile
可能看起来像普通的旧配置文件,也是键值对。但是需要理解的关键点是,Jamfile
实际上是脚本文件。是在用编程语言编写Jamfile
。b2不是Boost.Build
的核心组件, 它知道如何编译程序。Boost.Build的逻辑在Jamfile中, 它在告诉b2如何编译程序。
即使Boost.Build是基于编程语言,在创建Jamfile时也不需要考虑编程。Boost.Build编程语言的语法, 能让我们更多地创建普通的旧配置文件。这样做的目的是实现两个方面的最佳结合:(深入浅出)一种功能强大且灵活的编程语言,但又是在其它编译系统中熟悉的简单语法。
本文不是向您介绍Boost.Build的编程语言。这种编程语言是专有的,使用起来并不有趣。它不是Javascript或Python等流行脚本语言的竞争对手。Boost.Build的开发人员认识到这一点,并使用另一个基于Python的Boost.Build版本。然而,对于计划使用Boost.Build管理项目的开发人员来说,所有这些都没有什么关系。一旦认识到Boost.Build中有一种编程语言,它将有助于更好地理解jamfile的语法。但是不需要学习编程语言的细节。
让我们看一个简单的Jamfile,它可以用于从源文件hello.cpp
编译hello执行程序。
exe hello : hello.cpp ;
Boost.Build提供了许多内置规则,exe
就是其中之一。虽然Boost.Build的文档将exe
作为规则引用,但是您已经知道,上面的Jamfile实际上是使用编程语言构建的。事实上, 规则只是函数。上面的Jamfile包含一个函数调用。
对于编译程序通常需要做的大多数任务,Boost.Build提供了预定义规则(函数)。它和其他编程语言中的函数一样,可以传递参数。在上面的Jamfile中,在调用函数exe
时, 使用了两个参数hello
和hello.cpp
。
Boost.Build编程语言只基于一种数据类型: 所有内容都是字符串列表。列表可以是空的,也可以包含一个或多个字符串。在上面的Jamfile中,在调用函数exe
时, 使用了两个参数, 每个参数包含一个字符串的列表。
exe "hello" : "hello.cpp" ;
可以使用引号, 但并不必须, 因为列表中的每个值都是字符串数据类型。只有参数包含空格时才使用引号。
规则和第一个参数之间没有特殊的分隔符,但是必须其他参数间必须使用冒号分隔。它还需要以分号结束一行,就像您从C++中习惯的那样。
请注意,Boost.Build的编程语言要求在所有标志周围都有一个空格。例如,冒号的左边和右边必须有一个空格, 分号的左边必须有一个空格。如果标志周围没有空格,b2将无法正确解析jamfile。
如果在包含上面Jamfile和hello.cpp
文件的目录中运行b2, 且在Windows上使用msvc工具集,将创建一个子目录binmsvc-9.0debug
, 用来编译可执行的hello.exe。
PS > b2
warning: No toolsets are configured.
warning: Configuring default toolset "msvc".
warning: If the default is wrong, your build may not work correctly.
warning: Use the "toolset=xxxxx" option to override our guess.
warning: For more configuration options, please consult
warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html
...found 16 targets...
...updating 10 targets...
msvc.write-setup-script binstandalonemsvcmsvc-14.1msvc-setup.bat
compile-c-C++ binmsvc-14.1debughello.obj
hello.cpp
msvc.link binmsvc-14.1debughello.exe
msvc.manifest binmsvc-14.1debughello.exe
...updated 11 targets...
正如您所看到的,从源文件编译可执行文件只需要Jamfile中的一行。如果程序是在Windows上编译的,甚至还有正确的文件扩展名exe
。
Boost.Build的主要优点是,定义所需的内容, 以告诉编译系统如何生成程序. Boost.Build可以自动完成的任何事情都是自动完成的。您不需要检测构建在某个程序上的平台,以决定是否应该添加exe之类的文件扩展名。您不需要指定如何调用Visual C++
之类的编译器来编译源代码。
Boost.Build支持许多现成的工具集。由于可以使用不同的工具集编译程序,Boost.Build使用与工具集相关的目录。通过这种方式,可以用不同的工具集构建程序,而不需要一个工具集不断覆盖另一个工具集生成的文件。
不仅有工具集相关的目录, 还有版本相关的目录。版本是指调试或发行。对于每个版本, 都有一个目录用于编译程序 —— 这样也不会覆盖另一个版本生成的文件。默认情况下, 生成调试版本。这就是为什么会创建子目录binmsvc-9.0debug
的原因。如果您想要创建一个发行版本, 您可以在命令行中指定版本b2 variant=release
, 或, 甚至更简单b2 release
。
b2 release
warning: No toolsets are configured.
warning: Configuring default toolset "msvc".
warning: If the default is wrong, your build may not work correctly.
warning: Use the "toolset=xxxxx" option to override our guess.
warning: For more configuration options, please consult
warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html
...found 15 targets...
...updating 3 targets...
compile-c-C++ binmsvc-14.1
eleasehello.obj
hello.cpp
msvc.link binmsvc-14.1
eleasehello.exe
msvc.manifest binmsvc-14.1
eleasehello.exe
...updated 3 targets...
根据variant
参数release
, 将hello.exe
编译到目录binmsvc-9.0
elease
.
选择版本是一件经常要做的事情,b2 release
就可以。Boost.Build指出发行版是为了选择版本(variant)。
如果您不希望在命令行上指定版本,但希望在默认情况下构建hello.exe
的发行版,Jamfile修改如下:
exe hello : hello.cpp : <variant>release ;
exe
规则(函数)接受几个可选参数。第三个参数是需求列表。您可以想象命令行选项,这些选项总是设置并传递给运行命令以编译可执行文件。
为了强制编译发行版,variant
属性必须设置为release
,就像以前在命令行上所做的那样。但是在Jamfile中设置变量的语法与其它编译工具是不同的。
Boost.Build定义了类XML标记的特性(features)。Boost.Build支持的特性之一是<variant>
。如果一个特性要设置为一个值,那么值必须放在<variant>
标记的旁边(中间没有空格)。一些特性是自由的,这意味着它们可以被设置为您想要的任何值。<variant>
是一个非自由特性,因为它只能被设置为debug
或release
, 不允许有其他值。如果设置了其它值,b2会输出错误。
如果您运行b2 variant=debug
, 并试图编译hello.exe的调试版, 它不能成功,因为Jamfile包含hello.exe
要作为一个发布版编译的要求(requirement)。如果您希望能够在命令行上覆盖该特性,则必须将该特性作为第四个参数而不是第三个参数传递。
exe hello : hello.cpp : : <variant>release ;
第四个参数包含默认使用但可以覆盖的特性。
如果您要在默认情况下, 生成hello.exe的debug和release版, 那么, 需要两次设置<variant>
特性为debug
和release
。
exe hello : hello.cpp : : <variant>debug <variant>release ;
这非常重要,<variant>
在第四个参数(默认值)中设置了两次。如果是指定需求的第三个参数,b2将输出错误。可以在需求中多次设置特性,但是只有在值不是互斥的情况下才可以。程序不能在第三个参数中同时设置为debug,release版. 只有在默认值部分设置<variant>
, 这样, Boost.Build才理解如何编译hello的两个exe
版本。
exe hello : hello.cpp : <define>WIN32 <define>_WIN32 : <variant>debug <variant>release ;
上面的Jamfile是一个在需求中多次设置特性的例子。特性<define>
用于定义预处理器指令。定义几个预处理器指令是没有问题的。因此,hello.exe
的两个版本都使用了的两个指令WIN32
和_WIN32
来生成它们。
exe hello : hello.cpp : : <variant>debug <variant>release <define>WIN32 <define>_WIN32 ;
如果将定义移动到第四个参数,并运行b2,则hello.exe
的两个版本, 都同样使用两个指令WIN32和_WIN32进行编译. 由于<define>
不期望互斥值,因此没有生成其他可执行文件集。这个Jamfile与上一个Jamfile的惟一区别是,在第四个参数中传递的指令是默认值,可以删除这些值,而作为第三个参数传递的任何指令都是不可变的要求。
下面是另一个值互斥的特性示例。
exe hello : hello.cpp : : <variant>debug <variant>release <optimization>speed <optimization>off ;
b2创建hello.exe
的四个版本。针对速度优化的调试版、没有优化的调试版、针对速度优化的发行版和没有优化的发行版。所有这些版本都编译在自动创建的独立目录中。
到目前为止,唯一使用的规则是exe
。但是Boost.Build提供了更多的内置规则。另一个重要的规则是lib
,它用于编译一个库。
lib world : world.cpp ;
上面的Jamfile从源文件world.cpp
编译了一个共享库。在Windows上, 会创建一个world.dll
的文件。通常, 文件扩展名是由Boost.Build自动追加。
默认情况下,将生成一个共享库。如果希望生成静态库,可以将<link>
特性设置为static
。
lib world : world.cpp : <link>static ;
另一个有用的规则是install
。在生成了可执行文件和库之后,可以使用此规则来安装它们。
exe hello : hello.cpp ;
install "C:/Program Files/hello" : hello ;
上面的Jamfile, 会把可执行文件hello.exe
安装到C:Program Fileshello
. 第二个参数hello
是对第一行中定义的目标hello
的引用。请注意,路径必须加引号,因为它包含一个空格。
在这里,从其它编译系统的概念很有价值: 与其考虑函数调用,不如每行定义一个目标。依赖关系是通过引用其他目标创建的。这就是Boost.Build如何知道应该以什么顺序生成目标。
但是,install
规则的编写通常是不同的。使用<location>
特性在第三个参数中设置安装目录,而不是将安装目录作为第一个参数传递。
exe hello : hello.cpp ;
install install-bin : hello : <location>"C:/Program Files/hello" ;
使用<location>
更好的主要原因是, 第一个参数总是定义一个目标。其他规则可能引用目标。这就是为什么, 使用以后不必更改的目标名称是一个好主意。设想一个程序应该安装到另一个目录。如果<location>
特性已被用作不需要更新可能引用到install-bin的其他规则,则更改安装目录将更容易。It's easier to change the installation directory if the <location>
feature has been used as no other rules which might refer to install-bin have to be updated.
使用特性还有另一个原因。Boost.Build支持条件属性,这些属性可以根据编译程序的平台使用不同的安装目录。
exe hello : hello.cpp ;
install install-bin : hello : <target-os>windows:<location>"C:/Program Files/hello" <target-os>linux:<location>/usr/local/bin ;
特性<target-os>
是另一个具有互斥值的特性。例如,它可以设置为windows或linux,但不能同时设置为windows和linux。
特性<location>
在<target-os>
之后, 仅用冒号分隔。这样的构造称为条件属性: Boost.Build根据操作系统选择安装目录。
当然,条件属性也可以与其他规则一起使用。例如,在编译程序或库时,可以根据不同的版本定义不同的预处理器指令。
Boost.Build提供了更多的内置规则。另一个有用的规则是glob
,它让使用通配符成为可能。在一个包含许多源文件的大型项目中,不需要逐一列出它们,而是使用glob
引用它们。
exe hello : [ glob *.cpp ] ;
上面的Jamfile包含一个嵌套的函数调用: 规则glob
的结果作为第二个参数传递给exe。由于编程语言的要求,Boost.Build是基于方括号的,必须用于嵌套函数调用。
项目管理 Project management
多Jamfiles
在有很多jamfile的大型项目中,需要以某种方式连接jamfile。在项目的根目录, 通常有一个Jamroot.jam
文件, 在各个子目录, 有Jamfile.jam文件。如果在根目录中运行b2,开发人员可能希望生成整个项目,包括子目录中的所有组件。当b2在父目录而不是子目录中查找jamfile时,jamfile需要显式地引用子目录中的jamfile。
build-project hello ;
如果一个Jamfile看起来像上面的示例,它将引用hello
子目录中的Jamfile。build-project
是一个规则,它期望路径作为它的唯一参数, 然后在该路径中查找Jamfile。
build-project hello ;
build-project world ;
如果您希望构建多个项目,则必须多次使用build-project。
除了在子目录中引用jamfile之外,在项目中生成组件时, 对应该使用的选项进行分组也是有意义的。
project : default-build release ;
build-project hello ;
build-project world ;
project
规则接受各种参数,以便为当前工作目录和子目录中的Jamfile设置选项。
project
规则使用命名参数, 而其他规则,如exe
和lib
,参数顺序传递。在上面的示例中,参数的名称是default-build。这就是为什么可以在一个非常不同的参数中传递值release
。(That's why it is possible to pass the value release in a very different parameter.)
project : : : : : : : : : default-build release ;
build-project hello ;
build-project world ;
将release
作为第10个参数传递是没有意义的。但它的工作原理是, project
不关心顺序。它可以使用第10个参数default-build
。
project
只支持几个命名参数。另一个参数是requirements
,它可以用来设置不能修改的选项。
project : requirements <variant>release ;
build-project hello ;
build-project world ;
上面的Jamfile只生成release版。不可能再生成debug版本,因为不能修改需求。这与上一个示例中使用的名为default-build的命名参数不同: 它可以修改。
当使用build-project
时,Boost.Build假定该参数是对一个子目录的引用。我们以前见过另一种类型的引用。
exe hello : hello.cpp ;
install install-bin : hello : <location>"C:/Program Files/hello" ;
在上面的Jamfile中,install
规则引用第一行中定义的目标hello
。
在大型项目中,可能需要引用在其他目录里jamfile中定义的目标。可以使用双斜杠将路径与Jamfile中的目标相连。It is possible to concatenate a path to a Jamfile and a target with a double slash.)
install install-bin : subdir//hello : <location>"C:/Program Files/hello" ;
现在,install
规则引用子目录subdir
中的Jamfile中的目标hello
。
让我们假设可执行hello依赖于另一个目录中的world
库。这个库也是用Boost.Build使用lib
规则生成的。
lib world : world.cpp ;
在生成可执行文件的Jamfile中,需要引用库的Jamfile。没有必要直接引用world
目标,因为默认情况下,Jamfile中的所有目标都是构建的。
exe hello : hello.cpp world : : <variant>debug <variant>release ;
上面的Jamfile假设库及其Jamfile位于子目录world
中。
在生成可执行文件时,会生成两个版本 — 调试版和发行版。虽然库的Jamfile没有设置<variant>
特性, 但是Boost.Build假定它也会构建这个库的两个版本。特性<variant>
在这里就进行了传播。
传播特性(Propagating features)简化了项目管理,因为您不需要在各种jamfile中设置相同的特性。当然,这也使得理解组件是如何构建的变得更加复杂,因为它完全依赖于传播的特性。您可以假定Boos.tBuild知道它应该做什么。当然,这并不意味着你很容易理解它做了什么。
让我们看另一个使用特性<define>
的例子。
exe hello : hello.cpp world : <define>WIN32 : <variant>debug <variant>release ;
上面的Jamfile为程序hello
定义了一个预处理器指令WIN32
。但是WIN32
也会为这个库定义吗?
它不会,因为<define>
不是一个传播特性。如果您想知道应该如何知道: 查找传播特性的惟一方法是查找文档。
如果您安装了Boost C++库,您可能希望链接到其中一些库。您必须以某种方式向项目的Jamfile中相应的Boost C++库添加一个依赖项。如果没有删除已解压缩Boost C++库源文件的目录,则可以引用根目录中Jamfile中的目标。
exe hello : hello.cpp world C:/boost_1_39_0//filesystem/ ;
现在, hello还依赖于Boost.Filesystem库。由于目标文件系统是在Boost C++库根目录下的Jamfile中定义的,因此exe
规则可以引用它。不仅会链接适当的Boost C++库 —— 还会将include目录传递给编译器以查找头文件。如果hello.cpp
包含boost/filesystem.hpp
,就会找到这个头文件。
在上面的Jamfile中,Boost C++库的根目录的路径是硬编码的。b2需要知道在哪里可以找到Boost C++库。但是,如果只硬编码一次路径,以防止项目中的几个组件需要链接到某个Boost C++库,那就更好了。
project : requirements <variant>release ;
use-project /boost : C:/boost_1_39_0 ;
build-project hello ;
build-project world ;
use-project
规则用于定义另一个目录中Jamfile的别名。子目录中的Jamfiles使用别名引用Boost C++库。
exe hello : hello.cpp world /boost//filesystem ;
b2会分析出hello.cpp
是源文件,world
是子目录,/boost//filesystem
是对C:oost_1_39_0
目录里, Jamfile文件中的目标filesystem的引用。
请注意, 如果引用的是项目,引用必须以斜杠开头。
由于库可以用不同的方式链接,因此可以设置与链接器相关的特性。
exe hello : hello.cpp world /boost//filesystem/<link>static ;
默认情况下,库是动态链接的。如果库应该静态链接,则必须将特性<link>
设置为static
。
特性可以用斜杠附加。如果需要设置多个特性,则在前一个特性后面附加另一个斜杠。
exe hello : hello.cpp world /boost//filesystem/<link>static/<threading>multi ;
<threading>
是另一个可以设置为single(单线程)
或multi(多线程)
的特性。如果hello应该链接到线程安全( thread-safe)版本的Boost.Filesystem,则可以相应地设置该特性。
通过引用Jamfile链接Boost C++库可能并不总是有效。如果Boost C++库的安装方式不同,因为它们不是从源代码生成的,那么就不会有任何可以引用的Jamfile。
lib filesystem : : <name>libboost_filesystem <search>C:/libs ;
exe hello : hello.cpp world filesystem : <include>C:/include ;
lib
规则不仅可以用于从源代码生成库。它还用于引用现有预生成的库。
如果lib
不需要从源代码生成库,则第二个参数必须为空。在第三个参数中,特性<name>
和<search>
用于指定库的名称和用于Boost.Build查找库的位置。
以独立于平台的方式指定库名非常重要。例如,对于上面的Jamfile, Boost.Build将尝试在Windows上找到libboost_filesystem.lib文件。通常的文件扩展名会自动附加。
如果您想通过指定文件的确切名称来引用文件,可以使用<file>
特性。
如果应该引用一个系统库,您可以期望Boost.Build知道在哪里可以找到它,那么可以删除<search>
特性。
也可以使用project
规则来确保项目中的所有目标都自动链接到库。
lib filesystem : : <name>libboost_filesystem <search>C:/libs ;
explicit filesystem ;
project : requirements <include>C:/include <library>filesystem ;
lib world : world.cpp ;
必须使用名为<library>
的特性向project
规则添加库依赖项。<library>
必须引用一个使用已知特性<name>
和<search>
的lib
规则。
现在,明确lib
规则非常重要。这是通过使用explicit
规则来实现的。这很重要,因为默认情况下,Jamfile中的所有目标都是生成的。当project
规则为Jamfile中的所有目标定义需求时,它们也是lib
规则的需求。因此,lib
规则指的是它自己。如果lib
规则是explicit(显式)
的,它就不会生成的,也不会发生递归引用。
请注意,只有当规则引用目标时,Jamfile中的规则顺序才重要: 在引用目标之前,必须定义了目标。
最佳实践 Best practices
其他人如何使用Boost.Build How Boost.Build is used by others
由于Boost.Build是一个高级编译系统,如果您保持Jamfiles平台和编译器独立,那么您将获得最大的好处。毕竟,您的想法是在任何平台上使用任何编译器编译C++或C项目,而不需要修改或维护多个jamfile。
您将遇到的一个典型问题是,希望使用的第三方库将安装在不同的目录中。如果希望在Windows和Unix平台上生成项目,路径看起来也非常不同。此外,您可能需要链接某个平台上的一些系统库,而在另一个平台上不需要。
与其尝试将不同平台的路径放在项目的jamfile中,不如依赖每个系统上的配置文件进行特定于系统的设置。实际上,b2在启动时确实会寻找另外两个配置文件。
应该使用site-config.jam
文件为整个系统设置选项, 它是机器特有的, b2是希望在下列目录中找到它, Windows平台上的C:Windows
目录, Unix系统的/etc
目录。因为site-config.jam
是依赖于机器的,所以到本地库的路径是没有问题的。
但是, 用户可能无法创建或更改site-config.jam
。它们要么需要等待系统管理员更新文件,要么再次被迫向自己的jamfile添加特定于系统的路径。由于这两种方法都不是一个好的解决方案,b2还会在用户的主目录中寻找user-config.jam
。在Windows上它是C:Users
的子目录,在Unix上它是/home
的子目录。由于用户可以维护user-config.jam
文件,所以它可能比site-config.jam
更常用。
您可以像使用其他任何Jamfile一样使用site-config.jam
和user-config.jam
。由于这些配置文件不属于项目,而是属于机器或机器上的用户,因此允许它们包含特定于机器的选项。例如,它们可以包含一个using
规则。
using msvc ;
上面的using
规则告诉b2使用msvc工具集。如果您知道系统上只安装了Visual C++,那么将这行代码放入配置文件是有意义的。这样b2就不需要再猜测要使用哪个工具集,也不会遗漏一个警告。
如果您在site-config.jam
或user-config.jam
中定义目标,并且希望在Jamfiles中引用这些目标,则必须使用project
规则来设置名称。
using msvc ;
project user-config ;
lib xml : : <name>libxml <search>C:/lib : : <include>C:/include ;
这里, lib
规则用于引用一个预生成的库,它的名称是libxml
,可以在C:lib
中找到它。使用这个XML库的程序可能需要包含这个库中的头文件。这就是为什么在使用需求中的第五个参数 —— 特性<include>
设置为C:include
: 使用这个规则将继承<include>
特性。
由于project
规则设置了名称为user-config
,所以Jamfile可以通过 /user-config//xml
引用XML库。
exe xmlparser : xmlparser.cpp : <library>/user-config//xml ;
为了生成xmlparser
,必须将程序链接到XML库。尽管库及其头文件的位置可能有所不同,但是Jamfile并不包含任何特定于系统的路径。Jamfile希望在项目user-config
中找到目标xml
。如果这是一个配置文件,那么在将所有配置文件绑定到机器或机器上的用户之后,使用特定于系统的路径是没有问题的。
由于已经创建了Boost.Build来生成和安装Boost C++库,因此在系统配置文件中内置,可以更轻松地使用预生成的Boost C++库。
using msvc ;
project user-config ;
using boost : 1.39 : <include>C:/include/boost-1_39 <library>C:/lib ;
using
规则必须用于引用名为boost的工具集。这个工具集不同于msvc这样的工具集(到目前为止您已经读过的): 它不包含任何将在稍后运行的程序。作为对预生成的Boost C++库的支持,已经在一个工具集中实现了,但是需要使用using
规则。
与其他库一样,Boost C++库的位置可能有所不同。因此,将using
规则放入两个配置文件之一是有意义的。
可以将参数传递给using
规则: 第一个是版本号,第二个是选项列表。在上面的Jamfile中使用了Boost C++库1.39,可以在作为选项传递的目录中找到它。
一旦使用了boost工具集,就可以使用Boost C++库而无需自己定义目标。
import boost ;
boost.use-project 1.39 ;
exe hello : hello.cpp : <library>/boost//thread ;
如果一个程序使用Boost C++库,它可以引用名为boost
的项目中的目标。为了识别项目的boost,必须导入boost模块和使用boost.use-project
规则: 导入boost模块让boost.use-project
规则可用。此规则期望版本号作为其唯一参数。由于可以使用using
规则来引用Boost C++库的不同版本,所以项目可以指定要使用哪个版本。在上面的Jamfile中,程序hello
使用1.39版的Boost.Thread
。
规则参考 Rule reference
Building blocks for Jamfiles
如果您使用Boost.Build管理项目并创建jamfile,那么您将一直使用规则。因此,您应该知道存在哪些规则以及如何使用它们。下表概述了最重要的规则。
在一些参数后面有一个星号、加号或问号。星号意味着可以有任意多个值,加号必须至少有一个值,问号必须是零或恰好有一个值。
Name | Parameters | Description |
---|---|---|
alias | name : sources * : requirements * : default-build * : usage-requirements * | Refer to sources or |
build-project | dir | Refer to a Jamfile in another directory to build a project. |
conditional | condition + : requirements * | Create conditional requirements without using conditional |
exe | name : sources * : requirements * : default-build * : usage-requirements * | Build an executable. |
explicit | target-names * | Make targets explicit. |
glob | wildcards + : excludes * | Reference files in a directory via wildcards. |
glob-tree | wildcards + : excludes * | Reference files in a directory and all subdirectories via wildcards. |
install | name-and-dir : sources * : requirements * : default-build * | Install files to a directory. |
lib | names + : sources * : requirements * : default-build * : usage-requirements * | Build a library. |
project | id ? : options * : * | Set project options. |
unit-test | target : source : properties * | Build and run an executable. |
use-project | id : where | Reference a Jamfile in another directory to use the project id as a target. |
using | toolset-module : * | Select a toolset. |
您的Boost.Build版本可能支持比上面列出的更多的规则。如果您想知道支持哪些规则,您应该查看Boost.Build安装的子目录build
中的文件。
属性参考 Feature reference
生成过程的配置选项 Configuration options for the build process
Name | Values | Description |
---|---|---|
<address-model> |
16, 32, 64, 32_64 | Generate 16-, 32- or 64-bit code. |
<architecture> |
x86, ia64, sparc, power, mips1, mips2, mips3, mips4, mips32, mips32r2, mips64, parisc, arm, combined, combined-x86-power | Set processor family to generate code for. |
<c++-template-depth> |
1, 2, 3, ... | Set maximum template depth. |
<cflags> |
... | Pass flags to C compiler. |
<cxxflags> |
... | Pass flags to C++ compiler |
<debug-symbols> |
on, off | Create debug symbols. |
<def-file> |
... | Set path to def file (specific to Windows DLLs). |
<define> |
... | Define preprocessor directives. |
<embed-manifest> |
on, off | Embed manifest (specific to msvc toolset). |
<host-os> |
aix, bsd, cygwin, darwin, freebsd, hpux, iphone, linux, netbsd, openbsd, osf, qnx, qnxnto, sgi, solaris, unix, unixware, windows | Use in conditional properties if features depend on host operating systems. |
<include> |
... | Set include directories. |
<inlining> |
off, on, full | Inline functions. |
<library> |
... | Link to a library (use in project rule). |
<link> |
shared, static | Link to shared or static version of a library. |
<linkflags> |
... | Pass flags to linker. |
<location> |
... | Set directory (use in install rule). |
<name> |
... | Set basename of a library (use in lib rule). |
<optimization> |
off, speed, space | Generate optimized code. |
<profiling> |
off, on | Generate profiled code. |
<runtime-link> |
shared, static | Link to single-threaded or thread-safe runtime library. |
<search> |
... | Set directory to search for libraries (use in lib rule together with `). |
<source> |
... | Set source in requirements parameter of project rule or in conditional properties. |
<target-os> |
aix, appletv, bsd, cygwin, darwin, freebsd, hpux, iphone, linux, netbsd, openbsd, osf, qnx, qnxnto, sgi, solaris, unix, unixware, windows | Use in conditional properties if features depend on target operating systems. |
<threading> |
single, multi | Build singlethreaded or thread-safe version. |
<toolset> |
gcc, msvc, intel-linux, intel-win, acc, borland, como-linux, cw, dmc, hp_cxx, sun | Use in conditional properties if features depend on toolsets. |
<undef> |
... | Undefine preprocessor directives. |
<use> |
... | Take over only usage requirements of a referenced target but don't do anything else. |
<variant> |
debug, release, profile | Build debug, release or profile version. |
<warnings> |
on, all, off | Switch off warnings. |
<warnings-as-errors> |
off, on | Treat warnings as errors. |
有关Boost.Build特性的完整和最新引用,请在Boost.Build安装的子目录tool
中查找文件builtin.jam
。搜索以feature.feature
开始的行 —— 这是用来定义特性的内部规则。