浏览代码

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 <PREFIX>_RESTRICT symbol define to WriteCompilerDetectionHeader
to conditionally represent the c_restrict feature.
Stephen Kelly 12 年之前
父节点
当前提交
e0890d03a4
共有 57 个文件被更改,包括 630 次插入27 次删除
  1. 2 1
      Help/command/target_compile_features.rst
  2. 4 0
      Help/manual/cmake-properties.7.rst
  3. 4 0
      Help/manual/cmake-variables.7.rst
  4. 25 0
      Help/prop_gbl/CMAKE_C_KNOWN_FEATURES.rst
  5. 8 0
      Help/prop_tgt/C_EXTENSIONS.rst
  6. 27 0
      Help/prop_tgt/C_STANDARD.rst
  7. 14 0
      Help/prop_tgt/C_STANDARD_REQUIRED.rst
  8. 6 0
      Help/release/dev/compile-language-features.rst
  9. 8 0
      Help/variable/CMAKE_C_COMPILE_FEATURES.rst
  10. 8 0
      Help/variable/CMAKE_C_EXTENSIONS.rst
  11. 8 0
      Help/variable/CMAKE_C_STANDARD.rst
  12. 8 0
      Help/variable/CMAKE_C_STANDARD_REQUIRED.rst
  13. 5 0
      Modules/CMakeCCompiler.cmake.in
  14. 39 1
      Modules/CMakeDetermineCompileFeatures.cmake
  15. 3 0
      Modules/CMakeTestCCompiler.cmake
  16. 12 0
      Modules/Compiler/GNU-C-FeatureTests.cmake
  17. 32 0
      Modules/Compiler/GNU-C.cmake
  18. 20 4
      Modules/WriteCompilerDetectionHeader.cmake
  19. 4 0
      Source/cmLocalGenerator.cxx
  20. 114 2
      Source/cmMakefile.cxx
  21. 6 0
      Source/cmMakefile.h
  22. 3 0
      Source/cmTarget.cxx
  23. 6 2
      Source/cmake.cxx
  24. 6 0
      Source/cmake.h
  25. 31 11
      Tests/CMakeCommands/target_compile_features/CMakeLists.txt
  26. 9 0
      Tests/CMakeCommands/target_compile_features/lib_restrict.c
  27. 7 0
      Tests/CMakeCommands/target_compile_features/lib_restrict.h
  28. 12 0
      Tests/CMakeCommands/target_compile_features/main.c
  29. 14 0
      Tests/CMakeCommands/target_compile_features/restrict_user.c
  30. 8 2
      Tests/CompileFeatures/CMakeLists.txt
  31. 9 0
      Tests/CompileFeatures/c_function_prototypes.c
  32. 7 0
      Tests/CompileFeatures/c_restrict.c
  33. 2 0
      Tests/CompileFeatures/c_static_assert.c
  34. 15 0
      Tests/CompileFeatures/c_variadic_macros.c
  35. 12 0
      Tests/CompileFeatures/main.c
  36. 4 1
      Tests/ExportImport/Export/Interface/CMakeLists.txt
  37. 21 0
      Tests/ExportImport/Import/Interface/CMakeLists.txt
  38. 3 2
      Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt
  39. 1 0
      Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt
  40. 8 0
      Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-stderr.txt
  41. 5 0
      Tests/RunCMake/CompileFeatures/NoSupportedCFeatures.cmake
  42. 1 0
      Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt
  43. 6 0
      Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt
  44. 5 0
      Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex.cmake
  45. 9 0
      Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
  46. 7 0
      Tests/RunCMake/CompileFeatures/empty.c
  47. 6 0
      Tests/RunCMake/CompileFeatures/generate_feature_list.cmake
  48. 1 1
      Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt
  49. 2 0
      Tests/RunCMake/target_compile_features/RunCMakeTest.cmake
  50. 7 0
      Tests/RunCMake/target_compile_features/empty.c
  51. 1 0
      Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt
  52. 8 0
      Tests/RunCMake/target_compile_features/no_matching_c_feature-stderr.txt
  53. 15 0
      Tests/RunCMake/target_compile_features/no_matching_c_feature.cmake
  54. 1 0
      Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt
  55. 5 0
      Tests/RunCMake/target_compile_features/not_a_c_feature-stderr.txt
  56. 6 0
      Tests/RunCMake/target_compile_features/not_a_c_feature.cmake
  57. 10 0
      Tests/SystemInformation/SystemInformation.in

