Boost.Build 简明教程

Boost.Build简明教程(译)
Written by Boris Schäling.

历史:

2018-12-20 姚彧 第一版

目录


介绍 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++库, 你就已经用过了b2b2查找配置文件,读取配置文件, 并编译相应的项目。它还接受各种命令行选项,例如显示在b2编译项目过程中所有的命令。

项目可以很大,可以由许多组件组成,其源代码分布在多个目录中。不需要为整个项目创建一个大的配置文件,组件有自己的配置文件。这对于Boost.Build没有什么不同:在一个大的项目中, 有很多的配置文件,b2会发现和解释它们。

对Boost.Build来说, 有配置文件的目录就是一个项目: 如果目录里有配置文件,就可以编译。对Boost.Build来说, 子目录里的一个组件与包含很多组件的软件没有区别.

b2启动时,它不会在整个文件系统上运行搜索配置文件。它仅在当前工作目录中搜索配置文件。如果没有找到配置文件,它就什么也不做。如果当前工作目录中没有配置文件,b2不会在任何其他目录中搜索配置文件。

b2配置文件叫Jamfile.jam. 有jam后缀的文件叫Jamfiles. 如果b2发现当前目录下有Jamfile, 它会逐层查找父目录中的Jamfilesb2逐层查找上级目录,直到找到Jamroot.jam文件. Jamroot.jamJamfile.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:\Users\Boris\Desktop 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实际上是脚本文件。是在用编程语言编写Jamfileb2不是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时, 使用了两个参数hellohello.cpp

Boost.Build编程语言只基于一种数据类型: 所有内容都是字符串列表。列表可以是空的,也可以包含一个或多个字符串。在上面的Jamfile中,在调用函数exe时, 使用了两个参数, 每个参数包含一个字符串的列表。

exe "hello" : "hello.cpp" ; 

可以使用引号, 但并不必须, 因为列表中的每个值都是字符串数据类型。只有参数包含空格时才使用引号。

规则和第一个参数之间没有特殊的分隔符,但是必须其他参数间必须使用冒号分隔。它还需要以分号结束一行,就像您从C++中习惯的那样。

请注意,Boost.Build的编程语言要求在所有标志周围都有一个空格。例如,冒号的左边和右边必须有一个空格, 分号的左边必须有一个空格。如果标志周围没有空格,b2将无法正确解析jamfile。

如果在包含上面Jamfile和hello.cpp文件的目录中运行b2, 且在Windows上使用msvc工具集,将创建一个子目录bin\msvc-9.0\debug, 用来编译可执行的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 bin\standalone\msvc\msvc-14.1\msvc-setup.bat
compile-c-C++ bin\msvc-14.1\debug\hello.obj
hello.cpp
msvc.link bin\msvc-14.1\debug\hello.exe
msvc.manifest bin\msvc-14.1\debug\hello.exe
...updated 11 targets...

正如您所看到的,从源文件编译可执行文件只需要Jamfile中的一行。如果程序是在Windows上编译的,甚至还有正确的文件扩展名exe

Boost.Build的主要优点是,定义所需的内容, 以告诉编译系统如何生成程序. Boost.Build可以自动完成的任何事情都是自动完成的。您不需要检测构建在某个程序上的平台,以决定是否应该添加exe之类的文件扩展名。您不需要指定如何调用Visual C++之类的编译器来编译源代码。

Boost.Build支持许多现成的工具集。由于可以使用不同的工具集编译程序,Boost.Build使用与工具集相关的目录。通过这种方式,可以用不同的工具集构建程序,而不需要一个工具集不断覆盖另一个工具集生成的文件。

不仅有工具集相关的目录, 还有版本相关的目录。版本是指调试或发行。对于每个版本, 都有一个目录用于编译程序 —— 这样也不会覆盖另一个版本生成的文件。默认情况下, 生成调试版本。这就是为什么会创建子目录bin\msvc-9.0\debug的原因。如果您想要创建一个发行版本, 您可以在命令行中指定版本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++ bin\msvc-14.1\release\hello.obj
hello.cpp
msvc.link bin\msvc-14.1\release\hello.exe
msvc.manifest bin\msvc-14.1\release\hello.exe
...updated 3 targets...

根据variant参数release, 将hello.exe编译到目录bin\msvc-9.0\release.

选择版本是一件经常要做的事情,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>是一个非自由特性,因为它只能被设置为debugrelease, 不允许有其他值。如果设置了其它值,b2会输出错误。

如果您运行b2 variant=debug, 并试图编译hello.exe的调试版, 它不能成功,因为Jamfile包含hello.exe要作为一个发布版编译的要求(requirement)。如果您希望能够在命令行上覆盖该特性,则必须将该特性作为第四个参数而不是第三个参数传递。

exe hello : hello.cpp : : <variant>release ; 

第四个参数包含默认使用但可以覆盖的特性。

如果您要在默认情况下, 生成hello.exe的debug和release版, 那么, 需要两次设置<variant>特性为debugrelease

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 Files\hello. 第二个参数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规则使用命名参数, 而其他规则,如exelib,参数顺序传递。在上面的示例中,参数的名称是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:\boost_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.jamuser-config.jam。由于这些配置文件不属于项目,而是属于机器或机器上的用户,因此允许它们包含特定于机器的选项。例如,它们可以包含一个using规则。

using msvc ; 

上面的using规则告诉b2使用msvc工具集。如果您知道系统上只安装了Visual C++,那么将这行代码放入配置文件是有意义的。这样b2就不需要再猜测要使用哪个工具集,也不会遗漏一个警告。

如果您在site-config.jamuser-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,那么您将一直使用规则。因此,您应该知道存在哪些规则以及如何使用它们。下表概述了最重要的规则。

在一些参数后面有一个星号、加号或问号。星号意味着可以有任意多个值,加号必须至少有一个值,问号必须是零或恰好有一个值。

Table 1. Rules
NameParametersDescription
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

Table 2. Features
NameValuesDescription
<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开始的行 —— 这是用来定义特性的内部规则。

posted @ 2016-06-02 11:45  一花一世界,一叶一乾坤  阅读(7580)  评论(0编辑  收藏  举报