The cppx library so far relies on four areas of compiler-specific functionality:
- debugger API implementation
(e.g. trace to debugger),
- fixed size types
(although <stdint.h> could be used, that would introduce a dependency on e.g. Boost),
(turning off MSVC sillywarnings so as to be able to compile at highest warning level, and yes it works 🙂 ), and
friendship declarations for class templates,
(MSVC 7.1 requires non-standard syntax, fixed in MSVC 9.0).
Instead of peppering the code with preprocessor conditionals I’ve collected all the compiler specific functionality in header files that abstract away the compiler specific implementation, so that …
- there are no preprocessor conditionals in ordinary source files (all centralized above!), and …
- it’s very clearly apparent what is compiler specific, and how and where it’s implemented for each compiler and OS.
Each such abstracting header file relies on a general “select compiler” mechanism to include the proper compiler-specific file, using a macro
CPPX_COMPILER_SPECIFIC_INCLUDE, like …
In abstracting header file [progrock/cppx/compiler_specific/friendship.h]:
#include <progrock/cppx/compiler_specific/include.h> #include CPPX_COMPILER_SPECIFIC_INCLUDE( friendship.h )
… where the file included for a general standard-conforming compiler defines …
In file [progrock/cppx/compiler_specific/_generic/friendship.h]:
#define CPPX_TEMPLATE_FRIEND( template_args ) \ template< template_args > friend
… while the file included for MSVC (Microsoft Visual C++) defines …
In file [progrock/cppx/compiler_specific/msvc/friendship.h]:
#if _MSC_VER <= 0x0701 # define CPPX_TEMPLATE_FRIEND( template_args ) \ friend #else # include <progrock/cppx/compiler_specific/_generic/friendship.h> #endif
I’m not sure about which version of MSVC fixed this, but at least the friendship syntax is non-standard in MSVC 7.1 and is OK, conforming, in MSVC 9.0.
The general mechanism for bringing in the compiler-specific header, which is of course the C++ equivalent of old WWW “browser sniffing” and therefore sort of brittle and ungood, but probably the Lesser Evil for this kind of thing?:
In file [progrock/cppx/compiler_specific/include.h]:
#include <progrock/cppx/macro_util.h> // CPPX_CONCAT3 #if defined( _MSC_VER ) # define CPPX_CSI_SUBDIR msvc #elif defined( __GNUC__ ) # define CPPX_CSI_SUBDIR gnuc #else # define CPPX_CSI_SUBDIR _generic #endif #define CPPX_CSI_DIR( maindir ) \ CPPX_CONCAT3( maindir, /, CPPX_CSI_SUBDIR ) #define CPPX_CSI_PATH( maindir, path ) \ CPPX_CONCAT3( CPPX_CSI_DIR( maindir ), /, path ) #define CPPX_CSI_BRACKET_PATH( maindir, path ) \ CPPX_CONCAT3( <, CPPX_CSI_PATH( maindir, path ), > ) // To avoid macro replacement a component of 'path' should not be all uppercase // and should not be any of 'assert', 'errno', 'offsetof', 'setjmp', 'va_arg', // 'va_end' or 'va_start', which are macros -- see C++98 §220.127.116.11/5. #define CPPX_COMPILER_SPECIFIC_INCLUDE( path ) \ CPPX_CSI_BRACKET_PATH( progrock/cppx/compiler_specific, path )
Hopefully I won’t get up against some functionality where this scheme doesn’t work well. So far it’s held up.