+ 2 - 1
Help/command/target_compile_features.rst

@@ -8,7 +8,8 @@ Add expected compiler features to a target.
   target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
   target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
 
 
 Specify compiler features required when compiling a given target.  If the
 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
 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
 an additional compiler flag, such as ``-std=c++11``, the flag will be added
 automatically.
 automatically.

+ 4 - 0
Help/manual/cmake-properties.7.rst

@@ -16,6 +16,7 @@ Properties of Global Scope
    /prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS
    /prop_gbl/ALLOW_DUPLICATE_CUSTOM_TARGETS
    /prop_gbl/AUTOGEN_TARGETS_FOLDER
    /prop_gbl/AUTOGEN_TARGETS_FOLDER
    /prop_gbl/AUTOMOC_TARGETS_FOLDER
    /prop_gbl/AUTOMOC_TARGETS_FOLDER
+   /prop_gbl/CMAKE_C_KNOWN_FEATURES
    /prop_gbl/CMAKE_CXX_KNOWN_FEATURES
    /prop_gbl/CMAKE_CXX_KNOWN_FEATURES
    /prop_gbl/DEBUG_CONFIGURATIONS
    /prop_gbl/DEBUG_CONFIGURATIONS
    /prop_gbl/DISABLED_FEATURES
    /prop_gbl/DISABLED_FEATURES
@@ -93,6 +94,9 @@ Properties on Targets
    /prop_tgt/BUILD_WITH_INSTALL_RPATH
    /prop_tgt/BUILD_WITH_INSTALL_RPATH
    /prop_tgt/BUNDLE_EXTENSION
    /prop_tgt/BUNDLE_EXTENSION
    /prop_tgt/BUNDLE
    /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_BOOL
    /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX
    /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MAX
    /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN
    /prop_tgt/COMPATIBLE_INTERFACE_NUMBER_MIN

+ 4 - 0
Help/manual/cmake-variables.7.rst

@@ -260,6 +260,10 @@ Variables for Languages
    :maxdepth: 1
    :maxdepth: 1
 
 
    /variable/CMAKE_COMPILER_IS_GNULANG
    /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_COMPILE_FEATURES
    /variable/CMAKE_CXX_EXTENSIONS
    /variable/CMAKE_CXX_EXTENSIONS
    /variable/CMAKE_CXX_STANDARD
    /variable/CMAKE_CXX_STANDARD

+ 25 - 0
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``.

+ 8 - 0
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.

+ 27 - 0
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.

+ 14 - 0
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.

+ 6 - 0
Help/release/dev/compile-language-features.rst

@@ -7,6 +7,12 @@ target-language-features
   :variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_EXTENSIONS`
   :variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_EXTENSIONS`
   variables may be set to initialize the target properties.
   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
 * New :prop_tgt:`COMPILE_FEATURES` target property may contain a list
   of features required to compile a target.  CMake uses this
   of features required to compile a target.  CMake uses this
   information to ensure that the compiler in use is capable of building
   information to ensure that the compiler in use is capable of building

+ 8 - 0
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.

+ 8 - 0
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.

+ 8 - 0
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.

+ 8 - 0
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.

