diff options
46 files changed, 756 insertions, 77 deletions
diff --git a/Help/command/add_compile_options.rst b/Help/command/add_compile_options.rst index 5d71e11..214f4be 100644 --- a/Help/command/add_compile_options.rst +++ b/Help/command/add_compile_options.rst @@ -14,7 +14,7 @@ alternative commands exist to add preprocessor definitions include directories (:command:`target_include_directories` and :command:`include_directories`). See documentation of the :prop_tgt:`directory <COMPILE_OPTIONS>` and -:prop_tgt:` target <COMPILE_OPTIONS>` ``COMPILE_OPTIONS`` properties. +:prop_tgt:`target <COMPILE_OPTIONS>` ``COMPILE_OPTIONS`` properties. Arguments to ``add_compile_options`` may use "generator expressions" with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index dfda8dc..9184580 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -83,6 +83,12 @@ otherwise expands to nothing. else ``0``. If the policy was not set, the warning message for the policy will be emitted. This generator expression only works for a subset of policies. +``$<COMPILE_FEATURES:feature[,feature]...>`` + ``1`` if all of the ``feature`` features are available for the 'head' + target, and ``0`` otherwise. If this expression is used while evaluating + the link implementation of a target and if any dependency transitively + increases the required :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD` + for the 'head' target, an error is reported. Informational Expressions ========================= diff --git a/Help/release/dev/compile-language-features.rst b/Help/release/dev/compile-language-features.rst index fe72e39..d10e22b 100644 --- a/Help/release/dev/compile-language-features.rst +++ b/Help/release/dev/compile-language-features.rst @@ -22,3 +22,7 @@ target-language-features * New :command:`target_compile_features` command allows populating the :prop_tgt:`COMPILE_FEATURES` target property, just like any other build variable. + +* New ``COMPILE_FEATURES`` + :manual:`generator expression <cmake-generator-expressions(7)>` allows + setting build properties based on available compiler features. diff --git a/Modules/CMakeDetermineCompileFeatures.cmake b/Modules/CMakeDetermineCompileFeatures.cmake index 3762912..da68e94 100644 --- a/Modules/CMakeDetermineCompileFeatures.cmake +++ b/Modules/CMakeDetermineCompileFeatures.cmake @@ -67,7 +67,7 @@ function(cmake_determine_compile_features lang) return() endif() - if (CMAKE_CXX98_COMPILE_FEATURES) + if (CMAKE_CXX11_COMPILE_FEATURES AND CMAKE_CXX98_COMPILE_FEATURES) list(REMOVE_ITEM CMAKE_CXX11_COMPILE_FEATURES ${CMAKE_CXX98_COMPILE_FEATURES}) endif() diff --git a/Modules/Compiler/Clang-C-FeatureTests.cmake b/Modules/Compiler/Clang-C-FeatureTests.cmake new file mode 100644 index 0000000..4a72e87 --- /dev/null +++ b/Modules/Compiler/Clang-C-FeatureTests.cmake @@ -0,0 +1,11 @@ + +set(_cmake_oldestSupported "((__clang_major__ * 100) + __clang_minor__) >= 304") + +set(Clang_C11 "${_cmake_oldestSupported} && __STDC_VERSION__ >= 201112L") +set(_cmake_feature_test_c_static_assert "${Clang_C11}") +set(Clang_C99 "${_cmake_oldestSupported} && __STDC_VERSION__ >= 199901L") +set(_cmake_feature_test_c_restrict "${Clang_C99}") +set(_cmake_feature_test_c_variadic_macros "${Clang_C99}") + +set(Clang_C90 "${_cmake_oldestSupported} && !defined(__STDC_VERSION__)") +set(_cmake_feature_test_c_function_prototypes "${Clang_C90}") diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake index 98fcd0b..05d3c0b 100644 --- a/Modules/Compiler/Clang-C.cmake +++ b/Modules/Compiler/Clang-C.cmake @@ -1,2 +1,38 @@ include(Compiler/Clang) __compiler_clang(C) + +cmake_policy(GET CMP0025 appleClangPolicy) +if(WIN32 OR (APPLE AND NOT appleClangPolicy STREQUAL NEW)) + return() +endif() + +if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) + set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90") + set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90") + + set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99") + set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99") + + set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11") + set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11") +endif() + +set(CMAKE_C_STANDARD_DEFAULT 90) + +macro(cmake_record_c_compile_features) + macro(_get_clang_features std_version list) + record_compiler_features(C "-std=${std_version}" ${list}) + endmacro() + + if (UNIX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) + _get_clang_features(c11 CMAKE_C11_COMPILE_FEATURES) + if (_result EQUAL 0) + _get_clang_features(c99 CMAKE_C99_COMPILE_FEATURES) + endif() + if (_result EQUAL 0) + _get_clang_features(c90 CMAKE_C90_COMPILE_FEATURES) + endif() + else() + set(_result 0) + endif() +endmacro() diff --git a/Modules/Compiler/Clang-CXX-FeatureTests.cmake b/Modules/Compiler/Clang-CXX-FeatureTests.cmake new file mode 100644 index 0000000..c4092c4 --- /dev/null +++ b/Modules/Compiler/Clang-CXX-FeatureTests.cmake @@ -0,0 +1,69 @@ + +# Reference: http://clang.llvm.org/cxx_status.html +# http://clang.llvm.org/docs/LanguageExtensions.html + +set(testable_features + cxx_alias_templates + cxx_alignas + cxx_attributes + cxx_auto_type + cxx_constexpr + cxx_decltype + cxx_decltype_incomplete_return_types + cxx_default_function_template_args + cxx_defaulted_functions + cxx_delegating_constructors + cxx_deleted_functions + cxx_explicit_conversions + cxx_generalized_initializers + cxx_inheriting_constructors + cxx_lambdas + cxx_local_type_template_args + cxx_noexcept + cxx_nonstatic_member_init + cxx_nullptr + cxx_range_for + cxx_raw_string_literals + cxx_reference_qualified_functions + cxx_rvalue_references + cxx_static_assert + cxx_strong_enums + cxx_thread_local + cxx_unicode_literals + cxx_unrestricted_unions + cxx_user_literals + cxx_variadic_templates +) + +set(_cmake_oldestSupported "((__clang_major__ * 100) + __clang_minor__) >= 304") + +foreach(feature ${testable_features}) + set(_cmake_feature_test_${feature} "${_cmake_oldestSupported} && __has_feature(${feature})") +endforeach() + +unset(testable_features) + +set(_cmake_feature_test_cxx_trailing_return_types "${_cmake_oldestSupported} && __has_feature(cxx_trailing_return)") +set(_cmake_feature_test_cxx_alignof "${_cmake_oldestSupported} && __has_feature(cxx_alignas)") +set(_cmake_feature_test_cxx_final "${_cmake_oldestSupported} && __has_feature(cxx_override_control)") +set(_cmake_feature_test_cxx_override "${_cmake_oldestSupported} && __has_feature(cxx_override_control)") +set(_cmake_feature_test_cxx_uniform_initialization "${_cmake_oldestSupported} && __has_feature(cxx_generalized_initializers)") +set(_cmake_feature_test_cxx_defaulted_move_initializers "${_cmake_oldestSupported} && __has_feature(cxx_defaulted_functions)") + +# TODO: Should be supported by Clang 3.1 +set(Clang31_CXX11 "${_cmake_oldestSupported} && __cplusplus >= 201103L") +set(_cmake_feature_test_cxx_enum_forward_declarations "${Clang31_CXX11}") +set(_cmake_feature_test_cxx_sizeof_member "${Clang31_CXX11}") +# TODO: Should be supported by Clang 2.9 +set(Clang29_CXX11 "${_cmake_oldestSupported} && __cplusplus >= 201103L") +set(_cmake_feature_test_cxx_extended_friend_declarations "${Clang29_CXX11}") +set(_cmake_feature_test_cxx_extern_templates "${Clang29_CXX11}") +set(_cmake_feature_test_cxx_func_identifier "${Clang29_CXX11}") +set(_cmake_feature_test_cxx_inline_namespaces "${Clang29_CXX11}") +set(_cmake_feature_test_cxx_long_long_type "${Clang29_CXX11}") +set(_cmake_feature_test_cxx_right_angle_brackets "${Clang29_CXX11}") +set(_cmake_feature_test_cxx_variadic_macros "${Clang29_CXX11}") + +# TODO: Should be supported forever? +set(Clang_CXX98 "${_cmake_oldestSupported} && __cplusplus >= 199711L") +set(_cmake_feature_test_cxx_template_template_parameters "${Clang_CXX98}") diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake index 0409c24..bdb6d69 100644 --- a/Modules/Compiler/Clang-CXX.cmake +++ b/Modules/Compiler/Clang-CXX.cmake @@ -6,7 +6,7 @@ if(NOT CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC") endif() cmake_policy(GET CMP0025 appleClangPolicy) -if(APPLE AND NOT appleClangPolicy STREQUAL NEW) +if(WIN32 OR (APPLE AND NOT appleClangPolicy STREQUAL NEW)) return() endif() @@ -22,3 +22,28 @@ 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() + +if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) + set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++1y") + set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++1y") +endif() + +set(CMAKE_CXX_STANDARD_DEFAULT 98) + +macro(cmake_record_cxx_compile_features) + macro(_get_clang_features std_version list) + record_compiler_features(CXX "-std=${std_version}" ${list}) + endmacro() + + if (UNIX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) + _get_clang_features(c++1y CMAKE_CXX14_COMPILE_FEATURES) + if (_result EQUAL 0) + _get_clang_features(c++11 CMAKE_CXX11_COMPILE_FEATURES) + endif() + if (_result EQUAL 0) + _get_clang_features(c++98 CMAKE_CXX98_COMPILE_FEATURES) + endif() + else() + set(_result 0) + endif() +endmacro() diff --git a/Modules/FindQt3.cmake b/Modules/FindQt3.cmake index 4fc6829..86997ba 100644 --- a/Modules/FindQt3.cmake +++ b/Modules/FindQt3.cmake @@ -161,7 +161,7 @@ find_library(QT_QASSISTANTCLIENT_LIBRARY # Qt 3 should prefer QTDIR over the PATH find_program(QT_MOC_EXECUTABLE - NAMES moc-qt3 moc moc3 moc3-mt + NAMES moc-qt3 moc3 moc3-mt moc HINTS ENV QTDIR PATHS @@ -186,7 +186,7 @@ endif() # Qt 3 should prefer QTDIR over the PATH find_program(QT_UIC_EXECUTABLE - NAMES uic-qt3 uic uic3 uic3-mt + NAMES uic-qt3 uic3 uic3-mt uic HINTS ENV QTDIR PATHS diff --git a/Modules/FindQt4.cmake b/Modules/FindQt4.cmake index e44d1d9..9487a62 100644 --- a/Modules/FindQt4.cmake +++ b/Modules/FindQt4.cmake @@ -1137,17 +1137,17 @@ if (QT_QMAKE_EXECUTABLE AND QTVERSION) endif() endmacro() - _find_qt4_program(QT_MOC_EXECUTABLE Qt4::moc moc-qt4 moc moc4) - _find_qt4_program(QT_UIC_EXECUTABLE Qt4::uic uic-qt4 uic uic4) + _find_qt4_program(QT_MOC_EXECUTABLE Qt4::moc moc-qt4 moc4 moc) + _find_qt4_program(QT_UIC_EXECUTABLE Qt4::uic uic-qt4 uic4 uic) _find_qt4_program(QT_UIC3_EXECUTABLE Qt4::uic3 uic3) _find_qt4_program(QT_RCC_EXECUTABLE Qt4::rcc rcc) _find_qt4_program(QT_DBUSCPP2XML_EXECUTABLE Qt4::qdbuscpp2xml qdbuscpp2xml) _find_qt4_program(QT_DBUSXML2CPP_EXECUTABLE Qt4::qdbusxml2cpp qdbusxml2cpp) - _find_qt4_program(QT_LUPDATE_EXECUTABLE Qt4::lupdate lupdate-qt4 lupdate lupdate4) - _find_qt4_program(QT_LRELEASE_EXECUTABLE Qt4::lrelease lrelease-qt4 lrelease lrelease4) + _find_qt4_program(QT_LUPDATE_EXECUTABLE Qt4::lupdate lupdate-qt4 lupdate4 lupdate) + _find_qt4_program(QT_LRELEASE_EXECUTABLE Qt4::lrelease lrelease-qt4 lrelease4 lrelease) _find_qt4_program(QT_QCOLLECTIONGENERATOR_EXECUTABLE Qt4::qcollectiongenerator qcollectiongenerator-qt4 qcollectiongenerator) - _find_qt4_program(QT_DESIGNER_EXECUTABLE Qt4::designer designer-qt4 designer designer4) - _find_qt4_program(QT_LINGUIST_EXECUTABLE Qt4::linguist linguist-qt4 linguist linguist4) + _find_qt4_program(QT_DESIGNER_EXECUTABLE Qt4::designer designer-qt4 designer4 designer) + _find_qt4_program(QT_LINGUIST_EXECUTABLE Qt4::linguist linguist-qt4 linguist4 linguist) if (NOT TARGET Qt4::qmake) add_executable(Qt4::qmake IMPORTED) diff --git a/Modules/GNUInstallDirs.cmake b/Modules/GNUInstallDirs.cmake index d868cb3..eac553d 100644 --- a/Modules/GNUInstallDirs.cmake +++ b/Modules/GNUInstallDirs.cmake @@ -192,9 +192,26 @@ if(NOT CMAKE_INSTALL_DATADIR) set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}") endif() -if(NOT CMAKE_INSTALL_INFODIR) - set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)") - set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info") +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + if(NOT CMAKE_INSTALL_INFODIR) + set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (info)") + set(CMAKE_INSTALL_INFODIR "info") + endif() + + if(NOT CMAKE_INSTALL_MANDDIR) + set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (man)") + set(CMAKE_INSTALL_MANDIR "man") + endif() +else() + if(NOT CMAKE_INSTALL_INFODIR) + set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)") + set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info") + endif() + + if(NOT CMAKE_INSTALL_MANDDIR) + set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)") + set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man") + endif() endif() if(NOT CMAKE_INSTALL_LOCALEDIR) @@ -202,11 +219,6 @@ if(NOT CMAKE_INSTALL_LOCALEDIR) set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale") endif() -if(NOT CMAKE_INSTALL_MANDIR) - set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)") - set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man") -endif() - if(NOT CMAKE_INSTALL_DOCDIR) set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)") set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}") diff --git a/Modules/Platform/OpenBSD.cmake b/Modules/Platform/OpenBSD.cmake index a4f6114..7ac6c7e 100644 --- a/Modules/Platform/OpenBSD.cmake +++ b/Modules/Platform/OpenBSD.cmake @@ -17,6 +17,22 @@ endif() set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_OPENBSD_VERSIONING 1) +# OpenBSD has no multilib +set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS FALSE) + # OpenBSD policy requires that shared libraries be installed without # executable permission. set(CMAKE_INSTALL_SO_NO_EXE 1) + +if($ENV{LOCALBASE}) + set(OPENBSD_LOCALBASE $ENV{LOCALBASE}) +else() + set(OPENBSD_LOCALBASE /usr/local) +endif() +if($ENV{X11BASE}) + set(OPENBSD_X11BASE $ENV{X11BASE}) +else() + set(OPENBSD_X11BASE /usr/X11R6) +endif() + +list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${OPENBSD_LOCALBASE}) diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake index d3c2037..d7b89cb 100644 --- a/Modules/WriteCompilerDetectionHeader.cmake +++ b/Modules/WriteCompilerDetectionHeader.cmake @@ -200,6 +200,7 @@ function(write_compiler_detection_header set(compilers GNU + Clang ) foreach(_comp ${_WCD_COMPILERS}) list(FIND compilers ${_comp} idx) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 2a28059..57f2ff6 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 0) -set(CMake_VERSION_PATCH 20140521) +set(CMake_VERSION_PATCH 20140522) #set(CMake_VERSION_RC 1) diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 5bfb664..4ee34df 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -232,9 +232,10 @@ bool cmFileCommand::HandleWriteCommand(std::vector<std::string> const& args, cmsys::ofstream file(fileName.c_str(), append?std::ios::app: std::ios::out); if ( !file ) { - std::string error = "Internal CMake error when trying to open file: "; - error += fileName.c_str(); - error += " for writing."; + std::string error = "failed to open for writing ("; + error += cmSystemTools::GetLastSystemError(); + error += "):\n "; + error += fileName; this->SetError(error); return false; } @@ -292,9 +293,10 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args) if ( !file ) { - std::string error = "Internal CMake error when trying to open file: "; - error += fileName.c_str(); - error += " for reading."; + std::string error = "failed to open for reading ("; + error += cmSystemTools::GetLastSystemError(); + error += "):\n "; + error += fileName; this->SetError(error); return false; } diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index d09e950..d53bdd7 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -110,6 +110,9 @@ const char *cmCompiledGeneratorExpression::Evaluate( break; } } + + this->MaxLanguageStandard = context.MaxLanguageStandard; + if (!context.HadError) { this->HadContextSensitiveCondition = context.HadContextSensitiveCondition; @@ -465,3 +468,17 @@ bool cmGeneratorExpression::IsValidTargetName(const std::string &input) return targetNameValidator.find(input.c_str()); } + +//---------------------------------------------------------------------------- +void +cmCompiledGeneratorExpression::GetMaxLanguageStandard(cmTarget const* tgt, + std::map<std::string, std::string>& mapping) +{ + typedef std::map<cmTarget const*, + std::map<std::string, std::string> > MapType; + MapType::const_iterator it = this->MaxLanguageStandard.find(tgt); + if (it != this->MaxLanguageStandard.end()) + { + mapping = it->second; + } +} diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index da64515..ef5360e 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -117,6 +117,9 @@ public: this->EvaluateForBuildsystem = eval; } + void GetMaxLanguageStandard(cmTarget const* tgt, + std::map<std::string, std::string>& mapping); + private: cmCompiledGeneratorExpression(cmListFileBacktrace const& backtrace, const std::string& input); @@ -134,6 +137,8 @@ private: mutable std::set<cmTarget*> DependTargets; mutable std::set<cmTarget const*> AllTargetsSeen; mutable std::set<std::string> SeenTargetProperties; + mutable std::map<cmTarget const*, std::map<std::string, std::string> > + MaxLanguageStandard; mutable std::string Output; mutable bool HadContextSensitiveCondition; bool EvaluateForBuildsystem; diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index a513921..0b357f6 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -1314,6 +1314,94 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode } targetObjectsNode; //---------------------------------------------------------------------------- +static const struct CompileFeaturesNode : public cmGeneratorExpressionNode +{ + CompileFeaturesNode() {} + + virtual int NumExpectedParameters() const { return OneOrMoreParameters; } + + std::string Evaluate(const std::vector<std::string> ¶meters, + cmGeneratorExpressionContext *context, + const GeneratorExpressionContent *content, + cmGeneratorExpressionDAGChecker *dagChecker) const + { + cmTarget const* target = context->HeadTarget; + if (!target) + { + reportError(context, content->GetOriginalExpression(), + "$<COMPILE_FEATURE> may only be used with binary targets. It may " + "not be used with add_custom_command or add_custom_target."); + return std::string(); + } + + typedef std::map<std::string, std::vector<std::string> > LangMap; + static LangMap availableFeatures; + + LangMap testedFeatures; + + for (std::vector<std::string>::const_iterator it = parameters.begin(); + it != parameters.end(); ++it) + { + std::string error; + std::string lang; + if (!context->Makefile->CompileFeatureKnown(context->HeadTarget, + *it, lang, &error)) + { + reportError(context, content->GetOriginalExpression(), error); + return std::string(); + } + testedFeatures[lang].push_back(*it); + + if (availableFeatures.find(lang) == availableFeatures.end()) + { + const char* featuresKnown + = context->Makefile->CompileFeaturesAvailable(lang, &error); + if (!featuresKnown) + { + reportError(context, content->GetOriginalExpression(), error); + return std::string(); + } + cmSystemTools::ExpandListArgument(featuresKnown, + availableFeatures[lang]); + } + } + + bool evalLL = dagChecker && dagChecker->EvaluatingLinkLibraries(); + + std::string result; + + for (LangMap::const_iterator lit = testedFeatures.begin(); + lit != testedFeatures.end(); ++lit) + { + for (std::vector<std::string>::const_iterator it = lit->second.begin(); + it != lit->second.end(); ++it) + { + if (!context->Makefile->HaveFeatureAvailable(target, + lit->first, *it)) + { + if (evalLL) + { + const char* l = target->GetProperty(lit->first + "_STANDARD"); + if (!l) + { + l = context->Makefile + ->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT"); + } + assert(l); + context->MaxLanguageStandard[target][lit->first] = l; + } + else + { + return "0"; + } + } + } + } + return "1"; + } +} compileFeaturesNode; + +//---------------------------------------------------------------------------- static const char* targetPolicyWhitelist[] = { 0 #define TARGET_POLICY_STRING(POLICY) \ @@ -1647,6 +1735,7 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier) nodeMap["C_COMPILER_VERSION"] = &cCompilerVersionNode; nodeMap["CXX_COMPILER_VERSION"] = &cxxCompilerVersionNode; nodeMap["PLATFORM_ID"] = &platformIdNode; + nodeMap["COMPILE_FEATURES"] = &compileFeaturesNode; nodeMap["CONFIGURATION"] = &configurationNode; nodeMap["CONFIG"] = &configurationTestNode; nodeMap["TARGET_FILE"] = &targetFileNode; diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 54a2548..eb76d7f 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -26,6 +26,8 @@ struct cmGeneratorExpressionContext std::set<cmTarget*> DependTargets; std::set<cmTarget const*> AllTargets; std::set<std::string> SeenTargetProperties; + std::map<cmTarget const*, std::map<std::string, std::string> > + MaxLanguageStandard; cmMakefile *Makefile; std::string Config; cmTarget const* HeadTarget; // The target whose property is being evaluated. diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index dac95ff..e80b8ee 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1482,6 +1482,31 @@ void cmLocalGenerator::AddCompileOptions( return; } } + + for(std::map<std::string, std::string>::const_iterator it + = target->GetMaxLanguageStandards().begin(); + it != target->GetMaxLanguageStandards().end(); ++it) + { + const char* standard = target->GetProperty(it->first + "_STANDARD"); + if(!standard) + { + continue; + } + if (this->Makefile->IsLaterStandard(it->first, standard, it->second)) + { + cmOStringStream e; + e << "The COMPILE_FEATURES property of target \"" + << target->GetName() << "\" was evaluated when computing the link " + "implementation, and the \"" << it->first << "_STANDARD\" was \"" + << it->second << "\" for that computation. Computing the " + "COMPILE_FEATURES based on the link implementation resulted in a " + "higher \"" << it->first << "_STANDARD\" \"" << standard << "\". " + "This is not permitted. The COMPILE_FEATURES may not both depend on " + "and be depended on by the link implementation." << std::endl; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } + } this->AddCompilerRequirementFlag(flags, target, lang); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 42dedc9..9f33b92 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -5004,38 +5004,91 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature, target->AppendProperty("COMPILE_FEATURES", feature.c_str()); return true; } + + std::string lang; + if (!this->CompileFeatureKnown(target, feature, lang, error)) + { + return false; + } + + const char* features = this->CompileFeaturesAvailable(lang, error); + if (!features) + { + return false; + } + + std::vector<std::string> availableFeatures; + cmSystemTools::ExpandListArgument(features, availableFeatures); + if (std::find(availableFeatures.begin(), + availableFeatures.end(), + feature) == availableFeatures.end()) + { + cmOStringStream e; + e << "The compiler feature \"" << feature + << "\" is not known to " << lang << " 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()); + + return lang == "C" + ? this->AddRequiredTargetCFeature(target, feature) + : this->AddRequiredTargetCxxFeature(target, feature); +} + +//---------------------------------------------------------------------------- +bool cmMakefile:: +CompileFeatureKnown(cmTarget const* target, const std::string& feature, + std::string& lang, std::string *error) const +{ + assert(cmGeneratorExpression::Find(feature) == std::string::npos); + bool isCFeature = std::find_if(cmArrayBegin(C_FEATURES) + 1, cmArrayEnd(C_FEATURES), cmStrCmp(feature)) != cmArrayEnd(C_FEATURES); + if (isCFeature) + { + lang = "C"; + return true; + } bool isCxxFeature = std::find_if(cmArrayBegin(CXX_FEATURES) + 1, cmArrayEnd(CXX_FEATURES), cmStrCmp(feature)) != cmArrayEnd(CXX_FEATURES); - if (!isCFeature && !isCxxFeature) + 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; + lang = "CXX"; + return true; } + 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 = isCFeature ? "C" : "CXX"; - +//---------------------------------------------------------------------------- +const char* cmMakefile:: +CompileFeaturesAvailable(const std::string& lang, std::string *error) const +{ const char* featuresKnown = this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES"); @@ -5062,40 +5115,150 @@ AddRequiredTargetFeature(cmTarget *target, const std::string& feature, { this->IssueMessage(cmake::FATAL_ERROR, e.str()); } - return false; + return 0; } + return featuresKnown; +} - std::vector<std::string> availableFeatures; - cmSystemTools::ExpandListArgument(featuresKnown, availableFeatures); - if (std::find(availableFeatures.begin(), - availableFeatures.end(), - feature) == availableFeatures.end()) +//---------------------------------------------------------------------------- +bool cmMakefile::HaveFeatureAvailable(cmTarget const* target, + std::string const& lang, + const std::string& feature) const +{ + return lang == "C" + ? this->HaveCFeatureAvailable(target, feature) + : this->HaveCxxFeatureAvailable(target, feature); +} + +//---------------------------------------------------------------------------- +bool cmMakefile:: +HaveCFeatureAvailable(cmTarget const* target, const std::string& feature) const +{ + bool needC90 = false; + bool needC99 = false; + bool needC11 = false; + + this->CheckNeededCLanguage(feature, needC90, needC99, needC11); + + const char *existingCStandard = target->GetProperty("C_STANDARD"); + if (!existingCStandard) + { + existingCStandard = this->GetDefinition("CMAKE_C_STANDARD_DEFAULT"); + } + + if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS), + cmStrCmp(existingCStandard)) == cmArrayEnd(C_STANDARDS)) { cmOStringStream e; - e << "The compiler feature \"" << feature - << "\" is not known to " << lang << " compiler\n\"" - << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID") - << "\"\nversion " - << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << "."; - this->IssueMessage(cmake::FATAL_ERROR, e.str()); + e << "The C_STANDARD property on target \"" << target->GetName() + << "\" contained an invalid value: \"" << existingCStandard << "\"."; + this->IssueMessage(cmake::FATAL_ERROR, e.str().c_str()); return false; } - target->AppendProperty("COMPILE_FEATURES", feature.c_str()); + const char * const *existingCIt = existingCStandard + ? std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp(existingCStandard)) + : cmArrayEnd(C_STANDARDS); - return isCFeature - ? this->AddRequiredTargetCFeature(target, feature) - : this->AddRequiredTargetCxxFeature(target, feature); + if (needC11 && existingCStandard && existingCIt < + std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp("11"))) + { + return false; + } + else if(needC99 && existingCStandard && existingCIt < + std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp("99"))) + { + return false; + } + else if(needC90 && existingCStandard && existingCIt < + std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp("90"))) + { + return false; + } + return true; } //---------------------------------------------------------------------------- -bool cmMakefile:: -AddRequiredTargetCxxFeature(cmTarget *target, - const std::string& feature) const +bool cmMakefile::IsLaterStandard(std::string const& lang, + std::string const& lhs, + std::string const& rhs) +{ + if (lang == "C") + { + const char * const *rhsIt = std::find_if(cmArrayBegin(C_STANDARDS), + cmArrayEnd(C_STANDARDS), + cmStrCmp(rhs)); + + return std::find_if(rhsIt, cmArrayEnd(C_STANDARDS), + cmStrCmp(lhs)) != cmArrayEnd(C_STANDARDS); + } + const char * const *rhsIt = std::find_if(cmArrayBegin(CXX_STANDARDS), + cmArrayEnd(CXX_STANDARDS), + cmStrCmp(rhs)); + + return std::find_if(rhsIt, cmArrayEnd(CXX_STANDARDS), + cmStrCmp(lhs)) != cmArrayEnd(CXX_STANDARDS); +} + +//---------------------------------------------------------------------------- +bool cmMakefile::HaveCxxFeatureAvailable(cmTarget const* target, + const std::string& feature) const { bool needCxx98 = false; bool needCxx11 = false; + this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11); + + const char *existingCxxStandard = target->GetProperty("CXX_STANDARD"); + if (!existingCxxStandard) + { + existingCxxStandard = this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); + } + 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); + + if (needCxx11 && existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), + cmArrayEnd(CXX_STANDARDS), + cmStrCmp("11"))) + { + return false; + } + else if(needCxx98 && existingCxxIt < + std::find_if(cmArrayBegin(CXX_STANDARDS), + cmArrayEnd(CXX_STANDARDS), + cmStrCmp("98"))) + { + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, + bool& needCxx98, + bool& needCxx11) const +{ if (const char *propCxx98 = this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) { @@ -5110,6 +5273,17 @@ AddRequiredTargetCxxFeature(cmTarget *target, cmSystemTools::ExpandListArgument(propCxx11, props); needCxx11 = std::find(props.begin(), props.end(), feature) != props.end(); } +} + +//---------------------------------------------------------------------------- +bool cmMakefile:: +AddRequiredTargetCxxFeature(cmTarget *target, + const std::string& feature) const +{ + bool needCxx98 = false; + bool needCxx11 = false; + + this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11); const char *existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (existingCxxStandard) @@ -5160,13 +5334,11 @@ AddRequiredTargetCxxFeature(cmTarget *target, } //---------------------------------------------------------------------------- -bool cmMakefile:: -AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const +void cmMakefile::CheckNeededCLanguage(const std::string& feature, + bool& needC90, + bool& needC99, + bool& needC11) const { - bool needC90 = false; - bool needC99 = false; - bool needC11 = false; - if (const char *propC90 = this->GetDefinition("CMAKE_C90_COMPILE_FEATURES")) { @@ -5188,6 +5360,17 @@ AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const cmSystemTools::ExpandListArgument(propC11, props); needC11 = std::find(props.begin(), props.end(), feature) != props.end(); } +} + +//---------------------------------------------------------------------------- +bool cmMakefile:: +AddRequiredTargetCFeature(cmTarget *target, const std::string& feature) const +{ + bool needC90 = false; + bool needC99 = false; + bool needC11 = false; + + this->CheckNeededCLanguage(feature, needC90, needC99, needC11); const char *existingCStandard = target->GetProperty("C_STANDARD"); if (existingCStandard) diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 90e2e19..11904a6 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -889,6 +889,19 @@ public: const std::string& feature, std::string *error = 0) const; + bool CompileFeatureKnown(cmTarget const* target, const std::string& feature, + std::string& lang, std::string *error) const; + + const char* CompileFeaturesAvailable(const std::string& lang, + std::string *error) const; + + bool HaveFeatureAvailable(cmTarget const* target, std::string const& lang, + const std::string& feature) const; + + bool IsLaterStandard(std::string const& lang, + std::string const& lhs, + std::string const& rhs); + void ClearMatches(); void StoreMatches(cmsys::RegularExpression& re); @@ -1104,6 +1117,16 @@ private: bool AddRequiredTargetCxxFeature(cmTarget *target, const std::string& feature) const; + + void CheckNeededCLanguage(const std::string& feature, bool& needC90, + bool& needC99, bool& needC11) const; + void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, + bool& needCxx11) const; + + bool HaveCFeatureAvailable(cmTarget const* target, + const std::string& feature) const; + bool HaveCxxFeatureAvailable(cmTarget const* target, + const std::string& feature) const; }; //---------------------------------------------------------------------------- diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d8b7373..15acfdd 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -1220,7 +1220,7 @@ void cmTarget::GetDirectLinkLibraries(const std::string& config, &dagChecker), libs); - std::set<std::string> seenProps = cge->GetSeenTargetProperties(); + std::set<std::string> const& seenProps = cge->GetSeenTargetProperties(); for (std::set<std::string>::const_iterator it = seenProps.begin(); it != seenProps.end(); ++it) { @@ -1229,6 +1229,7 @@ void cmTarget::GetDirectLinkLibraries(const std::string& config, this->LinkImplicitNullProperties.insert(*it); } } + cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards); } } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 93e1b5b..2d51835 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -589,6 +589,12 @@ public: const std::string &report, const std::string &compatibilityType) const; + std::map<std::string, std::string> const& + GetMaxLanguageStandards() const + { + return this->MaxLanguageStandards; + } + private: bool HandleLocationPropertyPolicy(cmMakefile* context) const; @@ -720,6 +726,7 @@ private: mutable bool DebugSourcesDone; mutable bool DebugCompileFeaturesDone; mutable std::set<std::string> LinkImplicitNullProperties; + mutable std::map<std::string, std::string> MaxLanguageStandards; bool BuildInterfaceIncludesAppended; // Cache target output paths for each configuration. diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt index 0e1e6c9..7a8a975 100644 --- a/Tests/CompileFeatures/CMakeLists.txt +++ b/Tests/CompileFeatures/CMakeLists.txt @@ -83,3 +83,17 @@ set_property(TARGET iface ) add_executable(IfaceCompileFeatures main.cpp) target_link_libraries(IfaceCompileFeatures iface) + +add_executable(CompileFeaturesGenex genex_test.cpp) +set_property(TARGET CompileFeaturesGenex PROPERTY CXX_STANDARD 11) +target_compile_definitions(CompileFeaturesGenex PRIVATE HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>) + +add_executable(CompileFeaturesGenex2 genex_test.cpp) +target_compile_features(CompileFeaturesGenex2 PRIVATE cxx_constexpr) +target_compile_definitions(CompileFeaturesGenex2 PRIVATE HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>) + +add_library(noexcept_iface INTERFACE) +target_compile_features(noexcept_iface INTERFACE cxx_noexcept) +add_executable(CompileFeaturesGenex3 genex_test.cpp) +target_link_libraries(CompileFeaturesGenex3 PRIVATE noexcept_iface) +target_compile_definitions(CompileFeaturesGenex3 PRIVATE HAVE_OVERRIDE_CONTROL=$<COMPILE_FEATURES:cxx_final,cxx_override>) diff --git a/Tests/CompileFeatures/genex_test.cpp b/Tests/CompileFeatures/genex_test.cpp new file mode 100644 index 0000000..ca38883 --- /dev/null +++ b/Tests/CompileFeatures/genex_test.cpp @@ -0,0 +1,21 @@ + +#if !HAVE_OVERRIDE_CONTROL +#error "Expect override control feature" +#else + +struct A +{ + virtual int getA() { return 7; } +}; + +struct B final : A +{ + int getA() override { return 42; } +}; + +#endif + +int main() +{ + +} diff --git a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt index 8dd262e..ab0ebc3 100644 --- a/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt +++ b/Tests/Module/WriteCompilerDetectionHeader/CMakeLists.txt @@ -11,7 +11,7 @@ get_property(c_known_features GLOBAL PROPERTY CMAKE_C_KNOWN_FEATURES) write_compiler_detection_header( FILE "${CMAKE_CURRENT_BINARY_DIR}/test_compiler_detection.h" PREFIX TEST - COMPILERS GNU + COMPILERS GNU Clang VERSION 3.1 PROLOG "// something" EPILOG "// more" @@ -49,7 +49,8 @@ macro(set_defines target true_defs false_defs) ) endmacro() -if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) +if (CMAKE_CXX_COMPILER_ID STREQUAL GNU + OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) # False for C++98 mode. list(APPEND false_defs EXPECTED_COMPILER_CXX_DELEGATING_CONSTRUCTORS) list(APPEND false_defs EXPECTED_COMPILER_CXX_VARIADIC_TEMPLATES) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 3eeda2f..4efc73a 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -84,6 +84,7 @@ add_RunCMake_test(add_dependencies) add_RunCMake_test(build_command) add_RunCMake_test(export) add_RunCMake_test(cmake_minimum_required) +add_RunCMake_test(file) add_RunCMake_test(find_package) add_RunCMake_test(get_filename_component) add_RunCMake_test(if) diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt new file mode 100644 index 0000000..a584d7d --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle-stderr.txt @@ -0,0 +1,7 @@ +CMake Error in CMakeLists.txt: + The COMPILE_FEATURES property of target "empty1" was evaluated when + computing the link implementation, and the "CXX_STANDARD" was "98" for that + computation. Computing the COMPILE_FEATURES based on the link + implementation resulted in a higher "CXX_STANDARD" "11". This is not + permitted. The COMPILE_FEATURES may not both depend on and be depended on + by the link implementation. diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake new file mode 100644 index 0000000..9d56bc0 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycle.cmake @@ -0,0 +1,15 @@ + +add_library(empty1 empty.cpp) + +add_library(empty2 INTERFACE) +add_library(empty3 INTERFACE) +target_compile_features(empty3 INTERFACE cxx_constexpr) + +target_link_libraries(empty1 + # When starting, $<COMPILE_FEATURES:cxx_final> is '0', so 'freeze' the + # CXX_STANDARD at 98 during computation. + $<$<COMPILE_FEATURES:cxx_final>:empty2> + # This would add cxx_constexpr, but that would require CXX_STANDARD = 11, + # which is not allowed after freeze. Report an error. + empty3 +) diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt new file mode 100644 index 0000000..10f3293 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved-stderr.txt @@ -0,0 +1 @@ +^$ diff --git a/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake new file mode 100644 index 0000000..0df548b --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/LinkImplementationFeatureCycleSolved.cmake @@ -0,0 +1,14 @@ + +add_library(empty1 empty.cpp) + +add_library(empty2 INTERFACE) +add_library(empty3 INTERFACE) +target_compile_features(empty3 INTERFACE cxx_constexpr) + +target_link_libraries(empty1 + $<$<COMPILE_FEATURES:cxx_final>:empty2> + empty3 +) +# This, or populating the COMPILE_FEATURES property with a feature in the +# same standard as cxx_final, solves the cycle above. +set_property(TARGET empty1 PROPERTY CXX_STANDARD 11) diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NonValidTarget1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt new file mode 100644 index 0000000..7f3b43b --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NonValidTarget1-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at NonValidTarget1.cmake:[0-9]+ \(add_custom_command\): + Error evaluating generator expression: + + \$<COMPILE_FEATURES:cxx_final> + + \$<COMPILE_FEATURE> may only be used with binary targets. It may not be + used with add_custom_command or add_custom_target. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake b/Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake new file mode 100644 index 0000000..c6707c1 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NonValidTarget1.cmake @@ -0,0 +1,17 @@ + +set(genexvar $<COMPILE_FEATURES:cxx_final>) + +if (HAVE_FINAL) + set(expected_result 1) +else() + set(expected_result 0) +endif() + +add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copied_file${HAVE_FINAL}.cpp" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp" "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.cpp" +) + +add_library(empty "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.cpp") +if (HAVE_FINAL) + target_compile_features(empty PRIVATE cxx_final) +endif() diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NonValidTarget2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt b/Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt new file mode 100644 index 0000000..635150c --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NonValidTarget2-stderr.txt @@ -0,0 +1,9 @@ +CMake Error at NonValidTarget2.cmake:4 \(add_custom_target\): + Error evaluating generator expression: + + \$<COMPILE_FEATURES:cxx_final> + + \$<COMPILE_FEATURE> may only be used with binary targets. It may not be + used with add_custom_command or add_custom_target. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake b/Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake new file mode 100644 index 0000000..eb84692 --- /dev/null +++ b/Tests/RunCMake/CompileFeatures/NonValidTarget2.cmake @@ -0,0 +1,8 @@ + +set(genexvar $<COMPILE_FEATURES:cxx_final>) + +add_custom_target(copy_target + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.cpp" "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.txt" +) + +add_library(empty "${CMAKE_CURRENT_BINARY_DIR}/copied_file${genexvar}.cpp") diff --git a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake index a23d44f..1892a5c 100644 --- a/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake +++ b/Tests/RunCMake/CompileFeatures/RunCMakeTest.cmake @@ -26,6 +26,16 @@ endif() if (NOT CXX_FEATURES) run_cmake(NoSupportedCxxFeatures) run_cmake(NoSupportedCxxFeaturesGenex) +else() + run_cmake(LinkImplementationFeatureCycle) + run_cmake(LinkImplementationFeatureCycleSolved) + + if (";${CXX_FEATURES};" MATCHES ";cxx_final;") + set(RunCMake_TEST_OPTIONS "-DHAVE_FINAL=1") + endif() + run_cmake(NonValidTarget1) + run_cmake(NonValidTarget2) + unset(RunCMake_TEST_OPTIONS) endif() foreach(standard 98 11) diff --git a/Tests/RunCMake/file/CMakeLists.txt b/Tests/RunCMake/file/CMakeLists.txt new file mode 100644 index 0000000..2897109 --- /dev/null +++ b/Tests/RunCMake/file/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.0) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/file/FileOpenFailRead-result.txt b/Tests/RunCMake/file/FileOpenFailRead-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/FileOpenFailRead-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/FileOpenFailRead-stderr.txt b/Tests/RunCMake/file/FileOpenFailRead-stderr.txt new file mode 100644 index 0000000..23d4337 --- /dev/null +++ b/Tests/RunCMake/file/FileOpenFailRead-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at FileOpenFailRead.cmake:[0-9]+ \(file\): + file failed to open for reading \(.*\): + + .*/Tests/RunCMake/file/does_not_exist/file.txt +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/file/FileOpenFailRead.cmake b/Tests/RunCMake/file/FileOpenFailRead.cmake new file mode 100644 index 0000000..4d4c6dc --- /dev/null +++ b/Tests/RunCMake/file/FileOpenFailRead.cmake @@ -0,0 +1 @@ +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/does_not_exist/file.txt" content) diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake new file mode 100644 index 0000000..7b05229 --- /dev/null +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -0,0 +1,3 @@ +include(RunCMake) + +run_cmake(FileOpenFailRead) |