123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- 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}-${lang}-DetermineCompiler.cmake" OPTIONAL
- RESULT_VARIABLE determinedCompiler)
- if (NOT determinedCompiler)
- include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-DetermineCompiler.cmake" OPTIONAL)
- endif()
- set(_compiler_id_version_compute_${CompilerId} ${_compiler_id_version_compute} PARENT_SCOPE)
- endfunction()
- macro(_simpledefine FEATURE_NAME FEATURE_TESTNAME FEATURE_STRING FEATURE_DEFAULT_STRING)
- if (feature STREQUAL "${FEATURE_NAME}")
- set(def_value "${prefix_arg}_${FEATURE_TESTNAME}")
- string(APPEND file_content "
- # if defined(${def_name}) && ${def_name}
- # define ${def_value} ${FEATURE_STRING}
- # else
- # define ${def_value} ${FEATURE_DEFAULT_STRING}
- # endif
- \n")
- endif()
- endmacro()
- function(write_compiler_detection_header
- file_keyword file_arg
- prefix_keyword prefix_arg
- )
- if (NOT "x${file_keyword}" STREQUAL "xFILE")
- message(FATAL_ERROR "write_compiler_detection_header: FILE parameter missing.")
- endif()
- if (NOT "x${prefix_keyword}" STREQUAL "xPREFIX")
- message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.")
- endif()
- set(options ALLOW_UNKNOWN_COMPILERS ALLOW_UNKNOWN_COMPILER_VERSIONS)
- set(oneValueArgs VERSION EPILOG PROLOG OUTPUT_FILES_VAR OUTPUT_DIR)
- 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 (prefix_arg STREQUAL "")
- message(FATAL_ERROR "A prefix must be specified")
- endif()
- string(MAKE_C_IDENTIFIER ${prefix_arg} cleaned_prefix)
- if (NOT prefix_arg STREQUAL cleaned_prefix)
- message(FATAL_ERROR "The prefix must be a valid C identifier.")
- endif()
- if(NOT _WCD_VERSION)
- set(_WCD_VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
- endif()
- set(_min_version 3.1.0)
- 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.")
- string(APPEND err " It must be set to at least ${_min_version}. ")
- string(APPEND err " Either set the VERSION parameter to the write_compiler_detection_header function, or update")
- string(APPEND err " your minimum required CMake version with the cmake_minimum_required command.")
- message(FATAL_ERROR "${err}")
- endif()
- if(_WCD_OUTPUT_FILES_VAR)
- if(NOT _WCD_OUTPUT_DIR)
- message(FATAL_ERROR "If OUTPUT_FILES_VAR is specified, then OUTPUT_DIR must also be specified.")
- endif()
- endif()
- if(_WCD_OUTPUT_DIR)
- if(NOT _WCD_OUTPUT_FILES_VAR)
- message(FATAL_ERROR "If OUTPUT_DIR is specified, then OUTPUT_FILES_VAR must also be specified.")
- endif()
- get_filename_component(main_file_dir ${file_arg} DIRECTORY)
- if (NOT IS_ABSOLUTE ${main_file_dir})
- set(main_file_dir "${CMAKE_CURRENT_BINARY_DIR}/${main_file_dir}")
- endif()
- if (NOT IS_ABSOLUTE ${_WCD_OUTPUT_DIR})
- set(_WCD_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_WCD_OUTPUT_DIR}")
- endif()
- get_filename_component(out_file_dir ${_WCD_OUTPUT_DIR} ABSOLUTE)
- string(FIND ${out_file_dir} ${main_file_dir} idx)
- if (NOT idx EQUAL 0)
- message(FATAL_ERROR "The compiler-specific output directory must be within the same directory as the main file.")
- endif()
- if (main_file_dir STREQUAL out_file_dir)
- unset(_WCD_OUTPUT_DIR)
- else()
- string(REPLACE "${main_file_dir}/" "" _WCD_OUTPUT_DIR "${out_file_dir}/")
- endif()
- endif()
- set(compilers
- GNU
- Clang
- AppleClang
- MSVC
- SunPro
- Intel
- )
- 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)
- string(APPEND file_content "\n${_WCD_PROLOG}\n")
- endif()
- if (_need_hex_conversion)
- string(APPEND 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 "^c_std_")
-
- elseif (feature MATCHES "^cxx_std_")
-
- elseif (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)
- if(_WCD_OUTPUT_FILES_VAR)
- get_filename_component(main_file_name ${file_arg} NAME)
- set(compiler_file_content_
- "#ifndef ${prefix_arg}_COMPILER_DETECTION_H
- # error This file may only be included from ${main_file_name}
- #endif\n")
- endif()
- foreach(_lang ${_langs})
- set(target_compilers)
- foreach(compiler ${_WCD_COMPILERS})
- _load_compiler_variables(${compiler} ${_lang} ${${_lang}_features})
- if(_cmake_oldestSupported_${compiler})
- list(APPEND target_compilers ${compiler})
- endif()
- endforeach()
- 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)
- string(APPEND file_content "\n#ifdef __cplusplus\n")
- else()
- string(APPEND file_content "\n#ifndef __cplusplus\n")
- endif()
- compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_
- ID_DEFINE
- )
- string(APPEND file_content "${ID_CONTENT}\n")
- set(pp_if "if")
- foreach(compiler ${target_compilers})
- string(APPEND file_content "\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n")
- if(_WCD_OUTPUT_FILES_VAR)
- set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h")
- string(APPEND file_content "\n# include \"${compile_file_name}\"\n")
- endif()
- if(_WCD_OUTPUT_FILES_VAR)
- set(compiler_file_content compiler_file_content_${compiler}_${_lang})
- else()
- set(compiler_file_content file_content)
- endif()
- if(NOT _WCD_ALLOW_UNKNOWN_COMPILER_VERSIONS)
- string(APPEND ${compiler_file_content} "
- # if !(${_cmake_oldestSupported_${compiler}})
- # error Unsupported compiler version
- # endif\n")
- endif()
- 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)
- string(APPEND ${compiler_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()
- string(APPEND ${compiler_file_content} "${_define_item}")
- endforeach()
- endforeach()
- if(pp_if STREQUAL "elif")
- if(_WCD_ALLOW_UNKNOWN_COMPILERS)
- string(APPEND file_content "
- # endif\n")
- else()
- string(APPEND file_content "
- # else
- # error Unsupported compiler
- # endif\n")
- endif()
- endif()
- foreach(feature ${${_lang}_features})
- string(TOUPPER ${feature} feature_upper)
- set(feature_PP "COMPILER_${feature_upper}")
- set(def_name ${prefix_arg}_${feature_PP})
- _simpledefine(c_restrict RESTRICT restrict "")
- _simpledefine(cxx_constexpr CONSTEXPR constexpr "")
- _simpledefine(cxx_final FINAL final "")
- _simpledefine(cxx_override OVERRIDE override "")
- 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(def_fallback "enum { ${prefix_arg}_STATIC_ASSERT_JOIN(${prefix_arg}StaticAssertEnum, __LINE__) = sizeof(${prefix_arg}StaticAssert<X>) }")
- string(APPEND file_content "# if defined(${def_name}) && ${def_name}
- # define ${def_value} static_assert(X, #X)
- # define ${def_value_msg} static_assert(X, MSG)
- # else
- # define ${prefix_arg}_STATIC_ASSERT_JOIN(X, Y) ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y)
- # define ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y) X##Y
- template<bool> struct ${prefix_arg}StaticAssert;
- template<> struct ${prefix_arg}StaticAssert<true>{};
- # define ${def_value} ${def_fallback}
- # define ${def_value_msg} ${def_fallback}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_alignas)
- set(def_value "${prefix_arg}_ALIGNAS(X)")
- string(APPEND file_content "
- # if defined(${def_name}) && ${def_name}
- # define ${def_value} alignas(X)
- # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
- # define ${def_value} __attribute__ ((__aligned__(X)))
- # elif ${prefix_arg}_COMPILER_IS_MSVC
- # define ${def_value} __declspec(align(X))
- # else
- # define ${def_value}
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_alignof)
- set(def_value "${prefix_arg}_ALIGNOF(X)")
- string(APPEND file_content "
- # if defined(${def_name}) && ${def_name}
- # define ${def_value} alignof(X)
- # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
- # define ${def_value} __alignof__(X)
- # elif ${prefix_arg}_COMPILER_IS_MSVC
- # define ${def_value} __alignof(X)
- # endif
- \n")
- endif()
- _simpledefine(cxx_deleted_functions DELETED_FUNCTION "= delete" "")
- _simpledefine(cxx_extern_templates EXTERN_TEMPLATE extern "")
- if (feature STREQUAL cxx_noexcept)
- set(def_value "${prefix_arg}_NOEXCEPT")
- string(APPEND file_content "
- # if defined(${def_name}) && ${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()
- _simpledefine(cxx_nullptr NULLPTR nullptr 0)
- if (feature STREQUAL cxx_thread_local)
- set(def_value "${prefix_arg}_THREAD_LOCAL")
- string(APPEND file_content "
- # if defined(${def_name}) && ${def_name}
- # define ${def_value} thread_local
- # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
- # define ${def_value} __thread
- # elif ${prefix_arg}_COMPILER_IS_MSVC
- # define ${def_value} __declspec(thread)
- # else
- // ${def_value} not defined for this configuration.
- # endif
- \n")
- endif()
- if (feature STREQUAL cxx_attribute_deprecated)
- set(def_name ${prefix_arg}_${feature_PP})
- set(def_value "${prefix_arg}_DEPRECATED")
- string(APPEND file_content "
- # ifndef ${def_value}
- # if defined(${def_name}) && ${def_name}
- # define ${def_value} [[deprecated]]
- # define ${def_value}_MSG(MSG) [[deprecated(MSG)]]
- # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang
- # define ${def_value} __attribute__((__deprecated__))
- # define ${def_value}_MSG(MSG) __attribute__((__deprecated__(MSG)))
- # elif ${prefix_arg}_COMPILER_IS_MSVC
- # define ${def_value} __declspec(deprecated)
- # define ${def_value}_MSG(MSG) __declspec(deprecated(MSG))
- # else
- # define ${def_value}
- # define ${def_value}_MSG(MSG)
- # endif
- # endif
- \n")
- endif()
- endforeach()
- string(APPEND file_content "#endif\n")
- endforeach()
- if(_WCD_OUTPUT_FILES_VAR)
- foreach(compiler ${_WCD_COMPILERS})
- foreach(_lang ${_langs})
- if(compiler_file_content_${compiler}_${_lang})
- set(CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_}")
- string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_${compiler}_${_lang}}")
- set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h")
- set(full_path "${main_file_dir}/${compile_file_name}")
- list(APPEND ${_WCD_OUTPUT_FILES_VAR} ${full_path})
- configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
- "${full_path}"
- @ONLY
- )
- endif()
- endforeach()
- endforeach()
- set(${_WCD_OUTPUT_FILES_VAR} ${${_WCD_OUTPUT_FILES_VAR}} PARENT_SCOPE)
- endif()
- if (_WCD_EPILOG)
- string(APPEND file_content "\n${_WCD_EPILOG}\n")
- endif()
- string(APPEND file_content "\n#endif")
- set(CMAKE_CONFIGURABLE_FILE_CONTENT ${file_content})
- configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
- "${file_arg}"
- @ONLY
- )
- endfunction()
|