| Home | Libraries | People | FAQ | More

## Features

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

    # Declare a new free 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
    {
        "./inline-file.py" $(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 that 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 passed to the compiler's command line.

Besides such portable features there are special 'raw' features that 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 you to pass any command line options to a C++ compiler. The `<include>` feature allows you to pass any string preceded by `-I` and the interpretation is tool-specific. (See the section called “Can I get output of external program as a variable in a Jamfile? ” for an example of very smart usage of that feature). Of course one should always strive to use portable features, but these are still be provided as a backdoor just to make sure Boost.Build does not take away any control from the user.

Using portable features is a good idea because:

- When a portable feature is given a fixed set of values, you can build your project with two different settings of the feature and Boost.Build will automatically use two different directories for generated files. Boost.Build does not try to separate targets built with different raw options.

- Unlike with “raw” features, you don't need to use specific command-line flags in your Jamfile, and it will be more likely to work with other tools.

### Steps for adding a feauture

Adding a feature requires three steps:

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

   - if a feature has several values and significally affects the build, make it “propagated,” so that the whole project is built with the same value by default

   - if a feature does not have a fixed list of values, it must be “free.” For example, the `include` feature is a free feature.

   - if a feature is used to refer to a path relative to the Jamfile, it must be a “path” feature. `include` is also a path feature.

   - if feature is used to refer to some target, it must be a “dependency” feature.

2. Representing the feature value in a target-specific variable. Build actions are command templates modified by Boost.Jam variable expansions. The `toolset.flags` rule sets a target-specific variable to the value of a feature.

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

### Another example

Here's another example. Let's see how we can make a feature that 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 that cares about DEF files is msvc. The following line should be added to it.

       flags msvc.link DEF_FILE <def-file> ;

3. Since the DEF_FILE variable is not used by the msvc.link 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 to translate the internal target name in `DEF_FILE` to a corresponding filename in the `link` action. Without it the expansion of `$(DEF_FILE)` would be a strange symbol that 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 `<variant>` and is a shortcut for a set of features.

It is possible to define your own 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 that 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.