+ 5 - 0
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_ARG1 "@CMAKE_C_COMPILER_ARG1@")
 set(CMAKE_C_COMPILER_ID "@CMAKE_C_COMPILER_ID@")
 set(CMAKE_C_COMPILER_ID "@CMAKE_C_COMPILER_ID@")
 set(CMAKE_C_COMPILER_VERSION "@CMAKE_C_COMPILER_VERSION@")
 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_PLATFORM_ID "@CMAKE_C_PLATFORM_ID@")
 set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@")
 set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@")
 set(CMAKE_C_SIMULATE_VERSION "@CMAKE_C_SIMULATE_VERSION@")
 set(CMAKE_C_SIMULATE_VERSION "@CMAKE_C_SIMULATE_VERSION@")

+ 39 - 1
Modules/CMakeDetermineCompileFeatures.cmake

@@ -14,7 +14,45 @@
 
 
 function(cmake_determine_compile_features lang)
 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")
     message(STATUS "Detecting ${lang} compile features")
 
 
     set(CMAKE_CXX98_COMPILE_FEATURES)
     set(CMAKE_CXX98_COMPILE_FEATURES)

+ 3 - 0
Modules/CMakeTestCCompiler.cmake

@@ -73,6 +73,9 @@ else()
   # Try to identify the ABI and configure it into CMakeCCompiler.cmake
   # Try to identify the ABI and configure it into CMakeCCompiler.cmake
   include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
   include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
   CMAKE_DETERMINE_COMPILER_ABI(C ${CMAKE_ROOT}/Modules/CMakeCCompilerABI.c)
   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.
   # Re-configure to save learned information.
   configure_file(
   configure_file(

+ 12 - 0
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}")

+ 32 - 0
Modules/Compiler/GNU-C.cmake

@@ -1,2 +1,34 @@
 include(Compiler/GNU)
 include(Compiler/GNU)
 __compiler_gnu(C)
 __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()

+ 20 - 4
Modules/WriteCompilerDetectionHeader.cmake

@@ -43,7 +43,8 @@
 # Possible compiler identifiers are documented with the
 # Possible compiler identifiers are documented with the
 # :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 # :variable:`CMAKE_<LANG>_COMPILER_ID` variable.
 # Available features in this version of CMake are listed in the
 # 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
 # Feature Test Macros
 # ===================
 # ===================
@@ -102,6 +103,7 @@
 # ========================== =================================== =================
 # ========================== =================================== =================
 #         Feature                          Define                      Symbol
 #         Feature                          Define                      Symbol
 # ========================== =================================== =================
 # ========================== =================================== =================
+# ``c_restrict``              ``<PREFIX>_RESTRICT``               ``restrict``
 # ``cxx_constexpr``           ``<PREFIX>_CONSTEXPR``              ``constexpr``
 # ``cxx_constexpr``           ``<PREFIX>_CONSTEXPR``              ``constexpr``
 # ``cxx_deleted_functions``   ``<PREFIX>_DELETED_FUNCTION``       ``= delete``
 # ``cxx_deleted_functions``   ``<PREFIX>_DELETED_FUNCTION``       ``= delete``
 # ``cxx_extern_templates``    ``<PREFIX>_EXTERN_TEMPLATE``        ``extern``
 # ``cxx_extern_templates``    ``<PREFIX>_EXTERN_TEMPLATE``        ``extern``
@@ -221,6 +223,9 @@ function(write_compiler_detection_header
     if (feature MATCHES "^cxx_")
     if (feature MATCHES "^cxx_")
       list(APPEND _langs CXX)
       list(APPEND _langs CXX)
       list(APPEND CXX_features ${feature})
       list(APPEND CXX_features ${feature})
+    elseif (feature MATCHES "^c_")
+      list(APPEND _langs C)
+      list(APPEND C_features ${feature})
     else()
     else()
       message(FATAL_ERROR "Unsupported feature ${feature}.")
       message(FATAL_ERROR "Unsupported feature ${feature}.")
     endif()
     endif()
@@ -239,6 +244,8 @@ function(write_compiler_detection_header
 
 
     if(_lang STREQUAL CXX)
     if(_lang STREQUAL CXX)
       set(file_content "${file_content}\n#ifdef __cplusplus\n")
       set(file_content "${file_content}\n#ifdef __cplusplus\n")
+    else()
+      set(file_content "${file_content}\n#ifndef __cplusplus\n")
     endif()
     endif()
 
 
     compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_
     compiler_id_detection(ID_CONTENT ${_lang} PREFIX ${prefix_arg}_
@@ -279,6 +286,16 @@ function(write_compiler_detection_header
       string(TOUPPER ${feature} feature_upper)
       string(TOUPPER ${feature} feature_upper)
       set(feature_PP "COMPILER_${feature_upper}")
       set(feature_PP "COMPILER_${feature_upper}")
       set(def_name ${prefix_arg}_${feature_PP})
       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)
       if (feature STREQUAL cxx_constexpr)
         set(def_value "${prefix_arg}_DECL_${feature_upper}")
         set(def_value "${prefix_arg}_DECL_${feature_upper}")
         set(file_content "${file_content}
         set(file_content "${file_content}
@@ -382,9 +399,8 @@ function(write_compiler_detection_header
 \n")
 \n")
       endif()
       endif()
     endforeach()
     endforeach()
-    if(_lang STREQUAL CXX)
-      set(file_content "${file_content}#endif\n")
-    endif()
+
+    set(file_content "${file_content}#endif\n")
 
 
   endforeach()
   endforeach()
 
 

+ 4 - 0
Source/cmLocalGenerator.cxx

@@ -2201,6 +2201,10 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
     // Maintain sorted order, most recent first.
     // Maintain sorted order, most recent first.
     langStdMap["CXX"].push_back("11");
     langStdMap["CXX"].push_back("11");
     langStdMap["CXX"].push_back("98");
     langStdMap["CXX"].push_back("98");
+
+    langStdMap["C"].push_back("11");
+    langStdMap["C"].push_back("99");
+    langStdMap["C"].push_back("90");
     }
     }
 
 
   std::string standard(standardProp);
   std::string standard(standardProp);

+ 114 - 2
Source/cmMakefile.cxx

@@ -4973,6 +4973,10 @@ void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
 }
 }
 
 
 #define FEATURE_STRING(F) , #F
 #define FEATURE_STRING(F) , #F
+static const char * const C_FEATURES[] = {
+  0
+  FOR_EACH_C_FEATURE(FEATURE_STRING)
+};
 
 
 static const char * const CXX_FEATURES[] = {
 static const char * const CXX_FEATURES[] = {
   0
   0
@@ -4980,6 +4984,11 @@ static const char * const CXX_FEATURES[] = {
 };
 };
 #undef FEATURE_STRING
 #undef FEATURE_STRING
 
 
+static const char * const C_STANDARDS[] = {
+    "90"
+  , "99"
+  , "11"
+};
 static const char * const CXX_STANDARDS[] = {
 static const char * const CXX_STANDARDS[] = {
     "98"
     "98"
   , "11"
   , "11"
@@ -4995,10 +5004,13 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
     target->AppendProperty("COMPILE_FEATURES", feature.c_str());
     target->AppendProperty("COMPILE_FEATURES", feature.c_str());
     return true;
     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,
   bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1,
               cmArrayEnd(CXX_FEATURES), cmStrCmp(feature))
               cmArrayEnd(CXX_FEATURES), cmStrCmp(feature))
               != cmArrayEnd(CXX_FEATURES);
               != cmArrayEnd(CXX_FEATURES);
-  if (!isCxxFeature)
+  if (!isCFeature && !isCxxFeature)
     {
     {
     cmOStringStream e;
     cmOStringStream e;
     if (error)
     if (error)
@@ -5022,7 +5034,7 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
     return false;
     return false;
     }
     }
 
 
-  std::string lang = "CXX";
+  std::string lang = isCFeature ? "C" : "CXX";
 
 
   const char* featuresKnown =
   const char* featuresKnown =
     this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
     this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
@@ -5071,6 +5083,16 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
 
 
   target->AppendProperty("COMPILE_FEATURES", feature.c_str());
   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 needCxx98 = false;
   bool needCxx11 = false;
   bool needCxx11 = false;
 
 
@@ -5136,3 +5158,93 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
     }
     }
   return true;
   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<std::string> 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<std::string> 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<std::string> 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;
+}

+ 6 - 0
Source/cmMakefile.h

@@ -1098,6 +1098,12 @@ private:
   std::vector<cmSourceFile*> QtUiFilesWithOptions;
   std::vector<cmSourceFile*> QtUiFilesWithOptions;
 
 
   unsigned int NumLastMatches;
   unsigned int NumLastMatches;
+
+  bool AddRequiredTargetCFeature(cmTarget *target,
+                                 const std::string& feature) const;
+
+  bool AddRequiredTargetCxxFeature(cmTarget *target,
+                                   const std::string& feature) const;
 };
 };
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------

