Common tasksThis 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 .
ProgramsexePrograms 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.
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. See .
LibrariesLibraries 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
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 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 ;
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.
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.
Alias
The alias rule gives an 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 an alias has sources, their usage
requirements are propagated as well. For example:
lib library1 : library1.cpp : : : <include>/library/include1 ;
lib library2 : library2.cpp : : : <include>/library/include2 ;
alias static_libraries : library1 library2 : <link>static ;
exe main : main.cpp static_libraries ;
will compile main.cpp with additional includes
required for using the specified static libraries.
InstallingThis section describes various ways to install built target
and arbitrary files.Basic installFor 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
Installing with all dependencies
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.
Preserving Directory Hierarchyinstall-source-rootBy 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 glob-tree rule
can be used to find all files below a given directory, making
it easy to install entire directory tree.Installing into Several DirectoriesThe 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 see the definition of "free" in .
have no effect when used in requirements of the install rule.
The only two which matter are
dependency and, on Unix,
dll-path.
(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.
TestingBoost.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 few specialized testing rules, listed below:
rule compile ( sources : requirements * : target-name ? )
rule compile-fail ( sources : requirements * : target-name ? )
rule link ( sources + : requirements * : target-name ? )
rule link-fail ( sources + : requirements * : target-name ? )
They are are given a list of sources and requirements.
If the target name is not provided, the name of the first
source file is used instead. The compile*
tests try to compile the passed source. The link*
rules try to compile and link an application from all the passed sources.
The compile and link rules expect
that compilation/linking succeeds. The compile-fail
and link-fail rules, on the opposite, expect that
the compilation/linking fails.
There are two specialized rules for running applications, which
are more powerful than the unit-test rule. The
run rule has the following signature:
rule run ( sources + : args * : input-files * : requirements * : target-name ?
: default-build * )
The rule builds application from the provided sources and runs it,
passing args and input-files
as command-line arguments. The args parameter
is passed verbatim and the values of the input-files
parameter are treated as paths relative to containing Jamfile, and are
adjusted if bjam is invoked from a different
directory. The run-fail rule is identical to the
run rule, except that it expects that the run fails.
All rules described in this section, if executed successfully,
create a special manifest file to indicate that the test passed.
For the unit-test rule the files is named
target-name.passed and
for the other rules it is called
target-name.test.
The run* rules also capture all output from the program,
and store it in a file named
target-name.output.The run and the run-fail rules, if
the test passes, automatically delete the linked executable, to
save space. This behaviour can be suppressed by passing the
--preserve-test-targets command line option.It is possible to print the list of all test targets (except for
unit-test) declared in your project, by passing
the --dump-tests command-line option. The output
will consist of lines of the form:
boost-test(test-type) path : sourcesIt is possible to process the list of tests, the output of
bjam during command run, and the presense/absense of the
*.test files created when test passes into
human-readable status table of tests. Such processing utilities
are not included in Boost.Build.Custom commandsWhen you use most of main target rules, Boost.Build automatically
figures what commands to run and it what order. As soon as you want
to use new file types, or support new tools, one approach is to
extend Boost.Build to smoothly support them, as documented in
. However, if there's a single
place where the new tool is used, it might be easier to just
explicitly specify the commands to run.Three main target rules can be used for that. The
make rule allows you to construct
a single file from any number of source file, by running a
command you specify. The notfile rule
allows you to run an arbitrary command, without creating any files.
Finaly, the generate rule allows you
to describe transformation using Boost.Build's virtual targets.
This is higher-level than file names that the make rule operates with,
and allows you to create more than one target, or create differently
named targets depending on properties, or use more than one
tool.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 .
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.
The generate rule is used when
you want to express transformations using Boost.Build's virtual targets,
as opposed to just filenames. The generate
rule has the standard main target rule signature, but you are required
to specify the generating-rule property. The value
of the property should be in the form
@rule-name and the named
rule should have the following signature:
rule generating-rule ( project name : property-set : sources * )
and will be called with an instance of the project-target
class, the name of the main target, an instance of the
property-set class containing build properties,
and the list of instances of the virtual-target class
corresponding to sources.
The rule must return a list of virtual-target instances.
The interface of the virtual-target class can be learned
by looking at the build/virtual-target.jam file.
The generate example in Boost.Build distribution
illustrates how the generate rule can be used.
Precompiled HeadersPrecompiled 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 a new Boost.Build target for the precompiled header
and add that precompiled header to the sources of the target whose compilation
you want to speed up:
cpp-pch pch : pch.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 compile the source files
and the precompiled header 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.On the gcc compiler, the name of the header being
precompiled must be equal to the name of the cpp-pch
target. This is gcc requirement.Prior to version 4.2, the gcc compiler did not
handle anonymous namespaces in precompiled headers, which
limit their utility. See the bug
report for details.Generated headersUsually, 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.