浏览代码

Merge topic 'target_compile_features'

9eaf3755 Export: Populate INTERFACE_COMPILE_FEATURES property.
8ed59fc2 Add target_compile_features command.
4e6ca504 cmTargetPropCommandBase: Change the interface to return bool.
5412dede cmTarget: Transitively evaluate compiler features.
baff4434 cmTarget: Allow populating COMPILE_FEATURES using generator expressions.
f97bf437 Features: Add cxx_auto_type.
03355d6b cmTarget: Add COMPILE_FEATURES target property.
faeddf64 project: Add infrastructure for recording CXX compiler features
913394af cmTarget: Add CXX_STANDARD and CXX_EXTENSION target properties.
8238a6cd Add some COMPILE_OPTIONS for specifying C++ dialect.
892243fc Tests: Require CMake 3.0 for the SystemInformation test.
59b5fdd3 Don't load Clang-CXX from AppleClang-CXX.
Brad King 11 年之前
父节点
当前提交
b56a9ae7f1
共有 100 个文件被更改,包括 1127 次插入20 次删除
  1. 30 0
      Help/command/target_compile_features.rst
  2. 1 0
      Help/manual/cmake-commands.7.rst
  3. 4 0
      Help/manual/cmake-properties.7.rst
  4. 4 0
      Help/manual/cmake-variables.7.rst
  5. 11 0
      Help/prop_tgt/COMPILE_FEATURES.rst
  6. 8 0
      Help/prop_tgt/CXX_EXTENSIONS.rst
  7. 14 0
      Help/prop_tgt/CXX_STANDARD.rst
  8. 14 0
      Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst
  9. 18 0
      Help/release/dev/compile-language-features.rst
  10. 8 0
      Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst
  11. 8 0
      Help/variable/CMAKE_CXX_EXTENSIONS.rst
  12. 18 0
      Help/variable/CMAKE_CXX_KNOWN_FEATURES.rst
  13. 8 0
      Help/variable/CMAKE_CXX_STANDARD.rst
  14. 1 1
      Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst
  15. 3 0
      Modules/CMakeCXXCompiler.cmake.in
  16. 43 0
      Modules/CMakeDetermineCompileFeatures.cmake
  17. 3 0
      Modules/CMakeTestCXXCompiler.cmake
  18. 6 1
      Modules/Compiler/AppleClang-CXX.cmake
  19. 18 0
      Modules/Compiler/Clang-CXX.cmake
  20. 8 0
      Modules/Compiler/GNU-CXX-FeatureTests.cmake
  21. 25 0
      Modules/Compiler/GNU-CXX.cmake
  22. 57 0
      Modules/Internal/FeatureTesting.cmake
  23. 1 0
      Source/CMakeLists.txt
  24. 3 0
      Source/cmExportBuildFileGenerator.cxx
  25. 4 0
      Source/cmExportInstallFileGenerator.cxx
  26. 2 1
      Source/cmGeneratorExpressionDAGChecker.h
  27. 39 0
      Source/cmLocalGenerator.cxx
  28. 2 0
      Source/cmLocalGenerator.h
  29. 133 0
      Source/cmMakefile.cxx
  30. 4 0
      Source/cmMakefile.h
  31. 159 0
      Source/cmTarget.cxx
  32. 3 0
      Source/cmTarget.h
  33. 2 1
      Source/cmTargetCompileDefinitionsCommand.cxx
  34. 1 1
      Source/cmTargetCompileDefinitionsCommand.h
  35. 70 0
      Source/cmTargetCompileFeaturesCommand.cxx
  36. 41 0
      Source/cmTargetCompileFeaturesCommand.h
  37. 2 1
      Source/cmTargetCompileOptionsCommand.cxx
  38. 1 1
      Source/cmTargetCompileOptionsCommand.h
  39. 2 1
      Source/cmTargetIncludeDirectoriesCommand.cxx
  40. 1 1
      Source/cmTargetIncludeDirectoriesCommand.h
  41. 8 6
      Source/cmTargetPropCommandBase.cxx
  42. 2 2
      Source/cmTargetPropCommandBase.h
  43. 2 1
      Source/cmTargetSourcesCommand.cxx
  44. 1 1
      Source/cmTargetSourcesCommand.h
  45. 17 0
      Tests/CMakeCommands/target_compile_features/CMakeLists.txt
  46. 5 0
      Tests/CMakeCommands/target_compile_features/dummy.cpp
  47. 6 0
      Tests/CMakeCommands/target_compile_features/lib_auto_type.cpp
  48. 8 0
      Tests/CMakeCommands/target_compile_features/lib_auto_type.h
  49. 7 0
      Tests/CMakeCommands/target_compile_features/lib_user.cpp
  50. 6 0
      Tests/CMakeCommands/target_compile_features/main.cpp
  51. 18 0
      Tests/CMakeLists.txt
  52. 36 0
      Tests/CompileFeatures/CMakeLists.txt
  53. 5 0
      Tests/CompileFeatures/cxx_auto_type.cpp
  54. 6 0
      Tests/CompileFeatures/main.cpp
  55. 14 0
      Tests/CxxDialect/CMakeLists.txt
  56. 10 0
      Tests/CxxDialect/use_constexpr.cxx
  57. 11 0
      Tests/CxxDialect/use_constexpr_and_typeof.cxx
  58. 6 0
      Tests/CxxDialect/use_typeof.cxx
  59. 4 1
      Tests/ExportImport/Export/Interface/CMakeLists.txt
  60. 1 0
      Tests/ExportImport/Import/CMakeLists.txt
  61. 17 0
      Tests/ExportImport/Import/Interface/CMakeLists.txt
  62. 5 0
      Tests/RunCMake/CMakeLists.txt
  63. 3 0
      Tests/RunCMake/CompileFeatures/CMakeLists.txt
  64. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeature-result.txt
  65. 2 0
      Tests/RunCMake/CompileFeatures/NotAFeature-stderr.txt
  66. 3 0
      Tests/RunCMake/CompileFeatures/NotAFeature.cmake
  67. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeatureGenex-result.txt
  68. 2 0
      Tests/RunCMake/CompileFeatures/NotAFeatureGenex-stderr.txt
  69. 3 0
      Tests/RunCMake/CompileFeatures/NotAFeatureGenex.cmake
  70. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-result.txt
  71. 2 0
      Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt
  72. 6 0
      Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake
  73. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-result.txt
  74. 11 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt
  75. 4 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake
  76. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-result.txt
  77. 11 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt
  78. 4 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake
  79. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-result.txt
  80. 11 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt
  81. 6 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake
  82. 1 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug_target_compile_features-result.txt
  83. 5 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug_target_compile_features-stderr.txt
  84. 4 0
      Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug_target_compile_features.cmake
  85. 9 0
      Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake
  86. 7 0
      Tests/RunCMake/CompileFeatures/empty.cpp
  87. 3 0
      Tests/RunCMake/target_compile_features/CMakeLists.txt
  88. 11 0
      Tests/RunCMake/target_compile_features/RunCMakeTest.cmake
  89. 1 0
      Tests/RunCMake/target_compile_features/alias_target-result.txt
  90. 4 0
      Tests/RunCMake/target_compile_features/alias_target-stderr.txt
  91. 4 0
      Tests/RunCMake/target_compile_features/alias_target.cmake
  92. 7 0
      Tests/RunCMake/target_compile_features/empty.cpp
  93. 1 0
      Tests/RunCMake/target_compile_features/imported_target-result.txt
  94. 4 0
      Tests/RunCMake/target_compile_features/imported_target-stderr.txt
  95. 3 0
      Tests/RunCMake/target_compile_features/imported_target.cmake
  96. 1 0
      Tests/RunCMake/target_compile_features/invalid_args-result.txt
  97. 4 0
      Tests/RunCMake/target_compile_features/invalid_args-stderr.txt
  98. 3 0
      Tests/RunCMake/target_compile_features/invalid_args.cmake
  99. 1 0
      Tests/RunCMake/target_compile_features/invalid_args_on_interface-result.txt
  100. 5 0
      Tests/RunCMake/target_compile_features/invalid_args_on_interface-stderr.txt

+ 30 - 0
Help/command/target_compile_features.rst

