The Platform Module¶
To use this module, include ccbase/platform.hpp.
Overview¶
This module does the following three things:
- Provides macros to identify various features describing the host platform.
- Provides macros to invoke compiler attributes in a cross-platform way.
- Provides clean, cross-platform syntax to access compiler intrinsics.
Platform Identification¶
This module attempts to identify the following features of the host platform:
- The compiler.
- The compiler version.
- The processor architecture.
- The processor ABI.
- The operating system.
- The kernel.
- The integer byte order. (Note that the floating-point byte order can potentially be different from the integer byte order, but the header makes no attempt to identify the latter.)
- The platform newline character.
- The platform directory separator.
- The maximum permissible file and path name lengths.
Here are some examples of what this module lets you do:
// Safely include platform-specific header files.
#if PLATFORM_KERNEL == PLATFORM_KERNEL_LINUX || \
PLATFORM_KERNEL == PLATFORM_KERNEL_XNU
#include <unistd.h>
#else
#error Unsupported platform.
#endif
// Safely include compiler-specific header files.
#if PLATFORM_COMPILER == PLATFORM_COMPILER_GCC || \
PLATFORM_COMPILER == PLATFORM_COMPILER_CLANG || \
PLATFORM_COMPILER == PLATFORM_COMPILER_ICC
#include <cpuid.h>
#else
#error Unsupported compiler.
#endif
// Parse a big-endian value.
auto val = get_big_endian_value();
#if PLATFORM_INTEGER_BYTE_ORDER == PLATFORM_BYTE_ORDER_BIG
// Do nothing.
#elif PLATFORM_INTEGER_BYTE_ORDER == PLATFORM_BYTE_ORDER_LITTLE
val = cc::bswap(val);
#else
#error Unsupported platform byte order.
#endif
// Deploy workarounds for buggy compilers.
#if PLATFORM_COMPILER_VERSION < CC_COMPILER_VERSION(3, 2, 1)
// Use workaround.
#else
// Use normal method.
#endif
Since this module relies on knowledge of predefined preprocessor macros, not all of the features tabulated below may be succesfully identified. In the case that a particular feature (say, XXX) is not successfully identified, the corresponding macro PLATFORM_XXX is usually set to the value PLATFORM_XXX_UNKNOWN. However, this is not always the case. Consult the table below for details.
Reference¶
The macros defined by the preprocessor are listed in the table below. Where * is used to indicate the value of a macro, the name of the macro is to be substituted.
Macro | Description | Possible Values |
---|---|---|
PLATFORM_ARCH | Platform CPU architecture. | *_ARM, *_ITANIUM, *_X86, *_UNKNOWN |
PLATFORM_COMPILER | Platform compiler. | *_CLANG, *_COMEAU, *_GCC, *_ICC, *_MSVC, *_UNKNOWN |
PLATFORM_COMPILER_VERSION | Platform compiler version. | Integer value or *_UNKNOWN; compare to CC_COMPILER_VERSION(version, revision, patch). |
PLATFORM_COMPILER_MAJOR_VERSION | Platform compiler major version. | Integer value or *_UNKNOWN. |
PLATFORM_COMPILER_MINOR_VERSION | Platform compiler minor version. | Integer value or *_UNKNOWN. |
PLATFORM_COMPILER_PATCH_LEVEL | Platform compiler patch level. | Integer value or *_UNKNOWN. |
PLATFORM_INTEGER_BYTE_ORDER | Platform byte order. | (* = PLATFORM_BYTE_ORDER) *_LITTLE, *_BIG, *_LITTLE_WORD, *_UNKNOWN |
PLATFORM_KERNEL | Platform kernel. | *_LINUX, *_WINDOWS_NT, *_XNU, *_UNKNOWN |
PLATFORM_OS | Platform operating system. | *_LINUX, *_WINDOWS, *_OS_X, *_UNKNOWN |
PLATFORM_WORD_SIZE | Platform word size. | 32, 64, *_UNKNOWN |
PLATFORM_NEWLINE | Platform newline. | "\n", "\r\n", or undefined. |
PLATFORM_NEWLINE_LENGTH | Platform newline length. | Integer value or *_UNKNOWN. |
PLATFORM_DIRECTORY_SEPARATOR | Platform directory separator. | Character literal or undefined. |
PLATFORM_MAX_FILENAME_LENGTH | Maximum permissible file name length. | Integer value or undefined. |
PLATFORM_MAX_PATHNAME_LENGTH | Maximum permissible path name length. | Integer value or undefined. |
Compiler Attributes¶
This following macros provide access to nonstandard attributes that are commonly implemented by compilers. If the host compiler does not implement the attribute corresponding to a given macro, then the macro expands to nothing.
Macro | Description |
---|---|
CC_ALWAYS_INLINE | Forces the compiler to inline the designated function. |
CC_NEVER_INLINE | Instructs the compiler not to inline the designated function. |
CC_CONST | Tells the compiler that the designated function does not access global memory. |
CC_PURE | Tells the compiler that the designated function does not modify any global memory. |
CC_RESTRICT | Expands to the compiler’s equivalent of the C99 restrict keyword. |
CC_ALIGN(n) | Used to align addresses of static arrays to multiples of n. |
Compiler Intrinsics¶
The following functions provide access to intrinsics commonly defined by compilers.
- T bswap(T value) noexcept¶
This function is defined for each arithmetic type T. It returns a copy of the variable value with the order of the bytes reversed. If the compiler defines an intrinsic to perform this operation, then the intrinsic is used. Otherwise, the library resorts to a default implementation.
- void yield_processor() noexcept¶
Evaluates to the compiler intrinsic that emits the pause instruction for x86_64 CPUs, if such an intrinsic is available. Otherwise, this function does nothing. Using the pause instruction in spinlocks is beneficial for the following three reasons [1]:
- Improves performance by decreasing memory contention within the processor.
- Decreases power consumption.
- Improves performance in the context of hyperthreading, because it avoids saturating use of the ALU.
[1] | http://www.1024cores.net/home/lock-free-algorithms/tricks/spinning |