Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Use in a non-header only library

A non-header only library is a library which gets built into a shared library or a static library. In a traditional non-header only library all the source code of the library is built into the shared library or static library. A non-header only library also could contain some code which is header only along with the code which consists of the built portion of the library. Because the built portion of a non-header library is code whose functionality is fixed a non-header only library presents a more difficult problem when CXXD is used.

The problem

The reason why a non-header only library presents a problem if CXXD is used is because CXXD does its work at compile time. This means that once the built portions of a non-header only library get compiled and linked the choice for any of the CXXD dual libraries has already been made and essentially encoded into the resulting shared or static library. This choice is based on the compiler and its command line switches when the non-header only library is built. The ability of CXXD to choose, for the end-user of the built portion of the library, at compile time the particular dual library being used is eliminated in such a case.

The solution

There is a solution to the fixed nature of the built portion of a non-header only library using CXXD. It consists of generating more than one variant for the non-header only library based on different CXXD dual possibilities. Each variant would have:

For a particular non-header only library different variants of the library, depending on the CXXD dual library possibilities, are built. Then depending on the end-user's compiler settings when he uses the library the particular correct variant of the library is 'linked' to his code as a shared library or as a static library.

The solution in general

As a simple generalized example without immediately going into all the details, which I will do shortly, let's suppose that a shared or static library, whose current base name is called MyLib, is changed to use the CXXD regex interface in a built portion of the library. The process would be that when MyLib is built it will consist of two variants; one variant when MyLib is built when using the Boost regex library and one variant when MyLib is built when using the C++ standard regex library. In order for this to work I need two separate 'base' names for MyLib, depending on whether Boost regex or C++ standard regex is the dual library for regex when the library is built. The choice of these 'base' names will be encoded into the build process for MyLib so that each variant will have a different library name.

When an end-user uses my library, by including its appropriate header file(s), he links to the correct variant of MyLib depending on whether or not CXXD chooses the Boost regex or C++ standard regex library as the dual library when the regex mod header file gets included.

The solution in detail

Now let's look in detail, using a simple example, how this would be implemented in MyLib's code.

First we have MyLib's functionality which uses the CXXD regex mod. Since MyLib is a non-header only library our functionality will consist of a header file, which the end-user will include, and a source file, which contains the code which will be compiled and linked in order to create MyLib's shared or static library.

When we used a header-only library our regex example was:

// Header file MyHeader.hpp
#include <boost/cxx_dual/regex.hpp>
class MyClass
    {
    public:
    void MyFunction(cxxd_regex_ns::regex & rx) { /* Some functionality */ }
    };

For our non-header only library as the header file for our example, we specify instead:

// Header file MyHeader.hpp
#include <boost/cxx_dual/regex.hpp>
class MyClass
    {
    public:
    void MyFunction(cxxd_regex_ns::regex & rx);
    };

This is very little different from what we presented before with a header-only library. Our difference is that for our non-header only library we are going to compile the implementation of MyClass into a shared or static library. So we now have both our header file and a separate source code file MyHeader.cpp:

// Source file MyHeader.cpp
#include "MyHeader.hpp"
void MyClass::MyFunction(cxxd_regex_ns::regex & rx)
    {
    /* Some Functionality using 'rx' */
    }

At this point we have two problems to solve:

Building the library

The first of our two problems is the easiest to solve. As long as we have a system for building our library where we can specify the name of the library we want along with specifying macros we define for our build on the command line, we always have a solution for our first problem.

In specific terms we are going to specify two builds for our library under two different names, and we are going to specify appropriate CXXD override macros on the command line for each build. For the purposes of our example I will choose the library name 'MyLib' for the build where the Boost regex library will be used and the library name 'MyLib_std' for the build where the C++ standard version of the regex library will be used. When we build 'MyLib' we will pass the regex override macro CXXD_REGEX_USE_BOOST on the command line of the build process. When we build 'MyLib_std' we will pass the regex override macro CXXD_REGEX_USE_STD on the command line of the build process. In Boost bjam terms this would mean, at minimum:

lib MyLib : MyHeader.cpp : <define>CXXD_REGEX_USE_BOOST ;
lib MyLib_std : MyHeader.cpp : <define>CXXD_REGEX_USE_STD ;

Other build systems would have their own syntax for building a library.

This is an instance where we use CXXD override macros which we have not seen before, but it is perfectly valid since we want to force a particular dual library choice when we build our library. The CXXD override macros for the regex mod are specified in the build and not in a header file. This allows us to force a particular dual library when we build the library but otherwise leave the choice of the dual library up to the CXXD mechanism for choosing the library when MyLib is being used.

