diff options
-rw-r--r-- | Help/manual/cmake-developer.7.rst | 4 | ||||
-rw-r--r-- | Help/prop_tgt/CXX_STANDARD.rst | 3 | ||||
-rw-r--r-- | Help/prop_tgt/CXX_STANDARD_REQUIRED.rst | 3 | ||||
-rw-r--r-- | Help/prop_tgt/C_STANDARD.rst | 3 | ||||
-rw-r--r-- | Help/prop_tgt/C_STANDARD_REQUIRED.rst | 3 | ||||
-rw-r--r-- | Source/cmGeneratorExpressionEvaluator.cxx | 11 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 9 | ||||
-rw-r--r-- | Source/cmMakefile.cxx | 46 | ||||
-rw-r--r-- | Tests/CompileFeatures/CMakeLists.txt | 36 | ||||
-rw-r--r-- | Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake | 36 | ||||
-rw-r--r-- | Tests/RunCMake/CompileFeatures/generate_feature_list.cmake | 14 |
11 files changed, 126 insertions, 42 deletions
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst index 65b3a72..e18250c 100644 --- a/Help/manual/cmake-developer.7.rst +++ b/Help/manual/cmake-developer.7.rst @@ -80,7 +80,9 @@ When adding the first supported feature to a particular CompilerId, it is necessary to list support for all features known to cmake (See :variable:`CMAKE_C_COMPILE_FEATURES` and :variable:`CMAKE_CXX_COMPILE_FEATURES` as appropriate), where available for -the compiler. +the compiler. Furthermore, set ``CMAKE_<LANG>_STANDARD_DEFAULT`` to the +default language standard level the compiler uses, or to the empty string +if the compiler has no notion of standard levels (such as ``MSVC``). It is sensible to record the features for the most recent version of a particular CompilerId first, and then work backwards. It is sensible to diff --git a/Help/prop_tgt/CXX_STANDARD.rst b/Help/prop_tgt/CXX_STANDARD.rst index 6329e34..65b30ec 100644 --- a/Help/prop_tgt/CXX_STANDARD.rst +++ b/Help/prop_tgt/CXX_STANDARD.rst @@ -5,7 +5,8 @@ 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=gnu++11`` to the compile line. +flag such as ``-std=gnu++11`` to the compile line. For compilers that +have no notion of a standard level, such as MSVC, this has no effect. Supported values are ``98``, ``11`` and ``14``. diff --git a/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst b/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst index ac103a4..4e24e5e 100644 --- a/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst +++ b/Help/prop_tgt/CXX_STANDARD_REQUIRED.rst @@ -7,7 +7,8 @@ If this property is set to ``ON``, then the value of the :prop_tgt:`CXX_STANDARD` target property is treated as a requirement. If this property is ``OFF`` or unset, the :prop_tgt:`CXX_STANDARD` target property is treated as optional and may "decay" to a previous standard if the requested is -not available. +not available. For compilers that have no notion of a standard level, such as +MSVC, this has no effect. See the :manual:`cmake-compile-features(7)` manual for information on compile features. diff --git a/Help/prop_tgt/C_STANDARD.rst b/Help/prop_tgt/C_STANDARD.rst index 88ca926..3aa74af 100644 --- a/Help/prop_tgt/C_STANDARD.rst +++ b/Help/prop_tgt/C_STANDARD.rst @@ -5,7 +5,8 @@ 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=gnu11`` to the compile line. +flag such as ``-std=gnu11`` to the compile line. For compilers that +have no notion of a standard level, such as MSVC, this has no effect. Supported values are ``90``, ``99`` and ``11``. diff --git a/Help/prop_tgt/C_STANDARD_REQUIRED.rst b/Help/prop_tgt/C_STANDARD_REQUIRED.rst index a7304f4..743d568 100644 --- a/Help/prop_tgt/C_STANDARD_REQUIRED.rst +++ b/Help/prop_tgt/C_STANDARD_REQUIRED.rst @@ -7,7 +7,8 @@ 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. +not available. For compilers that have no notion of a standard level, such as +MSVC, this has no effect. See the :manual:`cmake-compile-features(7)` manual for information on compile features. diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 5f246f9..6692a92 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -1370,6 +1370,8 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode { std::vector<std::string> const& langAvailable = availableFeatures[lit->first]; + const char* standardDefault = context->Makefile + ->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT"); for (std::vector<std::string>::const_iterator it = lit->second.begin(); it != lit->second.end(); ++it) { @@ -1378,6 +1380,12 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode { return "0"; } + if (standardDefault && !*standardDefault) + { + // This compiler has no notion of language standard levels. + // All features known for the language are always available. + continue; + } if (!context->Makefile->HaveStandardAvailable(target, lit->first, *it)) { @@ -1386,8 +1394,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode const char* l = target->GetProperty(lit->first + "_STANDARD"); if (!l) { - l = context->Makefile - ->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT"); + l = standardDefault; } assert(l); context->MaxLanguageStandard[target][lit->first] = l; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 834f705..af4c950 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2207,6 +2207,13 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target, { return; } + const char* defaultStd + = this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT"); + if (defaultStd && !*defaultStd) + { + // This compiler has no notion of language standard levels. + return; + } std::string stdProp = lang + "_STANDARD"; const char *standardProp = target->GetProperty(stdProp); if (!standardProp) @@ -2269,8 +2276,6 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target, std::find(stds.begin(), stds.end(), standard); assert(stdIt != stds.end()); - const char* defaultStd - = this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT"); std::vector<std::string>::const_iterator defaultStdIt; if (defaultStd) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 87e62d7..ba914e1 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -5253,6 +5253,27 @@ bool cmMakefile:: HaveCStandardAvailable(cmTarget const* target, const std::string& feature) const { + const char* defaultCStandard = + this->GetDefinition("CMAKE_C_STANDARD_DEFAULT"); + if (!defaultCStandard) + { + std::ostringstream e; + e << "CMAKE_C_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " + "not fully configured for this compiler."; + this->IssueMessage(cmake::INTERNAL_ERROR, e.str()); + // Return true so the caller does not try to lookup the default standard. + return true; + } + if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), + cmStrCmp(defaultCStandard)) == cmArrayEnd(C_STANDARDS)) + { + std::ostringstream e; + e << "The CMAKE_C_STANDARD_DEFAULT variable contains an " + "invalid value: \"" << defaultCStandard << "\"."; + this->IssueMessage(cmake::INTERNAL_ERROR, e.str()); + return false; + } + bool needC90 = false; bool needC99 = false; bool needC11 = false; @@ -5262,7 +5283,7 @@ HaveCStandardAvailable(cmTarget const* target, const char *existingCStandard = target->GetProperty("C_STANDARD"); if (!existingCStandard) { - existingCStandard = this->GetDefinition("CMAKE_C_STANDARD_DEFAULT"); + existingCStandard = defaultCStandard; } if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), @@ -5331,6 +5352,27 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, const std::string& feature) const { + const char* defaultCxxStandard = + this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); + if (!defaultCxxStandard) + { + std::ostringstream e; + e << "CMAKE_CXX_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " + "not fully configured for this compiler."; + this->IssueMessage(cmake::INTERNAL_ERROR, e.str()); + // Return true so the caller does not try to lookup the default standard. + return true; + } + if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), + cmStrCmp(defaultCxxStandard)) == cmArrayEnd(CXX_STANDARDS)) + { + std::ostringstream e; + e << "The CMAKE_CXX_STANDARD_DEFAULT variable contains an " + "invalid value: \"" << defaultCxxStandard << "\"."; + this->IssueMessage(cmake::INTERNAL_ERROR, e.str()); + return false; + } + bool needCxx98 = false; bool needCxx11 = false; bool needCxx14 = false; @@ -5339,7 +5381,7 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, const char *existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (!existingCxxStandard) { - existingCxxStandard = this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); + existingCxxStandard = defaultCxxStandard; } if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt index aacf4c1..9ef8049 100644 --- a/Tests/CompileFeatures/CMakeLists.txt +++ b/Tests/CompileFeatures/CMakeLists.txt @@ -128,26 +128,30 @@ foreach(lang CXX C) endforeach() if (CMAKE_C_COMPILE_FEATURES) - string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx) - if (std_flag_idx EQUAL -1) - add_executable(default_dialect_C default_dialect.c) - target_compile_definitions(default_dialect_C PRIVATE - DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11> - DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99> - DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90> - ) + if (CMAKE_C_STANDARD_DEFAULT) + string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx) + if (std_flag_idx EQUAL -1) + add_executable(default_dialect_C default_dialect.c) + target_compile_definitions(default_dialect_C PRIVATE + DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11> + DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99> + DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90> + ) + endif() endif() endif() if (CMAKE_CXX_COMPILE_FEATURES) - string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx) - if (std_flag_idx EQUAL -1) - add_executable(default_dialect default_dialect.cpp) - target_compile_definitions(default_dialect PRIVATE - DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14> - DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11> - DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98> - ) + if (CMAKE_CXX_STANDARD_DEFAULT) + string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx) + if (std_flag_idx EQUAL -1) + add_executable(default_dialect default_dialect.cpp) + target_compile_definitions(default_dialect PRIVATE + DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14> + DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11> + DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98> + ) + endif() endif() add_executable(CompileFeatures main.cpp) diff --git a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake index 376f75a..833a315 100644 --- a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake +++ b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake @@ -17,6 +17,8 @@ file(READ "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt" CXX_FEATURES ) +include("${RunCMake_BINARY_DIR}/generate_feature_list-build/c_standard_default.cmake") +include("${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_standard_default.cmake") if (NOT C_FEATURES) run_cmake(NoSupportedCFeatures) @@ -27,7 +29,9 @@ if (NOT CXX_FEATURES) run_cmake(NoSupportedCxxFeatures) run_cmake(NoSupportedCxxFeaturesGenex) else() - run_cmake(LinkImplementationFeatureCycle) + if(CXX_STANDARD_DEFAULT) + run_cmake(LinkImplementationFeatureCycle) + endif() run_cmake(LinkImplementationFeatureCycleSolved) if (";${CXX_FEATURES};" MATCHES ";cxx_final;") @@ -38,17 +42,19 @@ else() unset(RunCMake_TEST_OPTIONS) endif() -foreach(standard 98 11) - file(READ - "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx${standard}_flag.txt" - CXX${standard}_FLAG - ) - if (CXX${standard}_FLAG STREQUAL NOTFOUND) - run_cmake(RequireCXX${standard}) - run_cmake(RequireCXX${standard}Variable) - endif() - if (CXX${standard}EXT_FLAG STREQUAL NOTFOUND) - run_cmake(RequireCXX${standard}Ext) - run_cmake(RequireCXX${standard}ExtVariable) - endif() -endforeach() +if(CXX_STANDARD_DEFAULT) + foreach(standard 98 11) + file(READ + "${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx${standard}_flag.txt" + CXX${standard}_FLAG + ) + if (CXX${standard}_FLAG STREQUAL NOTFOUND) + run_cmake(RequireCXX${standard}) + run_cmake(RequireCXX${standard}Variable) + endif() + if (CXX${standard}EXT_FLAG STREQUAL NOTFOUND) + run_cmake(RequireCXX${standard}Ext) + run_cmake(RequireCXX${standard}ExtVariable) + endif() + endforeach() +endif() diff --git a/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake b/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake index 09e17b1..5c58052 100644 --- a/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake +++ b/Tests/RunCMake/CompileFeatures/generate_feature_list.cmake @@ -9,6 +9,20 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_features.txt" "${CMAKE_CXX_COMPILE_FEATURES}" ) +if(DEFINED CMAKE_C_STANDARD_DEFAULT) + set(c_standard_default_code "set(C_STANDARD_DEFAULT \"${CMAKE_C_STANDARD_DEFAULT}\")\n") +else() + set(c_standard_default_code "unset(C_STANDARD_DEFAULT)\n") +endif() +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/c_standard_default.cmake" "${c_standard_default_code}") + +if(DEFINED CMAKE_CXX_STANDARD_DEFAULT) + set(cxx_standard_default_code "set(CXX_STANDARD_DEFAULT \"${CMAKE_CXX_STANDARD_DEFAULT}\")\n") +else() + set(cxx_standard_default_code "unset(CXX_STANDARD_DEFAULT)\n") +endif() +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_standard_default.cmake" "${cxx_standard_default_code}") + foreach(standard 98 11) set(CXX${standard}_FLAG NOTFOUND) if (DEFINED CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION) |