+ 3 - 0
Source/cmTarget.cxx

@@ -314,6 +314,9 @@ void cmTarget::SetMakefile(cmMakefile* mf)
     this->SetPropertyDefault("MACOSX_BUNDLE", 0);
     this->SetPropertyDefault("MACOSX_BUNDLE", 0);
     this->SetPropertyDefault("MACOSX_RPATH", 0);
     this->SetPropertyDefault("MACOSX_RPATH", 0);
     this->SetPropertyDefault("NO_SYSTEM_FROM_IMPORTED", 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", 0);
     this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0);
     this->SetPropertyDefault("CXX_STANDARD_REQUIRED", 0);
     this->SetPropertyDefault("CXX_EXTENSIONS", 0);
     this->SetPropertyDefault("CXX_EXTENSIONS", 0);

+ 6 - 2
Source/cmake.cxx

@@ -2273,12 +2273,16 @@ const char *cmake::GetProperty(const std::string& prop,
       }
       }
     this->SetProperty("ENABLED_LANGUAGES", lang.c_str());
     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")
   if (prop == "CMAKE_CXX_KNOWN_FEATURES")
     {
     {
-#define STRING_LIST_ELEMENT(F) ";" #F
     return FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT) + 1;
     return FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT) + 1;
-#undef STRING_LIST_ELEMENT
     }
     }