When the end-user builds the MyLib library he will pass appropriate command line switches which determine whether or not the C++ standard regex library is supported. If the C++ standard regex library is not supported by appropriate command line switches the build of 'MyLib' should still succeed but the build of 'MyLib_std' will fail. This is as it should be. A build of MyLib with the appropriate command line switches ( usually C++11 support ) will succeed in also building 'MyLib_std'.

Linking to the library

The end-user of our built library will include our MyHeader.hpp and whether the Boost regex library is chosen or the C++ standard regex library is chosen will be determined at compile time when the end-user compiles his code. Our problem is that when the end-user includes MyHeader.hpp in a compilation we would like to be able to specify at that time, based on which dual regex library is being used, the correctly named library to which to link.

The solution to our problem lies in auto-linking for those compilers which support it. Without auto-linking what we can do is provide some sort of documentation specifying the name of our library depending on the dual library choice which occurs when the end-user uses our library.

In either case, whether the compiler supports auto-linking or not, what we want to do in MyLib is to create a header file which will encode the correct name of our library as a preprocessor macro depending on our dual library choice. This can be easily done in our example because each dual library has a macro which will tell us at compile time which choice has been made. For our example with the regex library the macro is CXXD_HAS_STD_REGEX, which is 1 if the C++ standard regex library is being used and 0 if the Boost regex library is being used.

Furthermore, for those compilers which support auto-linking, we want to provide whatever compiler mechanism is available to auto-link to our correct library name. For my example I will use the auto-linking mechanism that is built into Boost.Config. We only want this auto-link header file's functionality to be used when we are not building MyLib, ie. when MyLib is being used by another library or executable.

In our example we will add a header file to our MyLib library and call it MyLibName.hpp. We only need to include the low-level implementation regex header since we only need the mod's choice macro to produce our unique variant library names:

// Header file MyLibName.hpp
#include <boost/cxx_dual/impl/regex.hpp>
#if CXXD_HAS_STD_REGEX
    #define MYLIB_LIBRARY_NAME MyLib_std
#else
    #define MYLIB_LIBRARY_NAME MyLib
#endif

We will also add a header file to our MyLib library and call it MyLibLink.hpp:

// Header file MyLibLink.hpp
#include <boost/config.hpp>
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_MY_LIBRARY_NO_LIB) && !defined(MYLIB_BEING_BUILT)
#include "MyLibName.hpp"
#define BOOST_LIB_NAME MYLIB_LIBRARY_NAME
#if defined MYLIB_DYN_LINK
    #define BOOST_DYN_LINK
#endif
#include <boost/config/auto_link.hpp>
#endif

We alter the header file which the end-user sees, MyHeader.hpp, to include our auto-linking code in MyLibLink.hpp:

// Header file MyHeader.hpp
#include <boost/cxx_dual/regex.hpp>
#include "MyLibLink.hpp"
class MyClass
    {
    public:
    void MyFunction(cxxd_regex_ns::regex &);
    };

We want to change our code which builds the MyLib variants to define the MYLIB_BEING_BUILT macro:

lib MyLib : MyHeader.cpp : <define>CXXD_REGEX_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_std : MyHeader.cpp : <define>CXXD_REGEX_USE_STD <define>MYLIB_BEING_BUILT ;

As part of the auto-linking mechanism of Boost.Config the end-user of our library could also define the MYLIB_DYN_LINK, before including MyHeader.hpp in his code, to auto-link to the shared library version instead of the static library version of the appropriate MyLib variant.

For the end-user which is using a compiler that does not support auto-linking we should make sure to document the built variant names of our library depending on whether the end-user compilation chooses the Boost regex library or the C++ standard regex library. That end-user will have to manually link the correct library name in his own code. This is usually done by adding the name of the library to the linker command line.

As an added tool for that end-user whose compiler does not support auto-linking the MyLib build could also create a program which prints to standard output the name of the library to link using the library name generated in our MyLibName.hpp header file. We could do that with a source file called MyLibName.cpp:

// Source file MyLibName.cpp
#include <iostream>
#include "MyLibName.hpp"
#define MYLIB_LIBRARY_NAME_AS_STRING #MYLIB_LIBRARY_NAME
int main()
    {
    std::cout << "The MyLib library name is: '" << MYLIB_LIBRARY_NAME_AS_STRING << "'.";
    return 0;
    }

In our example this could be added to the Boost jam file that builds the library variants as:

