...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
To use the automatically defined predefs one needs to only include the single top-level header:
#include <boost/predef.h>
This defines all the version macros known to the library. For each macro it will be defined to either a zero valued expression for when the particular item is not detected, and to a positive value if it is detected. The predef macros fall onto five categories each with macros of a particular prefix:
BOOST_ARCH_
for system/CPU
architecture one is compiling for.
BOOST_COMP_
for the compiler
one is using.
BOOST_LANG_
for language
standards one is compiling against.
BOOST_LIB_C_
and BOOST_LIB_STD_
for the C and C++ standard
library in use.
BOOST_OS_
for the operating
system we are compiling to.
BOOST_PLAT_
for platforms
on top of operating system or compilers.
BOOST_ENDIAN_
for endianness
of the os and architecture combination.
BOOST_HW_
for hardware
specific features.
BOOST_HW_SIMD
for SIMD
(Single Instruction Multiple Data) detection.
Note | |
---|---|
The detected definitions are for the configuration one is targeting during the compile. In particular in a cross-compile this means the target system, and not the host system. |
One uses the individual definitions to compare against specific versions by
comparing against the BOOST_VERSION_NUMBER
macro. For example, to make a choice based on the version of the GCC C++ compiler
one would:
#include <boost/predef.h> #include <iostream> int main() { if (BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4,0,0)) std::cout << "GCC compiler is at least version 4.0.0" << std::endl; else std::cout << "GCC compiler is at older than version 4.0.0, or not a GCC compiler" << std::endl; return 0; }
As you might notice above the else
clause also covers the case where the particular compiler is not detected.
But one can make the test also test for the detection. All predef definitions
are defined as a zero (0) expression when not detected. Hence one could use
the detection with a natural single condition. For example:
#include <boost/predef.h> #include <iostream> int main() { if (BOOST_COMP_GNUC) std::cout << "This is GNU GCC!" << std::endl; else std::cout << "Not GNU GCC." << std::endl; return 0; }
And since the predef's are preprocessor definitions the same is possible from the preprocessor:
#include <boost/predef.h> #include <iostream> #if BOOST_COMP_GNUC #if BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4,0,0) const char * the_compiler = "GNU GCC, of at least version 4." #else const char * the_compiler = "GNU GCC, less than version 4." #endif #else const char * the_compiler = "Not GNU GCC." #endif int main() { std::cout << the_compiler << std::endl; return 0; }
In addition, for each version macro defined there is an *_AVAILABLE
macro defined only when the particular
aspect is detected. I.e. a definition equivalent to:
#if BOOST_PREDEF_ABC #define BOOST_PREDEF_ABC_AVAILABLE #endif
Also for each aspect there is a macro defined with a descriptive name of what the detection is.
*_EMULATED
macros
Predef definitions are guaranteed to be uniquely detected within one category.
But there are contexts under which multiple underlying detections are possible.
The well known example of this is detection of GCC and MSVC compilers which
are commonly emulated by other compilers by defining the same base macros.
To account for this detection headers are allowed to define *_EMULATED
predefs when this situation is
detected. The emulated predefs will be set to the version number of the detection
instead of the regular predef macro for that detection. For example MSVC will
set BOOST_COMP_MSVC_EMULATED
but not set BOOST_COMP_MSVC
,
and it will also set BOOST_COMP_MSVC_AVAILABLE
.
BOOST_VERSION_NUMBER
macro
All the predefs are defined to be a use of the BOOST_VERSION_NUMBER
macro. The macro takes individual major, minor, and patch value expressions:
#define BOOST_VERSION_NUMBER( major, minor, patch ) ...
The arguments are:
The ranges for each are "enforced" by the use of a modulo ("%"), i.e. truncation, as opposed to a clamp. And hence this means that the limits are enforced only enough to keep from having out-of-range problems. But not enough to prevent other kinds of problems. Like exceeding the range and getting false detections, or non-detections. It is up to the individual predefs to ensure correct usage beyond the range guarantee.
The values for the arguments can be any preprocessor valid constant value expression.
Only constant value arithmetic is used in the definition of the BOOST_VERSION_NUMBER
macro and in any of
the other predef macros. This means that any allowed base is possible, i.e.
binary, octal, decimal, and hexadecimal. For example:
#define MY_APPLICATION_VERSION_NUMBER BOOST_VERSION_NUMBER(2,0xA,015)
Is equivalent to:
#define MY_APPLICATION_VERSION_NUMBER BOOST_VERSION_NUMBER(2,10,13)