Home | Libraries | People | FAQ | More |
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.
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 another 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
.
The alias
rule follows the common syntax. For
example:
alias core : im reader writer ;
will build the sources and return the generated source targets without modification.
The alias
rule is a convenience tool. If you often build
the same group of targets at the same time, you can define an alias
to save typing.
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.
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 memnonic 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 the 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.
The alias
rule can be used when targets must be installed into several
directories:
install 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 [6]
have no effect when used in requirements of the install
.
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.
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.
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.