exe MyLibName : MyLibName.cpp ;

When the end-user invokes our build jamfile the MyLibName program is built with whatever command line options the end-user uses. Depending on those command line options the MyLibName executable will print the appropriate name of the MyLib library for those options. For an end-user without auto-linking he could then use that name to successful link MyLib to his own library or executable.

In Boost the library name as specified by the library author is often not the actual final generated name of the library, since Boost can decorate the library author's name for his library with other information. Using Boost auto-linking facilities this discrepancy between what the library author passes to the Boost.Config auto-linking mechanism and the actual generated final name of the library is automatically handled. For compilers that do not support auto-linking it is up to the end-user to understand what the generated final name of the library will be as compared to the name given by the library author. The MyLibName program will generate the correct name given by the library author, so it is then up to the user of the library to understand the generated final name. This is no different from what happens when CXXD is not being used.

Working with possible library variants

I have chosen a very simple example in using CXXD in the built portion of a non-header only library. This is because my example uses a single mod in the built code, and the built code consists of a single source file with its corresponding header file. It is quite probable, however, that a non-header only library uses many more mods in the built portion of the library and that the use of mods occurs in many more source files with their corresponding header files. While the exact same principles apply when using a number of mods as using a single one, an important issue that comes up when using a number of mods is whether we have to support all possible library variants and how we would limit the possible variants if necessary.

Let's consider that if the number of separate mods in the built portion of a non-header only library is designated as 'n', we have 2n of different CXXD combinations which the end-user of our library could use. As an example, for just 4 different mods being included, we now have 16 different variants of our library to support and build. Furthermore, when counting the mods being included we must take into account the number of mods being used in the built portion of a non-header only library as not only being those mods our library is directly using but also possibly mods being used by other libraries which our own non-header only library is using in its built portion. Clearly the number of mods in the built portion of a non-header only library may proliferate to an unmanageable amount if we have to build every possible variant.

Despite the fact that there are 2n possible variants it is quite possible that the library developer will choose to support many less variants. In fact very often he may choose to support only two variants. Those two variants are often divided by whether or not the library is being compiled in C++11 mode or not. For most, if not all, of the mods in a given compiler implementation, when compiling in C++11 mode the C++ standard library version of the dual library is available and when not compiling in C++11 mode only the Boost version will be available. So realistically, even when 'n' different mods are being used by the built portion of a non-header only library, the library developer may choose to support only two variants, either all Boost libraries or all C++ standard library equivalents.

Whatever the choice of the number of variants supported in a non-header only library compared to the maximum number of variants possible based on the mods used by that library in its built portion, we need some way to name each of the variants supported and we may need some way to intelligently limit the number of variants supported.

Let's take a look at our example MyLib and let's see what we have to do to support more library variants and possibly limit the number of variants. Imagine that in the source of the library being built we are supporting more than simply the regex mod but also other mods. For the sake of this updated example let's suppose we also are using the array, function, and tuple mods in the built portion of MyLib. We will do this by adding some functionality to our MyHeader interface. In actuality the built portion of a non-header only library will usually encompass far more than a single source/header file pairing, but for the sake of our still fairly simple example we will continue to imagine a single source/header pairing.

Our updated Myheader.hpp will now look like:

// Header file MyHeader.hpp
#include <boost/cxx_dual/array.hpp>
#include <boost/cxx_dual/function.hpp>
#include <boost/cxx_dual/regex.hpp>
#include <boost/cxx_dual/tuple.hpp>
#include "MyLibLink.hpp"
class MyClass
    {
    public:
    void MyFunction(cxxd_regex_ns::regex &);
    void AFunction(cxxd_array_ns::array<int,5> &);
    void AnotherFunction(cxxd_function_ns::function<long (double)> &);
    void YetAnotherFunction(cxxd_tuple_ns::tuple<float,short> &);
    };

Our updated MyHeader.cpp will now look like:

// Source file MyHeader.cpp
#include "MyHeader.hpp"
void MyClass::MyFunction(cxxd_regex_ns::regex & rx)
    {
    /* Some Functionality using 'rx' */
    }
void MyClass::AFunction(cxxd_array_ns::array<int,5> & arr)
    {
    /* Some Functionality using 'arr' */
    }
void MyClass::AnotherFunction(cxxd_function_ns::function<long (double)> & fun)
    {
    /* Some Functionality using 'fun' */
    }
void MyClass::YetAnotherFunction(cxxd_tuple_ns::tuple<float,short> &tup)
    {
    /* Some Functionality using 'tup' */
    }

