WriteCompilerDetectionHeader.cmake 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. #.rst:
  4. # WriteCompilerDetectionHeader
  5. # ----------------------------
  6. #
  7. # This module provides the function write_compiler_detection_header().
  8. #
  9. # The ``WRITE_COMPILER_DETECTION_HEADER`` function can be used to generate
  10. # a file suitable for preprocessor inclusion which contains macros to be
  11. # used in source code::
  12. #
  13. # write_compiler_detection_header(
  14. # FILE <file>
  15. # PREFIX <prefix>
  16. # [OUTPUT_FILES_VAR <output_files_var> OUTPUT_DIR <output_dir>]
  17. # COMPILERS <compiler> [...]
  18. # FEATURES <feature> [...]
  19. # [BARE_FEATURES <feature> [...]]
  20. # [VERSION <version>]
  21. # [PROLOG <prolog>]
  22. # [EPILOG <epilog>]
  23. # [ALLOW_UNKNOWN_COMPILERS]
  24. # [ALLOW_UNKNOWN_COMPILER_VERSIONS]
  25. # )
  26. #
  27. # The ``write_compiler_detection_header`` function generates the
  28. # file ``<file>`` with macros which all have the prefix ``<prefix>``.
  29. #
  30. # By default, all content is written directly to the ``<file>``. The
  31. # ``OUTPUT_FILES_VAR`` may be specified to cause the compiler-specific
  32. # content to be written to separate files. The separate files are then
  33. # available in the ``<output_files_var>`` and may be consumed by the caller
  34. # for installation for example. The ``OUTPUT_DIR`` specifies a relative
  35. # path from the main ``<file>`` to the compiler-specific files. For example:
  36. #
  37. # .. code-block:: cmake
  38. #
  39. # write_compiler_detection_header(
  40. # FILE climbingstats_compiler_detection.h
  41. # PREFIX ClimbingStats
  42. # OUTPUT_FILES_VAR support_files
  43. # OUTPUT_DIR compilers
  44. # COMPILERS GNU Clang MSVC Intel
  45. # FEATURES cxx_variadic_templates
  46. # )
  47. # install(FILES
  48. # ${CMAKE_CURRENT_BINARY_DIR}/climbingstats_compiler_detection.h
  49. # DESTINATION include
  50. # )
  51. # install(FILES
  52. # ${support_files}
  53. # DESTINATION include/compilers
  54. # )
  55. #
  56. #
  57. # ``VERSION`` may be used to specify the API version to be generated.
  58. # Future versions of CMake may introduce alternative APIs. A given
  59. # API is selected by any ``<version>`` value greater than or equal
  60. # to the version of CMake that introduced the given API and less
  61. # than the version of CMake that introduced its succeeding API.
  62. # The value of the :variable:`CMAKE_MINIMUM_REQUIRED_VERSION`
  63. # variable is used if no explicit version is specified.
  64. # (As of CMake version |release| there is only one API version.)
  65. #
  66. # ``PROLOG`` may be specified as text content to write at the start of the
  67. # header. ``EPILOG`` may be specified as text content to write at the end
  68. # of the header
  69. #
  70. # At least one ``<compiler>`` and one ``<feature>`` must be listed. Compilers
  71. # which are known to CMake, but not specified are detected and a preprocessor
  72. # ``#error`` is generated for them. A preprocessor macro matching
  73. # ``<PREFIX>_COMPILER_IS_<compiler>`` is generated for each compiler
  74. # known to CMake to contain the value ``0`` or ``1``.
  75. #
  76. # Possible compiler identifiers are documented with the
  77. # :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
  78. # Available features in this version of CMake are listed in the
  79. # :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and
  80. # :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties.
  81. # The ``{c,cxx}_std_*`` meta-features are ignored if requested.
  82. #
  83. # See the :manual:`cmake-compile-features(7)` manual for information on
  84. # compile features.
  85. #
  86. # ``BARE_FEATURES`` will define the compatibility macros with the name used in
  87. # newer versions of the language standard, so the code can use the new feature
  88. # name unconditionally.
  89. #
  90. # ``ALLOW_UNKNOWN_COMPILERS`` and ``ALLOW_UNKNOWN_COMPILER_VERSIONS`` cause
  91. # the module to generate conditions that treat unknown compilers as simply
  92. # lacking all features. Without these options the default behavior is to
  93. # generate a ``#error`` for unknown compilers and versions.
  94. #
  95. # Feature Test Macros
  96. # ===================
  97. #
  98. # For each compiler, a preprocessor macro is generated matching
  99. # ``<PREFIX>_COMPILER_IS_<compiler>`` which has the content either ``0``
  100. # or ``1``, depending on the compiler in use. Preprocessor macros for
  101. # compiler version components are generated matching
  102. # ``<PREFIX>_COMPILER_VERSION_MAJOR`` ``<PREFIX>_COMPILER_VERSION_MINOR``
  103. # and ``<PREFIX>_COMPILER_VERSION_PATCH`` containing decimal values
  104. # for the corresponding compiler version components, if defined.
  105. #
  106. # A preprocessor test is generated based on the compiler version
  107. # denoting whether each feature is enabled. A preprocessor macro
  108. # matching ``<PREFIX>_COMPILER_<FEATURE>``, where ``<FEATURE>`` is the
  109. # upper-case ``<feature>`` name, is generated to contain the value
  110. # ``0`` or ``1`` depending on whether the compiler in use supports the
  111. # feature:
  112. #
  113. # .. code-block:: cmake
  114. #
  115. # write_compiler_detection_header(
  116. # FILE climbingstats_compiler_detection.h
  117. # PREFIX ClimbingStats
  118. # COMPILERS GNU Clang AppleClang MSVC Intel
  119. # FEATURES cxx_variadic_templates
  120. # )
  121. #
  122. # .. code-block:: c++
  123. #
  124. # #if ClimbingStats_COMPILER_CXX_VARIADIC_TEMPLATES
  125. # template<typename... T>
  126. # void someInterface(T t...) { /* ... */ }
  127. # #else
  128. # // Compatibility versions
  129. # template<typename T1>
  130. # void someInterface(T1 t1) { /* ... */ }
  131. # template<typename T1, typename T2>
  132. # void someInterface(T1 t1, T2 t2) { /* ... */ }
  133. # template<typename T1, typename T2, typename T3>
  134. # void someInterface(T1 t1, T2 t2, T3 t3) { /* ... */ }
  135. # #endif
  136. #
  137. # Symbol Macros
  138. # =============
  139. #
  140. # Some additional symbol-defines are created for particular features for
  141. # use as symbols which may be conditionally defined empty:
  142. #
  143. # .. code-block:: c++
  144. #
  145. # class MyClass ClimbingStats_FINAL
  146. # {
  147. # ClimbingStats_CONSTEXPR int someInterface() { return 42; }
  148. # };
  149. #
  150. # The ``ClimbingStats_FINAL`` macro will expand to ``final`` if the
  151. # compiler (and its flags) support the ``cxx_final`` feature, and the
  152. # ``ClimbingStats_CONSTEXPR`` macro will expand to ``constexpr``
  153. # if ``cxx_constexpr`` is supported.
  154. #
  155. # If ``BARE_FEATURES cxx_final`` was given as argument the ``final`` keyword
  156. # will be defined for old compilers, too.
  157. #
  158. # The following features generate corresponding symbol defines and if they
  159. # are available as ``BARE_FEATURES``:
  160. #
  161. # ========================== =================================== ================= ======
  162. # Feature Define Symbol bare
  163. # ========================== =================================== ================= ======
  164. # ``c_restrict`` ``<PREFIX>_RESTRICT`` ``restrict`` yes
  165. # ``cxx_constexpr`` ``<PREFIX>_CONSTEXPR`` ``constexpr`` yes
  166. # ``cxx_deleted_functions`` ``<PREFIX>_DELETED_FUNCTION`` ``= delete``
  167. # ``cxx_extern_templates`` ``<PREFIX>_EXTERN_TEMPLATE`` ``extern``
  168. # ``cxx_final`` ``<PREFIX>_FINAL`` ``final`` yes
  169. # ``cxx_noexcept`` ``<PREFIX>_NOEXCEPT`` ``noexcept`` yes
  170. # ``cxx_noexcept`` ``<PREFIX>_NOEXCEPT_EXPR(X)`` ``noexcept(X)``
  171. # ``cxx_override`` ``<PREFIX>_OVERRIDE`` ``override`` yes
  172. # ========================== =================================== ================= ======
  173. #
  174. # Compatibility Implementation Macros
  175. # ===================================
  176. #
  177. # Some features are suitable for wrapping in a macro with a backward
  178. # compatibility implementation if the compiler does not support the feature.
  179. #
  180. # When the ``cxx_static_assert`` feature is not provided by the compiler,
  181. # a compatibility implementation is available via the
  182. # ``<PREFIX>_STATIC_ASSERT(COND)`` and
  183. # ``<PREFIX>_STATIC_ASSERT_MSG(COND, MSG)`` function-like macros. The macros
  184. # expand to ``static_assert`` where that compiler feature is available, and
  185. # to a compatibility implementation otherwise. In the first form, the
  186. # condition is stringified in the message field of ``static_assert``. In
  187. # the second form, the message ``MSG`` is passed to the message field of
  188. # ``static_assert``, or ignored if using the backward compatibility
  189. # implementation.
  190. #
  191. # The ``cxx_attribute_deprecated`` feature provides a macro definition
  192. # ``<PREFIX>_DEPRECATED``, which expands to either the standard
  193. # ``[[deprecated]]`` attribute or a compiler-specific decorator such
  194. # as ``__attribute__((__deprecated__))`` used by GNU compilers.
  195. #
  196. # The ``cxx_alignas`` feature provides a macro definition
  197. # ``<PREFIX>_ALIGNAS`` which expands to either the standard ``alignas``
  198. # decorator or a compiler-specific decorator such as
  199. # ``__attribute__ ((__aligned__))`` used by GNU compilers.
  200. #
  201. # The ``cxx_alignof`` feature provides a macro definition
  202. # ``<PREFIX>_ALIGNOF`` which expands to either the standard ``alignof``
  203. # decorator or a compiler-specific decorator such as ``__alignof__``
  204. # used by GNU compilers.
  205. #
  206. # ============================= ================================ ===================== ======
  207. # Feature Define Symbol bare
  208. # ============================= ================================ ===================== ======
  209. # ``cxx_alignas`` ``<PREFIX>_ALIGNAS`` ``alignas``
  210. # ``cxx_alignof`` ``<PREFIX>_ALIGNOF`` ``alignof``
  211. # ``cxx_nullptr`` ``<PREFIX>_NULLPTR`` ``nullptr`` yes
  212. # ``cxx_static_assert`` ``<PREFIX>_STATIC_ASSERT`` ``static_assert``
  213. # ``cxx_static_assert`` ``<PREFIX>_STATIC_ASSERT_MSG`` ``static_assert``
  214. # ``cxx_attribute_deprecated`` ``<PREFIX>_DEPRECATED`` ``[[deprecated]]``
  215. # ``cxx_attribute_deprecated`` ``<PREFIX>_DEPRECATED_MSG`` ``[[deprecated]]``
  216. # ``cxx_thread_local`` ``<PREFIX>_THREAD_LOCAL`` ``thread_local``
  217. # ============================= ================================ ===================== ======
  218. #
  219. # A use-case which arises with such deprecation macros is the deprecation
  220. # of an entire library. In that case, all public API in the library may
  221. # be decorated with the ``<PREFIX>_DEPRECATED`` macro. This results in
  222. # very noisy build output when building the library itself, so the macro
  223. # may be may be defined to empty in that case when building the deprecated
  224. # library:
  225. #
  226. # .. code-block:: cmake
  227. #
  228. # add_library(compat_support ${srcs})
  229. # target_compile_definitions(compat_support
  230. # PRIVATE
  231. # CompatSupport_DEPRECATED=
  232. # )
  233. include(${CMAKE_CURRENT_LIST_DIR}/CMakeCompilerIdDetection.cmake)
  234. function(_load_compiler_variables CompilerId lang)
  235. include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-FeatureTests.cmake" OPTIONAL)
  236. set(_cmake_oldestSupported_${CompilerId} ${_cmake_oldestSupported} PARENT_SCOPE)
  237. foreach(feature ${ARGN})
  238. set(_cmake_feature_test_${CompilerId}_${feature} ${_cmake_feature_test_${feature}} PARENT_SCOPE)
  239. endforeach()
  240. include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-${lang}-DetermineCompiler.cmake" OPTIONAL
  241. RESULT_VARIABLE determinedCompiler)
  242. if (NOT determinedCompiler)
  243. include("${CMAKE_ROOT}/Modules/Compiler/${CompilerId}-DetermineCompiler.cmake" OPTIONAL)
  244. endif()
  245. set(_compiler_id_version_compute_${CompilerId} ${_compiler_id_version_compute} PARENT_SCOPE)
  246. endfunction()
  247. macro(_simpledefine FEATURE_NAME FEATURE_TESTNAME FEATURE_STRING FEATURE_DEFAULT_STRING)
  248. if (feature STREQUAL "${FEATURE_NAME}")
  249. set(def_value "${prefix_arg}_${FEATURE_TESTNAME}")
  250. string(APPEND file_content "
  251. # if defined(${def_name}) && ${def_name}
  252. # define ${def_value} ${FEATURE_STRING}
  253. # else
  254. # define ${def_value} ${FEATURE_DEFAULT_STRING}
  255. # endif
  256. \n")
  257. endif()
  258. endmacro()
  259. macro(_simplebaredefine FEATURE_NAME FEATURE_STRING FEATURE_DEFAULT_STRING)
  260. if (feature STREQUAL "${FEATURE_NAME}")
  261. string(APPEND file_content "
  262. # if !(defined(${def_name}) && ${def_name})
  263. # define ${FEATURE_STRING} ${FEATURE_DEFAULT_STRING}
  264. # endif
  265. \n")
  266. endif()
  267. endmacro()
  268. function(_check_feature_lists C_FEATURE_VAR CXX_FEATURE_VAR)
  269. foreach(feature ${ARGN})
  270. if (feature MATCHES "^c_std_")
  271. # ignored
  272. elseif (feature MATCHES "^cxx_std_")
  273. # ignored
  274. elseif (feature MATCHES "^cxx_")
  275. list(APPEND _langs CXX)
  276. list(APPEND ${CXX_FEATURE_VAR} ${feature})
  277. elseif (feature MATCHES "^c_")
  278. list(APPEND _langs C)
  279. list(APPEND ${C_FEATURE_VAR} ${feature})
  280. else()
  281. message(FATAL_ERROR "Unsupported feature ${feature}.")
  282. endif()
  283. endforeach()
  284. set(${C_FEATURE_VAR} ${${C_FEATURE_VAR}} PARENT_SCOPE)
  285. set(${CXX_FEATURE_VAR} ${${CXX_FEATURE_VAR}} PARENT_SCOPE)
  286. set(_langs ${_langs} PARENT_SCOPE)
  287. endfunction()
  288. function(write_compiler_detection_header
  289. file_keyword file_arg
  290. prefix_keyword prefix_arg
  291. )
  292. if (NOT "x${file_keyword}" STREQUAL "xFILE")
  293. message(FATAL_ERROR "write_compiler_detection_header: FILE parameter missing.")
  294. endif()
  295. if (NOT "x${prefix_keyword}" STREQUAL "xPREFIX")
  296. message(FATAL_ERROR "write_compiler_detection_header: PREFIX parameter missing.")
  297. endif()
  298. set(options ALLOW_UNKNOWN_COMPILERS ALLOW_UNKNOWN_COMPILER_VERSIONS)
  299. set(oneValueArgs VERSION EPILOG PROLOG OUTPUT_FILES_VAR OUTPUT_DIR)
  300. set(multiValueArgs COMPILERS FEATURES BARE_FEATURES)
  301. cmake_parse_arguments(_WCD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  302. if (NOT _WCD_COMPILERS)
  303. message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one compiler.")
  304. endif()
  305. if (NOT _WCD_FEATURES AND NOT _WCD_BARE_FEATURES)
  306. message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one feature.")
  307. endif()
  308. if(_WCD_UNPARSED_ARGUMENTS)
  309. message(FATAL_ERROR "Unparsed arguments: ${_WCD_UNPARSED_ARGUMENTS}")
  310. endif()
  311. if (prefix_arg STREQUAL "")
  312. message(FATAL_ERROR "A prefix must be specified")
  313. endif()
  314. string(MAKE_C_IDENTIFIER ${prefix_arg} cleaned_prefix)
  315. if (NOT prefix_arg STREQUAL cleaned_prefix)
  316. message(FATAL_ERROR "The prefix must be a valid C identifier.")
  317. endif()
  318. if(NOT _WCD_VERSION)
  319. set(_WCD_VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
  320. endif()
  321. set(_min_version 3.1.0) # Version which introduced this function
  322. if (_WCD_VERSION VERSION_LESS _min_version)
  323. set(err "VERSION compatibility for write_compiler_detection_header is set to ${_WCD_VERSION}, which is too low.")
  324. string(APPEND err " It must be set to at least ${_min_version}. ")
  325. string(APPEND err " Either set the VERSION parameter to the write_compiler_detection_header function, or update")
  326. string(APPEND err " your minimum required CMake version with the cmake_minimum_required command.")
  327. message(FATAL_ERROR "${err}")
  328. endif()
  329. if(_WCD_OUTPUT_FILES_VAR)
  330. if(NOT _WCD_OUTPUT_DIR)
  331. message(FATAL_ERROR "If OUTPUT_FILES_VAR is specified, then OUTPUT_DIR must also be specified.")
  332. endif()
  333. endif()
  334. if(_WCD_OUTPUT_DIR)
  335. if(NOT _WCD_OUTPUT_FILES_VAR)
  336. message(FATAL_ERROR "If OUTPUT_DIR is specified, then OUTPUT_FILES_VAR must also be specified.")
  337. endif()
  338. get_filename_component(main_file_dir ${file_arg} DIRECTORY)
  339. if (NOT IS_ABSOLUTE ${main_file_dir})
  340. set(main_file_dir "${CMAKE_CURRENT_BINARY_DIR}/${main_file_dir}")
  341. endif()
  342. if (NOT IS_ABSOLUTE ${_WCD_OUTPUT_DIR})
  343. set(_WCD_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_WCD_OUTPUT_DIR}")
  344. endif()
  345. get_filename_component(out_file_dir ${_WCD_OUTPUT_DIR} ABSOLUTE)
  346. string(FIND ${out_file_dir} ${main_file_dir} idx)
  347. if (NOT idx EQUAL 0)
  348. message(FATAL_ERROR "The compiler-specific output directory must be within the same directory as the main file.")
  349. endif()
  350. if (main_file_dir STREQUAL out_file_dir)
  351. unset(_WCD_OUTPUT_DIR)
  352. else()
  353. string(REPLACE "${main_file_dir}/" "" _WCD_OUTPUT_DIR "${out_file_dir}/")
  354. endif()
  355. endif()
  356. set(compilers
  357. GNU
  358. Clang
  359. AppleClang
  360. MSVC
  361. SunPro
  362. Intel
  363. )
  364. set(_hex_compilers ADSP Borland Embarcadero SunPro)
  365. foreach(_comp ${_WCD_COMPILERS})
  366. list(FIND compilers ${_comp} idx)
  367. if (idx EQUAL -1)
  368. message(FATAL_ERROR "Unsupported compiler ${_comp}.")
  369. endif()
  370. if (NOT _need_hex_conversion)
  371. list(FIND _hex_compilers ${_comp} idx)
  372. if (NOT idx EQUAL -1)
  373. set(_need_hex_conversion TRUE)
  374. endif()
  375. endif()
  376. endforeach()
  377. set(file_content "
  378. // This is a generated file. Do not edit!
  379. #ifndef ${prefix_arg}_COMPILER_DETECTION_H
  380. #define ${prefix_arg}_COMPILER_DETECTION_H
  381. ")
  382. if (_WCD_PROLOG)
  383. string(APPEND file_content "\n${_WCD_PROLOG}\n")
  384. endif()
  385. if (_need_hex_conversion)
  386. string(APPEND file_content "
  387. #define ${prefix_arg}_DEC(X) (X)
  388. #define ${prefix_arg}_HEX(X) ( \\
  389. ((X)>>28 & 0xF) * 10000000 + \\
  390. ((X)>>24 & 0xF) * 1000000 + \\
  391. ((X)>>20 & 0xF) * 100000 + \\
  392. ((X)>>16 & 0xF) * 10000 + \\
  393. ((X)>>12 & 0xF) * 1000 + \\
  394. ((X)>>8 & 0xF) * 100 + \\
  395. ((X)>>4 & 0xF) * 10 + \\
  396. ((X) & 0xF) \\
  397. )\n")
  398. endif()
  399. _check_feature_lists(C_features CXX_features ${_WCD_FEATURES})
  400. _check_feature_lists(C_bare_features CXX_bare_features ${_WCD_BARE_FEATURES})
  401. list(REMOVE_DUPLICATES _langs)
  402. if(_WCD_OUTPUT_FILES_VAR)
  403. get_filename_component(main_file_name ${file_arg} NAME)
  404. set(compiler_file_content_
  405. "#ifndef ${prefix_arg}_COMPILER_DETECTION_H
  406. # error This file may only be included from ${main_file_name}
  407. #endif\n")
  408. endif()
  409. foreach(_lang ${_langs})
  410. set(target_compilers)
  411. foreach(compiler ${_WCD_COMPILERS})
  412. _load_compiler_variables(${compiler} ${_lang} ${${_lang}_features})
  413. if(_cmake_oldestSupported_${compiler})
  414. list(APPEND target_compilers ${compiler})
  415. endif()
  416. endforeach()
  417. get_property(known_features GLOBAL PROPERTY CMAKE_${_lang}_KNOWN_FEATURES)
  418. foreach(feature ${${_lang}_features})
  419. list(FIND known_features ${feature} idx)
  420. if (idx EQUAL -1)
  421. message(FATAL_ERROR "Unsupported feature ${feature}.")
  422. endif()
  423. endforeach()
  424. if(_lang STREQUAL CXX)
  425. string(APPEND file_content "\n#ifdef __cplusplus\n")
  426. else()
  427. string(APPEND file_content "\n#ifndef __cplusplus\n")
  428. endif()
  429. compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_
  430. ID_DEFINE
  431. )
  432. string(APPEND file_content "${ID_CONTENT}\n")
  433. set(pp_if "if")
  434. foreach(compiler ${target_compilers})
  435. string(APPEND file_content "\n# ${pp_if} ${prefix_arg}_COMPILER_IS_${compiler}\n")
  436. if(_WCD_OUTPUT_FILES_VAR)
  437. set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h")
  438. string(APPEND file_content "\n# include \"${compile_file_name}\"\n")
  439. endif()
  440. if(_WCD_OUTPUT_FILES_VAR)
  441. set(compiler_file_content compiler_file_content_${compiler}_${_lang})
  442. else()
  443. set(compiler_file_content file_content)
  444. endif()
  445. if(NOT _WCD_ALLOW_UNKNOWN_COMPILER_VERSIONS)
  446. string(APPEND ${compiler_file_content} "
  447. # if !(${_cmake_oldestSupported_${compiler}})
  448. # error Unsupported compiler version
  449. # endif\n")
  450. endif()
  451. set(PREFIX ${prefix_arg}_)
  452. if (_need_hex_conversion)
  453. set(MACRO_DEC ${prefix_arg}_DEC)
  454. set(MACRO_HEX ${prefix_arg}_HEX)
  455. else()
  456. set(MACRO_DEC)
  457. set(MACRO_HEX)
  458. endif()
  459. string(CONFIGURE "${_compiler_id_version_compute_${compiler}}" VERSION_BLOCK @ONLY)
  460. string(APPEND ${compiler_file_content} "${VERSION_BLOCK}\n")
  461. set(PREFIX)
  462. set(MACRO_DEC)
  463. set(MACRO_HEX)
  464. set(pp_if "elif")
  465. foreach(feature ${${_lang}_features})
  466. string(TOUPPER ${feature} feature_upper)
  467. set(feature_PP "COMPILER_${feature_upper}")
  468. set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
  469. if (_cmake_feature_test_${compiler}_${feature} STREQUAL "1")
  470. set(_define_item "\n# define ${prefix_arg}_${feature_PP} 1\n")
  471. elseif (_cmake_feature_test_${compiler}_${feature})
  472. set(_define_item "\n# define ${prefix_arg}_${feature_PP} 0\n")
  473. set(_define_item "\n# if ${_cmake_feature_test_${compiler}_${feature}}\n# define ${prefix_arg}_${feature_PP} 1\n# else${_define_item}# endif\n")
  474. endif()
  475. string(APPEND ${compiler_file_content} "${_define_item}")
  476. endforeach()
  477. endforeach()
  478. if(pp_if STREQUAL "elif")
  479. if(_WCD_ALLOW_UNKNOWN_COMPILERS)
  480. string(APPEND file_content "
  481. # endif\n")
  482. else()
  483. string(APPEND file_content "
  484. # else
  485. # error Unsupported compiler
  486. # endif\n")
  487. endif()
  488. endif()
  489. foreach(feature ${${_lang}_features})
  490. string(TOUPPER ${feature} feature_upper)
  491. set(feature_PP "COMPILER_${feature_upper}")
  492. set(def_name ${prefix_arg}_${feature_PP})
  493. _simpledefine(c_restrict RESTRICT restrict "")
  494. _simpledefine(cxx_constexpr CONSTEXPR constexpr "")
  495. _simpledefine(cxx_final FINAL final "")
  496. _simpledefine(cxx_override OVERRIDE override "")
  497. if (feature STREQUAL cxx_static_assert)
  498. set(def_value "${prefix_arg}_STATIC_ASSERT(X)")
  499. set(def_value_msg "${prefix_arg}_STATIC_ASSERT_MSG(X, MSG)")
  500. set(def_fallback "enum { ${prefix_arg}_STATIC_ASSERT_JOIN(${prefix_arg}StaticAssertEnum, __LINE__) = sizeof(${prefix_arg}StaticAssert<X>) }")
  501. string(APPEND file_content "# if defined(${def_name}) && ${def_name}
  502. # define ${def_value} static_assert(X, #X)
  503. # define ${def_value_msg} static_assert(X, MSG)
  504. # else
  505. # define ${prefix_arg}_STATIC_ASSERT_JOIN(X, Y) ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y)
  506. # define ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y) X##Y
  507. template<bool> struct ${prefix_arg}StaticAssert;
  508. template<> struct ${prefix_arg}StaticAssert<true>{};
  509. # define ${def_value} ${def_fallback}
  510. # define ${def_value_msg} ${def_fallback}
  511. # endif
  512. \n")
  513. endif()
  514. if (feature STREQUAL cxx_alignas)
  515. set(def_value "${prefix_arg}_ALIGNAS(X)")
  516. string(APPEND file_content "
  517. # if defined(${def_name}) && ${def_name}
  518. # define ${def_value} alignas(X)
  519. # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
  520. # define ${def_value} __attribute__ ((__aligned__(X)))
  521. # elif ${prefix_arg}_COMPILER_IS_MSVC
  522. # define ${def_value} __declspec(align(X))
  523. # else
  524. # define ${def_value}
  525. # endif
  526. \n")
  527. endif()
  528. if (feature STREQUAL cxx_alignof)
  529. set(def_value "${prefix_arg}_ALIGNOF(X)")
  530. string(APPEND file_content "
  531. # if defined(${def_name}) && ${def_name}
  532. # define ${def_value} alignof(X)
  533. # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
  534. # define ${def_value} __alignof__(X)
  535. # elif ${prefix_arg}_COMPILER_IS_MSVC
  536. # define ${def_value} __alignof(X)
  537. # endif
  538. \n")
  539. endif()
  540. _simpledefine(cxx_deleted_functions DELETED_FUNCTION "= delete" "")
  541. _simpledefine(cxx_extern_templates EXTERN_TEMPLATE extern "")
  542. if (feature STREQUAL cxx_noexcept)
  543. set(def_value "${prefix_arg}_NOEXCEPT")
  544. string(APPEND file_content "
  545. # if defined(${def_name}) && ${def_name}
  546. # define ${def_value} noexcept
  547. # define ${def_value}_EXPR(X) noexcept(X)
  548. # else
  549. # define ${def_value}
  550. # define ${def_value}_EXPR(X)
  551. # endif
  552. \n")
  553. endif()
  554. if (feature STREQUAL cxx_nullptr)
  555. set(def_value "${prefix_arg}_NULLPTR")
  556. string(APPEND file_content "
  557. # if defined(${def_name}) && ${def_name}
  558. # define ${def_value} nullptr
  559. # elif ${prefix_arg}_COMPILER_IS_GNU
  560. # define ${def_value} __null
  561. # else
  562. # define ${def_value} 0
  563. # endif
  564. \n")
  565. endif()
  566. if (feature STREQUAL cxx_thread_local)
  567. set(def_value "${prefix_arg}_THREAD_LOCAL")
  568. string(APPEND file_content "
  569. # if defined(${def_name}) && ${def_name}
  570. # define ${def_value} thread_local
  571. # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang || ${prefix_arg}_COMPILER_IS_AppleClang
  572. # define ${def_value} __thread
  573. # elif ${prefix_arg}_COMPILER_IS_MSVC
  574. # define ${def_value} __declspec(thread)
  575. # else
  576. // ${def_value} not defined for this configuration.
  577. # endif
  578. \n")
  579. endif()
  580. if (feature STREQUAL cxx_attribute_deprecated)
  581. set(def_name ${prefix_arg}_${feature_PP})
  582. set(def_value "${prefix_arg}_DEPRECATED")
  583. string(APPEND file_content "
  584. # ifndef ${def_value}
  585. # if defined(${def_name}) && ${def_name}
  586. # define ${def_value} [[deprecated]]
  587. # define ${def_value}_MSG(MSG) [[deprecated(MSG)]]
  588. # elif ${prefix_arg}_COMPILER_IS_GNU || ${prefix_arg}_COMPILER_IS_Clang
  589. # define ${def_value} __attribute__((__deprecated__))
  590. # define ${def_value}_MSG(MSG) __attribute__((__deprecated__(MSG)))
  591. # elif ${prefix_arg}_COMPILER_IS_MSVC
  592. # define ${def_value} __declspec(deprecated)
  593. # define ${def_value}_MSG(MSG) __declspec(deprecated(MSG))
  594. # else
  595. # define ${def_value}
  596. # define ${def_value}_MSG(MSG)
  597. # endif
  598. # endif
  599. \n")
  600. endif()
  601. endforeach()
  602. foreach(feature ${${_lang}_bare_features})
  603. string(TOUPPER ${feature} feature_upper)
  604. set(feature_PP "COMPILER_${feature_upper}")
  605. set(def_name ${prefix_arg}_${feature_PP})
  606. _simplebaredefine(c_restrict restrict "")
  607. _simplebaredefine(cxx_constexpr constexpr "")
  608. _simplebaredefine(cxx_final final "")
  609. _simplebaredefine(cxx_override override "")
  610. if (feature STREQUAL cxx_nullptr)
  611. set(def_value "nullptr")
  612. string(APPEND file_content "
  613. # if !(defined(${def_name}) && ${def_name})
  614. # if ${prefix_arg}_COMPILER_IS_GNU
  615. # define ${def_value} __null
  616. # else
  617. # define ${def_value} 0
  618. # endif
  619. # endif
  620. \n")
  621. endif()
  622. _simplebaredefine(cxx_noexcept noexcept "")
  623. endforeach()
  624. string(APPEND file_content "#endif\n")
  625. endforeach()
  626. if(_WCD_OUTPUT_FILES_VAR)
  627. foreach(compiler ${_WCD_COMPILERS})
  628. foreach(_lang ${_langs})
  629. if(compiler_file_content_${compiler}_${_lang})
  630. set(CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_}")
  631. string(APPEND CMAKE_CONFIGURABLE_FILE_CONTENT "${compiler_file_content_${compiler}_${_lang}}")
  632. set(compile_file_name "${_WCD_OUTPUT_DIR}${prefix_arg}_COMPILER_INFO_${compiler}_${_lang}.h")
  633. set(full_path "${main_file_dir}/${compile_file_name}")
  634. list(APPEND ${_WCD_OUTPUT_FILES_VAR} ${full_path})
  635. configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
  636. "${full_path}"
  637. @ONLY
  638. )
  639. endif()
  640. endforeach()
  641. endforeach()
  642. set(${_WCD_OUTPUT_FILES_VAR} ${${_WCD_OUTPUT_FILES_VAR}} PARENT_SCOPE)
  643. endif()
  644. if (_WCD_EPILOG)
  645. string(APPEND file_content "\n${_WCD_EPILOG}\n")
  646. endif()
  647. string(APPEND file_content "\n#endif")
  648. set(CMAKE_CONFIGURABLE_FILE_CONTENT ${file_content})
  649. configure_file("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
  650. "${file_arg}"
  651. @ONLY
  652. )
  653. endfunction()