diff options
62 files changed, 798 insertions, 755 deletions
diff --git a/Help/command/if.rst b/Help/command/if.rst index d8e3a45..be992df 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -29,6 +29,8 @@ If used, it must be a verbatim repeat of the argument of the opening ``if`` command. +.. _`Condition Syntax`: + Condition Syntax ^^^^^^^^^^^^^^^^ diff --git a/Help/variable/CMAKE_MESSAGE_INDENT.rst b/Help/variable/CMAKE_MESSAGE_INDENT.rst index f7975ab..7e44a4c 100644 --- a/Help/variable/CMAKE_MESSAGE_INDENT.rst +++ b/Help/variable/CMAKE_MESSAGE_INDENT.rst @@ -23,8 +23,10 @@ Example: Which results in the following output: +.. code-block:: none + -- Collected items in the "listVar": -- one -- two - -- tree + -- three -- No more indent diff --git a/Modules/CMakeDependentOption.cmake b/Modules/CMakeDependentOption.cmake index 6046d85..99d5070 100644 --- a/Modules/CMakeDependentOption.cmake +++ b/Modules/CMakeDependentOption.cmake @@ -12,7 +12,7 @@ conditions are true. When the option is not presented a default value is used, but any value set by the user is preserved for when the option is presented again. Example invocation: -:: +.. code-block:: cmake CMAKE_DEPENDENT_OPTION(USE_FOO "Use Foo" ON "USE_BAR;NOT USE_ZOT" OFF) @@ -21,7 +21,8 @@ If USE_BAR is true and USE_ZOT is false, this provides an option called USE_FOO that defaults to ON. Otherwise, it sets USE_FOO to OFF. If the status of USE_BAR or USE_ZOT ever changes, any value for the USE_FOO option is saved so that when the option is re-enabled it -retains its old value. +retains its old value. Each element in the fourth parameter is +evaluated as an if-condition, so :ref:`Condition Syntax` can be used. #]=======================================================================] macro(CMAKE_DEPENDENT_OPTION option doc default depends force) diff --git a/Modules/CMakeDetermineCCompiler.cmake b/Modules/CMakeDetermineCCompiler.cmake index 8be781a..037c33b 100644 --- a/Modules/CMakeDetermineCCompiler.cmake +++ b/Modules/CMakeDetermineCCompiler.cmake @@ -124,6 +124,22 @@ if(NOT CMAKE_C_COMPILER_ID_RUN) elseif(CMAKE_C_PLATFORM_ID MATCHES "Cygwin") set(CMAKE_COMPILER_IS_CYGWIN 1) endif() +else() + if(NOT DEFINED CMAKE_C_COMPILER_FRONTEND_VARIANT) + # Some toolchain files set our internal CMAKE_C_COMPILER_ID_RUN + # variable but are not aware of CMAKE_C_COMPILER_FRONTEND_VARIANT. + # They pre-date our support for the GNU-like variant targeting the + # MSVC ABI so we do not consider that here. + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC") + set(CMAKE_C_COMPILER_FRONTEND_VARIANT "MSVC") + else() + set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU") + endif() + else() + set(CMAKE_C_COMPILER_FRONTEND_VARIANT "") + endif() + endif() endif() if (NOT _CMAKE_TOOLCHAIN_LOCATION) diff --git a/Modules/CMakeDetermineCXXCompiler.cmake b/Modules/CMakeDetermineCXXCompiler.cmake index 00ef5b9..7274eec 100644 --- a/Modules/CMakeDetermineCXXCompiler.cmake +++ b/Modules/CMakeDetermineCXXCompiler.cmake @@ -119,6 +119,22 @@ if(NOT CMAKE_CXX_COMPILER_ID_RUN) elseif(CMAKE_CXX_PLATFORM_ID MATCHES "Cygwin") set(CMAKE_COMPILER_IS_CYGWIN 1) endif() +else() + if(NOT DEFINED CMAKE_CXX_COMPILER_FRONTEND_VARIANT) + # Some toolchain files set our internal CMAKE_CXX_COMPILER_ID_RUN + # variable but are not aware of CMAKE_CXX_COMPILER_FRONTEND_VARIANT. + # They pre-date our support for the GNU-like variant targeting the + # MSVC ABI so we do not consider that here. + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") + set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "MSVC") + else() + set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "GNU") + endif() + else() + set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "") + endif() + endif() endif() if (NOT _CMAKE_TOOLCHAIN_LOCATION) diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake index 2e9a052..bd69819 100644 --- a/Modules/FindGLEW.cmake +++ b/Modules/FindGLEW.cmake @@ -70,11 +70,27 @@ if(GLEW_VERBOSE) message(STATUS "FindGLEW: did not find GLEW CMake config file. Searching for libraries.") endif() +if(APPLE) + find_package(OpenGL QUIET) + + if(OpenGL_FOUND) + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: Found OpenGL Framework.") + message(STATUS "FindGLEW: OPENGL_LIBRARIES: ${OPENGL_LIBRARIES}") + endif() + else() + if(GLEW_VERBOSE) + message(STATUS "FindGLEW: could not find GLEW library.") + endif() + return() + endif() +endif() + function(__glew_set_find_library_suffix shared_or_static) - if(UNIX AND "${shared_or_static}" MATCHES "SHARED") + if((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "SHARED") set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE) - elseif(UNIX AND "${shared_or_static}" MATCHES "STATIC") + elseif((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "STATIC") set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE) elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED") set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE) @@ -194,7 +210,7 @@ find_package_handle_standard_args(GLEW if(NOT GLEW_FOUND) if(GLEW_VERBOSE) - message(STATUS "FindGLEW: could not found GLEW library.") + message(STATUS "FindGLEW: could not find GLEW library.") endif() return() endif() @@ -210,6 +226,11 @@ if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS) set_target_properties(GLEW::glew PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + if(APPLE) + set_target_properties(GLEW::glew + PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL) + endif() + if(GLEW_SHARED_LIBRARY_RELEASE) set_property(TARGET GLEW::glew APPEND @@ -238,6 +259,11 @@ elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS) set_target_properties(GLEW::glew_s PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + if(APPLE) + set_target_properties(GLEW::glew_s + PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL) + endif() + if(GLEW_STATIC_LIBRARY_RELEASE) set_property(TARGET GLEW::glew_s APPEND @@ -267,6 +293,11 @@ if(NOT TARGET GLEW::GLEW) set_target_properties(GLEW::GLEW PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}") + if(APPLE) + set_target_properties(GLEW::GLEW + PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL) + endif() + if(TARGET GLEW::glew) if(GLEW_SHARED_LIBRARY_RELEASE) set_property(TARGET GLEW::GLEW diff --git a/Modules/Platform/Windows-OpenWatcom.cmake b/Modules/Platform/Windows-OpenWatcom.cmake index d38d616..76cd28b 100644 --- a/Modules/Platform/Windows-OpenWatcom.cmake +++ b/Modules/Platform/Windows-OpenWatcom.cmake @@ -10,7 +10,7 @@ set(__WINDOWS_OPENWATCOM 1) set(CMAKE_LIBRARY_PATH_FLAG "libpath ") set(CMAKE_LINK_LIBRARY_FLAG "library ") -set(CMAKE_LINK_LIBRARY_FILE_FLAG "library") +set(CMAKE_LINK_LIBRARY_FILE_FLAG "library ") if(CMAKE_VERBOSE_MAKEFILE) set(CMAKE_WCL_QUIET) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index fe40af3..b1f4ca5 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -532,6 +532,8 @@ set(SRCS cmFindProgramCommand.h cmForEachCommand.cxx cmForEachCommand.h + cmFunctionBlocker.cxx + cmFunctionBlocker.h cmFunctionCommand.cxx cmFunctionCommand.h cmGetCMakePropertyCommand.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 04564a0..96e5ee5 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 15) -set(CMake_VERSION_PATCH 20190803) +set(CMake_VERSION_PATCH 20190807) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index a075a17..f130e05 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -8,6 +8,7 @@ #include "cmCPackIFWRepository.h" #include "cmCPackLog.h" // IWYU pragma: keep #include "cmGeneratedFileStream.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmXMLParser.h" #include "cmXMLWriter.h" @@ -292,7 +293,7 @@ protected: { if (this->file) { std::string content(data, data + length); - content = cmSystemTools::TrimWhitespace(content); + content = cmTrimWhitespace(content); std::string source = this->basePath + "/" + content; std::string destination = this->path + "/" + content; if (!cmSystemTools::CopyFileIfDifferent(source, destination)) { diff --git a/Source/CPack/WiX/cmCMakeToWixPath.cxx b/Source/CPack/WiX/cmCMakeToWixPath.cxx index b3889cf..630a8f8 100644 --- a/Source/CPack/WiX/cmCMakeToWixPath.cxx +++ b/Source/CPack/WiX/cmCMakeToWixPath.cxx @@ -2,7 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCMakeToWixPath.h" -#include "cmSystemTools.h" +#include "cmStringAlgorithms.h" #include <string> #include <vector> @@ -29,7 +29,7 @@ std::string CMakeToWixPath(const std::string& cygpath) return cygpath; } - return cmSystemTools::TrimWhitespace(winpath_chars.data()); + return cmTrimWhitespace(winpath_chars.data()); } #else std::string CMakeToWixPath(const std::string& path) diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx index 563de02..b5e287d 100644 --- a/Source/CPack/WiX/cmWIXAccessControlList.cxx +++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx @@ -4,6 +4,7 @@ #include "cmCPackGenerator.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmWIXAccessControlList::cmWIXAccessControlList( @@ -48,8 +49,7 @@ void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry) user = user_and_domain; } - std::vector<std::string> permissions = - cmSystemTools::tokenize(permission_string, ","); + std::vector<std::string> permissions = cmTokenize(permission_string, ","); this->SourceWriter.BeginElement("Permission"); this->SourceWriter.AddAttribute("User", user); @@ -57,8 +57,7 @@ void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry) this->SourceWriter.AddAttribute("Domain", domain); } for (std::string const& permission : permissions) { - this->EmitBooleanAttribute(entry, - cmSystemTools::TrimWhitespace(permission)); + this->EmitBooleanAttribute(entry, cmTrimWhitespace(permission)); } this->SourceWriter.EndElement("Permission"); } diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index 7a5b8d1..f8d9f1b 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -24,7 +24,6 @@ #include "cmCTestUploadCommand.h" #include "cmCommand.h" #include "cmDuration.h" -#include "cmFunctionBlocker.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -49,32 +48,8 @@ # include <unistd.h> #endif -class cmExecutionStatus; -struct cmListFileFunction; - #define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log" -// used to keep elapsed time up to date -class cmCTestScriptFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus& /*status*/) override; - // virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf); - // virtual void ScopeEnded(cmMakefile &mf); - - cmCTestScriptHandler* CTestScriptHandler; -}; - -// simply update the time and don't block anything -bool cmCTestScriptFunctionBlocker::IsFunctionBlocked( - const cmListFileFunction& /*lff*/, cmMakefile& /*mf*/, - cmExecutionStatus& /*status*/) -{ - this->CTestScriptHandler->UpdateElapsedTime(); - return false; -} - cmCTestScriptHandler::cmCTestScriptHandler() { this->Backup = false; @@ -373,12 +348,8 @@ int cmCTestScriptHandler::ReadInScript(const std::string& total_script_arg) this->Makefile->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0"); #endif - // always add a function blocker to update the elapsed time - { - auto fb = cm::make_unique<cmCTestScriptFunctionBlocker>(); - fb->CTestScriptHandler = this; - this->Makefile->AddFunctionBlocker(std::move(fb)); - } + // set a callback function to update the elapsed time + this->Makefile->OnExecuteCommand([this] { this->UpdateElapsedTime(); }); /* Execute CTestScriptMode.cmake, which loads CMakeDetermineSystem and CMakeSystemSpecificInformation, so diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index ca29967..5583520 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -5,6 +5,7 @@ #include "cmCommandArgumentLexer.h" #include "cmMakefile.h" #include "cmState.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include <iostream> @@ -58,7 +59,7 @@ const char* cmCommandArgumentParserHelper::ExpandSpecialVariable( std::string str; if (cmSystemTools::GetEnv(var, str)) { if (this->EscapeQuotes) { - return this->AddString(cmSystemTools::EscapeQuotes(str)); + return this->AddString(cmEscapeQuotes(str)); } return this->AddString(str); } @@ -68,7 +69,7 @@ const char* cmCommandArgumentParserHelper::ExpandSpecialVariable( if (const std::string* c = this->Makefile->GetState()->GetInitializedCacheValue(var)) { if (this->EscapeQuotes) { - return this->AddString(cmSystemTools::EscapeQuotes(*c)); + return this->AddString(cmEscapeQuotes(*c)); } return this->AddString(*c); } @@ -99,7 +100,7 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) } } if (this->EscapeQuotes && value) { - return this->AddString(cmSystemTools::EscapeQuotes(value)); + return this->AddString(cmEscapeQuotes(value)); } return this->AddString(value ? value : ""); } diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 78cddf0..5f46631 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -990,11 +990,6 @@ void cmComputeLinkInformation::AddTargetItem(std::string const& item, return; } - // If this platform wants a flag before the full path, add it. - if (!this->LibLinkFileFlag.empty()) { - this->Items.emplace_back(this->LibLinkFileFlag, false); - } - // For compatibility with CMake 2.4 include the item's directory in // the linker search path. if (this->OldLinkDirMode && !target->IsFrameworkOnApple() && @@ -1057,11 +1052,6 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item) this->OldLinkDirItems.push_back(item); } - // If this platform wants a flag before the full path, add it. - if (!this->LibLinkFileFlag.empty()) { - this->Items.emplace_back(this->LibLinkFileFlag, false); - } - // Now add the full path to the library. this->Items.emplace_back(item, true); } diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 3be2c7f..784d3fa 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -56,6 +56,11 @@ public: std::string GetChrpathString() const; std::set<cmGeneratorTarget const*> const& GetSharedLibrariesLinked() const; + std::string const& GetLibLinkFileFlag() const + { + return this->LibLinkFileFlag; + } + std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; } std::string GetRPathLinkString() const; diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index d2a4148..e286ed7 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -238,7 +238,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (doing == DoingLinkOptions) { linkOptions.push_back(argv[i]); } else if (doing == DoingLinkLibraries) { - libsToLink += "\"" + cmSystemTools::TrimWhitespace(argv[i]) + "\" "; + libsToLink += "\"" + cmTrimWhitespace(argv[i]) + "\" "; if (cmTarget* tgt = this->Makefile->FindTargetToUse(argv[i])) { switch (tgt->GetType()) { case cmStateEnums::SHARED_LIBRARY: diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index e9ee7f5..e4b7670 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -21,6 +21,7 @@ #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetDepend.h" @@ -1144,12 +1145,9 @@ Json::Value Target::DumpInstallPrefix() Json::Value Target::DumpInstallDestinations() { Json::Value destinations = Json::arrayValue; - auto installGens = this->GT->Makefile->GetInstallGenerators(); - for (auto iGen : installGens) { - auto itGen = dynamic_cast<cmInstallTargetGenerator*>(iGen); - if (itGen != nullptr && itGen->GetTarget() == this->GT) { - destinations.append(this->DumpInstallDestination(itGen)); - } + auto installGens = this->GT->Target->GetInstallGenerators(); + for (auto itGen : installGens) { + destinations.append(this->DumpInstallDestination(itGen)); } return destinations; } @@ -1273,11 +1271,11 @@ Json::Value Target::DumpLinkCommandFragments() lg->GetTargetFlags(&linkLineComputer, this->Config, linkLibs, linkLanguageFlags, linkFlags, frameworkPath, linkPath, this->GT); - linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags); - linkFlags = cmSystemTools::TrimWhitespace(linkFlags); - frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath); - linkPath = cmSystemTools::TrimWhitespace(linkPath); - linkLibs = cmSystemTools::TrimWhitespace(linkLibs); + linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags); + linkFlags = cmTrimWhitespace(linkFlags); + frameworkPath = cmTrimWhitespace(frameworkPath); + linkPath = cmTrimWhitespace(linkPath); + linkLibs = cmTrimWhitespace(linkLibs); if (!linkLanguageFlags.empty()) { linkFragments.append( diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 04fbbad..0159ca5 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -517,7 +517,9 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, loadedPackage = true; } else { // The package was not loaded. Report errors. - HandlePackageMode(HandlePackageModeType::Module); + if (HandlePackageMode(HandlePackageModeType::Module)) { + loadedPackage = true; + } } } } else { diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 06dce2c..1d961be 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -8,16 +8,40 @@ #include <utility> #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" #include "cmSystemTools.h" +class cmForEachFunctionBlocker : public cmFunctionBlocker +{ +public: + cmForEachFunctionBlocker(cmMakefile* mf); + ~cmForEachFunctionBlocker() override; + + cm::string_view StartCommandName() const override { return "foreach"_s; } + cm::string_view EndCommandName() const override { return "endforeach"_s; } + + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const override; + + bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& inStatus) override; + + std::vector<std::string> Args; + +private: + cmMakefile* Makefile; +}; + cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf) : Makefile(mf) - , Depth(0) { this->Makefile->PushLoopBlock(); } @@ -27,89 +51,58 @@ cmForEachFunctionBlocker::~cmForEachFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) +bool cmForEachFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "foreach") { - // record the number of nested foreach commands - this->Depth++; - } else if (lff.Name.Lower == "endforeach") { - // if this is the endofreach for this statement - if (!this->Depth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr<cmFunctionBlocker> fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; - } + std::vector<std::string> expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; +} - // at end of for each execute recorded commands - // store the old value - std::string oldDef; - if (mf.GetDefinition(this->Args[0])) { - oldDef = mf.GetDefinition(this->Args[0]); - } +bool cmForEachFunctionBlocker::Replay( + std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // at end of for each execute recorded commands + // store the old value + std::string oldDef; + if (mf.GetDefinition(this->Args[0])) { + oldDef = mf.GetDefinition(this->Args[0]); + } - for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { - // set the variable to the loop value - mf.AddDefinition(this->Args[0], arg); - // Invoke all the functions that were collected in the block. - cmExecutionStatus status(mf); - for (cmListFileFunction const& func : this->Functions) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; - } - if (status.GetBreakInvoked()) { - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } + for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { + // set the variable to the loop value + mf.AddDefinition(this->Args[0], arg); + // Invoke all the functions that were collected in the block. + cmExecutionStatus status(mf); + for (cmListFileFunction const& func : functions) { + status.Clear(); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetBreakInvoked()) { + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; } - - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef); - return true; } - // close out a nested foreach - this->Depth--; } - // record the command - this->Functions.push_back(lff); - - // always return true + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); return true; } -bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) -{ - if (lff.Name.Lower == "endforeach") { - std::vector<std::string> expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments); - // if the endforeach has arguments then make sure - // they match the begin foreach arguments - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } - return false; -} - bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { diff --git a/Source/cmForEachCommand.h b/Source/cmForEachCommand.h index cd112b8..135abf0 100644 --- a/Source/cmForEachCommand.h +++ b/Source/cmForEachCommand.h @@ -11,28 +11,8 @@ #include "cm_memory.hxx" #include "cmCommand.h" -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" class cmExecutionStatus; -class cmMakefile; - -class cmForEachFunctionBlocker : public cmFunctionBlocker -{ -public: - cmForEachFunctionBlocker(cmMakefile* mf); - ~cmForEachFunctionBlocker() override; - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; - - std::vector<std::string> Args; - std::vector<cmListFileFunction> Functions; - -private: - cmMakefile* Makefile; - int Depth; -}; /// Starts foreach() ... endforeach() block class cmForEachCommand : public cmCommand diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx new file mode 100644 index 0000000..5778a71 --- /dev/null +++ b/Source/cmFunctionBlocker.cxx @@ -0,0 +1,46 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFunctionBlocker.h" + +#include <cassert> +#include <sstream> +#include <utility> + +#include "cmExecutionStatus.h" +#include "cmMakefile.h" +#include "cmMessageType.h" + +bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, + cmExecutionStatus& status) +{ + if (lff.Name.Lower == this->StartCommandName()) { + this->ScopeDepth++; + } else if (lff.Name.Lower == this->EndCommandName()) { + this->ScopeDepth--; + if (this->ScopeDepth == 0U) { + cmMakefile& mf = status.GetMakefile(); + auto self = mf.RemoveFunctionBlocker(); + assert(self.get() == this); + + if (!this->ArgumentsMatch(lff, mf)) { + cmListFileContext const& lfc = this->GetStartingContext(); + cmListFileContext closingContext = + cmListFileContext::FromCommandContext(lff, lfc.FilePath); + std::ostringstream e; + /* clang-format off */ + e << "A logical block opening on the line\n" + << " " << lfc << "\n" + << "closes on the line\n" + << " " << closingContext << "\n" + << "with mis-matching arguments."; + /* clang-format on */ + mf.IssueMessage(MessageType::AUTHOR_WARNING, e.str()); + } + + return this->Replay(std::move(this->Functions), status); + } + } + + this->Functions.push_back(lff); + return true; +} diff --git a/Source/cmFunctionBlocker.h b/Source/cmFunctionBlocker.h index cd6b05d..87bdccd 100644 --- a/Source/cmFunctionBlocker.h +++ b/Source/cmFunctionBlocker.h @@ -3,6 +3,12 @@ #ifndef cmFunctionBlocker_h #define cmFunctionBlocker_h +#include "cmConfigure.h" // IWYU pragma: keep + +#include <vector> + +#include "cm_string_view.hxx" + #include "cmListFileCache.h" class cmExecutionStatus; @@ -14,17 +20,8 @@ public: /** * should a function be blocked */ - virtual bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus& status) = 0; - - /** - * should this function blocker be removed, useful when one function adds a - * blocker and another must remove it - */ - virtual bool ShouldRemove(const cmListFileFunction&, cmMakefile&) - { - return false; - } + bool IsFunctionBlocked(cmListFileFunction const& lff, + cmExecutionStatus& status); virtual ~cmFunctionBlocker() = default; @@ -39,7 +36,19 @@ public: } private: + virtual cm::string_view StartCommandName() const = 0; + virtual cm::string_view EndCommandName() const = 0; + + virtual bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const = 0; + + virtual bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& status) = 0; + +private: cmListFileContext StartingContext; + std::vector<cmListFileFunction> Functions; + unsigned int ScopeDepth = 1; }; #endif diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 2809cf7..610f516 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -5,8 +5,13 @@ #include <sstream> #include <utility> +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" + #include "cmAlgorithms.h" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmRange.h" @@ -102,53 +107,42 @@ bool cmFunctionHelperCommand::operator()( return true; } -bool cmFunctionFunctionBlocker::IsFunctionBlocked( - const cmListFileFunction& lff, cmMakefile& mf, cmExecutionStatus&) +class cmFunctionFunctionBlocker : public cmFunctionBlocker { - // record commands until we hit the ENDFUNCTION - // at the ENDFUNCTION call we shift gears and start looking for invocations - if (lff.Name.Lower == "function") { - this->Depth++; - } else if (lff.Name.Lower == "endfunction") { - // if this is the endfunction for this function then execute - if (!this->Depth) { - // create a new command and add it to cmake - cmFunctionHelperCommand f; - f.Args = this->Args; - f.Functions = this->Functions; - f.FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - // remove the function blocker now that the function is defined - mf.RemoveFunctionBlocker(this, lff); - return true; - } - // decrement for each nested function that ends - this->Depth--; - } +public: + cm::string_view StartCommandName() const override { return "function"_s; } + cm::string_view EndCommandName() const override { return "endfunction"_s; } - // if it wasn't an endfunction and we are not executing then we must be - // recording - this->Functions.push_back(lff); - return true; -} + bool ArgumentsMatch(cmListFileFunction const&, + cmMakefile& mf) const override; -bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) + bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& status) override; + + std::vector<std::string> Args; +}; + +bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "endfunction") { - std::vector<std::string> expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments, - this->GetStartingContext().FilePath.c_str()); - // if the endfunction has arguments then make sure - // they match the ones in the opening function command - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } + std::vector<std::string> expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments, + this->GetStartingContext().FilePath.c_str()); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; +} - return false; +bool cmFunctionFunctionBlocker::Replay( + std::vector<cmListFileFunction> functions, cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + // create a new command and add it to cmake + cmFunctionHelperCommand f; + f.Args = this->Args; + f.Functions = std::move(functions); + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); + mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + return true; } bool cmFunctionCommand::InitialPass(std::vector<std::string> const& args, diff --git a/Source/cmFunctionCommand.h b/Source/cmFunctionCommand.h index 449a180..b334525 100644 --- a/Source/cmFunctionCommand.h +++ b/Source/cmFunctionCommand.h @@ -11,23 +11,8 @@ #include "cm_memory.hxx" #include "cmCommand.h" -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" class cmExecutionStatus; -class cmMakefile; - -class cmFunctionFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; - - std::vector<std::string> Args; - std::vector<cmListFileFunction> Functions; - int Depth = 0; -}; /// Starts function() ... endfunction() block class cmFunctionCommand : public cmCommand diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 7340bc2..03fc5ae 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3410,8 +3410,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( cmSystemTools::ParseUnixCommandLine( value.c_str() + LINKER_SHELL.length(), linkerOptions); } else { - linkerOptions = - cmSystemTools::tokenize(value.substr(LINKER.length()), ","); + linkerOptions = cmTokenize(value.substr(LINKER.length()), ","); } if (linkerOptions.empty() || @@ -5219,7 +5218,7 @@ void cmGeneratorTarget::ComputeLinkInterface( const std::string& config, cmOptionalLinkInterface& iface, cmGeneratorTarget const* headTarget) const { - if (iface.ExplicitLibraries) { + if (iface.Explicit) { if (this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::STATIC_LIBRARY || this->GetType() == cmStateEnums::INTERFACE_LIBRARY) { @@ -5603,8 +5602,9 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // libraries and executables that export symbols. const char* explicitLibraries = nullptr; std::string linkIfaceProp; - if (this->GetPolicyStatusCMP0022() != cmPolicies::OLD && - this->GetPolicyStatusCMP0022() != cmPolicies::WARN) { + bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD && + this->GetPolicyStatusCMP0022() != cmPolicies::WARN); + if (cmp0022NEW) { // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES. linkIfaceProp = "INTERFACE_LINK_LIBRARIES"; explicitLibraries = this->GetProperty(linkIfaceProp); @@ -5659,15 +5659,14 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( return; } iface.Exists = true; - iface.ExplicitLibraries = explicitLibraries; + iface.Explicit = cmp0022NEW || explicitLibraries != nullptr; if (explicitLibraries) { // The interface libraries have been explicitly set. this->ExpandLinkItems(linkIfaceProp, explicitLibraries, config, headTarget, usage_requirements_only, iface.Libraries, iface.HadHeadSensitiveCondition); - } else if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN || - this->GetPolicyStatusCMP0022() == cmPolicies::OLD) + } else if (!cmp0022NEW) // If CMP0022 is NEW then the plain tll signature sets the // INTERFACE_LINK_LIBRARIES, so if we get here then the project // cleared the property explicitly and we should not fall back diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index fc82535..c948b2a 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -4,6 +4,7 @@ #include "cmMakefile.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" class cmExecutionStatus; @@ -64,7 +65,7 @@ bool cmGetFilenameComponentCommand::InitialPass( // First assume the path to the program was specified with no // arguments and with no quoting or escaping for spaces. // Only bother doing this if there is non-whitespace. - if (!cmSystemTools::TrimWhitespace(filename).empty()) { + if (!cmTrimWhitespace(filename).empty()) { result = cmSystemTools::FindProgram(filename); } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 0b68966..9914d15 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -383,7 +383,7 @@ void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os, } // Do not add a variable if the value is empty. - std::string val = cmSystemTools::TrimWhitespace(value); + std::string val = cmTrimWhitespace(value); if (val.empty()) { return; } @@ -528,7 +528,7 @@ bool cmGlobalNinjaGenerator::FindMakeProgram(cmMakefile* mf) cmSystemTools::SetFatalErrorOccured(); return false; } - this->NinjaVersion = cmSystemTools::TrimWhitespace(version); + this->NinjaVersion = cmTrimWhitespace(version); this->CheckNinjaFeatures(); } return true; diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 4a3cadd..720b6c5 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -325,7 +325,7 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset( std::string const& ts, cmMakefile* mf) { - std::vector<std::string> const fields = cmSystemTools::tokenize(ts, ","); + std::vector<std::string> const fields = cmTokenize(ts, ","); std::vector<std::string>::const_iterator fi = fields.begin(); if (fi == fields.end()) { return true; diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index bead0e3..ca80d3b 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -518,9 +518,9 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( const std::string::size_type posEqual = itPair.find('='); if (posEqual != std::string::npos) { const std::string key = - cmSystemTools::TrimWhitespace(itPair.substr(0, posEqual)); + cmTrimWhitespace(itPair.substr(0, posEqual)); const std::string value = - cmSystemTools::TrimWhitespace(itPair.substr(posEqual + 1)); + cmTrimWhitespace(itPair.substr(posEqual + 1)); fout << "\t\t" << key << " = " << value << "\n"; if (key == "SolutionGuid") { addGuid = false; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 8f4ae62..f675c8e 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2945,8 +2945,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup( if (it != this->TargetGroup.end()) { tgroup = it->second; } else { - std::vector<std::string> tgt_folders = - cmSystemTools::tokenize(target, "/"); + std::vector<std::string> tgt_folders = cmTokenize(target, "/"); std::string curr_tgt_folder; for (std::vector<std::string>::size_type i = 0; i < tgt_folders.size(); i++) { @@ -2980,8 +2979,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateOrGetPBXGroup( if (sg->GetFullName() != sg->GetName()) { std::string curr_folder = target; curr_folder += "/"; - for (auto const& folder : - cmSystemTools::tokenize(sg->GetFullName(), "\\")) { + for (auto const& folder : cmTokenize(sg->GetFullName(), "\\")) { curr_folder += folder; std::map<std::string, cmXCodeObject*>::iterator i_folder = this->GroupNameMap.find(curr_folder); diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index 385022c..c5cfd8c 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -3,10 +3,14 @@ #include "cmIfCommand.h" #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" #include "cmExpandedCommandArgument.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmOutputConverter.h" @@ -28,152 +32,138 @@ static std::string cmIfCommandError( return err; } -//========================================================================= -bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) +class cmIfFunctionBlocker : public cmFunctionBlocker { - // we start by recording all the functions - if (lff.Name.Lower == "if") { - this->ScopeDepth++; - } else if (lff.Name.Lower == "endif") { - this->ScopeDepth--; - // if this is the endif for this if statement, then start executing - if (!this->ScopeDepth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr<cmFunctionBlocker> fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; +public: + cm::string_view StartCommandName() const override { return "if"_s; } + cm::string_view EndCommandName() const override { return "endif"_s; } + + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile&) const override; + + bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& inStatus) override; + + std::vector<cmListFileArgument> Args; + bool IsBlocking; + bool HasRun = false; + bool ElseSeen = false; +}; + +bool cmIfFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile&) const +{ + return lff.Arguments.empty() || lff.Arguments == this->Args; +} + +bool cmIfFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // execute the functions for the true parts of the if statement + cmExecutionStatus status(mf); + int scopeDepth = 0; + for (cmListFileFunction const& func : functions) { + // keep track of scope depth + if (func.Name.Lower == "if") { + scopeDepth++; + } + if (func.Name.Lower == "endif") { + scopeDepth--; + } + // watch for our state change + if (scopeDepth == 0 && func.Name.Lower == "else") { + + if (this->ElseSeen) { + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "A duplicate ELSE command was found inside an IF block.", bt); + cmSystemTools::SetFatalErrorOccured(); + return true; } - // execute the functions for the true parts of the if statement - cmExecutionStatus status(mf); - int scopeDepth = 0; - for (cmListFileFunction const& func : this->Functions) { - // keep track of scope depth - if (func.Name.Lower == "if") { - scopeDepth++; - } - if (func.Name.Lower == "endif") { - scopeDepth--; + this->IsBlocking = this->HasRun; + this->HasRun = true; + this->ElseSeen = true; + + // if trace is enabled, print a (trivially) evaluated "else" + // statement + if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) { + mf.PrintCommandTrace(func); + } + } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { + if (this->ElseSeen) { + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + "An ELSEIF command was found after an ELSE command.", bt); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + + if (this->HasRun) { + this->IsBlocking = true; + } else { + // if trace is enabled, print the evaluated "elseif" statement + if (mf.GetCMakeInstance()->GetTrace()) { + mf.PrintCommandTrace(func); } - // watch for our state change - if (scopeDepth == 0 && func.Name.Lower == "else") { - - if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, - "A duplicate ELSE command was found inside an IF block.", bt); - cmSystemTools::SetFatalErrorOccured(); - return true; - } - this->IsBlocking = this->HasRun; - this->HasRun = true; - this->ElseSeen = true; + std::string errorString; - // if trace is enabled, print a (trivially) evaluated "else" - // statement - if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) { - mf.PrintCommandTrace(func); - } - } else if (scopeDepth == 0 && func.Name.Lower == "elseif") { - if (this->ElseSeen) { - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage( - MessageType::FATAL_ERROR, - "An ELSEIF command was found after an ELSE command.", bt); + std::vector<cmExpandedCommandArgument> expandedArguments; + mf.ExpandArguments(func.Arguments, expandedArguments); + + MessageType messType; + + cmListFileContext conditionContext = + cmListFileContext::FromCommandContext( + func, this->GetStartingContext().FilePath); + + cmConditionEvaluator conditionEvaluator(mf, conditionContext, + mf.GetBacktrace(func)); + + bool isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messType); + + if (!errorString.empty()) { + std::string err = cmIfCommandError(expandedArguments); + err += errorString; + cmListFileBacktrace bt = mf.GetBacktrace(func); + mf.GetCMakeInstance()->IssueMessage(messType, err, bt); + if (messType == MessageType::FATAL_ERROR) { cmSystemTools::SetFatalErrorOccured(); return true; } - - if (this->HasRun) { - this->IsBlocking = true; - } else { - // if trace is enabled, print the evaluated "elseif" statement - if (mf.GetCMakeInstance()->GetTrace()) { - mf.PrintCommandTrace(func); - } - - std::string errorString; - - std::vector<cmExpandedCommandArgument> expandedArguments; - mf.ExpandArguments(func.Arguments, expandedArguments); - - MessageType messType; - - cmListFileContext conditionContext = - cmListFileContext::FromCommandContext( - func, this->GetStartingContext().FilePath); - - cmConditionEvaluator conditionEvaluator(mf, conditionContext, - mf.GetBacktrace(func)); - - bool isTrue = conditionEvaluator.IsTrue(expandedArguments, - errorString, messType); - - if (!errorString.empty()) { - std::string err = cmIfCommandError(expandedArguments); - err += errorString; - cmListFileBacktrace bt = mf.GetBacktrace(func); - mf.GetCMakeInstance()->IssueMessage(messType, err, bt); - if (messType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } - - if (isTrue) { - this->IsBlocking = false; - this->HasRun = true; - } - } } - // should we execute? - else if (!this->IsBlocking) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - return true; - } - if (status.GetBreakInvoked()) { - inStatus.SetBreakInvoked(); - return true; - } - if (status.GetContinueInvoked()) { - inStatus.SetContinueInvoked(); - return true; - } + if (isTrue) { + this->IsBlocking = false; + this->HasRun = true; } } - return true; } - } - // record the command - this->Functions.push_back(lff); - - // always return true - return true; -} - -//========================================================================= -bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile&) -{ - if (lff.Name.Lower == "endif") { - // if the endif has arguments, then make sure - // they match the arguments of the matching if - if (lff.Arguments.empty() || lff.Arguments == this->Args) { - return true; + // should we execute? + else if (!this->IsBlocking) { + status.Clear(); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + return true; + } + if (status.GetBreakInvoked()) { + inStatus.SetBreakInvoked(); + return true; + } + if (status.GetContinueInvoked()) { + inStatus.SetContinueInvoked(); + return true; + } } } - - return false; + return true; } //========================================================================= @@ -208,7 +198,6 @@ bool cmIfCommand(std::vector<cmListFileArgument> const& args, { auto fb = cm::make_unique<cmIfFunctionBlocker>(); // if is isn't true block the commands - fb->ScopeDepth = 1; fb->IsBlocking = !isTrue; if (isTrue) { fb->HasRun = true; diff --git a/Source/cmIfCommand.h b/Source/cmIfCommand.h index 775e609..820ffa4 100644 --- a/Source/cmIfCommand.h +++ b/Source/cmIfCommand.h @@ -7,26 +7,8 @@ #include <vector> -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" - class cmExecutionStatus; -class cmMakefile; - -class cmIfFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; - - std::vector<cmListFileArgument> Args; - std::vector<cmListFileFunction> Functions; - bool IsBlocking; - bool HasRun = false; - bool ElseSeen = false; - unsigned int ScopeDepth = 0; -}; +struct cmListFileArgument; /// Starts an if block bool cmIfCommand(std::vector<cmListFileArgument> const& args, diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index aca7268..5349a9d 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -43,11 +43,13 @@ static cmInstallTargetGenerator* CreateInstallTargetGenerator( target.SetHaveInstallRule(true); const char* component = namelink ? args.GetNamelinkComponent().c_str() : args.GetComponent().c_str(); - return new cmInstallTargetGenerator( + auto g = new cmInstallTargetGenerator( target.GetName(), destination.c_str(), impLib, args.GetPermissions().c_str(), args.GetConfigurations(), component, message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt, backtrace); + target.AddInstallGenerator(g); + return g; } static cmInstallTargetGenerator* CreateInstallTargetGenerator( diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx index 2423faf..953333c 100644 --- a/Source/cmJsonObjects.cxx +++ b/Source/cmJsonObjects.cxx @@ -20,6 +20,7 @@ #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTest.h" @@ -541,19 +542,19 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags, linkFlags, frameworkPath, linkPath, target); - linkLibs = cmSystemTools::TrimWhitespace(linkLibs); - linkFlags = cmSystemTools::TrimWhitespace(linkFlags); - linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags); - frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath); - linkPath = cmSystemTools::TrimWhitespace(linkPath); + linkLibs = cmTrimWhitespace(linkLibs); + linkFlags = cmTrimWhitespace(linkFlags); + linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags); + frameworkPath = cmTrimWhitespace(frameworkPath); + linkPath = cmTrimWhitespace(linkPath); - if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) { + if (!cmTrimWhitespace(linkLibs).empty()) { result[kLINK_LIBRARIES_KEY] = linkLibs; } - if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) { + if (!cmTrimWhitespace(linkFlags).empty()) { result[kLINK_FLAGS_KEY] = linkFlags; } - if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) { + if (!cmTrimWhitespace(linkLanguageFlags).empty()) { result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags; } if (!frameworkPath.empty()) { diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 6450c62..d71ff49 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -87,7 +87,7 @@ struct cmOptionalLinkInterface : public cmLinkInterface bool LibrariesDone = false; bool AllDone = false; bool Exists = false; - const char* ExplicitLibraries = nullptr; + bool Explicit = false; }; struct cmHeadToLinkInterfaceMap diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx index 8746b35..4430f97 100644 --- a/Source/cmLinkLineComputer.cxx +++ b/Source/cmLinkLineComputer.cxx @@ -63,6 +63,7 @@ std::string cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation& cli) continue; } if (item.IsPath) { + linkLibs += cli.GetLibLinkFileFlag(); linkLibs += this->ConvertToOutputFormat(this->ConvertToLinkReference(item.Value)); } else { diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index 8c14596..1f748ca 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -855,7 +855,7 @@ bool cmListCommand::HandleTransformCommand( { "STRIP", 0, [&command](const std::string& s) -> std::string { if (command.Selector->InSelection(s)) { - return cmSystemTools::TrimWhitespace(s); + return cmTrimWhitespace(s); } return s; diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 1f2b5b2..8689c8f 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -7,9 +7,13 @@ #include <utility> #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmAlgorithms.h" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmRange.h" @@ -136,55 +140,43 @@ bool cmMacroHelperCommand::operator()( return true; } -bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus&) +class cmMacroFunctionBlocker : public cmFunctionBlocker { - // record commands until we hit the ENDMACRO - // at the ENDMACRO call we shift gears and start looking for invocations - if (lff.Name.Lower == "macro") { - this->Depth++; - } else if (lff.Name.Lower == "endmacro") { - // if this is the endmacro for this macro then execute - if (!this->Depth) { - mf.AppendProperty("MACROS", this->Args[0].c_str()); - // create a new command and add it to cmake - cmMacroHelperCommand f; - f.Args = this->Args; - f.Functions = this->Functions; - f.FilePath = this->GetStartingContext().FilePath; - mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - // remove the function blocker now that the macro is defined - mf.RemoveFunctionBlocker(this, lff); - return true; - } - // decrement for each nested macro that ends - this->Depth--; - } +public: + cm::string_view StartCommandName() const override { return "macro"_s; } + cm::string_view EndCommandName() const override { return "endmacro"_s; } - // if it wasn't an endmacro and we are not executing then we must be - // recording - this->Functions.push_back(lff); - return true; -} + bool ArgumentsMatch(cmListFileFunction const&, + cmMakefile& mf) const override; + + bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& status) override; + + std::vector<std::string> Args; +}; -bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) +bool cmMacroFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "endmacro") { - std::vector<std::string> expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments, - this->GetStartingContext().FilePath.c_str()); - // if the endmacro has arguments make sure they - // match the arguments of the macro - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } + std::vector<std::string> expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments, + this->GetStartingContext().FilePath.c_str()); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; +} - return false; +bool cmMacroFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& status) +{ + cmMakefile& mf = status.GetMakefile(); + mf.AppendProperty("MACROS", this->Args[0].c_str()); + // create a new command and add it to cmake + cmMacroHelperCommand f; + f.Args = this->Args; + f.Functions = std::move(functions); + f.FilePath = this->GetStartingContext().FilePath; + mf.RecordPolicies(f.Policies); + mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); + return true; } bool cmMacroCommand::InitialPass(std::vector<std::string> const& args, diff --git a/Source/cmMacroCommand.h b/Source/cmMacroCommand.h index 3ebd959..0d7083a 100644 --- a/Source/cmMacroCommand.h +++ b/Source/cmMacroCommand.h @@ -11,23 +11,8 @@ #include "cm_memory.hxx" #include "cmCommand.h" -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" class cmExecutionStatus; -class cmMakefile; - -class cmMacroFunctionBlocker : public cmFunctionBlocker -{ -public: - bool IsFunctionBlocked(const cmListFileFunction&, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction&, cmMakefile& mf) override; - - std::vector<std::string> Args; - std::vector<cmListFileFunction> Functions; - int Depth = 0; -}; /// Starts macro() ... endmacro() block class cmMacroCommand : public cmCommand diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8188ffa..86a002f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -353,6 +353,11 @@ private: cmMakefile* Makefile; }; +void cmMakefile::OnExecuteCommand(std::function<void()> callback) +{ + this->ExecuteCommandCallback = std::move(callback); +} + bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, cmExecutionStatus& status) { @@ -364,6 +369,10 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, return result; } + if (this->ExecuteCommandCallback) { + this->ExecuteCommandCallback(); + } + // Place this call on the call stack. cmMakefileCall stack_manager(this, lff, status); static_cast<void>(stack_manager); @@ -2166,8 +2175,7 @@ cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name) if (delimiter == nullptr) { delimiter = "\\"; } - return this->GetOrCreateSourceGroup( - cmSystemTools::tokenize(name, delimiter)); + return this->GetOrCreateSourceGroup(cmTokenize(name, delimiter)); } /** @@ -2659,7 +2667,7 @@ MessageType cmMakefile::ExpandVariablesInStringOld( if (const char* val = this->GetDefinition(var)) { // Store the value in the output escaping as requested. if (escapeQuotes) { - source.append(cmSystemTools::EscapeQuotes(val)); + source.append(cmEscapeQuotes(val)); } else { source.append(val); } @@ -2823,7 +2831,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew( // Get the string we're meant to append to. if (value) { if (escapeQuotes) { - varresult = cmSystemTools::EscapeQuotes(value); + varresult = cmEscapeQuotes(value); } else { varresult = value; } @@ -2949,7 +2957,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew( } if (escapeQuotes) { - varresult = cmSystemTools::EscapeQuotes(varresult); + varresult = cmEscapeQuotes(varresult); } // Skip over the variable. result.append(last, in - last); @@ -3061,7 +3069,7 @@ bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff, return false; } - return this->FunctionBlockers.top()->IsFunctionBlocked(lff, *this, status); + return this->FunctionBlockers.top()->IsFunctionBlocked(lff, status); } void cmMakefile::PushFunctionBlockerBarrier() @@ -3211,30 +3219,12 @@ void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb) this->FunctionBlockers.push(std::move(fb)); } -std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker( - cmFunctionBlocker* fb, const cmListFileFunction& lff) +std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker() { assert(!this->FunctionBlockers.empty()); - assert(this->FunctionBlockers.top().get() == fb); assert(this->FunctionBlockerBarriers.empty() || this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back()); - // Warn if the arguments do not match, but always remove. - if (!fb->ShouldRemove(lff, *this)) { - cmListFileContext const& lfc = fb->GetStartingContext(); - cmListFileContext closingContext = - cmListFileContext::FromCommandContext(lff, lfc.FilePath); - std::ostringstream e; - /* clang-format off */ - e << "A logical block opening on the line\n" - << " " << lfc << "\n" - << "closes on the line\n" - << " " << closingContext << "\n" - << "with mis-matching arguments."; - /* clang-format on */ - this->IssueMessage(MessageType::AUTHOR_WARNING, e.str()); - } - auto b = std::move(this->FunctionBlockers.top()); this->FunctionBlockers.pop(); return b; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index dc196ac..4d61c05 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -107,8 +107,7 @@ public: * Remove the function blocker whose scope ends with the given command. * This returns ownership of the function blocker object. */ - std::unique_ptr<cmFunctionBlocker> RemoveFunctionBlocker( - cmFunctionBlocker* fb, const cmListFileFunction& lff); + std::unique_ptr<cmFunctionBlocker> RemoveFunctionBlocker(); /** * Try running cmake and building a file. This is used for dynalically @@ -628,6 +627,11 @@ public: void PrintCommandTrace(const cmListFileFunction& lff) const; /** + * Set a callback that is invoked whenever ExecuteCommand is called. + */ + void OnExecuteCommand(std::function<void()> callback); + + /** * Execute a single CMake command. Returns true if the command * succeeded or false if it failed. */ @@ -964,6 +968,7 @@ private: bool EnforceUniqueDir(const std::string& srcPath, const std::string& binPath) const; + std::function<void()> ExecuteCommandCallback; using FunctionBlockerPtr = std::unique_ptr<cmFunctionBlocker>; using FunctionBlockersType = std::stack<FunctionBlockerPtr, std::vector<FunctionBlockerPtr>>; diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index ffdd0ce..0f69c84 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -21,7 +21,7 @@ const std::string kSourceGroupOptionName = "<sg_name>"; std::vector<std::string> tokenizePath(const std::string& path) { - return cmSystemTools::tokenize(path, "\\/"); + return cmTokenize(path, "\\/"); } std::string getFullFilePath(const std::string& currentPath, diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index 5deb9b0..5867a44 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -5,6 +5,59 @@ #include <algorithm> #include <cstdio> +std::string cmTrimWhitespace(cm::string_view str) +{ + auto start = str.begin(); + while (start != str.end() && cmIsSpace(*start)) { + ++start; + } + if (start == str.end()) { + return std::string(); + } + auto stop = str.end() - 1; + while (cmIsSpace(*stop)) { + --stop; + } + return std::string(start, stop + 1); +} + +std::string cmEscapeQuotes(cm::string_view str) +{ + std::string result; + result.reserve(str.size()); + for (const char ch : str) { + if (ch == '"') { + result += '\\'; + } + result += ch; + } + return result; +} + +std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep) +{ + std::vector<std::string> tokens; + cm::string_view::size_type tokend = 0; + + do { + cm::string_view::size_type tokstart = str.find_first_not_of(sep, tokend); + if (tokstart == cm::string_view::npos) { + break; // no more tokens + } + tokend = str.find_first_of(sep, tokstart); + if (tokend == cm::string_view::npos) { + tokens.emplace_back(str.substr(tokstart)); + } else { + tokens.emplace_back(str.substr(tokstart, tokend - tokstart)); + } + } while (tokend != cm::string_view::npos); + + if (tokens.empty()) { + tokens.emplace_back(); + } + return tokens; +} + namespace { template <std::size_t N, typename T> inline void MakeDigits(cm::string_view& view, char (&digits)[N], diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index cdb494f..1898649 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -7,6 +7,7 @@ #include "cmRange.h" #include "cm_string_view.hxx" +#include <cctype> #include <initializer_list> #include <sstream> #include <string.h> @@ -31,6 +32,18 @@ private: std::string const Test_; }; +/** Returns true if the character @a ch is a whitespace character. **/ +inline bool cmIsSpace(char ch) +{ + return ((ch & 0x80) == 0) && std::isspace(ch); +} + +/** Returns a string that has whitespace removed from the start and the end. */ +std::string cmTrimWhitespace(cm::string_view str); + +/** Escape quotes in a string. */ +std::string cmEscapeQuotes(cm::string_view str); + /** Joins elements of a range with separator into a single string. */ template <typename Range> std::string cmJoin(Range const& rng, cm::string_view separator) @@ -49,6 +62,9 @@ std::string cmJoin(Range const& rng, cm::string_view separator) return os.str(); } +/** Extract tokens that are separated by any of the characters in @a sep. */ +std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep); + /** Concatenate string pieces into a single string. */ std::string cmCatViews(std::initializer_list<cm::string_view> views); diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 5f4e1fc..aed787e 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -84,11 +84,6 @@ cmSystemTools::OutputCallback s_StdoutCallback; } // namespace -static bool cm_isspace(char c) -{ - return ((c & 0x80) == 0) && isspace(c); -} - #if !defined(HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE) // For GetEnvironmentVariables # if defined(_WIN32) @@ -177,19 +172,6 @@ void cmSystemTools::ExpandRegistryValues(std::string& source, } #endif -std::string cmSystemTools::EscapeQuotes(cm::string_view str) -{ - std::string result; - result.reserve(str.size()); - for (const char ch : str) { - if (ch == '"') { - result += '\\'; - } - result += ch; - } - return result; -} - std::string cmSystemTools::HelpFileName(cm::string_view str) { std::string name(str); @@ -198,22 +180,6 @@ std::string cmSystemTools::HelpFileName(cm::string_view str) return name; } -std::string cmSystemTools::TrimWhitespace(cm::string_view str) -{ - auto start = str.begin(); - while (start != str.end() && cm_isspace(*start)) { - ++start; - } - if (start == str.end()) { - return std::string(); - } - auto stop = str.end() - 1; - while (cm_isspace(*stop)) { - --stop; - } - return std::string(start, stop + 1); -} - void cmSystemTools::Error(const std::string& m) { std::string message = "CMake Error: " + m; @@ -396,7 +362,7 @@ void cmSystemTools::ParseWindowsCommandLine(const char* command, } else { arg.append(backslashes, '\\'); backslashes = 0; - if (cm_isspace(*c)) { + if (cmIsSpace(*c)) { if (in_quotes) { arg.append(1, *c); } else if (in_argument) { @@ -2882,31 +2848,6 @@ bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir) return false; } -std::vector<std::string> cmSystemTools::tokenize(const std::string& str, - const std::string& sep) -{ - std::vector<std::string> tokens; - std::string::size_type tokend = 0; - - do { - std::string::size_type tokstart = str.find_first_not_of(sep, tokend); - if (tokstart == std::string::npos) { - break; // no more tokens - } - tokend = str.find_first_of(sep, tokstart); - if (tokend == std::string::npos) { - tokens.push_back(str.substr(tokstart)); - } else { - tokens.push_back(str.substr(tokstart, tokend - tokstart)); - } - } while (tokend != std::string::npos); - - if (tokens.empty()) { - tokens.emplace_back(); - } - return tokens; -} - bool cmSystemTools::StringToLong(const char* str, long* value) { errno = 0; diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index ac1aa80..d3fcb64 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -77,17 +77,9 @@ public: static void ExpandRegistryValues(std::string& source, KeyWOW64 view = KeyWOW64_Default); - //! Escape quotes in a string. - static std::string EscapeQuotes(cm::string_view str); - /** Map help document name to file name. */ static std::string HelpFileName(cm::string_view); - /** - * Returns a string that has whitespace removed from the start and the end. - */ - static std::string TrimWhitespace(cm::string_view str); - using MessageCallback = std::function<void(const std::string&, const char*)>; /** * Set the function used by GUIs to display error messages @@ -508,10 +500,6 @@ public: /** Remove a directory; repeat a few times in case of locked files. */ static bool RepeatedRemoveDirectory(const std::string& dir); - /** Tokenize a string */ - static std::vector<std::string> tokenize(const std::string& str, - const std::string& sep); - /** Convert string to long. Expected that the whole string is an integer */ static bool StringToLong(const char* str, long* value); static bool StringToULong(const char* str, unsigned long* value); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index beccfce..7ca2391 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -180,6 +180,7 @@ public: std::vector<cmCustomCommand> PreBuildCommands; std::vector<cmCustomCommand> PreLinkCommands; std::vector<cmCustomCommand> PostBuildCommands; + std::vector<cmInstallTargetGenerator*> InstallGenerators; std::set<std::string> SystemIncludeDirectories; cmTarget::LinkLibraryVectorType OriginalLinkLibraries; std::vector<std::string> IncludeDirectoriesEntries; @@ -873,6 +874,17 @@ void cmTarget::SetHaveInstallRule(bool hir) impl->HaveInstallRule = hir; } +void cmTarget::AddInstallGenerator(cmInstallTargetGenerator* g) +{ + impl->InstallGenerators.emplace_back(g); +} + +std::vector<cmInstallTargetGenerator*> const& cmTarget::GetInstallGenerators() + const +{ + return impl->InstallGenerators; +} + bool cmTarget::GetIsGeneratorProvided() const { return impl->IsGeneratorProvided; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 4e5141b..2b75879 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -21,6 +21,7 @@ class cmCustomCommand; class cmGlobalGenerator; +class cmInstallTargetGenerator; class cmMakefile; class cmMessenger; class cmPropertyMap; @@ -147,6 +148,9 @@ public: bool GetHaveInstallRule() const; void SetHaveInstallRule(bool hir); + void AddInstallGenerator(cmInstallTargetGenerator* g); + std::vector<cmInstallTargetGenerator*> const& GetInstallGenerators() const; + /** * Get/Set whether this target was auto-created by a generator. */ diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index c78361e..20f5e2f 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVSSetupHelper.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" @@ -195,7 +196,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) { return false; } - vcToolsVersion = cmSystemTools::TrimWhitespace(vcToolsVersion); + vcToolsVersion = cmTrimWhitespace(vcToolsVersion); std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion; if (!cmSystemTools::FileIsDirectory(vcToolsDir)) { return false; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index e1b0c70..6c28996 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -193,7 +193,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() std::string arch_name = arch[0]; std::vector<std::string> codes; if (!code.empty()) { - codes = cmSystemTools::tokenize(code[0], ","); + codes = cmTokenize(code[0], ","); } if (codes.empty()) { codes.push_back(arch_name); @@ -220,7 +220,7 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() cmSystemTools::ReplaceString(entry, "]", ""); cmSystemTools::ReplaceString(entry, "\"", ""); - std::vector<std::string> codes = cmSystemTools::tokenize(entry, ","); + std::vector<std::string> codes = cmTokenize(entry, ","); if (codes.size() >= 2) { auto gencode_arch = cm::cbegin(codes); for (auto ci = gencode_arch + 1; ci != cm::cend(codes); ++ci) { diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx index 3e7e142..9eaee11 100644 --- a/Source/cmVisualStudioSlnParser.cxx +++ b/Source/cmVisualStudioSlnParser.cxx @@ -463,7 +463,7 @@ bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, cmSlnData& output, if (!this->ParseBOM(input, line, state)) return false; do { - line = cmSystemTools::TrimWhitespace(line); + line = cmTrimWhitespace(line); if (line.empty()) continue; ParsedLine parsedLine; @@ -579,9 +579,9 @@ bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line, return true; } const std::string& key = line.substr(0, idxEqualSign); - parsedLine.SetTag(cmSystemTools::TrimWhitespace(key)); + parsedLine.SetTag(cmTrimWhitespace(key)); const std::string& value = line.substr(idxEqualSign + 1); - parsedLine.AddValue(cmSystemTools::TrimWhitespace(value)); + parsedLine.AddValue(cmTrimWhitespace(value)); return true; } @@ -590,18 +590,17 @@ bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag, { size_t idxLeftParen = fullTag.find('('); if (idxLeftParen == fullTag.npos) { - parsedLine.SetTag(cmSystemTools::TrimWhitespace(fullTag)); + parsedLine.SetTag(cmTrimWhitespace(fullTag)); return true; } - parsedLine.SetTag( - cmSystemTools::TrimWhitespace(fullTag.substr(0, idxLeftParen))); + parsedLine.SetTag(cmTrimWhitespace(fullTag.substr(0, idxLeftParen))); size_t idxRightParen = fullTag.rfind(')'); if (idxRightParen == fullTag.npos) { this->LastResult.SetError(ResultErrorInputStructure, state.GetCurrentLine()); return false; } - const std::string& arg = cmSystemTools::TrimWhitespace( + const std::string& arg = cmTrimWhitespace( fullTag.substr(idxLeftParen + 1, idxRightParen - idxLeftParen - 1)); if (arg.front() == '"') { if (arg.back() != '"') { @@ -618,7 +617,7 @@ bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag, bool cmVisualStudioSlnParser::ParseValue(const std::string& value, ParsedLine& parsedLine) { - const std::string& trimmed = cmSystemTools::TrimWhitespace(value); + const std::string& trimmed = cmTrimWhitespace(value); if (trimmed.empty()) parsedLine.AddValue(trimmed); else if (trimmed.front() == '"' && trimmed.back() == '"') diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 37d1c74..a396852 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -3,10 +3,14 @@ #include "cmWhileCommand.h" #include "cm_memory.hxx" +#include "cm_static_string_view.hxx" +#include "cm_string_view.hxx" #include "cmConditionEvaluator.h" #include "cmExecutionStatus.h" #include "cmExpandedCommandArgument.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSystemTools.h" @@ -14,9 +18,29 @@ #include <string> #include <utility> +class cmWhileFunctionBlocker : public cmFunctionBlocker +{ +public: + cmWhileFunctionBlocker(cmMakefile* mf); + ~cmWhileFunctionBlocker() override; + + cm::string_view StartCommandName() const override { return "while"_s; } + cm::string_view EndCommandName() const override { return "endwhile"_s; } + + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const override; + + bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& inStatus) override; + + std::vector<cmListFileArgument> Args; + +private: + cmMakefile* Makefile; +}; + cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf) : Makefile(mf) - , Depth(0) { this->Makefile->PushLoopBlock(); } @@ -26,108 +50,77 @@ cmWhileFunctionBlocker::~cmWhileFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) +bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile&) const { - // at end of for each execute recorded commands - if (lff.Name.Lower == "while") { - // record the number of while commands past this one - this->Depth++; - } else if (lff.Name.Lower == "endwhile") { - // if this is the endwhile for this while loop then execute - if (!this->Depth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr<cmFunctionBlocker> fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; - } + return lff.Arguments.empty() || lff.Arguments == this->Args; +} - std::string errorString; - - std::vector<cmExpandedCommandArgument> expandedArguments; - mf.ExpandArguments(this->Args, expandedArguments); - MessageType messageType; - - cmListFileContext execContext = this->GetStartingContext(); - - cmCommandContext commandContext; - commandContext.Line = execContext.Line; - commandContext.Name = execContext.Name; - - cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), - mf.GetBacktrace(commandContext)); - - bool isTrue = - conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); - - while (isTrue) { - if (!errorString.empty()) { - std::string err = "had incorrect arguments: "; - for (cmListFileArgument const& arg : this->Args) { - err += (arg.Delim ? "\"" : ""); - err += arg.Value; - err += (arg.Delim ? "\"" : ""); - err += " "; - } - err += "("; - err += errorString; - err += ")."; - mf.IssueMessage(messageType, err); - if (messageType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } - - // Invoke all the functions that were collected in the block. - for (cmListFileFunction const& fn : this->Functions) { - cmExecutionStatus status(mf); - mf.ExecuteCommand(fn, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - return true; - } - if (status.GetBreakInvoked()) { - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } - expandedArguments.clear(); - mf.ExpandArguments(this->Args, expandedArguments); - isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString, - messageType); - } - return true; - } - // decrement for each nested while that ends - this->Depth--; - } +bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + std::string errorString; - // record the command - this->Functions.push_back(lff); + std::vector<cmExpandedCommandArgument> expandedArguments; + mf.ExpandArguments(this->Args, expandedArguments); + MessageType messageType; - // always return true - return true; -} + cmListFileContext execContext = this->GetStartingContext(); -bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile&) -{ - if (lff.Name.Lower == "endwhile") { - // if the endwhile has arguments, then make sure - // they match the arguments of the matching while - if (lff.Arguments.empty() || lff.Arguments == this->Args) { - return true; + cmCommandContext commandContext; + commandContext.Line = execContext.Line; + commandContext.Name = execContext.Name; + + cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(), + mf.GetBacktrace(commandContext)); + + bool isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); + + while (isTrue) { + if (!errorString.empty()) { + std::string err = "had incorrect arguments: "; + for (cmListFileArgument const& arg : this->Args) { + err += (arg.Delim ? "\"" : ""); + err += arg.Value; + err += (arg.Delim ? "\"" : ""); + err += " "; + } + err += "("; + err += errorString; + err += ")."; + mf.IssueMessage(messageType, err); + if (messageType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccured(); + return true; + } } + + // Invoke all the functions that were collected in the block. + for (cmListFileFunction const& fn : functions) { + cmExecutionStatus status(mf); + mf.ExecuteCommand(fn, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + return true; + } + if (status.GetBreakInvoked()) { + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; + } + } + expandedArguments.clear(); + mf.ExpandArguments(this->Args, expandedArguments); + isTrue = + conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); } - return false; + return true; } bool cmWhileCommand(std::vector<cmListFileArgument> const& args, diff --git a/Source/cmWhileCommand.h b/Source/cmWhileCommand.h index 2257799..beca652 100644 --- a/Source/cmWhileCommand.h +++ b/Source/cmWhileCommand.h @@ -7,28 +7,8 @@ #include <vector> -#include "cmFunctionBlocker.h" -#include "cmListFileCache.h" - class cmExecutionStatus; -class cmMakefile; - -class cmWhileFunctionBlocker : public cmFunctionBlocker -{ -public: - cmWhileFunctionBlocker(cmMakefile* mf); - ~cmWhileFunctionBlocker() override; - bool IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile& mf, - cmExecutionStatus&) override; - bool ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) override; - - std::vector<cmListFileArgument> Args; - std::vector<cmListFileFunction> Functions; - -private: - cmMakefile* Makefile; - int Depth; -}; +struct cmListFileArgument; /// \brief Starts a while loop bool cmWhileCommand(std::vector<cmListFileArgument> const& args, diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 309efd3..a81b7e4 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -28,6 +28,7 @@ #include "cmUtils.hxx" #include "cmVersionConfig.h" #include "cmWorkingDirectory.h" +#include "cm_string_view.hxx" #include "cm_sys_stat.h" #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -132,22 +133,15 @@ static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, } cmake::cmake(Role role, cmState::Mode mode) + : FileTimeCache(cm::make_unique<cmFileTimeCache>()) +#ifdef CMAKE_BUILD_WITH_CMAKE + , VariableWatch(cm::make_unique<cmVariableWatch>()) +#endif + , State(cm::make_unique<cmState>()) + , Messenger(cm::make_unique<cmMessenger>()) { - this->Trace = false; - this->TraceExpand = false; - this->WarnUninitialized = false; - this->WarnUnused = false; - this->WarnUnusedCli = true; - this->CheckSystemVars = false; - this->DebugOutput = false; - this->DebugTryCompile = false; - this->ClearBuildSystem = false; - this->FileTimeCache = cm::make_unique<cmFileTimeCache>(); - - this->State = cm::make_unique<cmState>(); this->State->SetMode(mode); this->CurrentSnapshot = this->State->CreateBaseSnapshot(); - this->Messenger = cm::make_unique<cmMessenger>(); #ifdef __APPLE__ struct rlimit rlp; @@ -159,16 +153,6 @@ cmake::cmake(Role role, cmState::Mode mode) } #endif - this->GlobalGenerator = nullptr; - this->GeneratorInstanceSet = false; - this->GeneratorPlatformSet = false; - this->GeneratorToolsetSet = false; - this->CurrentWorkingMode = NORMAL_MODE; - -#ifdef CMAKE_BUILD_WITH_CMAKE - this->VariableWatch = cm::make_unique<cmVariableWatch>(); -#endif - this->AddDefaultGenerators(); this->AddDefaultExtraGenerators(); if (role == RoleScript || role == RoleProject) { @@ -188,32 +172,25 @@ cmake::cmake(Role role, cmState::Mode mode) // Set up a list of source and header extensions. // These are used to find files when the extension is not given. { - auto fillExts = [](FileExtensions& exts, - std::initializer_list<const char*> extList) { + auto setupExts = [](FileExtensions& exts, + std::initializer_list<cm::string_view> extList) { // Fill ordered vector exts.ordered.reserve(extList.size()); - for (const char* ext : extList) { + for (cm::string_view ext : extList) { exts.ordered.emplace_back(ext); }; // Fill unordered set exts.unordered.insert(exts.ordered.begin(), exts.ordered.end()); }; - // Source extensions // The "c" extension MUST precede the "C" extension. - fillExts(this->SourceFileExtensions, - { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "m", "M", "mm" }); - - // Header extensions - fillExts(this->HeaderFileExtensions, - { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" }); - - // Cuda extensions - fillExts(this->CudaFileExtensions, { "cu" }); - - // Fortran extensions - fillExts(this->FortranFileExtensions, - { "f", "F", "for", "f77", "f90", "f95", "f03" }); + setupExts(this->SourceFileExtensions, + { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "m", "M", "mm" }); + setupExts(this->HeaderFileExtensions, + { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" }); + setupExts(this->CudaFileExtensions, { "cu" }); + setupExts(this->FortranFileExtensions, + { "f", "F", "for", "f77", "f90", "f95", "f03" }); } } diff --git a/Source/cmake.h b/Source/cmake.h index 6aa00e1..92494ae 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -509,14 +509,14 @@ protected: void AddDefaultGenerators(); void AddDefaultExtraGenerators(); - cmGlobalGenerator* GlobalGenerator; + cmGlobalGenerator* GlobalGenerator = nullptr; std::map<std::string, DiagLevel> DiagLevels; std::string GeneratorInstance; std::string GeneratorPlatform; std::string GeneratorToolset; - bool GeneratorInstanceSet; - bool GeneratorPlatformSet; - bool GeneratorToolsetSet; + bool GeneratorInstanceSet = false; + bool GeneratorPlatformSet = false; + bool GeneratorToolsetSet = false; //! read in a cmake list file to initialize the cache void ReadListFile(const std::vector<std::string>& args, @@ -543,14 +543,14 @@ protected: private: ProgressCallbackType ProgressCallback; - WorkingMode CurrentWorkingMode; - bool DebugOutput; - bool Trace; - bool TraceExpand; - bool WarnUninitialized; - bool WarnUnused; - bool WarnUnusedCli; - bool CheckSystemVars; + WorkingMode CurrentWorkingMode = NORMAL_MODE; + bool DebugOutput = false; + bool Trace = false; + bool TraceExpand = false; + bool WarnUninitialized = false; + bool WarnUnused = false; + bool WarnUnusedCli = true; + bool CheckSystemVars = false; std::map<std::string, bool> UsedCliVariables; std::string CMakeEditCommand; std::string CXXEnvironment; @@ -564,8 +564,8 @@ private: FileExtensions HeaderFileExtensions; FileExtensions CudaFileExtensions; FileExtensions FortranFileExtensions; - bool ClearBuildSystem; - bool DebugTryCompile; + bool ClearBuildSystem = false; + bool DebugTryCompile = false; std::unique_ptr<cmFileTimeCache> FileTimeCache; std::string GraphVizFile; InstalledFilesMap InstalledFiles; diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx index 95616ff..55d2a8f 100644 --- a/Tests/CMakeLib/testStringAlgorithms.cxx +++ b/Tests/CMakeLib/testStringAlgorithms.cxx @@ -38,6 +38,28 @@ int testStringAlgorithms(int /*unused*/, char* /*unused*/ []) }; // ---------------------------------------------------------------------- + // Test cmTrimWhitespace + { + std::string base = "base"; + std::string spaces = " \f\f\n\n\r\r\t\t\v\v"; + assert_string(cmTrimWhitespace(spaces + base), base, + "cmTrimWhitespace front"); + assert_string(cmTrimWhitespace(base + spaces), base, + "cmTrimWhitespace back"); + assert_string(cmTrimWhitespace(spaces + base + spaces), base, + "cmTrimWhitespace front and back"); + } + + // ---------------------------------------------------------------------- + // Test cmEscapeQuotes + { + assert_string(cmEscapeQuotes("plain"), "plain", "cmEscapeQuotes plain"); + std::string base = "\"base\"\""; + std::string result = "\\\"base\\\"\\\""; + assert_string(cmEscapeQuotes(base), result, "cmEscapeQuotes escaped"); + } + + // ---------------------------------------------------------------------- // Test cmJoin { typedef std::string ST; @@ -52,6 +74,21 @@ int testStringAlgorithms(int /*unused*/, char* /*unused*/ []) } // ---------------------------------------------------------------------- + // Test cmTokenize + { + typedef std::vector<std::string> VT; + assert_ok(cmTokenize("", ";") == VT{ "" }, "cmTokenize empty"); + assert_ok(cmTokenize(";", ";") == VT{ "" }, "cmTokenize sep"); + assert_ok(cmTokenize("abc", ";") == VT{ "abc" }, "cmTokenize item"); + assert_ok(cmTokenize("abc;", ";") == VT{ "abc" }, "cmTokenize item sep"); + assert_ok(cmTokenize(";abc", ";") == VT{ "abc" }, "cmTokenize sep item"); + assert_ok(cmTokenize("abc;;efg", ";") == VT{ "abc", "efg" }, + "cmTokenize item sep sep item"); + assert_ok(cmTokenize("a1;a2;a3;a4", ";") == VT{ "a1", "a2", "a3", "a4" }, + "cmTokenize multiple items"); + } + + // ---------------------------------------------------------------------- // Test cmStrCat { int ni = -1100; diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index 519608c..7217f43 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -653,3 +653,9 @@ find_package(ACME NO_MODULE) if(ACME_FOUND) message(SEND_ERROR "Should not find ACME package") endif() + +############################################################################ +##Test find_package CMAKE_FIND_PACKAGE_PREFER_CONFIG with unknown package + +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) +find_package(DoesNotExist) diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py index 3b0ec6e..89f63d0 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py +++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py @@ -2092,7 +2092,40 @@ def gen_check_targets(c, g, inSource): ], "build": "^cxx$", "source": "^cxx$", - "install": None, + "install": { + "prefix": "^(/usr/local|[A-Za-z]:.*/codemodel-v2)$", + "destinations": [ + { + "path": "bin", + "backtrace": [ + { + "file": "^codemodel-v2\\.cmake$", + "line": 37, + "command": "install", + "hasParent": True, + }, + { + "file": "^codemodel-v2\\.cmake$", + "line": None, + "command": None, + "hasParent": True, + }, + { + "file": "^CMakeLists\\.txt$", + "line": 3, + "command": "include", + "hasParent": True, + }, + { + "file": "^CMakeLists\\.txt$", + "line": None, + "command": None, + "hasParent": False, + }, + ], + }, + ], + }, "link": { "language": "CXX", "lto": None, diff --git a/Tests/RunCMake/FileAPI/codemodel-v2.cmake b/Tests/RunCMake/FileAPI/codemodel-v2.cmake index 72073d5..c98a84c 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2.cmake +++ b/Tests/RunCMake/FileAPI/codemodel-v2.cmake @@ -33,3 +33,5 @@ if(_ipo) set_property(TARGET c_static_lib PROPERTY INTERPROCEDURAL_OPTIMIZATION ON) file(WRITE "${CMAKE_BINARY_DIR}/ipo_enabled.txt" "") endif() + +install(TARGETS cxx_exe) diff --git a/Tests/RuntimePath/CMakeLists.txt b/Tests/RuntimePath/CMakeLists.txt index 6583a87..bb87440 100644 --- a/Tests/RuntimePath/CMakeLists.txt +++ b/Tests/RuntimePath/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 3.15) project(RuntimePath C) # Add a simple chain of shared libraries that must be found. @@ -31,3 +31,14 @@ if(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG) set_property(TARGET bar2 PROPERTY LIBRARY_OUTPUT_DIRECTORY A) target_link_libraries(bar2 foo2) endif() + +# Add a library that is missing the rpath for its dependency. +add_library(bar1_no_rpath SHARED bar1.c) +set_property(TARGET bar1_no_rpath PROPERTY LIBRARY_OUTPUT_DIRECTORY B) +set_property(TARGET bar1_no_rpath PROPERTY SKIP_BUILD_RPATH 1) +target_link_libraries(bar1_no_rpath PRIVATE foo1) + +# Add an executable linking to the library with a missing dependency rpath. +# CMake should generate the proper rpath-link flag to find it at build time. +add_executable(main_with_bar1_no_rpath main.c) +target_link_libraries(main_with_bar1_no_rpath bar1_no_rpath) @@ -326,6 +326,7 @@ CMAKE_CXX_SOURCES="\ cmFindPathCommand \ cmFindProgramCommand \ cmForEachCommand \ + cmFunctionBlocker \ cmFunctionCommand \ cmFSPermissions \ cmGeneratedFileStream \ |