最近正在试用 bjam 来编译我的工程,网上到处找不到中文资料,手册又看的迷惑,连闷带猜的研究了半天,总算能编译我的工程了,写一点心得。
如果你使用过 boost 库,也许会对bjam的强大功能有一些认识,bjam是专门为boost库设计的make工具,因此功能超强(其实我觉得过强了,毕竟强大的另一半就是复杂)。 它的一些基础知识可以参考 Jam 使用说明 、Bjam简明教程 ,如果打算拜读官方文档,可以参考 Boost.Build v2官方文档导读。如果阅读本文有任何迷惑,请参考官方文档,本人概不负责。
Jamroot 文件
一个bjam 工程是从 Jamroot 文件开始的,一个解决方案有且只能有一个Jamroot 文件(相当与VC 的 Solution 文件 *.sln)。编译一个工程时,bjam会自动查找这个文件,当前目录没有就到上一层目录,没有再去上一层寻找,直到找到。Jamroot 中的设置会传递给所有工程。
注意:由于bjam 以空字符来切分命令,";" 前必须有一个空格。 "=" 前后也需要空格
Jamfile 文件
Jamfile 文件( 使用 bjam v2 规则的有 v2 后缀 ) 代表了一组工程,执行bjam 命令时,它会在当前目录下查找 Jamfile 文件,并执行之。一个典型的 Jamfile 文件如下:
exe hello : hello.cpp :
这个 jamfile 使用 hello.cpp 编译 hello.exe 文件,注意,头文件会自动被管理,不需要列出。其中参数的意义参看下文。
再看看另一个 jamfile:
project
: requirements
exe hello : hello.cpp ;
exe hello2 : hello.cpp ;
这个文件使用同样的参数(在 project 中定义)来编译 hello.exe 和 hello2.exe。
目录
bjam 使用目录来区分个个工程组,每个子目录下有且仅有一个 Jamfile 文件。
规则(rule)
事实上,JamFile 只提供了一些基本功能,复杂的功能大都是通过规则来实现的,规则基本上相当于我们熟悉的函数。调用方式一般是 rulename param1 : param2 ; 参数之间使用 : 分割(再次提醒,前后需要空格)
读取环境变量
import os ;
BOOST_PATH = [ os.environ BOOST_PATH ] ;
这段代码把环境变量 BOOST_PATH 读到变量 BOOST_PATH 中,以后用 $(BOOST_PATH) 使用这个变量。os 是模块名,environ 是一个规则。
注:import 会在当前和 bjam 目录查找并执行后缀为 jam 的对应模块文件,一般放在文件头上。
获取绝对路径
相对路径很多时候并不能正确工作,因此把相对路径转换为绝对路径来工作更合适。我们可以使用 path-constant 规则(rule)来完成这个工作,
path-constant vername : ../../path ;
这行代码把相对路径(../../path)转换成绝对路径并保存在变量 vername 中。
引用工程
use-project 这个规则可以给一个工程设置一个别名,比如下面这段代码,把 ./core 目录下的工程(由 core 目录下的 jamfile 定义)定义为 "/library-cc/core":
use-project /library-cc/core : ./core ;
如果需要编译的文件引用了这个工程,就可以直接使用 "/library-cc/core":
exe myproject : hello.cpp /library-cc/core//core ;
这样编译 myproject 的时候,会把 ./core 目录下的 jamfile 文件中定义的 lib core 连接进来。
工程的基础配置
使用 project 规则可以为多个工程设置基础配置。
属性 | 名称 | 默认值 | 说明 |
---|---|---|---|
Project id | none | none | 工程的绝对名称 |
Source location | source-location | 当前工程jamfile 文件所在目录 | 设置原文件的查找目录 |
Requirements | requirements | 父需求 | 父工程的需求(requirements)由已传递的需求精炼而来,其结果被项目需求使用 |
Default build | default-build | none | 默认编译 |
Build directory | build-dir | 编译路径(输出路径) |
例子:
project
: requirements
: default-build release
: build-dir ../output
;
这段代码定义了一组默认属性,每个
名称 | 可选值 | 解释 |
---|---|---|
包含路径 | ||
库路径 |
||
single multi |
线程 |
|
full speed space off |
优化参数 |
|
宏定义 |
||
static shared |
连接类型 |
预编译头
cpp-pch 规则可以编译预编译头文件。
用法: cpp-pch [名称] : [头文件] : [参数列表] ;
比如:
cpp-pch mypch
: ../inc/pch.h
:
;
目标文件
这里的几个规则定义输出目标文件,使用的参数和 project 规则基本一样,区别就是多了第二个参数,是cpp文件列表。
exe | 编译一个可执行文件 |
lib | 编译一个库文件 |
例子:
lib core
: mypch [ glob-tree $(source-core)/src : *.cxx : .svn ] ;
这条指令递归查询 $(source-core)/src 目录下的所有 *.cxx 文件(排除 .svn 目录,如果不想递归查询目录,也就是不查询子目录,可以使用 glob 而不是 glob-tree),把这些文件编译为 core.lib 文件。其中,mypch 是前面定义的预编译头。
额外的库
在exe中引用额外库的方法如下:
# 系统库列表
local .system_lib = kernel32 comctl32 rpcrt4 winmm user32 advapi32 odbc32 shell32 gdi32 comdlg32 oleaut32 ole32 ;
lib $(.system_lib) ;
exe hello : hello.cpp $(.system_lib) ;
编译一个子工程
build-project 规则可以要求 bjam 编译一个子工程。
例子:
build-project /library-cc/core//mycore ;
bjam 会编译 /library-cc/core ( 由use-project 定义 ) 里面的 mycore.lib 。
install (安装)
install 规则定义了执行 bjam install 时要复制的文件。
用法:
install [名称] : [要复制的目标列表] : [参数] ;
参数中使用
例子
install dist : hello helpers :
注意:
别名
alias 规则可以给工程之类的定义了一个别名。