| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- #.rst:
- # WriteCompilerDetectionHeader
- # ----------------------------
- #
- # This module provides the function write_compiler_detection_header().
- #
- # The ``WRITE_COMPILER_DETECTION_HEADER`` function can be used to generate
- # a file suitable for preprocessor inclusion which contains macros to be
- # used in source code::
- #
- # write_compiler_detection_header(
- # FILE <file>
- # PREFIX <prefix>
- # COMPILERS <compiler> [...]
- # FEATURES <feature> [...]
- # [VERSION <version>]
- # [PROLOG <prolog>]
- # [EPILOG <epilog>]
- # )
- #
- # The ``write_compiler_detection_header`` function generates the
- # file ``<file>`` with macros which all have the prefix ``<prefix>``.
- #
- # ``VERSION`` may be used to specify the API version to be generated.
- # Future versions of CMake may introduce alternative APIs. A given
- # API is selected by any ``<version>`` value greater than or equal
- # to the version of CMake that introduced the given API and less
- # than the version of CMake that introduced its succeeding API.
- # The value of the :variable:`CMAKE_MINIMUM_REQUIRED_VERSION`
- # variable is used if no explicit version is specified.
- # (As of CMake version |release| there is only one API version.)
- #
- # ``PROLOG`` may be specified as text content to write at the start of the
- # header. ``EPILOG`` may be specified as text content to write at the end
- # of the header
- #
- # At least one ``<compiler>`` and one ``<feature>`` must be listed. Compilers
- # which are known to CMake, but not specified are detected and a preprocessor
- # ``#error`` is generated for them. A preprocessor macro matching
- # ``<PREFIX>_COMPILER_IS_<compiler>`` is generated for each compiler
- # known to CMake to contain the value ``0`` or ``1``.
- #
- # Possible compiler identifiers are documented with the
- # :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
- # Available features in this version of CMake are listed in the
- # :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
- # :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties.
- #
- # See the :manual:`cmake-compile-features(7)` manual for information on
- # compile features.
- #
- # Feature Test Macros
- # ===================
- #
- # For each compiler, a preprocessor macro is generated matching
- # ``<PREFIX>_COMPILER_IS_<compiler>`` which has the content either ``0``
- # or ``1``, depending on the compiler in use. Preprocessor macros for
- # compiler version components are generated matching
- # ``<PREFIX>_COMPILER_VERSION_MAJOR`` ``<PREFIX>_COMPILER_VERSION_MINOR``
- # and ``<PREFIX>_COMPILER_VERSION_PATCH`` containing decimal values
- # for the corresponding compiler version components, if defined.
- #
- # A preprocessor test is generated based on the compiler version
- # denoting whether each feature is enabled. A preprocessor macro
- # matching ``<PREFIX>_COMPILER_<FEATURE>``, where ``<FEATURE>`` is the
- # upper-case ``<feature>`` name, is generated to contain the value
- # ``0`` or ``1`` depending on whether the compiler in use supports the
- # feature:
- #
- # .. code-block:: cmake
- #
- # write_compiler_detection_header(
- # FILE climbingstats_compiler_detection.h
- # PREFIX ClimbingStats
- # COMPILERS GNU Clang MSVC
- # FEATURES cxx_variadic_templates
- # )
- #
- # .. code-block:: c++
- #
- # #if ClimbingStats_COMPILER_CXX_VARIADIC_TEMPLATES
- # template<typename... T>
- # void someInterface(T t...) { /* ... */ }
- # #else
- # // Compatibility versions
- # template<typename T1>
- # void someInterface(T1 t1) { /* ... */ }
- # template<typename T1, typename T2>
- # void someInterface(T1 t1, T2 t2) { /* ... */ }
- # template<typename T1, typename T2, typename T3>
- # void someInterface(T1 t1, T2 t2, T3 t3) { /* ... */ }
- # #endif
- #
- # Symbol Macros
- # =============
- #
- # Some additional symbol-defines are created for particular features for
- # use as symbols which may be conditionally defined empty:
- #
- # .. code-block:: c++
- #
- # class MyClass ClimbingStats_DECL_CXX_FINAL
- # {
- # ClimbingStats_DECL_CXX_CONSTEXPR int someInterface() { return 42; }
- # };
- #
- # The ``ClimbingStats_DECL_CXX_FINAL`` macro will expand to ``final`` if the
- # compiler (and its flags) support the ``cxx_final`` feature, and the
- # ``ClimbingStats_DECL_CXX_CONSTEXPR`` macro will expand to ``constexpr``
- # if ``cxx_constexpr`` is supported.
- #
- # The following features generate corresponding symbol defines:
- #
- # ========================== =================================== =================
- # Feature Define Symbol
- # ========================== =================================== =================
- # ``c_restrict`` ``<PREFIX>_RESTRICT`` ``restrict``
- # ``cxx_constexpr`` ``<PREFIX>_CONSTEXPR`` ``constexpr``
- # ``cxx_deleted_functions`` ``<PREFIX>_DELETED_FUNCTION`` ``= delete``
- # ``cxx_extern_templates`` ``<PREFIX>_EXTERN_TEMPLATE`` ``extern``
- # ``cxx_final`` ``<PREFIX>_FINAL`` ``final``
- # ``cxx_noexcept`` ``<PREFIX>_NOEXCEPT`` ``noexcept``
- # ``cxx_noexcept`` ``<PREFIX>_NOEXCEPT_EXPR(X)`` ``noexcept(X)``
- # ``cxx_override`` ``<PREFIX>_OVERRIDE`` ``override``
- # ========================== =================================== =================
- #
- # Compatibility Implementation Macros
- # ===================================
- #
- # Some features are suitable for wrapping in a macro with a backward
- # compatibility implementation if the compiler does not support the feature.
- #
- # When the ``cxx_static_assert`` feature is not provided by the compiler,
- # a compatibility implementation is available via the
- # ``<PREFIX>_STATIC_ASSERT(COND)`` and
- # ``<PREFIX>_STATIC_ASSERT_MSG(COND, MSG)`` function-like macros. The macros
- # expand to ``static_assert`` where that compiler feature is available, and
- # to a compatibility implementation otherwise. In the first form, the
- # condition is stringified in the message field of ``static_assert``. In
- # the second form, the message ``MSG`` is passed to the message field of
- # ``static_assert``, or ignored if using the backward compatibility
- # implementation.
- #
- # ====================== ================================ ===================
- # Feature Define Symbol
- # ====================== ================================ ===================
- # ``cxx_alignas`` ``<PREFIX>_ALIGNAS`` ``alignas``
- # ``cxx_alignof`` ``<PREFIX>_ALIGNOF`` ``alignof``
- # ``cxx_nullptr`` ``<PREFIX>_NULLPTR`` ``nullptr``
- # ``cxx_static_assert`` ``<PREFIX>_STATIC_ASSERT`` ``static_assert``
- # ``cxx_static_assert`` ``<PREFIX>_STATIC_ASSERT_MSG`` ``static_assert``
- # ====================== ================================ ===================
- #=============================================================================
- # Copyright 2014 Stephen Kelly <[email protected]>
- #
- # Distributed under the OSI-approved BSD License (the "License");
- # see accompanying file Copyright.txt for details.
- #
- # This software is distributed WITHOUT ANY WARRANTY; without even the
- # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- # See the License for more information.
- #=============================================================================
- # (To distribute this file outside of CMake, substitute the full
- # License text for the above reference.)
- include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake)
- include(${CMAKE_CURRENT_LIST_DIR}/CMakeCompilerIdDetection.cmake)
- function(_load_compiler_variables CompilerId lang)
- include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-FeatureTests.cmake" OPTIONAL)
- set(_cmake_oldestSupported_${CompilerId} ${_cmake_oldestSupported} PARENT_SCOPE)
- foreach(feature ${ARGN})
- set(_cmake_feature_test_${CompilerId}_${feature} ${_cmake_feature_test_${feature}} PARENT_SCOPE)
- endforeach()
- include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-DetermineCompiler.cmake" OPTIONAL)
- set(_compiler_id_version_compute_${CompilerId} ${_compiler_id_version_compute} PARENT_SCOPE)
- endfunction()
- function(write_compiler_detection_header
- file_keyword file_arg
- prefix_keyword prefix_arg
- )
- if (NOT file_keyword STREQUAL FILE)
- message(FATAL_ERROR "write_compiler_detection_header: FILE parameter missing.")
- endif()
- if (NOT prefix_keyword STREQUAL PREFIX)
- message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.")
- endif()
- set(options)
- set(oneValueArgs VERSION EPILOG PROLOG)
- set(multiValueArgs COMPILERS FEATURES)
- cmake_parse_arguments(_WCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
- if (NOT _WCD_COMPILERS)
- message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one compiler.")
- endif()
- if (NOT _WCD_FEATURES)
- message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one feature.")
- endif()
- if(_WCD_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Unparsed arguments: ${_WCD_UNPARSED_ARGUMENTS}")
- endif()
- if(NOT _WCD_VERSION)
- set(_WCD_VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
- endif()
- set(_min_version 3.1.0) # Version which introduced this function
- if (_WCD_VERSION VERSION_LESS _min_version)
- set(err "VERSION compatibility for write_compiler_detection_header is set to ${_WCD_VERSION}, which is too low.")
- set(err "${err} It must be set to at least ${_min_version}. ")
- set(err "${err} Either set the VERSION parameter to the write_compiler_detection_header function, or update")
- set(err "${err} your minimum required CMake version with the cmake_minimum_required command.")
- message(FATAL_ERROR "${err}")
- endif()
- set(compilers
- GNU
- Clang
- )
- set(_hex_compilers ADSP Borland Embarcadero SunPro)
- foreach(_comp ${_WCD_COMPILERS})
- list(FIND compilers ${_comp} idx)
- if (idx EQUAL -1)
- message(FATAL_ERROR "Unsupported compiler ${_comp}.")
- endif()
- if (NOT _need_hex_conversion)
- list(FIND _hex_compilers ${_comp} idx)
- if (NOT idx EQUAL -1)
- set(_need_hex_conversion TRUE)
- endif()
- endif()
- endforeach()
- set(file_content "
- // This is a generated file. Do not edit!
- #ifndef ${prefix_arg}_COMPILER_DETECTION_H
- #define ${prefix_arg}_COMPILER_DETECTION_H
- ")
- if (_WCD_PROLOG)
- set(file_content "${file_content}\n${_WCD_PROLOG}\n")
- endif()
- if (_need_hex_conversion)
- set(file_content "${file_content}
- #define ${prefix_arg}_DEC(X) (X)
- #define ${prefix_arg}_HEX(X) ( \\
- ((X)>>28 & 0xF) * 10000000 + \\
- ((X)>>24 & 0xF) * 1000000 + \\
- ((X)>>20 & 0xF) * 100000 + \\
- ((X)>>16 & 0xF) * 10000 + \\
- ((X)>>12 & 0xF) * 1000 + \\
- ((X)>>8 & 0xF) * 100 + \\
- ((X)>>4 & 0xF) * 10 + \\
- ((X) & 0xF) \\
- )\n")
- endif()
- foreach(feature ${_WCD_FEATURES})
- if (feature MATCHES "^cxx_")
- list(APPEND _langs CXX)
- list(APPEND CXX_features ${feature})
- elseif (feature MATCHES "^c_")
- list(APPEND _langs C)
- list(APPEND C_features ${feature})
- else()
- message(FATAL_ERROR "Unsupported feature ${feature}.")
- endif()
- endforeach()
- list(REMOVE_DUPLICATES _langs)
- foreach(_lang ${_langs})
- get_property(known_features GLOBAL PROPERTY CMAKE_${_lang}_KNOWN_FEATURES)
- foreach(feature ${${_lang}_features})
- list(FIND known_features ${feature} idx)
- if (idx EQUAL -1)
- message(FATAL_ERROR "Unsupported feature ${feature}.")
- endif()
- endforeach()
- if(_lang STREQUAL CXX)
- set(file_content "${file_content}\n#ifdef __cplusplus\n")
- else()
- set(file_content "${file_content}\n#ifndef __cplusplus\n")
- endif()
- compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_
- ID_DEFINE
- )
- set(file_content "${file_content}${ID_CONTENT}\n")
- set(pp_if "if")
- foreach(compiler ${_WCD_COMPILERS})
- _load_compiler_variables(${compiler} ${_lang} ${${_lang}_features})
- set(file_content "${file_content}\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n")
- set(file_content "${file_content}
- # if !(${_cmake_oldestSupported_${compiler}})
- # error Unsupported compiler version
- # endif\n")
- set(PREFIX ${prefix_arg}_)
- if (_need_hex_conversion)
- set(MACRO_DEC ${prefix_arg}_DEC)
- set(MACRO_HEX ${prefix_arg}_HEX)
- else()
- set(MACRO_DEC)
- set(MACRO_HEX)
- endif()
- string(CONFIGURE "${_compiler_id_version_compute_${compiler}}" VERSION_BLOCK @ONLY)
- set(file_content "${file_content}${VERSION_BLOCK}\n")
- set(PREFIX)
- set(MACRO_DEC)
- set(MACRO_HEX)
- set(pp_if "elif")
- foreach(feature ${${_lang}_features})
- string(TOUPPER ${feature} feature_upper)
- set(feature_PP "COMPILER_${feature_upper}")
- set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
- if (_cmake_feature_test_${compiler}_${feature} STREQUAL "1")
- set(_define_item "\n# define ${prefix_arg}_${feature_PP} 1\n")
- elseif (_cmake_feature_test_${compiler}_${feature})
- set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
- set(_define_item "\n# if ${_cmake_feature_test_${compiler}_${feature}}\n# define ${prefix_arg}_${feature_PP} 1\n# else${_define_item}# endif\n")
- endif()
- set(file_content "${file_content}${_define_item}")
- endforeach()
- endforeach()
- if(pp_if STREQUAL "elif")
- set(file_content "${file_content}
- # else
- # error Unsupported compiler
- # endif\n")
- endif()
- foreach(feature ${${_lang}_features})
- string(TOUPPER ${feature} feature_upper)
- set(feature_PP "COMPILER_${feature_upper}")
- set(def_name ${prefix_arg}_${feature_PP})
- if (feature STREQUAL c_restrict)
- set(def_value "${prefix_arg}_RESTRICT")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} restrict
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_constexpr)
- set(def_value "${prefix_arg}_DECL_${feature_upper}")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} constexpr
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_final)
- set(def_value "${prefix_arg}_DECL_${feature_upper}")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} final
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_override)
- set(def_value "${prefix_arg}_DECL_${feature_upper}")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} override
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_static_assert)
- set(def_value "${prefix_arg}_STATIC_ASSERT(X)")
- set(def_value_msg "${prefix_arg}_STATIC_ASSERT_MSG(X, MSG)")
- set(static_assert_struct "template<bool> struct ${prefix_arg}StaticAssert;\ntemplate<> struct ${prefix_arg}StaticAssert<true>{};\n")
- set(def_standard "# define ${def_value} static_assert(X, #X)\n# define ${def_value_msg} static_assert(X, MSG)")
- set(def_alternative "${static_assert_struct}# define ${def_value} sizeof(${prefix_arg}StaticAssert<X>)\n# define ${def_value_msg} sizeof(${prefix_arg}StaticAssert<X>)")
- set(file_content "${file_content}# if ${def_name}\n${def_standard}\n# else\n${def_alternative}\n# endif\n\n")
- endif()
- if (feature STREQUAL cxx_alignas)
- set(def_value "${prefix_arg}_ALIGNAS(X)")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} alignas(X)
- # elif ${prefix_arg}_COMPILER_IS_GNU
- # define ${def_value} __attribute__ ((__aligned__(X)))
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_alignof)
- set(def_value "${prefix_arg}_ALIGNOF(X)")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} alignof(X)
- # elif ${prefix_arg}_COMPILER_IS_GNU
- # define ${def_value} __alignof__(X)
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_deleted_functions)
- set(def_value "${prefix_arg}_DELETED_FUNCTION")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} = delete
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_extern_templates)
- set(def_value "${prefix_arg}_EXTERN_TEMPLATE")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} extern
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_noexcept)
- set(def_value "${prefix_arg}_NOEXCEPT")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} noexcept
- # define ${def_value}_EXPR(X) noexcept(X)
- # else
- # define ${def_value}
- # define ${def_value}_EXPR(X)
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_nullptr)
- set(def_value "${prefix_arg}_NULLPTR")
- set(file_content "${file_content}
- # if ${def_name}
- # define ${def_value} nullptr
- # else
- # define ${def_value} static_cast<void*>(0)
- # endif
- \n")
- endif()
- endforeach()
- set(file_content "${file_content}#endif\n")
- endforeach()
- if (_WCD_EPILOG)
- set(file_content "${file_content}\n${_WCD_EPILOG}\n")
- endif()
- set(file_content "${file_content}\n#endif")
- set(CMAKE_CONFIGURABLE_FILE_CONTENT ${file_content})
- configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
- "${file_arg}"
- @ONLY
- )
- endfunction()
|