@@ -0,0 +1,30 @@
+target_compile_features
+-----------------------
+
+Add expected compiler features to a target.
+
+::
+
+  target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
+
+Specify compiler features required when compiling a given target.  If the
+feature is not listed in the :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.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the features.  ``PRIVATE`` and ``PUBLIC`` items will
+populate the :prop_tgt:`COMPILE_FEATURES` property of ``<target>``.
+``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_COMPILE_FEATURES` property of ``<target>``.  Repeated
+calls for the same ``<target>`` append items.
+
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be
+an ``IMPORTED`` target.
+
+Arguments to ``target_compile_features`` may use "generator expressions"
+with the syntax ``$<...>``.
+See the :manual:`cmake-generator-expressions(7)` manual for available
+expressions.

+ 1 - 0
Help/manual/cmake-commands.7.rst

@@ -91,6 +91,7 @@ These commands may be used freely in CMake projects.
    /command/source_group
    /command/source_group
    /command/string
    /command/string
    /command/target_compile_definitions
    /command/target_compile_definitions
+   /command/target_compile_features
    /command/target_compile_options
    /command/target_compile_options
    /command/target_include_directories
    /command/target_include_directories
    /command/target_link_libraries
    /command/target_link_libraries

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

@@ -98,6 +98,7 @@ Properties on Targets
    /prop_tgt/COMPATIBLE_INTERFACE_STRING
    /prop_tgt/COMPATIBLE_INTERFACE_STRING
    /prop_tgt/COMPILE_DEFINITIONS_CONFIG
    /prop_tgt/COMPILE_DEFINITIONS_CONFIG
    /prop_tgt/COMPILE_DEFINITIONS
    /prop_tgt/COMPILE_DEFINITIONS
+   /prop_tgt/COMPILE_FEATURES
    /prop_tgt/COMPILE_FLAGS
    /prop_tgt/COMPILE_FLAGS
    /prop_tgt/COMPILE_OPTIONS
    /prop_tgt/COMPILE_OPTIONS
    /prop_tgt/COMPILE_PDB_NAME
    /prop_tgt/COMPILE_PDB_NAME
@@ -106,6 +107,8 @@ Properties on Targets
    /prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
    /prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG
    /prop_tgt/CONFIG_OUTPUT_NAME
    /prop_tgt/CONFIG_OUTPUT_NAME
    /prop_tgt/CONFIG_POSTFIX
    /prop_tgt/CONFIG_POSTFIX
+   /prop_tgt/CXX_STANDARD
+   /prop_tgt/CXX_EXTENSIONS
    /prop_tgt/DEBUG_POSTFIX
    /prop_tgt/DEBUG_POSTFIX
    /prop_tgt/DEFINE_SYMBOL
    /prop_tgt/DEFINE_SYMBOL
    /prop_tgt/EchoString
    /prop_tgt/EchoString
@@ -148,6 +151,7 @@ Properties on Targets
    /prop_tgt/INSTALL_RPATH_USE_LINK_PATH
    /prop_tgt/INSTALL_RPATH_USE_LINK_PATH
    /prop_tgt/INTERFACE_AUTOUIC_OPTIONS
    /prop_tgt/INTERFACE_AUTOUIC_OPTIONS
    /prop_tgt/INTERFACE_COMPILE_DEFINITIONS
    /prop_tgt/INTERFACE_COMPILE_DEFINITIONS
+   /prop_tgt/INTERFACE_COMPILE_FEATURES
    /prop_tgt/INTERFACE_COMPILE_OPTIONS
    /prop_tgt/INTERFACE_COMPILE_OPTIONS
    /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
    /prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
    /prop_tgt/INTERFACE_LINK_LIBRARIES
    /prop_tgt/INTERFACE_LINK_LIBRARIES

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

@@ -257,6 +257,10 @@ Variables for Languages
    :maxdepth: 1
    :maxdepth: 1
 
 
    /variable/CMAKE_COMPILER_IS_GNULANG
    /variable/CMAKE_COMPILER_IS_GNULANG
+   /variable/CMAKE_CXX_COMPILE_FEATURES
+   /variable/CMAKE_CXX_KNOWN_FEATURES
+   /variable/CMAKE_CXX_STANDARD
+   /variable/CMAKE_CXX_EXTENSIONS
    /variable/CMAKE_Fortran_MODDIR_DEFAULT
    /variable/CMAKE_Fortran_MODDIR_DEFAULT
    /variable/CMAKE_Fortran_MODDIR_FLAG
    /variable/CMAKE_Fortran_MODDIR_FLAG
    /variable/CMAKE_Fortran_MODOUT_FLAG
    /variable/CMAKE_Fortran_MODOUT_FLAG

+ 11 - 0
Help/prop_tgt/COMPILE_FEATURES.rst

@@ -0,0 +1,11 @@
+COMPILE_FEATURES
+----------------
+
+Compiler features enabled for this target.
+
+The list of features in this property are a subset of the features listed
+in the :variable:`CMAKE_CXX_COMPILE_FEATURES` variable.
+
+Contents of ``COMPILE_FEATURES`` may use "generator expressions" with the
+syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)` manual for
+available expressions.

+ 8 - 0
Help/prop_tgt/CXX_EXTENSIONS.rst

@@ -0,0 +1,8 @@
+CXX_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=gnu++11`` instead of ``-std=c++11`` to the compile line.

+ 14 - 0
Help/prop_tgt/CXX_STANDARD.rst

@@ -0,0 +1,14 @@
+CXX_STANDARD
+------------
+
+The C++ standard whose features are required to build this target.
+
+This property specifies the C++ standard whose features are required
+to build this target.  For some compilers, this results in adding a
+flag such as ``-std=c++11`` to the compile line.
+
+Supported values are ``98`` and ``11``.
+
+This property is initialized by the value of
+the :variable:`CMAKE_CXX_STANDARD` variable if it is set when a target
+is created.

+ 14 - 0
Help/prop_tgt/INTERFACE_COMPILE_FEATURES.rst

@@ -0,0 +1,14 @@
+INTERFACE_COMPILE_FEATURES
+--------------------------
+
+List of public compile requirements for a library.
+
+Targets may populate this property to publish the compiler features
+required to compile against the headers for the target.  Consuming
+targets can add entries to their own :prop_tgt:`COMPILE_FEATURES`
+property such as ``$<TARGET_PROPERTY:foo,INTERFACE_COMPILE_FEATURES>``
+to require the features specified in the interface of ``foo``.
+
+Contents of ``INTERFACE_COMPILE_FEATURES`` may use "generator expressions"
+with the syntax ``$<...>``.  See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions.

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

@@ -0,0 +1,18 @@
+target-language-features
+------------------------
+
+* New :prop_tgt:`CXX_STANDARD` and :prop_tgt:`CXX_EXTENSIONS` target
+  properties may specify values which CMake uses to compute required
+  compile options such as ``-std=c++11`` or ``-std=gnu++11``. The
+  :variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_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
+  the target, and to add any necessary compile flags to support language
+  features.
+
+* New :command:`target_compile_features` command allows populating the
+  :prop_tgt:`COMPILE_FEATURES` target property, just like any other
+  build variable.

+ 8 - 0
Help/variable/CMAKE_CXX_COMPILE_FEATURES.rst

@@ -0,0 +1,8 @@
+CMAKE_CXX_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 :variable:`CMAKE_CXX_KNOWN_FEATURES`
+variable.

+ 8 - 0
Help/variable/CMAKE_CXX_EXTENSIONS.rst

