diff options
59 files changed, 783 insertions, 314 deletions
diff --git a/.clang-tidy b/.clang-tidy index bfcb67c..57e571a 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -3,16 +3,21 @@ Checks: "-*,\ bugprone-*,\ -bugprone-macro-parentheses,\ -bugprone-misplaced-widening-cast,\ +-bugprone-narrowing-conversions,\ +-bugprone-too-small-loop-variable,\ google-readability-casting,\ misc-*,\ -misc-incorrect-roundings,\ -misc-macro-parentheses,\ -misc-misplaced-widening-cast,\ +-misc-non-private-member-variables-in-classes,\ -misc-static-assert,\ modernize-*,\ +-modernize-avoid-c-arrays,\ -modernize-deprecated-headers,\ -modernize-return-braced-init-list,\ -modernize-use-auto,\ +-modernize-use-nodiscard,\ -modernize-use-noexcept,\ -modernize-use-transparent-functors,\ -modernize-use-using,\ @@ -24,8 +29,11 @@ readability-*,\ -readability-implicit-bool-cast,\ -readability-implicit-bool-conversion,\ -readability-inconsistent-declaration-parameter-name,\ +-readability-isolate-declaration,\ +-readability-magic-numbers,\ -readability-named-parameter,\ -readability-redundant-declaration,\ +-readability-uppercase-literal-suffix,\ " HeaderFilterRegex: 'Source/cm[^/]*\.(h|hxx|cxx)$' CheckOptions: diff --git a/Help/guide/tutorial/MultiPackage/CMakeLists.txt b/Help/guide/tutorial/MultiPackage/CMakeLists.txt index 067e807..bea611c 100644 --- a/Help/guide/tutorial/MultiPackage/CMakeLists.txt +++ b/Help/guide/tutorial/MultiPackage/CMakeLists.txt @@ -1,19 +1,26 @@ cmake_minimum_required(VERSION 3.3) project(Tutorial) -# control how we mark up Debug libraries compared to Release libraries -set(CMAKE_DEBUG_POSTFIX "-d") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# set the version number +set(Tutorial_VERSION_MAJOR 1) +set(Tutorial_VERSION_MINOR 0) # control where the static and shared libraries are built so that on windows # we don't need to tinker with the path to run the executable set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") option(BUILD_SHARED_LIBS "Build using shared libraries" ON) -# the version number. -set(Tutorial_VERSION_MAJOR 1) -set(Tutorial_VERSION_MINOR 0) +if(APPLE) + set(CMAKE_INSTALL_RPATH "@executable_path/../lib") +elseif(UNIX) + set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") +endif() # configure a header file to pass the version number only configure_file( diff --git a/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt index 161ad64..63c0f5f 100644 --- a/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/MultiPackage/MathFunctions/CMakeLists.txt @@ -1,4 +1,3 @@ - # add the library that runs add_library(MathFunctions MathFunctions.cxx) @@ -62,6 +61,7 @@ target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0") set_property(TARGET MathFunctions PROPERTY SOVERSION "1") +# install rules install(TARGETS MathFunctions DESTINATION lib EXPORT MathFunctionsTargets) diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 1914f52..0fcbbb7 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -138,7 +138,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src) set(_variant "") if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang") - if(CMAKE_HOST_WIN32 AND "x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC") + if("x${CMAKE_${lang}_SIMULATE_ID}" STREQUAL "xMSVC") if(CMAKE_GENERATOR MATCHES "Visual Studio") set(CMAKE_${lang}_COMPILER_FRONTEND_VARIANT "MSVC") else() diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index 0e84116..773ee53 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -72,7 +72,7 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND find_program(CMAKE_LINKER NAMES link HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) find_program(CMAKE_MT NAMES mt HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - list(APPEND _CMAKE_TOOL_VARS CMAKE_LINKER CMAKE_MT) + list(APPEND _CMAKE_TOOL_VARS LINKER MT) # in all other cases search for ar, ranlib, etc. else() @@ -84,27 +84,36 @@ else() endif() if("${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL Clang) - set(LLVM_OBJDUMP "llvm-objdump") - set(LLVM_LLD "ld.lld") - set(LLVM_RANLIB "llvm-ranlib") - set(LLVM_AR "llvm-ar") + set(_CMAKE_ADDITIONAL_AR_NAMES "llvm-ar") + set(_CMAKE_ADDITIONAL_RANLIB_NAMES "llvm-ranlib") + set(_CMAKE_ADDITIONAL_STRIP_NAMES "llvm-strip") + set(_CMAKE_ADDITIONAL_LINKER_NAMES "ld.lld") + set(_CMAKE_ADDITIONAL_NM_NAMES "llvm-nm") + set(_CMAKE_ADDITIONAL_OBJDUMP_NAMES "llvm-objdump") + set(_CMAKE_ADDITIONAL_OBJCOPY_NAMES "llvm-objcopy") + set(_CMAKE_ADDITIONAL_READELF_NAMES "llvm-readelf") + set(_CMAKE_ADDITIONAL_DLLTOOL_NAMES "llvm-dlltool") + set(_CMAKE_ADDITIONAL_ADDR2LINE_NAMES "llvm-addr2line") endif() - find_program(CMAKE_AR NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ar${_CMAKE_TOOLCHAIN_SUFFIX} ${LLVM_AR} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_AR NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ar${_CMAKE_TOOLCHAIN_SUFFIX} ${_CMAKE_ADDITIONAL_AR_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - find_program(CMAKE_RANLIB NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ranlib ${LLVM_RANLIB} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_RANLIB NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ranlib ${_CMAKE_ADDITIONAL_RANLIB_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) if(NOT CMAKE_RANLIB) set(CMAKE_RANLIB : CACHE INTERNAL "noop for ranlib") endif() - find_program(CMAKE_STRIP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}strip${_CMAKE_TOOLCHAIN_SUFFIX} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - find_program(CMAKE_LINKER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ld ${LLVM_LLD} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - find_program(CMAKE_OBJDUMP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objdump ${LLVM_OBJDUMP} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - find_program(CMAKE_OBJCOPY NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objcopy HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_STRIP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}strip${_CMAKE_TOOLCHAIN_SUFFIX} ${_CMAKE_ADDITIONAL_STRIP_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_LINKER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}ld ${_CMAKE_ADDITIONAL_LINKER_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm ${_CMAKE_ADDITIONAL_NM_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_OBJDUMP NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objdump ${_CMAKE_ADDITIONAL_OBJDUMP_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_OBJCOPY NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objcopy ${_CMAKE_ADDITIONAL_OBJCOPY_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_READELF NAMES ${_CMAKE_TOOLCHAIN_PREFIX}readelf ${_CMAKE_ADDITIONAL_READELF_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_DLLTOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}dlltool ${_CMAKE_ADDITIONAL_DLLTOOL_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + find_program(CMAKE_ADDR2LINE NAMES ${_CMAKE_TOOLCHAIN_PREFIX}addr2line ${_CMAKE_ADDITIONAL_ADDR2LINE_NAMES} HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) - list(APPEND _CMAKE_TOOL_VARS CMAKE_AR CMAKE_RANLIB CMAKE_STRIP CMAKE_LINKER CMAKE_NM CMAKE_OBJDUMP CMAKE_OBJCOPY) + list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE) endif() @@ -115,15 +124,16 @@ if(CMAKE_PLATFORM_HAS_INSTALLNAME) message(FATAL_ERROR "Could not find install_name_tool, please check your installation.") endif() - list(APPEND _CMAKE_TOOL_VARS CMAKE_INSTALL_NAME_TOOL) + list(APPEND _CMAKE_TOOL_VARS INSTALL_NAME_TOOL) endif() # Mark any tool cache entries as advanced. foreach(var IN LISTS _CMAKE_TOOL_VARS) - get_property(_CMAKE_TOOL_CACHED CACHE ${var} PROPERTY TYPE) + get_property(_CMAKE_TOOL_CACHED CACHE CMAKE_${var} PROPERTY TYPE) if(_CMAKE_TOOL_CACHED) - mark_as_advanced(${var}) + mark_as_advanced(CMAKE_${var}) endif() + unset(_CMAKE_ADDITIONAL_${var}_NAMES) endforeach() unset(_CMAKE_TOOL_VARS) unset(_CMAKE_TOOL_CACHED) diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 14fc231..e55ed46 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -1079,7 +1079,7 @@ function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git message(FATAL_ERROR "Tag for git checkout should not be empty.") endif() - set(git_clone_options) + set(git_clone_options "--no-checkout") if(git_shallow) if(NOT GIT_VERSION_STRING VERSION_LESS 1.7.10) list(APPEND git_clone_options "--depth 1 --no-single-branch") diff --git a/Modules/FindPythonInterp.cmake b/Modules/FindPythonInterp.cmake index da33301..ccc7d5b 100644 --- a/Modules/FindPythonInterp.cmake +++ b/Modules/FindPythonInterp.cmake @@ -39,6 +39,15 @@ If calling both ``find_package(PythonInterp)`` and ``find_package(PythonLibs)``, call ``find_package(PythonInterp)`` first to get the currently active Python version by default with a consistent version of PYTHON_LIBRARIES. + +.. note:: + + A call to ``find_package(PythonInterp ${V})`` for python version ``V`` + may find a ``python`` executable with no version suffix. In this case + no attempt is made to avoid python executables from other versions. + Use :module:`FindPython3`, :module:`FindPython2` or :module:`FindPython` + instead. + #]=======================================================================] unset(_Python_NAMES) 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 a6babe5..b1f4ca5 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -404,6 +404,7 @@ set(SRCS cmStateSnapshot.cxx cmStateSnapshot.h cmStateTypes.h + cmStringAlgorithms.cxx cmStringAlgorithms.h cmSystemTools.cxx cmSystemTools.h diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 63a4207..3bbbd28 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 20190730) +set(CMake_VERSION_PATCH 20190805) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 512ac7a..3fd124b 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -21,6 +21,7 @@ #include "cmMakefile.h" #include "cmState.h" #include "cmStateSnapshot.h" +#include "cmStringAlgorithms.h" #include "cmVersion.h" #include "cmWorkingDirectory.h" #include "cmXMLSafe.h" @@ -772,7 +773,7 @@ int cmCPackGenerator::InstallCMakeProject( // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory // exists: // - if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) { + if (cmHasLiteralPrefix(dir, "/")) { dir = tempInstallDirectory + dir; } else { dir = tempInstallDirectory + "/" + dir; diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index f6028c4..54fe612 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -13,6 +13,7 @@ #include "cmParseGTMCoverage.h" #include "cmParseJacocoCoverage.h" #include "cmParsePHPCoverage.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmWorkingDirectory.h" #include "cmXMLWriter.h" @@ -1181,7 +1182,7 @@ int cmCTestCoverageHandler::HandleGCovCoverage( // gcov 4.7 can have output lines saying "No executable lines" and // "Removing 'filename.gcov'"... Don't log those as "errors." if (line != "No executable lines" && - !cmSystemTools::StringStartsWith(line.c_str(), "Removing ")) { + !cmHasLiteralPrefix(line, "Removing ")) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Unknown gcov output line: [" << line << "]" << std::endl); diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 237ca82..bbf490e 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -16,6 +16,7 @@ #include "cmProcessOutput.h" #include "cmState.h" #include "cmStateSnapshot.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmXMLWriter.h" #include "cmake.h" @@ -594,7 +595,7 @@ bool cmCTestLaunch::Match(std::string const& line, bool cmCTestLaunch::MatchesFilterPrefix(std::string const& line) const { return !this->OptionFilterPrefix.empty() && - cmSystemTools::StringStartsWith(line, this->OptionFilterPrefix.c_str()); + cmHasPrefix(line, this->OptionFilterPrefix); } int cmCTestLaunch::Main(int argc, const char* const argv[]) diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx index 63d6a15..b74decb 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.cxx +++ b/Source/CTest/cmParseBlanketJSCoverage.cxx @@ -110,7 +110,8 @@ cmParseBlanketJSCoverage::cmParseBlanketJSCoverage( { } -bool cmParseBlanketJSCoverage::LoadCoverageData(std::vector<std::string> files) +bool cmParseBlanketJSCoverage::LoadCoverageData( + std::vector<std::string> const& files) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found " << files.size() << " Files" << std::endl, diff --git a/Source/CTest/cmParseBlanketJSCoverage.h b/Source/CTest/cmParseBlanketJSCoverage.h index 696121f..cd1b225 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.h +++ b/Source/CTest/cmParseBlanketJSCoverage.h @@ -29,7 +29,7 @@ class cmParseBlanketJSCoverage public: cmParseBlanketJSCoverage(cmCTestCoverageHandlerContainer& cont, cmCTest* ctest); - bool LoadCoverageData(std::vector<std::string> files); + bool LoadCoverageData(std::vector<std::string> const& files); // Read the JSON output bool ReadJSONFile(std::string const& file); diff --git a/Source/CTest/cmParseJacocoCoverage.cxx b/Source/CTest/cmParseJacocoCoverage.cxx index b78142a..5f1e712 100644 --- a/Source/CTest/cmParseJacocoCoverage.cxx +++ b/Source/CTest/cmParseJacocoCoverage.cxx @@ -2,6 +2,7 @@ #include "cmCTest.h" #include "cmCTestCoverageHandler.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmXMLParser.h" @@ -118,7 +119,7 @@ protected: // Check if any of the locations found match our package. for (std::string const& f : files) { std::string dir = cmsys::SystemTools::GetParentDirectory(f); - if (cmsys::SystemTools::StringEndsWith(dir, this->PackageName.c_str())) { + if (cmHasSuffix(dir, this->PackageName)) { cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Found package directory for " << fileName << ": " << dir << std::endl, diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 610e9f9..026250d 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1965,7 +1965,7 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, if (this->CheckArgument(arg, "-N", "--show-only")) { this->Impl->ShowOnly = true; } - if (cmSystemTools::StringStartsWith(arg.c_str(), "--show-only=")) { + if (cmHasLiteralPrefix(arg, "--show-only=")) { this->Impl->ShowOnly = true; // Check if a specific format is requested. Defaults to human readable @@ -2227,7 +2227,7 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) // attempts are simply ignored since previous ctest versions ignore // this too. (As well as many other unknown command line args.) // - if (arg != "-D" && cmSystemTools::StringStartsWith(arg.c_str(), "-D")) { + if (arg != "-D" && cmHasLiteralPrefix(arg, "-D")) { std::string input = arg.substr(2); this->AddVariableDefinition(input); } diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx index f7a2244..9e152ff 100644 --- a/Source/cmCallVisualStudioMacro.cxx +++ b/Source/cmCallVisualStudioMacro.cxx @@ -4,6 +4,7 @@ #include <sstream> +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #if defined(_MSC_VER) @@ -328,8 +329,7 @@ HRESULT FindVisualStudioInstances(const std::string& slnFile, if (SUCCEEDED(hr)) { std::map<std::string, IUnknownPtr>::iterator it; for (it = mrot.begin(); it != mrot.end(); ++it) { - if (cmSystemTools::StringStartsWith(it->first.c_str(), - "!VisualStudio.DTE.")) { + if (cmHasLiteralPrefix(it->first, "!VisualStudio.DTE.")) { IDispatchPtr disp(it->second); if (disp != (IDispatch*)0) { std::string slnName; 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/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 8fd2947..87f9b4c 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -1209,8 +1209,8 @@ bool cmExportFileGenerator::PopulateExportProperties( targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) { for (auto& prop : cmSystemTools::ExpandedListArgument(exportProperties)) { /* Black list reserved properties */ - if (cmSystemTools::StringStartsWith(prop, "IMPORTED_") || - cmSystemTools::StringStartsWith(prop, "INTERFACE_")) { + if (cmHasLiteralPrefix(prop, "IMPORTED_") || + cmHasLiteralPrefix(prop, "INTERFACE_")) { std::ostringstream e; e << "Target \"" << gte->Target->GetName() << "\" contains property \"" << prop << "\" in EXPORT_PROPERTIES but IMPORTED_* and INTERFACE_* " diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index aa84396..2594287 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -684,7 +684,6 @@ void cmFileAPI::BuildClientRequestCodeModel( Json::Value cmFileAPI::BuildCodeModel(Object const& object) { - using namespace std::placeholders; Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version); codemodel["kind"] = this->ObjectKindName(object.Kind); @@ -719,7 +718,6 @@ void cmFileAPI::BuildClientRequestCache( Json::Value cmFileAPI::BuildCache(Object const& object) { - using namespace std::placeholders; Json::Value cache = cmFileAPICacheDump(*this, object.Version); cache["kind"] = this->ObjectKindName(object.Kind); @@ -754,7 +752,6 @@ void cmFileAPI::BuildClientRequestCMakeFiles( Json::Value cmFileAPI::BuildCMakeFiles(Object const& object) { - using namespace std::placeholders; Json::Value cmakeFiles = cmFileAPICMakeFilesDump(*this, object.Version); cmakeFiles["kind"] = this->ObjectKindName(object.Kind); diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 7b916cd..172897c 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -30,6 +30,9 @@ #include <algorithm> #include <cassert> +#include <cstddef> +#include <functional> +#include <limits> #include <map> #include <memory> #include <set> @@ -135,6 +138,40 @@ std::string TargetId(cmGeneratorTarget const* gt, std::string const& topBuild) return gt->GetName() + CMAKE_DIRECTORY_ID_SEP + hash; } +class JBTIndex +{ +public: + JBTIndex() = default; + explicit operator bool() const { return Index != None; } + Json::ArrayIndex Index = None; + static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1); +}; + +template <typename T> +class JBT +{ +public: + JBT(T v = T(), JBTIndex bt = JBTIndex()) + : Value(std::move(v)) + , Backtrace(bt) + { + } + T Value; + JBTIndex Backtrace; + friend bool operator==(JBT<T> const& l, JBT<T> const& r) + { + return l.Value == r.Value && l.Backtrace.Index == r.Backtrace.Index; + } + static bool ValueEq(JBT<T> const& l, JBT<T> const& r) + { + return l.Value == r.Value; + } + static bool ValueLess(JBT<T> const& l, JBT<T> const& r) + { + return l.Value < r.Value; + } +}; + class BacktraceData { std::string TopSource; @@ -169,7 +206,7 @@ class BacktraceData public: BacktraceData(std::string topSource); - bool Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index); + JBTIndex Add(cmListFileBacktrace const& bt); Json::Value Dump(); }; @@ -178,16 +215,17 @@ BacktraceData::BacktraceData(std::string topSource) { } -bool BacktraceData::Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index) +JBTIndex BacktraceData::Add(cmListFileBacktrace const& bt) { + JBTIndex index; if (bt.Empty()) { - return false; + return index; } cmListFileContext const* top = &bt.Top(); auto found = this->NodeMap.find(top); if (found != this->NodeMap.end()) { - index = found->second; - return true; + index.Index = found->second; + return index; } Json::Value entry = Json::objectValue; entry["file"] = this->AddFile(top->FilePath); @@ -197,13 +235,12 @@ bool BacktraceData::Add(cmListFileBacktrace const& bt, Json::ArrayIndex& index) if (!top->Name.empty()) { entry["command"] = this->AddCommand(top->Name); } - Json::ArrayIndex parent; - if (this->Add(bt.Pop(), parent)) { - entry["parent"] = parent; + if (JBTIndex parent = this->Add(bt.Pop())) { + entry["parent"] = parent.Index; } - index = this->NodeMap[top] = this->Nodes.size(); + index.Index = this->NodeMap[top] = this->Nodes.size(); this->Nodes.append(std::move(entry)); // NOLINT(*) - return true; + return index; } Json::Value BacktraceData::Dump() @@ -222,32 +259,65 @@ struct CompileData { struct IncludeEntry { - BT<std::string> Path; + JBT<std::string> Path; bool IsSystem = false; - IncludeEntry(BT<std::string> path, bool isSystem) + IncludeEntry(JBT<std::string> path, bool isSystem) : Path(std::move(path)) , IsSystem(isSystem) { } + friend bool operator==(IncludeEntry const& l, IncludeEntry const& r) + { + return l.Path == r.Path && l.IsSystem == r.IsSystem; + } }; - void SetDefines(std::set<BT<std::string>> const& defines); - std::string Language; std::string Sysroot; - std::vector<BT<std::string>> Flags; - std::vector<BT<std::string>> Defines; + std::vector<JBT<std::string>> Flags; + std::vector<JBT<std::string>> Defines; std::vector<IncludeEntry> Includes; + + friend bool operator==(CompileData const& l, CompileData const& r) + { + return (l.Language == r.Language && l.Sysroot == r.Sysroot && + l.Flags == r.Flags && l.Defines == r.Defines && + l.Includes == r.Includes); + } }; +} + +namespace std { -void CompileData::SetDefines(std::set<BT<std::string>> const& defines) +template <> +struct hash<CompileData> { - this->Defines.reserve(defines.size()); - for (BT<std::string> const& d : defines) { - this->Defines.push_back(d); + std::size_t operator()(CompileData const& in) const + { + using std::hash; + size_t result = + hash<std::string>()(in.Language) ^ hash<std::string>()(in.Sysroot); + for (auto const& i : in.Includes) { + result = result ^ + (hash<std::string>()(i.Path.Value) ^ + hash<Json::ArrayIndex>()(i.Path.Backtrace.Index) ^ + (i.IsSystem ? std::numeric_limits<size_t>::max() : 0)); + } + for (auto const& i : in.Flags) { + result = result ^ hash<std::string>()(i.Value) ^ + hash<Json::ArrayIndex>()(i.Backtrace.Index); + } + for (auto const& i : in.Defines) { + result = result ^ hash<std::string>()(i.Value) ^ + hash<Json::ArrayIndex>()(i.Backtrace.Index); + } + return result; } -} +}; +} // namespace std + +namespace { class Target { cmGeneratorTarget* GT; @@ -272,24 +342,32 @@ class Target struct CompileGroup { - std::map<Json::Value, Json::ArrayIndex>::iterator Entry; + std::unordered_map<CompileData, Json::ArrayIndex>::iterator Entry; Json::Value SourceIndexes = Json::arrayValue; }; - std::map<Json::Value, Json::ArrayIndex> CompileGroupMap; + std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap; std::vector<CompileGroup> CompileGroups; + template <typename T> + JBT<T> ToJBT(BT<T> const& bt) + { + return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace)); + } + void ProcessLanguages(); void ProcessLanguage(std::string const& lang); Json::ArrayIndex AddSourceGroup(cmSourceGroup* sg, Json::ArrayIndex si); CompileData BuildCompileData(cmSourceFile* sf); + CompileData MergeCompileData(CompileData const& fd); Json::ArrayIndex AddSourceCompileGroup(cmSourceFile* sf, Json::ArrayIndex si); void AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt); + void AddBacktrace(Json::Value& object, JBTIndex bt); Json::Value DumpPaths(); - Json::Value DumpCompileData(CompileData cd); + Json::Value DumpCompileData(CompileData const& cd); Json::Value DumpInclude(CompileData::IncludeEntry const& inc); - Json::Value DumpDefine(BT<std::string> const& def); + Json::Value DumpDefine(JBT<std::string> const& def); Json::Value DumpSources(); Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk, Json::ArrayIndex si); @@ -306,8 +384,8 @@ class Target Json::Value DumpLink(); Json::Value DumpArchive(); Json::Value DumpLinkCommandFragments(); - Json::Value DumpCommandFragments(std::vector<BT<std::string>> const& frags); - Json::Value DumpCommandFragment(BT<std::string> const& frag, + Json::Value DumpCommandFragments(std::vector<JBT<std::string>> const& frags); + Json::Value DumpCommandFragment(JBT<std::string> const& frag, std::string const& role = std::string()); Json::Value DumpDependencies(); Json::Value DumpDependency(cmTargetDepend const& td); @@ -722,16 +800,20 @@ void Target::ProcessLanguage(std::string const& lang) // which may need to be factored out. std::string flags; lg->GetTargetCompileFlags(this->GT, this->Config, lang, flags); - cd.Flags.emplace_back(std::move(flags), cmListFileBacktrace()); + cd.Flags.emplace_back(std::move(flags), JBTIndex()); } std::set<BT<std::string>> defines = lg->GetTargetDefines(this->GT, this->Config, lang); - cd.SetDefines(defines); + cd.Defines.reserve(defines.size()); + for (BT<std::string> const& d : defines) { + cd.Defines.emplace_back(this->ToJBT(d)); + } std::vector<BT<std::string>> includePathList = lg->GetIncludeDirectories(this->GT, lang, this->Config); for (BT<std::string> const& i : includePathList) { cd.Includes.emplace_back( - i, this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang)); + this->ToJBT(i), + this->GT->IsSystemIncludeDirectory(i.Value, this->Config, lang)); } } @@ -758,26 +840,22 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) if (fd.Language.empty()) { return fd; } - CompileData const& cd = this->CompileDataMap.at(fd.Language); - - fd.Sysroot = cd.Sysroot; cmLocalGenerator* lg = this->GT->GetLocalGenerator(); cmGeneratorExpressionInterpreter genexInterpreter(lg, this->Config, this->GT, fd.Language); - fd.Flags = cd.Flags; const std::string COMPILE_FLAGS("COMPILE_FLAGS"); if (const char* cflags = sf->GetProperty(COMPILE_FLAGS)) { std::string flags = genexInterpreter.Evaluate(cflags, COMPILE_FLAGS); - fd.Flags.emplace_back(std::move(flags), cmListFileBacktrace()); + fd.Flags.emplace_back(std::move(flags), JBTIndex()); } const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); if (const char* coptions = sf->GetProperty(COMPILE_OPTIONS)) { std::string flags; lg->AppendCompileOptions( flags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); - fd.Flags.emplace_back(std::move(flags), cmListFileBacktrace()); + fd.Flags.emplace_back(std::move(flags), JBTIndex()); } // Add include directories from source file properties. @@ -796,8 +874,6 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) } } } - fd.Includes.insert(fd.Includes.end(), cd.Includes.begin(), - cd.Includes.end()); const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); std::set<std::string> fileDefines; @@ -814,27 +890,62 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS)); } - std::set<BT<std::string>> defines; - defines.insert(fileDefines.begin(), fileDefines.end()); - defines.insert(cd.Defines.begin(), cd.Defines.end()); - - fd.SetDefines(defines); + fd.Defines.reserve(fileDefines.size()); + for (std::string const& d : fileDefines) { + fd.Defines.emplace_back(d, JBTIndex()); + } return fd; } +CompileData Target::MergeCompileData(CompileData const& fd) +{ + CompileData cd; + cd.Language = fd.Language; + if (cd.Language.empty()) { + return cd; + } + CompileData const& td = this->CompileDataMap.at(cd.Language); + + // All compile groups share the sysroot of the target. + cd.Sysroot = td.Sysroot; + + // Use target-wide flags followed by source-specific flags. + cd.Flags.reserve(td.Flags.size() + fd.Flags.size()); + cd.Flags.insert(cd.Flags.end(), td.Flags.begin(), td.Flags.end()); + cd.Flags.insert(cd.Flags.end(), fd.Flags.begin(), fd.Flags.end()); + + // Use source-specific includes followed by target-wide includes. + cd.Includes.reserve(fd.Includes.size() + td.Includes.size()); + cd.Includes.insert(cd.Includes.end(), fd.Includes.begin(), + fd.Includes.end()); + cd.Includes.insert(cd.Includes.end(), td.Includes.begin(), + td.Includes.end()); + + // Use target-wide defines followed by source-specific defines. + cd.Defines.reserve(td.Defines.size() + fd.Defines.size()); + cd.Defines.insert(cd.Defines.end(), td.Defines.begin(), td.Defines.end()); + cd.Defines.insert(cd.Defines.end(), fd.Defines.begin(), fd.Defines.end()); + + // De-duplicate defines. + std::stable_sort(cd.Defines.begin(), cd.Defines.end(), + JBT<std::string>::ValueLess); + auto end = std::unique(cd.Defines.begin(), cd.Defines.end(), + JBT<std::string>::ValueEq); + cd.Defines.erase(end, cd.Defines.end()); + + return cd; +} + Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf, Json::ArrayIndex si) { - Json::Value compileDataJson = - this->DumpCompileData(this->BuildCompileData(sf)); - std::map<Json::Value, Json::ArrayIndex>::iterator i = - this->CompileGroupMap.find(compileDataJson); + CompileData compileData = this->BuildCompileData(sf); + auto i = this->CompileGroupMap.find(compileData); if (i == this->CompileGroupMap.end()) { Json::ArrayIndex cgIndex = static_cast<Json::ArrayIndex>(this->CompileGroups.size()); - i = - this->CompileGroupMap.emplace(std::move(compileDataJson), cgIndex).first; + i = this->CompileGroupMap.emplace(std::move(compileData), cgIndex).first; CompileGroup g; g.Entry = i; this->CompileGroups.push_back(std::move(g)); @@ -845,9 +956,15 @@ Json::ArrayIndex Target::AddSourceCompileGroup(cmSourceFile* sf, void Target::AddBacktrace(Json::Value& object, cmListFileBacktrace const& bt) { - Json::ArrayIndex backtrace; - if (this->Backtraces.Add(bt, backtrace)) { - object["backtrace"] = backtrace; + if (JBTIndex backtrace = this->Backtraces.Add(bt)) { + object["backtrace"] = backtrace.Index; + } +} + +void Target::AddBacktrace(Json::Value& object, JBTIndex bt) +{ + if (bt) { + object["backtrace"] = bt.Index; } } @@ -915,7 +1032,7 @@ Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk, return source; } -Json::Value Target::DumpCompileData(CompileData cd) +Json::Value Target::DumpCompileData(CompileData const& cd) { Json::Value result = Json::objectValue; @@ -937,7 +1054,7 @@ Json::Value Target::DumpCompileData(CompileData cd) } if (!cd.Defines.empty()) { Json::Value defines = Json::arrayValue; - for (BT<std::string> const& d : cd.Defines) { + for (JBT<std::string> const& d : cd.Defines) { defines.append(this->DumpDefine(d)); } result["defines"] = std::move(defines); @@ -957,7 +1074,7 @@ Json::Value Target::DumpInclude(CompileData::IncludeEntry const& inc) return include; } -Json::Value Target::DumpDefine(BT<std::string> const& def) +Json::Value Target::DumpDefine(JBT<std::string> const& def) { Json::Value define = Json::objectValue; define["define"] = def.Value; @@ -993,7 +1110,8 @@ Json::Value Target::DumpCompileGroups() Json::Value Target::DumpCompileGroup(CompileGroup& cg) { - Json::Value group = cg.Entry->first; + Json::Value group = + this->DumpCompileData(this->MergeCompileData(cg.Entry->first)); group["sourceIndexes"] = std::move(cg.SourceIndexes); return group; } @@ -1026,12 +1144,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; } @@ -1190,16 +1305,16 @@ Json::Value Target::DumpLinkCommandFragments() } Json::Value Target::DumpCommandFragments( - std::vector<BT<std::string>> const& frags) + std::vector<JBT<std::string>> const& frags) { Json::Value commandFragments = Json::arrayValue; - for (BT<std::string> const& f : frags) { + for (JBT<std::string> const& f : frags) { commandFragments.append(this->DumpCommandFragment(f)); } return commandFragments; } -Json::Value Target::DumpCommandFragment(BT<std::string> const& frag, +Json::Value Target::DumpCommandFragment(JBT<std::string> const& frag, std::string const& role) { Json::Value fragment = Json::objectValue; diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 782f746..8fcf1ac 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -4,6 +4,7 @@ #include "cmMakefile.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" class cmExecutionStatus; @@ -71,7 +72,7 @@ struct cmFindProgramHelper bool CheckDirectoryForName(std::string const& path, std::string const& name) { for (std::string const& ext : this->Extensions) { - if (!ext.empty() && cmSystemTools::StringEndsWith(name, ext.c_str())) { + if (!ext.empty() && cmHasSuffix(name, ext)) { continue; } this->TestNameExt = name; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 38f34ac..d9e5e71 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -4192,7 +4192,7 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const if (stripResources) { flags.MacFolder = ""; } - } else if (cmSystemTools::StringStartsWith(location, "Resources/")) { + } else if (cmHasLiteralPrefix(location, "Resources/")) { flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource; if (stripResources) { flags.MacFolder += strlen("Resources/"); @@ -5219,7 +5219,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 +5603,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 +5660,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/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 7b8ffc5..88da5eb 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -337,15 +337,16 @@ bool cmGlobalGenerator::CheckTargetsForType() const bool failed = false; for (cmLocalGenerator* generator : this->LocalGenerators) { for (cmGeneratorTarget* target : generator->GetGeneratorTargets()) { - std::vector<std::string> configs; - target->Makefile->GetConfigurations(configs); - if (configs.empty()) { - configs.emplace_back(); - } + if (target->GetType() == cmStateEnums::EXECUTABLE && + target->GetPropertyAsBool("WIN32_EXECUTABLE")) { + std::vector<std::string> configs; + target->Makefile->GetConfigurations(configs); + if (configs.empty()) { + configs.emplace_back(); + } - for (std::string const& config : configs) { - if (target->GetLinkerLanguage(config) == "Swift") { - if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) { + for (std::string const& config : configs) { + if (target->GetLinkerLanguage(config) == "Swift") { this->GetCMakeInstance()->IssueMessage( MessageType::FATAL_ERROR, "WIN32_EXECUTABLE property is not supported on Swift " diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index bad715d..0b68966 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -415,14 +415,6 @@ void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os, cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm) : cmGlobalCommonGenerator(cm) - , UsingGCCOnWindows(false) - , ComputingUnknownDependencies(false) - , PolicyCMP0058(cmPolicies::WARN) - , NinjaSupportsConsolePool(false) - , NinjaSupportsImplicitOuts(false) - , NinjaSupportsManifestRestat(false) - , NinjaSupportsMultilineDepfile(false) - , NinjaSupportsDyndeps(0) { #ifdef _WIN32 cm->GetState()->SetWindowsShell(true); @@ -556,14 +548,22 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures() this->NinjaSupportsMultilineDepfile = !cmSystemTools::VersionCompare( cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), RequiredNinjaVersionForMultilineDepfile().c_str()); - { + this->NinjaSupportsDyndeps = !cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), + RequiredNinjaVersionForDyndeps().c_str()); + if (!this->NinjaSupportsDyndeps) { + // The ninja version number is not new enough to have upstream support. // Our ninja branch adds ".dyndep-#" to its version number, // where '#' is a feature-specific version number. Extract it. static std::string const k_DYNDEP_ = ".dyndep-"; std::string::size_type pos = this->NinjaVersion.find(k_DYNDEP_); if (pos != std::string::npos) { const char* fv = &this->NinjaVersion[pos + k_DYNDEP_.size()]; - cmSystemTools::StringToULong(fv, &this->NinjaSupportsDyndeps); + unsigned long dyndep = 0; + cmSystemTools::StringToULong(fv, &dyndep); + if (dyndep == 1) { + this->NinjaSupportsDyndeps = true; + } } } } @@ -580,37 +580,25 @@ bool cmGlobalNinjaGenerator::CheckLanguages( bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const { - if (this->NinjaSupportsDyndeps == 1) { + if (this->NinjaSupportsDyndeps) { return true; } std::ostringstream e; - if (this->NinjaSupportsDyndeps == 0) { - /* clang-format off */ - e << - "The Ninja generator does not support Fortran using Ninja version\n" - " " + this->NinjaVersion + "\n" - "due to lack of required features. " - "Kitware has implemented the required features but as of this version " - "of CMake they have not been integrated to upstream ninja. " - "Pending integration, Kitware maintains a branch at:\n" - " https://github.com/Kitware/ninja/tree/features-for-fortran#readme\n" - "with the required features. " - "One may build ninja from that branch to get support for Fortran." - ; - /* clang-format on */ - } else { - /* clang-format off */ - e << - "The Ninja generator in this version of CMake does not support Fortran " - "using Ninja version\n" - " " + this->NinjaVersion + "\n" - "because its 'dyndep' feature version is " << - this->NinjaSupportsDyndeps << ". " - "This version of CMake is aware only of 'dyndep' feature version 1." - ; - /* clang-format on */ - } + /* clang-format off */ + e << + "The Ninja generator does not support Fortran using Ninja version\n" + " " + this->NinjaVersion + "\n" + "due to lack of required features. " + "Kitware has implemented the required features and they have been " + "merged to upstream ninja for inclusion in Ninja 1.10 and higher. " + "As of this version of CMake, Ninja 1.10 has not been released. " + "Meanwhile, Kitware maintains a branch of Ninja at:\n" + " https://github.com/Kitware/ninja/tree/features-for-fortran#readme\n" + "with the required features. " + "One may build ninja from that branch to get support for Fortran." + ; + /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); cmSystemTools::SetFatalErrorOccured(); return false; diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 99afc1d..db64031 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -322,6 +322,7 @@ public: { return "1.9"; } + static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; } bool SupportsConsolePool() const; bool SupportsImplicitOuts() const; bool SupportsManifestRestat() const; @@ -402,7 +403,7 @@ private: /// The set of dependencies to add to the "all" target. cmNinjaDeps AllDependencies; - bool UsingGCCOnWindows; + bool UsingGCCOnWindows = false; /// The set of custom commands we have seen. std::set<cmCustomCommand const*> CustomCommands; @@ -412,8 +413,8 @@ private: /// Whether we are collecting known build outputs and needed /// dependencies to determine unknown dependencies. - bool ComputingUnknownDependencies; - cmPolicies::PolicyStatus PolicyCMP0058; + bool ComputingUnknownDependencies = false; + cmPolicies::PolicyStatus PolicyCMP0058 = cmPolicies::WARN; /// The combined explicit dependencies of custom build commands std::set<std::string> CombinedCustomCommandExplicitDependencies; @@ -435,11 +436,11 @@ private: std::string NinjaCommand; std::string NinjaVersion; - bool NinjaSupportsConsolePool; - bool NinjaSupportsImplicitOuts; - bool NinjaSupportsManifestRestat; - bool NinjaSupportsMultilineDepfile; - unsigned long NinjaSupportsDyndeps; + bool NinjaSupportsConsolePool = false; + bool NinjaSupportsImplicitOuts = false; + bool NinjaSupportsManifestRestat = false; + bool NinjaSupportsMultilineDepfile = false; + bool NinjaSupportsDyndeps = false; private: void InitOutputPathPrefix(); diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 8401efb..bead0e3 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -8,7 +8,9 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmState.h" +#include "cmStringAlgorithms.h" #include "cmUuid.h" +#include "cm_string_view.hxx" #include "cmake.h" #include "cmsys/Encoding.hxx" @@ -432,16 +434,15 @@ void cmGlobalVisualStudio7Generator::WriteTargetDepends( void cmGlobalVisualStudio7Generator::WriteFolders(std::ostream& fout) { - const char* prefix = "CMAKE_FOLDER_GUID_"; - const std::string::size_type skip_prefix = strlen(prefix); + cm::string_view const prefix = "CMAKE_FOLDER_GUID_"; std::string guidProjectTypeFolder = "2150E333-8FDC-42A3-9474-1A3956D46DE8"; for (auto const& iter : VisualStudioFolders) { std::string fullName = iter.first; std::string guid = this->GetGUID(fullName); std::replace(fullName.begin(), fullName.end(), '/', '\\'); - if (cmSystemTools::StringStartsWith(fullName.c_str(), prefix)) { - fullName = fullName.substr(skip_prefix); + if (cmHasPrefix(fullName, prefix)) { + fullName = fullName.substr(prefix.size()); } std::string nameOnly = cmSystemTools::GetFilenameName(fullName); 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/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/cmNewLineStyle.cxx b/Source/cmNewLineStyle.cxx index 3f6523e..1ff741e 100644 --- a/Source/cmNewLineStyle.cxx +++ b/Source/cmNewLineStyle.cxx @@ -41,7 +41,7 @@ bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args, return true; } -const std::string cmNewLineStyle::GetCharacters() const +std::string cmNewLineStyle::GetCharacters() const { switch (NewLineStyle) { case Invalid: diff --git a/Source/cmNewLineStyle.h b/Source/cmNewLineStyle.h index f1a7bc6..ab9002e 100644 --- a/Source/cmNewLineStyle.h +++ b/Source/cmNewLineStyle.h @@ -30,7 +30,7 @@ public: bool ReadFromArguments(const std::vector<std::string>& args, std::string& errorString); - const std::string GetCharacters() const; + std::string GetCharacters() const; private: Style NewLineStyle = Invalid; diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 2aefe8f..0801c24 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -1894,7 +1894,7 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) std::list<std::string>::iterator it = includes.begin(); while (it != includes.end()) { std::string const& path = *it; - if (cmSystemTools::StringStartsWith(path, ppath->c_str())) { + if (cmHasPrefix(path, *ppath)) { MocConst_.IncludePaths.push_back(path); it = includes.erase(it); } else { diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index c5de742..8fcb710 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -378,8 +378,7 @@ void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path, SendSignal(kFILE_CHANGE_SIGNAL, obj); } -const cmServerResponse cmServerProtocol1::Process( - const cmServerRequest& request) +cmServerResponse cmServerProtocol1::Process(const cmServerRequest& request) { assert(this->m_State >= STATE_ACTIVE); diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h index 2f55a20..5da4344 100644 --- a/Source/cmServerProtocol.h +++ b/Source/cmServerProtocol.h @@ -80,7 +80,7 @@ public: virtual std::pair<int, int> ProtocolVersion() const = 0; virtual bool IsExperimental() const = 0; - virtual const cmServerResponse Process(const cmServerRequest& request) = 0; + virtual cmServerResponse Process(const cmServerRequest& request) = 0; bool Activate(cmServer* server, const cmServerRequest& request, std::string* errorMessage); @@ -106,7 +106,7 @@ class cmServerProtocol1 : public cmServerProtocol public: std::pair<int, int> ProtocolVersion() const override; bool IsExperimental() const override; - const cmServerResponse Process(const cmServerRequest& request) override; + cmServerResponse Process(const cmServerRequest& request) override; private: bool DoActivate(const cmServerRequest& request, diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 5cdacaa..ffdd0ce 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -9,6 +9,7 @@ #include "cmMakefile.h" #include "cmSourceGroup.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" namespace { @@ -54,7 +55,7 @@ bool rootIsPrefix(const std::string& root, const std::vector<std::string>& files, std::string& error) { for (std::string const& file : files) { - if (!cmSystemTools::StringStartsWith(file, root.c_str())) { + if (!cmHasPrefix(file, root)) { error = "ROOT: " + root + " is not a prefix of file: " + file; return false; } @@ -63,15 +64,6 @@ bool rootIsPrefix(const std::string& root, return true; } -std::string prepareFilePathForTree(const std::string& path, - const std::string& currentSourceDir) -{ - if (!cmSystemTools::FileIsFullPath(path)) { - return cmSystemTools::CollapseFullPath(currentSourceDir + "/" + path); - } - return cmSystemTools::CollapseFullPath(path); -} - std::vector<std::string> prepareFilesPathsForTree( const std::vector<std::string>& filesPaths, const std::string& currentSourceDir) @@ -80,9 +72,11 @@ std::vector<std::string> prepareFilesPathsForTree( prepared.reserve(filesPaths.size()); for (auto const& filePath : filesPaths) { + std::string fullPath = + cmSystemTools::CollapseFullPath(filePath, currentSourceDir); // If provided file path is actually not a file, silently ignore it. - if (cmSystemTools::FileExists(filePath, /*isFile=*/true)) { - prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir)); + if (cmSystemTools::FileExists(fullPath, /*isFile=*/true)) { + prepared.emplace_back(std::move(fullPath)); } } diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx new file mode 100644 index 0000000..5deb9b0 --- /dev/null +++ b/Source/cmStringAlgorithms.cxx @@ -0,0 +1,73 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmStringAlgorithms.h" + +#include <algorithm> +#include <cstdio> + +namespace { +template <std::size_t N, typename T> +inline void MakeDigits(cm::string_view& view, char (&digits)[N], + const char* pattern, T value) +{ + int res = std::snprintf(digits, N, pattern, value); + if (res > 0 && res < static_cast<int>(N)) { + view = cm::string_view(digits, static_cast<std::size_t>(res)); + } +} +} // unnamed namespace + +cmAlphaNum::cmAlphaNum(int val) +{ + MakeDigits(View_, Digits_, "%i", val); +} + +cmAlphaNum::cmAlphaNum(unsigned int val) +{ + MakeDigits(View_, Digits_, "%u", val); +} + +cmAlphaNum::cmAlphaNum(long int val) +{ + MakeDigits(View_, Digits_, "%li", val); +} + +cmAlphaNum::cmAlphaNum(unsigned long int val) +{ + MakeDigits(View_, Digits_, "%lu", val); +} + +cmAlphaNum::cmAlphaNum(long long int val) +{ + MakeDigits(View_, Digits_, "%lli", val); +} + +cmAlphaNum::cmAlphaNum(unsigned long long int val) +{ + MakeDigits(View_, Digits_, "%llu", val); +} + +cmAlphaNum::cmAlphaNum(float val) +{ + MakeDigits(View_, Digits_, "%g", static_cast<double>(val)); +} + +cmAlphaNum::cmAlphaNum(double val) +{ + MakeDigits(View_, Digits_, "%g", val); +} + +std::string cmCatViews(std::initializer_list<cm::string_view> views) +{ + std::size_t total_size = 0; + for (cm::string_view const& view : views) { + total_size += view.size(); + } + + std::string result(total_size, '\0'); + std::string::iterator sit = result.begin(); + for (cm::string_view const& view : views) { + sit = std::copy_n(view.data(), view.size(), sit); + } + return result; +} diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 149e0ad..cdb494f 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -7,120 +7,158 @@ #include "cmRange.h" #include "cm_string_view.hxx" -#include <algorithm> -#include <iterator> +#include <initializer_list> #include <sstream> #include <string.h> #include <string> #include <utility> #include <vector> +/** String range type. */ typedef cmRange<std::vector<std::string>::const_iterator> cmStringRange; +/** Callable string comparison struct. */ struct cmStrCmp { - cmStrCmp(const char* test) - : m_test(test) - { - } - cmStrCmp(std::string test) - : m_test(std::move(test)) + cmStrCmp(std::string str) + : Test_(std::move(str)) { } - bool operator()(const std::string& input) const { return m_test == input; } - - bool operator()(const char* input) const - { - return strcmp(input, m_test.c_str()) == 0; - } + bool operator()(cm::string_view sv) const { return Test_ == sv; } private: - const std::string m_test; + std::string const Test_; }; +/** Joins elements of a range with separator into a single string. */ template <typename Range> -std::string cmJoin(Range const& r, const char* delimiter) +std::string cmJoin(Range const& rng, cm::string_view separator) { - if (r.empty()) { + if (rng.empty()) { return std::string(); } - std::ostringstream os; - typedef typename Range::value_type ValueType; - typedef typename Range::const_iterator InputIt; - const InputIt first = r.begin(); - InputIt last = r.end(); - --last; - std::copy(first, last, std::ostream_iterator<ValueType>(os, delimiter)); - - os << *last; + std::ostringstream os; + auto it = rng.begin(); + auto const end = rng.end(); + os << *it; + while (++it != end) { + os << separator << *it; + } return os.str(); } -template <typename Range> -std::string cmJoin(Range const& r, std::string const& delimiter) +/** Concatenate string pieces into a single string. */ +std::string cmCatViews(std::initializer_list<cm::string_view> views); + +/** Utility class for cmStrCat. */ +class cmAlphaNum +{ +public: + cmAlphaNum(cm::string_view view) + : View_(view) + { + } + cmAlphaNum(std::string const& str) + : View_(str) + { + } + cmAlphaNum(const char* str) + : View_(str) + { + } + cmAlphaNum(char ch) + : View_(Digits_, 1) + { + Digits_[0] = ch; + } + cmAlphaNum(int val); + cmAlphaNum(unsigned int val); + cmAlphaNum(long int val); + cmAlphaNum(unsigned long int val); + cmAlphaNum(long long int val); + cmAlphaNum(unsigned long long int val); + cmAlphaNum(float val); + cmAlphaNum(double val); + + cm::string_view View() const { return View_; } + +private: + cm::string_view View_; + char Digits_[32]; +}; + +/** Concatenate string pieces and numbers into a single string. */ +template <typename... AV> +inline std::string cmStrCat(cmAlphaNum const& a, cmAlphaNum const& b, + AV const&... args) { - return cmJoin(r, delimiter.c_str()); + return cmCatViews( + { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... }); } +/** Joins wrapped elements of a range with separator into a single string. */ template <typename Range> -std::string cmWrap(std::string const& prefix, Range const& r, - std::string const& suffix, std::string const& sep) +std::string cmWrap(cm::string_view prefix, Range const& rng, + cm::string_view suffix, cm::string_view sep) { - if (r.empty()) { + if (rng.empty()) { return std::string(); } - return prefix + cmJoin(r, suffix + sep + prefix) + suffix; + return cmCatViews( + { prefix, cmJoin(rng, cmCatViews({ suffix, sep, prefix })), suffix }); } +/** Joins wrapped elements of a range with separator into a single string. */ template <typename Range> -std::string cmWrap(char prefix, Range const& r, char suffix, - std::string const& sep) +std::string cmWrap(char prefix, Range const& rng, char suffix, + cm::string_view sep) { - return cmWrap(std::string(1, prefix), r, std::string(1, suffix), sep); + return cmWrap(cm::string_view(&prefix, 1), rng, cm::string_view(&suffix, 1), + sep); } -/** Returns true if string @a str starts with the character @a prefix. **/ +/** Returns true if string @a str starts with the character @a prefix. */ inline bool cmHasPrefix(cm::string_view str, char prefix) { return !str.empty() && (str.front() == prefix); } -/** Returns true if string @a str starts with string @a prefix. **/ +/** Returns true if string @a str starts with string @a prefix. */ inline bool cmHasPrefix(cm::string_view str, cm::string_view prefix) { return str.compare(0, prefix.size(), prefix) == 0; } -/** Returns true if string @a str starts with string @a prefix. **/ +/** Returns true if string @a str starts with string @a prefix. */ template <size_t N> inline bool cmHasLiteralPrefix(cm::string_view str, const char (&prefix)[N]) { return cmHasPrefix(str, cm::string_view(prefix, N - 1)); } -/** Returns true if string @a str ends with the character @a suffix. **/ +/** Returns true if string @a str ends with the character @a suffix. */ inline bool cmHasSuffix(cm::string_view str, char suffix) { return !str.empty() && (str.back() == suffix); } -/** Returns true if string @a str ends with string @a suffix. **/ +/** Returns true if string @a str ends with string @a suffix. */ inline bool cmHasSuffix(cm::string_view str, cm::string_view suffix) { return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } -/** Returns true if string @a str ends with string @a suffix. **/ +/** Returns true if string @a str ends with string @a suffix. */ template <size_t N> inline bool cmHasLiteralSuffix(cm::string_view str, const char (&suffix)[N]) { return cmHasSuffix(str, cm::string_view(suffix, N - 1)); } -/** Removes an existing suffix character of from the string @a str. **/ +/** Removes an existing suffix character of from the string @a str. */ inline void cmStripSuffixIfExists(std::string& str, char suffix) { if (cmHasSuffix(str, suffix)) { @@ -128,7 +166,7 @@ inline void cmStripSuffixIfExists(std::string& str, char suffix) } } -/** Removes an existing suffix string of from the string @a str. **/ +/** Removes an existing suffix string of from the string @a str. */ inline void cmStripSuffixIfExists(std::string& str, cm::string_view suffix) { if (cmHasSuffix(str, suffix)) { 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/cmTargetDepend.h b/Source/cmTargetDepend.h index 5ea0085..4ca78fa 100644 --- a/Source/cmTargetDepend.h +++ b/Source/cmTargetDepend.h @@ -31,7 +31,7 @@ public: operator cmGeneratorTarget const*() const { return this->Target; } cmGeneratorTarget const* operator->() const { return this->Target; } cmGeneratorTarget const& operator*() const { return *this->Target; } - friend bool operator<(cmTargetDepend l, cmTargetDepend r) + friend bool operator<(cmTargetDepend const& l, cmTargetDepend const& r) { return l.Target < r.Target; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4a151b3..ed6e4d9 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1235,8 +1235,11 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( if (this->IPOEnabledConfigurations.count(config) > 0) { e1.Element("WholeProgramOptimization", "true"); } - if (this->SpectreMitigationConfigurations.count(config) > 0) { - e1.Element("SpectreMitigation", "Spectre"); + { + auto s = this->SpectreMitigation.find(config); + if (s != this->SpectreMitigation.end()) { + e1.Element("SpectreMitigation", s->second); + } } } @@ -2766,8 +2769,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } } - if (clOptions.HasFlag("SpectreMitigation")) { - this->SpectreMitigationConfigurations.insert(configName); + if (const char* s = clOptions.GetFlag("SpectreMitigation")) { + this->SpectreMitigation[configName] = s; clOptions.RemoveFlag("SpectreMitigation"); } diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 860b809..6607e77 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -215,7 +215,7 @@ private: unsigned int NsightTegraVersion[4]; bool TargetCompileAsWinRT; std::set<std::string> IPOEnabledConfigurations; - std::set<std::string> SpectreMitigationConfigurations; + std::map<std::string, std::string> SpectreMitigation; cmGlobalVisualStudio10Generator* const GlobalGenerator; cmLocalVisualStudio10Generator* const LocalGenerator; std::set<std::string> CSharpCustomCommandNames; diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx index 9353276..3e7e142 100644 --- a/Source/cmVisualStudioSlnParser.cxx +++ b/Source/cmVisualStudioSlnParser.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVisualStudioSlnParser.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmVisualStudioSlnData.h" #include "cmsys/FStream.hxx" @@ -192,8 +193,8 @@ bool cmVisualStudioSlnParser::State::Process( assert(!line.IsComment()); switch (this->Stack.top()) { case FileStateStart: - if (!cmSystemTools::StringStartsWith( - line.GetTag().c_str(), "Microsoft Visual Studio Solution File")) { + if (!cmHasLiteralPrefix(line.GetTag(), + "Microsoft Visual Studio Solution File")) { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 3b4a6c0..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" }); } } @@ -620,7 +597,7 @@ void cmake::LoadEnvironmentPresets() this->EnvironmentGenerator = envGenVar; } - auto readGeneratorVar = [&](std::string name, std::string& key) { + auto readGeneratorVar = [&](std::string const& name, std::string& key) { std::string varValue; if (cmSystemTools::GetEnv(name, varValue)) { if (hasEnvironmentGenerator) { @@ -2031,8 +2008,7 @@ void cmake::AppendGlobalGeneratorsDocumentation( for (cmGlobalGeneratorFactory* g : this->Generators) { cmDocumentationEntry e; g->GetDocumentation(e); - if (!foundDefaultOne && - cmSystemTools::StringStartsWith(e.Name, defaultName.c_str())) { + if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) { e.CustomNamePrefix = '*'; foundDefaultOne = true; } 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/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index a25f25a..cd4dbc8 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -10,6 +10,7 @@ set(CMakeLib_TESTS testRST.cxx testRange.cxx testString.cxx + testStringAlgorithms.cxx testSystemTools.cxx testUTF8.cxx testXMLParser.cxx diff --git a/Tests/CMakeLib/testStringAlgorithms.cxx b/Tests/CMakeLib/testStringAlgorithms.cxx new file mode 100644 index 0000000..95616ff --- /dev/null +++ b/Tests/CMakeLib/testStringAlgorithms.cxx @@ -0,0 +1,134 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include <cmConfigure.h> // IWYU pragma: keep + +#include "cm_string_view.hxx" +#include <iostream> +#include <sstream> +#include <string> +#include <vector> + +#include "cmStringAlgorithms.h" + +int testStringAlgorithms(int /*unused*/, char* /*unused*/ []) +{ + int failed = 0; + + auto assert_ok = [&failed](bool test, cm::string_view title) { + if (test) { + std::cout << "Passed: " << title << "\n"; + } else { + std::cout << "Failed: " << title << "\n"; + ++failed; + } + }; + + auto assert_string = [&failed](cm::string_view generated, + cm::string_view expected, + cm::string_view title) { + if (generated == expected) { + std::cout << "Passed: " << title << "\n"; + } else { + std::cout << "Failed: " << title << "\n"; + std::cout << "Expected: " << expected << "\n"; + std::cout << "Got: " << generated << "\n"; + ++failed; + } + }; + + // ---------------------------------------------------------------------- + // Test cmJoin + { + typedef std::string ST; + typedef std::vector<std::string> VT; + assert_string(cmJoin(ST("abc"), ";"), "a;b;c", "cmJoin std::string"); + assert_string(cmJoin(VT{}, ";"), "", "cmJoin std::vector empty"); + assert_string(cmJoin(VT{ "a" }, ";"), "a", "cmJoin std::vector single"); + assert_string(cmJoin(VT{ "a", "b", "c" }, ";"), "a;b;c", + "cmJoin std::vector multiple"); + assert_string(cmJoin(VT{ "a", "b", "c" }, "<=>"), "a<=>b<=>c", + "cmJoin std::vector long sep"); + } + + // ---------------------------------------------------------------------- + // Test cmStrCat + { + int ni = -1100; + unsigned int nui = 1100u; + long int nli = -12000l; + unsigned long int nuli = 12000ul; + long long int nlli = -130000ll; + unsigned long long int nulli = 130000ull; + std::string val = + cmStrCat("<test>", ni, ',', nui, ',', nli, ",", nuli, ", ", nlli, + std::string(", "), nulli, cm::string_view("</test>")); + std::string expect = + "<test>-1100,1100,-12000,12000, -130000, 130000</test>"; + assert_string(val, expect, "cmStrCat strings and integers"); + } + { + float const val = 1.5f; + float const div = 0.00001f; + float f = 0.0f; + std::istringstream(cmStrCat("", val)) >> f; + f -= val; + assert_ok((f < div) && (f > -div), "cmStrCat float"); + } + { + double const val = 1.5; + double const div = 0.00001; + double d = 0.0; + std::istringstream(cmStrCat("", val)) >> d; + d -= val; + assert_ok((d < div) && (d > -div), "cmStrCat double"); + } + + // ---------------------------------------------------------------------- + // Test cmWrap + { + typedef std::vector<std::string> VT; + assert_string(cmWrap("<", VT{}, ">", "; "), // + "", // + "cmWrap empty, string prefix and suffix"); + assert_string(cmWrap("<", VT{ "abc" }, ">", "; "), // + "<abc>", // + "cmWrap single, string prefix and suffix"); + assert_string(cmWrap("<", VT{ "a1", "a2", "a3" }, ">", "; "), // + "<a1>; <a2>; <a3>", // + "cmWrap multiple, string prefix and suffix"); + + assert_string(cmWrap('<', VT{}, '>', "; "), // + "", // + "cmWrap empty, char prefix and suffix"); + assert_string(cmWrap('<', VT{ "abc" }, '>', "; "), // + "<abc>", // + "cmWrap single, char prefix and suffix"); + assert_string(cmWrap('<', VT{ "a1", "a2", "a3" }, '>', "; "), // + "<a1>; <a2>; <a3>", // + "cmWrap multiple, char prefix and suffix"); + } + + // ---------------------------------------------------------------------- + // Test cmHas(Literal)Prefix and cmHas(Literal)Suffix + { + std::string str("abc"); + assert_ok(cmHasPrefix(str, 'a'), "cmHasPrefix char"); + assert_ok(!cmHasPrefix(str, 'c'), "cmHasPrefix char not"); + assert_ok(cmHasPrefix(str, "ab"), "cmHasPrefix string"); + assert_ok(!cmHasPrefix(str, "bc"), "cmHasPrefix string not"); + assert_ok(cmHasPrefix(str, str), "cmHasPrefix complete string"); + assert_ok(cmHasLiteralPrefix(str, "ab"), "cmHasLiteralPrefix string"); + assert_ok(!cmHasLiteralPrefix(str, "bc"), "cmHasLiteralPrefix string not"); + + assert_ok(cmHasSuffix(str, 'c'), "cmHasSuffix char"); + assert_ok(!cmHasSuffix(str, 'a'), "cmHasSuffix char not"); + assert_ok(cmHasSuffix(str, "bc"), "cmHasSuffix string"); + assert_ok(!cmHasSuffix(str, "ab"), "cmHasSuffix string not"); + assert_ok(cmHasSuffix(str, str), "cmHasSuffix complete string"); + assert_ok(cmHasLiteralSuffix(str, "bc"), "cmHasLiteralSuffix string"); + assert_ok(!cmHasLiteralSuffix(str, "ab"), "cmHasLiteralPrefix string not"); + } + + return failed; +} diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt index 1aeab8b..19f3f79 100644 --- a/Tests/CMakeOnly/CMakeLists.txt +++ b/Tests/CMakeOnly/CMakeLists.txt @@ -84,5 +84,5 @@ function(add_major_test module) endfunction() add_major_test(PythonLibs VERSIONS 2 3 VERSION_VAR PYTHONLIBS_VERSION_STRING) -add_major_test(PythonInterp NOLANG VERSIONS 2 3 VERSION_VAR PYTHON_VERSION_STRING) +add_major_test(PythonInterp NOLANG VERSIONS 3 VERSION_VAR PYTHON_VERSION_STRING) add_major_test(Qt VERSIONS 3 4 VERSION_VAR QT_VERSION_STRING) 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/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index 5b2c7cb..1cb4ce5 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -28,3 +28,7 @@ run_cmake(VsDpiAwareBadParam) if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.05) run_cmake(VsJustMyCode) endif() + +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20) + run_cmake(VsSpectreMitigation) +endif() diff --git a/Tests/RunCMake/VS10Project/VsSpectreMitigation-check.cmake b/Tests/RunCMake/VS10Project/VsSpectreMitigation-check.cmake new file mode 100644 index 0000000..6117763 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsSpectreMitigation-check.cmake @@ -0,0 +1,30 @@ +macro(VsSpectreMitigation_check tgt spectre_expect) + set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/${tgt}.vcxproj") + if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not exist.") + return() + endif() + + set(HAVE_SpectreMitigation 0) + + file(STRINGS "${vcProjectFile}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "^ *<SpectreMitigation>([^<>]+)</SpectreMitigation>") + set(spectre_actual "${CMAKE_MATCH_1}") + if(NOT "${spectre_actual}" STREQUAL "${spectre_expect}") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj has <SpectreMitigation> '${spectre_actual}', not '${spectre_expect}'.") + return() + endif() + set(HAVE_SpectreMitigation 1) + break() + endif() + endforeach() + + if(NOT HAVE_SpectreMitigation AND NOT "${spectre_expect}" STREQUAL "") + set(RunCMake_TEST_FAILED "Project file ${tgt}.vcxproj does not have a <SpectreMitigation> field.") + return() + endif() +endmacro() + +VsSpectreMitigation_check(SpectreMitigationOn-C "Spectre") +VsSpectreMitigation_check(SpectreMitigationOff-C "false") diff --git a/Tests/RunCMake/VS10Project/VsSpectreMitigation.cmake b/Tests/RunCMake/VS10Project/VsSpectreMitigation.cmake new file mode 100644 index 0000000..b3779d7 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsSpectreMitigation.cmake @@ -0,0 +1,8 @@ +set(CMAKE_CONFIGURATION_TYPES Debug) +enable_language(C) + +add_library(SpectreMitigationOn-C empty.c) +target_compile_options(SpectreMitigationOn-C PRIVATE -Qspectre) + +add_library(SpectreMitigationOff-C empty.c) +target_compile_options(SpectreMitigationOff-C PRIVATE -Qspectre-) 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) diff --git a/Tests/SwiftOnly/CMakeLists.txt b/Tests/SwiftOnly/CMakeLists.txt index e5f8588..f4cbac2 100644 --- a/Tests/SwiftOnly/CMakeLists.txt +++ b/Tests/SwiftOnly/CMakeLists.txt @@ -8,3 +8,6 @@ elseif(NOT XCODE_VERSION VERSION_LESS 8.0) endif() add_executable(SwiftOnly main.swift) + +# Dummy to make sure generation works with such targets. +add_library(SwiftIface INTERFACE) @@ -423,6 +423,7 @@ CMAKE_CXX_SOURCES="\ cmState \ cmStateDirectory \ cmStateSnapshot \ + cmStringAlgorithms \ cmStringReplaceHelper \ cmStringCommand \ cmSubdirCommand \ |