From f38d05023125803d42a6535dfc11c6de4041e28d Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 19 Mar 2018 21:42:25 +0100 Subject: WCDH: introduce BARE_FEATURES This allows defining compat versions of some C/C++ features with the name of the keyword itself, so all code can look as if it was written for the new language standard. --- Help/release/dev/wcdh-raw-features.rst | 6 ++ Modules/WriteCompilerDetectionHeader.cmake | 116 +++++++++++++++------ .../WriteCompilerDetectionHeader/CMakeLists.txt | 15 ++- .../WriteCompilerDetectionHeader/main_bare.cpp | 23 ++++ .../InvalidFeature-stderr.txt | 1 + 5 files changed, 127 insertions(+), 34 deletions(-) create mode 100644 Help/release/dev/wcdh-raw-features.rst create mode 100644 Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp diff --git a/Help/release/dev/wcdh-raw-features.rst b/Help/release/dev/wcdh-raw-features.rst new file mode 100644 index 0000000..bdc7b62 --- /dev/null +++ b/Help/release/dev/wcdh-raw-features.rst @@ -0,0 +1,6 @@ +wcdh-raw-features +----------------- + +* The :module:`WriteCompilerDetectionHeader` module now supports the + ``BARE_FEATURES`` argument which allows to add a compatibility define for + the exact keyword of a new language feature. diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake index 675df84..3718e9d 100644 --- a/Modules/WriteCompilerDetectionHeader.cmake +++ b/Modules/WriteCompilerDetectionHeader.cmake @@ -17,6 +17,7 @@ # [OUTPUT_FILES_VAR OUTPUT_DIR ] # COMPILERS [...] # FEATURES [...] +# [BARE_FEATURES [...]] # [VERSION ] # [PROLOG ] # [EPILOG ] @@ -83,10 +84,14 @@ # See the :manual:`cmake-compile-features(7)` manual for information on # compile features. # +# ``BARE_FEATURES`` will define the compatibility macros with the name used in +# newer versions of the language standard, so the code can use the new feature +# name unconditionally. +# # ``ALLOW_UNKNOWN_COMPILERS`` and ``ALLOW_UNKNOWN_COMPILER_VERSIONS`` cause # the module to generate conditions that treat unknown compilers as simply # lacking all features. Without these options the default behavior is to -# generate a ``#error`` for unknown compilers. +# generate a ``#error`` for unknown compilers and versions. # # Feature Test Macros # =================== @@ -148,20 +153,24 @@ # ``ClimbingStats_CONSTEXPR`` macro will expand to ``constexpr`` # if ``cxx_constexpr`` is supported. # -# The following features generate corresponding symbol defines: +# If ``BARE_FEATURES cxx_final`` was given as argument the ``final`` keyword +# will be defined for old compilers, too. +# +# The following features generate corresponding symbol defines and if they +# are available as ``BARE_FEATURES``: # -# ========================== =================================== ================= -# Feature Define Symbol -# ========================== =================================== ================= -# ``c_restrict`` ``_RESTRICT`` ``restrict`` -# ``cxx_constexpr`` ``_CONSTEXPR`` ``constexpr`` +# ========================== =================================== ================= ====== +# Feature Define Symbol bare +# ========================== =================================== ================= ====== +# ``c_restrict`` ``_RESTRICT`` ``restrict`` yes +# ``cxx_constexpr`` ``_CONSTEXPR`` ``constexpr`` yes # ``cxx_deleted_functions`` ``_DELETED_FUNCTION`` ``= delete`` # ``cxx_extern_templates`` ``_EXTERN_TEMPLATE`` ``extern`` -# ``cxx_final`` ``_FINAL`` ``final`` -# ``cxx_noexcept`` ``_NOEXCEPT`` ``noexcept`` +# ``cxx_final`` ``_FINAL`` ``final`` yes +# ``cxx_noexcept`` ``_NOEXCEPT`` ``noexcept`` yes # ``cxx_noexcept`` ``_NOEXCEPT_EXPR(X)`` ``noexcept(X)`` -# ``cxx_override`` ``_OVERRIDE`` ``override`` -# ========================== =================================== ================= +# ``cxx_override`` ``_OVERRIDE`` ``override`` yes +# ========================== =================================== ================= ====== # # Compatibility Implementation Macros # =================================== @@ -195,18 +204,18 @@ # decorator or a compiler-specific decorator such as ``__alignof__`` # used by GNU compilers. # -# ============================= ================================ ===================== -# Feature Define Symbol -# ============================= ================================ ===================== +# ============================= ================================ ===================== ====== +# Feature Define Symbol bare +# ============================= ================================ ===================== ====== # ``cxx_alignas`` ``_ALIGNAS`` ``alignas`` # ``cxx_alignof`` ``_ALIGNOF`` ``alignof`` -# ``cxx_nullptr`` ``_NULLPTR`` ``nullptr`` +# ``cxx_nullptr`` ``_NULLPTR`` ``nullptr`` yes # ``cxx_static_assert`` ``_STATIC_ASSERT`` ``static_assert`` # ``cxx_static_assert`` ``_STATIC_ASSERT_MSG`` ``static_assert`` # ``cxx_attribute_deprecated`` ``_DEPRECATED`` ``[[deprecated]]`` # ``cxx_attribute_deprecated`` ``_DEPRECATED_MSG`` ``[[deprecated]]`` # ``cxx_thread_local`` ``_THREAD_LOCAL`` ``thread_local`` -# ============================= ================================ ===================== +# ============================= ================================ ===================== ====== # # A use-case which arises with such deprecation macros is the deprecation # of an entire library. In that case, all public API in the library may @@ -252,6 +261,37 @@ macro(_simpledefine FEATURE_NAME FEATURE_TESTNAME FEATURE_STRING FEATURE_DEFAULT endif() endmacro() +macro(_simplebaredefine FEATURE_NAME FEATURE_STRING FEATURE_DEFAULT_STRING) + if (feature STREQUAL "${FEATURE_NAME}") + string(APPEND file_content " +# if !(defined(${def_name}) && ${def_name}) +# define ${FEATURE_STRING} ${FEATURE_DEFAULT_STRING} +# endif +\n") + endif() +endmacro() + +function(_check_feature_lists C_FEATURE_VAR CXX_FEATURE_VAR) + foreach(feature ${ARGN}) + if (feature MATCHES "^c_std_") + # ignored + elseif (feature MATCHES "^cxx_std_") + # ignored + elseif (feature MATCHES "^cxx_") + list(APPEND _langs CXX) + list(APPEND ${CXX_FEATURE_VAR} ${feature}) + elseif (feature MATCHES "^c_") + list(APPEND _langs C) + list(APPEND ${C_FEATURE_VAR} ${feature}) + else() + message(FATAL_ERROR "Unsupported feature ${feature}.") + endif() + endforeach() + set(${C_FEATURE_VAR} ${${C_FEATURE_VAR}} PARENT_SCOPE) + set(${CXX_FEATURE_VAR} ${${CXX_FEATURE_VAR}} PARENT_SCOPE) + set(_langs ${_langs} PARENT_SCOPE) +endfunction() + function(write_compiler_detection_header file_keyword file_arg prefix_keyword prefix_arg @@ -264,13 +304,13 @@ function(write_compiler_detection_header endif() set(options ALLOW_UNKNOWN_COMPILERS ALLOW_UNKNOWN_COMPILER_VERSIONS) set(oneValueArgs VERSION EPILOG PROLOG OUTPUT_FILES_VAR OUTPUT_DIR) - set(multiValueArgs COMPILERS FEATURES) + set(multiValueArgs COMPILERS FEATURES BARE_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) + if (NOT _WCD_FEATURES AND NOT _WCD_BARE_FEATURES) message(FATAL_ERROR "Invalid arguments. write_compiler_detection_header requires at least one feature.") endif() @@ -377,21 +417,8 @@ function(write_compiler_detection_header )\n") endif() - foreach(feature ${_WCD_FEATURES}) - if (feature MATCHES "^c_std_") - # ignored - elseif (feature MATCHES "^cxx_std_") - # ignored - 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() + _check_feature_lists(C_features CXX_features ${_WCD_FEATURES}) + _check_feature_lists(C_bare_features CXX_bare_features ${_WCD_BARE_FEATURES}) list(REMOVE_DUPLICATES _langs) if(_WCD_OUTPUT_FILES_VAR) @@ -606,6 +633,29 @@ template<> struct ${prefix_arg}StaticAssert{}; endif() endforeach() + foreach(feature ${${_lang}_bare_features}) + string(TOUPPER ${feature} feature_upper) + set(feature_PP "COMPILER_${feature_upper}") + set(def_name ${prefix_arg}_${feature_PP}) + _simplebaredefine(c_restrict restrict "") + _simplebaredefine(cxx_constexpr constexpr "") + _simplebaredefine(cxx_final final "") + _simplebaredefine(cxx_override override "") + if (feature STREQUAL cxx_nullptr) + set(def_value "nullptr") + string(APPEND file_content " +# if !(defined(${def_name}) && ${def_name}) +# if ${prefix_arg}_COMPILER_IS_GNU +# define ${def_value} __null +# else +# define ${def_value} 0 +# endif +# endif +\n") + endif() + _simplebaredefine(cxx_noexcept noexcept "") + endforeach() + string(APPEND file_content "#endif\n") endforeach() diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt index 52d4613..45bb229 100644 --- a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt +++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt @@ -190,7 +190,7 @@ write_compiler_detection_header( ALLOW_UNKNOWN_COMPILERS ) -# intentionally abuse the TEST_NULLPR variable: this will only work +# intentionally abuse the TEST_NULLPTR variable: this will only work # with the fallback code. check_cxx_source_compiles("#include \"${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_allow_unknown.h\" int main() {\n int i = TEST_NULLPTR;\n return 0; }\n" @@ -199,3 +199,16 @@ int main() {\n int i = TEST_NULLPTR;\n return 0; }\n" if (NOT file_include_works_allow_unknown) message(SEND_ERROR "Inclusion of ${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_allow_unknown.h was expected to work, but did not.") endif() + +# test for BARE_FEATURES + +write_compiler_detection_header( + FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection_bare_features.h" + PREFIX TEST + COMPILERS GNU Clang AppleClang MSVC SunPro Intel + VERSION 3.1 + BARE_FEATURES cxx_nullptr cxx_override cxx_noexcept cxx_final +) + +add_executable(WriteCompilerDetectionHeaderBareFeatures main_bare.cpp) +set_property(TARGET WriteCompilerDetectionHeaderBareFeatures PROPERTY CXX_STANDARD 11) diff --git a/Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp b/Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp new file mode 100644 index 0000000..6954318 --- /dev/null +++ b/Tests/Module/WriteCompilerDetectionHeader/main_bare.cpp @@ -0,0 +1,23 @@ +#include "test_compiler_detection_bare_features.h" + +class base +{ +public: + virtual ~base() {} + virtual void baz() = 0; +}; + +class foo final +{ +public: + virtual ~foo() {} + char* bar; + void baz() noexcept override { bar = nullptr; } +}; + +int main() +{ + foo f; + + return 0; +} diff --git a/Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature-stderr.txt b/Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature-stderr.txt index 0445744..f444992 100644 --- a/Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature-stderr.txt +++ b/Tests/RunCMake/WriteCompilerDetectionHeader/InvalidFeature-stderr.txt @@ -1,5 +1,6 @@ CMake Error at .*Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(message\): Unsupported feature not_a_feature. Call Stack \(most recent call first\): + .*Modules/WriteCompilerDetectionHeader.cmake:[0-9]+ \(_check_feature_lists\) InvalidFeature.cmake:4 \(write_compiler_detection_header\) CMakeLists.txt:3 \(include\) -- cgit v0.12