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 which 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 which should be passed to the -l option, and the file property specifies the file location. The search feature specifies paths where the library should be searched. That feature can be specified several time, or 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 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 giu : : <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), which 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 which link to a will also link to b.
One feature of Boost.Build which is very important for libraries is usage requirements. For example, if you write:
lib helpers : helpers.cpp : : : <include>. ;
then compiler include path for all targets which use helpers will contain the directory where the target is defined.path to "helpers.cpp". So, the user need only to add helpers to the list of sources, and don't bother about other requirements. This allows to greatly simplify Jamfiles.
If you don't want shared libraries to include all libraries which 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 which 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 the 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 boost_thread : /boost/thread//boost_thread : <link>static ;
and use only the boost_thread alias in your Jamfiles.
It is also allowed to 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 the built target you should use the stage rule follows the common syntax. For example:
stage dist : hello helpers ;
will cause the targets hello and helpers to be moved to the dist directory. The directory can be changed with the location property:
stage dist : hello helpers : <location>/usr/bin ;
Specifying the names of all libraries to install can be boring. The stage allows to specify only the top-level executable targets to install, and automatically install all dependencies:
stage dist : hello : <traverse-dependencies>on <include-type>EXE <include-type>LIB ;
will find all targets that hello depends on, and install all of the which are either executables or libraries.
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 error, the build system will also return 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 yet.