Writing Jamfiles

| Home | Libraries | People | FAQ | More

## Writing Jamfiles

### Overview

Jamfiles are the thing which is most important to the user, bacause they declare the targets which should be build. Jamfiles are also used for organizing targets -- each Jamfile is a separate project, which can be build independently from the other projects.

Jamfile mostly contain calls to Boost.Build functions, which do all the work, specifically:

- declare main targets

- define project properties

- do various other things

In addition to Jamfiles, Boost.Build has another user-editable file, project-root.jam, which is mostly useful to declare constants global to all the projects. It is described in more detail below.

### Main targets

Main target is a user-defined named entity which can be build, for example a named executable file. Declaring a main target is usually done using one of main target functions. The user can also declare custom main target function.

Most main targets rules in Boost.Build use similiar syntax:

    function-name main-target-name
        : sources
        : requirements
        : default-build
        : usage-requirements
        ;

- "main-target-name" is the name used to request the target on command line and to use it from other main targets. Main target name may contain alphanumeric characters and symbols '-' and '_';
- "sources" is the list of source files and other main targets that must be combined.
- "requirements" is the list of properties that must always be present when this main target is built.
- "default-build" is the list of properties that will be used unless some other value of the same feature is already specified.
- "usage-requirements" is the list of properties that will be propagated to all main targets that use this one, i.e. to all dependents.

Note that the actual requirements, default-build and usage-requirements attributes for a target are obtained by combining the explicitly specified one with those specified for the project where a target is declared.

Some main target rules have shorter list of parameters, and you should consult their documentation for details.

The list of sources specifies what should be processed to get the resulting targets. Most of the time, it's just a list of files. Sometimes, you'd want to use all files with the same extension as sources, in which case you can use the "glob" rule. Here are two examples:

    exe a : a.cpp ;
    exe b : [ glob *.cpp ] ;

Unless you specify a files with absolute path, the name is considered relative to the source directory -- which is typically the same as directory when Jamfile is located, but can be changed as described here

The list of sources can also reference other main targets. The targets in the same project can be referred by using the name, and targets in other project need to specify directory or a symbolic name of the other project. For example:

    lib helper : helper.cpp ;
    exe a : a.cpp helper ;
    exe b : b.cpp ..//utils ;
    exe c : c.cpp /boost/program_options//program_opions ;

The first exe uses the library defined in the same project. The second one uses some target (most likely library) defined by Jamfile one level higher. Finally, the third target uses some C++ Boost library, using the symbolic name to refer to it. More information about it can be found in tutorial and in target id reference.

Requirements are the properties that should always be present when building a target. Typically, they are includes and defines:

    exe hello : hello.cpp : <include>/opt/boost <define>MY_DEBUG ;

In special circumstances, other properties can be used, for example if a library does not work if it's shared, or a file can't be compiled with optimization due to a compiler bug, one can use

    lib util : util.cpp : <link>static ;
    obj main : main.cpp : <optimization>off ;

Sometimes, requirements are necessary only for a specific compiler, or build variant. The conditional properties can be used in that case:

    lib util : util.cpp : <toolset>msvc:<link>static ;

In means when whenever `<toolset>msvc` property is in build properties, the `<link>static` property will be included as well. The conditional requirements can be "chained":

    lib util : util.cpp : <toolset>msvc:<link>static
                          <link>static:<define>STATIC_LINK ;

will set of static link and the `STATIC_LINK` define on the `msvc` toolset.

The default-build attribute is a set of properties which should be used if build request does not specify a value. For example:

    exe hello : hello.cpp : : <threading>multi ;

would build the target in multi-threaded mode, unless the user explicitly requests single-threaded version. The difference between requirements and default-build is that requirements cannot be overriden in any way.

A target of the same name can be declared several times. In that case is declaration is called an alternative. When the target is build, one of the alternatives will be selected and use. Alternatives need not be defined by the same main target rule. The following is OK:

    lib helpers : helpers.hpp ;
    alias helpers : helpers.lib : <toolset>msvc ;

Building of the same main target can differ greatly from platform to platform. For example, you might have different list of sources for different compilers, or different options for those compilers. Two approaches to this are explained in the tutorial.

Sometimes a main target is really needed only by some other main target. For example, a rule that declares a test-suite uses a main target that represent test, but those main targets are rarely needed by themself.

It is possible to declare target inline, i.e. the "sources" parameter may include call to other main rules. For example:

    exe hello : hello.cpp
        [ obj helpers : helpers.cpp : <optimization>off ] ;

Will cause "helpers.cpp" to be always compiled without optimization. It's possible to request main targets declared inline, but since they are considered local, they are renamed to "parent-main-target_name..main-target-name". In the example above, to build only helpers, one should run "bjam hello..helpers".

### Projects

As mentioned before, targets are grouped into project, and each Jamfile is a separate project. Projects are useful because it allows to group related targets together, define properties common to all those targets, and assign a symbolic name to the project, allowing to easily refer to the targets in the project. Two last goals are accompished with the "project" rule.

The rule has this syntax

    project id : <attributes> ;

Here, attributes is a sequence of (attribute-name, attribute-value) pairs. The list of attribute names along with its handling is also shown in the table below. For example, it is possible to write:

    project tennis
        : requirements <threading>multi
        : default-build release
        ;

The possible attributes are listed below.

Project id is a short way to denote a project, as opposed to the Jamfile's pathname. It is a hierarchical path, unrelated to filesystem, such as "boost/thread". Target references make use of project ids to specify a target.

Source location specifies the directory where sources for the project are located.

Project requirements are requirements that apply to all the targets in the projects as well as all subprojects.

Default build is the build request that should be used when no build request is specified explicitly.

The default values for those attributes are given in the table below.

Table 21.1.

Attribute | Name for the 'project' rule | Default value | Handling by the 'project' rule
--- | --- | --- | ---
Project id | none | none | Assigned from the first parameter of the 'project' rule. It is assumed to denote absolute project id.
Source location | `source-location` | The location of jamfile for the project | Sets to the passed value
Requirements | `requirements` | The parent's requirements | The parent's requirements are refined with the passed requirement and the result is used as the project requirements.
Default build | `default-build` | none | Sets to the passed value
Build directory | `build-dir` | If parent has a build dir set, the value of it, joined with the relative path from parent to the current project. Otherwise, empty | Sets to the passed value, interpreted as relative to the project's location.

### Additional Jamfile rules

There's a number of other helper rules which can be used in Jamfile, described in the following table.

Table 21.2.

Rule | Semantic
--- | ---
project | Define project attributes.
use-project | Make another project known.
build-project | Build another project when this one is built.
explicit | States that the target should be built only by explicit request.
glob | Takes a list of wildcards, and returns the list of files which match any of the wildcards.

### Project root

Each project is also associated with project root. That's a root for a tree of projects, which specifies some global properties.

Project root for a projects is the nearest parent directory which contains a file called `project-root.jam`. That file defines certain properties which apply to all projects under project root. It can:

- configure toolsets, via call to `toolset.using`
- refer to other projects, via the `use-project` rule
- declare constants, via the `constant` and `path-constant` rules.

To facilitate declaration of simple projects, Jamfile and project-root can be merged together. To achieve this effect, the project root file should call the `project` rule. The semantic is precisely the same as if the call was made in Jamfile, except that project-root.jam will start to serve as Jamfile. The Jamfile in the directory of project-root.jam will be ignored, and project-root.jam will be able to declare main targets as usual.