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