If we look back at our MyLibName.hpp we can both extend the name of the library to encompass more variants as well as limit the variants we wish to allow. Allowing all our new variants could give us something like:

// Header file MyLibName.hpp
#include <boost/cxx_dual/impl/array.hpp>
#include <boost/cxx_dual/impl/function.hpp>
#include <boost/cxx_dual/impl/regex.hpp>
#include <boost/cxx_dual/impl/tuple.hpp>
#if CXXD_HAS_STD_ARRAY
    #if CXXD_HAS_STD_FUNCTION
        #if CXXD_HAS_STD_REGEX
            #if CXXD_HAS_STD_TUPLE
                #define MYLIB_LIBRARY_NAME MyLib_std
            #else
                #define MYLIB_LIBRARY_NAME MyLib_ar_fn_rx
            #endif
        #elif CXXD_HAS_STD_TUPLE
            #define MYLIB_LIBRARY_NAME MyLib_ar_fn_tp
        #else
            #define MYLIB_LIBRARY_NAME MyLib_ar_fn
        #endif
    #elif CXXD_HAS_STD_REGEX
        #if CXXD_HAS_STD_TUPLE
            #define MYLIB_LIBRARY_NAME MyLib_ar_rx_tp
        #else
            #define MYLIB_LIBRARY_NAME MyLib_ar_rx
        #endif
    #elif CXXD_HAS_STD_TUPLE
        #define MYLIB_LIBRARY_NAME MyLib_ar_tp
    #else
        #define MYLIB_LIBRARY_NAME MyLib_ar
    #endif
#elif CXXD_HAS_STD_FUNCTION
    #if CXXD_HAS_STD_REGEX
        #if CXXD_HAS_STD_TUPLE
            #define MYLIB_LIBRARY_NAME MyLib_fn_rx_tp
        #else
            #define MYLIB_LIBRARY_NAME MyLib_fn_rx
        #endif
    #elif CXXD_HAS_STD_TUPLE
        #define MYLIB_LIBRARY_NAME MyLib_fn_tp
    #else
        #define MYLIB_LIBRARY_NAME MyLib_fn
    #endif
#elif CXXD_HAS_STD_REGEX
    #if CXXD_HAS_STD_TUPLE
        #define MYLIB_LIBRARY_NAME MyLib_rx_tp
    #else
        #define MYLIB_LIBRARY_NAME MyLib_rx
    #endif
#elif CXXD_HAS_STD_TUPLE
    #define MYLIB_LIBRARY_NAME MyLib_tp
#else
    #define MYLIB_LIBRARY_NAME MyLib
#endif

That is some complicated-looking code to just give a name to each variant, but it is really just a series of tests of all 16 combinations of CXXD_HAS_STD_'XXX' for the possible 'XXX' mod being used. It is actually more tedious than really complicated. We just have to choose a naming convention for our variants so that all variant names are unique. In our case the manual naming convention chosen is that each mod where the C++ standard library is being chosen has a two character abbreviation preceded by an underscore appended to the base 'MyLib' name, but if all the mods have the C++ standard library being chosen the mnemonic '_std' is appended to the base 'MyLib' name instead. Furthermore the appends are done in the alphabetical order of mods being used. This manual scheme is purely arbitrary for naming variants when building a non-header only library and, of course, the library developer using CXXD may choose whatever manual scheme he wishes to give each variant he chooses to support a unique name.

Later in this documentation section I will discuss CXXD support in the form of a CXXD macro which which the library developer can use to automate the naming scheme if he wishes with a single invocation of the macro.

Now suppose we do not want to support all variants in MyLib but just a subset of the 16 possible variants in our example. As one case suppose we want to support only those variants where both CXXD array and CXXD function are both using either the Boost library or both are using the C++ standard library. Our changed MyLibName.hpp could then be:

// Header file MyLibName.hpp
#include <boost/cxx_dual/impl/array.hpp>
#include <boost/cxx_dual/impl/function.hpp>
#include <boost/cxx_dual/impl/regex.hpp>
#include <boost/cxx_dual/impl/tuple.hpp>
#if CXXD_HAS_STD_ARRAY
    #if CXXD_HAS_STD_FUNCTION
        #if CXXD_HAS_STD_REGEX
            #if CXXD_HAS_STD_TUPLE
                #define MYLIB_LIBRARY_NAME MyLib_std
            #else
                #define MYLIB_LIBRARY_NAME MyLib_ar_fn_rx
            #endif
        #elif CXXD_HAS_STD_TUPLE
            #define MYLIB_LIBRARY_NAME MyLib_ar_fn_tp
        #else
            #define MYLIB_LIBRARY_NAME MyLib_ar_fn
        #endif
    #else
        #error MyLib - CXXD configuration not supported where array and function differ.
    #endif