+#undef STRING_LIST_ELEMENT
   return this->Properties.GetPropertyValue(prop, scope, chain);
   return this->Properties.GetPropertyValue(prop, scope, chain);
 }
 }
 
 

+ 6 - 0
Source/cmake.h

@@ -458,6 +458,12 @@ private:
   {"-Wno-dev", "Suppress developer warnings."},\
   {"-Wno-dev", "Suppress developer warnings."},\
   {"-Wdev", "Enable 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) \
 #define FOR_EACH_CXX_FEATURE(F) \
   F(cxx_alias_templates) \
   F(cxx_alias_templates) \
   F(cxx_alignas) \
   F(cxx_alignas) \

+ 31 - 11
Tests/CMakeCommands/target_compile_features/CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 3.0)
 cmake_minimum_required(VERSION 3.0)
 project(target_compile_features)
 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"
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test_dummy.cpp"
     "int main(int,char**) { return 0; }\n"
     "int main(int,char**) { return 0; }\n"
   )
   )
@@ -11,15 +11,35 @@ endif()
 
 
 set(CMAKE_VERBOSE_MAKEFILE ON)
 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()

+ 9 - 0
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;
+}

+ 7 - 0
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

+ 12 - 0
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;
+}

+ 14 - 0
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;
+}

+ 8 - 2
Tests/CompileFeatures/CMakeLists.txt

@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0)
 
 
 project(CompileFeatures)
 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"
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
     "int main(int,char**) { return 0; }\n"
     "int main(int,char**) { return 0; }\n"
   )
   )
