| 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 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, 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:

- Since a portable feature have a fixed set of value, you will be able to build your project with two different settings of the feature. Boost.Build will automatically use two different directories for produced files. If you pass raw compiler options, Boost.Build assumes you know what you are doing, and would not care about what options are passed.

- Unlike "raw" features, you don't need to use specific compiler flags in Jamfile, and it will more likely work on other systems.

### 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 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 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.