| Home | Libraries | People | FAQ | More

## Adding new predefs

We know that a library like this one will be an eternal work-in-progress. And as such we expect, and look forward to, others contributing corrections and additions to the predefs. With that in mind we need to keep a consistent way of defining the new predefs. Hence all current, and future, predefs follow the same structure and requirements.

#### Requirements of the header

All predefs need to follow a set of requirements:

- The headers must use the Boost Software License.
- The predef must, by default, be defined as `BOOST_VERSION_NUMBER_NOT_AVAILABLE`.
- The predef must be redefined to a non-zero value once detected.
- The predef must, by default, be defined to `BOOST_VERSION_NUMBER_AVAILABLE` when the predef is detected.
- If possible, the predef will be defined as the version number detected.
- The predef must define `*_AVAILABLE` macros as needed.
- The predef must define a symbolic constant string name macro.
- The predef must declare itself, after being defined, for the testing system.
- The predef must guarantee that it is the only one defined as detected per category.
- But a predef can define `*_EMULATED` macros to indicate that it was previously detected by another header and is being "emulated" by the system. Note that the `*_AVAILABLE` macros must still be defined in this situation.

And there are some extra guidelines that predef headers should follow:

- The detection should avoid including extra headers that might otherwise not be included by default.
- If the detection must include a header, prefer guarding it within the detection if possible.
- If the detection must include headers unconditionally, and has a choice of headers to include, prefer the ones with the least impact. I.e. include the one with the minimal set of definitions and other dependencies.

#### Structure of the header

For general consistency it's suggested that new predef headers follow the structure below, as current predef headers do. First we have the copyright and license statement, followed by the include guard:

    /*
    Copyright Jane Doe YYYY
    Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
    */

    #ifndef BOOST_PREDEF_category_tag_H
    #define BOOST_PREDEF_category_tag_H

If the detection depends on the detection of another predef you should include those headers here.

    #include <boost/predef/CATEGORY_TAG/DEPENDENCY.h>

Depending on how you are defining the predef you will at minimum have to include the `version_number.h` header. But you might also want to include the `make.h` header for the version number decomposing utility macros:

    #include <boost/predef/version_number.h>
    #include <boost/predef/make.h>

The Predef library uses Quickbook for documentation and for the individual predefs to appear in the reference section we add in-code documentation followed by the zero-value default definition of the predef macro. We strongly recommend this particular placement of the documentation and default definition because some development environments automatically interpret this and provide in-line help for the macro. In particular this works for the popular Eclipse IDE:

    /*`
    [heading `BOOST_category_tag`]

    Documentation about what is detected.
    */

    #define BOOST_category_tag BOOST_VERSION_NUMBER_NOT_AVAILABLE

Next is the detection and definition of the particular predef. The structure for this is to do a single overall check (`condition_a`) and place further version detection inside this. The first action inside the overall check is to "`#undef BOOST_category_tag`" which undefines the zero-value default. The rest is up to the you how to do the checks for defining the version. But at minimum it must "`#define BOOST_category_tag BOOST_VERSION_NUMBER_AVAILABLE`" as the fallback to minimally indicate that the predef was detected:

    #if (condition_a)
    #   undef BOOST_category_tag
    #   if (condition_b)
    #        define BOOST_category_tag BOOST_VERSION_NUMBER(major,minor,patch)
    #    else
    #        define BOOST_category_tag BOOST_VERSION_NUMBER_AVAILABLE
    #    endif
    #endif

We also need to provide the `*_AVAILABLE` versions of the predef.

    #if BOOST_category_tag
    #   define BOOST_category_tag_AVAILABLE
    #endif

And for convenience we also want to provide a `*_NAME` macro:

    #define BOOST_category_tag_NAME "Name"

The testing of the predef macros is automated to generate checks for all the defined predefs, whether detected or not. To do this we need to declare the predef to the test system. This declaration is empty for regular use. And during the test programs they expand out specially to create informational output:

    #include <boost/predef/detail/test.h>
    BOOST_PREDEF_DECLARE_TEST(BOOST_category_tag,BOOST_category_tag_NAME)

And, of course, we last need to close out the include guard:

    #endif

#### Adding exclusive predefs

For headers of predefs that need to be mutually exclusive in the detection we need to add checks and definitions to detect when the predef is detected by multiple headers.

Internally compiler, operating system, and platforms define `BOOST_PREDEF_DETAIL_COMP_DETECTED`, `BOOST_PREDEF_DEFAIL_OS_DETECTED`, and `BOOST_PREDEF_DETAIL_PLAT_DETECTED` respectively when the predef is first detected. This is used to guard against multiple definition of the detection in later included headers. In those cases the detection would instead be written as:

    #if !BOOST_PREDEF_DETAIL_category_DETECTED && (condition_a)
    #   undef BOOST_category_tag
    #   if (condition_b)
    #        define BOOST_category_tag BOOST_VERSION_NUMBER(major,minor,patch)
    #    else
    #        define BOOST_category_tag BOOST_VERSION_NUMBER(0,0,1)
    #    endif
    #endif

And we also include a header that defines the `*_DETECTED` macro when we have the detection:

    #if BOOST_category_tag
    #   define BOOST_category_tag_AVAILABLE
    #   include <boost/predef/detail/CATEGORY_detected.h>
    #endif

Everything else about the header is the same as the basic detection header.

#### Adding an exclusive but emulated predef

Because compilers are frequently emulated by other compilers we both want to have exclusive detection of the compiler and also provide information that we detected the emulation of the compiler. To accomplish this we define a local `*_DETECTION` macro for the compiler detection. And conditionally define either the base compiler predef `BOOST_COMP_compiler` or the alternate `BOOST_COMP_compiler_EMULATED` predef.

The initial detection would look like:

    #if (condition_a)
    #   if (condition_b)
    #        define BOOST_COMP_tag_DETECTION BOOST_VERSION_NUMBER(major,minor,patch)
    #    else
    #        define BOOST_COMP_tag_DETECTION BOOST_VERSION_NUMBER_AVAILABLE
    #    endif
    #endif

And then we can conditionally define the base or emulated predefs:

    #ifdef BOOST_COMP_tag_DETECTION
    #   if defined(BOOST_PREDEF_DETAIL_COMP_DETECTED)
    #       define BOOST_COMP_tag_EMULATED BOOST_COMP_tag_DETECTION
    #   else
    #       undef BOOST_COMP_tag
    #       define BOOST_COMP_tag BOOST_COMP_tag_DETECTION
    #   endif
    #   define BOOST_category_tag_AVAILABLE
    #   include <boost/predef/detail/comp_detected.h>
    #endif

#### Using utility pattern macros

By including:

    #include <boost/predef/make.h>

One will get a set of utility macros to decompose common version macros as defined by compilers. For example the EDG compiler uses a simple 3-digit version macro (M,N,P). It can be decomposed and defined as:

    #define BOOST_COMP_EDG BOOST_PREDEF_MAKE_N_N_N(__EDG_VERSION__)

The decomposition macros are split into three types: decimal decomposition, hexadecimal decomposition, and date decomposition. They follow the format of using "N" for decimal, "F" for hexadecimal, and "Y", "M", "D" for dates.