@@ -22,6 +22,10 @@ macro(run_test feature lang)
   endif()
   endif()
 endmacro()
 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)
 get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
 foreach(feature ${cxx_features})
 foreach(feature ${cxx_features})
   run_test(${feature} CXX)
   run_test(${feature} CXX)
@@ -34,9 +38,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU
   )
   )
 endif()
 endif()
 
 
+set(C_ext c)
+set(C_standard_flag 11)
 set(CXX_ext cpp)
 set(CXX_ext cpp)
 set(CXX_standard_flag 11)
 set(CXX_standard_flag 11)
-foreach(lang CXX)
+foreach(lang CXX C)
   if (CMAKE_${lang}_COMPILE_FEATURES)
   if (CMAKE_${lang}_COMPILE_FEATURES)
     foreach(feature ${${lang}_non_features})
     foreach(feature ${${lang}_non_features})
       message("Testing feature : ${feature}")
       message("Testing feature : ${feature}")

+ 9 - 0
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;
+}

+ 7 - 0
Tests/CompileFeatures/c_restrict.c

@@ -0,0 +1,7 @@
+
+int f (int * restrict a, int * restrict b)
+{
+  (void)a;
+  (void)b;
+  return 0;
+}

+ 2 - 0
Tests/CompileFeatures/c_static_assert.c

@@ -0,0 +1,2 @@
+
+_Static_assert(1, "Static assert test");

+ 15 - 0
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);
+}

+ 12 - 0
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;
+}

+ 4 - 1
Tests/ExportImport/Export/Interface/CMakeLists.txt

@@ -26,7 +26,10 @@ target_link_libraries(sharediface INTERFACE sharedlib)
 add_library(use_auto_type INTERFACE)
 add_library(use_auto_type INTERFACE)
 target_compile_features(use_auto_type INTERFACE cxx_auto_type)
 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
   EXPORT expInterface
 )
 )
 install(TARGETS sharedlib
 install(TARGETS sharedlib

+ 21 - 0
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)
 add_executable(interfacetest_bld interfacetest.cpp)
 target_link_libraries(interfacetest_bld bld::sharediface)
 target_link_libraries(interfacetest_bld bld::sharediface)
 
 
+include(CheckCSourceCompiles)
 include(CheckCXXSourceCompiles)
 include(CheckCXXSourceCompiles)
 
 
 macro(do_try_compile prefix)
 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}")
     message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}")
   endif()
   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;")
   if (";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_auto_type;")
     set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_auto_type)
     set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_auto_type)
     check_cxx_source_compiles(
     check_cxx_source_compiles(

+ 3 - 2
Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt

@@ -6,6 +6,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 include(WriteCompilerDetectionHeader)
 include(WriteCompilerDetectionHeader)
 
 
 get_property(cxx_known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
 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(
 write_compiler_detection_header(
   FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h"
   FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h"
@@ -15,10 +16,10 @@ write_compiler_detection_header(
   PROLOG "// something"
   PROLOG "// something"
   EPILOG "// more"
   EPILOG "// more"
   FEATURES
   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"
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp"
     "int main(int,char**) { return 0; }\n"
     "int main(int,char**) { return 0; }\n"
   )
   )

+ 1 - 0
Tests/RunCMake/CompileFeatures/NoSupportedCFeatures-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
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\)

+ 5 - 0
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)

+ 1 - 0
Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-result.txt

@@ -0,0 +1 @@
+1

+ 6 - 0
Tests/RunCMake/CompileFeatures/NoSupportedCFeaturesGenex-stderr.txt

@@ -0,0 +1,6 @@
+CMake Error in CMakeLists.txt:
+  No known features for C compiler
+
+  "[^"]*"
+
+  version *[.0-9]+\.

+ 5 - 0
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>)

+ 9 - 0
Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake

@@ -9,11 +9,20 @@ run_cmake(NotAFeature_OriginDebugTransitive)
 run_cmake(NotAFeature_OriginDebug_target_compile_features)
 run_cmake(NotAFeature_OriginDebug_target_compile_features)
 
 
 run_cmake(generate_feature_list)
 run_cmake(generate_feature_list)
+file(READ
+  "${RunCMake_BINARY_DIR}/generate_feature_list-build/c_features.txt"
+  C_FEATURES
+)
 file(READ
 file(READ
   "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt"
   "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt"
   CXX_FEATURES
   CXX_FEATURES
 )
 )
 
 
+if (NOT C_FEATURES)
+  run_cmake(NoSupportedCFeatures)
+  run_cmake(NoSupportedCFeaturesGenex)
+endif()
+
 if (NOT CXX_FEATURES)
 if (NOT CXX_FEATURES)
   run_cmake(NoSupportedCxxFeatures)
   run_cmake(NoSupportedCxxFeatures)
   run_cmake(NoSupportedCxxFeaturesGenex)
   run_cmake(NoSupportedCxxFeaturesGenex)

+ 7 - 0
Tests/RunCMake/CompileFeatures/empty.c

@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int empty()
+{
+  return 0;
+}

+ 6 - 0
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"
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_features.txt"
   "${CMAKE_CXX_COMPILE_FEATURES}"
   "${CMAKE_CXX_COMPILE_FEATURES}"
 )
 )

+ 1 - 1
Tests/RunCMake/Configure/FailCopyFileABI-stdout.txt

@@ -1,4 +1,4 @@
 -- Detecting C compiler ABI info
 -- Detecting C compiler ABI info
--- Detecting C compiler ABI info - failed
+-- Detecting C compiler ABI info - failed.*
 -- Configuring done
 -- Configuring done
 -- Generating done
 -- Generating done

+ 2 - 0
Tests/RunCMake/target_compile_features/RunCMakeTest.cmake

@@ -9,3 +9,5 @@ run_cmake(imported_target)
 run_cmake(no_target)
 run_cmake(no_target)
 run_cmake(not_a_cxx_feature)
 run_cmake(not_a_cxx_feature)
 run_cmake(no_matching_cxx_feature)
 run_cmake(no_matching_cxx_feature)
+run_cmake(not_a_c_feature)
+run_cmake(no_matching_c_feature)

+ 7 - 0
Tests/RunCMake/target_compile_features/empty.c

@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int empty()
+{
+  return 0;
+}

+ 1 - 0
Tests/RunCMake/target_compile_features/no_matching_c_feature-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
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\)

+ 15 - 0
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
+)

+ 1 - 0
Tests/RunCMake/target_compile_features/not_a_c_feature-result.txt

@@ -0,0 +1 @@
+1

+ 5 - 0
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\)

+ 6 - 0
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
+)

+ 10 - 0
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_COMPILER_IS_GNUCXX == "${CMAKE_COMPILER_IS_GNUCXX}"
 CMAKE_C_COMPILER_ID == "${CMAKE_C_COMPILER_ID}"
 CMAKE_C_COMPILER_ID == "${CMAKE_C_COMPILER_ID}"
 CMAKE_C_COMPILER_VERSION == "${CMAKE_C_COMPILER_VERSION}"
 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_ID == "${CMAKE_CXX_COMPILER_ID}"
 CMAKE_CXX_COMPILER_VERSION == "${CMAKE_CXX_COMPILER_VERSION}"
 CMAKE_CXX_COMPILER_VERSION == "${CMAKE_CXX_COMPILER_VERSION}"
 CMAKE_CXX98_STANDARD_COMPILE_OPTION == "${CMAKE_CXX98_STANDARD_COMPILE_OPTION}"
 CMAKE_CXX98_STANDARD_COMPILE_OPTION == "${CMAKE_CXX98_STANDARD_COMPILE_OPTION}"