#elif CXXD_HAS_STD_FUNCTION
    #error MyLib - CXXD configuration not supported where array and function differ.
#elif CXXD_HAS_STD_REGEX
    #if CXXD_HAS_STD_TUPLE
        #define MYLIB_LIBRARY_NAME MyLib_rx_tp
    #else
        #define MYLIB_LIBRARY_NAME MyLib_rx
    #endif
#elif CXXD_HAS_STD_TUPLE
    #define MYLIB_LIBRARY_NAME MyLib_tp
#else
    #define MYLIB_LIBRARY_NAME MyLib
#endif

We have simplified the file producing half the number of variants as before, and we have produced a means by which we notify the end-user at compile time of the variants we do not support. Of course we could and should also notify the end-user of MyLib in its documentation about the variants we do or do not support. But the nice thing is that we can produce a compile-time error, in the form of a preprocessor error, while still using CXXD to limit the subset of variants.

Later in this documentation section I will discuss CXXD support in the form of a CXXD macro which which the library developer can use to test for all his valid variant possibilities with a single macro invocation.

Suppose we simplify further in a manner I suggested previously where we will only support the two variants which most likely corresponds to the end-user compiling with C++11 on up support or not. Now our MyLibName.hpp gets much simpler:

// Header file MyLibName.hpp
#include <boost/cxx_dual/impl/array.hpp>
#include <boost/cxx_dual/impl/function.hpp>
#include <boost/cxx_dual/impl/regex.hpp>
#include <boost/cxx_dual/impl/tuple.hpp>
#if CXXD_HAS_STD_ARRAY && CXXD_HAS_STD_FUNCTION && CXXD_HAS_STD_REGEX && CXXD_HAS_STD_TUPLE
    #define MYLIB_LIBRARY_NAME MyLib_std
#elif !(CXXD_HAS_STD_ARRAY || CXXD_HAS_STD_FUNCTION || CXXD_HAS_STD_REGEX || CXXD_HAS_STD_TUPLE)
    #define MYLIB_LIBRARY_NAME MyLib
#else
    #error CXXD configuration only supported if all dual libraries are Boost or all dual libraries are C++ standard.
#endif

Here we have further simplified the number of variants, theoretically producing builds which either support C++11 or do not support C++11. Of course this may produce problems if the end-user wants to compile in C++11 mode but the compiler the end-user uses has C++ standard support for one or more of the CXXD modules we are using but not for all of those we are using. In that case the end-user would encounter the preprocessor error directive in the example above. However even in that case the end-user could turn off C++11 mode when compiling and link to the MyLib variant which supports all Boost libraries for the mods without getting an error.

In these examples the library author needs to adjust the build of his library to only build the variants which he allows. In Boost terms this means modifying the jam file which builds his library.

With our first extended example, for all 16 variants, the updated jam file would be, at minimum:

lib MyLib : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_std : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_fn_rx : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_fn_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_fn : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_rx_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_rx : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_ar : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_fn_rx_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_fn_rx : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_fn_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_fn : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_rx_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_rx : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;

With our second extended example, with its 8 variants, the updated jam file would be, at minimum:

lib MyLib : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_std : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_fn_rx : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_fn_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_ar_fn : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_rx_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;
lib MyLib_rx : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_tp : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;

With our third extended example, with its 2 variants, the updated jam file would be, at minimum:

lib MyLib : MyHeader.cpp : <define>CXXD_ARRAY_USE_BOOST <define>CXXD_FUNCTION_USE_BOOST <define>CXXD_REGEX_USE_BOOST <define>CXXD_TUPLE_USE_BOOST <define>MYLIB_BEING_BUILT ;
lib MyLib_std : MyHeader.cpp : <define>CXXD_ARRAY_USE_STD <define>CXXD_FUNCTION_USE_STD <define>CXXD_REGEX_USE_STD <define>CXXD_TUPLE_USE_STD <define>MYLIB_BEING_BUILT ;

Aside from the functional changes in MyLib itself, to use more CXXD mods in the built portion of the library, the changes to a proposed MyLibName.hpp in our example and the changes to the jam file used to build the non-header only library are the only ones that need to be done to support more variants, and possibly limit the variants compared to the total number possible. The rest of the infrastructure in our example remains in place.


PrevUpHomeNext