@@ -0,0 +1,8 @@
+CMAKE_CXX_EXTENSIONS
+--------------------
+
+Default value for ``CXX_EXTENSIONS`` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CXX_EXTENSIONS`
+property on all targets.  See that target property for additional
+information.

+ 18 - 0
Help/variable/CMAKE_CXX_KNOWN_FEATURES.rst

@@ -0,0 +1,18 @@
+CMAKE_CXX_KNOWN_FEATURES
+------------------------
+
+List of C++ features known to this version of CMake.
+
+The features listed in this variable 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_CXX_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:
+
+``cxx_auto_type``
+  Automatic type deduction, as defined in N1984_.
+
+  .. _N1984: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf

+ 8 - 0
Help/variable/CMAKE_CXX_STANDARD.rst

@@ -0,0 +1,8 @@
+CMAKE_CXX_STANDARD
+------------------
+
+Default value for ``CXX_STANDARD`` property of targets.
+
+This variable is used to initialize the :prop_tgt:`CXX_STANDARD`
+property on all targets.  See that target property for additional
+information.

+ 1 - 1
Help/variable/CMAKE_DEBUG_TARGET_PROPERTIES.rst

@@ -7,7 +7,7 @@ This variable can be populated with a list of properties to generate
 debug output for when evaluating target properties.  Currently it can
 debug output for when evaluating target properties.  Currently it can
 only be used when evaluating the :prop_tgt:`INCLUDE_DIRECTORIES`,
 only be used when evaluating the :prop_tgt:`INCLUDE_DIRECTORIES`,
 :prop_tgt:`COMPILE_DEFINITIONS`, :prop_tgt:`COMPILE_OPTIONS`,
 :prop_tgt:`COMPILE_DEFINITIONS`, :prop_tgt:`COMPILE_OPTIONS`,
-:prop_tgt:`AUTOUIC_OPTIONS`, :prop_tgt:`SOURCES`,
+:prop_tgt:`AUTOUIC_OPTIONS`, :prop_tgt:`SOURCES`, :prop_tgt:`COMPILE_FEATURES`,
 :prop_tgt:`POSITION_INDEPENDENT_CODE` target properties and any other property
 :prop_tgt:`POSITION_INDEPENDENT_CODE` target properties and any other property
 listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other ``COMPATIBLE_INTERFACE_``
 listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other ``COMPATIBLE_INTERFACE_``
 properties.  It outputs an origin for each entry in the target property.
 properties.  It outputs an origin for each entry in the target property.

+ 3 - 0
Modules/CMakeCXXCompiler.cmake.in

@@ -2,6 +2,9 @@ set(CMAKE_CXX_COMPILER "@CMAKE_CXX_COMPILER@")
 set(CMAKE_CXX_COMPILER_ARG1 "@CMAKE_CXX_COMPILER_ARG1@")
 set(CMAKE_CXX_COMPILER_ARG1 "@CMAKE_CXX_COMPILER_ARG1@")
 set(CMAKE_CXX_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@")
 set(CMAKE_CXX_COMPILER_ID "@CMAKE_CXX_COMPILER_ID@")
 set(CMAKE_CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@")
 set(CMAKE_CXX_COMPILER_VERSION "@CMAKE_CXX_COMPILER_VERSION@")
+set(CMAKE_CXX_COMPILE_FEATURES "@CMAKE_CXX_COMPILE_FEATURES@")
+set(CMAKE_CXX11_COMPILE_FEATURES "@CMAKE_CXX11_COMPILE_FEATURES@")
+
 set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@")
 set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@")
 set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@")
 set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@")
 set(CMAKE_CXX_SIMULATE_VERSION "@CMAKE_CXX_SIMULATE_VERSION@")
 set(CMAKE_CXX_SIMULATE_VERSION "@CMAKE_CXX_SIMULATE_VERSION@")

+ 43 - 0
Modules/CMakeDetermineCompileFeatures.cmake

@@ -0,0 +1,43 @@
+
+#=============================================================================
+# Copyright 2013 Stephen Kelly <[email protected]>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+function(cmake_determine_compile_features lang)
+
+  if(lang STREQUAL CXX AND COMMAND cmake_record_cxx_compile_features)
+    message(STATUS "Detecting ${lang} compile features")
+
+    set(CMAKE_CXX11_COMPILE_FEATURES)
+
+    include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake")
+
+    cmake_record_cxx_compile_features()
+
+    if(NOT _result EQUAL 0)
+      message(STATUS "Detecting ${lang} compile features - failed")
+      return()
+    endif()
+
+    if(NOT CMAKE_CXX_COMPILE_FEATURES)
+      set(CMAKE_CXX_COMPILE_FEATURES
+        ${CMAKE_CXX11_COMPILE_FEATURES}
+      )
+    endif()
+
+    set(CMAKE_CXX_COMPILE_FEATURES ${CMAKE_CXX_COMPILE_FEATURES} PARENT_SCOPE)
+    set(CMAKE_CXX11_COMPILE_FEATURES ${CMAKE_CXX11_COMPILE_FEATURES} PARENT_SCOPE)
+
+    message(STATUS "Detecting ${lang} compile features - done")
+  endif()
+
+endfunction()

+ 3 - 0
Modules/CMakeTestCXXCompiler.cmake

@@ -66,6 +66,9 @@ else()
   # Try to identify the ABI and configure it into CMakeCXXCompiler.cmake
   # Try to identify the ABI and configure it into CMakeCXXCompiler.cmake
   include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
   include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
   CMAKE_DETERMINE_COMPILER_ABI(CXX ${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp)
   CMAKE_DETERMINE_COMPILER_ABI(CXX ${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp)
+  # Try to identify the compiler features
+  include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake)
+  CMAKE_DETERMINE_COMPILE_FEATURES(CXX)
 
 
   # Re-configure to save learned information.
   # Re-configure to save learned information.
   configure_file(
   configure_file(

+ 6 - 1
Modules/Compiler/AppleClang-CXX.cmake

@@ -1 +1,6 @@
-include(Compiler/Clang-CXX)
+include(Compiler/Clang)
+__compiler_clang(CXX)
+
+if(NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+  set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
+endif()

+ 18 - 0
Modules/Compiler/Clang-CXX.cmake

@@ -4,3 +4,21 @@ __compiler_clang(CXX)
 if(NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
 if(NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
   set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
   set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
 endif()
 endif()
+
+cmake_policy(GET CMP0025 appleClangPolicy)
+if(NOT appleClangPolicy STREQUAL NEW)
+  return()
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
+  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.1)
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
+endif()

+ 8 - 0
Modules/Compiler/GNU-CXX-FeatureTests.cmake

@@ -0,0 +1,8 @@
+
+# Reference: http://gcc.gnu.org/projects/cxx0x.html
+
+set(_oldestSupported "(__GNUC__ * 100 + __GNUC_MINOR__) >= 408")
+# TODO: Should be supported by GNU 4.4
+set(GNU44_CXX11 "${_oldestSupported} && __cplusplus >= 201103L")
+set(_cmake_feature_test_cxx_auto_type "${GNU44_CXX11}")
+set(_oldestSupported)

+ 25 - 0
Modules/Compiler/GNU-CXX.cmake

@@ -10,3 +10,28 @@ else()
     set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
     set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
   endif()
   endif()
 endif()
 endif()
+
+if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.3)
+  set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
+  set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+endif()
+
+if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.3)
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
+endif()
+
+macro(cmake_record_cxx_compile_features)
+  macro(_get_gcc_features std_version list)
+    record_compiler_features(CXX "-std=${std_version}" ${list})
+  endmacro()
+
+  if (UNIX AND NOT APPLE AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+    _get_gcc_features(c++11 CMAKE_CXX11_COMPILE_FEATURES)
+  else()
+    set(_result 0)
+  endif()
+endmacro()

+ 57 - 0
Modules/Internal/FeatureTesting.cmake

@@ -0,0 +1,57 @@
+
+macro(record_compiler_features lang compile_flags feature_list)
+  include("${CMAKE_ROOT}/Modules/Compiler/${CMAKE_${lang}_COMPILER_ID}-${lang}-FeatureTests.cmake" OPTIONAL)
+
+  string(TOLOWER ${lang} lang_lc)
+  file(REMOVE "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin")
+  file(WRITE "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}" "
+  extern const char features[] = {\"\"\n")
+  foreach(feature ${CMAKE_${lang}_KNOWN_FEATURES})
+    if (_cmake_feature_test_${feature})
+      if (${_cmake_feature_test_${feature}} STREQUAL 1)
+        set(_feature_condition "\"1\" ")
+      else()
+        set(_feature_condition "#if ${_cmake_feature_test_${feature}}\n\"1\"\n#else\n\"0\"\n#endif\n")
+      endif()
+      file(APPEND "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}" "\"${lang}_FEATURE:\"\n${_feature_condition}\"${feature}\\n\"\n")
+    endif()
+  endforeach()
+  file(APPEND "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}"
+    "\n};\n\nint main(int, char **) { return 0; }\n")
+
+  try_compile(CMAKE_${lang}_FEATURE_TEST
+    ${CMAKE_BINARY_DIR} "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.${lang_lc}"
+    COMPILE_DEFINITIONS "${compile_flags}"
+    OUTPUT_VARIABLE _output
+    COPY_FILE "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin"
+    COPY_FILE_ERROR _copy_error
+    )
+  if(CMAKE_${lang}_FEATURE_TEST AND NOT _copy_error)
+    set(_result 0)
+  else()
+    set(_result 255)
+  endif()
+  unset(CMAKE_${lang}_FEATURE_TEST CACHE)
+
+  if (_result EQUAL 0)
+    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+      "\n\nDetecting ${lang} [${compile_flags}] compiler features compiled with the following output:\n${_output}\n\n")
+    if(EXISTS "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin")
+      file(STRINGS "${CMAKE_BINARY_DIR}/CMakeFiles/feature_tests.bin"
+        features REGEX "${lang}_FEATURE:.*")
+      foreach(info ${features})
+        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+          "    Feature record: ${info}\n")
+        string(REPLACE "${lang}_FEATURE:" "" info ${info})
+        string(SUBSTRING ${info} 0 1 has_feature)
+        if(has_feature)
+          string(REGEX REPLACE "^1" "" feature ${info})
+          list(APPEND ${feature_list} ${feature})
+        endif()
+      endforeach()
+    endif()
+  else()
+    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+      "Detecting ${lang} [${compile_flags}] compiler features failed to compile with the following output:\n${_output}\n${_copy_error}\n\n")
+  endif()
+endmacro()

+ 1 - 0
Source/CMakeLists.txt

@@ -346,6 +346,7 @@ foreach(command_file
     cmSourceGroupCommand
     cmSourceGroupCommand
     cmSubdirDependsCommand
     cmSubdirDependsCommand
     cmTargetCompileDefinitionsCommand
     cmTargetCompileDefinitionsCommand
+    cmTargetCompileFeaturesCommand
     cmTargetCompileOptionsCommand
     cmTargetCompileOptionsCommand
     cmTargetIncludeDirectoriesCommand
     cmTargetIncludeDirectoriesCommand
     cmTargetSourcesCommand
     cmTargetSourcesCommand

+ 3 - 0
Source/cmExportBuildFileGenerator.cxx

@@ -85,6 +85,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
     this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", te,
     this->PopulateInterfaceProperty("INTERFACE_AUTOUIC_OPTIONS", te,
                                     cmGeneratorExpression::BuildInterface,
                                     cmGeneratorExpression::BuildInterface,
                                     properties, missingTargets);
                                     properties, missingTargets);
+    this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES", te,
+                                    cmGeneratorExpression::BuildInterface,
+                                    properties, missingTargets);
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
     this->PopulateInterfaceProperty("INTERFACE_POSITION_INDEPENDENT_CODE",
                                   te, properties);
                                   te, properties);
     const bool newCMP0022Behavior =
     const bool newCMP0022Behavior =

+ 4 - 0
Source/cmExportInstallFileGenerator.cxx

@@ -149,6 +149,10 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
                                   te,
                                   te,
                                   cmGeneratorExpression::InstallInterface,
                                   cmGeneratorExpression::InstallInterface,
                                   properties, missingTargets);
                                   properties, missingTargets);
+    this->PopulateInterfaceProperty("INTERFACE_COMPILE_FEATURES",
+                                  te,
+                                  cmGeneratorExpression::InstallInterface,
+                                  properties, missingTargets);
 
 
     const bool newCMP0022Behavior =
     const bool newCMP0022Behavior =
                               te->GetPolicyStatusCMP0022() != cmPolicies::WARN
                               te->GetPolicyStatusCMP0022() != cmPolicies::WARN

+ 2 - 1
Source/cmGeneratorExpressionDAGChecker.h

@@ -26,7 +26,8 @@
   SELECT(F, EvaluatingCompileDefinitions,       COMPILE_DEFINITIONS) \
   SELECT(F, EvaluatingCompileDefinitions,       COMPILE_DEFINITIONS) \
   SELECT(F, EvaluatingCompileOptions,           COMPILE_OPTIONS) \
   SELECT(F, EvaluatingCompileOptions,           COMPILE_OPTIONS) \
   SELECT(F, EvaluatingAutoUicOptions,           AUTOUIC_OPTIONS) \
   SELECT(F, EvaluatingAutoUicOptions,           AUTOUIC_OPTIONS) \
-  SELECT(F, EvaluatingSources,                  SOURCES)
+  SELECT(F, EvaluatingSources,                  SOURCES) \
+  SELECT(F, EvaluatingCompileFeatures,          COMPILE_FEATURES)
 
 
 #define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
 #define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
   CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)
   CM_FOR_EACH_TRANSITIVE_PROPERTY_IMPL(F, CM_SELECT_BOTH)

+ 39 - 0
Source/cmLocalGenerator.cxx

@@ -1460,6 +1460,17 @@ void cmLocalGenerator::AddCompileOptions(
       this->AppendFlagEscape(flags, *i);
       this->AppendFlagEscape(flags, *i);
       }
       }
     }
     }
+  std::vector<std::string> features;
+  target->GetCompileFeatures(features, config);
+  for(std::vector<std::string>::const_iterator it = features.begin();
+      it != features.end(); ++it)
+    {
+     if (!this->Makefile->AddRequiredTargetFeature(target, *it))
+      {
+      return;
+      }
+    }
+  this->AddCompilerRequirementFlag(flags, target, lang);
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -2131,6 +2142,34 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags,
     }
     }
 }
 }
 
 
+//----------------------------------------------------------------------------
+void cmLocalGenerator::
+AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
+                           const std::string& lang)
+{
+  if (lang.empty())
+    {
+    return;
+    }
+  std::string stdProp = lang + "_STANDARD";
+  const char *standard = target->GetProperty(stdProp);
+  if (!standard)
+    {
+    return;
+    }
+  std::string extProp = lang + "_EXTENSIONS";
+  bool ext = target->GetPropertyAsBool(extProp);
+  std::string type = ext ? "EXTENSION" : "STANDARD";
+
+  std::string compile_option =
+            "CMAKE_" + lang + std::string(standard)
+                     + "_" + type + "_COMPILE_OPTION";
+  if (const char *opt = target->GetMakefile()->GetDefinition(compile_option))
+    {
+    this->AppendFlags(flags, opt);
+    }
+}
+
 static void AddVisibilityCompileOption(std::string &flags, cmTarget* target,
 static void AddVisibilityCompileOption(std::string &flags, cmTarget* target,
                                        cmLocalGenerator *lg,
                                        cmLocalGenerator *lg,
                                        const std::string& lang)
                                        const std::string& lang)

+ 2 - 0
Source/cmLocalGenerator.h

@@ -149,6 +149,8 @@ public:
                                 const std::string& lang);
                                 const std::string& lang);
   void AddConfigVariableFlags(std::string& flags, const std::string& var,
   void AddConfigVariableFlags(std::string& flags, const std::string& var,
                               const std::string& config);
                               const std::string& config);
+  void AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
+                                  const std::string& lang);
   ///! Append flags to a string.
   ///! Append flags to a string.
   virtual void AppendFlags(std::string& flags, const char* newFlags);
   virtual void AppendFlags(std::string& flags, const char* newFlags);
   virtual void AppendFlagEscape(std::string& flags,
   virtual void AppendFlagEscape(std::string& flags,

+ 133 - 0
Source/cmMakefile.cxx

@@ -41,6 +41,9 @@
 #include <ctype.h> // for isspace
 #include <ctype.h> // for isspace
 #include <assert.h>
 #include <assert.h>
 
 
+#define FOR_EACH_CXX_FEATURE(F) \
+  F(cxx_auto_type)
+
 class cmMakefile::Internals
 class cmMakefile::Internals
 {
 {
 public:
 public:
@@ -2451,6 +2454,12 @@ const char* cmMakefile::GetDefinition(const std::string& name) const
     {
     {
     this->Internal->VarUsageStack.top().insert(name);
     this->Internal->VarUsageStack.top().insert(name);
     }
     }
+  if (name == "CMAKE_CXX_KNOWN_FEATURES")
+    {
+#define STRING_LIST_ELEMENT(F) ";" #F
+    return FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT) + 1;
+#undef STRING_LIST_ELEMENT
+    }
   const char* def = this->Internal->VarStack.top().Get(name);
   const char* def = this->Internal->VarStack.top().Get(name);
   if(!def)
   if(!def)
     {
     {
@@ -4494,3 +4503,127 @@ void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
     pm[pid] = this->GetPolicyStatus(pid);
     pm[pid] = this->GetPolicyStatus(pid);
     }
     }
 }
 }
+
+#define FEATURE_STRING(F) , #F
+
+static const char * const CXX_FEATURES[] = {
+  0
+  FOR_EACH_CXX_FEATURE(FEATURE_STRING)
+};
+
+static const char * const CXX_STANDARDS[] = {
+    "98"
+  , "11"
+};
+
+//----------------------------------------------------------------------------
+bool cmMakefile::
+AddRequiredTargetFeature(cmTarget *target, const std::string& feature,
+                         std::string *error) const
+{
+  if (cmGeneratorExpression::Find(feature) != std::string::npos)
+    {
+    target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+    return true;
+    }
+  bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1,
+              cmArrayEnd(CXX_FEATURES), cmStrCmp(feature))
+              != cmArrayEnd(CXX_FEATURES);
+  if (!isCxxFeature)
+    {
+    cmOStringStream e;
+    if (error)
+      {
+      e << "specified";
+      }
+    else
+      {
+      e << "Specified";
+      }
+    e << " unknown feature \"" << feature << "\" for "
+      "target \"" << target->GetName() << "\".";
+    if (error)
+      {
+      *error = e.str();
+      }
+    else
+      {
+      this->IssueMessage(cmake::FATAL_ERROR, e.str());
+      }
+    return false;
+    }
+
+  std::string lang = "CXX";
+
+  const char* featuresKnown =
+    this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
+
+  if (!featuresKnown || !*featuresKnown)
+    {
+    // We know of no features for the compiler at all.
+    return true;
+    }
+
+  std::vector<std::string> availableFeatures;
+  cmSystemTools::ExpandListArgument(featuresKnown, availableFeatures);
+  if (std::find(availableFeatures.begin(),
+                availableFeatures.end(),
+                feature) == availableFeatures.end())
+    {
+    cmOStringStream e;
+    e << "The compiler feature \"" << feature
+      << "\" is not known to compiler\n\""
+      << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
+      << "\"\nversion "
+      << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
+    this->IssueMessage(cmake::FATAL_ERROR, e.str());
+    return false;
+    }
+
+  target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+
+  bool needCxx11 = false;
+
+  if (const char *propCxx11 =
+          this->GetDefinition("CMAKE_CXX11_COMPILE_FEATURES"))
+    {
+    std::vector<std::string> props;
+    cmSystemTools::ExpandListArgument(propCxx11, props);
+    needCxx11 = std::find(props.begin(), props.end(), feature) != props.end();
+    }
+
+  const char *existingCxxStandard = target->GetProperty("CXX_STANDARD");
+  if (existingCxxStandard)
+    {
+    if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
+                  cmStrCmp(existingCxxStandard)) == cmArrayEnd(CXX_STANDARDS))
+      {
+      cmOStringStream e;
+      e << "The CXX_STANDARD property on target \"" << target->GetName()
+        << "\" contained an invalid value: \"" << existingCxxStandard << "\".";
+      this->IssueMessage(cmake::FATAL_ERROR, e.str());
+      return false;
+      }
+    }
+  const char * const *existingCxxIt = existingCxxStandard
+                                    ? std::find_if(cmArrayBegin(CXX_STANDARDS),
+                                      cmArrayEnd(CXX_STANDARDS),
+                                      cmStrCmp(existingCxxStandard))
+                                    : cmArrayEnd(CXX_STANDARDS);
+
+  bool setCxx11 = needCxx11 && !existingCxxStandard;
+
+  if (needCxx11 && existingCxxStandard && existingCxxIt <
+                                    std::find_if(cmArrayBegin(CXX_STANDARDS),
+                                      cmArrayEnd(CXX_STANDARDS),
+                                      cmStrCmp("11")))
+    {
+    setCxx11 = true;
+    }
+
+  if (setCxx11)
+    {
+    target->SetProperty("CXX_STANDARD", "11");
+    }
+  return true;
+}

+ 4 - 0
Source/cmMakefile.h

@@ -885,6 +885,10 @@ public:
 
 
   bool PolicyOptionalWarningEnabled(std::string const& var);
   bool PolicyOptionalWarningEnabled(std::string const& var);
 
 
+  bool AddRequiredTargetFeature(cmTarget *target,
+                                const std::string& feature,
+                                std::string *error = 0) const;
+
 protected:
 protected:
   // add link libraries and directories to the target
   // add link libraries and directories to the target
   void AddGlobalLinkInformation(const std::string& name, cmTarget& target);
   void AddGlobalLinkInformation(const std::string& name, cmTarget& target);

+ 159 - 0
Source/cmTarget.cxx

@@ -153,6 +153,7 @@ public:
   };
   };
   std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
   std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
   std::vector<TargetPropertyEntry*> CompileOptionsEntries;
   std::vector<TargetPropertyEntry*> CompileOptionsEntries;
+  std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
   std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
   std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
   std::vector<TargetPropertyEntry*> SourceEntries;
   std::vector<TargetPropertyEntry*> SourceEntries;
   std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries;
   std::vector<cmValueWithOrigin> LinkImplementationPropertyEntries;
@@ -165,11 +166,14 @@ public:
                                 CachedLinkInterfaceCompileDefinitionsEntries;
                                 CachedLinkInterfaceCompileDefinitionsEntries;
   mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
   mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
                                 CachedLinkInterfaceSourcesEntries;
                                 CachedLinkInterfaceSourcesEntries;
+  mutable std::map<std::string, std::vector<TargetPropertyEntry*> >
+                                CachedLinkInterfaceCompileFeaturesEntries;
 
 
   mutable std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceIncludeDirectoriesDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceCompileDefinitionsDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceCompileOptionsDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceSourcesDone;
   mutable std::map<std::string, bool> CacheLinkInterfaceSourcesDone;
+  mutable std::map<std::string, bool> CacheLinkInterfaceCompileFeaturesDone;
 };
 };
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -204,6 +208,7 @@ cmTargetInternals::~cmTargetInternals()
 {
 {
   deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries);
   deleteAndClear(this->CachedLinkInterfaceIncludeDirectoriesEntries);
   deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries);
   deleteAndClear(this->CachedLinkInterfaceCompileOptionsEntries);
+  deleteAndClear(this->CachedLinkInterfaceCompileFeaturesEntries);
   deleteAndClear(this->CachedLinkInterfaceCompileDefinitionsEntries);
   deleteAndClear(this->CachedLinkInterfaceCompileDefinitionsEntries);
   deleteAndClear(this->CachedLinkInterfaceSourcesEntries);
   deleteAndClear(this->CachedLinkInterfaceSourcesEntries);
 }
 }
@@ -227,6 +232,7 @@ cmTarget::cmTarget()
   this->BuildInterfaceIncludesAppended = false;
   this->BuildInterfaceIncludesAppended = false;
   this->DebugIncludesDone = false;
   this->DebugIncludesDone = false;
   this->DebugCompileOptionsDone = false;
   this->DebugCompileOptionsDone = false;
+  this->DebugCompileFeaturesDone = false;
   this->DebugCompileDefinitionsDone = false;
   this->DebugCompileDefinitionsDone = false;
   this->DebugSourcesDone = false;
   this->DebugSourcesDone = false;
   this->LinkImplementationLanguageIsContextDependent = true;
   this->LinkImplementationLanguageIsContextDependent = true;
@@ -308,6 +314,8 @@ 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("CXX_STANDARD", 0);
+    this->SetPropertyDefault("CXX_EXTENSIONS", 0);
     }
     }
 
 
   // Collect the set of configuration types.
   // Collect the set of configuration types.
@@ -1803,6 +1811,17 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
                           new cmTargetInternals::TargetPropertyEntry(cge));
                           new cmTargetInternals::TargetPropertyEntry(cge));
     return;
     return;
     }
     }
+  if(prop == "COMPILE_FEATURES")
+    {
+    cmListFileBacktrace lfbt;
+    this->Makefile->GetBacktrace(lfbt);
+    cmGeneratorExpression ge(lfbt);
+    deleteAndClear(this->Internal->CompileFeaturesEntries);
+    cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value);
+    this->Internal->CompileFeaturesEntries.push_back(
+                          new cmTargetInternals::TargetPropertyEntry(cge));
+    return;
+    }
   if(prop == "COMPILE_DEFINITIONS")
   if(prop == "COMPILE_DEFINITIONS")
     {
     {
     cmListFileBacktrace lfbt;
     cmListFileBacktrace lfbt;
@@ -1893,6 +1912,15 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
               new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
               new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
     return;
     return;
     }
     }
+  if(prop == "COMPILE_FEATURES")
+    {
+    cmListFileBacktrace lfbt;
+    this->Makefile->GetBacktrace(lfbt);
+    cmGeneratorExpression ge(lfbt);
+    this->Internal->CompileFeaturesEntries.push_back(
+              new cmTargetInternals::TargetPropertyEntry(ge.Parse(value)));
+    return;
+    }
   if(prop == "COMPILE_DEFINITIONS")
   if(prop == "COMPILE_DEFINITIONS")
     {
     {
     cmListFileBacktrace lfbt;
     cmListFileBacktrace lfbt;
@@ -2676,6 +2704,118 @@ void cmTarget::GetCompileDefinitions(std::vector<std::string> &list,
     }
     }
 }
 }
 
 
+//----------------------------------------------------------------------------
+static void processCompileFeatures(cmTarget const* tgt,
+      const std::vector<cmTargetInternals::TargetPropertyEntry*> &entries,
+      std::vector<std::string> &options,
+      std::set<std::string> &uniqueOptions,
+      cmGeneratorExpressionDAGChecker *dagChecker,
+      const std::string& config, bool debugOptions)
+{
+  processCompileOptionsInternal(tgt, entries, options, uniqueOptions,
+                                dagChecker, config, debugOptions, "features");
+}
+
+//----------------------------------------------------------------------------
+void cmTarget::GetCompileFeatures(std::vector<std::string> &result,
+                                  const std::string& config) const
+{
+  std::set<std::string> uniqueFeatures;
+  cmListFileBacktrace lfbt;
+
+  cmGeneratorExpressionDAGChecker dagChecker(lfbt,
+                                             this->GetName(),
+                                             "COMPILE_FEATURES",
+                                             0, 0);
+
+  std::vector<std::string> debugProperties;
+  const char *debugProp =
+              this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+  if (debugProp)
+    {
+    cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+    }
+
+  bool debugFeatures = !this->DebugCompileFeaturesDone
+                    && std::find(debugProperties.begin(),
+                                 debugProperties.end(),
+                                 "COMPILE_FEATURES")
+                        != debugProperties.end();
+
+  if (this->Makefile->IsGeneratingBuildSystem())
+    {
+    this->DebugCompileFeaturesDone = true;
+    }
+
+  processCompileFeatures(this,
+                            this->Internal->CompileFeaturesEntries,
+                            result,
+                            uniqueFeatures,
+                            &dagChecker,
+                            config,
+                            debugFeatures);
+
+  if (!this->Internal->CacheLinkInterfaceCompileFeaturesDone[config])
+    {
+    for (std::vector<cmValueWithOrigin>::const_iterator
+        it = this->Internal->LinkImplementationPropertyEntries.begin(),
+        end = this->Internal->LinkImplementationPropertyEntries.end();
+        it != end; ++it)
+      {
+      if (!cmGeneratorExpression::IsValidTargetName(it->Value)
+          && cmGeneratorExpression::Find(it->Value) == std::string::npos)
+        {
+        continue;
+        }
+      {
+      cmGeneratorExpression ge(lfbt);
+      cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
+                                                        ge.Parse(it->Value);
+      std::string targetResult = cge->Evaluate(this->Makefile, config,
+                                        false, this, 0, 0);
+      if (!this->Makefile->FindTargetToUse(targetResult))
+        {
+        continue;
+        }
+      }
+      std::string featureGenex = "$<TARGET_PROPERTY:" +
+                              it->Value + ",INTERFACE_COMPILE_FEATURES>";
+      if (cmGeneratorExpression::Find(it->Value) != std::string::npos)
+        {
+        // Because it->Value is a generator expression, ensure that it
+        // evaluates to the non-empty string before being used in the
+        // TARGET_PROPERTY expression.
+        featureGenex = "$<$<BOOL:" + it->Value + ">:" + featureGenex + ">";
+        }
+      cmGeneratorExpression ge(it->Backtrace);
+      cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(
+                                                                featureGenex);
+
+      this->Internal
+        ->CachedLinkInterfaceCompileFeaturesEntries[config].push_back(
+                        new cmTargetInternals::TargetPropertyEntry(cge,
+                                                              it->Value));
+      }
+    }
+
+  processCompileFeatures(this,
+    this->Internal->CachedLinkInterfaceCompileFeaturesEntries[config],
+                            result,
+                            uniqueFeatures,
+                            &dagChecker,
+                            config,
+                            debugFeatures);
+
+  if (!this->Makefile->IsGeneratingBuildSystem())
+    {
+    deleteAndClear(this->Internal->CachedLinkInterfaceCompileFeaturesEntries);
+    }
+  else
+    {
+    this->Internal->CacheLinkInterfaceCompileFeaturesDone[config] = true;
+    }
+}
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 void cmTarget::MaybeInvalidatePropertyCache(const std::string& prop)
 void cmTarget::MaybeInvalidatePropertyCache(const std::string& prop)
 {
 {
@@ -3190,6 +3330,24 @@ const char *cmTarget::GetProperty(const std::string& prop,
       }
       }
     return output.c_str();
     return output.c_str();
     }
     }
+  if(prop == "COMPILE_FEATURES")
+    {
+    static std::string output;
+    output = "";
+    std::string sep;
+    typedef cmTargetInternals::TargetPropertyEntry
+                                TargetPropertyEntry;
+    for (std::vector<TargetPropertyEntry*>::const_iterator
+        it = this->Internal->CompileFeaturesEntries.begin(),
+        end = this->Internal->CompileFeaturesEntries.end();
+        it != end; ++it)
+      {
+      output += sep;
+      output += (*it)->ge->GetInput();
+      sep = ";";
+      }
+    return output.c_str();
+    }
   if(prop == "COMPILE_DEFINITIONS")
   if(prop == "COMPILE_DEFINITIONS")
     {
     {
     static std::string output;
     static std::string output;
@@ -6987,6 +7145,7 @@ cmTargetInternalPointer::~cmTargetInternalPointer()
 {
 {
   deleteAndClear(this->Pointer->IncludeDirectoriesEntries);
   deleteAndClear(this->Pointer->IncludeDirectoriesEntries);
   deleteAndClear(this->Pointer->CompileOptionsEntries);
   deleteAndClear(this->Pointer->CompileOptionsEntries);
+  deleteAndClear(this->Pointer->CompileFeaturesEntries);
   deleteAndClear(this->Pointer->CompileDefinitionsEntries);
   deleteAndClear(this->Pointer->CompileDefinitionsEntries);
   deleteAndClear(this->Pointer->SourceEntries);
   deleteAndClear(this->Pointer->SourceEntries);
   delete this->Pointer;
   delete this->Pointer;

+ 3 - 0
Source/cmTarget.h

@@ -549,6 +549,8 @@ public:
                          const std::string& config) const;
                          const std::string& config) const;
   void GetAutoUicOptions(std::vector<std::string> &result,
   void GetAutoUicOptions(std::vector<std::string> &result,
                          const std::string& config) const;
                          const std::string& config) const;
+  void GetCompileFeatures(std::vector<std::string> &features,
+                          const std::string& config) const;
 
 
   bool IsNullImpliedByLinkLibraries(const std::string &p) const;
   bool IsNullImpliedByLinkLibraries(const std::string &p) const;
   bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
   bool IsLinkInterfaceDependentBoolProperty(const std::string &p,
@@ -715,6 +717,7 @@ private:
   mutable bool DebugCompileOptionsDone;
   mutable bool DebugCompileOptionsDone;
   mutable bool DebugCompileDefinitionsDone;
   mutable bool DebugCompileDefinitionsDone;
   mutable bool DebugSourcesDone;
   mutable bool DebugSourcesDone;
+  mutable bool DebugCompileFeaturesDone;
   mutable std::set<std::string> LinkImplicitNullProperties;
   mutable std::set<std::string> LinkImplicitNullProperties;
   bool BuildInterfaceIncludesAppended;
   bool BuildInterfaceIncludesAppended;
 
 

+ 2 - 1
Source/cmTargetCompileDefinitionsCommand.cxx

@@ -58,9 +58,10 @@ std::string cmTargetCompileDefinitionsCommand
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
-void cmTargetCompileDefinitionsCommand
+bool cmTargetCompileDefinitionsCommand
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
                                    bool, bool)
                                    bool, bool)
 {
 {
   tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str());
   tgt->AppendProperty("COMPILE_DEFINITIONS", this->Join(content).c_str());
+  return true;
 }
 }

+ 1 - 1
Source/cmTargetCompileDefinitionsCommand.h

@@ -44,7 +44,7 @@ private:
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleMissingTarget(const std::string &name);
   virtual void HandleMissingTarget(const std::string &name);
 
 
-  virtual void HandleDirectContent(cmTarget *tgt,
+  virtual bool HandleDirectContent(cmTarget *tgt,
                                    const std::vector<std::string> &content,
                                    const std::vector<std::string> &content,
                                    bool prepend, bool system);
                                    bool prepend, bool system);
   virtual std::string Join(const std::vector<std::string> &content);
   virtual std::string Join(const std::vector<std::string> &content);

+ 70 - 0
Source/cmTargetCompileFeaturesCommand.cxx

@@ -0,0 +1,70 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Stephen Kelly <[email protected]>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmTargetCompileFeaturesCommand.h"
+
+bool cmTargetCompileFeaturesCommand::InitialPass(
+  std::vector<std::string> const& args,
+  cmExecutionStatus &)
+{
+  return this->HandleArguments(args, "COMPILE_FEATURES", NO_FLAGS);
+}
+
+void cmTargetCompileFeaturesCommand
+::HandleImportedTarget(const std::string &tgt)
+{
+  cmOStringStream e;
+  e << "Cannot specify compile features for imported target \""
+    << tgt << "\".";
+  this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+void cmTargetCompileFeaturesCommand
+::HandleMissingTarget(const std::string &name)
+{
+  cmOStringStream e;
+  e << "Cannot specify compile features for target \"" << name << "\" "
+       "which is not built by this project.";
+  this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+//----------------------------------------------------------------------------
+std::string cmTargetCompileFeaturesCommand
+::Join(const std::vector<std::string> &content)
+{
+  std::string defs;
+  std::string sep;
+  for(std::vector<std::string>::const_iterator it = content.begin();
+    it != content.end(); ++it)
+    {
+    defs += sep + *it;
+    sep = ";";
+    }
+  return defs;
+}
+
+//----------------------------------------------------------------------------
+bool cmTargetCompileFeaturesCommand
+::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
+                                   bool, bool)
+{
+  for(std::vector<std::string>::const_iterator it = content.begin();
+    it != content.end(); ++it)
+    {
+    std::string error;
+    if(!this->Makefile->AddRequiredTargetFeature(tgt, *it, &error))
+      {
+      this->SetError(error);
+      return false;
+      }
+    }
+  return true;
+}

+ 41 - 0
Source/cmTargetCompileFeaturesCommand.h

@@ -0,0 +1,41 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Stephen Kelly <[email protected]>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmTargetCompileFeaturesCommand_h
+#define cmTargetCompileFeaturesCommand_h
+
+#include "cmTargetPropCommandBase.h"
+
+class cmTargetCompileFeaturesCommand : public cmTargetPropCommandBase
+{
+  virtual cmCommand* Clone()
+    {
+    return new cmTargetCompileFeaturesCommand;
+    }
+
+  virtual bool InitialPass(std::vector<std::string> const& args,
+                           cmExecutionStatus &status);
+
+  virtual std::string GetName() const { return "target_compile_features";}
+
+  cmTypeMacro(cmTargetCompileFeaturesCommand, cmTargetPropCommandBase);
+
+private:
+  virtual void HandleImportedTarget(const std::string &tgt);
+  virtual void HandleMissingTarget(const std::string &name);
+
+  virtual bool HandleDirectContent(cmTarget *tgt,
+                                   const std::vector<std::string> &content,
+                                   bool prepend, bool system);
+  virtual std::string Join(const std::vector<std::string> &content);
+};
+
+#endif

+ 2 - 1
Source/cmTargetCompileOptionsCommand.cxx

@@ -51,7 +51,7 @@ std::string cmTargetCompileOptionsCommand
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
-void cmTargetCompileOptionsCommand
+bool cmTargetCompileOptionsCommand
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
                                    bool, bool)
                                    bool, bool)
 {
 {
@@ -59,4 +59,5 @@ void cmTargetCompileOptionsCommand
   this->Makefile->GetBacktrace(lfbt);
   this->Makefile->GetBacktrace(lfbt);
   cmValueWithOrigin entry(this->Join(content), lfbt);
   cmValueWithOrigin entry(this->Join(content), lfbt);
   tgt->InsertCompileOption(entry);
   tgt->InsertCompileOption(entry);
+  return true;
 }
 }

+ 1 - 1
Source/cmTargetCompileOptionsCommand.h

@@ -44,7 +44,7 @@ private:
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleMissingTarget(const std::string &name);
   virtual void HandleMissingTarget(const std::string &name);
 
 
-  virtual void HandleDirectContent(cmTarget *tgt,
+  virtual bool HandleDirectContent(cmTarget *tgt,
                                    const std::vector<std::string> &content,
                                    const std::vector<std::string> &content,
                                    bool prepend, bool system);
                                    bool prepend, bool system);
   virtual std::string Join(const std::vector<std::string> &content);
   virtual std::string Join(const std::vector<std::string> &content);

+ 2 - 1
Source/cmTargetIncludeDirectoriesCommand.cxx

@@ -66,7 +66,7 @@ std::string cmTargetIncludeDirectoriesCommand
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
-void cmTargetIncludeDirectoriesCommand
+bool cmTargetIncludeDirectoriesCommand
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
                       bool prepend, bool system)
                       bool prepend, bool system)
 {
 {
@@ -78,6 +78,7 @@ void cmTargetIncludeDirectoriesCommand
     {
     {
     tgt->AddSystemIncludeDirectories(content);
     tgt->AddSystemIncludeDirectories(content);
     }
     }
+  return true;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------

+ 1 - 1
Source/cmTargetIncludeDirectoriesCommand.h

@@ -45,7 +45,7 @@ private:
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleMissingTarget(const std::string &name);
   virtual void HandleMissingTarget(const std::string &name);
 
 
-  virtual void HandleDirectContent(cmTarget *tgt,
+  virtual bool HandleDirectContent(cmTarget *tgt,
                                    const std::vector<std::string> &content,
                                    const std::vector<std::string> &content,
                                    bool prepend, bool system);
                                    bool prepend, bool system);
   virtual void HandleInterfaceContent(cmTarget *tgt,
   virtual void HandleInterfaceContent(cmTarget *tgt,

+ 8 - 6
Source/cmTargetPropCommandBase.cxx

@@ -132,29 +132,31 @@ bool cmTargetPropCommandBase
         || args[i] == "PRIVATE"
         || args[i] == "PRIVATE"
         || args[i] == "INTERFACE" )
         || args[i] == "INTERFACE" )
       {
       {
-      this->PopulateTargetProperies(scope, content, prepend, system);
-      return true;
+      return this->PopulateTargetProperies(scope, content, prepend, system);
       }
       }
     content.push_back(args[i]);
     content.push_back(args[i]);
     }
     }
-  this->PopulateTargetProperies(scope, content, prepend, system);
-  return true;
+  return this->PopulateTargetProperies(scope, content, prepend, system);
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
-void cmTargetPropCommandBase
+bool cmTargetPropCommandBase
 ::PopulateTargetProperies(const std::string &scope,
 ::PopulateTargetProperies(const std::string &scope,
                           const std::vector<std::string> &content,
                           const std::vector<std::string> &content,
                           bool prepend, bool system)
                           bool prepend, bool system)
 {
 {
   if (scope == "PRIVATE" || scope == "PUBLIC")
   if (scope == "PRIVATE" || scope == "PUBLIC")
     {
     {
-    this->HandleDirectContent(this->Target, content, prepend, system);
+    if (!this->HandleDirectContent(this->Target, content, prepend, system))
+      {
+      return false;
+      }
     }
     }
   if (scope == "INTERFACE" || scope == "PUBLIC")
   if (scope == "INTERFACE" || scope == "PUBLIC")
     {
     {
     this->HandleInterfaceContent(this->Target, content, prepend, system);
     this->HandleInterfaceContent(this->Target, content, prepend, system);
     }
     }
+  return true;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------

+ 2 - 2
Source/cmTargetPropCommandBase.h

@@ -44,7 +44,7 @@ private:
   virtual void HandleImportedTarget(const std::string &tgt) = 0;
   virtual void HandleImportedTarget(const std::string &tgt) = 0;
   virtual void HandleMissingTarget(const std::string &name) = 0;
   virtual void HandleMissingTarget(const std::string &name) = 0;
 
 
-  virtual void HandleDirectContent(cmTarget *tgt,
+  virtual bool HandleDirectContent(cmTarget *tgt,
                                    const std::vector<std::string> &content,
                                    const std::vector<std::string> &content,
                                    bool prepend, bool system) = 0;
                                    bool prepend, bool system) = 0;
 
 
@@ -52,7 +52,7 @@ private:
 
 
   bool ProcessContentArgs(std::vector<std::string> const& args,
   bool ProcessContentArgs(std::vector<std::string> const& args,
                           unsigned int &argIndex, bool prepend, bool system);
                           unsigned int &argIndex, bool prepend, bool system);
-  void PopulateTargetProperies(const std::string &scope,
+  bool PopulateTargetProperies(const std::string &scope,
                                const std::vector<std::string> &content,
                                const std::vector<std::string> &content,
                                bool prepend, bool system);
                                bool prepend, bool system);
 };
 };

+ 2 - 1
Source/cmTargetSourcesCommand.cxx

@@ -56,9 +56,10 @@ std::string cmTargetSourcesCommand
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
-void cmTargetSourcesCommand
+bool cmTargetSourcesCommand
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
 ::HandleDirectContent(cmTarget *tgt, const std::vector<std::string> &content,
                       bool, bool)
                       bool, bool)
 {
 {
   tgt->AppendProperty("SOURCES", this->Join(content).c_str());
   tgt->AppendProperty("SOURCES", this->Join(content).c_str());
+  return true;
 }
 }

+ 1 - 1
Source/cmTargetSourcesCommand.h

@@ -45,7 +45,7 @@ private:
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleImportedTarget(const std::string &tgt);
   virtual void HandleMissingTarget(const std::string &name);
   virtual void HandleMissingTarget(const std::string &name);
 
 
-  virtual void HandleDirectContent(cmTarget *tgt,
+  virtual bool HandleDirectContent(cmTarget *tgt,
                                    const std::vector<std::string> &content,
                                    const std::vector<std::string> &content,
                                    bool prepend, bool system);
                                    bool prepend, bool system);
 
 

+ 17 - 0
Tests/CMakeCommands/target_compile_features/CMakeLists.txt

@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.0)
+project(target_compile_features)
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+add_executable(target_compile_features main.cpp)
+target_compile_features(target_compile_features
+  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)

+ 5 - 0
Tests/CMakeCommands/target_compile_features/dummy.cpp

@@ -0,0 +1,5 @@
+
+int main(int, char **)
+{
+  return 0;
+}

+ 6 - 0
Tests/CMakeCommands/target_compile_features/lib_auto_type.cpp

@@ -0,0 +1,6 @@
+
+int getAutoTypeImpl()
+{
+  auto i = 0;
+  return i;
+}

+ 8 - 0
Tests/CMakeCommands/target_compile_features/lib_auto_type.h

@@ -0,0 +1,8 @@
+
+int getAutoTypeImpl();
+
+int getAutoType()
+{
+  auto i = getAutoTypeImpl();
+  return i;
+}

+ 7 - 0
Tests/CMakeCommands/target_compile_features/lib_user.cpp

@@ -0,0 +1,7 @@
+
+#include "lib_auto_type.h"
+
+int main(int argc, char **argv)
+{
+  return getAutoType();
+}

+ 6 - 0
Tests/CMakeCommands/target_compile_features/main.cpp

@@ -0,0 +1,6 @@
+
+int main(int, char **)
+{
+  auto i = 0;
+  return i;
+}

+ 18 - 0
Tests/CMakeLists.txt

@@ -197,6 +197,11 @@ if(BUILD_TESTING)
   ADD_TEST_MACRO(TarTest TarTest)
   ADD_TEST_MACRO(TarTest TarTest)
   ADD_TEST_MACRO(SystemInformation SystemInformation)
   ADD_TEST_MACRO(SystemInformation SystemInformation)
   ADD_TEST_MACRO(MathTest MathTest)
   ADD_TEST_MACRO(MathTest MathTest)
+  if(CMAKE_CXX_COMPILER_ID STREQUAL GNU
+      AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+    ADD_TEST_MACRO(CompileFeatures CompileFeatures)
+    ADD_TEST_MACRO(CMakeCommands.target_compile_features target_compile_features)
+  endif()
   # assume no resources building to test
   # assume no resources building to test
   set(TEST_RESOURCES FALSE)
   set(TEST_RESOURCES FALSE)
   # for windows and cygwin assume we have resources
   # for windows and cygwin assume we have resources
@@ -283,6 +288,19 @@ if(BUILD_TESTING)
     ADD_TEST_MACRO(ConfigSources ConfigSources)
     ADD_TEST_MACRO(ConfigSources ConfigSources)
   endif()
   endif()
   ADD_TEST_MACRO(SourcesProperty SourcesProperty)
   ADD_TEST_MACRO(SourcesProperty SourcesProperty)
+  if(CMAKE_CXX_COMPILER_ID STREQUAL GNU
+      AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
+    set(runCxxDialectTest 1)
+  endif()
+  if(CMAKE_CXX_COMPILER_ID STREQUAL Clang
+        AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.9)
+    if(NOT APPLE OR POLICY CMP0025)
+      set(runCxxDialectTest 1)
+    endif()
+  endif()
+  if(runCxxDialectTest)
+    ADD_TEST_MACRO(CxxDialect CxxDialect)
+  endif()
   set_tests_properties(EmptyLibrary PROPERTIES
   set_tests_properties(EmptyLibrary PROPERTIES
     PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test")
     PASS_REGULAR_EXPRESSION "CMake Error: CMake can not determine linker language for target: test")
   ADD_TEST_MACRO(CrossCompile CrossCompile)
   ADD_TEST_MACRO(CrossCompile CrossCompile)

+ 36 - 0
Tests/CompileFeatures/CMakeLists.txt

@@ -0,0 +1,36 @@
+
+cmake_minimum_required(VERSION 3.0)
+
+project(CompileFeatures)
+
+macro(run_test feature)
+  if (";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ${feature})
+    add_library(test_${feature} OBJECT ${feature}.cpp)
+    set_property(TARGET test_${feature}
+      PROPERTY COMPILE_FEATURES "${feature}"
+    )
+  else()
+    message("Not supported: ${feature}")
+  endif()
+endmacro()
+
+foreach(feature ${CMAKE_CXX_KNOWN_FEATURES})
+  run_test(${feature})
+endforeach()
+
+add_executable(CompileFeatures main.cpp)
+set_property(TARGET CompileFeatures
+  PROPERTY COMPILE_FEATURES "cxx_auto_type"
+)
+
+add_executable(GenexCompileFeatures main.cpp)
+set_property(TARGET GenexCompileFeatures
+  PROPERTY COMPILE_FEATURES "$<1:cxx_auto_type>;$<0:not_a_feature>"
+)
+
+add_library(iface INTERFACE)
+set_property(TARGET iface
+  PROPERTY INTERFACE_COMPILE_FEATURES "cxx_auto_type"
+)
+add_executable(IfaceCompileFeatures main.cpp)
+target_link_libraries(IfaceCompileFeatures iface)

+ 5 - 0
Tests/CompileFeatures/cxx_auto_type.cpp

@@ -0,0 +1,5 @@
+
+void someFunc()
+{
+  auto x = 3.14;
+}

+ 6 - 0
Tests/CompileFeatures/main.cpp

@@ -0,0 +1,6 @@
+
+int main(int,char**)
+{
+  auto value = 0;
+  return value;
+}

+ 14 - 0
Tests/CxxDialect/CMakeLists.txt

@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.8.12)
+cmake_policy(SET CMP0025 NEW)
+project(CxxDialect)
+
+add_executable(use_typeof use_typeof.cxx)
+set_property(TARGET use_typeof PROPERTY CXX_STANDARD 98)
+set_property(TARGET use_typeof PROPERTY CXX_EXTENSIONS ON)
+
+add_executable(use_constexpr use_constexpr.cxx)
+set_property(TARGET use_constexpr PROPERTY CXX_STANDARD 11)
+
+add_executable(CxxDialect use_constexpr_and_typeof.cxx)
+set_property(TARGET CxxDialect PROPERTY CXX_STANDARD 11)
+set_property(TARGET CxxDialect PROPERTY CXX_EXTENSIONS ON)

+ 10 - 0
Tests/CxxDialect/use_constexpr.cxx

@@ -0,0 +1,10 @@
+
+constexpr int foo()
+{
+  return 0;
+}
+
+int main(int argc, char**)
+{
+  return foo();
+}

+ 11 - 0
Tests/CxxDialect/use_constexpr_and_typeof.cxx

@@ -0,0 +1,11 @@
+
+constexpr int foo()
+{
+  return 0;
+}
+
+int main(int argc, char**)
+{
+  typeof(argc) ret = foo();
+  return ret;
+}

+ 6 - 0
Tests/CxxDialect/use_typeof.cxx

@@ -0,0 +1,6 @@
+
+int main(int argc, char**)
+{
+  typeof(argc) ret = 0;
+  return ret;
+}

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

@@ -23,7 +23,10 @@ set_property(TARGET sharedlib PROPERTY INTERFACE_COMPILE_DEFINITIONS "SHAREDLIB_
 add_library(sharediface INTERFACE)
 add_library(sharediface INTERFACE)
 target_link_libraries(sharediface INTERFACE sharedlib)
 target_link_libraries(sharediface INTERFACE sharedlib)
 
 
-install(TARGETS headeronly sharediface
+add_library(use_auto_type INTERFACE)
+target_compile_features(use_auto_type INTERFACE cxx_auto_type)
+
+install(TARGETS headeronly sharediface use_auto_type
   EXPORT expInterface
   EXPORT expInterface
 )
 )
 install(TARGETS sharedlib
 install(TARGETS sharedlib

+ 1 - 0
Tests/ExportImport/Import/CMakeLists.txt

@@ -1,4 +1,5 @@
 cmake_minimum_required (VERSION 2.7.20090711)
 cmake_minimum_required (VERSION 2.7.20090711)
+cmake_policy(SET CMP0025 NEW)
 project(Import C CXX)
 project(Import C CXX)
 
 
 # Import everything in a subdirectory.
 # Import everything in a subdirectory.

+ 17 - 0
Tests/ExportImport/Import/Interface/CMakeLists.txt

@@ -40,6 +40,23 @@ macro(do_try_compile prefix)
   if(NOT ${prefix}IFACE_TRY_COMPILE)
   if(NOT ${prefix}IFACE_TRY_COMPILE)
     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_CXX_COMPILE_FEATURES};" MATCHES ";cxx_auto_type;")
+    set(CMAKE_REQUIRED_LIBRARIES ${prefix}::use_auto_type)
+    check_cxx_source_compiles(
+      "
+    int main(int,char**)
+    {
+      auto value = 0;
+      return value;
+    }
+    " ${prefix}IMPORTED_IFACE_CONSTEXPR)
+
+    if(NOT ${prefix}IMPORTED_IFACE_CONSTEXPR)
+      message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}")
+    endif()
+  endif()
+
 endmacro()
 endmacro()
 
 
 do_try_compile(bld)
 do_try_compile(bld)

+ 5 - 0
Tests/RunCMake/CMakeLists.txt

@@ -53,6 +53,7 @@ add_RunCMake_test(ObjectLibrary)
 add_RunCMake_test(TargetObjects)
 add_RunCMake_test(TargetObjects)
 add_RunCMake_test(TargetSources)
 add_RunCMake_test(TargetSources)
 add_RunCMake_test(find_dependency)
 add_RunCMake_test(find_dependency)
+add_RunCMake_test(CompileFeatures)
 if(NOT WIN32)
 if(NOT WIN32)
   add_RunCMake_test(PositionIndependentCode)
   add_RunCMake_test(PositionIndependentCode)
   set(SKIP_VISIBILITY 0)
   set(SKIP_VISIBILITY 0)
@@ -124,6 +125,10 @@ endif()
 add_RunCMake_test(File_Generate)
 add_RunCMake_test(File_Generate)
 add_RunCMake_test(ExportWithoutLanguage)
 add_RunCMake_test(ExportWithoutLanguage)
 add_RunCMake_test(target_link_libraries)
 add_RunCMake_test(target_link_libraries)
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
+  add_RunCMake_test(target_compile_features)
+endif()
 add_RunCMake_test(CheckModules)
 add_RunCMake_test(CheckModules)
 add_RunCMake_test(CommandLine)
 add_RunCMake_test(CommandLine)
 
 

+ 3 - 0
Tests/RunCMake/CompileFeatures/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)

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

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

+ 2 - 0
Tests/RunCMake/CompileFeatures/NotAFeature-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error in CMakeLists.txt:
+  Specified unknown feature "not_a_feature" for target "somelib".

+ 3 - 0
Tests/RunCMake/CompileFeatures/NotAFeature.cmake

@@ -0,0 +1,3 @@
+
+add_library(somelib STATIC empty.cpp)
+set_property(TARGET somelib PROPERTY COMPILE_FEATURES "not_a_feature")

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

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

+ 2 - 0
Tests/RunCMake/CompileFeatures/NotAFeatureGenex-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error in CMakeLists.txt:
+  Specified unknown feature "not_a_feature" for target "somelib".

+ 3 - 0
Tests/RunCMake/CompileFeatures/NotAFeatureGenex.cmake

@@ -0,0 +1,3 @@
+
+add_library(somelib STATIC empty.cpp)
+set_property(TARGET somelib PROPERTY COMPILE_FEATURES "$<1:not_a_feature>")

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

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

+ 2 - 0
Tests/RunCMake/CompileFeatures/NotAFeatureTransitive-stderr.txt

@@ -0,0 +1,2 @@
+CMake Error in CMakeLists.txt:
+  Specified unknown feature "not_a_feature" for target "somelib".

+ 6 - 0
Tests/RunCMake/CompileFeatures/NotAFeatureTransitive.cmake

@@ -0,0 +1,6 @@
+
+add_library(iface INTERFACE)
+set_property(TARGET iface PROPERTY INTERFACE_COMPILE_FEATURES "not_a_feature")
+
+add_library(somelib STATIC empty.cpp)
+target_link_libraries(somelib iface)

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

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

+ 11 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug-stderr.txt

@@ -0,0 +1,11 @@
+CMake Debug Log at NotAFeature_OriginDebug.cmake:4 \(set_property\):
+  Used compile features for target somelib:
+
+   \* not_a_feature
+
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Error in CMakeLists.txt:
+  Specified unknown feature "not_a_feature" for target "somelib".

+ 4 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug.cmake

@@ -0,0 +1,4 @@
+
+set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
+add_library(somelib STATIC empty.cpp)
+set_property(TARGET somelib PROPERTY COMPILE_FEATURES "not_a_feature")

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

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

+ 11 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex-stderr.txt

@@ -0,0 +1,11 @@
+CMake Debug Log at NotAFeature_OriginDebugGenex.cmake:4 \(set_property\):
+  Used compile features for target somelib:
+
+   \* not_a_feature
+
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Error in CMakeLists.txt:
+  Specified unknown feature "not_a_feature" for target "somelib".

+ 4 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugGenex.cmake

@@ -0,0 +1,4 @@
+
+set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
+add_library(somelib STATIC empty.cpp)
+set_property(TARGET somelib PROPERTY COMPILE_FEATURES "$<1:not_a_feature>")

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

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

+ 11 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive-stderr.txt

@@ -0,0 +1,11 @@
+CMake Debug Log at NotAFeature_OriginDebugTransitive.cmake:6 \(target_link_libraries\):
+  Used compile features for target somelib:
+
+   \* not_a_feature
+
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Error in CMakeLists.txt:
+  Specified unknown feature "not_a_feature" for target "somelib".

+ 6 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebugTransitive.cmake

@@ -0,0 +1,6 @@
+
+set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
+add_library(iface INTERFACE)
+set_property(TARGET iface PROPERTY INTERFACE_COMPILE_FEATURES "not_a_feature")
+add_library(somelib STATIC empty.cpp)
+target_link_libraries(somelib iface)

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

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

+ 5 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug_target_compile_features-stderr.txt

@@ -0,0 +1,5 @@
+CMake Error at NotAFeature_OriginDebug_target_compile_features.cmake:4 \(target_compile_features\):
+  target_compile_features specified unknown feature "not_a_feature" for
+  target "somelib".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/CompileFeatures/NotAFeature_OriginDebug_target_compile_features.cmake

@@ -0,0 +1,4 @@
+
+set(CMAKE_DEBUG_TARGET_PROPERTIES COMPILE_FEATURES)
+add_library(somelib STATIC empty.cpp)
+target_compile_features(somelib PRIVATE not_a_feature)

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

@@ -0,0 +1,9 @@
+include(RunCMake)
+
+run_cmake(NotAFeature)
+run_cmake(NotAFeatureGenex)
+run_cmake(NotAFeatureTransitive)
+run_cmake(NotAFeature_OriginDebug)
+run_cmake(NotAFeature_OriginDebugGenex)
+run_cmake(NotAFeature_OriginDebugTransitive)
+run_cmake(NotAFeature_OriginDebug_target_compile_features)

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

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

+ 3 - 0
Tests/RunCMake/target_compile_features/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.0)
+project(${RunCMake_TEST} CXX)
+include(${RunCMake_TEST}.cmake)

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

@@ -0,0 +1,11 @@
+include(RunCMake)
+
+run_cmake(not_enough_args)
+run_cmake(alias_target)
+run_cmake(utility_target)
+run_cmake(invalid_args)
+run_cmake(invalid_args_on_interface)
+run_cmake(imported_target)
+run_cmake(no_target)
+run_cmake(not_a_cxx_feature)
+run_cmake(no_matching_cxx_feature)

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

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

+ 4 - 0
Tests/RunCMake/target_compile_features/alias_target-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at alias_target.cmake:4 \(target_compile_features\):
+  target_compile_features can not be used on an ALIAS target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/target_compile_features/alias_target.cmake

@@ -0,0 +1,4 @@
+
+add_executable(main empty.cpp)
+add_executable(Alias::Main ALIAS main)
+target_compile_features(Alias::Main PRIVATE cxx_delegating_constructors)

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

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

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

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

+ 4 - 0
Tests/RunCMake/target_compile_features/imported_target-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at imported_target.cmake:3 \(target_compile_features\):
+  Cannot specify compile features for imported target "main".
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 3 - 0
Tests/RunCMake/target_compile_features/imported_target.cmake

@@ -0,0 +1,3 @@
+
+add_library(main INTERFACE IMPORTED)
+target_compile_features(main INTERFACE cxx_delegating_constructors)

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

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

+ 4 - 0
Tests/RunCMake/target_compile_features/invalid_args-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at invalid_args.cmake:3 \(target_compile_features\):
+  target_compile_features called with invalid arguments
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 3 - 0
Tests/RunCMake/target_compile_features/invalid_args.cmake

@@ -0,0 +1,3 @@
+
+add_executable(main empty.cpp)
+target_compile_features(main INVALID cxx_delegating_constructors)

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

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

+ 5 - 0
Tests/RunCMake/target_compile_features/invalid_args_on_interface-stderr.txt

@@ -0,0 +1,5 @@
+CMake Error at invalid_args_on_interface.cmake:3 \(target_compile_features\):
+  target_compile_features may only be set INTERFACE properties on INTERFACE
+  targets
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

部分文件因为文件数量过多而无法显示