From e0890d03a48d12904ffe24aa94fb2847d8d5f4e7 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Mon, 4 Nov 2013 01:15:43 +0100 Subject: [PATCH] Features: Extend concept to C language. Add properties and variables corresponding to CXX equivalents. Add features for c_function_prototypes (C90), c_restrict (C99), c_variadic_macros (C99) and c_static_assert (C11). This feature set can be extended later. Add a _RESTRICT symbol define to WriteCompilerDetectionHeader to conditionally represent the c_restrict feature. --- Help/command/target_compile_features.rst | 3 +- Help/manual/cmake-properties.7.rst | 4 + Help/manual/cmake-variables.7.rst | 4 + Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst | 25 ++++ Help/prop_tgt/C_EXTENSIONS.rst | 8 ++ Help/prop_tgt/C_STANDARD.rst | 27 ++++ Help/prop_tgt/C_STANDARD_REQUIRED.rst | 14 +++ .../release/dev/compile-language-features.rst | 6 + Help/variable/CMAKE_C_COMPILE_FEATURES.rst | 8 ++ Help/variable/CMAKE_C_EXTENSIONS.rst | 8 ++ Help/variable/CMAKE_C_STANDARD.rst | 8 ++ Help/variable/CMAKE_C_STANDARD_REQUIRED.rst | 8 ++ Modules/CMakeCCompiler.cmake.in | 5 + Modules/CMakeDetermineCompileFeatures.cmake | 40 +++++- Modules/CMakeTestCCompiler.cmake | 3 + Modules/Compiler/GNU-C-FeatureTests.cmake | 12 ++ Modules/Compiler/GNU-C.cmake | 32 +++++ Modules/WriteCompilerDetectionHeader.cmake | 24 +++- Source/cmLocalGenerator.cxx | 4 + Source/cmMakefile.cxx | 116 +++++++++++++++++- Source/cmMakefile.h | 6 + Source/cmTarget.cxx | 3 + Source/cmake.cxx | 8 +- Source/cmake.h | 6 + .../target_compile_features/CMakeLists.txt | 42 +++++-- .../target_compile_features/lib_restrict.c | 9 ++ .../target_compile_features/lib_restrict.h | 7 ++ .../target_compile_features/main.c | 12 ++ .../target_compile_features/restrict_user.c | 14 +++ Tests/CompileFeatures/CMakeLists.txt | 10 +- Tests/CompileFeatures/c_function_prototypes.c | 9 ++ Tests/CompileFeatures/c_restrict.c | 7 ++ Tests/CompileFeatures/c_static_assert.c | 2 + Tests/CompileFeatures/c_variadic_macros.c | 15 +++ Tests/CompileFeatures/main.c | 12 ++ .../Export/Interface/CMakeLists.txt | 5 +- .../Import/Interface/CMakeLists.txt | 21 ++++ .../CMakeLists.txt | 5 +- .../NoSupportedCFeatures-result.txt | 1 + .../NoSupportedCFeatures-stderr.txt | 8 ++ .../NoSupportedCFeatures.cmake | 5 + .../NoSupportedCFeaturesGenex-result.txt | 1 + .../NoSupportedCFeaturesGenex-stderr.txt | 6 + .../NoSupportedCFeaturesGenex.cmake | 5 + .../CompileFeatures/RunCMakeTest.cmake | 9 ++ Tests/RunCMake/CompileFeatures/empty.c | 7 ++ .../generate_feature_list.cmake | 6 + .../Configure/FailCopyFileABI-stdout.txt | 2 +- .../RunCMakeTest.cmake | 2 + .../RunCMake/target_compile_features/empty.c | 7 ++ .../no_matching_c_feature-result.txt | 1 + .../no_matching_c_feature-stderr.txt | 8 ++ .../no_matching_c_feature.cmake | 15 +++ .../not_a_c_feature-result.txt | 1 + .../not_a_c_feature-stderr.txt | 5 + .../not_a_c_feature.cmake | 6 + Tests/SystemInformation/SystemInformation.in | 10 ++ 57 files changed, 630 insertions(+), 27 deletions(-) create mode 100644 Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst create mode 100644 Help/prop_tgt/C_EXTENSIONS.rst create mode 100644 Help/prop_tgt/C_STANDARD.rst create mode 100644 Help/prop_tgt/C_STANDARD_REQUIRED.rst create mode 100644 Help/variable/CMAKE_C_COMPILE_FEATURES.rst create mode 100644 Help/variable/CMAKE_C_EXTENSIONS.rst create mode 100644 Help/variable/CMAKE_C_STANDARD.rst create mode 100644 Help/variable/CMAKE_C_STANDARD_REQUIRED.rst create mode 100644 Modules/Compiler/GNU-C-FeatureTests.cmake create mode 100644 Tests/CMakeCommands/target_compile_features/lib_restrict.c create mode 100644 Tests/CMakeCommands/target_compile_features/lib_restrict.h create mode 100644 Tests/CMakeCommands/target_compile_features/main.c create mode 100644 Tests/CMakeCommands/target_compile_features/restrict_user.c create mode 100644 Tests/CompileFeatures/c_function_prototypes.c create mode 100644 Tests/CompileFeatures/c_restrict.c create mode 100644 Tests/CompileFeatures/c_static_assert.c create mode 100644 Tests/CompileFeatures/c_variadic_macros.c create mode 100644 Tests/CompileFeatures/main.c create mode 100644 Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt create mode 100644 Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-stderr.txt create mode 100644 Tests/RunCMake/CompileFeatures/NoSupportedCFeatures.cmake create mode 100644 Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt create mode 100644 Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt create mode 100644 Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex.cmake create mode 100644 Tests/RunCMake/CompileFeatures/empty.c create mode 100644 Tests/RunCMake/target_compile_features/empty.c create mode 100644 Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt create mode 100644 Tests/RunCMake/target_compile_features/no_matching_c_feature-stderr.txt create mode 100644 Tests/RunCMake/target_compile_features/no_matching_c_feature.cmake create mode 100644 Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt create mode 100644 Tests/RunCMake/target_compile_features/not_a_c_feature-stderr.txt create mode 100644 Tests/RunCMake/target_compile_features/not_a_c_feature.cmake diff --git a/Help/command/target_compile_features.rst b/Help/command/target_compile_features.rst index f8e5c5448..95596003f 100644 --- a/Help/command/target_compile_features.rst +++ b/Help/command/target_compile_features.rst @@ -8,7 +8,8 @@ Add expected compiler features to a target. target_compile_features( [...]) Specify compiler features required when compiling a given target. If the -feature is not listed in the :variable:`CMAKE_CXX_COMPILE_FEATURES` variable, +feature is not listed in the :variable:`CMAKE_C_COMPILE_FEATURES` variable +or :variable:`CMAKE_CXX_COMPILE_FEATURES` variable, then an error will be reported by CMake. If the use of the feature requires an additional compiler flag, such as ``-std=c++11``, the flag will be added automatically. diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 14d2e7fa3..a204a9cbc 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -16,6 +16,7 @@ Properties of Global Scope /prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS /prop_gbl/AUTOGEN_TARGETS_FOLDER /prop_gbl/AUTOMOC_TARGETS_FOLDER + /prop_gbl/CMAKE_C_KNOWN_FEATURES /prop_gbl/CMAKE_CXX_KNOWN_FEATURES /prop_gbl/DEBUG_CONFIGURATIONS /prop_gbl/DISABLED_FEATURES @@ -93,6 +94,9 @@ Properties on Targets /prop_tgt/BUILD_WITH_INSTALL_RPATH /prop_tgt/BUNDLE_EXTENSION /prop_tgt/BUNDLE + /prop_tgt/C_EXTENSIONS + /prop_tgt/C_STANDARD + /prop_tgt/C_STANDARD_REQUIRED /prop_tgt/COMPATIBLE_INTERFACE_BOOL /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index a7d4af600..b2dc88fa9 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -260,6 +260,10 @@ Variables for Languages :maxdepth: 1 /variable/CMAKE_COMPILER_IS_GNULANG + /variable/CMAKE_C_COMPILE_FEATURES + /variable/CMAKE_C_EXTENSIONS + /variable/CMAKE_C_STANDARD + /variable/CMAKE_C_STANDARD_REQUIRED /variable/CMAKE_CXX_COMPILE_FEATURES /variable/CMAKE_CXX_EXTENSIONS /variable/CMAKE_CXX_STANDARD diff --git a/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst new file mode 100644 index 000000000..c57bc735f --- /dev/null +++ b/Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst @@ -0,0 +1,25 @@ +CMAKE_C_KNOWN_FEATURES +---------------------- + +List of C features known to this version of CMake. + +The features listed in this global property may be known to be available to the +C compiler. If the feature is available with the C compiler, it will +be listed in the :variable:`CMAKE_C_COMPILE_FEATURES` variable. + +The features listed here may be used with the :command:`target_compile_features` +command. + +The features known to this version of CMake are: + +``c_function_prototypes`` + Function prototypes, as defined in ``ISO/IEC 9899:1990``. + +``c_restrict`` + ``restrict`` keyword, as defined in ``ISO/IEC 9899:1999``. + +``c_static_assert`` + Static assert, as defined in ``ISO/IEC 9899:2011``. + +``c_variadic_macros`` + Variadic macros, as defined in ``ISO/IEC 9899:1999``. diff --git a/Help/prop_tgt/C_EXTENSIONS.rst b/Help/prop_tgt/C_EXTENSIONS.rst new file mode 100644 index 000000000..246e93d05 --- /dev/null +++ b/Help/prop_tgt/C_EXTENSIONS.rst @@ -0,0 +1,8 @@ +C_EXTENSIONS +------------ + +Boolean specifying whether compiler specific extensions are requested. + +This property specifies whether compiler specific extensions should be +used. For some compilers, this results in adding a flag such +as ``-std=gnu11`` instead of ``-std=c11`` to the compile line. diff --git a/Help/prop_tgt/C_STANDARD.rst b/Help/prop_tgt/C_STANDARD.rst new file mode 100644 index 000000000..9fdc0bb00 --- /dev/null +++ b/Help/prop_tgt/C_STANDARD.rst @@ -0,0 +1,27 @@ +C_STANDARD +---------- + +The C standard whose features are requested to build this target. + +This property specifies the C standard whose features are requested +to build this target. For some compilers, this results in adding a +flag such as ``-std=c11`` to the compile line. + +Supported values are ``90``, ``99`` and ``11``. + +If the value requested does not result in a compile flag being added for +the compiler in use, a previous standard flag will be added instead. This +means that using: + +.. code-block:: cmake + + set_property(TARGET tgt PROPERTY C_STANDARD 11) + +with a compiler which does not support ``-std=c11`` or an equivalent +flag will not result in an error or warning, but will instead add the +``-std=c99`` or ``-std=c90`` flag if supported. This "decay" behavior may +be controlled with the :prop_tgt:`C_STANDARD_REQUIRED` target property. + +This property is initialized by the value of +the :variable:`CMAKE_C_STANDARD` variable if it is set when a target +is created. diff --git a/Help/prop_tgt/C_STANDARD_REQUIRED.rst b/Help/prop_tgt/C_STANDARD_REQUIRED.rst new file mode 100644 index 000000000..6c39e96a9 --- /dev/null +++ b/Help/prop_tgt/C_STANDARD_REQUIRED.rst @@ -0,0 +1,14 @@ +C_STANDARD_REQUIRED +------------------- + +Boolean describing whether the value of :prop_tgt:`C_STANDARD` is a requirement. + +If this property is set to ``ON``, then the value of the +:prop_tgt:`C_STANDARD` target property is treated as a requirement. If this +property is ``OFF`` or unset, the :prop_tgt:`C_STANDARD` target property is +treated as optional and may "decay" to a previous standard if the requested is +not available. + +This property is initialized by the value of +the :variable:`CMAKE_C_STANDARD_REQUIRED` variable if it is set when a +target is created. diff --git a/Help/release/dev/compile-language-features.rst b/Help/release/dev/compile-language-features.rst index 3c5d7cadc..fe72e39c2 100644 --- a/Help/release/dev/compile-language-features.rst +++ b/Help/release/dev/compile-language-features.rst @@ -7,6 +7,12 @@ target-language-features :variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_EXTENSIONS` variables may be set to initialize the target properties. +* New :prop_tgt:`C_STANDARD` and :prop_tgt:`C_EXTENSIONS` target + properties may specify values which CMake uses to compute required + compile options such as ``-std=c11`` or ``-std=gnu11``. The + :variable:`CMAKE_C_STANDARD` and :variable:`CMAKE_C_EXTENSIONS` + variables may be set to initialize the target properties. + * New :prop_tgt:`COMPILE_FEATURES` target property may contain a list of features required to compile a target. CMake uses this information to ensure that the compiler in use is capable of building diff --git a/Help/variable/CMAKE_C_COMPILE_FEATURES.rst b/Help/variable/CMAKE_C_COMPILE_FEATURES.rst new file mode 100644 index 000000000..7d1c8b197 --- /dev/null +++ b/Help/variable/CMAKE_C_COMPILE_FEATURES.rst @@ -0,0 +1,8 @@ +CMAKE_C_COMPILE_FEATURES +------------------------ + +List of features known to the C compiler + +These features are known to be available for use with the C compiler. This +list is a subset of the features listed in the :prop_gbl:`CMAKE_C_KNOWN_FEATURES` +global property. diff --git a/Help/variable/CMAKE_C_EXTENSIONS.rst b/Help/variable/CMAKE_C_EXTENSIONS.rst new file mode 100644 index 000000000..ff2569bbc --- /dev/null +++ b/Help/variable/CMAKE_C_EXTENSIONS.rst @@ -0,0 +1,8 @@ +CMAKE_C_EXTENSIONS +------------------ + +Default value for ``C_EXTENSIONS`` property of targets. + +This variable is used to initialize the :prop_tgt:`C_EXTENSIONS` +property on all targets. See that target property for additional +information. diff --git a/Help/variable/CMAKE_C_STANDARD.rst b/Help/variable/CMAKE_C_STANDARD.rst new file mode 100644 index 000000000..c1f8c29da --- /dev/null +++ b/Help/variable/CMAKE_C_STANDARD.rst @@ -0,0 +1,8 @@ +CMAKE_C_STANDARD +---------------- + +Default value for ``C_STANDARD`` property of targets. + +This variable is used to initialize the :prop_tgt:`C_STANDARD` +property on all targets. See that target property for additional +information. diff --git a/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst b/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst new file mode 100644 index 000000000..13ea49ffc --- /dev/null +++ b/Help/variable/CMAKE_C_STANDARD_REQUIRED.rst @@ -0,0 +1,8 @@ +CMAKE_C_STANDARD_REQUIRED +------------------------- + +Default value for ``C_STANDARD_REQUIRED`` property of targets. + +This variable is used to initialize the :prop_tgt:`C_STANDARD_REQUIRED` +property on all targets. See that target property for additional +information. diff --git a/Modules/CMakeCCompiler.cmake.in b/Modules/CMakeCCompiler.cmake.in index 694f8b879..86cd89450 100644 --- a/Modules/CMakeCCompiler.cmake.in +++ b/Modules/CMakeCCompiler.cmake.in @@ -2,6 +2,11 @@ set(CMAKE_C_COMPILER "@CMAKE_C_COMPILER@") set(CMAKE_C_COMPILER_ARG1 "@CMAKE_C_COMPILER_ARG1@") set(CMAKE_C_COMPILER_ID "@CMAKE_C_COMPILER_ID@") set(CMAKE_C_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@") +set(CMAKE_C_COMPILE_FEATURES "@CMAKE_C_COMPILE_FEATURES@") +set(CMAKE_C90_COMPILE_FEATURES "@CMAKE_C90_COMPILE_FEATURES@") +set(CMAKE_C99_COMPILE_FEATURES "@CMAKE_C99_COMPILE_FEATURES@") +set(CMAKE_C11_COMPILE_FEATURES "@CMAKE_C11_COMPILE_FEATURES@") + set(CMAKE_C_PLATFORM_ID "@CMAKE_C_PLATFORM_ID@") set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@") set(CMAKE_C_SIMULATE_VERSION "@CMAKE_C_SIMULATE_VERSION@") diff --git a/Modules/CMakeDetermineCompileFeatures.cmake b/Modules/CMakeDetermineCompileFeatures.cmake index 583ff8dfa..376291284 100644 --- a/Modules/CMakeDetermineCompileFeatures.cmake +++ b/Modules/CMakeDetermineCompileFeatures.cmake @@ -14,7 +14,45 @@ function(cmake_determine_compile_features lang) - if(lang STREQUAL CXX AND COMMAND cmake_record_cxx_compile_features) + if(lang STREQUAL C AND COMMAND cmake_record_c_compile_features) + message(STATUS "Detecting ${lang} compile features") + + set(CMAKE_C90_COMPILE_FEATURES) + set(CMAKE_C99_COMPILE_FEATURES) + set(CMAKE_C11_COMPILE_FEATURES) + + include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake") + + cmake_record_c_compile_features() + + if(NOT _result EQUAL 0) + message(STATUS "Detecting ${lang} compile features - failed") + return() + endif() + + if (CMAKE_C99_COMPILE_FEATURES AND CMAKE_C11_COMPILE_FEATURES) + list(REMOVE_ITEM CMAKE_C11_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES}) + endif() + if (CMAKE_C90_COMPILE_FEATURES AND CMAKE_C99_COMPILE_FEATURES) + list(REMOVE_ITEM CMAKE_C99_COMPILE_FEATURES ${CMAKE_C90_COMPILE_FEATURES}) + endif() + + if(NOT CMAKE_C_COMPILE_FEATURES) + set(CMAKE_C_COMPILE_FEATURES + ${CMAKE_C90_COMPILE_FEATURES} + ${CMAKE_C99_COMPILE_FEATURES} + ${CMAKE_C11_COMPILE_FEATURES} + ) + endif() + + set(CMAKE_C_COMPILE_FEATURES ${CMAKE_C_COMPILE_FEATURES} PARENT_SCOPE) + set(CMAKE_C90_COMPILE_FEATURES ${CMAKE_C90_COMPILE_FEATURES} PARENT_SCOPE) + set(CMAKE_C99_COMPILE_FEATURES ${CMAKE_C99_COMPILE_FEATURES} PARENT_SCOPE) + set(CMAKE_C11_COMPILE_FEATURES ${CMAKE_C11_COMPILE_FEATURES} PARENT_SCOPE) + + message(STATUS "Detecting ${lang} compile features - done") + + elseif(lang STREQUAL CXX AND COMMAND cmake_record_cxx_compile_features) message(STATUS "Detecting ${lang} compile features") set(CMAKE_CXX98_COMPILE_FEATURES) diff --git a/Modules/CMakeTestCCompiler.cmake b/Modules/CMakeTestCCompiler.cmake index d13304264..29a58bdc9 100644 --- a/Modules/CMakeTestCCompiler.cmake +++ b/Modules/CMakeTestCCompiler.cmake @@ -73,6 +73,9 @@ else() # Try to identify the ABI and configure it into CMakeCCompiler.cmake include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) CMAKE_DETERMINE_COMPILER_ABI(C ${CMAKE_ROOT}/Modules/CMakeCCompilerABI.c) + # Try to identify the compiler features + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake) + CMAKE_DETERMINE_COMPILE_FEATURES(C) # Re-configure to save learned information. configure_file( diff --git a/Modules/Compiler/GNU-C-FeatureTests.cmake b/Modules/Compiler/GNU-C-FeatureTests.cmake new file mode 100644 index 000000000..dc1695c79 --- /dev/null +++ b/Modules/Compiler/GNU-C-FeatureTests.cmake @@ -0,0 +1,12 @@ + +set(_cmake_oldestSupported "(__GNUC__ * 100 + __GNUC_MINOR__) >= 407") + +set(GNU46_C11 "${_cmake_oldestSupported} && __STDC_VERSION__ >= 201112L") +set(_cmake_feature_test_c_static_assert "${GNU46_C11}") +# Since 4.4 at least: +set(GNU44_C99 "${_cmake_oldestSupported} && __STDC_VERSION__ >= 199901L") +set(_cmake_feature_test_c_restrict "${GNU44_C99}") +set(_cmake_feature_test_c_variadic_macros "${GNU44_C99}") + +set(GNU_C90 "${_cmake_oldestSupported} && !defined(__STDC_VERSION__)") +set(_cmake_feature_test_c_function_prototypes "${GNU_C90}") diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake index 9a5137a4b..35954be52 100644 --- a/Modules/Compiler/GNU-C.cmake +++ b/Modules/Compiler/GNU-C.cmake @@ -1,2 +1,34 @@ include(Compiler/GNU) __compiler_gnu(C) + +if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7) + set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90") + set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90") + + set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99") + set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99") + + set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11") + set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11") +endif() + +# This may change in a future GNU version. +set(CMAKE_C_STANDARD_DEFAULT 90) + +macro(cmake_record_c_compile_features) + macro(_get_gcc_features std_version list) + record_compiler_features(C "-std=${std_version}" ${list}) + endmacro() + + if (UNIX AND NOT APPLE AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7) + _get_gcc_features(c90 CMAKE_C90_COMPILE_FEATURES) + if (_result EQUAL 0) + _get_gcc_features(c99 CMAKE_C99_COMPILE_FEATURES) + endif() + if (_result EQUAL 0) + _get_gcc_features(c11 CMAKE_C11_COMPILE_FEATURES) + endif() + else() + set(_result 0) + endif() +endmacro() diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake index fd236c105..d3c20372d 100644 --- a/Modules/WriteCompilerDetectionHeader.cmake +++ b/Modules/WriteCompilerDetectionHeader.cmake @@ -43,7 +43,8 @@ # Possible compiler identifiers are documented with the # :variable:`CMAKE__COMPILER_ID` variable. # Available features in this version of CMake are listed in the -# :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global property. +# :prop_gbl:`CMAKE_C_KNOWN_FEATURES` and +# :prop_gbl:`CMAKE_CXX_KNOWN_FEATURES` global properties. # # Feature Test Macros # =================== @@ -102,6 +103,7 @@ # ========================== =================================== ================= # Feature Define Symbol # ========================== =================================== ================= +# ``c_restrict`` ``_RESTRICT`` ``restrict`` # ``cxx_constexpr`` ``_CONSTEXPR`` ``constexpr`` # ``cxx_deleted_functions`` ``_DELETED_FUNCTION`` ``= delete`` # ``cxx_extern_templates`` ``_EXTERN_TEMPLATE`` ``extern`` @@ -221,6 +223,9 @@ function(write_compiler_detection_header 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() @@ -239,6 +244,8 @@ function(write_compiler_detection_header 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}_ @@ -279,6 +286,16 @@ function(write_compiler_detection_header 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} @@ -382,9 +399,8 @@ function(write_compiler_detection_header \n") endif() endforeach() - if(_lang STREQUAL CXX) - set(file_content "${file_content}#endif\n") - endif() + + set(file_content "${file_content}#endif\n") endforeach() diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 7028da0e3..a6ad714f3 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2201,6 +2201,10 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target, // Maintain sorted order, most recent first. langStdMap["CXX"].push_back("11"); langStdMap["CXX"].push_back("98"); + + langStdMap["C"].push_back("11"); + langStdMap["C"].push_back("99"); + langStdMap["C"].push_back("90"); } std::string standard(standardProp); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 90a7b0bd4..42dedc971 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -4973,6 +4973,10 @@ void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) } #define FEATURE_STRING(F) , #F +static const char * const C_FEATURES[] = { + 0 + FOR_EACH_C_FEATURE(FEATURE_STRING) +}; static const char * const CXX_FEATURES[] = { 0 @@ -4980,6 +4984,11 @@ static const char * const CXX_FEATURES[] = { }; #undef FEATURE_STRING +static const char * const C_STANDARDS[] = { + "90" + , "99" + , "11" +}; static const char * const CXX_STANDARDS[] = { "98" , "11" @@ -4995,10 +5004,13 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature, target->AppendProperty("COMPILE_FEATURES", feature.c_str()); return true; } + bool isCFeature = std::find_if(cmArrayBegin(C_FEATURES) + 1, + cmArrayEnd(C_FEATURES), cmStrCmp(feature)) + != cmArrayEnd(C_FEATURES); bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1, cmArrayEnd(CXX_FEATURES), cmStrCmp(feature)) != cmArrayEnd(CXX_FEATURES); - if (!isCxxFeature) + if (!isCFeature && !isCxxFeature) { cmOStringStream e; if (error) @@ -5022,7 +5034,7 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature, return false; } - std::string lang = "CXX"; + std::string lang = isCFeature ? "C" : "CXX"; const char* featuresKnown = this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES"); @@ -5071,6 +5083,16 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature, target->AppendProperty("COMPILE_FEATURES", feature.c_str()); + return isCFeature + ? this->AddRequiredTargetCFeature(target, feature) + : this->AddRequiredTargetCxxFeature(target, feature); +} + +//---------------------------------------------------------------------------- +bool cmMakefile:: +AddRequiredTargetCxxFeature(cmTarget *target, + const std::string& feature) const +{ bool needCxx98 = false; bool needCxx11 = false; @@ -5136,3 +5158,93 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature, } return true; } + +//---------------------------------------------------------------------------- +bool cmMakefile:: +AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const +{ + bool needC90 = false; + bool needC99 = false; + bool needC11 = false; + + if (const char *propC90 = + this->GetDefinition("CMAKE_C90_COMPILE_FEATURES")) + { + std::vector props; + cmSystemTools::ExpandListArgument(propC90, props); + needC90 = std::find(props.begin(), props.end(), feature) != props.end(); + } + if (const char *propC99 = + this->GetDefinition("CMAKE_C99_COMPILE_FEATURES")) + { + std::vector props; + cmSystemTools::ExpandListArgument(propC99, props); + needC99 = std::find(props.begin(), props.end(), feature) != props.end(); + } + if (const char *propC11 = + this->GetDefinition("CMAKE_C11_COMPILE_FEATURES")) + { + std::vector props; + cmSystemTools::ExpandListArgument(propC11, props); + needC11 = std::find(props.begin(), props.end(), feature) != props.end(); + } + + const char *existingCStandard = target->GetProperty("C_STANDARD"); + if (existingCStandard) + { + if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), + cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS)) + { + cmOStringStream e; + e << "The C_STANDARD property on target \"" << target->GetName() + << "\" contained an invalid value: \"" << existingCStandard << "\"."; + this->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); + return false; + } + } + const char * const *existingCIt = existingCStandard + ? std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp(existingCStandard)) + : cmArrayEnd(C_STANDARDS); + + bool setC90 = needC90 && !existingCStandard; + bool setC99 = needC99 && !existingCStandard; + bool setC11 = needC11 && !existingCStandard; + + if (needC11 && existingCStandard && existingCIt < + std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp("11"))) + { + setC11 = true; + } + else if(needC99 && existingCStandard && existingCIt < + std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp("99"))) + { + setC99 = true; + } + else if(needC90 && existingCStandard && existingCIt < + std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp("90"))) + { + setC90 = true; + } + + if (setC11) + { + target->SetProperty("C_STANDARD", "11"); + } + else if (setC99) + { + target->SetProperty("C_STANDARD", "99"); + } + else if (setC90) + { + target->SetProperty("C_STANDARD", "90"); + } + return true; +} diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 2bfd19b01..90e2e19c5 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -1098,6 +1098,12 @@ private: std::vector QtUiFilesWithOptions; unsigned int NumLastMatches; + + bool AddRequiredTargetCFeature(cmTarget *target, + const std::string& feature) const; + + bool AddRequiredTargetCxxFeature(cmTarget *target, + const std::string& feature) const; }; //---------------------------------------------------------------------------- diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 3f2ae9e27..319b609e8 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -314,6 +314,9 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("MACOSX_BUNDLE", 0); this->SetPropertyDefault("MACOSX_RPATH", 0); this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 0); + this->SetPropertyDefault("C_STANDARD", 0); + this->SetPropertyDefault("C_STANDARD_REQUIRED", 0); + this->SetPropertyDefault("C_EXTENSIONS", 0); this->SetPropertyDefault("CXX_STANDARD", 0); this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0); this->SetPropertyDefault("CXX_EXTENSIONS", 0); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 3e789901d..a83ebd562 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2273,12 +2273,16 @@ const char *cmake::GetProperty(const std::string& prop, } this->SetProperty("ENABLED_LANGUAGES", lang.c_str()); } +#define STRING_LIST_ELEMENT(F) ";" #F + if (prop == "CMAKE_C_KNOWN_FEATURES") + { + return FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT) + 1; + } if (prop == "CMAKE_CXX_KNOWN_FEATURES") { -#define STRING_LIST_ELEMENT(F) ";" #F return FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT) + 1; -#undef STRING_LIST_ELEMENT } +#undef STRING_LIST_ELEMENT return this->Properties.GetPropertyValue(prop, scope, chain); } diff --git a/Source/cmake.h b/Source/cmake.h index 33b4f74b6..33a5d7889 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -458,6 +458,12 @@ private: {"-Wno-dev", "Suppress developer warnings."},\ {"-Wdev", "Enable developer warnings."} +#define FOR_EACH_C_FEATURE(F) \ + F(c_function_prototypes) \ + F(c_restrict) \ + F(c_static_assert) \ + F(c_variadic_macros) + #define FOR_EACH_CXX_FEATURE(F) \ F(cxx_alias_templates) \ F(cxx_alignas) \ diff --git a/Tests/CMakeCommands/target_compile_features/CMakeLists.txt b/Tests/CMakeCommands/target_compile_features/CMakeLists.txt index 62e3ce0b7..9b35f2713 100644 --- a/Tests/CMakeCommands/target_compile_features/CMakeLists.txt +++ b/Tests/CMakeCommands/target_compile_features/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.0) project(target_compile_features) -if (NOT CMAKE_CXX_COMPILE_FEATURES) +if (NOT CMAKE_CXX_COMPILE_FEATURES AND NOT CMAKE_C_COMPILE_FEATURES) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_dummy.cpp" "int main(int,char**) { return 0; }\n" ) @@ -11,15 +11,35 @@ endif() set(CMAKE_VERBOSE_MAKEFILE ON) -add_executable(target_compile_features main.cpp) -target_compile_features(target_compile_features - PRIVATE cxx_auto_type -) +if (CMAKE_C_COMPILE_FEATURES) + add_executable(target_compile_features main.c) + target_compile_features(target_compile_features + PRIVATE c_restrict + ) -add_library(lib_auto_type lib_auto_type.cpp) -target_compile_features(lib_auto_type - PUBLIC cxx_auto_type -) + add_library(lib_restrict lib_restrict.c) + target_compile_features(lib_restrict + PUBLIC c_restrict + ) -add_executable(lib_user lib_user.cpp) -target_link_libraries(lib_user lib_auto_type) + add_executable(restrict_user restrict_user.c) + target_link_libraries(restrict_user lib_restrict) +endif() + +if (CMAKE_CXX_COMPILE_FEATURES) + if (CMAKE_C_COMPILE_FEATURES) + set(target_suffix _cxx) + endif() + add_executable(target_compile_features${target_suffix} main.cpp) + target_compile_features(target_compile_features${target_suffix} + PRIVATE cxx_auto_type + ) + + add_library(lib_auto_type lib_auto_type.cpp) + target_compile_features(lib_auto_type + PUBLIC cxx_auto_type + ) + + add_executable(lib_user lib_user.cpp) + target_link_libraries(lib_user lib_auto_type) +endif() diff --git a/Tests/CMakeCommands/target_compile_features/lib_restrict.c b/Tests/CMakeCommands/target_compile_features/lib_restrict.c new file mode 100644 index 000000000..049c1b008 --- /dev/null +++ b/Tests/CMakeCommands/target_compile_features/lib_restrict.c @@ -0,0 +1,9 @@ + +#include "lib_restrict.h" + +int foo(int * restrict a, int * restrict b) +{ + (void)a; + (void)b; + return 0; +} diff --git a/Tests/CMakeCommands/target_compile_features/lib_restrict.h b/Tests/CMakeCommands/target_compile_features/lib_restrict.h new file mode 100644 index 000000000..eca22be10 --- /dev/null +++ b/Tests/CMakeCommands/target_compile_features/lib_restrict.h @@ -0,0 +1,7 @@ + +#ifndef LIB_RESTRICT_H +#define LIB_RESTRICT_H + +int foo(int * restrict a, int * restrict b); + +#endif diff --git a/Tests/CMakeCommands/target_compile_features/main.c b/Tests/CMakeCommands/target_compile_features/main.c new file mode 100644 index 000000000..831c5eb27 --- /dev/null +++ b/Tests/CMakeCommands/target_compile_features/main.c @@ -0,0 +1,12 @@ + +int foo(int * restrict a, int * restrict b) +{ + (void)a; + (void)b; + return 0; +} + +int main() +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_compile_features/restrict_user.c b/Tests/CMakeCommands/target_compile_features/restrict_user.c new file mode 100644 index 000000000..d47b847b4 --- /dev/null +++ b/Tests/CMakeCommands/target_compile_features/restrict_user.c @@ -0,0 +1,14 @@ + +#include "lib_restrict.h" + +int bar(int * restrict a, int * restrict b) +{ + (void)a; + (void)b; + return foo(a, b); +} + +int main() +{ + return 0; +} diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt index adf50d54e..0e1e6c99a 100644 --- a/Tests/CompileFeatures/CMakeLists.txt +++ b/Tests/CompileFeatures/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0) project(CompileFeatures) -if (NOT CMAKE_CXX_COMPILE_FEATURES) +if (NOT CMAKE_C_COMPILE_FEATURES AND NOT CMAKE_CXX_COMPILE_FEATURES) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp" "int main(int,char**) { return 0; }\n" ) @@ -22,6 +22,10 @@ macro(run_test feature lang) endif() endmacro() +get_property(c_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES) +foreach(feature ${c_features}) + run_test(${feature} C) +endforeach() get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) foreach(feature ${cxx_features}) run_test(${feature} CXX) @@ -34,9 +38,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU ) endif() +set(C_ext c) +set(C_standard_flag 11) set(CXX_ext cpp) set(CXX_standard_flag 11) -foreach(lang CXX) +foreach(lang CXX C) if (CMAKE_${lang}_COMPILE_FEATURES) foreach(feature ${${lang}_non_features}) message("Testing feature : ${feature}") diff --git a/Tests/CompileFeatures/c_function_prototypes.c b/Tests/CompileFeatures/c_function_prototypes.c new file mode 100644 index 000000000..ab3c94887 --- /dev/null +++ b/Tests/CompileFeatures/c_function_prototypes.c @@ -0,0 +1,9 @@ + +int someFunc(int a, int b); + +int someFunc(int a, int b) +{ + (void)a; + (void)b; + return 0; +} diff --git a/Tests/CompileFeatures/c_restrict.c b/Tests/CompileFeatures/c_restrict.c new file mode 100644 index 000000000..7bc756658 --- /dev/null +++ b/Tests/CompileFeatures/c_restrict.c @@ -0,0 +1,7 @@ + +int f (int * restrict a, int * restrict b) +{ + (void)a; + (void)b; + return 0; +} diff --git a/Tests/CompileFeatures/c_static_assert.c b/Tests/CompileFeatures/c_static_assert.c new file mode 100644 index 000000000..afab50418 --- /dev/null +++ b/Tests/CompileFeatures/c_static_assert.c @@ -0,0 +1,2 @@ + +_Static_assert(1, "Static assert test"); diff --git a/Tests/CompileFeatures/c_variadic_macros.c b/Tests/CompileFeatures/c_variadic_macros.c new file mode 100644 index 000000000..4da111e62 --- /dev/null +++ b/Tests/CompileFeatures/c_variadic_macros.c @@ -0,0 +1,15 @@ + +int someFunc(int i1, char c, int i2) +{ + (void)i1; + (void)c; + (void)i2; + return 0; +} + +#define FUNC_WRAPPER(...) someFunc(__VA_ARGS__) + +void otherFunc() +{ + FUNC_WRAPPER(42, 'a', 7); +} diff --git a/Tests/CompileFeatures/main.c b/Tests/CompileFeatures/main.c new file mode 100644 index 000000000..831c5eb27 --- /dev/null +++ b/Tests/CompileFeatures/main.c @@ -0,0 +1,12 @@ + +int foo(int * restrict a, int * restrict b) +{ + (void)a; + (void)b; + return 0; +} + +int main() +{ + return 0; +} diff --git a/Tests/ExportImport/Export/Interface/CMakeLists.txt b/Tests/ExportImport/Export/Interface/CMakeLists.txt index 1b653ebd5..523fc298c 100644 --- a/Tests/ExportImport/Export/Interface/CMakeLists.txt +++ b/Tests/ExportImport/Export/Interface/CMakeLists.txt @@ -26,7 +26,10 @@ target_link_libraries(sharediface INTERFACE sharedlib) add_library(use_auto_type INTERFACE) target_compile_features(use_auto_type INTERFACE cxx_auto_type) -install(TARGETS headeronly sharediface use_auto_type +add_library(use_c_restrict INTERFACE) +target_compile_features(use_c_restrict INTERFACE c_restrict) + +install(TARGETS headeronly sharediface use_auto_type use_c_restrict EXPORT expInterface ) install(TARGETS sharedlib diff --git a/Tests/ExportImport/Import/Interface/CMakeLists.txt b/Tests/ExportImport/Import/Interface/CMakeLists.txt index 18d9b76d6..4028405ae 100644 --- a/Tests/ExportImport/Import/Interface/CMakeLists.txt +++ b/Tests/ExportImport/Import/Interface/CMakeLists.txt @@ -17,6 +17,7 @@ set_property(TARGET bld::sharediface APPEND PROPERTY INTERFACE_LINK_LIBRARIES de add_executable(interfacetest_bld interfacetest.cpp) target_link_libraries(interfacetest_bld bld::sharediface) +include(CheckCSourceCompiles) include(CheckCXXSourceCompiles) macro(do_try_compile prefix) @@ -41,6 +42,26 @@ macro(do_try_compile prefix) message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}") endif() + if (";${CMAKE_C_COMPILE_FEATURES};" MATCHES ";c_restrict;") + set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_c_restrict) + check_c_source_compiles( + " + int foo(int * restrict a, int * restrict b) + { + (void)a; + (void)b; + return 0; + } + int main() + { + return 0; + } + " ${prefix}IMPORTED_IFACE_C_RESTRICT) + + if(NOT ${prefix}IMPORTED_IFACE_C_RESTRICT) + message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}") + endif() + endif() if (";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_auto_type;") set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_auto_type) check_cxx_source_compiles( diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt index 6c5e0bee9..8dd262e0f 100644 --- a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt +++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) include(WriteCompilerDetectionHeader) get_property(cxx_known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) +get_property(c_known_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES) write_compiler_detection_header( FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h" @@ -15,10 +16,10 @@ write_compiler_detection_header( PROLOG "// something" EPILOG "// more" FEATURES - ${cxx_known_features} + ${cxx_known_features} ${c_known_features} ) -if (NOT CMAKE_CXX_COMPILE_FEATURES) +if (NOT CMAKE_CXX_COMPILE_FEATURES AND NOT CMAKE_C_COMPILE_FEATURES) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp" "int main(int,char**) { return 0; }\n" ) diff --git a/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt b/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-stderr.txt b/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-stderr.txt new file mode 100644 index 000000000..fd18c885b --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at NoSupportedCFeatures.cmake:[0-9]+ \(target_compile_features\): + target_compile_features no known features for C compiler + + "[^"]*" + + version *[.0-9]+\. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures.cmake b/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures.cmake new file mode 100644 index 000000000..3624d4b9f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NoSupportedCFeatures.cmake @@ -0,0 +1,5 @@ + +enable_language(C) + +add_library(no_features empty.c) +target_compile_features(no_features PRIVATE c_static_assert) diff --git a/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt b/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt b/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt new file mode 100644 index 000000000..df647e8b3 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt @@ -0,0 +1,6 @@ +CMake Error in CMakeLists.txt: + No known features for C compiler + + "[^"]*" + + version *[.0-9]+\. diff --git a/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex.cmake b/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex.cmake new file mode 100644 index 000000000..b6053aaf1 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex.cmake @@ -0,0 +1,5 @@ + +enable_language(C) + +add_library(no_features empty.c) +target_compile_features(no_features PRIVATE $<1:c_static_assert>) diff --git a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake index bb4e0f904..a23d44f6b 100644 --- a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake +++ b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake @@ -9,11 +9,20 @@ run_cmake(NotAFeature_OriginDebugTransitive) run_cmake(NotAFeature_OriginDebug_target_compile_features) run_cmake(generate_feature_list) +file(READ + "${RunCMake_BINARY_DIR}/generate_feature_list-build/c_features.txt" + C_FEATURES +) file(READ "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt" CXX_FEATURES ) +if (NOT C_FEATURES) + run_cmake(NoSupportedCFeatures) + run_cmake(NoSupportedCFeaturesGenex) +endif() + if (NOT CXX_FEATURES) run_cmake(NoSupportedCxxFeatures) run_cmake(NoSupportedCxxFeaturesGenex) diff --git a/Tests/RunCMake/CompileFeatures/empty.c b/Tests/RunCMake/CompileFeatures/empty.c new file mode 100644 index 000000000..bfbbddeb9 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/empty.c @@ -0,0 +1,7 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int empty() +{ + return 0; +} diff --git a/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake b/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake index beb15fc89..09e17b114 100644 --- a/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake +++ b/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake @@ -1,4 +1,10 @@ +enable_language(C) + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/c_features.txt" + "${CMAKE_C_COMPILE_FEATURES}" +) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_features.txt" "${CMAKE_CXX_COMPILE_FEATURES}" ) diff --git a/Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt b/Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt index bb87f4c31..92fe2330a 100644 --- a/Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt +++ b/Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt @@ -1,4 +1,4 @@ -- Detecting C compiler ABI info --- Detecting C compiler ABI info - failed +-- Detecting C compiler ABI info - failed.* -- Configuring done -- Generating done diff --git a/Tests/RunCMake/target_compile_features/RunCMakeTest.cmake b/Tests/RunCMake/target_compile_features/RunCMakeTest.cmake index f2abef7ad..33faf2bbb 100644 --- a/Tests/RunCMake/target_compile_features/RunCMakeTest.cmake +++ b/Tests/RunCMake/target_compile_features/RunCMakeTest.cmake @@ -9,3 +9,5 @@ run_cmake(imported_target) run_cmake(no_target) run_cmake(not_a_cxx_feature) run_cmake(no_matching_cxx_feature) +run_cmake(not_a_c_feature) +run_cmake(no_matching_c_feature) diff --git a/Tests/RunCMake/target_compile_features/empty.c b/Tests/RunCMake/target_compile_features/empty.c new file mode 100644 index 000000000..bfbbddeb9 --- /dev/null +++ b/Tests/RunCMake/target_compile_features/empty.c @@ -0,0 +1,7 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int empty() +{ + return 0; +} diff --git a/Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt b/Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_compile_features/no_matching_c_feature-stderr.txt b/Tests/RunCMake/target_compile_features/no_matching_c_feature-stderr.txt new file mode 100644 index 000000000..96b959cf5 --- /dev/null +++ b/Tests/RunCMake/target_compile_features/no_matching_c_feature-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at no_matching_c_feature.cmake:[0-9][0-9]? \((target_compile_features|message)\): + The compiler feature "gnu_c_dummy" is not known to C compiler + + "GNU" + + version 4.8.1. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/target_compile_features/no_matching_c_feature.cmake b/Tests/RunCMake/target_compile_features/no_matching_c_feature.cmake new file mode 100644 index 000000000..a44caf29a --- /dev/null +++ b/Tests/RunCMake/target_compile_features/no_matching_c_feature.cmake @@ -0,0 +1,15 @@ + +if (NOT ";${CMAKE_C_COMPILE_FEATURES};" MATCHES ";gnu_c_typeof;") + # Simulate passing the test. + message(SEND_ERROR + "The compiler feature \"gnu_c_dummy\" is not known to C compiler\n\"GNU\"\nversion 4.8.1." + ) + return() +endif() + +add_executable(main empty.c) + +target_compile_features(main + PRIVATE + gnu_c_typeof +) diff --git a/Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt b/Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/target_compile_features/not_a_c_feature-stderr.txt b/Tests/RunCMake/target_compile_features/not_a_c_feature-stderr.txt new file mode 100644 index 000000000..6dd00f359 --- /dev/null +++ b/Tests/RunCMake/target_compile_features/not_a_c_feature-stderr.txt @@ -0,0 +1,5 @@ +CMake Error at not_a_c_feature.cmake:3 \(target_compile_features\): + target_compile_features specified unknown feature "c_not_a_feature" for + target "main". +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/target_compile_features/not_a_c_feature.cmake b/Tests/RunCMake/target_compile_features/not_a_c_feature.cmake new file mode 100644 index 000000000..0420698bc --- /dev/null +++ b/Tests/RunCMake/target_compile_features/not_a_c_feature.cmake @@ -0,0 +1,6 @@ + +add_executable(main empty.c) +target_compile_features(main + PRIVATE + c_not_a_feature +) diff --git a/Tests/SystemInformation/SystemInformation.in b/Tests/SystemInformation/SystemInformation.in index 9966e8dab..7e1ee24b6 100644 --- a/Tests/SystemInformation/SystemInformation.in +++ b/Tests/SystemInformation/SystemInformation.in @@ -19,6 +19,16 @@ CMAKE_COMPILER_IS_GNUCC == "${CMAKE_COMPILER_IS_GNUCC}" CMAKE_COMPILER_IS_GNUCXX == "${CMAKE_COMPILER_IS_GNUCXX}" CMAKE_C_COMPILER_ID == "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_VERSION == "${CMAKE_C_COMPILER_VERSION}" +CMAKE_C90_STANDARD_COMPILE_OPTION == "${CMAKE_C90_STANDARD_COMPILE_OPTION}" +CMAKE_C99_STANDARD_COMPILE_OPTION == "${CMAKE_C99_STANDARD_COMPILE_OPTION}" +CMAKE_C11_STANDARD_COMPILE_OPTION == "${CMAKE_C11_STANDARD_COMPILE_OPTION}" +CMAKE_C90_EXTENSION_COMPILE_OPTION == "${CMAKE_C90_EXTENSION_COMPILE_OPTION}" +CMAKE_C99_EXTENSION_COMPILE_OPTION == "${CMAKE_C99_EXTENSION_COMPILE_OPTION}" +CMAKE_C11_EXTENSION_COMPILE_OPTION == "${CMAKE_C11_EXTENSION_COMPILE_OPTION}" +CMAKE_C_COMPILE_FEATURES == "${CMAKE_C_COMPILE_FEATURES}" +CMAKE_C90_COMPILE_FEATURES == "${CMAKE_C90_COMPILE_FEATURES}" +CMAKE_C99_COMPILE_FEATURES == "${CMAKE_C99_COMPILE_FEATURES}" +CMAKE_C11_COMPILE_FEATURES == "${CMAKE_C11_COMPILE_FEATURES}" CMAKE_CXX_COMPILER_ID == "${CMAKE_CXX_COMPILER_ID}" CMAKE_CXX_COMPILER_VERSION == "${CMAKE_CXX_COMPILER_VERSION}" CMAKE_CXX98_STANDARD_COMPILE_OPTION == "${CMAKE_CXX98_STANDARD_COMPILE_OPTION}"