![]() |
Home | Libraries | People | FAQ | More |
This section describes main targets types that Boost.Build supports of-of-the-box. Unless otherwise noted, all mentioned main target rules have the common signature, described in ???.
Programs are created using the exe rule, which follows the common syntax. For example:
exe hello : hello.cpp some_library.lib /some_project//library
: <threading>multi
;
This will create an executable file from the sources -- in this case, one C++ file, one library file present in the same directory, and another library that is created by Boost.Build. Generally, sources can include C and C++ files, object files and libraries. Boost.Build will automatically try to convert targets of other types.
![]() |
Tip |
|---|---|
On Windows, if an application uses dynamic libraries, and both the application and the libraries are built by Boost.Build, its not possible to immediately run the application, because the PATH environment variable should include the path to the libraries. It means you have to either add the paths manually, or place the application and the libraries to the same directory, for example using the stage rule. | |
Libraries are created using the lib rule, which follows the common syntax. For example:
lib helpers : helpers.cpp : <include>boost : : <include>. ;
In the most common case, the lib creates a library from the specified sources. Depending on the value of <link> feature the library will be either static or shared. There are two other cases. First is when the library is installed somewhere in compiler's search paths, and should be searched by the compiler (typically, using the -l option). The second case is where the library is available as a prebuilt file and the full path is known.
The syntax for these case is given below:
lib z : : <name>z <search>/home/ghost ; lib compress : : <file>/opt/libs/compress.a ;
The name property specifies the name that should be passed to the -l option, and the file property specifies the file location. The search feature specifies paths in which to search for the library. That feature can be specified several times, or it can be omitted, in which case only default compiler paths will be searched.
The difference between using the file feature as opposed to the name feature together with the search feature is that file is more precise. A specific file will be used. On the other hand, the search feature only adds a library path, and the name feature gives the basic name of the library. The search rules are specific to the linker. For example, given these definition:
lib a : : <variant>release <file>/pool/release/a.so ; lib a : : <variant>debug <file>/pool/debug/a.so ; lib b : : <variant>release <file>/pool/release/b.so ; lib b : : <variant>debug <file>/pool/debug/b.so ;
It's possible to use release version of a and debug version of b. Had we used the name and search features, the linker would always pick either release or debug versions.
For convenience, the following syntax is allowed:
lib z ; lib gui db aux ;
and is does exactly the same as:
lib z : : <name>z ; lib gui : : <name>gui ; lib db : : <name>db ; lib aux : : <name>aux ;
When a library uses another library you should put that other library in the list of sources. This will do the right thing in all cases. For portability, you should specify library dependencies even for searched and prebuilt libraries, othewise, static linking on Unix won't work. For example:
lib z ; lib png : z : <name>png ;
![]() |
Note |
|---|---|
When a library (say, a), that has another library, (say, b) is linked dynamically, the b library will be incorporated in a. (If b is dynamic library as well, then a will only refer to it, and not include any extra code.) When the a library is linked statically, Boost.Build will assure that all executables that link to a will also link to b. | |
One feature of Boost.Build that is very important for libraries is usage requirements. For example, if you write:
lib helpers : helpers.cpp : : : <include>. ;
then the compiler include path for all targets that use helpers will contain the directory where the target is defined.path to "helpers.cpp". The user only needs to add helpers to the list of sources, and needn't consider the requirements its use imposes on a dependent target. This feature greatly simplifies Jamfiles.
![]() |
Note |
|---|---|
|
If you don't want shared libraries to include all libraries that are specified in sources (especially statically linked ones), you'd need to use the following: lib b : a.cpp ; lib a : a.cpp : <use>b : : <library>b ; This specifies that a uses b, and causes all executables that link to a also link to b. In this case, even for shared linking, the a library won't even refer to b. | |
The alias rule gives alternative name to a group of targets. For example, to give the name core to a group of three other targets with the following code:
alias core : im reader writer ;
Using core on the command line, or in the source list of any other target is the same as explicitly using im, reader, and writer, but it is just more convenient.
Another use of the alias rule is to change build properties. For example, if you always want static linking for a specific C++ Boost library, you can write the following:
alias threads : /boost/thread//boost_thread : <link>static ;
and use only the threads alias in your Jamfiles.
You can also specify usage requirements for the alias target. If you write the following:
alias header_only_library : : : : <include>/usr/include/header_only_library ;
then using header_only_library in sources will only add an include path. Also note that when there are some sources, their usage requirements are propagated, too. For example:
lib lib : lib.cpp : : : <include>. ; alias lib_alias ; exe main : main.cpp lib_alias ;
will compile main.cpp with the additional include.
This section describes various ways to install built target and arbitrary files.
For installing a built target you should use the install rule, which follows the common syntax. For example:
install dist : hello helpers ;
will cause the targets hello and helpers to be moved to the dist directory, relative to Jamfile's directory. The directory can be changed with the location property:
install dist : hello helpers : <location>/usr/bin ;
While you can achieve the same effect by changing the target name to /usr/bin, using the location property is better, because it allows you to use a mnemonic target name.
The location property is especially handy when the location is not fixed, but depends on build variant or environment variables:
install dist : hello helpers : <variant>release:<location>dist/release
<variant>debug:<location>dist/debug ;
install dist2 : hello helpers : <location>$(DIST) ;
See also conditional properties and environment variables
Specifying the names of all libraries to install can be boring. The install allows you to specify only the top-level executable targets to install, and automatically install all dependencies:
install dist : hello
: <install-dependencies>on <install-type>EXE
<install-type>LIB
;
will find all targets that hello depends on, and install all of those which are either executables or libraries. More specifically, for each target, other targets that were specified as sources or as dependency properties, will be recursively found. One exception is that targets referred with the use feature are not considered, because that feature is typically used to refer to header-only libraries. If the set of target types is specified, only targets of that type will be installed, otherwise, all found target will be installed.
By default, the install rules will stip paths from it's sources. So, if sources include a/b/c.hpp, the a/b part will be ignored. To make the install rule preserve the directory hierarchy you need to use the install-source-root feature to specify the root of the hierarchy you are installing. Relative paths from that root will be preserved. For example, if you write:
install headers
: a/b/c.h
: <location>/tmp <install-source-root>a
;
the a file named /tmp/b/c.h will be created.
The alias rule can be used when targets must be installed into several directories:
alias install : install-bin install-lib ; install install-bin : applications : /usr/bin ; install install-lib : helper : /usr/lib ;
Because the install rule just copies targets, most free features [7] have no effect when used in requirements of the install rule. The only two which matter are dependency and, on Unix, dll-path.
![]() |
Note |
|---|---|
(Unix specific). On Unix, executables built with Boost.Build typically contain the list of paths to all used dynamic libraries. For installing, this is not desired, so Boost.Build relinks the executable with an empty list of paths. You can also specify additional paths for installed executables with the dll-path feature. | |
Boost.Build has convenient support for running unit tests. The simplest way is the unit-test rule, which follows the common syntax. For example:
unit-test helpers_test : helpers_test.cpp helpers ;
The unit-test rule behaves like the exe rule, but after the executable is created it is run. If the executable returns an error code, the build system will also return an error and will try running the executable on the next invocation until it runs successfully. This behaviour ensures that you can't miss a unit test failure.
By default, the executable is run directly. Sometimes, it's desirable to run the executable using some helper command. You should use the testing.launcher property to specify the name of the helper command. For example, if you write:
unit-test helpers_test
: helpers_test.cpp helpers
: <testing.launcher>valgrind
;
The command used to run the executable will be:
valgrind bin/$toolset/debug/helpers_test
There are rules for more elaborate testing: compile, compile-fail, run and run-fail. They are more suitable for automated testing, and are not covered here.
Sometimes, the builtin target types are not enough, and you want Boost.Build to just run specific commands. There are two main target rules that make it possible: make and notfile.
The make rule is used when you want to create one file from a number of sources using some specific command. The notfile is used to unconditionally run a command.
Suppose you want to create file file.out from file file.in by running command in2out. Here's how you'd do this in Boost.Build:
actions in2out
{
in2out $(<) $(>)
}
make file.out : file.in : @in2out ;
If you run bjam and file.out does not exist, Boost.Build will run the in2out command to create that file. For more details on specifying actions, see the section called “Boost.Jam Language”.
![]() |
Note |
|---|---|
The make rule is useful to express custom transformation that are used just once or twice in your project. For transformations that are used often, you are advised to declare new generator, as described in the section called “Tools and generators”. | |
It could be that you just want to run some command unconditionally, and that command does not create any specific files. The, you can use the notfile rule. For example:
notfile echo_something : @echo ;
actions echo
{
echo "something"
}
The only difference from the make rule is that the name of the target is not considered a name of a file, so Boost.Build will unconditionally run the action.
Precompiled headers is a mechanism to speed up compilation by creating a partially processed version of some header files, and then using that version during compilations rather then repeatedly parsing the original headers. Boost.Build supports precompiled headers with gcc and msvc toolsets.
To use precompiled headers, follow these steps:
Create a header that includes big headers used by your project. It's better to include only headers that are sufficiently stable — like headers from the compiler, and external libraries. Please wrap the header in #ifdef BOOST_BUILD_PCH_ENABLED, so that the potentially expensive inclusion of headers is not done when PCH is not enabled. Include the new header at the top of your source files.
Declare new Boost.Build target for the precompiled header and add that precompiled header to sources of the target whose compilation you want to speed up:
cpp-pch pch : header.hpp ; exe main : main.cpp pch ;
You can use the c-pch if you want to use the precompiled header in C programs.
The pch example in Boost.Build distribution can be used as reference.
Please note the following:
The inclusion of the precompiled header must be the first thing in a source file, before any code or preprocessor directives.
The build properties used to build the sources and the preprocessed must be the same. Consider using project requirements to assure this.
Precompiled headers must be used purely as a way to improve compilation time, not to save the number of include statements. If a source file needs to include some header, explicitly include it in the source file, even if the same header is included from the precompiled header. This makes sure that your project will build even if precompiled headers are not supported.
Usually, Boost.Build handles implicit dependendies completely automatically. For example, for C++ files, all #include statements are found and handled. The only aspect where user help might be needed is implicit dependency on generated files.
By default, Boost.Build handles such dependencies within one main target. For example, assume that main target "app" has two sources, "app.cpp" and "parser.y". The latter source is converted into "parser.c" and "parser.h". Then, if "app.cpp" includes "parser.h", Boost.Build will detect this dependency. Moreover, since "parser.h" will be generated into a build directory, the path to that directory will automatically added to include path.
Making this mechanism work across main target boundaries is possible, but imposes certain overhead. For that reason, if there's implicit dependency on files from other main targets, the <implicit-dependency> [ link ] feature must be used, for example:
lib parser : parser.y ; exe app : app.cpp : <implicit-dependency>parser ;
The above example tells the build system that when scanning all sources of "app" for implicit-dependencies, it should consider targets from "parser" as potential dependencies.
A feature that combines several low-level features, making it easy to request common build configurations.
Allowed values: debug, release, profile.
The value debug expands to
<optimization>off <debug-symbols>on <inlining>off <runtime-debugging>on
The value release expands to
<optimization>speed <debug-symbols>off <inlining>full <runtime-debugging>off
The value profile expands to the same as release, plus:
<profiling>on <debug-symbols>on
User can define his own build variants using the variant rule from the common module.
Notee: Runtime debugging is on in debug builds to suit the expectations of people used to various IDEs.
A feature that controls how libraries are built.
Allowed values: shared, static
Controls automatic generation of dll-path properties.
Allowed values: true, false. This property is specific to Unix systems. If an executable is built with <hardcode-dll-paths>true, the generated binary will contain the list of all the paths to the used shared libraries. As the result, the executable can be run without changing system paths to shared libraries or installing the libraries to system paths. This is very convenient during development. Plase see the FAQ entry for details. Note that on Mac OSX, the paths are unconditionally hardcoded by the linker, and it's not possible to disable that behaviour.
off - disables all warnings.
on - enables default warning level for the tool.
all - enables all warnings.
Allowed values: no
The build feature is used to conditionally disable build of a target. If <build>no is in properties when building a target, build of that target is skipped. Combined with conditional requirements this allows to skip building some target in configurations where the build is known to fail.
The tag feature is used to customize the name of the generated files. The value should have the form:
@rulename
where rulename should be a name of a rule with the following signature:
rule tag ( name : type ? : property-set )
The rule will be called for each target with the default name computed by Boost.Build, the type of the target, and property set. The rule can either return a string that must be used as the name of the target, or empty string, in which case the default name will be used.
Most typical use of the tag feature is to encode build properties, or library version in library target names. You should take care to return non-empty string from the tag rule only for types you care about — otherwise, you might end up modifying names of object files, generated header file and other targets for which changing names does not make sense.