Boost C++ Libraries of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of boost. Click here for the latest Boost documentation.


Often, we need to control the options passed the invoked tools. This is done with features. Consider an example:

# Declare a new feature
import feature : feature ;
feature verbatim-options : : free ;

# Cause the value of the 'verbatim-options' feature to be
# available as 'OPTIONS' variable inside verbatim.inline-file
import toolset : flags ;
flags verbatim.inline-file OPTIONS <verbatim-options> ;

# Use the "OPTIONS" variable
actions inline-file
    "./" $(OPTIONS) $(<) $(>)

We first define a new feature. Then, the flags invocation says that whenever verbatin.inline-file action is run, the value of the verbatim-options feature will be added to the OPTIONS variable, an can be used inside the action body. You'd need to consult online help (--help) to find all the features of the toolset.flags rule.

Although you can define any set of features and interpret their values in any way, Boost.Build suggests the following coding standard for designing features.

Most features should have a fixed set of values, which is portable (tool neutral) across the class of tools they are designed to work with. The user does not have to adjust the values for a exact tool. For example, <optimization>speed has the same meaning for all C++ compilers and the user does not have to worry about the exact options which are passed to the compiler's command line.

Besides such portable features there are special 'raw' features which allow the user to pass any value to the command line parameters for a particular tool, if so desired. For example, the <cxxflags> feature allows to pass any command line options to a C++ compiler. The <include> feature allows to pass any value to the -I and the interpretation is tool-specific. (There an example of very smart usage of that feature). Of course one should always strive to use the portable features but these should still be provided as a backdoor just to make sure Boost.Build does not take away any control from the user.

Some of the reasons why portable features are better are:

Steps for adding a feauture

Adding a feature requires three steps:

  1. Declaring a feature. For that, the "feature.feature" rule is used. You should have to decide on the set of feature attributes:

    • if feature has several values, and significally affects build, make it "propagated", so that whole project is build with the same value by default

    • if a feature does not have a fixed list of values, it must be "free".

    • if feature is used to refer to a path, it must be "path".

    • if feature is used to refer to some target, it must be "dependency".

  2. Converting the feature value into variable. To use feature in build action, it must be converted into a variable, accessible in build action. This is accomplished by "toolset.flags" rule.

  3. Using the variable. The variable set in step 2 can be used in build action to form command parameters or files.

Another example

Here's an another example. Let's see how we can make a feature which refers to a target. For example, when linking dynamic libraries on windows, one sometimes needs to specify "DEF file", telling what functions should be exported. It would be nice to use this file like this:

        lib a : a.cpp : <def-file>a.def ;

Actually, this feature is already supported, but anyway...

  1. Since the feature refers to a target, it must be "dependency".

    feature def-file : : free dependency ;
  2. One of the toolsets which cares about DEF files is msvc. The following line should be added to it.

    flags DEF_FILE <def-file> ;
  3. Since the DEF_FILE variable is not used by the action, we need to modify it to be:

    actions link bind DEF_FILE
        $(.LD) .... /DEF:$(DEF_FILE) ....

    Note the "bind DEF_FILE" part. It tells bjam that DEF_FILE refers to a file, otherwise the variable will contain internal target name, which is not likely to make sense for the linker.

    We've almost done, but should stop for a small workaround. Add the following code to msvc.jam

    rule link
        DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;

    This is needed to accomodate some bug in bjam, which hopefully will be fixed one day.

Variants and composite features.

Sometimes you want to create a shorcut for some set of features. For example, release is a value of the variant and is a shortcut for a set of features.


It is possible to define your build variants. For example:

variant crazy : <optimization>speed <inlining>off
                <debug-symbols>on <profiling>on ;

will define a new variant with the specified set of properties. You can also extend an existing variant:

variant super_release : release : <define>USE_ASM ;

In this case, super_release will expand to all properties specified by release, and the additional one you've specified.

You are not restricted to using the variant feature only. Here's example which defines a brand new feature:

feature parallelism : mpi fake none : composite link-incompatible ;
feature.compose <parallelism>mpi : <library>/mpi//mpi/<parallelism>none ;
feature.compose <parallelism>fake : <library>/mpi//fake/<parallelism>none ;

This will allow you to specify value of feature parallelism, which will expand to link to the necessary library.