diff options
Diffstat (limited to 'Source')
126 files changed, 2567 insertions, 1838 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 0142c07..7e37141 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -10,36 +10,6 @@ if (NOT CMAKE_SYSTEM_NAME STREQUAL "QNX") endif() include(CheckIncludeFile) -# Check if we can build support for ELF parsing. -if(WIN32) - set(HAVE_ELF_H 0) -elseif(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD") - CHECK_INCLUDE_FILES("stdint.h;elf_abi.h" HAVE_ELF_H) -else() - CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H) -endif() -if(HAVE_ELF_H) - set(CMake_USE_ELF_PARSER 1) -elseif(HAIKU) - # On Haiku, we need to include elf32.h from the private headers - set(CMake_HAIKU_INCLUDE_DIRS - /boot/system/develop/headers/private/system - /boot/system/develop/headers/private/system/arch/x86 - ) - - set(CMAKE_REQUIRED_INCLUDES ${CMake_HAIKU_INCLUDE_DIRS}) - CHECK_INCLUDE_FILE("elf32.h" HAVE_ELF32_H) - unset(CMAKE_REQUIRED_INCLUDES) - - if(HAVE_ELF32_H) - set(CMake_USE_ELF_PARSER 1) - else() - unset(CMake_HAIKU_INCLUDE_DIRS) - set(CMake_USE_ELF_PARSER) - endif() -else() - set(CMake_USE_ELF_PARSER) -endif() if(NOT CMake_DEFAULT_RECURSION_LIMIT) if(DEFINED ENV{DASHBOARD_TEST_FROM_CTEST}) @@ -111,11 +81,6 @@ include_directories( ${CMake_HAIKU_INCLUDE_DIRS} ) -# Check if we can build the ELF parser. -if(CMake_USE_ELF_PARSER) - set(ELF_SRCS cmELF.h cmELF.cxx) -endif() - # Check if we can build the Mach-O parser. if(CMake_USE_MACH_PARSER) set(MACH_SRCS cmMachO.h cmMachO.cxx) @@ -245,7 +210,8 @@ set(SRCS cmDocumentationSection.cxx cmDynamicLoader.cxx cmDynamicLoader.h - ${ELF_SRCS} + cmELF.h + cmELF.cxx cmExprParserHelper.cxx cmExportBuildAndroidMKGenerator.h cmExportBuildAndroidMKGenerator.cxx @@ -415,6 +381,7 @@ set(SRCS cmProcessOutput.h cmProcessTools.cxx cmProcessTools.h + cmProperty.cxx cmProperty.h cmPropertyDefinition.cxx cmPropertyDefinition.h @@ -432,8 +399,6 @@ set(SRCS cmQtAutoMocUic.h cmQtAutoRcc.cxx cmQtAutoRcc.h - cmQtAutoUicHelpers.cxx - cmQtAutoUicHelpers.h cmRST.cxx cmRST.h cmRuntimeDependencyArchive.cxx @@ -996,6 +961,7 @@ set(CTEST_SRCS cmCTest.cxx CTest/cmCTestSubmitHandler.cxx CTest/cmCTestTestCommand.cxx CTest/cmCTestTestHandler.cxx + CTest/cmCTestTestMeasurementXMLParser.cxx CTest/cmCTestUpdateCommand.cxx CTest/cmCTestUpdateHandler.cxx CTest/cmCTestUploadCommand.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 88263e0..d10822f 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 21) -set(CMake_VERSION_PATCH 1) +set(CMake_VERSION_PATCH 20210824) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 006d66d..829cef4 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -2,11 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCPackDebGenerator.h" -#include <cstdlib> +#include <algorithm> #include <cstring> #include <map> #include <ostream> #include <set> +#include <stdexcept> #include <utility> #include "cmsys/Glob.hxx" @@ -54,7 +55,7 @@ private: const std::string TopLevelDir; const std::string TemporaryDir; const char* DebianArchiveType; - int NumThreads; + long NumThreads; const std::map<std::string, std::string> ControlValues; const bool GenShLibs; const std::string ShLibsFilename; @@ -98,19 +99,22 @@ DebGenerator::DebGenerator( debianCompressionType = "gzip"; } - if (!strcmp(debianCompressionType, "lzma")) { + if (!std::strcmp(debianCompressionType, "lzma")) { this->CompressionSuffix = ".lzma"; this->TarCompressionType = cmArchiveWrite::CompressLZMA; - } else if (!strcmp(debianCompressionType, "xz")) { + } else if (!std::strcmp(debianCompressionType, "xz")) { this->CompressionSuffix = ".xz"; this->TarCompressionType = cmArchiveWrite::CompressXZ; - } else if (!strcmp(debianCompressionType, "bzip2")) { + } else if (!std::strcmp(debianCompressionType, "bzip2")) { this->CompressionSuffix = ".bz2"; this->TarCompressionType = cmArchiveWrite::CompressBZip2; - } else if (!strcmp(debianCompressionType, "gzip")) { + } else if (!std::strcmp(debianCompressionType, "gzip")) { this->CompressionSuffix = ".gz"; this->TarCompressionType = cmArchiveWrite::CompressGZip; - } else if (!strcmp(debianCompressionType, "none")) { + } else if (!std::strcmp(debianCompressionType, "zstd")) { + this->CompressionSuffix = ".zst"; + this->TarCompressionType = cmArchiveWrite::CompressZstd; + } else if (!std::strcmp(debianCompressionType, "none")) { this->CompressionSuffix.clear(); this->TarCompressionType = cmArchiveWrite::CompressNone; } else { @@ -119,16 +123,15 @@ DebGenerator::DebGenerator( << debianCompressionType << std::endl); } - if (numThreads == nullptr) { - numThreads = "1"; - } - - char* endptr; - this->NumThreads = static_cast<int>(strtol(numThreads, &endptr, 10)); - if (numThreads != endptr && *endptr != '\0') { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Unrecognized number of threads: " << numThreads - << std::endl); + if (numThreads != nullptr) { + if (!cmStrToLong(numThreads, &this->NumThreads)) { + this->NumThreads = 1; + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Unrecognized number of threads: " << numThreads + << std::endl); + } + } else { + this->NumThreads = 1; } } @@ -187,8 +190,15 @@ bool DebGenerator::generateDataTar() const return false; } cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType, - this->DebianArchiveType, 0, this->NumThreads); - data_tar.Open(); + this->DebianArchiveType, 0, + static_cast<int>(this->NumThreads)); + if (!data_tar.Open()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error opening the archive \"" + << filename_data_tar + << "\", ERROR = " << data_tar.GetError() << std::endl); + return false; + } // uid/gid should be the one of the root user, and this root user has // always uid/gid equal to 0. @@ -248,11 +258,15 @@ bool DebGenerator::generateDataTar() const // do not recurse because the loop will do it if (!data_tar.Add(file, topLevelLength, ".", false)) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Problem adding file to tar:" - << std::endl - << "#top level directory: " << this->WorkDir << std::endl - << "#file: " << file << std::endl - << "#error:" << data_tar.GetError() << std::endl); + "Problem adding file to tar:\n" + "#top level directory: " + << this->WorkDir + << "\n" + "#file: " + << file + << "\n" + "#error:" + << data_tar.GetError() << std::endl); return false; } } @@ -309,7 +323,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const cmArchiveWrite control_tar(fileStream_control_tar, cmArchiveWrite::CompressGZip, this->DebianArchiveType); - control_tar.Open(); + if (!control_tar.Open()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error opening the archive \"" + << filename_control_tar + << "\", ERROR = " << control_tar.GetError() << std::endl); + return false; + } // sets permissions and uid/gid for the files control_tar.SetUIDAndGID(0u, 0u); @@ -334,11 +354,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const !control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(), ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error adding file to tar:" - << std::endl - << "#top level directory: " << this->WorkDir << std::endl - << "#file: \"control\" or \"md5sums\"" << std::endl - << "#error:" << control_tar.GetError() << std::endl); + "Error adding file to tar:\n" + "#top level directory: " + << this->WorkDir + << "\n" + "#file: \"control\" or \"md5sums\"\n" + "#error:" + << control_tar.GetError() << std::endl); return false; } @@ -346,11 +368,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const if (this->GenShLibs) { if (!control_tar.Add(this->ShLibsFilename, this->WorkDir.length(), ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error adding file to tar:" - << std::endl - << "#top level directory: " << this->WorkDir << std::endl - << "#file: \"shlibs\"" << std::endl - << "#error:" << control_tar.GetError() << std::endl); + "Error adding file to tar:\n" + "#top level directory: " + << this->WorkDir + << "\n" + "#file: \"shlibs\"\n" + "#error:" + << control_tar.GetError() << std::endl); return false; } } @@ -360,11 +384,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const control_tar.SetPermissions(permission755); if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error adding file to tar:" - << std::endl - << "#top level directory: " << this->WorkDir << std::endl - << "#file: \"postinst\"" << std::endl - << "#error:" << control_tar.GetError() << std::endl); + "Error adding file to tar:\n" + "#top level directory: " + << this->WorkDir + << "\n" + "#file: \"postinst\"\n" + "#error:" + << control_tar.GetError() << std::endl); return false; } control_tar.SetPermissions(permission644); @@ -374,11 +400,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const control_tar.SetPermissions(permission755); if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error adding file to tar:" - << std::endl - << "#top level directory: " << this->WorkDir << std::endl - << "#file: \"postinst\"" << std::endl - << "#error:" << control_tar.GetError() << std::endl); + "Error adding file to tar:\n" + "#top level directory: " + << this->WorkDir + << "\n" + "#file: \"postinst\"\n" + "#error:" + << control_tar.GetError() << std::endl); return false; } control_tar.SetPermissions(permission644); @@ -412,11 +440,12 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const // if we can copy the file, it means it does exist, let's add it: if (!cmsys::SystemTools::FileExists(i)) { cmCPackLogger(cmCPackLog::LOG_WARNING, - "Adding file to tar:" << std::endl - << "#top level directory: " - << this->WorkDir << std::endl - << "#missing file: " << i - << std::endl); + "Adding file to tar:\n" + "#top level directory: " + << this->WorkDir + << "\n" + "#missing file: " + << i << std::endl); } if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) { @@ -440,7 +469,13 @@ bool DebGenerator::generateDeb() const cmGeneratedFileStream debStream; debStream.Open(outputPath, false, true); cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd"); - deb.Open(); + if (!deb.Open()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error opening the archive \"" + << outputPath << "\", ERROR = " << deb.GetError() + << std::endl); + return false; + } // uid/gid should be the one of the root user, and this root user has // always uid/gid equal to 0. @@ -451,17 +486,37 @@ bool DebGenerator::generateDeb() const !deb.Add(tlDir + "control.tar.gz", tlDir.length()) || !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error creating debian package:" - << std::endl - << "#top level directory: " << this->TopLevelDir - << std::endl - << "#file: " << this->OutputName << std::endl - << "#error:" << deb.GetError() << std::endl); + "Error creating debian package:\n" + "#top level directory: " + << this->TopLevelDir + << "\n" + "#file: " + << this->OutputName + << "\n" + "#error:" + << deb.GetError() << std::endl); return false; } return true; } +std::vector<std::string> findFilesIn(const std::string& path) +{ + cmsys::Glob gl; + std::string findExpr = path + "/*"; + gl.RecurseOn(); + gl.SetRecurseListDirs(true); + gl.SetRecurseThroughSymlinks(false); + if (!gl.FindFiles(findExpr)) { + throw std::runtime_error( + "Cannot find any files in the installed directory"); + } + std::vector<std::string> files{ gl.GetFiles() }; + // Sort files so that they have a reproducible order + std::sort(files.begin(), files.end()); + return files; +} + } // end anonymous namespace cmCPackDebGenerator::cmCPackDebGenerator() = default; @@ -480,7 +535,6 @@ int cmCPackDebGenerator::InitializeInternal() int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, std::string const& packageName) { - int retval = 1; // Begin the archive for this pack std::string localToplevel(initialTopLevel); std::string packageFileName( @@ -507,101 +561,48 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackDeb.cmake" << std::endl); - retval = 0; - return retval; - } - - { // Isolate globbing of binaries vs. dbgsyms - cmsys::Glob gl; - std::string findExpr(this->GetOption("GEN_WDIR")); - findExpr += "/*"; - gl.RecurseOn(); - gl.SetRecurseListDirs(true); - gl.SetRecurseThroughSymlinks(false); - if (!gl.FindFiles(findExpr)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Cannot find any files in the installed directory" - << std::endl); - return 0; - } - this->packageFiles = gl.GetFiles(); - } - - int res = this->createDeb(); - if (res != 1) { - retval = 0; - } - // add the generated package to package file names list - packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/', - this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME")); - this->packageFileNames.push_back(std::move(packageFileName)); - - if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") && - this->GetOption("GEN_DBGSYMDIR")) { - cmsys::Glob gl; - std::string findExpr(this->GetOption("GEN_DBGSYMDIR")); - findExpr += "/*"; - gl.RecurseOn(); - gl.SetRecurseListDirs(true); - gl.SetRecurseThroughSymlinks(false); - if (!gl.FindFiles(findExpr)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Cannot find any files in the installed directory" - << std::endl); - return 0; - } - this->packageFiles = gl.GetFiles(); - - res = this->createDbgsymDDeb(); - if (res != 1) { - retval = 0; - } - // add the generated package to package file names list - packageFileName = - cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/', - this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME")); - this->packageFileNames.push_back(std::move(packageFileName)); + return 0; } - return retval; + return this->createDebPackages(); } int cmCPackDebGenerator::PackageComponents(bool ignoreGroup) { - int retval = 1; - /* Reset package file name list it will be populated during the - * component packaging run*/ + // Reset package file name list it will be populated during the + // component packaging run this->packageFileNames.clear(); std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); + int retval = 1; // The default behavior is to have one package by component group // unless CPACK_COMPONENTS_IGNORE_GROUP is specified. - if (!ignoreGroup) { - for (auto const& compG : this->ComponentGroups) { - cmCPackLogger(cmCPackLog::LOG_VERBOSE, - "Packaging component group: " << compG.first << std::endl); - // Begin the archive for this group - retval &= this->PackageOnePack(initialTopLevel, compG.first); - } - // Handle Orphan components (components not belonging to any groups) + if (ignoreGroup) { + // CPACK_COMPONENTS_IGNORE_GROUPS is set + // We build 1 package per component for (auto const& comp : this->Components) { - // Does the component belong to a group? - if (comp.second.Group == nullptr) { - cmCPackLogger( - cmCPackLog::LOG_VERBOSE, - "Component <" - << comp.second.Name - << "> does not belong to any group, package it separately." - << std::endl); - // Begin the archive for this orphan component - retval &= this->PackageOnePack(initialTopLevel, comp.first); - } + retval &= this->PackageOnePack(initialTopLevel, comp.first); } + return retval; } - // CPACK_COMPONENTS_IGNORE_GROUPS is set - // We build 1 package per component - else { - for (auto const& comp : this->Components) { + + for (auto const& compG : this->ComponentGroups) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Packaging component group: " << compG.first << std::endl); + // Begin the archive for this group + retval &= this->PackageOnePack(initialTopLevel, compG.first); + } + // Handle Orphan components (components not belonging to any groups) + for (auto const& comp : this->Components) { + // Does the component belong to a group? + if (comp.second.Group == nullptr) { + cmCPackLogger( + cmCPackLog::LOG_VERBOSE, + "Component <" + << comp.second.Name + << "> does not belong to any group, package it separately." + << std::endl); + // Begin the archive for this orphan component retval &= this->PackageOnePack(initialTopLevel, comp.first); } } @@ -612,7 +613,6 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup) int cmCPackDebGenerator::PackageComponentsAllInOne( const std::string& compInstDirName) { - int retval = 1; /* Reset package file name list it will be populated during the * component packaging run*/ this->packageFileNames.clear(); @@ -655,33 +655,10 @@ int cmCPackDebGenerator::PackageComponentsAllInOne( if (!this->ReadListFile("Internal/CPack/CPackDeb.cmake")) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackDeb.cmake" << std::endl); - retval = 0; - return retval; - } - - cmsys::Glob gl; - std::string findExpr(this->GetOption("GEN_WDIR")); - findExpr += "/*"; - gl.RecurseOn(); - gl.SetRecurseListDirs(true); - gl.SetRecurseThroughSymlinks(false); - if (!gl.FindFiles(findExpr)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Cannot find any files in the installed directory" - << std::endl); return 0; } - this->packageFiles = gl.GetFiles(); - int res = this->createDeb(); - if (res != 1) { - retval = 0; - } - // add the generated package to package file names list - packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/', - this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME")); - this->packageFileNames.push_back(std::move(packageFileName)); - return retval; + return this->createDebPackages(); } int cmCPackDebGenerator::PackageFiles() @@ -705,7 +682,40 @@ int cmCPackDebGenerator::PackageFiles() return this->PackageComponentsAllInOne(""); } -int cmCPackDebGenerator::createDeb() +bool cmCPackDebGenerator::createDebPackages() +{ + auto make_package = [this](const char* const path, + const char* const output_var, + bool (cmCPackDebGenerator::*creator)()) -> bool { + try { + this->packageFiles = findFilesIn(path); + } catch (const std::runtime_error& ex) { + cmCPackLogger(cmCPackLog::LOG_ERROR, ex.what() << std::endl); + return false; + } + + if ((this->*creator)()) { + // add the generated package to package file names list + this->packageFileNames.emplace_back( + cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/', + this->GetOption(output_var))); + return true; + } + return false; + }; + bool retval = + make_package(this->GetOption("GEN_WDIR"), "GEN_CPACK_OUTPUT_FILE_NAME", + &cmCPackDebGenerator::createDeb); + const char* const dbgsymdir_path = this->GetOption("GEN_DBGSYMDIR"); + if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") && dbgsymdir_path) { + retval = make_package(dbgsymdir_path, "GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME", + &cmCPackDebGenerator::createDbgsymDDeb) && + retval; + } + return int(retval); +} + +bool cmCPackDebGenerator::createDeb() { std::map<std::string, std::string> controlValues; @@ -829,13 +839,10 @@ int cmCPackDebGenerator::createDeb() this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"), this->packageFiles); - if (!gen.generate()) { - return 0; - } - return 1; + return gen.generate(); } -int cmCPackDebGenerator::createDbgsymDDeb() +bool cmCPackDebGenerator::createDbgsymDDeb() { // Packages containing debug symbols follow the same structure as .debs // but have different metadata and content. @@ -875,7 +882,6 @@ int cmCPackDebGenerator::createDbgsymDDeb() DebGenerator gen( this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"), this->GetOption("GEN_DBGSYMDIR"), - this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), this->GetOption("CPACK_TEMPORARY_DIRECTORY"), this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"), @@ -885,10 +891,7 @@ int cmCPackDebGenerator::createDbgsymDDeb() this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"), this->packageFiles); - if (!gen.generate()) { - return 0; - } - return 1; + return gen.generate(); } bool cmCPackDebGenerator::SupportsComponentInstallation() const diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h index ee8f39a..61a6616 100644 --- a/Source/CPack/cmCPackDebGenerator.h +++ b/Source/CPack/cmCPackDebGenerator.h @@ -63,8 +63,9 @@ protected: const std::string& componentName) override; private: - int createDeb(); - int createDbgsymDDeb(); + bool createDebPackages(); + bool createDeb(); + bool createDbgsymDDeb(); std::vector<std::string> packageFiles; }; diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index 6bd0d1b..395b1df 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -235,6 +235,13 @@ int cmCPackNSISGenerator::PackageFiles() brandingTextCode.c_str()); } + if (!this->IsSet("CPACK_NSIS_IGNORE_LICENSE_PAGE")) { + std::string licenceCode = + cmStrCat("!insertmacro MUI_PAGE_LICENSE \"", + this->GetOption("CPACK_RESOURCE_FILE_LICENSE"), "\"\n"); + this->SetOptionIfNotSet("CPACK_NSIS_LICENSE_PAGE", licenceCode.c_str()); + } + // Setup all of the component sections if (this->Components.empty()) { this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", ""); @@ -487,12 +494,12 @@ int cmCPackNSISGenerator::InitializeInternal() } if (versionRex.find(output)) { double nsisVersion = atof(versionRex.match(1).c_str()); - double minNSISVersion = 3.0; + double minNSISVersion = 3.03; cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: " << nsisVersion << std::endl); if (nsisVersion < minNSISVersion) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "CPack requires NSIS Version 3.0 or greater. " + "CPack requires NSIS Version 3.03 or greater. " "NSIS found on the system was: " << nsisVersion << std::endl); return 0; diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 125d003..6bb8e79 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -305,7 +305,7 @@ int cmCTestMemCheckHandler::GetDefectCount() const return this->DefectCount; } -void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) +void cmCTestMemCheckHandler::GenerateCTestXML(cmXMLWriter& xml) { if (!this->CTest->GetProduceXML()) { return; diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index b200c43..a63a24d 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -119,9 +119,9 @@ private: bool InitializeMemoryChecking(); /** - * Generate the Dart compatible output + * Generate CTest DynamicAnalysis.xml files */ - void GenerateDartOutput(cmXMLWriter& xml) override; + void GenerateCTestXML(cmXMLWriter& xml) override; std::vector<std::string> CustomPreMemCheck; std::vector<std::string> CustomPostMemCheck; diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 86a8e00..d90c4a6 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -1026,6 +1026,11 @@ static Json::Value DumpCTestProperties( properties.append(DumpCTestProperty( "ENVIRONMENT", DumpToJsonArray(testProperties.Environment))); } + if (!testProperties.EnvironmentModification.empty()) { + properties.append(DumpCTestProperty( + "ENVIRONMENT_MODIFICATION", + DumpToJsonArray(testProperties.EnvironmentModification))); + } if (!testProperties.ErrorRegularExpressions.empty()) { properties.append(DumpCTestProperty( "FAIL_REGULAR_EXPRESSION", diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index a892113..20f0ed3 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -2,17 +2,22 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestRunTest.h" +#include <algorithm> #include <chrono> #include <cstddef> // IWYU pragma: keep #include <cstdint> #include <cstdio> #include <cstring> +#include <functional> #include <iomanip> #include <ratio> #include <sstream> #include <utility> #include <cm/memory> +#include <cm/optional> +#include <cm/string_view> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" @@ -44,7 +49,9 @@ void cmCTestRunTest::CheckOutput(std::string const& line) // Check for special CTest XML tags in this line of output. // If any are found, this line is excluded from ProcessOutput. if (!line.empty() && line.find("<CTest") != std::string::npos) { + bool ctest_tag_found = false; if (this->TestHandler->CustomCompletionStatusRegex.find(line)) { + ctest_tag_found = true; this->TestResult.CustomCompletionStatus = this->TestHandler->CustomCompletionStatusRegex.match(1); cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, @@ -52,6 +59,20 @@ void cmCTestRunTest::CheckOutput(std::string const& line) << "Test Details changed to '" << this->TestResult.CustomCompletionStatus << "'" << std::endl); + } else if (this->TestHandler->CustomLabelRegex.find(line)) { + ctest_tag_found = true; + auto label = this->TestHandler->CustomLabelRegex.match(1); + auto& labels = this->TestProperties->Labels; + if (std::find(labels.begin(), labels.end(), label) == labels.end()) { + labels.push_back(label); + std::sort(labels.begin(), labels.end()); + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + this->GetIndex() + << ": " + << "Test Label added: '" << label << "'" << std::endl); + } + } + if (ctest_tag_found) { return; } } @@ -245,7 +266,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) *this->TestHandler->LogFile << "Test time = " << buf << std::endl; } - this->DartProcessing(); + this->ParseOutputForMeasurements(); // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler @@ -623,6 +644,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout, &this->TestProperties->Environment, + &this->TestProperties->EnvironmentModification, &this->TestProperties->Affinity); } @@ -679,28 +701,45 @@ void cmCTestRunTest::ComputeArguments() cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->Index << ": " << env << std::endl); } + if (!this->TestProperties->EnvironmentModification.empty()) { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + this->Index << ": " + << "Environment variable modifications: " + << std::endl); + } + for (std::string const& envmod : + this->TestProperties->EnvironmentModification) { + cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, + this->Index << ": " << envmod << std::endl); + } } -void cmCTestRunTest::DartProcessing() +void cmCTestRunTest::ParseOutputForMeasurements() { if (!this->ProcessOutput.empty() && - this->ProcessOutput.find("<DartMeasurement") != std::string::npos) { - if (this->TestHandler->DartStuff.find(this->ProcessOutput)) { - this->TestResult.DartString = this->TestHandler->DartStuff.match(1); + (this->ProcessOutput.find("<DartMeasurement") != std::string::npos || + this->ProcessOutput.find("<CTestMeasurement") != std::string::npos)) { + if (this->TestHandler->AllTestMeasurementsRegex.find( + this->ProcessOutput)) { + this->TestResult.TestMeasurementsOutput = + this->TestHandler->AllTestMeasurementsRegex.match(1); // keep searching and replacing until none are left - while (this->TestHandler->DartStuff1.find(this->ProcessOutput)) { + while (this->TestHandler->SingleTestMeasurementRegex.find( + this->ProcessOutput)) { // replace the exact match for the string cmSystemTools::ReplaceString( - this->ProcessOutput, this->TestHandler->DartStuff1.match(1).c_str(), - ""); + this->ProcessOutput, + this->TestHandler->SingleTestMeasurementRegex.match(1).c_str(), ""); } } } } -bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, - std::vector<std::string>* environment, - std::vector<size_t>* affinity) +bool cmCTestRunTest::ForkProcess( + cmDuration testTimeOut, bool explicitTimeout, + std::vector<std::string>* environment, + std::vector<std::string>* environment_modification, + std::vector<size_t>* affinity) { this->TestProcess->SetId(this->Index); this->TestProcess->SetWorkingDirectory(this->TestProperties->Directory); @@ -749,6 +788,127 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout, } } + if (environment_modification && !environment_modification->empty()) { + std::map<std::string, cm::optional<std::string>> env_application; + +#ifdef _WIN32 + char path_sep = ';'; +#else + char path_sep = ':'; +#endif + + auto apply_diff = + [&env_application](const std::string& name, + std::function<void(std::string&)> const& apply) { + auto entry = env_application.find(name); + std::string output; + if (entry != env_application.end() && entry->second) { + output = *entry->second; + } + apply(output); + entry->second = output; + }; + + bool err_occurred = false; + + for (auto const& envmod : *environment_modification) { + // Split on `=` + auto const eq_loc = envmod.find_first_of('='); + if (eq_loc == std::string::npos) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error: Missing `=` after the variable name in: " + << envmod << std::endl); + err_occurred = true; + continue; + } + auto const name = envmod.substr(0, eq_loc); + + // Split value on `:` + auto const op_value_start = eq_loc + 1; + auto const colon_loc = envmod.find_first_of(':', op_value_start); + if (colon_loc == std::string::npos) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error: Missing `:` after the operation in: " << envmod + << std::endl); + err_occurred = true; + continue; + } + auto const op = + envmod.substr(op_value_start, colon_loc - op_value_start); + + auto const value_start = colon_loc + 1; + auto const value = envmod.substr(value_start); + + // Determine what to do with the operation. + if (op == "reset"_s) { + auto entry = env_application.find(name); + if (entry != env_application.end()) { + env_application.erase(entry); + } + } else if (op == "set"_s) { + env_application[name] = value; + } else if (op == "unset"_s) { + env_application[name] = {}; + } else if (op == "string_append"_s) { + apply_diff(name, [&value](std::string& output) { output += value; }); + } else if (op == "string_prepend"_s) { + apply_diff(name, + [&value](std::string& output) { output.insert(0, value); }); + } else if (op == "path_list_append"_s) { + apply_diff(name, [&value, path_sep](std::string& output) { + if (!output.empty()) { + output += path_sep; + } + output += value; + }); + } else if (op == "path_list_prepend"_s) { + apply_diff(name, [&value, path_sep](std::string& output) { + if (!output.empty()) { + output.insert(output.begin(), path_sep); + } + output.insert(0, value); + }); + } else if (op == "cmake_list_append"_s) { + apply_diff(name, [&value](std::string& output) { + if (!output.empty()) { + output += ';'; + } + output += value; + }); + } else if (op == "cmake_list_prepend"_s) { + apply_diff(name, [&value](std::string& output) { + if (!output.empty()) { + output.insert(output.begin(), ';'); + } + output.insert(0, value); + }); + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "Error: Unrecognized environment manipulation argument: " + << op << std::endl); + err_occurred = true; + continue; + } + } + + if (err_occurred) { + return false; + } + + for (auto const& env_apply : env_application) { + if (env_apply.second) { + auto const env_update = + cmStrCat(env_apply.first, '=', *env_apply.second); + cmSystemTools::PutEnv(env_update); + envMeasurement << env_update << std::endl; + } else { + cmSystemTools::UnsetEnv(env_apply.first.c_str()); + // Signify that this variable is being actively unset + envMeasurement << "#" << env_apply.first << "=" << std::endl; + } + } + } + if (this->UseAllocatedResources) { std::vector<std::string> envLog; this->SetupResourcesEnvironment(&envLog); diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 863ac1b..2082156 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -109,10 +109,11 @@ public: private: bool NeedsToRepeat(); - void DartProcessing(); + void ParseOutputForMeasurements(); void ExeNotFound(std::string exe); bool ForkProcess(cmDuration testTimeOut, bool explicitTimeout, std::vector<std::string>* environment, + std::vector<std::string>* environment_modification, std::vector<size_t>* affinity); void WriteLogOutputTop(size_t completed, size_t total); // Run post processing of the process output for MemCheck diff --git a/Source/CTest/cmCTestStartCommand.cxx b/Source/CTest/cmCTestStartCommand.cxx index 53e1b2f..a8c2403 100644 --- a/Source/CTest/cmCTestStartCommand.cxx +++ b/Source/CTest/cmCTestStartCommand.cxx @@ -30,8 +30,8 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args, size_t cnt = 0; const char* smodel = nullptr; - const std::string* src_dir = nullptr; - const std::string* bld_dir = nullptr; + cmProp src_dir; + cmProp bld_dir; while (cnt < args.size()) { if (args[cnt] == "GROUP" || args[cnt] == "TRACK") { @@ -55,10 +55,10 @@ bool cmCTestStartCommand::InitialPass(std::vector<std::string> const& args, smodel = args[cnt].c_str(); cnt++; } else if (!src_dir) { - src_dir = &args[cnt]; + src_dir = cmProp(args[cnt]); cnt++; } else if (!bld_dir) { - bld_dir = &args[cnt]; + bld_dir = cmProp(args[cnt]); cnt++; } else { this->SetError("Too many arguments"); diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index bdba0e5..7aeb288 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -36,8 +36,8 @@ std::unique_ptr<cmCommand> cmCTestSubmitCommand::Clone() cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() { - const std::string* submitURL = !this->SubmitURL.empty() - ? &this->SubmitURL + cmProp submitURL = !this->SubmitURL.empty() + ? cmProp(this->SubmitURL) : this->Makefile->GetDefinition("CTEST_SUBMIT_URL"); if (submitURL) { diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 730ec0f..1157d10 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -32,6 +32,7 @@ #include "cmCTest.h" #include "cmCTestMultiProcessHandler.h" #include "cmCTestResourceGroupsLexerHelper.h" +#include "cmCTestTestMeasurementXMLParser.h" #include "cmDuration.h" #include "cmExecutionStatus.h" #include "cmGeneratedFileStream.h" @@ -303,15 +304,24 @@ cmCTestTestHandler::cmCTestTestHandler() // Support for JUnit XML output. this->JUnitXMLFileName = ""; - // regex to detect <DartMeasurement>...</DartMeasurement> - this->DartStuff.compile("(<DartMeasurement.*/DartMeasurement[a-zA-Z]*>)"); - // regex to detect each individual <DartMeasurement>...</DartMeasurement> - this->DartStuff1.compile( - "(<DartMeasurement[^<]*</DartMeasurement[a-zA-Z]*>)"); + // Regular expressions to scan test output for custom measurements. - // regex to detect <CTestDetails>...</CTestDetails> + // Capture the whole section of test output from the first opening + // <(CTest|Dart)Measurement*> tag to the last </(CTest|Dart)Measurement*> + // closing tag. + this->AllTestMeasurementsRegex.compile( + "(<(CTest|Dart)Measurement.*/(CTest|Dart)Measurement[a-zA-Z]*>)"); + + // Capture a single <(CTest|Dart)Measurement*> XML element. + this->SingleTestMeasurementRegex.compile( + "(<(CTest|Dart)Measurement[^<]*</(CTest|Dart)Measurement[a-zA-Z]*>)"); + + // Capture content from <CTestDetails>...</CTestDetails> this->CustomCompletionStatusRegex.compile( "<CTestDetails>(.*)</CTestDetails>"); + + // Capture content from <CTestLabel>...</CTestLabel> + this->CustomLabelRegex.compile("<CTestLabel>(.*)</CTestLabel>"); } void cmCTestTestHandler::Initialize() @@ -692,7 +702,7 @@ bool cmCTestTestHandler::GenerateXML() return false; } cmXMLWriter xml(xmlfile); - this->GenerateDartOutput(xml); + this->GenerateCTestXML(xml); } return true; @@ -1400,7 +1410,7 @@ void cmCTestTestHandler::GenerateTestCommand( { } -void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) +void cmCTestTestHandler::GenerateCTestXML(cmXMLWriter& xml) { if (!this->CTest->GetProduceXML()) { return; @@ -1436,7 +1446,7 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml) xml.Element("Value", result.ReturnValue); xml.EndElement(); // NamedMeasurement } - this->GenerateRegressionImages(xml, result.DartString); + this->RecordCustomTestMeasurements(xml, result.TestMeasurementsOutput); xml.StartElement("NamedMeasurement"); xml.Attribute("type", "numeric/double"); xml.Attribute("name", "Execution Time"); @@ -1976,124 +1986,48 @@ void cmCTestTestHandler::ExpandTestsToRunInformationForRerunFailed() } } -// Just for convenience -#define SPACE_REGEX "[ \t\r\n]" -void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, - const std::string& dart) -{ - cmsys::RegularExpression twoattributes( - "<DartMeasurement" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*>([^<]*)</DartMeasurement>"); - cmsys::RegularExpression threeattributes( - "<DartMeasurement" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*>([^<]*)</DartMeasurement>"); - cmsys::RegularExpression fourattributes( - "<DartMeasurement" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*>([^<]*)</DartMeasurement>"); - cmsys::RegularExpression cdatastart( - "<DartMeasurement" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*>" SPACE_REGEX "*<!\\[CDATA\\["); - cmsys::RegularExpression cdataend("]]>" SPACE_REGEX "*</DartMeasurement>"); - cmsys::RegularExpression measurementfile( - "<DartMeasurementFile" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*(name|type|encoding|compression)=\"([^\"]*)\"" SPACE_REGEX - "*>([^<]*)</DartMeasurementFile>"); - - bool done = false; - std::string cxml = dart; - while (!done) { - if (twoattributes.find(cxml)) { - xml.StartElement("NamedMeasurement"); - xml.Attribute(twoattributes.match(1).c_str(), twoattributes.match(2)); - xml.Attribute(twoattributes.match(3).c_str(), twoattributes.match(4)); - xml.Element("Value", twoattributes.match(5)); - xml.EndElement(); - cxml.erase(twoattributes.start(), - twoattributes.end() - twoattributes.start()); - } else if (threeattributes.find(cxml)) { - xml.StartElement("NamedMeasurement"); - xml.Attribute(threeattributes.match(1).c_str(), - threeattributes.match(2)); - xml.Attribute(threeattributes.match(3).c_str(), - threeattributes.match(4)); - xml.Attribute(threeattributes.match(5).c_str(), - threeattributes.match(6)); - xml.Element("Value", twoattributes.match(7)); - xml.EndElement(); - cxml.erase(threeattributes.start(), - threeattributes.end() - threeattributes.start()); - } else if (fourattributes.find(cxml)) { +void cmCTestTestHandler::RecordCustomTestMeasurements(cmXMLWriter& xml, + std::string content) +{ + while (this->SingleTestMeasurementRegex.find(content)) { + // Extract regex match from content and parse it as an XML element. + auto measurement_str = this->SingleTestMeasurementRegex.match(1); + auto parser = cmCTestTestMeasurementXMLParser(); + parser.Parse(measurement_str.c_str()); + + if (parser.ElementName == "CTestMeasurement" || + parser.ElementName == "DartMeasurement") { xml.StartElement("NamedMeasurement"); - xml.Attribute(fourattributes.match(1).c_str(), fourattributes.match(2)); - xml.Attribute(fourattributes.match(3).c_str(), fourattributes.match(4)); - xml.Attribute(fourattributes.match(5).c_str(), fourattributes.match(6)); - xml.Attribute(fourattributes.match(7).c_str(), fourattributes.match(8)); - xml.Element("Value", twoattributes.match(9)); + xml.Attribute("type", parser.MeasurementType); + xml.Attribute("name", parser.MeasurementName); + xml.Element("Value", parser.CharacterData); xml.EndElement(); - cxml.erase(fourattributes.start(), - fourattributes.end() - fourattributes.start()); - } else if (cdatastart.find(cxml) && cdataend.find(cxml)) { - xml.StartElement("NamedMeasurement"); - xml.Attribute(cdatastart.match(1).c_str(), cdatastart.match(2)); - xml.Attribute(cdatastart.match(3).c_str(), cdatastart.match(4)); - xml.StartElement("Value"); - xml.CData( - cxml.substr(cdatastart.end(), cdataend.start() - cdatastart.end())); - xml.EndElement(); // Value - xml.EndElement(); // NamedMeasurement - cxml.erase(cdatastart.start(), cdataend.end() - cdatastart.start()); - } else if (measurementfile.find(cxml)) { - const std::string& filename = - cmCTest::CleanString(measurementfile.match(5)); - if (cmSystemTools::FileExists(filename)) { + } else if (parser.ElementName == "CTestMeasurementFile" || + parser.ElementName == "DartMeasurementFile") { + const std::string& filename = cmCTest::CleanString(parser.CharacterData); + if (!cmSystemTools::FileExists(filename)) { + xml.StartElement("NamedMeasurement"); + xml.Attribute("name", parser.MeasurementName); + xml.Attribute("text", "text/string"); + xml.Element("Value", "File " + filename + " not found"); + xml.EndElement(); + cmCTestOptionalLog( + this->CTest, HANDLER_OUTPUT, + "File \"" << filename << "\" not found." << std::endl, this->Quiet); + } else { long len = cmSystemTools::FileLength(filename); - std::string k1 = measurementfile.match(1); - std::string v1 = measurementfile.match(2); - std::string k2 = measurementfile.match(3); - std::string v2 = measurementfile.match(4); if (len == 0) { - if (cmSystemTools::LowerCase(k1) == "type") { - v1 = "text/string"; - } - if (cmSystemTools::LowerCase(k2) == "type") { - v2 = "text/string"; - } - xml.StartElement("NamedMeasurement"); - xml.Attribute(k1.c_str(), v1); - xml.Attribute(k2.c_str(), v2); + xml.Attribute("name", parser.MeasurementName); + xml.Attribute("type", "text/string"); xml.Attribute("encoding", "none"); xml.Element("Value", "Image " + filename + " is empty"); xml.EndElement(); } else { - std::string type; - std::string name; - if (cmSystemTools::LowerCase(k1) == "type") { - type = v1; - } else if (cmSystemTools::LowerCase(k2) == "type") { - type = v2; - } - if (cmSystemTools::LowerCase(k1) == "name") { - name = v1; - } else if (cmSystemTools::LowerCase(k2) == "name") { - name = v2; - } - if (type == "file") { + if (parser.MeasurementType == "file") { // Treat this measurement like an "ATTACHED_FILE" when the type // is explicitly "file" (not an image). - this->AttachFile(xml, filename, name); + this->AttachFile(xml, filename, parser.MeasurementName); } else { cmsys::ifstream ifs(filename.c_str(), std::ios::in @@ -2110,10 +2044,8 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, encoded_buffer.get(), 1); xml.StartElement("NamedMeasurement"); - xml.Attribute(measurementfile.match(1).c_str(), - measurementfile.match(2)); - xml.Attribute(measurementfile.match(3).c_str(), - measurementfile.match(4)); + xml.Attribute("name", parser.MeasurementName); + xml.Attribute("type", parser.MeasurementType); xml.Attribute("encoding", "base64"); std::ostringstream ostr; for (size_t cc = 0; cc < rlen; cc++) { @@ -2126,25 +2058,11 @@ void cmCTestTestHandler::GenerateRegressionImages(cmXMLWriter& xml, xml.EndElement(); // NamedMeasurement } } - } else { - int idx = 4; - if (measurementfile.match(1) == "name") { - idx = 2; - } - xml.StartElement("NamedMeasurement"); - xml.Attribute("name", measurementfile.match(idx)); - xml.Attribute("text", "text/string"); - xml.Element("Value", "File " + filename + " not found"); - xml.EndElement(); - cmCTestOptionalLog( - this->CTest, HANDLER_OUTPUT, - "File \"" << filename << "\" not found." << std::endl, this->Quiet); } - cxml.erase(measurementfile.start(), - measurementfile.end() - measurementfile.start()); - } else { - done = true; } + + // Remove this element from content. + cmSystemTools::ReplaceString(content, measurement_str.c_str(), ""); } } @@ -2247,7 +2165,7 @@ bool cmCTestTestHandler::SetTestsProperties( // Ensure we have complete triples otherwise the data is corrupt. if (triples.size() % 3 == 0) { - cmState state; + cmState state(cmState::Unknown); rt.Backtrace = cmListFileBacktrace(state.CreateBaseSnapshot()); // the first entry represents the top of the trace so we need to @@ -2327,6 +2245,8 @@ bool cmCTestTestHandler::SetTestsProperties( cmExpandList(val, rt.Depends); } else if (key == "ENVIRONMENT"_s) { cmExpandList(val, rt.Environment); + } else if (key == "ENVIRONMENT_MODIFICATION"_s) { + cmExpandList(val, rt.EnvironmentModification); } else if (key == "LABELS"_s) { std::vector<std::string> Labels = cmExpandedList(val); rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end()); diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index bd51738..f2da320 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -151,6 +151,7 @@ public: // return code of test which will mark test as "not run" int SkipReturnCode; std::vector<std::string> Environment; + std::vector<std::string> EnvironmentModification; std::vector<std::string> Labels; std::set<std::string> LockedResources; std::set<std::string> FixturesSetup; @@ -177,7 +178,7 @@ public: std::string CompletionStatus; std::string CustomCompletionStatus; std::string Output; - std::string DartString; + std::string TestMeasurementsOutput; int TestCount; cmCTestTestProperties* Properties; }; @@ -276,9 +277,9 @@ public: private: /** - * Generate the Dart compatible output + * Write test results in CTest's Test.xml format */ - virtual void GenerateDartOutput(cmXMLWriter& xml); + virtual void GenerateCTestXML(cmXMLWriter& xml); /** * Write test results in JUnit XML format @@ -348,8 +349,7 @@ private: cmCTestResourceSpec ResourceSpec; std::string ResourceSpecFile; - void GenerateRegressionImages(cmXMLWriter& xml, const std::string& dart); - cmsys::RegularExpression DartStuff1; + void RecordCustomTestMeasurements(cmXMLWriter& xml, std::string content); void CheckLabelFilter(cmCTestTestProperties& it); void CheckLabelFilterExclude(cmCTestTestProperties& it); void CheckLabelFilterInclude(cmCTestTestProperties& it); @@ -358,8 +358,10 @@ private: bool UseUnion; ListOfTests TestList; size_t TotalNumberOfTests; - cmsys::RegularExpression DartStuff; + cmsys::RegularExpression AllTestMeasurementsRegex; + cmsys::RegularExpression SingleTestMeasurementRegex; cmsys::RegularExpression CustomCompletionStatusRegex; + cmsys::RegularExpression CustomLabelRegex; std::ostream* LogFile; diff --git a/Source/CTest/cmCTestTestMeasurementXMLParser.cxx b/Source/CTest/cmCTestTestMeasurementXMLParser.cxx new file mode 100644 index 0000000..636be24 --- /dev/null +++ b/Source/CTest/cmCTestTestMeasurementXMLParser.cxx @@ -0,0 +1,26 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmCTestTestMeasurementXMLParser.h" + +#include <cstring> + +void cmCTestTestMeasurementXMLParser::StartElement(const std::string& name, + const char** attributes) +{ + this->CharacterData.clear(); + this->ElementName = name; + for (const char** attr = attributes; *attr; attr += 2) { + if (strcmp(attr[0], "name") == 0) { + this->MeasurementName = attr[1]; + } else if (strcmp(attr[0], "type") == 0) { + this->MeasurementType = attr[1]; + } + } +} + +void cmCTestTestMeasurementXMLParser::CharacterDataHandler(const char* data, + int length) +{ + this->CharacterData.append(data, length); +} diff --git a/Source/CTest/cmCTestTestMeasurementXMLParser.h b/Source/CTest/cmCTestTestMeasurementXMLParser.h new file mode 100644 index 0000000..b2c3eb3 --- /dev/null +++ b/Source/CTest/cmCTestTestMeasurementXMLParser.h @@ -0,0 +1,21 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include <string> + +#include "cmXMLParser.h" + +class cmCTestTestMeasurementXMLParser : public cmXMLParser +{ +public: + cmCTestTestMeasurementXMLParser() {} + std::string CharacterData; + std::string ElementName; + std::string MeasurementName; + std::string MeasurementType; + +protected: + void StartElement(const std::string& name, const char** atts) override; + void EndElement(const std::string& /*name*/) override {} + void CharacterDataHandler(const char* data, int length) override; +}; diff --git a/Source/LexerParser/cmFortranParser.cxx b/Source/LexerParser/cmFortranParser.cxx index 3f3ddde..50e9752 100644 --- a/Source/LexerParser/cmFortranParser.cxx +++ b/Source/LexerParser/cmFortranParser.cxx @@ -600,12 +600,12 @@ static const yytype_int8 yytranslate[] = static const yytype_uint8 yyrline[] = { 0, 101, 101, 101, 104, 108, 113, 122, 128, 135, - 140, 144, 149, 157, 162, 167, 172, 177, 182, 187, - 192, 197, 201, 205, 209, 213, 214, 219, 219, 219, - 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, - 225, 225, 226, 226, 227, 227, 228, 228, 231, 232, - 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, - 243, 244, 245, 246, 247 + 140, 144, 149, 161, 166, 171, 176, 181, 186, 191, + 196, 201, 205, 209, 213, 217, 218, 223, 223, 223, + 224, 224, 225, 225, 226, 226, 227, 227, 228, 228, + 229, 229, 230, 230, 231, 231, 232, 232, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251 }; #endif @@ -1747,142 +1747,146 @@ yyreduce: cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); } + if (cmsysString_strcasecmp((yyvsp[-4].string), "intrinsic") == 0) { + cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); + cmFortranParser_RuleUseIntrinsic(parser, (yyvsp[-2].string)); + } free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1754 "cmFortranParser.cxx" +#line 1758 "cmFortranParser.cxx" break; case 13: /* stmt: INCLUDE STRING other EOSTMT */ -#line 157 "cmFortranParser.y" +#line 161 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1764 "cmFortranParser.cxx" +#line 1768 "cmFortranParser.cxx" break; case 14: /* stmt: CPP_LINE_DIRECTIVE STRING other EOSTMT */ -#line 162 "cmFortranParser.y" +#line 166 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1774 "cmFortranParser.cxx" +#line 1778 "cmFortranParser.cxx" break; case 15: /* stmt: CPP_INCLUDE_ANGLE other EOSTMT */ -#line 167 "cmFortranParser.y" +#line 171 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1784 "cmFortranParser.cxx" +#line 1788 "cmFortranParser.cxx" break; case 16: /* stmt: include STRING other EOSTMT */ -#line 172 "cmFortranParser.y" +#line 176 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1794 "cmFortranParser.cxx" +#line 1798 "cmFortranParser.cxx" break; case 17: /* stmt: define WORD other EOSTMT */ -#line 177 "cmFortranParser.y" +#line 181 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleDefine(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1804 "cmFortranParser.cxx" +#line 1808 "cmFortranParser.cxx" break; case 18: /* stmt: undef WORD other EOSTMT */ -#line 182 "cmFortranParser.y" +#line 186 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1814 "cmFortranParser.cxx" +#line 1818 "cmFortranParser.cxx" break; case 19: /* stmt: ifdef WORD other EOSTMT */ -#line 187 "cmFortranParser.y" +#line 191 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1824 "cmFortranParser.cxx" +#line 1828 "cmFortranParser.cxx" break; case 20: /* stmt: ifndef WORD other EOSTMT */ -#line 192 "cmFortranParser.y" +#line 196 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1834 "cmFortranParser.cxx" +#line 1838 "cmFortranParser.cxx" break; case 21: /* stmt: if other EOSTMT */ -#line 197 "cmFortranParser.y" +#line 201 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIf(parser); } -#line 1843 "cmFortranParser.cxx" +#line 1847 "cmFortranParser.cxx" break; case 22: /* stmt: elif other EOSTMT */ -#line 201 "cmFortranParser.y" +#line 205 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElif(parser); } -#line 1852 "cmFortranParser.cxx" +#line 1856 "cmFortranParser.cxx" break; case 23: /* stmt: else other EOSTMT */ -#line 205 "cmFortranParser.y" +#line 209 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElse(parser); } -#line 1861 "cmFortranParser.cxx" +#line 1865 "cmFortranParser.cxx" break; case 24: /* stmt: endif other EOSTMT */ -#line 209 "cmFortranParser.y" +#line 213 "cmFortranParser.y" { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleEndif(parser); } -#line 1870 "cmFortranParser.cxx" +#line 1874 "cmFortranParser.cxx" break; case 48: /* misc_code: WORD */ -#line 231 "cmFortranParser.y" +#line 235 "cmFortranParser.y" { free ((yyvsp[0].string)); } -#line 1876 "cmFortranParser.cxx" +#line 1880 "cmFortranParser.cxx" break; case 55: /* misc_code: STRING */ -#line 238 "cmFortranParser.y" +#line 242 "cmFortranParser.y" { free ((yyvsp[0].string)); } -#line 1882 "cmFortranParser.cxx" +#line 1886 "cmFortranParser.cxx" break; -#line 1886 "cmFortranParser.cxx" +#line 1890 "cmFortranParser.cxx" default: break; } @@ -2107,6 +2111,6 @@ yyreturn: return yyresult; } -#line 250 "cmFortranParser.y" +#line 254 "cmFortranParser.y" /* End of grammar */ diff --git a/Source/LexerParser/cmFortranParser.y b/Source/LexerParser/cmFortranParser.y index a3e1c24..8ef1903 100644 --- a/Source/LexerParser/cmFortranParser.y +++ b/Source/LexerParser/cmFortranParser.y @@ -151,6 +151,10 @@ stmt: cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, $5); } + if (cmsysString_strcasecmp($3, "intrinsic") == 0) { + cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); + cmFortranParser_RuleUseIntrinsic(parser, $5); + } free($3); free($5); } diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index e6faef4..41e8a55 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -128,11 +128,11 @@ void QCMake::setBinaryDirectory(const QString& _dir) } cmProp gen = state->GetCacheEntryValue("CMAKE_GENERATOR"); if (gen) { - const std::string* extraGen = + cmProp extraGen = state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR"); std::string curGen = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName( - *gen, extraGen ? *extraGen : ""); + cmExternalMakefileProjectGenerator::CreateFullGeneratorName(*gen, + *extraGen); this->setGenerator(QString::fromLocal8Bit(curGen.c_str())); } @@ -550,17 +550,14 @@ void QCMake::loadPresets() } QCMakePreset preset; - preset.name = std::move(QString::fromLocal8Bit(p.Name.data())); - preset.displayName = - std::move(QString::fromLocal8Bit(p.DisplayName.data())); - preset.description = - std::move(QString::fromLocal8Bit(p.Description.data())); - preset.generator = std::move(QString::fromLocal8Bit(p.Generator.data())); - preset.architecture = - std::move(QString::fromLocal8Bit(p.Architecture.data())); + preset.name = QString::fromLocal8Bit(p.Name.data()); + preset.displayName = QString::fromLocal8Bit(p.DisplayName.data()); + preset.description = QString::fromLocal8Bit(p.Description.data()); + preset.generator = QString::fromLocal8Bit(p.Generator.data()); + preset.architecture = QString::fromLocal8Bit(p.Architecture.data()); preset.setArchitecture = !p.ArchitectureStrategy || p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set; - preset.toolset = std::move(QString::fromLocal8Bit(p.Toolset.data())); + preset.toolset = QString::fromLocal8Bit(p.Toolset.data()); preset.setToolset = !p.ToolsetStrategy || p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set; preset.enabled = it.Expanded && it.Expanded->ConditionResult && diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 54b2998..9e0d80c 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -250,6 +250,9 @@ cmArchiveWrite::cmArchiveWrite(std::ostream& os, Compress c, bool cmArchiveWrite::Open() { + if (!this->Error.empty()) { + return false; + } if (archive_write_open( this->Archive, this, nullptr, reinterpret_cast<archive_write_callback*>(&Callback::Write), diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx index 99707a3..a69c00d 100644 --- a/Source/cmBinUtilsLinuxELFLinker.cxx +++ b/Source/cmBinUtilsLinuxELFLinker.cxx @@ -11,6 +11,7 @@ #include <cmsys/RegularExpression.hxx> #include "cmBinUtilsLinuxELFObjdumpGetRuntimeDependenciesTool.h" +#include "cmELF.h" #include "cmLDConfigLDConfigTool.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -18,10 +19,6 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#ifdef CMake_USE_ELF_PARSER -# include "cmELF.h" -#endif - static std::string ReplaceOrigin(const std::string& rpath, const std::string& origin) { @@ -91,7 +88,6 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies( { std::vector<std::string> parentRpaths; -#ifdef CMake_USE_ELF_PARSER cmELF elf(file.c_str()); if (!elf) { return false; @@ -106,7 +102,6 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies( this->Machine = elf.GetMachine(); } } -#endif return this->ScanDependencies(file, parentRpaths); } @@ -175,15 +170,11 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies( namespace { bool FileHasArchitecture(const char* filename, std::uint16_t machine) { -#ifdef CMake_USE_ELF_PARSER cmELF elf(filename); if (!elf) { return false; } return machine == 0 || machine == elf.GetMachine(); -#else - return true; -#endif } } diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx index 1f99043..b2830e2 100644 --- a/Source/cmCMakePolicyCommand.cxx +++ b/Source/cmCMakePolicyCommand.cxx @@ -6,6 +6,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index 1a950df..8fefaa6 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -500,7 +500,7 @@ cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const { if (const auto* entry = this->GetCacheEntry(key)) { if (entry->Initialized) { - return &entry->GetValue(); + return cmProp(entry->GetValue()); } } return nullptr; @@ -568,10 +568,10 @@ std::vector<std::string> cmCacheManager::CacheEntry::GetPropertyList() const cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const { if (prop == "TYPE") { - return &cmState::CacheEntryTypeToString(this->Type); + return cmProp(cmState::CacheEntryTypeToString(this->Type)); } if (prop == "VALUE") { - return &this->Value; + return cmProp(this->Value); } return this->Properties.GetPropertyValue(prop); } diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index 7a9a7dc..0238fb8 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -75,7 +75,7 @@ public: cmProp GetCacheEntryValue(const std::string& key) const { if (const auto* entry = this->GetCacheEntry(key)) { - return &entry->GetValue(); + return cmProp(entry->GetValue()); } return nullptr; } diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index deddba8..415f0c0 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -113,7 +113,7 @@ const char* cmCommandArgumentParserHelper::ExpandVariable(const char* var) if (this->EscapeQuotes && value) { return this->AddString(cmEscapeQuotes(*value)); } - return this->AddString(cmToCStrSafe(value)); + return this->AddString(value); } const char* cmCommandArgumentParserHelper::ExpandVariableForAt(const char* var) diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 7c2e20c..59e4141 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -39,10 +39,10 @@ std::vector<std::string> const& cmCommonTargetGenerator::GetConfigNames() const return this->ConfigNames; } -const char* cmCommonTargetGenerator::GetFeature(const std::string& feature, - const std::string& config) +cmProp cmCommonTargetGenerator::GetFeature(const std::string& feature, + const std::string& config) { - return this->GeneratorTarget->GetFeature(feature, config)->c_str(); + return this->GeneratorTarget->GetFeature(feature, config); } void cmCommonTargetGenerator::AddModuleDefinitionFlag( diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index a156a41..463a445 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -8,6 +8,8 @@ #include <string> #include <vector> +#include "cmProperty.h" + class cmGeneratorTarget; class cmGlobalCommonGenerator; class cmLinkLineComputer; @@ -28,8 +30,7 @@ public: protected: // Feature query methods. - const char* GetFeature(const std::string& feature, - const std::string& config); + cmProp GetFeature(const std::string& feature, const std::string& config); // Helper to add flag for windows .def file. void AddModuleDefinitionFlag(cmLinkLineComputer* linkLineComputer, @@ -40,6 +41,7 @@ protected: cmLocalCommonGenerator* LocalCommonGenerator; cmGlobalCommonGenerator* GlobalCommonGenerator; std::vector<std::string> ConfigNames; + bool UseLWYU = false; void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index f99592c..68bc4d8 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -2,16 +2,21 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmConditionEvaluator.h" +#include <array> #include <cstdio> #include <cstdlib> #include <functional> +#include <iterator> +#include <list> #include <sstream> #include <utility> +#include <cm/string_view> #include <cmext/algorithm> #include "cmsys/RegularExpression.hxx" +#include "cmExpandedCommandArgument.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmProperty.h" @@ -20,40 +25,184 @@ #include "cmSystemTools.h" #include "cmake.h" -class cmTest; - -static std::string const keyAND = "AND"; -static std::string const keyCOMMAND = "COMMAND"; -static std::string const keyDEFINED = "DEFINED"; -static std::string const keyEQUAL = "EQUAL"; -static std::string const keyEXISTS = "EXISTS"; -static std::string const keyGREATER = "GREATER"; -static std::string const keyGREATER_EQUAL = "GREATER_EQUAL"; -static std::string const keyIN_LIST = "IN_LIST"; -static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE"; -static std::string const keyIS_DIRECTORY = "IS_DIRECTORY"; -static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN"; -static std::string const keyIS_SYMLINK = "IS_SYMLINK"; -static std::string const keyLESS = "LESS"; -static std::string const keyLESS_EQUAL = "LESS_EQUAL"; -static std::string const keyMATCHES = "MATCHES"; -static std::string const keyNOT = "NOT"; -static std::string const keyOR = "OR"; -static std::string const keyParenL = "("; -static std::string const keyParenR = ")"; -static std::string const keyPOLICY = "POLICY"; -static std::string const keySTREQUAL = "STREQUAL"; -static std::string const keySTRGREATER = "STRGREATER"; -static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"; -static std::string const keySTRLESS = "STRLESS"; -static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL"; -static std::string const keyTARGET = "TARGET"; -static std::string const keyTEST = "TEST"; -static std::string const keyVERSION_EQUAL = "VERSION_EQUAL"; -static std::string const keyVERSION_GREATER = "VERSION_GREATER"; -static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"; -static std::string const keyVERSION_LESS = "VERSION_LESS"; -static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"; +namespace { +auto const keyAND = "AND"_s; +auto const keyCOMMAND = "COMMAND"_s; +auto const keyDEFINED = "DEFINED"_s; +auto const keyEQUAL = "EQUAL"_s; +auto const keyEXISTS = "EXISTS"_s; +auto const keyGREATER = "GREATER"_s; +auto const keyGREATER_EQUAL = "GREATER_EQUAL"_s; +auto const keyIN_LIST = "IN_LIST"_s; +auto const keyIS_ABSOLUTE = "IS_ABSOLUTE"_s; +auto const keyIS_DIRECTORY = "IS_DIRECTORY"_s; +auto const keyIS_NEWER_THAN = "IS_NEWER_THAN"_s; +auto const keyIS_SYMLINK = "IS_SYMLINK"_s; +auto const keyLESS = "LESS"_s; +auto const keyLESS_EQUAL = "LESS_EQUAL"_s; +auto const keyMATCHES = "MATCHES"_s; +auto const keyNOT = "NOT"_s; +auto const keyOR = "OR"_s; +auto const keyParenL = "("_s; +auto const keyParenR = ")"_s; +auto const keyPOLICY = "POLICY"_s; +auto const keySTREQUAL = "STREQUAL"_s; +auto const keySTRGREATER = "STRGREATER"_s; +auto const keySTRGREATER_EQUAL = "STRGREATER_EQUAL"_s; +auto const keySTRLESS = "STRLESS"_s; +auto const keySTRLESS_EQUAL = "STRLESS_EQUAL"_s; +auto const keyTARGET = "TARGET"_s; +auto const keyTEST = "TEST"_s; +auto const keyVERSION_EQUAL = "VERSION_EQUAL"_s; +auto const keyVERSION_GREATER = "VERSION_GREATER"_s; +auto const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL"_s; +auto const keyVERSION_LESS = "VERSION_LESS"_s; +auto const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL"_s; + +cmSystemTools::CompareOp const MATCH2CMPOP[5] = { + cmSystemTools::OP_LESS, cmSystemTools::OP_LESS_EQUAL, + cmSystemTools::OP_GREATER, cmSystemTools::OP_GREATER_EQUAL, + cmSystemTools::OP_EQUAL +}; + +// Run-Time to Compile-Time template selector +template <template <typename> class Comp, template <typename> class... Ops> +struct cmRt2CtSelector +{ + template <typename T> + static bool eval(int r, T lhs, T rhs) + { + switch (r) { + case 0: + return false; + case 1: + return Comp<T>()(lhs, rhs); + default: + return cmRt2CtSelector<Ops...>::eval(r - 1, lhs, rhs); + } + } +}; + +template <template <typename> class Comp> +struct cmRt2CtSelector<Comp> +{ + template <typename T> + static bool eval(int r, T lhs, T rhs) + { + return r == 1 && Comp<T>()(lhs, rhs); + } +}; + +std::string bool2string(bool const value) +{ + return std::string(std::size_t(1), static_cast<char>('0' + int(value))); +} + +bool looksLikeSpecialVariable(const std::string& var, + cm::static_string_view prefix, + const std::size_t varNameLen) +{ + // NOTE Expecting a variable name at least 1 char length: + // <prefix> + `{` + <varname> + `}` + return ((prefix.size() + 3) <= varNameLen) && + cmHasPrefix(var, cmStrCat(prefix, '{')) && var[varNameLen - 1] == '}'; +} +} // anonymous namespace + +#if defined(__SUNPRO_CC) +# define CM_INHERIT_CTOR(Class, Base, Tpl) \ + template <typename... Args> \ + Class(Args&&... args) \ + : Base Tpl(std::forward<Args>(args)...) \ + { \ + } +#else +# define CM_INHERIT_CTOR(Class, Base, Tpl) using Base Tpl ::Base; +#endif + +// BEGIN cmConditionEvaluator::cmArgumentList +class cmConditionEvaluator::cmArgumentList + : public std::list<cmExpandedCommandArgument> +{ + using base_t = std::list<cmExpandedCommandArgument>; + +public: + CM_INHERIT_CTOR(cmArgumentList, list, <cmExpandedCommandArgument>); + + class CurrentAndNextIter + { + friend class cmConditionEvaluator::cmArgumentList; + + public: + base_t::iterator current; + base_t::iterator next; + + CurrentAndNextIter advance(base_t& args) + { + this->current = std::next(this->current); + this->next = + std::next(this->current, difference_type(this->current != args.end())); + return *this; + } + + private: + CurrentAndNextIter(base_t& args) + : current(args.begin()) + , next(std::next(this->current, + difference_type(this->current != args.end()))) + { + } + }; + + class CurrentAndTwoMoreIter + { + friend class cmConditionEvaluator::cmArgumentList; + + public: + base_t::iterator current; + base_t::iterator next; + base_t::iterator nextnext; + + CurrentAndTwoMoreIter advance(base_t& args) + { + this->current = std::next(this->current); + this->next = + std::next(this->current, difference_type(this->current != args.end())); + this->nextnext = + std::next(this->next, difference_type(this->next != args.end())); + return *this; + } + + private: + CurrentAndTwoMoreIter(base_t& args) + : current(args.begin()) + , next(std::next(this->current, + difference_type(this->current != args.end()))) + , nextnext( + std::next(this->next, difference_type(this->next != args.end()))) + { + } + }; + + CurrentAndNextIter make2ArgsIterator() { return *this; } + CurrentAndTwoMoreIter make3ArgsIterator() { return *this; } + + template <typename Iter> + void ReduceOneArg(const bool value, Iter args) + { + *args.current = cmExpandedCommandArgument(bool2string(value), true); + this->erase(args.next); + } + + void ReduceTwoArgs(const bool value, CurrentAndTwoMoreIter args) + { + *args.current = cmExpandedCommandArgument(bool2string(value), true); + this->erase(args.nextnext); + this->erase(args.next); + } +}; + +// END cmConditionEvaluator::cmArgumentList cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt) @@ -99,25 +248,29 @@ bool cmConditionEvaluator::IsTrue( // now loop through the arguments and see if we can reduce any of them // we do this multiple times. Once for each level of precedence // parens - if (!this->HandleLevel0(newArgs, errorString, status)) { - return false; - } - // predicates - if (!this->HandleLevel1(newArgs, errorString, status)) { - return false; - } - // binary ops - if (!this->HandleLevel2(newArgs, errorString, status)) { - return false; - } + using handlerFn_t = bool (cmConditionEvaluator::*)( + cmArgumentList&, std::string&, MessageType&); + const std::array<handlerFn_t, 5> handlers = { { + &cmConditionEvaluator::HandleLevel0, // parenthesis + &cmConditionEvaluator::HandleLevel1, // predicates + &cmConditionEvaluator::HandleLevel2, // binary ops + &cmConditionEvaluator::HandleLevel3, // NOT + &cmConditionEvaluator::HandleLevel4 // AND OR + } }; + for (auto fn : handlers) { + // Call the reducer 'till there is anything to reduce... + // (i.e., if after an iteration the size becomes smaller) + auto levelResult = true; + for (auto beginSize = newArgs.size(); + (levelResult = (this->*fn)(newArgs, errorString, status)) && + newArgs.size() < beginSize; + beginSize = newArgs.size()) { + } - // NOT - if (!this->HandleLevel3(newArgs, errorString, status)) { - return false; - } - // AND OR - if (!this->HandleLevel4(newArgs, errorString, status)) { - return false; + if (!levelResult) { + // NOTE `errorString` supposed to be set already + return false; + } } // now at the end there should only be one argument left @@ -147,11 +300,13 @@ cmProp cmConditionEvaluator::GetDefinitionIfUnquoted( this->Policy54Status == cmPolicies::WARN) { if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) { std::ostringstream e; - e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n"; - e << "Quoted variables like \"" << argument.GetValue() - << "\" will no longer be dereferenced " - "when the policy is set to NEW. " + // clang-format off + e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) + << "\n" + "Quoted variables like \"" << argument.GetValue() << "\" " + "will no longer be dereferenced when the policy is set to NEW. " "Since the policy is not set the OLD behavior will be used."; + // clang-format on this->Makefile.GetCMakeInstance()->IssueMessage( MessageType::AUTHOR_WARNING, e.str(), this->Backtrace); @@ -168,15 +323,16 @@ cmProp cmConditionEvaluator::GetVariableOrString( cmProp def = this->GetDefinitionIfUnquoted(argument); if (!def) { - def = &argument.GetValue(); + def = cmProp(argument.GetValue()); } return def; } //========================================================================= -bool cmConditionEvaluator::IsKeyword(std::string const& keyword, - cmExpandedCommandArgument& argument) const +bool cmConditionEvaluator::IsKeyword( + cm::static_string_view keyword, + const cmExpandedCommandArgument& argument) const { if ((this->Policy54Status != cmPolicies::WARN && this->Policy54Status != cmPolicies::OLD) && @@ -184,17 +340,20 @@ bool cmConditionEvaluator::IsKeyword(std::string const& keyword, return false; } - bool isKeyword = argument.GetValue() == keyword; + const auto isKeyword = argument.GetValue() == keyword; if (isKeyword && argument.WasQuoted() && this->Policy54Status == cmPolicies::WARN) { if (!this->Makefile.HasCMP0054AlreadyBeenReported(this->Backtrace.Top())) { std::ostringstream e; - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n"; - e << "Quoted keywords like \"" << argument.GetValue() - << "\" will no longer be interpreted as keywords " + // clang-format off + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) + << "\n" + "Quoted keywords like \"" << argument.GetValue() << "\" " + "will no longer be interpreted as keywords " "when the policy is set to NEW. " "Since the policy is not set the OLD behavior will be used."; + // clang-format on this->Makefile.GetCMakeInstance()->IssueMessage( MessageType::AUTHOR_WARNING, e.str(), this->Backtrace); @@ -208,15 +367,7 @@ bool cmConditionEvaluator::IsKeyword(std::string const& keyword, bool cmConditionEvaluator::GetBooleanValue( cmExpandedCommandArgument& arg) const { - // Check basic constants. - if (arg == "0") { - return false; - } - if (arg == "1") { - return true; - } - - // Check named constants. + // Check basic and named constants. if (cmIsOn(arg.GetValue())) { return true; } @@ -227,7 +378,7 @@ bool cmConditionEvaluator::GetBooleanValue( // Check for numbers. if (!arg.empty()) { char* end; - double d = strtod(arg.GetValue().c_str(), &end); + const double d = std::strtod(arg.GetValue().c_str(), &end); if (*end == '\0') { // The whole string is a number. Use C conversion to bool. return static_cast<bool>(d); @@ -242,7 +393,7 @@ bool cmConditionEvaluator::GetBooleanValue( //========================================================================= // Boolean value behavior from CMake 2.6.4 and below. bool cmConditionEvaluator::GetBooleanValueOld( - cmExpandedCommandArgument const& arg, bool one) const + cmExpandedCommandArgument const& arg, bool const one) const { if (one) { // Old IsTrue behavior for single argument. @@ -257,8 +408,8 @@ bool cmConditionEvaluator::GetBooleanValueOld( } // Old GetVariableOrNumber behavior. cmProp def = this->GetDefinitionIfUnquoted(arg); - if (!def && atoi(arg.GetValue().c_str())) { - def = &arg.GetValue(); + if (!def && std::atoi(arg.GetValue().c_str())) { + def = cmProp(arg.GetValue()); } return !cmIsOff(def); } @@ -267,7 +418,7 @@ bool cmConditionEvaluator::GetBooleanValueOld( // returns the resulting boolean value bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( cmExpandedCommandArgument& newArg, std::string& errorString, - MessageType& status, bool oneArg) const + MessageType& status, bool const oneArg) const { // Use the policy if it is set. if (this->Policy12Status == cmPolicies::NEW) { @@ -278,8 +429,8 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( } // Check policy only if old and new results differ. - bool newResult = this->GetBooleanValue(newArg); - bool oldResult = this->GetBooleanValueOld(newArg, oneArg); + const auto newResult = this->GetBooleanValue(newArg); + const auto oldResult = this->GetBooleanValueOld(newArg, oneArg); if (newResult != oldResult) { switch (this->Policy12Status) { case cmPolicies::WARN: @@ -304,56 +455,31 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( return newResult; } -//========================================================================= -void cmConditionEvaluator::IncrementArguments( - cmArgumentList& newArgs, cmArgumentList::iterator& argP1, - cmArgumentList::iterator& argP2) const +template <int N> +inline int cmConditionEvaluator::matchKeysImpl( + const cmExpandedCommandArgument&) { - if (argP1 != newArgs.end()) { - argP1++; - argP2 = argP1; - if (argP1 != newArgs.end()) { - argP2++; - } - } + // Zero means "not found" + return 0; } -//========================================================================= -// helper function to reduce code duplication -void cmConditionEvaluator::HandlePredicate( - bool value, int& reducible, cmArgumentList::iterator& arg, - cmArgumentList& newArgs, cmArgumentList::iterator& argP1, - cmArgumentList::iterator& argP2) const +template <int N, typename T, typename... Keys> +inline int cmConditionEvaluator::matchKeysImpl( + const cmExpandedCommandArgument& arg, T current, Keys... key) { - if (value) { - *arg = cmExpandedCommandArgument("1", true); - } else { - *arg = cmExpandedCommandArgument("0", true); + if (this->IsKeyword(current, arg)) { + // Stop searching as soon as smth has found + return N; } - newArgs.erase(argP1); - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - reducible = 1; + return matchKeysImpl<N + 1>(arg, key...); } -//========================================================================= -// helper function to reduce code duplication -void cmConditionEvaluator::HandleBinaryOp(bool value, int& reducible, - cmArgumentList::iterator& arg, - cmArgumentList& newArgs, - cmArgumentList::iterator& argP1, - cmArgumentList::iterator& argP2) +template <typename... Keys> +inline int cmConditionEvaluator::matchKeys( + const cmExpandedCommandArgument& arg, Keys... key) { - if (value) { - *arg = cmExpandedCommandArgument("1", true); - } else { - *arg = cmExpandedCommandArgument("0", true); - } - newArgs.erase(argP2); - newArgs.erase(argP1); - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - reducible = 1; + // Get index of the matched key (1-based) + return matchKeysImpl<1>(arg, key...); } //========================================================================= @@ -362,55 +488,35 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs, std::string& errorString, MessageType& status) { - int reducible; - do { - reducible = 0; - auto arg = newArgs.begin(); - while (arg != newArgs.end()) { - if (this->IsKeyword(keyParenL, *arg)) { - // search for the closing paren for this opening one - cmArgumentList::iterator argClose; - argClose = arg; - argClose++; - unsigned int depth = 1; - while (argClose != newArgs.end() && depth) { - if (this->IsKeyword(keyParenL, *argClose)) { - depth++; - } - if (this->IsKeyword(keyParenR, *argClose)) { - depth--; - } - argClose++; - } - if (depth) { - errorString = "mismatched parenthesis in condition"; - status = MessageType::FATAL_ERROR; - return false; - } - // store the reduced args in this vector - std::vector<cmExpandedCommandArgument> newArgs2; - - // copy to the list structure - auto argP1 = arg; - argP1++; - cm::append(newArgs2, argP1, argClose); - newArgs2.pop_back(); - // now recursively invoke IsTrue to handle the values inside the - // parenthetical expression - bool value = this->IsTrue(newArgs2, errorString, status); - if (value) { - *arg = cmExpandedCommandArgument("1", true); - } else { - *arg = cmExpandedCommandArgument("0", true); - } - argP1 = arg; - argP1++; - // remove the now evaluated parenthetical expression - newArgs.erase(argP1, argClose); + for (auto arg = newArgs.begin(); arg != newArgs.end(); ++arg) { + if (this->IsKeyword(keyParenL, *arg)) { + // search for the closing paren for this opening one + auto depth = 1; + auto argClose = std::next(arg); + for (; argClose != newArgs.end() && depth; ++argClose) { + depth += int(this->IsKeyword(keyParenL, *argClose)) - + int(this->IsKeyword(keyParenR, *argClose)); } - ++arg; + if (depth) { + errorString = "mismatched parenthesis in condition"; + status = MessageType::FATAL_ERROR; + return false; + } + + // store the reduced args in this vector + auto argOpen = std::next(arg); + const std::vector<cmExpandedCommandArgument> subExpr( + argOpen, std::prev(argClose)); + + // now recursively invoke IsTrue to handle the values inside the + // parenthetical expression + const auto value = this->IsTrue(subExpr, errorString, status); + *arg = cmExpandedCommandArgument(bool2string(value), true); + argOpen = std::next(arg); + // remove the now evaluated parenthetical expression + newArgs.erase(argOpen, argClose); } - } while (reducible); + } return true; } @@ -419,96 +525,104 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs, bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, MessageType&) { - int reducible; - do { - reducible = 0; - auto arg = newArgs.begin(); - cmArgumentList::iterator argP1; - cmArgumentList::iterator argP2; - while (arg != newArgs.end()) { - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - // does a file exist - if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileExists(argP1->GetValue()), - reducible, arg, newArgs, argP1, argP2); - } - // does a directory with this name exist - if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate( - cmSystemTools::FileIsDirectory(argP1->GetValue()), reducible, arg, - newArgs, argP1, argP2); - } - // does a symlink with this name exist - if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->GetValue()), - reducible, arg, newArgs, argP1, argP2); - } - // is the given path an absolute path ? - if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->GetValue()), - reducible, arg, newArgs, argP1, argP2); - } - // does a command exist - if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) { - cmState::Command command = - this->Makefile.GetState()->GetCommand(argP1->GetValue()); - this->HandlePredicate(command != nullptr, reducible, arg, newArgs, - argP1, argP2); - } - // does a policy exist - if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end()) { - cmPolicies::PolicyID pid; - this->HandlePredicate( - cmPolicies::GetPolicyID(argP1->GetValue().c_str(), pid), reducible, - arg, newArgs, argP1, argP2); - } - // does a target exist - if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate( - this->Makefile.FindTargetToUse(argP1->GetValue()) != nullptr, - reducible, arg, newArgs, argP1, argP2); - } - // does a test exist - if (this->Policy64Status != cmPolicies::OLD && - this->Policy64Status != cmPolicies::WARN) { - if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end()) { - const cmTest* haveTest = this->Makefile.GetTest(argP1->GetValue()); - this->HandlePredicate(haveTest != nullptr, reducible, arg, newArgs, - argP1, argP2); - } - } else if (this->Policy64Status == cmPolicies::WARN && - this->IsKeyword(keyTEST, *arg)) { + const auto policy64IsOld = this->Policy64Status == cmPolicies::OLD || + this->Policy64Status == cmPolicies::WARN; + + for (auto args = newArgs.make2ArgsIterator(); args.current != newArgs.end(); + args.advance(newArgs)) { + + auto policyCheck = [&, this](const cmPolicies::PolicyID id, + const cmPolicies::PolicyStatus status, + const cm::static_string_view kw) { + if (status == cmPolicies::WARN && this->IsKeyword(kw, *args.current)) { std::ostringstream e; - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n"; - e << "TEST will be interpreted as an operator " + e << cmPolicies::GetPolicyWarning(id) << "\n" + << kw + << " will be interpreted as an operator " "when the policy is set to NEW. " "Since the policy is not set the OLD behavior will be used."; this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str()); } - // is a variable defined - if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) { - size_t argP1len = argP1->GetValue().size(); - bool bdef = false; - if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") && - argP1->GetValue().operator[](argP1len - 1) == '}') { - std::string env = argP1->GetValue().substr(4, argP1len - 5); - bdef = cmSystemTools::HasEnv(env); - } else if (argP1len > 6 && - cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") && - argP1->GetValue().operator[](argP1len - 1) == '}') { - std::string cache = argP1->GetValue().substr(6, argP1len - 7); - bdef = - this->Makefile.GetState()->GetCacheEntryValue(cache) != nullptr; - } else { - bdef = this->Makefile.IsDefinitionSet(argP1->GetValue()); - } - this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2); + }; + + // NOTE Checking policies for warnings are not require an access to the + // next arg. Check them first! + policyCheck(cmPolicies::CMP0064, this->Policy64Status, keyTEST); + + // NOTE Fail fast: All the predicates below require the next arg to be + // valid + if (args.next == newArgs.end()) { + continue; + } + + // does a file exist + if (this->IsKeyword(keyEXISTS, *args.current)) { + newArgs.ReduceOneArg(cmSystemTools::FileExists(args.next->GetValue()), + args); + } + // does a directory with this name exist + else if (this->IsKeyword(keyIS_DIRECTORY, *args.current)) { + newArgs.ReduceOneArg( + cmSystemTools::FileIsDirectory(args.next->GetValue()), args); + } + // does a symlink with this name exist + else if (this->IsKeyword(keyIS_SYMLINK, *args.current)) { + newArgs.ReduceOneArg(cmSystemTools::FileIsSymlink(args.next->GetValue()), + args); + } + // is the given path an absolute path ? + else if (this->IsKeyword(keyIS_ABSOLUTE, *args.current)) { + newArgs.ReduceOneArg( + cmSystemTools::FileIsFullPath(args.next->GetValue()), args); + } + // does a command exist + else if (this->IsKeyword(keyCOMMAND, *args.current)) { + newArgs.ReduceOneArg( + bool(this->Makefile.GetState()->GetCommand(args.next->GetValue())), + args); + } + // does a policy exist + else if (this->IsKeyword(keyPOLICY, *args.current)) { + cmPolicies::PolicyID pid; + newArgs.ReduceOneArg( + cmPolicies::GetPolicyID(args.next->GetValue().c_str(), pid), args); + } + // does a target exist + else if (this->IsKeyword(keyTARGET, *args.current)) { + newArgs.ReduceOneArg( + bool(this->Makefile.FindTargetToUse(args.next->GetValue())), args); + } + // is a variable defined + else if (this->IsKeyword(keyDEFINED, *args.current)) { + const auto& var = args.next->GetValue(); + const auto varNameLen = var.size(); + + auto result = false; + if (looksLikeSpecialVariable(var, "ENV"_s, varNameLen)) { + const auto env = args.next->GetValue().substr(4, varNameLen - 5); + result = cmSystemTools::HasEnv(env); + } + + else if (looksLikeSpecialVariable(var, "CACHE"_s, varNameLen)) { + const auto cache = args.next->GetValue().substr(6, varNameLen - 7); + result = bool(this->Makefile.GetState()->GetCacheEntryValue(cache)); } - ++arg; + + else { + result = this->Makefile.IsDefinitionSet(args.next->GetValue()); + } + newArgs.ReduceOneArg(result, args); + } + // does a test exist + else if (this->IsKeyword(keyTEST, *args.current)) { + if (policy64IsOld) { + continue; + } + newArgs.ReduceOneArg(bool(this->Makefile.GetTest(args.next->GetValue())), + args); } - } while (reducible); + } return true; } @@ -518,178 +632,143 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, std::string& errorString, MessageType& status) { - int reducible; - std::string def_buf; - cmProp def; - cmProp def2; - do { - reducible = 0; - auto arg = newArgs.begin(); - cmArgumentList::iterator argP1; - cmArgumentList::iterator argP2; - while (arg != newArgs.end()) { - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - if (argP1 != newArgs.end() && argP2 != newArgs.end() && - this->IsKeyword(keyMATCHES, *argP1)) { - def = this->GetDefinitionIfUnquoted(*arg); - if (!def) { - def = &arg->GetValue(); - } else if (cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) { - // The string to match is owned by our match result variables. - // Move it to our own buffer before clearing them. - def_buf = *def; - def = &def_buf; - } - const std::string& rex = argP2->GetValue(); - this->Makefile.ClearMatches(); - cmsys::RegularExpression regEntry; - if (!regEntry.compile(rex)) { - std::ostringstream error; - error << "Regular expression \"" << rex << "\" cannot compile"; - errorString = error.str(); - status = MessageType::FATAL_ERROR; - return false; - } - if (regEntry.find(*def)) { - this->Makefile.StoreMatches(regEntry); - *arg = cmExpandedCommandArgument("1", true); - } else { - *arg = cmExpandedCommandArgument("0", true); - } - newArgs.erase(argP2); - newArgs.erase(argP1); - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - reducible = 1; - } + for (auto args = newArgs.make3ArgsIterator(); args.current != newArgs.end(); + args.advance(newArgs)) { - if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg)) { - *arg = cmExpandedCommandArgument("0", true); - newArgs.erase(argP1); - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - reducible = 1; - } + int matchNo; - if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (this->IsKeyword(keyLESS, *argP1) || - this->IsKeyword(keyLESS_EQUAL, *argP1) || - this->IsKeyword(keyGREATER, *argP1) || - this->IsKeyword(keyGREATER_EQUAL, *argP1) || - this->IsKeyword(keyEQUAL, *argP1))) { - def = this->GetVariableOrString(*arg); - def2 = this->GetVariableOrString(*argP2); - double lhs; - double rhs; - bool result; - if (sscanf(def->c_str(), "%lg", &lhs) != 1 || - sscanf(def2->c_str(), "%lg", &rhs) != 1) { - result = false; - } else if (*(argP1) == keyLESS) { - result = (lhs < rhs); - } else if (*(argP1) == keyLESS_EQUAL) { - result = (lhs <= rhs); - } else if (*(argP1) == keyGREATER) { - result = (lhs > rhs); - } else if (*(argP1) == keyGREATER_EQUAL) { - result = (lhs >= rhs); - } else { - result = (lhs == rhs); - } - this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); - } + // NOTE Handle special case `if(... BLAH_BLAH MATCHES)` + // (i.e., w/o regex to match which is possibly result of + // variable expansion to an empty string) + if (args.next != newArgs.end() && + this->IsKeyword(keyMATCHES, *args.current)) { + newArgs.ReduceOneArg(false, args); + } + + // NOTE Fail fast: All the binary ops below require 2 arguments. + else if (args.next == newArgs.end() || args.nextnext == newArgs.end()) { + continue; + } - if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (this->IsKeyword(keySTRLESS, *argP1) || - this->IsKeyword(keySTRLESS_EQUAL, *argP1) || - this->IsKeyword(keySTRGREATER, *argP1) || - this->IsKeyword(keySTRGREATER_EQUAL, *argP1) || - this->IsKeyword(keySTREQUAL, *argP1))) { - def = this->GetVariableOrString(*arg); - def2 = this->GetVariableOrString(*argP2); - int val = (*def).compare(*def2); - bool result; - if (*(argP1) == keySTRLESS) { - result = (val < 0); - } else if (*(argP1) == keySTRLESS_EQUAL) { - result = (val <= 0); - } else if (*(argP1) == keySTRGREATER) { - result = (val > 0); - } else if (*(argP1) == keySTRGREATER_EQUAL) { - result = (val >= 0); - } else // strequal - { - result = (val == 0); - } - this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); + else if (this->IsKeyword(keyMATCHES, *args.next)) { + cmProp def = this->GetDefinitionIfUnquoted(*args.current); + + std::string def_buf; + if (!def) { + def = cmProp(args.current->GetValue()); + } else if (cmHasLiteralPrefix(args.current->GetValue(), + "CMAKE_MATCH_")) { + // The string to match is owned by our match result variables. + // Move it to our own buffer before clearing them. + def_buf = *def; + def = cmProp(def_buf); } - if (argP1 != newArgs.end() && argP2 != newArgs.end() && - (this->IsKeyword(keyVERSION_LESS, *argP1) || - this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) || - this->IsKeyword(keyVERSION_GREATER, *argP1) || - this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) || - this->IsKeyword(keyVERSION_EQUAL, *argP1))) { - def = this->GetVariableOrString(*arg); - def2 = this->GetVariableOrString(*argP2); - cmSystemTools::CompareOp op; - if (*argP1 == keyVERSION_LESS) { - op = cmSystemTools::OP_LESS; - } else if (*argP1 == keyVERSION_LESS_EQUAL) { - op = cmSystemTools::OP_LESS_EQUAL; - } else if (*argP1 == keyVERSION_GREATER) { - op = cmSystemTools::OP_GREATER; - } else if (*argP1 == keyVERSION_GREATER_EQUAL) { - op = cmSystemTools::OP_GREATER_EQUAL; - } else { // version_equal - op = cmSystemTools::OP_EQUAL; - } - bool result = - cmSystemTools::VersionCompare(op, def->c_str(), def2->c_str()); - this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); + this->Makefile.ClearMatches(); + + const auto& rex = args.nextnext->GetValue(); + cmsys::RegularExpression regEntry; + if (!regEntry.compile(rex)) { + std::ostringstream error; + error << "Regular expression \"" << rex << "\" cannot compile"; + errorString = error.str(); + status = MessageType::FATAL_ERROR; + return false; } - // is file A newer than file B - if (argP1 != newArgs.end() && argP2 != newArgs.end() && - this->IsKeyword(keyIS_NEWER_THAN, *argP1)) { - int fileIsNewer = 0; - cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare( - arg->GetValue(), (argP2)->GetValue(), &fileIsNewer); - this->HandleBinaryOp( - (!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0), reducible, arg, - newArgs, argP1, argP2); + const auto match = regEntry.find(*def); + if (match) { + this->Makefile.StoreMatches(regEntry); } + newArgs.ReduceTwoArgs(match, args); + } + + else if ((matchNo = + this->matchKeys(*args.next, keyLESS, keyLESS_EQUAL, keyGREATER, + keyGREATER_EQUAL, keyEQUAL))) { + + cmProp ldef = this->GetVariableOrString(*args.current); + cmProp rdef = this->GetVariableOrString(*args.nextnext); + + double lhs; + double rhs; + auto parseDoubles = [&]() { + return std::sscanf(ldef->c_str(), "%lg", &lhs) == 1 && + std::sscanf(rdef->c_str(), "%lg", &rhs) == 1; + }; + // clang-format off + const auto result = parseDoubles() && + cmRt2CtSelector< + std::less, std::less_equal, + std::greater, std::greater_equal, + std::equal_to + >::eval(matchNo, lhs, rhs); + // clang-format on + newArgs.ReduceTwoArgs(result, args); + } + + else if ((matchNo = this->matchKeys(*args.next, keySTRLESS, + keySTRLESS_EQUAL, keySTRGREATER, + keySTRGREATER_EQUAL, keySTREQUAL))) { + + const cmProp lhs = this->GetVariableOrString(*args.current); + const cmProp rhs = this->GetVariableOrString(*args.nextnext); + const auto val = (*lhs).compare(*rhs); + // clang-format off + const auto result = cmRt2CtSelector< + std::less, std::less_equal, + std::greater, std::greater_equal, + std::equal_to + >::eval(matchNo, val, 0); + // clang-format on + newArgs.ReduceTwoArgs(result, args); + } + + else if ((matchNo = + this->matchKeys(*args.next, keyVERSION_LESS, + keyVERSION_LESS_EQUAL, keyVERSION_GREATER, + keyVERSION_GREATER_EQUAL, keyVERSION_EQUAL))) { + const auto op = MATCH2CMPOP[matchNo - 1]; + const cmProp lhs = this->GetVariableOrString(*args.current); + const cmProp rhs = this->GetVariableOrString(*args.nextnext); + const auto result = + cmSystemTools::VersionCompare(op, lhs->c_str(), rhs->c_str()); + newArgs.ReduceTwoArgs(result, args); + } + + // is file A newer than file B + else if (this->IsKeyword(keyIS_NEWER_THAN, *args.next)) { + auto fileIsNewer = 0; + cmsys::Status ftcStatus = cmSystemTools::FileTimeCompare( + args.current->GetValue(), args.nextnext->GetValue(), &fileIsNewer); + newArgs.ReduceTwoArgs( + (!ftcStatus || fileIsNewer == 1 || fileIsNewer == 0), args); + } + + else if (this->IsKeyword(keyIN_LIST, *args.next)) { - if (argP1 != newArgs.end() && argP2 != newArgs.end() && - this->IsKeyword(keyIN_LIST, *argP1)) { - if (this->Policy57Status != cmPolicies::OLD && - this->Policy57Status != cmPolicies::WARN) { - bool result = false; - - def = this->GetVariableOrString(*arg); - def2 = this->Makefile.GetDefinition(argP2->GetValue()); - - if (def2) { - std::vector<std::string> list = cmExpandedList(*def2, true); - result = cm::contains(list, *def); - } - - this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); - } else if (this->Policy57Status == cmPolicies::WARN) { - std::ostringstream e; - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) << "\n"; - e << "IN_LIST will be interpreted as an operator " - "when the policy is set to NEW. " - "Since the policy is not set the OLD behavior will be used."; - - this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str()); - } + if (this->Policy57Status != cmPolicies::OLD && + this->Policy57Status != cmPolicies::WARN) { + + cmProp lhs = this->GetVariableOrString(*args.current); + cmProp rhs = this->Makefile.GetDefinition(args.nextnext->GetValue()); + + newArgs.ReduceTwoArgs( + rhs && cm::contains(cmExpandedList(*rhs, true), *lhs), args); } - ++arg; + else if (this->Policy57Status == cmPolicies::WARN) { + std::ostringstream e; + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) + << "\n" + "IN_LIST will be interpreted as an operator " + "when the policy is set to NEW. " + "Since the policy is not set the OLD behavior will be used."; + + this->Makefile.IssueMessage(MessageType::AUTHOR_WARNING, e.str()); + } } - } while (reducible); + } return true; } @@ -699,23 +778,14 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs, std::string& errorString, MessageType& status) { - int reducible; - do { - reducible = 0; - auto arg = newArgs.begin(); - cmArgumentList::iterator argP1; - cmArgumentList::iterator argP2; - while (arg != newArgs.end()) { - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - if (argP1 != newArgs.end() && this->IsKeyword(keyNOT, *arg)) { - bool rhs = this->GetBooleanValueWithAutoDereference( - *argP1, errorString, status); - this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2); - } - ++arg; + for (auto args = newArgs.make2ArgsIterator(); args.next != newArgs.end(); + args.advance(newArgs)) { + if (this->IsKeyword(keyNOT, *args.current)) { + const auto rhs = this->GetBooleanValueWithAutoDereference( + *args.next, errorString, status); + newArgs.ReduceOneArg(!rhs, args); } - } while (reducible); + } return true; } @@ -725,38 +795,24 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs, std::string& errorString, MessageType& status) { - int reducible; - bool lhs; - bool rhs; - do { - reducible = 0; - auto arg = newArgs.begin(); - cmArgumentList::iterator argP1; - cmArgumentList::iterator argP2; - while (arg != newArgs.end()) { - argP1 = arg; - this->IncrementArguments(newArgs, argP1, argP2); - if (argP1 != newArgs.end() && this->IsKeyword(keyAND, *argP1) && - argP2 != newArgs.end()) { - lhs = - this->GetBooleanValueWithAutoDereference(*arg, errorString, status); - rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString, - status); - this->HandleBinaryOp((lhs && rhs), reducible, arg, newArgs, argP1, - argP2); - } - - if (argP1 != newArgs.end() && this->IsKeyword(keyOR, *argP1) && - argP2 != newArgs.end()) { - lhs = - this->GetBooleanValueWithAutoDereference(*arg, errorString, status); - rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString, - status); - this->HandleBinaryOp((lhs || rhs), reducible, arg, newArgs, argP1, - argP2); - } - ++arg; + for (auto args = newArgs.make3ArgsIterator(); args.nextnext != newArgs.end(); + args.advance(newArgs)) { + + int matchNo; + + if ((matchNo = this->matchKeys(*args.next, keyAND, keyOR))) { + const auto lhs = this->GetBooleanValueWithAutoDereference( + *args.current, errorString, status); + const auto rhs = this->GetBooleanValueWithAutoDereference( + *args.nextnext, errorString, status); + // clang-format off + const auto result = + cmRt2CtSelector< + std::logical_and, std::logical_or + >::eval(matchNo, lhs, rhs); + // clang-format on + newArgs.ReduceTwoArgs(result, args); } - } while (reducible); + } return true; } diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h index cf00ede..00d896b 100644 --- a/Source/cmConditionEvaluator.h +++ b/Source/cmConditionEvaluator.h @@ -4,23 +4,22 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <list> #include <string> #include <vector> -#include "cmExpandedCommandArgument.h" +#include <cmext/string_view> + #include "cmListFileCache.h" #include "cmMessageType.h" #include "cmPolicies.h" #include "cmProperty.h" +class cmExpandedCommandArgument; class cmMakefile; class cmConditionEvaluator { public: - using cmArgumentList = std::list<cmExpandedCommandArgument>; - cmConditionEvaluator(cmMakefile& makefile, cmListFileBacktrace bt); // this is a shared function for both If and Else to determine if the @@ -30,14 +29,16 @@ public: std::string& errorString, MessageType& status); private: + class cmArgumentList; + // Filter the given variable definition based on policy CMP0054. cmProp GetDefinitionIfUnquoted( const cmExpandedCommandArgument& argument) const; cmProp GetVariableOrString(const cmExpandedCommandArgument& argument) const; - bool IsKeyword(std::string const& keyword, - cmExpandedCommandArgument& argument) const; + bool IsKeyword(cm::static_string_view keyword, + const cmExpandedCommandArgument& argument) const; bool GetBooleanValue(cmExpandedCommandArgument& arg) const; @@ -49,19 +50,14 @@ private: MessageType& status, bool oneArg = false) const; - void IncrementArguments(cmArgumentList& newArgs, - cmArgumentList::iterator& argP1, - cmArgumentList::iterator& argP2) const; + template <int N> + int matchKeysImpl(const cmExpandedCommandArgument&); - void HandlePredicate(bool value, int& reducible, - cmArgumentList::iterator& arg, cmArgumentList& newArgs, - cmArgumentList::iterator& argP1, - cmArgumentList::iterator& argP2) const; + template <int N, typename T, typename... Keys> + int matchKeysImpl(const cmExpandedCommandArgument&, T, Keys...); - void HandleBinaryOp(bool value, int& reducible, - cmArgumentList::iterator& arg, cmArgumentList& newArgs, - cmArgumentList::iterator& argP1, - cmArgumentList::iterator& argP2); + template <typename... Keys> + int matchKeys(const cmExpandedCommandArgument&, Keys...); bool HandleLevel0(cmArgumentList& newArgs, std::string& errorString, MessageType& status); diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index aeca6b4..6a419f6 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -16,7 +16,6 @@ #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE #cmakedefine HAVE_UNSETENV -#cmakedefine CMake_USE_ELF_PARSER #cmakedefine CMake_USE_MACH_PARSER #cmakedefine CMake_USE_XCOFF_PARSER #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index bf18143..0fd48f0 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -606,7 +606,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, std::string langFlags = "CMAKE_" + li + "_FLAGS"; cmProp flags = this->Makefile->GetDefinition(langFlags); fprintf(fout, "set(CMAKE_%s_FLAGS %s)\n", li.c_str(), - cmOutputConverter::EscapeForCMake(cmToCStrSafe(flags)).c_str()); + cmOutputConverter::EscapeForCMake(flags).c_str()); fprintf(fout, "set(CMAKE_%s_FLAGS \"${CMAKE_%s_FLAGS}" " ${COMPILE_DEFINITIONS}\")\n", @@ -644,9 +644,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, std::string const langFlagsCfg = cmStrCat("CMAKE_", li, "_FLAGS_", cfg); cmProp flagsCfg = this->Makefile->GetDefinition(langFlagsCfg); - fprintf( - fout, "set(%s %s)\n", langFlagsCfg.c_str(), - cmOutputConverter::EscapeForCMake(cmToCStrSafe(flagsCfg)).c_str()); + fprintf(fout, "set(%s %s)\n", langFlagsCfg.c_str(), + cmOutputConverter::EscapeForCMake(flagsCfg).c_str()); } } break; } @@ -679,8 +678,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, cmProp exeLinkFlags = this->Makefile->GetDefinition("CMAKE_EXE_LINKER_FLAGS"); fprintf(fout, "set(CMAKE_EXE_LINKER_FLAGS %s)\n", - cmOutputConverter::EscapeForCMake(cmToCStrSafe(exeLinkFlags)) - .c_str()); + cmOutputConverter::EscapeForCMake(exeLinkFlags).c_str()); } break; } diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx index 4a4f87d..9e2d7b9 100644 --- a/Source/cmDefinitions.cxx +++ b/Source/cmDefinitions.cxx @@ -34,11 +34,11 @@ cmDefinitions::Def const& cmDefinitions::GetInternal(const std::string& key, return begin->Map.emplace(key, def).first->second; } -const std::string* cmDefinitions::Get(const std::string& key, StackIter begin, - StackIter end) +cmProp cmDefinitions::Get(const std::string& key, StackIter begin, + StackIter end) { Def const& def = cmDefinitions::GetInternal(key, begin, end, false); - return def.Value ? def.Value.str_if_stable() : nullptr; + return def.Value ? cmProp(def.Value.str_if_stable()) : nullptr; } void cmDefinitions::Raise(const std::string& key, StackIter begin, diff --git a/Source/cmDefinitions.h b/Source/cmDefinitions.h index b650aa8..ee1db7a 100644 --- a/Source/cmDefinitions.h +++ b/Source/cmDefinitions.h @@ -12,6 +12,7 @@ #include <cm/string_view> #include "cmLinkedTree.h" +#include "cmProperty.h" #include "cmString.hxx" /** \class cmDefinitions @@ -28,8 +29,7 @@ class cmDefinitions public: // -- Static member functions - static const std::string* Get(const std::string& key, StackIter begin, - StackIter end); + static cmProp Get(const std::string& key, StackIter begin, StackIter end); static void Raise(const std::string& key, StackIter begin, StackIter end); diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index bca26b9..6024cf6 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -163,12 +163,17 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, mod_dir = this->LocalGenerator->GetCurrentBinaryDirectory(); } + bool building_intrinsics = + !mf->GetSafeDefinition("CMAKE_Fortran_TARGET_BUILDING_INSTRINSIC_MODULES") + .empty(); + // Actually write dependencies to the streams. using ObjectInfoMap = cmDependsFortranInternals::ObjectInfoMap; ObjectInfoMap const& objInfo = this->Internal->ObjectInfo; for (auto const& i : objInfo) { if (!this->WriteDependenciesReal(i.first, i.second, mod_dir, stamp_dir, - makeDepends, internalDepends)) { + makeDepends, internalDepends, + building_intrinsics)) { return false; } } @@ -307,7 +312,8 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, std::string const& mod_dir, std::string const& stamp_dir, std::ostream& makeDepends, - std::ostream& internalDepends) + std::ostream& internalDepends, + bool buildingIntrinsics) { // Get the source file for this object. std::string const& src = info.Source; @@ -339,8 +345,13 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, makeDepends << '\n'; } + std::set<std::string> req = info.Requires; + if (buildingIntrinsics) { + req.insert(info.Intrinsics.begin(), info.Intrinsics.end()); + } + // Write module requirements to the output stream. - for (std::string const& i : info.Requires) { + for (std::string const& i : req) { // Require only modules not provided in the same source. if (info.Provides.find(i) != info.Provides.cend()) { continue; diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h index 0d407bc..a74db91 100644 --- a/Source/cmDependsFortran.h +++ b/Source/cmDependsFortran.h @@ -72,7 +72,8 @@ protected: std::string const& mod_dir, std::string const& stamp_dir, std::ostream& makeDepends, - std::ostream& internalDepends); + std::ostream& internalDepends, + bool buildingIntrinsics); // The source file from which to start scanning. std::string SourceFile; diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 9a474e3..1678ce8 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -17,41 +17,9 @@ #include "cmsys/FStream.hxx" -// Include the ELF format information system header. -#if defined(__OpenBSD__) -# include <elf_abi.h> -#elif defined(__HAIKU__) -# include <elf32.h> -# include <elf64.h> -using Elf32_Ehdr = struct Elf32_Ehdr; -using Elf32_Shdr = struct Elf32_Shdr; -using Elf32_Sym = struct Elf32_Sym; -using Elf32_Rel = struct Elf32_Rel; -using Elf32_Rela = struct Elf32_Rela; -# define ELFMAG0 0x7F -# define ELFMAG1 'E' -# define ELFMAG2 'L' -# define ELFMAG3 'F' -# define ET_NONE 0 -# define ET_REL 1 -# define ET_EXEC 2 -# define ET_DYN 3 -# define ET_CORE 4 -# define EM_386 3 -# define EM_SPARC 2 -# define EM_PPC 20 -#else -# include <elf.h> -#endif -#if defined(__sun) -# include <sys/link.h> // For dynamic section information -#endif -#ifdef _SCO_DS -# include <link.h> // For DT_SONAME etc. -#endif -#ifndef DT_RUNPATH -# define DT_RUNPATH 29 -#endif +#include "cmelf/elf32.h" +#include "cmelf/elf64.h" +#include "cmelf/elf_common.h" // Low-level byte swapping implementation. template <size_t s> @@ -145,6 +113,7 @@ public: virtual std::vector<char> EncodeDynamicEntries( const cmELF::DynamicEntryList&) = 0; virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0; + virtual bool IsMips() const = 0; virtual void PrintInfo(std::ostream& os) const = 0; // Lookup the SONAME in the DYNAMIC section. @@ -218,7 +187,6 @@ struct cmELFTypes32 }; // Configure the implementation template for 64-bit ELF files. -#ifndef _SCO_DS struct cmELFTypes64 { using ELF_Ehdr = Elf64_Ehdr; @@ -228,7 +196,6 @@ struct cmELFTypes64 using tagtype = ::uint64_t; static const char* GetName() { return "64-bit"; } }; -#endif // Parser implementation template. template <class Types> @@ -262,6 +229,8 @@ public: // Lookup a string from the dynamic section with the given tag. StringEntry const* GetDynamicSectionString(unsigned int tag) override; + bool IsMips() const override { return this->ELFHeader.e_machine == EM_MIPS; } + // Print information about the ELF file. void PrintInfo(std::ostream& os) const override { @@ -345,16 +314,12 @@ private: eti == ET_CORE) { return true; } -#if defined(ET_LOOS) && defined(ET_HIOS) if (eti >= ET_LOOS && eti <= ET_HIOS) { return true; } -#endif -#if defined(ET_LOPROC) && defined(ET_HIPROC) if (eti >= ET_LOPROC && eti <= ET_HIPROC) { return true; } -#endif return false; } @@ -465,18 +430,14 @@ cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external, break; default: { unsigned int eti = static_cast<unsigned int>(this->ELFHeader.e_type); -#if defined(ET_LOOS) && defined(ET_HIOS) if (eti >= ET_LOOS && eti <= ET_HIOS) { this->ELFType = cmELF::FileTypeSpecificOS; break; } -#endif -#if defined(ET_LOPROC) && defined(ET_HIPROC) if (eti >= ET_LOPROC && eti <= ET_HIPROC) { this->ELFType = cmELF::FileTypeSpecificProc; break; } -#endif std::ostringstream e; e << "Unknown ELF file type " << eti; this->SetErrorMessage(e.str().c_str()); @@ -681,17 +642,12 @@ cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString( const long cmELF::TagRPath = DT_RPATH; const long cmELF::TagRunPath = DT_RUNPATH; - -#ifdef DT_MIPS_RLD_MAP_REL const long cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL; -#else -const long cmELF::TagMipsRldMapRel = 0; -#endif cmELF::cmELF(const char* fname) { // Try to open the file. - auto fin = cm::make_unique<cmsys::ifstream>(fname); + auto fin = cm::make_unique<cmsys::ifstream>(fname, std::ios::binary); // Quit now if the file could not be opened. if (!fin || !*fin) { @@ -736,15 +692,11 @@ cmELF::cmELF(const char* fname) // 32-bit ELF this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes32>>( this, std::move(fin), order); - } -#ifndef _SCO_DS - else if (ident[EI_CLASS] == ELFCLASS64) { + } else if (ident[EI_CLASS] == ELFCLASS64) { // 64-bit ELF this->Internal = cm::make_unique<cmELFInternalImpl<cmELFTypes64>>( this, std::move(fin), order); - } -#endif - else { + } else { this->ErrorMessage = "ELF file class is not 32-bit or 64-bit."; return; } @@ -846,6 +798,14 @@ cmELF::StringEntry const* cmELF::GetRunPath() return nullptr; } +bool cmELF::IsMIPS() const +{ + if (this->Valid()) { + return this->Internal->IsMips(); + } + return false; +} + void cmELF::PrintInfo(std::ostream& os) const { if (this->Valid()) { diff --git a/Source/cmELF.h b/Source/cmELF.h index f88ebe9..ce8bd7f 100644 --- a/Source/cmELF.h +++ b/Source/cmELF.h @@ -11,10 +11,6 @@ #include <utility> #include <vector> -#if !defined(CMake_USE_ELF_PARSER) -# error "This file may be included only if CMake_USE_ELF_PARSER is enabled." -#endif - class cmELFInternal; /** \class cmELF @@ -102,6 +98,9 @@ public: /** Get the RUNPATH field if any. */ StringEntry const* GetRunPath(); + /** Returns true if the ELF file targets a MIPS CPU. */ + bool IsMIPS() const; + /** Print human-readable information about the ELF file. */ void PrintInfo(std::ostream& os) const; diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 1a31ae4..6e3f918 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -18,6 +18,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" @@ -254,7 +255,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty( void cmExportBuildFileGenerator::HandleMissingTarget( std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget* depender, cmGeneratorTarget* dependee) + cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) { // The target is not in the export. if (!this->AppendMode) { @@ -321,7 +322,7 @@ cmExportBuildFileGenerator::FindBuildExportInfo(cmGlobalGenerator* gg, } void cmExportBuildFileGenerator::ComplainAboutMissingTarget( - cmGeneratorTarget* depender, cmGeneratorTarget* dependee, + cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, std::vector<std::string> const& exportFiles) { std::ostringstream e; @@ -344,7 +345,7 @@ void cmExportBuildFileGenerator::ComplainAboutMissingTarget( } std::string cmExportBuildFileGenerator::InstallNameDir( - cmGeneratorTarget* target, const std::string& config) + cmGeneratorTarget const* target, const std::string& config) { std::string install_name_dir; diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 264494d..244f526 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -60,11 +60,11 @@ protected: cmGeneratorTarget const* target) const; void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget* depender, + cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) override; - void ComplainAboutMissingTarget(cmGeneratorTarget* depender, - cmGeneratorTarget* dependee, + void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, + cmGeneratorTarget const* dependee, std::vector<std::string> const& namespaces); /** Fill in properties indicating built file locations. */ @@ -73,7 +73,7 @@ protected: cmGeneratorTarget* target, ImportPropertyMap& properties); - std::string InstallNameDir(cmGeneratorTarget* target, + std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; std::pair<std::vector<std::string>, std::string> FindBuildExportInfo( diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index dd611de..8b06a15 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -27,7 +27,6 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -#include "cmTargetExport.h" static std::string cmExportFileGeneratorEscape(std::string const& str) { @@ -123,7 +122,7 @@ void cmExportFileGenerator::GenerateImportConfig( } void cmExportFileGenerator::PopulateInterfaceProperty( - const std::string& propName, cmGeneratorTarget* target, + const std::string& propName, cmGeneratorTarget const* target, ImportPropertyMap& properties) { cmProp input = target->GetProperty(propName); @@ -134,7 +133,7 @@ void cmExportFileGenerator::PopulateInterfaceProperty( void cmExportFileGenerator::PopulateInterfaceProperty( const std::string& propName, const std::string& outputName, - cmGeneratorTarget* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { @@ -168,7 +167,7 @@ void cmExportFileGenerator::GenerateRequiredCMakeVersion( } bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( - cmGeneratorTarget* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { @@ -196,7 +195,7 @@ static bool isSubDirectory(std::string const& a, std::string const& b) } static bool checkInterfaceDirs(const std::string& prepro, - cmGeneratorTarget* target, + cmGeneratorTarget const* target, const std::string& prop) { std::string const& installDir = @@ -335,10 +334,10 @@ static void prefixItems(std::string& exportDirs) } void cmExportFileGenerator::PopulateSourcesInterface( - cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule, + cmGeneratorTarget const* gt, + cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { - cmGeneratorTarget* gt = tei->Target; assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_SOURCES"; @@ -366,10 +365,10 @@ void cmExportFileGenerator::PopulateSourcesInterface( } void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( - cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule, + cmGeneratorTarget const* target, + cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { - cmGeneratorTarget* target = tei->Target; assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_INCLUDE_DIRECTORIES"; @@ -378,7 +377,8 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( cmGeneratorExpression ge; std::string dirs = cmGeneratorExpression::Preprocess( - tei->InterfaceIncludeDirectories, preprocessRule, true); + cmJoin(target->Target->GetInstallIncludeDirectoriesEntries(), ";"), + preprocessRule, true); this->ReplaceInstallPrefix(dirs); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(dirs); std::string exportDirs = @@ -424,10 +424,10 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( } void cmExportFileGenerator::PopulateLinkDependsInterface( - cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule, + cmGeneratorTarget const* gt, + cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { - cmGeneratorTarget* gt = tei->Target; assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_LINK_DEPENDS"; @@ -455,10 +455,10 @@ void cmExportFileGenerator::PopulateLinkDependsInterface( } void cmExportFileGenerator::PopulateLinkDirectoriesInterface( - cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule, + cmGeneratorTarget const* gt, + cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { - cmGeneratorTarget* gt = tei->Target; assert(preprocessRule == cmGeneratorExpression::InstallInterface); const char* propName = "INTERFACE_LINK_DIRECTORIES"; @@ -486,7 +486,7 @@ void cmExportFileGenerator::PopulateLinkDirectoriesInterface( } void cmExportFileGenerator::PopulateInterfaceProperty( - const std::string& propName, cmGeneratorTarget* target, + const std::string& propName, cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { @@ -505,7 +505,7 @@ void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop, ifaceProperties.insert(content.begin(), content.end()); } -void getCompatibleInterfaceProperties(cmGeneratorTarget* target, +void getCompatibleInterfaceProperties(cmGeneratorTarget const* target, std::set<std::string>& ifaceProperties, const std::string& config) { @@ -544,7 +544,7 @@ void getCompatibleInterfaceProperties(cmGeneratorTarget* target, } void cmExportFileGenerator::PopulateCompatibleInterfaceProperties( - cmGeneratorTarget* gtarget, ImportPropertyMap& properties) + cmGeneratorTarget const* gtarget, ImportPropertyMap& properties) { this->PopulateInterfaceProperty("COMPATIBLE_INTERFACE_BOOL", gtarget, properties); @@ -596,7 +596,7 @@ void cmExportFileGenerator::GenerateInterfaceProperties( } bool cmExportFileGenerator::AddTargetNamespace( - std::string& input, cmGeneratorTarget* target, + std::string& input, cmGeneratorTarget const* target, std::vector<std::string>& missingTargets) { cmGeneratorTarget::TargetOrString resolved = @@ -627,7 +627,7 @@ bool cmExportFileGenerator::AddTargetNamespace( } void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( - std::string& input, cmGeneratorTarget* target, + std::string& input, cmGeneratorTarget const* target, std::vector<std::string>& missingTargets, FreeTargetsReplace replace) { if (replace == NoReplaceFreeTargets) { @@ -654,7 +654,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpressions( } void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( - std::string& input, cmGeneratorTarget* target, + std::string& input, cmGeneratorTarget const* target, std::vector<std::string>& missingTargets) { std::string::size_type pos = 0; @@ -744,7 +744,7 @@ void cmExportFileGenerator::ReplaceInstallPrefix(std::string& /*unused*/) void cmExportFileGenerator::SetImportLinkInterface( const std::string& config, std::string const& suffix, cmGeneratorExpression::PreprocessContext preprocessRule, - cmGeneratorTarget* target, ImportPropertyMap& properties, + cmGeneratorTarget const* target, ImportPropertyMap& properties, std::vector<std::string>& missingTargets) { // Add the transitive link dependencies for this configuration. @@ -880,7 +880,7 @@ static std::string const& asString(cmLinkItem const& l) template <typename T> void cmExportFileGenerator::SetImportLinkProperty( - std::string const& suffix, cmGeneratorTarget* target, + std::string const& suffix, cmGeneratorTarget const* target, const std::string& propName, std::vector<T> const& entries, ImportPropertyMap& properties, std::vector<std::string>& missingTargets, ImportLinkPropertyTargetNames targetNames) @@ -917,20 +917,20 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) // Protect that file against use with older CMake versions. /* clang-format off */ os << "# Generated by CMake\n\n"; - os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n" + os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.6)\n" << " message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n" << "endif()\n"; /* clang-format on */ // Isolate the file policy level. // Support CMake versions as far back as 2.6 but also support using NEW - // policy settings for up to CMake 3.19 (this upper limit may be reviewed + // policy settings for up to CMake 3.20 (this upper limit may be reviewed // and increased from time to time). This reduces the opportunity for CMake // warnings when an older export file is later used with newer CMake // versions. /* clang-format off */ os << "cmake_policy(PUSH)\n" - << "cmake_policy(VERSION 2.6...3.19)\n"; + << "cmake_policy(VERSION 2.6...3.20)\n"; /* clang-format on */ } @@ -1211,7 +1211,7 @@ void cmExportFileGenerator::GenerateImportedFileChecksCode( } bool cmExportFileGenerator::PopulateExportProperties( - cmGeneratorTarget* gte, ImportPropertyMap& properties, + cmGeneratorTarget const* gte, ImportPropertyMap& properties, std::string& errorMessage) { const auto& targetProperties = gte->Target->GetProperties(); diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 45eaed0..24e048b 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -27,8 +27,6 @@ class cmGeneratorTarget; CMake_VERSION_MINOR) "." STRINGIFY(CMake_VERSION_PATCH) \ : #major "." #minor ".0") -class cmTargetExport; - /** \class cmExportFileGenerator * \brief Generate a file exporting targets from a build or install tree. * @@ -108,7 +106,7 @@ protected: }; template <typename T> void SetImportLinkProperty(std::string const& suffix, - cmGeneratorTarget* target, + cmGeneratorTarget const* target, const std::string& propName, std::vector<T> const& entries, ImportPropertyMap& properties, @@ -127,44 +125,45 @@ protected: * export set. */ virtual void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget* depender, + cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) = 0; - void PopulateInterfaceProperty(const std::string&, cmGeneratorTarget* target, + void PopulateInterfaceProperty(const std::string&, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); bool PopulateInterfaceLinkLibrariesProperty( - cmGeneratorTarget* target, cmGeneratorExpression::PreprocessContext, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); void PopulateInterfaceProperty(const std::string& propName, - cmGeneratorTarget* target, + cmGeneratorTarget const* target, ImportPropertyMap& properties); - void PopulateCompatibleInterfaceProperties(cmGeneratorTarget* target, + void PopulateCompatibleInterfaceProperties(cmGeneratorTarget const* target, ImportPropertyMap& properties); virtual void GenerateInterfaceProperties( cmGeneratorTarget const* target, std::ostream& os, const ImportPropertyMap& properties); void PopulateIncludeDirectoriesInterface( - cmTargetExport* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); void PopulateSourcesInterface( - cmTargetExport* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); void PopulateLinkDirectoriesInterface( - cmTargetExport* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); void PopulateLinkDependsInterface( - cmTargetExport* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext preprocessRule, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); void SetImportLinkInterface( const std::string& config, std::string const& suffix, cmGeneratorExpression::PreprocessContext preprocessRule, - cmGeneratorTarget* target, ImportPropertyMap& properties, + cmGeneratorTarget const* target, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); enum FreeTargetsReplace @@ -174,14 +173,14 @@ protected: }; void ResolveTargetsInGeneratorExpressions( - std::string& input, cmGeneratorTarget* target, + std::string& input, cmGeneratorTarget const* target, std::vector<std::string>& missingTargets, FreeTargetsReplace replace = NoReplaceFreeTargets); virtual void GenerateRequiredCMakeVersion(std::ostream& os, const char* versionString); - bool PopulateExportProperties(cmGeneratorTarget* gte, + bool PopulateExportProperties(cmGeneratorTarget const* gte, ImportPropertyMap& properties, std::string& errorMessage); @@ -205,20 +204,20 @@ protected: private: void PopulateInterfaceProperty(const std::string&, const std::string&, - cmGeneratorTarget* target, + cmGeneratorTarget const* target, cmGeneratorExpression::PreprocessContext, ImportPropertyMap& properties, std::vector<std::string>& missingTargets); - bool AddTargetNamespace(std::string& input, cmGeneratorTarget* target, + bool AddTargetNamespace(std::string& input, cmGeneratorTarget const* target, std::vector<std::string>& missingTargets); void ResolveTargetsInGeneratorExpression( - std::string& input, cmGeneratorTarget* target, + std::string& input, cmGeneratorTarget const* target, std::vector<std::string>& missingTargets); virtual void ReplaceInstallPrefix(std::string& input); - virtual std::string InstallNameDir(cmGeneratorTarget* target, + virtual std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) = 0; }; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 3c69c50..46d2d31 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -16,6 +16,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -85,8 +86,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) ImportPropertyMap properties; this->PopulateIncludeDirectoriesInterface( - te, cmGeneratorExpression::InstallInterface, properties, missingTargets); - this->PopulateSourcesInterface(te, cmGeneratorExpression::InstallInterface, + gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); + this->PopulateSourcesInterface(gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); this->PopulateInterfaceProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", gt, cmGeneratorExpression::InstallInterface, @@ -110,9 +111,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) cmGeneratorExpression::InstallInterface, properties, missingTargets); this->PopulateLinkDirectoriesInterface( - te, cmGeneratorExpression::InstallInterface, properties, missingTargets); + gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); this->PopulateLinkDependsInterface( - te, cmGeneratorExpression::InstallInterface, properties, missingTargets); + gt, cmGeneratorExpression::InstallInterface, properties, missingTargets); std::string errorMessage; if (!this->PopulateExportProperties(gt, properties, errorMessage)) { @@ -447,7 +448,7 @@ cmStateEnums::TargetType cmExportInstallFileGenerator::GetExportTargetType( void cmExportInstallFileGenerator::HandleMissingTarget( std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget* depender, cmGeneratorTarget* dependee) + cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) { const std::string name = dependee->GetName(); cmGlobalGenerator* gg = dependee->GetLocalGenerator()->GetGlobalGenerator(); @@ -499,7 +500,7 @@ cmExportInstallFileGenerator::FindNamespaces(cmGlobalGenerator* gg, } void cmExportInstallFileGenerator::ComplainAboutMissingTarget( - cmGeneratorTarget* depender, cmGeneratorTarget* dependee, + cmGeneratorTarget const* depender, cmGeneratorTarget const* dependee, std::vector<std::string> const& exportFiles) { std::ostringstream e; @@ -521,7 +522,7 @@ void cmExportInstallFileGenerator::ComplainAboutMissingTarget( } std::string cmExportInstallFileGenerator::InstallNameDir( - cmGeneratorTarget* target, const std::string& config) + cmGeneratorTarget const* target, const std::string& config) { std::string install_name_dir; diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 2d8de9d..5cec2e0 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -63,13 +63,13 @@ protected: cmTargetExport const* targetExport) const; void HandleMissingTarget(std::string& link_libs, std::vector<std::string>& missingTargets, - cmGeneratorTarget* depender, + cmGeneratorTarget const* depender, cmGeneratorTarget* dependee) override; void ReplaceInstallPrefix(std::string& input) override; - void ComplainAboutMissingTarget(cmGeneratorTarget* depender, - cmGeneratorTarget* dependee, + void ComplainAboutMissingTarget(cmGeneratorTarget const* depender, + cmGeneratorTarget const* dependee, std::vector<std::string> const& exportFiles); std::pair<std::vector<std::string>, std::string> FindNamespaces( @@ -94,7 +94,7 @@ protected: ImportPropertyMap& properties, std::set<std::string>& importedLocations); - std::string InstallNameDir(cmGeneratorTarget* target, + std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; cmInstallExportGenerator* IEGen; diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index cac60e1..f89d0ad 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -126,7 +126,7 @@ void cmExportTryCompileFileGenerator::PopulateProperties( } std::string cmExportTryCompileFileGenerator::InstallNameDir( - cmGeneratorTarget* target, const std::string& config) + cmGeneratorTarget const* target, const std::string& config) { std::string install_name_dir; diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 6bf5781..127b8df 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -36,7 +36,8 @@ protected: { } void HandleMissingTarget(std::string&, std::vector<std::string>&, - cmGeneratorTarget*, cmGeneratorTarget*) override + cmGeneratorTarget const*, + cmGeneratorTarget*) override { } @@ -44,7 +45,7 @@ protected: ImportPropertyMap& properties, std::set<const cmGeneratorTarget*>& emitted); - std::string InstallNameDir(cmGeneratorTarget* target, + std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; private: diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index a2b5460..adeba74 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -813,8 +813,7 @@ Json::Value CodemodelConfig::DumpProject(Project& p) Json::Value CodemodelConfig::DumpMinimumCMakeVersion(cmStateSnapshot s) { Json::Value minimumCMakeVersion; - if (std::string const* def = - s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) { + if (cmProp def = s.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) { minimumCMakeVersion = Json::objectValue; minimumCMakeVersion["string"] = *def; } diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 0ad59c7..2730a07 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -31,6 +31,7 @@ #include "cmArgumentParser.h" #include "cmCMakePath.h" #include "cmCryptoHash.h" +#include "cmELF.h" #include "cmExecutionStatus.h" #include "cmFSPermissions.h" #include "cmFileCopier.h" @@ -64,10 +65,6 @@ # include "cmFileLockResult.h" #endif -#if defined(CMake_USE_ELF_PARSER) -# include "cmELF.h" -#endif - #if defined(_WIN32) # include <windows.h> #endif @@ -1242,8 +1239,12 @@ bool HandleReadElfCommand(std::vector<std::string> const& args, return false; } -#if defined(CMake_USE_ELF_PARSER) cmELF elf(fileNameArg.c_str()); + if (!elf) { + status.SetError(cmStrCat("READ_ELF given FILE \"", fileNameArg, + "\" that is not a valid ELF file.")); + return false; + } if (!arguments.RPath.empty()) { if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) { @@ -1261,15 +1262,6 @@ bool HandleReadElfCommand(std::vector<std::string> const& args, } return true; -#else - std::string error = "ELF parser not available on this platform."; - if (arguments.Error.empty()) { - status.SetError(error); - return false; - } - status.GetMakefile().AddDefinition(arguments.Error, error); - return true; -#endif } bool HandleInstallCommand(std::vector<std::string> const& args, @@ -1858,7 +1850,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, } else if (*i == "TLS_CAINFO") { ++i; if (i != args.end()) { - cainfo = &(*i); + cainfo = cmProp(*i); } else { status.SetError("DOWNLOAD missing file value for TLS_CAINFO."); return false; @@ -2244,7 +2236,7 @@ bool HandleUploadCommand(std::vector<std::string> const& args, } else if (*i == "TLS_CAINFO") { ++i; if (i != args.end()) { - cainfo = &(*i); + cainfo = cmProp(*i); } else { status.SetError("UPLOAD missing file value for TLS_CAINFO."); return false; diff --git a/Source/cmFileCopier.h b/Source/cmFileCopier.h index 217d58d..ee9872d 100644 --- a/Source/cmFileCopier.h +++ b/Source/cmFileCopier.h @@ -67,8 +67,9 @@ protected: bool InstallSymlinkChain(std::string& fromFile, std::string& toFile); bool InstallSymlink(const std::string& fromFile, const std::string& toFile); - bool InstallFile(const std::string& fromFile, const std::string& toFile, - MatchProperties match_properties); + virtual bool InstallFile(const std::string& fromFile, + const std::string& toFile, + MatchProperties match_properties); bool InstallDirectory(const std::string& source, const std::string& destination, MatchProperties match_properties); diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx index c89be96..0d8ba2d 100644 --- a/Source/cmFileInstaller.cxx +++ b/Source/cmFileInstaller.cxx @@ -3,7 +3,12 @@ #include "cmFileInstaller.h" +#include <map> #include <sstream> +#include <utility> + +#include <cm/string_view> +#include <cmext/string_view> #include "cm_sys_stat.h" @@ -18,6 +23,7 @@ using namespace cmFSPermissions; cmFileInstaller::cmFileInstaller(cmExecutionStatus& status) : cmFileCopier(status, "INSTALL") , InstallType(cmInstallType_FILES) + , InstallMode(cmInstallMode::COPY) , Optional(false) , MessageAlways(false) , MessageLazy(false) @@ -82,6 +88,93 @@ bool cmFileInstaller::Install(const std::string& fromFile, return this->cmFileCopier::Install(fromFile, toFile); } +bool cmFileInstaller::InstallFile(const std::string& fromFile, + const std::string& toFile, + MatchProperties match_properties) +{ + if (this->InstallMode == cmInstallMode::COPY) { + return this->cmFileCopier::InstallFile(fromFile, toFile, match_properties); + } + + std::string newFromFile; + + if (this->InstallMode == cmInstallMode::REL_SYMLINK || + this->InstallMode == cmInstallMode::REL_SYMLINK_OR_COPY || + this->InstallMode == cmInstallMode::SYMLINK || + this->InstallMode == cmInstallMode::SYMLINK_OR_COPY) { + // Try to get a relative path. + std::string toDir = cmSystemTools::GetParentDirectory(toFile); + newFromFile = cmSystemTools::ForceToRelativePath(toDir, fromFile); + + // Double check that we can restore the original path. + std::string reassembled = + cmSystemTools::CollapseFullPath(newFromFile, toDir); + if (!cmSystemTools::ComparePath(reassembled, fromFile)) { + if (this->InstallMode == cmInstallMode::SYMLINK || + this->InstallMode == cmInstallMode::SYMLINK_OR_COPY) { + // User does not mind, silently proceed with absolute path. + newFromFile = fromFile; + } else if (this->InstallMode == cmInstallMode::REL_SYMLINK_OR_COPY) { + // User expects a relative symbolic link or a copy. + // Since an absolute symlink won't do, copy instead. + return this->cmFileCopier::InstallFile(fromFile, toFile, + match_properties); + } else { + // We cannot meet user's expectation (REL_SYMLINK) + auto e = cmStrCat(this->Name, + " cannot determine relative path for symlink to \"", + newFromFile, "\" at \"", toFile, "\"."); + this->Status.SetError(e); + return false; + } + } + } else { + newFromFile = fromFile; // stick with absolute path + } + + // Compare the symlink value to that at the destination if not + // always installing. + bool copy = true; + if (!this->Always) { + std::string oldSymlinkTarget; + if (cmSystemTools::ReadSymlink(toFile, oldSymlinkTarget)) { + if (newFromFile == oldSymlinkTarget) { + copy = false; + } + } + } + + // Inform the user about this file installation. + this->ReportCopy(toFile, TypeLink, copy); + + if (copy) { + // Remove the destination file so we can always create the symlink. + cmSystemTools::RemoveFile(toFile); + + // Create destination directory if it doesn't exist + cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile)); + + // Create the symlink. + if (!cmSystemTools::CreateSymlink(newFromFile, toFile)) { + if (this->InstallMode == cmInstallMode::ABS_SYMLINK_OR_COPY || + this->InstallMode == cmInstallMode::REL_SYMLINK_OR_COPY || + this->InstallMode == cmInstallMode::SYMLINK_OR_COPY) { + // Failed to create a symbolic link, fall back to copying. + return this->cmFileCopier::InstallFile(newFromFile, toFile, + match_properties); + } + + auto e = cmStrCat(this->Name, " cannot create symlink to \"", + newFromFile, "\" at \"", toFile, + "\": ", cmSystemTools::GetLastSystemError(), "\"."); + this->Status.SetError(e); + return false; + } + } + + return true; +} + void cmFileInstaller::DefaultFilePermissions() { this->cmFileCopier::DefaultFilePermissions(); @@ -141,6 +234,31 @@ bool cmFileInstaller::Parse(std::vector<std::string> const& args) return false; } + static const std::map<cm::string_view, cmInstallMode> install_mode_dict{ + { "ABS_SYMLINK"_s, cmInstallMode::ABS_SYMLINK }, + { "ABS_SYMLINK_OR_COPY"_s, cmInstallMode::ABS_SYMLINK_OR_COPY }, + { "REL_SYMLINK"_s, cmInstallMode::REL_SYMLINK }, + { "REL_SYMLINK_OR_COPY"_s, cmInstallMode::REL_SYMLINK_OR_COPY }, + { "SYMLINK"_s, cmInstallMode::SYMLINK }, + { "SYMLINK_OR_COPY"_s, cmInstallMode::SYMLINK_OR_COPY } + }; + + std::string install_mode; + cmSystemTools::GetEnv("CMAKE_INSTALL_MODE", install_mode); + if (install_mode.empty() || install_mode == "COPY"_s) { + this->InstallMode = cmInstallMode::COPY; + } else { + auto it = install_mode_dict.find(install_mode); + if (it != install_mode_dict.end()) { + this->InstallMode = it->second; + } else { + auto e = cmStrCat("Unrecognized value '", install_mode, + "' for environment variable CMAKE_INSTALL_MODE"); + this->Status.SetError(e); + return false; + } + } + return true; } diff --git a/Source/cmFileInstaller.h b/Source/cmFileInstaller.h index 3a905d3..3f6bd45 100644 --- a/Source/cmFileInstaller.h +++ b/Source/cmFileInstaller.h @@ -8,6 +8,7 @@ #include <vector> #include "cmFileCopier.h" +#include "cmInstallMode.h" #include "cmInstallType.h" class cmExecutionStatus; @@ -19,6 +20,7 @@ struct cmFileInstaller : public cmFileCopier protected: cmInstallType InstallType; + cmInstallMode InstallMode; bool Optional; bool MessageAlways; bool MessageLazy; @@ -35,7 +37,8 @@ protected: bool ReportMissing(const std::string& fromFile) override; bool Install(const std::string& fromFile, const std::string& toFile) override; - + bool InstallFile(const std::string& fromFile, const std::string& toFile, + MatchProperties match_properties) override; bool Parse(std::vector<std::string> const& args) override; enum { diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index 1038ac2..f4e1763 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -311,7 +311,7 @@ bool cmFindBase::CheckForVariableDefined() if (cached && cacheType != cmStateEnums::UNINITIALIZED) { this->VariableType = cacheType; - if (const auto* hs = + if (const auto& hs = state->GetCacheEntryProperty(this->VariableName, "HELPSTRING")) { this->VariableDocumentation = *hs; } @@ -336,7 +336,7 @@ void cmFindBase::NormalizeFindResult() if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0125) == cmPolicies::NEW) { // ensure the path returned by find_* command is absolute - const auto* existingValue = + const auto& existingValue = this->Makefile->GetDefinition(this->VariableName); std::string value; if (!existingValue->empty()) { diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index 0cbe637..ef960d1 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -259,6 +259,34 @@ struct cmFindLibraryHelper }; }; +namespace { + +std::string const& get_prefixes(cmMakefile* mf) +{ +#ifdef _WIN32 + static std::string defaultPrefix = ";lib"; +#else + static std::string defaultPrefix = "lib"; +#endif + cmProp prefixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_PREFIXES"); + return (prefixProp) ? *prefixProp : defaultPrefix; +} + +std::string const& get_suffixes(cmMakefile* mf) +{ +#ifdef _WIN32 + static std::string defaultSuffix = ".lib;.dll.a;.a"; +#elif defined(__APPLE__) + static std::string defaultSuffix = ".tbd;.dylib;.so;.a"; +#elif defined(__hpux) + static std::string defaultSuffix = ".sl;.so;.a"; +#else + static std::string defaultSuffix = ".so;.a"; +#endif + cmProp suffixProp = mf->GetDefinition("CMAKE_FIND_LIBRARY_SUFFIXES"); + return (suffixProp) ? *suffixProp : defaultSuffix; +} +} cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf, cmFindBase const* base) : Makefile(mf) @@ -268,10 +296,9 @@ cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf, this->GG = this->Makefile->GetGlobalGenerator(); // Collect the list of library name prefixes/suffixes to try. - std::string const& prefixes_list = - this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_PREFIXES"); - std::string const& suffixes_list = - this->Makefile->GetRequiredDefinition("CMAKE_FIND_LIBRARY_SUFFIXES"); + std::string const& prefixes_list = get_prefixes(this->Makefile); + std::string const& suffixes_list = get_suffixes(this->Makefile); + cmExpandList(prefixes_list, this->Prefixes, true); cmExpandList(suffixes_list, this->Suffixes, true); this->RegexFromList(this->PrefixRegexStr, this->Prefixes); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index fba736e..a0de74c 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -478,17 +478,35 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) this->VersionMaxPatch, this->VersionMaxTweak); } + const std::string makePackageRequiredVar = + cmStrCat("CMAKE_REQUIRE_FIND_PACKAGE_", this->Name); + const bool makePackageRequiredSet = + this->Makefile->IsOn(makePackageRequiredVar); + if (makePackageRequiredSet) { + if (this->Required) { + this->Makefile->IssueMessage( + MessageType::WARNING, + cmStrCat("for module ", this->Name, + " already called with REQUIRED, thus ", + makePackageRequiredVar, " has no effect.")); + } else { + this->Required = true; + } + } + std::string disableFindPackageVar = cmStrCat("CMAKE_DISABLE_FIND_PACKAGE_", this->Name); if (this->Makefile->IsOn(disableFindPackageVar)) { if (this->Required) { this->SetError( - cmStrCat("for module ", this->Name, " called with REQUIRED, but ", - disableFindPackageVar, + cmStrCat("for module ", this->Name, + (makePackageRequiredSet + ? " was made REQUIRED with " + makePackageRequiredVar + : " called with REQUIRED, "), + " but ", disableFindPackageVar, " is enabled. A REQUIRED package cannot be disabled.")); return false; } - return true; } diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 4845a6d..b44f797 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -27,6 +27,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" diff --git a/Source/cmFortranParser.h b/Source/cmFortranParser.h index 1b14d17..70fe537 100644 --- a/Source/cmFortranParser.h +++ b/Source/cmFortranParser.h @@ -40,6 +40,8 @@ int cmFortranParser_GetOldStartcond(cmFortranParser* parser); /* Callbacks for parser. */ void cmFortranParser_Error(cmFortranParser* parser, const char* message); void cmFortranParser_RuleUse(cmFortranParser* parser, const char* module_name); +void cmFortranParser_RuleUseIntrinsic(cmFortranParser* parser, + const char* module_name); void cmFortranParser_RuleLineDirective(cmFortranParser* parser, const char* filename); void cmFortranParser_RuleInclude(cmFortranParser* parser, const char* name); @@ -99,6 +101,9 @@ public: std::set<std::string> Provides; std::set<std::string> Requires; + // Set of intrinsic modules. + std::set<std::string> Intrinsics; + // Set of files included in the translation unit. std::set<std::string> Includes; }; diff --git a/Source/cmFortranParserImpl.cxx b/Source/cmFortranParserImpl.cxx index 054a2a9..efcc5bb 100644 --- a/Source/cmFortranParserImpl.cxx +++ b/Source/cmFortranParserImpl.cxx @@ -197,6 +197,19 @@ void cmFortranParser_RuleUse(cmFortranParser* parser, const char* module_name) parser->Info.Requires.insert(parser->ModName(mod_name)); } +void cmFortranParser_RuleUseIntrinsic(cmFortranParser* parser, + const char* module_name) +{ + if (parser->InPPFalseBranch) { + return; + } + + // syntax: "use, intrinsic:: module_name" + // requires: "module_name.mod" + std::string const& mod_name = cmSystemTools::LowerCase(module_name); + parser->Info.Intrinsics.insert(parser->ModName(mod_name)); +} + void cmFortranParser_RuleLineDirective(cmFortranParser* parser, const char* filename) { diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 217ebe5..3e90ead 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1777,7 +1777,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode testedFeatures[lang].push_back(p); if (availableFeatures.find(lang) == availableFeatures.end()) { - const char* featuresKnown = + cmProp featuresKnown = standardResolver.CompileFeaturesAvailable(lang, &error); if (!featuresKnown) { reportError(context, content->GetOriginalExpression(), error); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f1ef130..4208689 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -62,7 +62,7 @@ cmProp cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( cmGeneratorTarget const* tgt, cmMessenger* /* messenger */, cmListFileBacktrace const& /* context */) { - return &tgt->GetSourcesProperty(); + return tgt->GetSourcesProperty(); } template <> @@ -332,7 +332,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) cmGeneratorTarget::~cmGeneratorTarget() = default; -const std::string& cmGeneratorTarget::GetSourcesProperty() const +cmProp cmGeneratorTarget::GetSourcesProperty() const { std::vector<std::string> values; for (auto const& se : this->SourceEntries) { @@ -341,7 +341,7 @@ const std::string& cmGeneratorTarget::GetSourcesProperty() const static std::string value; value.clear(); value = cmJoin(values, ";"); - return value; + return cmProp(value); } cmGlobalGenerator* cmGeneratorTarget::GetGlobalGenerator() const @@ -396,13 +396,7 @@ cmProp cmGeneratorTarget::GetProperty(const std::string& prop) const std::string const& cmGeneratorTarget::GetSafeProperty( std::string const& prop) const { - cmProp ret = this->GetProperty(prop); - if (ret) { - return *ret; - } - - static std::string const s_empty; - return s_empty; + return this->GetProperty(prop); } const char* cmGeneratorTarget::GetOutputTargetType( @@ -564,7 +558,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const // framework postfix. frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config); if (!frameworkPostfix.empty()) { - postfix = &frameworkPostfix; + postfix = cmProp(frameworkPostfix); } } return postfix ? *postfix : std::string(); @@ -966,7 +960,7 @@ cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang, this->GetLanguageStandardProperty(lang, config); if (languageStandard) { - return &(languageStandard->Value); + return cmProp(languageStandard->Value); } return nullptr; @@ -2142,7 +2136,6 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const return true; } -#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER) // Enable if the rpath flag uses a separator and the target uses // binaries we know how to edit. std::string ll = this->GetLinkerLanguage(config); @@ -2155,21 +2148,17 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const // CMAKE_EXECUTABLE_FORMAT. if (cmProp fmt = this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) { -# if defined(CMake_USE_ELF_PARSER) if (*fmt == "ELF") { return true; } -# endif -# if defined(CMake_USE_XCOFF_PARSER) +#if defined(CMake_USE_XCOFF_PARSER) if (*fmt == "XCOFF") { return true; } -# endif +#endif } } } -#endif - static_cast<void>(config); return false; } @@ -4466,6 +4455,13 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( // Last step: replace "LINKER:" prefixed elements by // actual linker wrapper + return this->ResolveLinkerWrapper(result, language); +} + +std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( + std::vector<BT<std::string>>& result, const std::string& language) const +{ + // replace "LINKER:" prefixed elements by actual linker wrapper const std::string wrapper(this->Makefile->GetSafeDefinition( "CMAKE_" + language + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG" @@ -5119,13 +5115,13 @@ void cmGeneratorTarget::GetFullNameInternal( if (this->IsFrameworkOnApple()) { fw_prefix = cmStrCat(this->GetFrameworkDirectory(config, ContentLevel), '/'); - targetPrefix = &fw_prefix; + targetPrefix = cmProp(fw_prefix); targetSuffix = nullptr; } if (this->IsCFBundleOnApple()) { fw_prefix = cmStrCat(this->GetCFBundleDirectory(config, FullLevel), '/'); - targetPrefix = &fw_prefix; + targetPrefix = cmProp(fw_prefix); targetSuffix = nullptr; } @@ -5141,7 +5137,7 @@ void cmGeneratorTarget::GetFullNameInternal( // EXECUTABLE_SUFFIX attribute. if (this->IsFrameworkOnApple() && this->GetGlobalGenerator()->GetName() == "Xcode") { - targetSuffix = &configPostfix; + targetSuffix = cmProp(configPostfix); } else { outBase += configPostfix; } @@ -5672,6 +5668,11 @@ std::string valueAsString<std::string>(std::string value) return value; } template <> +std::string valueAsString<cmProp>(cmProp value) +{ + return value ? value : std::string("(unset)"); +} +template <> std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/) { return "(unset)"; @@ -5747,7 +5748,7 @@ std::string getTypedProperty<std::string>( cmProp value = tgt->GetProperty(prop); if (genexInterpreter == nullptr) { - return valueAsString(cmToCStr(value)); + return valueAsString(value); } return genexInterpreter->Evaluate(value ? *value : "", prop); @@ -6175,6 +6176,14 @@ std::string cmGeneratorTarget::GetFortranModuleDirectory( return this->FortranModuleDirectory; } +bool cmGeneratorTarget::IsFortranBuildingInstrinsicModules() const +{ + if (cmProp prop = this->GetProperty("Fortran_BUILDING_INSTRINSIC_MODULES")) { + return cmIsOn(*prop); + } + return false; +} + std::string cmGeneratorTarget::CreateFortranModuleDirectory( std::string const& working_dir) const { @@ -6362,12 +6371,12 @@ cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( return maybeItem; } -void cmGeneratorTarget::ExpandLinkItems( - std::string const& prop, std::string const& value, std::string const& config, - cmGeneratorTarget const* headTarget, bool usage_requirements_only, - std::vector<cmLinkItem>& items, std::vector<cmLinkItem>& objects, - bool& hadHeadSensitiveCondition, bool& hadContextSensitiveCondition, - bool& hadLinkLanguageSensitiveCondition) const +void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, + std::string const& value, + std::string const& config, + cmGeneratorTarget const* headTarget, + bool usage_requirements_only, + cmLinkInterface& iface) const { // Keep this logic in sync with ComputeLinkImplementationLibraries. cmGeneratorExpression ge; @@ -6389,24 +6398,27 @@ void cmGeneratorTarget::ExpandLinkItems( for (std::string const& lib : libs) { if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem(lib, cge->GetBacktrace(), &scope)) { - if (!maybeItem->Target) { + cmLinkItem item = std::move(*maybeItem); + + if (!item.Target) { // Report explicitly linked object files separately. - std::string const& maybeObj = maybeItem->AsStr(); + std::string const& maybeObj = item.AsStr(); if (cmSystemTools::FileIsFullPath(maybeObj)) { cmSourceFile const* sf = mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { - objects.emplace_back(std::move(*maybeItem)); + iface.Objects.emplace_back(std::move(item)); continue; } } } - items.emplace_back(std::move(*maybeItem)); + + iface.Libraries.emplace_back(std::move(item)); } } - hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); - hadContextSensitiveCondition = cge->GetHadContextSensitiveCondition(); - hadLinkLanguageSensitiveCondition = + iface.HadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); + iface.HadContextSensitiveCondition = cge->GetHadContextSensitiveCondition(); + iface.HadLinkLanguageSensitiveCondition = cge->GetHadLinkLanguageSensitiveCondition(); } @@ -6903,23 +6915,20 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( return; } iface.Exists = true; + + // If CMP0022 is NEW then the plain tll signature sets the + // INTERFACE_LINK_LIBRARIES property. Even if the project + // clears it, the link interface is still explicit. iface.Explicit = cmp0022NEW || explicitLibraries; if (explicitLibraries) { // The interface libraries have been explicitly set. this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config, - headTarget, usage_requirements_only, iface.Libraries, - iface.Objects, iface.HadHeadSensitiveCondition, - iface.HadContextSensitiveCondition, - iface.HadLinkLanguageSensitiveCondition); - return; + headTarget, usage_requirements_only, iface); } - // 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 - // to the link implementation. - if (cmp0022NEW) { + // If the link interface is explicit, do not fall back to the link impl. + if (iface.Explicit) { return; } @@ -6932,22 +6941,15 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( !this->PolicyWarnedCMP0022 && !usage_requirements_only) { // Compare the link implementation fallback link interface to the // preferred new link interface property and warn if different. - std::vector<cmLinkItem> ifaceLibs; - std::vector<cmLinkItem> ifaceObjects; + cmLinkInterface ifaceNew; static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; if (cmProp newExplicitLibraries = this->GetProperty(newProp)) { - bool hadHeadSensitiveConditionDummy = false; - bool hadContextSensitiveConditionDummy = false; - bool hadLinkLanguageSensitiveConditionDummy = false; this->ExpandLinkItems(newProp, *newExplicitLibraries, config, - headTarget, usage_requirements_only, ifaceLibs, - ifaceObjects, hadHeadSensitiveConditionDummy, - hadContextSensitiveConditionDummy, - hadLinkLanguageSensitiveConditionDummy); + headTarget, usage_requirements_only, ifaceNew); } - if (ifaceLibs != iface.Libraries) { + if (ifaceNew.Libraries != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); - std::string newLibraries = cmJoin(ifaceLibs, ";"); + std::string newLibraries = cmJoin(ifaceNew.Libraries, ";"); if (oldLibraries.empty()) { oldLibraries = "(empty)"; } @@ -7085,10 +7087,7 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( iface.Multiplicity = info->Multiplicity; cmExpandList(info->Languages, iface.Languages); this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, - headTarget, usage_requirements_only, iface.Libraries, - iface.Objects, iface.HadHeadSensitiveCondition, - iface.HadContextSensitiveCondition, - iface.HadLinkLanguageSensitiveCondition); + headTarget, usage_requirements_only, iface); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); LookupLinkItemScope scope{ this->LocalGenerator }; for (std::string const& dep : deps) { @@ -7628,6 +7627,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( std::string const& evaluated = cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, this->LinkerLanguage); + bool const fromGenex = evaluated != *le; cmExpandList(evaluated, llibs); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; @@ -7699,7 +7699,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } } - impl.Libraries.emplace_back(std::move(item), evaluated != *le); + impl.Libraries.emplace_back(std::move(item), fromGenex); } std::set<std::string> const& seenProps = cge->GetSeenTargetProperties(); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 6d2aa85..fb1b2e6 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -498,6 +498,9 @@ public: std::vector<BT<std::string>> GetLinkOptions( std::string const& config, std::string const& language) const; + std::vector<BT<std::string>>& ResolveLinkerWrapper( + std::vector<BT<std::string>>& result, const std::string& language) const; + void GetStaticLibraryLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const; @@ -832,8 +835,9 @@ public: std::string const& config) const; std::string GetFortranModuleDirectory(std::string const& working_dir) const; + bool IsFortranBuildingInstrinsicModules() const; - const std::string& GetSourcesProperty() const; + cmProp GetSourcesProperty() const; void AddISPCGeneratedHeader(std::string const& header, std::string const& config); @@ -1037,11 +1041,8 @@ private: std::string const& config, const cmGeneratorTarget* headTarget, bool usage_requirements_only, - std::vector<cmLinkItem>& items, - std::vector<cmLinkItem>& objects, - bool& hadHeadSensitiveCondition, - bool& hadContextSensitiveCondition, - bool& hadLinkLanguageSensitiveCondition) const; + cmLinkInterface& iface) const; + struct LookupLinkItemScope { cmLocalGenerator const* LG; diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index cb657f9..bb3a40b 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -268,6 +268,11 @@ bool StoreResult(OutType infoType, cmMakefile& makefile, } return true; } +bool StoreResult(OutType infoType, cmMakefile& makefile, + const std::string& variable, cmProp value) +{ + return StoreResult(infoType, makefile, variable, value.GetCStr()); +} bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name, OutType infoType, const std::string& variable, @@ -280,9 +285,8 @@ bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name, // Get the property. cmake* cm = status.GetMakefile().GetCMakeInstance(); - return StoreResult( - infoType, status.GetMakefile(), variable, - cmToCStr(cm->GetState()->GetGlobalProperty(propertyName))); + return StoreResult(infoType, status.GetMakefile(), variable, + cm->GetState()->GetGlobalProperty(propertyName)); } bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, @@ -329,7 +333,7 @@ bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, // Get the property. return StoreResult(infoType, status.GetMakefile(), variable, - cmToCStr(mf->GetProperty(propertyName))); + mf->GetProperty(propertyName)); } bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, @@ -365,8 +369,7 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, if (!prop) { prop = target->GetProperty(propertyName); } - return StoreResult(infoType, status.GetMakefile(), variable, - cmToCStr(prop)); + return StoreResult(infoType, status.GetMakefile(), variable, prop); } status.SetError(cmStrCat("could not find TARGET ", name, ". Perhaps it has not yet been created.")); @@ -391,7 +394,7 @@ bool HandleSourceMode(cmExecutionStatus& status, const std::string& name, if (cmSourceFile* sf = directory_makefile.GetOrCreateSource(source_file_absolute_path)) { return StoreResult(infoType, status.GetMakefile(), variable, - cmToCStr(sf->GetPropertyForUser(propertyName))); + sf->GetPropertyForUser(propertyName)); } status.SetError( cmStrCat("given SOURCE name that could not be found or created: ", @@ -447,7 +450,7 @@ bool HandleCacheMode(cmExecutionStatus& status, const std::string& name, value = status.GetMakefile().GetState()->GetCacheEntryProperty( name, propertyName); } - StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(value)); + StoreResult(infoType, status.GetMakefile(), variable, value); return true; } diff --git a/Source/cmGetTestPropertyCommand.cxx b/Source/cmGetTestPropertyCommand.cxx index cf8c1d5..077353e 100644 --- a/Source/cmGetTestPropertyCommand.cxx +++ b/Source/cmGetTestPropertyCommand.cxx @@ -4,6 +4,7 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmTest.h" bool cmGetTestPropertyCommand(std::vector<std::string> const& args, @@ -19,12 +20,12 @@ bool cmGetTestPropertyCommand(std::vector<std::string> const& args, cmMakefile& mf = status.GetMakefile(); cmTest* test = mf.GetTest(testName); if (test) { - const char* prop = nullptr; + cmProp prop; if (!args[1].empty()) { prop = test->GetProperty(args[1]); } if (prop) { - mf.AddDefinition(var, prop); + mf.AddDefinition(var, prop->c_str()); return true; } } diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 32238e4..12fd9c4 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -376,7 +376,7 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( #ifdef _WIN32 std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%"; #else - std::string check_error = "if [[ $? -ne 0 ]]; then exit 1; fi"; + std::string check_error = "if [ $? -ne 0 ]; then exit 1; fi"; #endif #ifdef _WIN32 diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx index 9e5bbca..a8e0f23 100644 --- a/Source/cmGlobalCommonGenerator.cxx +++ b/Source/cmGlobalCommonGenerator.cxx @@ -16,8 +16,8 @@ #include "cmStateSnapshot.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" - -class cmake; +#include "cmSystemTools.h" +#include "cmake.h" cmGlobalCommonGenerator::cmGlobalCommonGenerator(cmake* cm) : cmGlobalGenerator(cm) @@ -95,3 +95,33 @@ bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig( } return !t.ExcludedFromAllInConfigs.empty(); } + +std::string cmGlobalCommonGenerator::GetEditCacheCommand() const +{ + // If generating for an extra IDE, the edit_cache target cannot + // launch a terminal-interactive tool, so always use cmake-gui. + if (!this->GetExtraGeneratorName().empty()) { + return cmSystemTools::GetCMakeGUICommand(); + } + + // Use an internal cache entry to track the latest dialog used + // to edit the cache, and use that for the edit_cache target. + cmake* cm = this->GetCMakeInstance(); + std::string editCacheCommand = cm->GetCMakeEditCommand(); + if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") || + !editCacheCommand.empty()) { + if (this->SupportsDirectConsole() && editCacheCommand.empty()) { + editCacheCommand = cmSystemTools::GetCMakeCursesCommand(); + } + if (editCacheCommand.empty()) { + editCacheCommand = cmSystemTools::GetCMakeGUICommand(); + } + if (!editCacheCommand.empty()) { + cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(), + "Path to cache edit program executable.", + cmStateEnums::INTERNAL); + } + } + cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND"); + return edit_cmd ? *edit_cmd : std::string(); +} diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h index 2aa9d27..fed9ce8 100644 --- a/Source/cmGlobalCommonGenerator.h +++ b/Source/cmGlobalCommonGenerator.h @@ -42,4 +42,9 @@ public: std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const; bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t, const std::string& config); + +protected: + virtual bool SupportsDirectConsole() const { return true; } + const char* GetEditCacheTargetName() const override { return "edit_cache"; } + std::string GetEditCacheCommand() const override; }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 9193778..3561deb 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -242,7 +242,7 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang, std::vector<std::string> cnameArgVec; if (cname && !cname->empty()) { cmExpandList(*cname, cnameArgVec); - cname = &cnameArgVec.front(); + cname = cmProp(cnameArgVec.front()); } std::string changeVars; @@ -498,6 +498,18 @@ bool cmGlobalGenerator::CheckLanguages( void cmGlobalGenerator::EnableLanguage( std::vector<std::string> const& languages, cmMakefile* mf, bool optional) { + if (!this->IsMultiConfig()) { + std::string envBuildType; + if (!mf->GetDefinition("CMAKE_BUILD_TYPE") && + cmSystemTools::GetEnv("CMAKE_BUILD_TYPE", envBuildType)) { + mf->AddCacheDefinition( + "CMAKE_BUILD_TYPE", envBuildType, + "Choose the type of build. Options include: empty, " + "Debug, Release, RelWithDebInfo, MinSizeRel.", + cmStateEnums::STRING); + } + } + if (languages.empty()) { cmSystemTools::Error("EnableLanguage must have a lang specified!"); cmSystemTools::SetFatalErrorOccured(); @@ -1167,10 +1179,10 @@ void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l, } } -const char* cmGlobalGenerator::GetGlobalSetting(std::string const& name) const +cmProp cmGlobalGenerator::GetGlobalSetting(std::string const& name) const { assert(!this->Makefiles.empty()); - return cmToCStr(this->Makefiles[0]->GetDefinition(name)); + return this->Makefiles[0]->GetDefinition(name); } bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const @@ -1183,7 +1195,7 @@ std::string cmGlobalGenerator::GetSafeGlobalSetting( std::string const& name) const { assert(!this->Makefiles.empty()); - return this->Makefiles[0]->GetSafeDefinition(name); + return this->Makefiles[0]->GetDefinition(name); } bool cmGlobalGenerator::IgnoreFile(const char* ext) const @@ -1251,10 +1263,8 @@ void cmGlobalGenerator::Configure() this->CreateDefaultGlobalTargets(globalTargets); for (const auto& mf : this->Makefiles) { - auto& targets = mf->GetTargets(); for (GlobalTargetInfo const& globalTarget : globalTargets) { - targets.emplace(globalTarget.Name, - this->CreateGlobalTarget(globalTarget, mf.get())); + this->CreateGlobalTarget(globalTarget, mf.get()); } } } @@ -1771,9 +1781,8 @@ void cmGlobalGenerator::CreateGeneratorTargets( std::map<cmTarget*, cmGeneratorTarget*> const& importedMap) { if (targetTypes == AllTargets) { - for (auto& target : mf->GetTargets()) { - cmTarget* t = &target.second; - lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(t, lg)); + for (cmTarget* target : mf->GetOrderedTargets()) { + lg->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(target, lg)); } } @@ -2740,7 +2749,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( singleLine.push_back(cfgArg); cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)"; } else { - cfgArg += cmToCStr(mf->GetDefinition("CMAKE_CFG_INTDIR")); + cfgArg += *mf->GetDefinition("CMAKE_CFG_INTDIR"); } singleLine.push_back(cfgArg); } @@ -2812,12 +2821,19 @@ bool cmGlobalGenerator::UseFolderProperty() const return false; } -cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, - cmMakefile* mf) +void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, + cmMakefile* mf) { // Package - cmTarget target(gti.Name, cmStateEnums::GLOBAL_TARGET, - cmTarget::VisibilityNormal, mf, gti.PerConfig); + auto tb = + mf->CreateNewTarget(gti.Name, cmStateEnums::GLOBAL_TARGET, gti.PerConfig); + + // Do nothing if gti.Name is already used + if (!tb.second) { + return; + } + + cmTarget& target = tb.first; target.SetProperty("EXCLUDE_FROM_ALL", "TRUE"); std::vector<std::string> no_outputs; @@ -2841,8 +2857,6 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, if (this->UseFolderProperty()) { target.SetProperty("FOLDER", this->GetPredefinedTargetsFolder()); } - - return target; } std::string cmGlobalGenerator::GenerateRuleFile( diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 147146e..34646d9 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -23,6 +23,7 @@ #include "cmCustomCommandLines.h" #include "cmDuration.h" #include "cmExportSet.h" +#include "cmProperty.h" #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -308,7 +309,7 @@ public: cmExportSetMap& GetExportSets() { return this->ExportSets; } - const char* GetGlobalSetting(std::string const& name) const; + cmProp GetGlobalSetting(std::string const& name) const; bool GlobalSettingIsOn(std::string const& name) const; std::string GetSafeGlobalSetting(std::string const& name) const; @@ -596,7 +597,7 @@ protected: void AddGlobalTarget_RebuildCache( std::vector<GlobalTargetInfo>& targets) const; void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets); - cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf); + void CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf); std::string FindMakeProgramFile; std::string ConfiguredFilesPath; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 7cf3e93..b81f82e 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -186,8 +186,7 @@ void cmGlobalGhsMultiGenerator::EnableLanguage( mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files - const char* tgtPlatform = - cmToCStrSafe(mf->GetDefinition("GHS_TARGET_PLATFORM")); + const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM")->c_str(); if (!tgtPlatform) { cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not " "specified; defaulting to \"integrity\""); diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 963118f..47a931d 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -382,7 +382,7 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( if (restat) { vars["restat"] = "1"; } - if (uses_terminal && this->SupportsConsolePool()) { + if (uses_terminal && this->SupportsDirectConsole()) { vars["pool"] = "console"; } else if (!job_pool.empty()) { vars["pool"] = job_pool; @@ -920,14 +920,7 @@ void cmGlobalNinjaGenerator::EnableLanguage( std::vector<std::string> const& langs, cmMakefile* mf, bool optional) { if (this->IsMultiConfig()) { - if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { - mf->AddCacheDefinition( - "CMAKE_CONFIGURATION_TYPES", "Debug;Release;RelWithDebInfo", - "Semicolon separated list of supported configuration types, only " - "supports Debug, Release, MinSizeRel, and RelWithDebInfo, anything " - "else will be ignored", - cmStateEnums::STRING); - } + mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;RelWithDebInfo"); } this->cmGlobalGenerator::EnableLanguage(langs, mf, optional); @@ -1019,13 +1012,6 @@ bool cmGlobalNinjaGenerator::HasRule(const std::string& name) // Private virtual overrides -std::string cmGlobalNinjaGenerator::GetEditCacheCommand() const -{ - // Ninja by design does not run interactive tools in the terminal, - // so our only choice is cmake-gui. - return cmSystemTools::GetCMakeGUICommand(); -} - void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory( cmGeneratorTarget* gt) const { @@ -1847,7 +1833,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) // Use 'console' pool to get non buffered output of the CMake re-run call // Available since Ninja 1.5 - if (this->SupportsConsolePool()) { + if (this->SupportsDirectConsole()) { reBuild.Variables["pool"] = "console"; } @@ -1941,7 +1927,7 @@ std::string cmGlobalNinjaGenerator::NinjaCmd() const return "ninja"; } -bool cmGlobalNinjaGenerator::SupportsConsolePool() const +bool cmGlobalNinjaGenerator::SupportsDirectConsole() const { return this->NinjaSupportsConsolePool; } diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index bb4ce2b..ec73475 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -220,7 +220,6 @@ public: { return "package_source"; } - const char* GetEditCacheTargetName() const override { return "edit_cache"; } const char* GetRebuildCacheTargetName() const override { return "rebuild_cache"; @@ -406,7 +405,7 @@ public: return "1.10.2"; } static std::string RequiredNinjaVersionForCodePage() { return "1.11"; } - bool SupportsConsolePool() const; + bool SupportsDirectConsole() const override; bool SupportsImplicitOuts() const; bool SupportsManifestRestat() const; bool SupportsMultilineDepfile() const; @@ -489,7 +488,6 @@ protected: std::string DefaultFileConfig; private: - std::string GetEditCacheCommand() const override; bool FindMakeProgram(cmMakefile* mf) override; void CheckNinjaFeatures(); void CheckNinjaCodePage(); diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 9c3de1e..d9f94a1 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -78,36 +78,6 @@ void cmGlobalUnixMakefileGenerator3::GetDocumentation( entry.Brief = "Generates standard UNIX makefiles."; } -std::string cmGlobalUnixMakefileGenerator3::GetEditCacheCommand() const -{ - // If generating for an extra IDE, the edit_cache target cannot - // launch a terminal-interactive tool, so always use cmake-gui. - if (!this->GetExtraGeneratorName().empty()) { - return cmSystemTools::GetCMakeGUICommand(); - } - - // Use an internal cache entry to track the latest dialog used - // to edit the cache, and use that for the edit_cache target. - cmake* cm = this->GetCMakeInstance(); - std::string editCacheCommand = cm->GetCMakeEditCommand(); - if (!cm->GetCacheDefinition("CMAKE_EDIT_COMMAND") || - !editCacheCommand.empty()) { - if (editCacheCommand.empty()) { - editCacheCommand = cmSystemTools::GetCMakeCursesCommand(); - } - if (editCacheCommand.empty()) { - editCacheCommand = cmSystemTools::GetCMakeGUICommand(); - } - if (!editCacheCommand.empty()) { - cm->AddCacheEntry("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(), - "Path to cache edit program executable.", - cmStateEnums::INTERNAL); - } - } - cmProp edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND"); - return edit_cmd ? *edit_cmd : std::string(); -} - void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory( cmGeneratorTarget* gt) const { diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 7c950cc..94ee476 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -228,7 +228,6 @@ protected: { return "package_source"; } - const char* GetEditCacheTargetName() const override { return "edit_cache"; } const char* GetRebuildCacheTargetName() const override { return "rebuild_cache"; @@ -278,7 +277,6 @@ protected: private: const char* GetBuildIgnoreErrorsFlag() const override { return "-i"; } - std::string GetEditCacheCommand() const override; std::map<cmStateSnapshot, std::set<cmGeneratorTarget const*>, cmStateSnapshot::StrictWeakOrder> diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index fdb7155..488ff2e 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -88,7 +88,7 @@ public: void GetDocumentation(cmDocumentationEntry& entry) const override { entry.Name = std::string(vs10generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2010 project files. " + entry.Brief = "Deprecated. Generates Visual Studio 2010 project files. " "Optional [arch] can be \"Win64\" or \"IA64\"."; } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 0c85a044..34dba1e 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -107,14 +107,7 @@ void cmGlobalVisualStudio7Generator::EnableLanguage( { mf->AddDefinition("CMAKE_GENERATOR_RC", "rc"); mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1"); - if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { - mf->AddCacheDefinition( - "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo", - "Semicolon separated list of supported configuration types, " - "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, " - "anything else will be ignored.", - cmStateEnums::STRING); - } + mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;MinSizeRel;RelWithDebInfo"); // Create list of configurations requested by user's cache, if any. this->cmGlobalVisualStudioGenerator::EnableLanguage(lang, mf, optional); @@ -303,6 +296,25 @@ void cmGlobalVisualStudio7Generator::Generate() this->CallVisualStudioMacro(MacroReload, GetSLNFile(this->LocalGenerators[0].get())); } + + if (this->Version == VS10 && !this->CMakeInstance->GetIsInTryCompile()) { + std::string cmakeWarnVS10; + if (cmProp cached = this->CMakeInstance->GetState()->GetCacheEntryValue( + "CMAKE_WARN_VS10")) { + this->CMakeInstance->MarkCliAsUsed("CMAKE_WARN_VS10"); + cmakeWarnVS10 = *cached; + } else { + cmSystemTools::GetEnv("CMAKE_WARN_VS10", cmakeWarnVS10); + } + if (cmakeWarnVS10.empty() || !cmIsOff(cmakeWarnVS10)) { + this->CMakeInstance->IssueMessage( + MessageType::WARNING, + "The \"Visual Studio 10 2010\" generator is deprecated " + "and will be removed in a future version of CMake." + "\n" + "Add CMAKE_WARN_VS10=OFF to the cache to disable this warning."); + } + } } void cmGlobalVisualStudio7Generator::OutputSLNFile( diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 77403b0..3994816 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -431,14 +431,7 @@ void cmGlobalXCodeGenerator::EnableLanguage( { mf->AddDefinition("XCODE", "1"); mf->AddDefinition("XCODE_VERSION", this->VersionString); - if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { - mf->AddCacheDefinition( - "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo", - "Semicolon separated list of supported configuration types, " - "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, " - "anything else will be ignored.", - cmStateEnums::STRING); - } + mf->InitCMAKE_CONFIGURATION_TYPES("Debug;Release;MinSizeRel;RelWithDebInfo"); mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1"); this->cmGlobalGenerator::EnableLanguage(lang, mf, optional); this->ComputeArchitectures(mf); diff --git a/Source/cmIncludeGuardCommand.cxx b/Source/cmIncludeGuardCommand.cxx index aefd098..d48c823 100644 --- a/Source/cmIncludeGuardCommand.cxx +++ b/Source/cmIncludeGuardCommand.cxx @@ -4,6 +4,7 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 79109b5..687741b 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -36,6 +36,7 @@ #include "cmMessageType.h" #include "cmPolicies.h" #include "cmProperty.h" +#include "cmRange.h" #include "cmRuntimeDependencyArchive.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -681,8 +682,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args, te->LibraryGenerator = libraryGenerator.get(); te->RuntimeGenerator = runtimeGenerator.get(); te->ObjectsGenerator = objectGenerator.get(); - te->InterfaceIncludeDirectories = - cmJoin(includesArgs.GetIncludeDirs(), ";"); + target.AddInstallIncludeDirectories( + cmMakeRange(includesArgs.GetIncludeDirs())); te->NamelinkOnly = namelinkOnly; helper.Makefile->GetGlobalGenerator() ->GetExportSets()[exports] diff --git a/Source/cmInstallMode.h b/Source/cmInstallMode.h new file mode 100644 index 0000000..5343d34 --- /dev/null +++ b/Source/cmInstallMode.h @@ -0,0 +1,17 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +/** + * Enumerate types known to file(INSTALL). + */ +enum class cmInstallMode +{ + COPY, + ABS_SYMLINK, + ABS_SYMLINK_OR_COPY, + REL_SYMLINK, + REL_SYMLINK_OR_COPY, + SYMLINK, + SYMLINK_OR_COPY +}; diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 4f7c959..2e444f2 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -548,7 +548,7 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const } cmListFileContext lfc = this->TopEntry->Context; cmStateSnapshot bottom = this->GetBottom(); - if (!bottom.GetState()->GetIsInTryCompile()) { + if (bottom.GetState()->GetProjectKind() == cmState::ProjectKind::Normal) { lfc.FilePath = cmSystemTools::RelativeIfUnder( bottom.GetState()->GetSourceDirectory(), lfc.FilePath); } @@ -579,7 +579,7 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const out << "Call Stack (most recent call first):\n"; } cmListFileContext lfc = cur->Context; - if (!bottom.GetState()->GetIsInTryCompile()) { + if (bottom.GetState()->GetProjectKind() == cmState::ProjectKind::Normal) { lfc.FilePath = cmSystemTools::RelativeIfUnder( bottom.GetState()->GetSourceDirectory(), lfc.FilePath); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 3b282de..028952a 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -107,10 +107,9 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) { std::vector<std::string> cpath; cmSystemTools::GetPath(cpath, "CPATH"); - for (std::string& cp : cpath) { + for (std::string const& cp : cpath) { if (cmSystemTools::FileIsFullPath(cp)) { - cp = cmSystemTools::CollapseFullPath(cp); - this->EnvCPATH.emplace(std::move(cp)); + this->EnvCPATH.emplace_back(cmSystemTools::CollapseFullPath(cp)); } } } @@ -878,9 +877,12 @@ std::string cmLocalGenerator::GetIncludeFlags( // Support special system include flag if it is available and the // normal flag is repeated for each directory. cmProp sysIncludeFlag = nullptr; + cmProp sysIncludeFlagWarning = nullptr; if (repeatFlag) { sysIncludeFlag = this->Makefile->GetDefinition( cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang)); + sysIncludeFlagWarning = this->Makefile->GetDefinition( + cmStrCat("_CMAKE_INCLUDE_SYSTEM_FLAG_", lang, "_WARNING")); } cmProp fwSearchFlag = this->Makefile->GetDefinition( @@ -889,6 +891,7 @@ std::string cmLocalGenerator::GetIncludeFlags( cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG")); bool flagUsed = false; + bool sysIncludeFlagUsed = false; std::set<std::string> emitted; #ifdef __APPLE__ emitted.insert("/System/Library/Frameworks"); @@ -915,6 +918,7 @@ std::string cmLocalGenerator::GetIncludeFlags( if (sysIncludeFlag && target && target->IsSystemIncludeDirectory(i, config, lang)) { includeFlags << *sysIncludeFlag; + sysIncludeFlagUsed = true; } else { includeFlags << includeFlag; } @@ -931,6 +935,9 @@ std::string cmLocalGenerator::GetIncludeFlags( } includeFlags << sep; } + if (sysIncludeFlagUsed && sysIncludeFlagWarning) { + includeFlags << *sysIncludeFlagWarning; + } std::string flags = includeFlags.str(); // remove trailing separators if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) { @@ -1239,19 +1246,31 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( } } + bool const isCorCxx = (lang == "C" || lang == "CXX"); + + // Resolve symlinks in CPATH for comparison with resolved include paths. + // We do this here instead of when EnvCPATH is populated in case symlinks + // on disk have changed in the meantime. + std::set<std::string> resolvedEnvCPATH; + if (isCorCxx) { + for (std::string const& i : this->EnvCPATH) { + resolvedEnvCPATH.emplace(this->GlobalGenerator->GetRealPath(i)); + } + } + // Checks if this is not an excluded (implicit) include directory. - auto notExcluded = [this, &implicitSet, &implicitExclude, - &lang](std::string const& dir) { - return ( - // Do not exclude directories that are not in an excluded set. - ((!cm::contains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) && - (!cm::contains(implicitExclude, dir))) + auto notExcluded = [this, &implicitSet, &implicitExclude, &resolvedEnvCPATH, + isCorCxx](std::string const& dir) -> bool { + std::string const& real_dir = this->GlobalGenerator->GetRealPath(dir); + return + // Do not exclude directories that are not in any excluded set. + !(cm::contains(implicitSet, real_dir) || + cm::contains(implicitExclude, dir)) // Do not exclude entries of the CPATH environment variable even though // they are implicitly searched by the compiler. They are meant to be // user-specified directories that can be re-ordered or converted to // -isystem without breaking real compiler builtin headers. - || - ((lang == "C" || lang == "CXX") && cm::contains(this->EnvCPATH, dir))); + || (isCorCxx && cm::contains(resolvedEnvCPATH, real_dir)); }; // Get the target-specific include directories. @@ -3039,6 +3058,30 @@ void cmLocalGenerator::AppendPositionIndependentLinkerFlags( } } +bool cmLocalGenerator::AppendLWYUFlags(std::string& flags, + const cmGeneratorTarget* target, + const std::string& lang) +{ + auto useLWYU = target->GetPropertyAsBool("LINK_WHAT_YOU_USE") && + (target->GetType() == cmStateEnums::TargetType::EXECUTABLE || + target->GetType() == cmStateEnums::TargetType::SHARED_LIBRARY || + target->GetType() == cmStateEnums::TargetType::MODULE_LIBRARY); + + if (useLWYU) { + const auto& lwyuFlag = this->GetMakefile()->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_LINK_WHAT_YOU_USE_FLAG")); + useLWYU = !lwyuFlag.empty(); + + if (useLWYU) { + std::vector<BT<std::string>> lwyuOpts; + lwyuOpts.emplace_back(lwyuFlag); + this->AppendFlags(flags, target->ResolveLinkerWrapper(lwyuOpts, lang)); + } + } + + return useLWYU; +} + void cmLocalGenerator::AppendCompileOptions(std::string& options, std::string const& options_list, const char* regex) const diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 993280a..1e09b23 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -171,6 +171,8 @@ public: cmGeneratorTarget* target, const std::string& config, const std::string& lang); + bool AppendLWYUFlags(std::string& flags, const cmGeneratorTarget* target, + const std::string& lang); enum class IncludePathStyle { @@ -587,7 +589,7 @@ protected: std::string::size_type ObjectPathMax; std::set<std::string> ObjectMaxPathViolations; - std::set<std::string> EnvCPATH; + std::vector<std::string> EnvCPATH; using GeneratorTargetMap = std::unordered_map<std::string, cmGeneratorTarget*>; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 7f7b1e7..9f8e7ed 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -279,7 +279,7 @@ void cmLocalNinjaGenerator::WriteNinjaRequiredVersion(std::ostream& os) std::string requiredVersion = cmGlobalNinjaGenerator::RequiredNinjaVersion(); // Ninja generator uses the 'console' pool if available (>= 1.5) - if (this->GetGlobalNinjaGenerator()->SupportsConsolePool()) { + if (this->GetGlobalNinjaGenerator()->SupportsDirectConsole()) { requiredVersion = cmGlobalNinjaGenerator::RequiredNinjaVersionForConsolePool(); } diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 002f484..46f9d31 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -171,7 +171,7 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( // for visual studio IDE add extra stuff to the PATH // if CMAKE_MSVCIDE_RUN_PATH is set. - if (this->Makefile->GetDefinition("MSVC_IDE")) { + if (this->GetGlobalGenerator()->IsVisualStudio()) { cmProp extraPath = this->Makefile->GetDefinition("CMAKE_MSVCIDE_RUN_PATH"); if (extraPath) { script += newline; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index c970abe..0b8778f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2118,15 +2118,23 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName, cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type, const std::string& name) { - auto it = this->Targets - .emplace(name, - cmTarget(name, type, cmTarget::VisibilityNormal, this, - cmTarget::PerConfig::Yes)) - .first; + return &this->CreateNewTarget(name, type).first; +} + +std::pair<cmTarget&, bool> cmMakefile::CreateNewTarget( + const std::string& name, cmStateEnums::TargetType type, + cmTarget::PerConfig perConfig) +{ + auto ib = this->Targets.emplace( + name, cmTarget(name, type, cmTarget::VisibilityNormal, this, perConfig)); + auto it = ib.first; + if (!ib.second) { + return std::make_pair(std::ref(it->second), false); + } this->OrderedTargets.push_back(&it->second); this->GetGlobalGenerator()->IndexTarget(&it->second); this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name); - return &it->second; + return std::make_pair(std::ref(it->second), true); } cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName, @@ -2571,12 +2579,7 @@ cmProp cmMakefile::GetDefinition(const std::string& name) const const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const { - static std::string const empty; - cmProp def = this->GetDefinition(name); - if (!def) { - return empty; - } - return *def; + return this->GetDefinition(name); } bool cmMakefile::GetDefExpandList(const std::string& name, @@ -2959,7 +2962,7 @@ MessageType cmMakefile::ExpandVariablesInStringNew( break; case ENVIRONMENT: if (cmSystemTools::GetEnv(lookup, svalue)) { - value = &svalue; + value = cmProp(svalue); } break; case CACHE: @@ -3182,6 +3185,23 @@ void cmMakefile::RemoveVariablesInString(std::string& source, } } +void cmMakefile::InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault) +{ + if (this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) { + return; + } + std::string initConfigs; + if (!cmSystemTools::GetEnv("CMAKE_CONFIGURATION_TYPES", initConfigs)) { + initConfigs = genDefault; + } + this->AddCacheDefinition( + "CMAKE_CONFIGURATION_TYPES", initConfigs, + "Semicolon separated list of supported configuration types, " + "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, " + "anything else will be ignored.", + cmStateEnums::STRING); +} + std::string cmMakefile::GetDefaultConfiguration() const { if (this->GetGlobalGenerator()->IsMultiConfig()) { @@ -3542,8 +3562,8 @@ int cmMakefile::TryCompile(const std::string& srcdir, // make sure the same generator is used // use this program as the cmake to be run, it should not // be run that way but the cmake object requires a vailid path - cmake cm(cmake::RoleProject, cmState::Project); - cm.SetIsInTryCompile(true); + cmake cm(cmake::RoleProject, cmState::Project, + cmState::ProjectKind::TryCompile); auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName()); if (!gg) { this->IssueMessage(MessageType::INTERNAL_ERROR, @@ -3987,7 +4007,7 @@ cmProp cmMakefile::GetProperty(const std::string& prop) const return pair.first; }); output = cmJoin(keys, ";"); - return &output; + return cmProp(output); } return this->StateSnapshot.GetDirectory().GetProperty(prop); @@ -4426,13 +4446,12 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, return false; } - // Deprecate old policies, especially those that require a lot - // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0081 && + // Deprecate old policies. + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0088 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. - id == cmPolicies::CMP0065))) { + id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083))) { this->IssueMessage(MessageType::DEPRECATION_WARNING, cmPolicies::GetPolicyDeprecatedWarning(id)); } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 77e9c74..5886c86 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -13,6 +13,7 @@ #include <stack> #include <string> #include <unordered_map> +#include <utility> #include <vector> #include <cm/optional> @@ -230,6 +231,10 @@ public: cmTarget* AddImportedTarget(const std::string& name, cmStateEnums::TargetType type, bool global); + std::pair<cmTarget&, bool> CreateNewTarget( + const std::string& name, cmStateEnums::TargetType type, + cmTarget::PerConfig perConfig = cmTarget::PerConfig::Yes); + cmTarget* AddNewTarget(cmStateEnums::TargetType type, const std::string& name); @@ -310,6 +315,8 @@ public: */ void SetProjectName(std::string const& name); + void InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault); + /* Get the default configuration */ std::string GetDefaultConfiguration() const; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 3a2744e..306b38f 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -397,9 +397,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) this->LocalGenerator->GetLinkLibsCMP0065( linkLanguage, *this->GeneratorTarget)); - if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) { - this->LocalGenerator->AppendFlags(linkFlags, " -Wl,--no-as-needed"); - } + this->UseLWYU = this->LocalGenerator->AppendLWYUFlags( + linkFlags, this->GeneratorTarget, linkLanguage); // Add language feature flags. this->LocalGenerator->AddLanguageFlagsForLinking( @@ -577,12 +576,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.Launcher = linkerLauncher.c_str(); } - if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) { - std::string cmakeCommand = - cmStrCat(this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), - " -E __run_co_compile --lwyu=", targetOutPathReal); - real_link_commands.push_back(std::move(cmakeCommand)); + if (this->UseLWYU) { + cmProp lwyuCheck = + this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK"); + if (lwyuCheck) { + std::string cmakeCommand = cmStrCat( + this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), + " -E __run_co_compile --lwyu="); + cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck); + cmakeCommand += cmStrCat(" --source=", targetOutPathReal); + real_link_commands.push_back(std::move(cmakeCommand)); + } } std::string launcher; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index d0e3837..64992f2 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -178,9 +178,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags, this->GetConfigName()); - if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) { - this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed"); - } + this->UseLWYU = this->LocalGenerator->AppendLWYUFlags( + extraFlags, this->GeneratorTarget, linkLanguage); + this->WriteLibraryRules(linkRuleVar, extraFlags, relink); } @@ -871,13 +871,18 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Get the set of commands. std::string linkRule = this->GetLinkRule(linkRuleVar); cmExpandList(linkRule, real_link_commands); - if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE") && - (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY)) { - std::string cmakeCommand = cmStrCat( - this->LocalGenerator->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), - " -E __run_co_compile --lwyu=", targetOutPathReal); - real_link_commands.push_back(std::move(cmakeCommand)); + if (this->UseLWYU) { + cmProp lwyuCheck = + this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK"); + if (lwyuCheck) { + std::string cmakeCommand = cmStrCat( + this->LocalGenerator->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), + " -E __run_co_compile --lwyu="); + cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck); + cmakeCommand += cmStrCat(" --source=", targetOutPathReal); + real_link_commands.push_back(std::move(cmakeCommand)); + } } // Expand placeholders. diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index a3e5553..626453f 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1398,6 +1398,13 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" << this->GeneratorTarget->GetFortranModuleDirectory(working_dir) << "\")\n"; + + if (this->GeneratorTarget->IsFortranBuildingInstrinsicModules()) { + *this->InfoFileStream + << "\n" + << "# Fortran compiler is building intrinsic modules.\n" + << "set(CMAKE_Fortran_TARGET_BUILDING_INSTRINSIC_MODULES ON) \n"; + } /* clang-format on */ // and now write the rule to use it diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx index 45043fa..5908f74 100644 --- a/Source/cmMarkAsAdvancedCommand.cxx +++ b/Source/cmMarkAsAdvancedCommand.cxx @@ -6,6 +6,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 5c21d1b..96e9142 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -581,17 +581,23 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( } } cmExpandList(linkCmdStr, linkCmds); - if (this->GetGeneratorTarget()->GetPropertyAsBool("LINK_WHAT_YOU_USE")) { - std::string cmakeCommand = cmStrCat( - this->GetLocalGenerator()->ConvertToOutputFormat( - cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), - " -E __run_co_compile --lwyu="); - cmGeneratorTarget& gt = *this->GetGeneratorTarget(); - std::string targetOutputReal = this->ConvertToNinjaPath( - gt.GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, - /*realname=*/true)); - cmakeCommand += targetOutputReal; - linkCmds.push_back(std::move(cmakeCommand)); + if (this->UseLWYU) { + cmProp lwyuCheck = mf->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK"); + if (lwyuCheck) { + std::string cmakeCommand = cmStrCat( + this->GetLocalGenerator()->ConvertToOutputFormat( + cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), + " -E __run_co_compile --lwyu="); + cmakeCommand += + this->GetLocalGenerator()->EscapeForShell(*lwyuCheck); + + std::string targetOutputReal = + this->ConvertToNinjaPath(this->GetGeneratorTarget()->GetFullPath( + config, cmStateEnums::RuntimeBinaryArtifact, + /*realname=*/true)); + cmakeCommand += cmStrCat(" --source=", targetOutputReal); + linkCmds.push_back(std::move(cmakeCommand)); + } } return linkCmds; } @@ -1156,12 +1162,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"], config); - if (gt->GetPropertyAsBool("LINK_WHAT_YOU_USE") && - (gt->GetType() == cmStateEnums::TargetType::EXECUTABLE || - gt->GetType() == cmStateEnums::TargetType::SHARED_LIBRARY || - gt->GetType() == cmStateEnums::TargetType::MODULE_LIBRARY)) { - vars["LINK_FLAGS"] += " -Wl,--no-as-needed"; - } + + this->UseLWYU = this->GetLocalGenerator()->AppendLWYUFlags( + vars["LINK_FLAGS"], this->GetGeneratorTarget(), + this->TargetLinkLanguage(config)); + vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]); vars["MANIFESTS"] = this->GetManifests(config); diff --git a/Source/cmOptionCommand.cxx b/Source/cmOptionCommand.cxx index bae67e0..014da4d 100644 --- a/Source/cmOptionCommand.cxx +++ b/Source/cmOptionCommand.cxx @@ -29,7 +29,7 @@ bool cmOptionCommand(std::vector<std::string> const& args, { auto policyStatus = status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0077); - const auto* existsBeforeSet = + const auto& existsBeforeSet = status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]); switch (policyStatus) { case cmPolicies::WARN: @@ -77,7 +77,7 @@ bool cmOptionCommand(std::vector<std::string> const& args, } if (checkAndWarn) { - const auto* existsAfterSet = + const auto& existsAfterSet = status.GetMakefile().GetStateSnapshot().GetDefinition(args[0]); if (!existsAfterSet) { status.GetMakefile().IssueMessage( diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 01e8c04..fc839c5 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -10,6 +10,7 @@ #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmProperty.h" #include "cmState.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" diff --git a/Source/cmProperty.cxx b/Source/cmProperty.cxx new file mode 100644 index 0000000..d012630 --- /dev/null +++ b/Source/cmProperty.cxx @@ -0,0 +1,113 @@ + +#include "cmProperty.h" + +#include <string> + +#include <cmext/string_view> + +#include "cmStringAlgorithms.h" + +std::string cmProp::Empty; + +bool cmProp::IsOn(cm::string_view value) noexcept +{ + switch (value.size()) { + case 1: + return value[0] == '1' || value[0] == 'Y' || value[0] == 'y'; + case 2: + return // + (value[0] == 'O' || value[0] == 'o') && // + (value[1] == 'N' || value[1] == 'n'); + case 3: + return // + (value[0] == 'Y' || value[0] == 'y') && // + (value[1] == 'E' || value[1] == 'e') && // + (value[2] == 'S' || value[2] == 's'); + case 4: + return // + (value[0] == 'T' || value[0] == 't') && // + (value[1] == 'R' || value[1] == 'r') && // + (value[2] == 'U' || value[2] == 'u') && // + (value[3] == 'E' || value[3] == 'e'); + default: + break; + } + + return false; +} + +bool cmProp::IsOff(cm::string_view value) noexcept +{ + switch (value.size()) { + case 0: + return true; + case 1: + return value[0] == '0' || value[0] == 'N' || value[0] == 'n'; + case 2: + return // + (value[0] == 'N' || value[0] == 'n') && // + (value[1] == 'O' || value[1] == 'o'); + case 3: + return // + (value[0] == 'O' || value[0] == 'o') && // + (value[1] == 'F' || value[1] == 'f') && // + (value[2] == 'F' || value[2] == 'f'); + case 5: + return // + (value[0] == 'F' || value[0] == 'f') && // + (value[1] == 'A' || value[1] == 'a') && // + (value[2] == 'L' || value[2] == 'l') && // + (value[3] == 'S' || value[3] == 's') && // + (value[4] == 'E' || value[4] == 'e'); + case 6: + return // + (value[0] == 'I' || value[0] == 'i') && // + (value[1] == 'G' || value[1] == 'g') && // + (value[2] == 'N' || value[2] == 'n') && // + (value[3] == 'O' || value[3] == 'o') && // + (value[4] == 'R' || value[4] == 'r') && // + (value[5] == 'E' || value[5] == 'e'); + default: + break; + } + + return IsNOTFOUND(value); +} +bool cmProp::IsNOTFOUND(cm::string_view value) noexcept +{ + return (value == "NOTFOUND"_s) || cmHasSuffix(value, "-NOTFOUND"_s); +} + +int cmProp::Compare(cmProp value) const noexcept +{ + if (this->Value == nullptr && !value) { + return 0; + } + if (this->Value == nullptr) { + return -1; + } + if (!value) { + return 1; + } + return this->Value->compare(*value); +} + +int cmProp::Compare(cm::string_view value) const noexcept +{ + if (this->Value == nullptr && value.data() == nullptr) { + return 0; + } + if (this->Value == nullptr) { + return -1; + } + if (value.data() == nullptr) { + return 1; + } + return cm::string_view(*this->Value).compare(value); +} + +std::ostream& operator<<(std::ostream& o, cmProp v) +{ + o << *v; + return o; +} diff --git a/Source/cmProperty.h b/Source/cmProperty.h index 1e03c3f..3a0a5be 100644 --- a/Source/cmProperty.h +++ b/Source/cmProperty.h @@ -4,8 +4,12 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> +#include <iosfwd> #include <string> +#include <cm/string_view> + class cmProperty { public: @@ -23,14 +27,210 @@ public: }; }; -using cmProp = const std::string*; +class cmProp +{ +public: + cmProp() noexcept = default; + cmProp(std::nullptr_t) noexcept {} + explicit cmProp(const std::string* value) noexcept + : Value(value) + { + } + explicit cmProp(const std::string& value) noexcept + : Value(&value) + { + } + cmProp(const cmProp& other) noexcept = default; -inline const char* cmToCStr(cmProp p) + cmProp& operator=(const cmProp& other) noexcept = default; + cmProp& operator=(std::nullptr_t) noexcept + { + this->Value = nullptr; + return *this; + } + + const std::string* Get() const noexcept { return this->Value; } + const char* GetCStr() const noexcept + { + return this->Value == nullptr ? nullptr : this->Value->c_str(); + } + + const std::string* operator->() const noexcept + { + return this->Value == nullptr ? &cmProp::Empty : this->Value; + } + const std::string& operator*() const noexcept + { + return this->Value == nullptr ? cmProp::Empty : *this->Value; + } + + explicit operator bool() const noexcept { return this->Value != nullptr; } + operator const std::string&() const noexcept { return this->operator*(); } + operator cm::string_view() const noexcept { return this->operator*(); } + + /** + * Does the value indicate a true or ON value? + */ + bool IsOn() const noexcept + { + return this->Value != nullptr && + cmProp::IsOn(cm::string_view(*this->Value)); + } + /** + * Does the value indicate a false or off value ? Note that this is + * not the same as !IsOn(...) because there are a number of + * ambiguous values such as "/usr/local/bin" a path will result in + * IsOn and IsOff both returning false. Note that the special path + * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true. + */ + bool IsOff() const noexcept + { + return this->Value == nullptr || + cmProp::IsOff(cm::string_view(*this->Value)); + } + /** Return true if value is NOTFOUND or ends in -NOTFOUND. */ + bool IsNOTFOUND() const noexcept + { + return this->Value != nullptr && + cmProp::IsNOTFOUND(cm::string_view(*this->Value)); + } + bool IsEmpty() const noexcept + { + return this->Value == nullptr || this->Value->empty(); + } + + bool IsSet() const noexcept + { + return !this->IsEmpty() && !this->IsNOTFOUND(); + } + + /** + * Does a string indicate a true or ON value? + */ + static bool IsOn(const char* value) noexcept + { + return value != nullptr && IsOn(cm::string_view(value)); + } + static bool IsOn(cm::string_view) noexcept; + + /** + * Compare method has same semantic as std::optional::compare + */ + int Compare(cmProp value) const noexcept; + int Compare(cm::string_view value) const noexcept; + + /** + * Does a string indicate a false or off value ? Note that this is + * not the same as !IsOn(...) because there are a number of + * ambiguous values such as "/usr/local/bin" a path will result in + * IsOn and IsOff both returning false. Note that the special path + * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true. + */ + static bool IsOff(const char* value) noexcept + { + return value == nullptr || IsOff(cm::string_view(value)); + } + static bool IsOff(cm::string_view) noexcept; + + /** Return true if value is NOTFOUND or ends in -NOTFOUND. */ + static bool IsNOTFOUND(const char* value) noexcept + { + return value == nullptr || IsNOTFOUND(cm::string_view(value)); + } + static bool IsNOTFOUND(cm::string_view) noexcept; + + static bool IsEmpty(const char* value) noexcept + { + return value == nullptr || *value == '\0'; + } + static bool IsEmpty(cm::string_view value) noexcept { return value.empty(); } + +private: + static std::string Empty; + const std::string* Value = nullptr; +}; + +std::ostream& operator<<(std::ostream& o, cmProp v); + +inline bool operator==(cmProp l, cmProp r) noexcept +{ + return l.Compare(r) == 0; +} +inline bool operator!=(cmProp l, cmProp r) noexcept { - return p ? p->c_str() : nullptr; + return l.Compare(r) != 0; +} +inline bool operator<(cmProp l, cmProp r) noexcept +{ + return l.Compare(r) < 0; +} +inline bool operator<=(cmProp l, cmProp r) noexcept +{ + return l.Compare(r) <= 0; +} +inline bool operator>(cmProp l, cmProp r) noexcept +{ + return l.Compare(r) > 0; +} +inline bool operator>=(cmProp l, cmProp r) noexcept +{ + return l.Compare(r) >= 0; } -inline const char* cmToCStrSafe(cmProp p) +inline bool operator==(cmProp l, cm::string_view r) noexcept +{ + return l.Compare(r) == 0; +} +inline bool operator!=(cmProp l, cm::string_view r) noexcept +{ + return l.Compare(r) != 0; +} +inline bool operator<(cmProp l, cm::string_view r) noexcept +{ + return l.Compare(r) < 0; +} +inline bool operator<=(cmProp l, cm::string_view r) noexcept +{ + return l.Compare(r) <= 0; +} +inline bool operator>(cmProp l, cm::string_view r) noexcept +{ + return l.Compare(r) > 0; +} +inline bool operator>=(cmProp l, cm::string_view r) noexcept +{ + return l.Compare(r) >= 0; +} + +inline bool operator==(cmProp l, std::nullptr_t) noexcept +{ + return l.Compare(cmProp{}) == 0; +} +inline bool operator!=(cmProp l, std::nullptr_t) noexcept +{ + return l.Compare(cmProp{}) != 0; +} +inline bool operator<(cmProp l, std::nullptr_t) noexcept +{ + return l.Compare(cmProp{}) < 0; +} +inline bool operator<=(cmProp l, std::nullptr_t) noexcept +{ + return l.Compare(cmProp{}) <= 0; +} +inline bool operator>(cmProp l, std::nullptr_t) noexcept +{ + return l.Compare(cmProp{}) > 0; +} +inline bool operator>=(cmProp l, std::nullptr_t) noexcept +{ + return l.Compare(cmProp{}) >= 0; +} + +/** + * Temporary wrapper + */ +inline const char* cmToCStr(cmProp p) { - return p ? p->c_str() : ""; + return p.GetCStr(); } diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx index 06e151a..3e3a44b 100644 --- a/Source/cmPropertyMap.cxx +++ b/Source/cmPropertyMap.cxx @@ -46,7 +46,7 @@ cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const { auto it = this->Map_.find(name); if (it != this->Map_.end()) { - return &it->second; + return cmProp(it->second); } return nullptr; } diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 898d862..57fcd2d 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -384,39 +384,3 @@ bool cmQtAutoGen::RccLister::list(std::string const& qrcFile, } return true; } - -bool cmQtAutoGen::FileRead(std::string& content, std::string const& filename, - std::string* error) -{ - content.clear(); - if (!cmSystemTools::FileExists(filename, true)) { - if (error != nullptr) { - *error = "Not a file."; - } - return false; - } - - unsigned long const length = cmSystemTools::FileLength(filename); - cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); - - // Use lambda to save destructor calls of ifs - return [&ifs, length, &content, error]() -> bool { - if (!ifs) { - if (error != nullptr) { - *error = "Opening the file for reading failed."; - } - return false; - } - content.reserve(length); - using IsIt = std::istreambuf_iterator<char>; - content.assign(IsIt{ ifs }, IsIt{}); - if (!ifs) { - content.clear(); - if (error != nullptr) { - *error = "Reading from the file failed."; - } - return false; - } - return true; - }(); -} diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index b9ae360..466a954 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -100,9 +100,6 @@ public: std::vector<std::string> const& newOpts, bool isQt5); - static bool FileRead(std::string& content, std::string const& filename, - std::string* error = nullptr); - /** @class RccLister * @brief Lists files in qrc resource files */ diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 6cc8328..4dd78e5 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -902,13 +902,6 @@ bool cmQtAutoGenInitializer::InitScanFiles() // The reason is that their file names might be discovered from source files // at generation time. if (this->MocOrUicEnabled()) { - std::set<std::string> uicIncludes; - auto collectUicIncludes = [&](std::unique_ptr<cmSourceFile> const& sf) { - std::string content; - FileRead(content, sf->GetFullPath()); - this->AutoUicHelpers.CollectUicIncludes(uicIncludes, content); - }; - for (const auto& sf : this->Makefile->GetSourceFiles()) { // sf->GetExtension() is only valid after sf->ResolveFullPath() ... // Since we're iterating over source files that might be not in the @@ -921,10 +914,6 @@ bool cmQtAutoGenInitializer::InitScanFiles() std::string const& extLower = cmSystemTools::LowerCase(sf->GetExtension()); - bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN); - bool const skipUic = - (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC) || - !this->Uic.Enabled); if (cm->IsAHeaderExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Headers, sf.get())) { auto muf = makeMUFile(sf.get(), fullPath, {}, false); @@ -932,9 +921,6 @@ bool cmQtAutoGenInitializer::InitScanFiles() addMUHeader(std::move(muf), extLower); } } - if (!skipUic && !sf->GetIsGenerated()) { - collectUicIncludes(sf); - } } else if (cm->IsACLikeSourceExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Sources, sf.get())) { auto muf = makeMUFile(sf.get(), fullPath, {}, false); @@ -942,11 +928,11 @@ bool cmQtAutoGenInitializer::InitScanFiles() addMUSource(std::move(muf)); } } - if (!skipUic && !sf->GetIsGenerated()) { - collectUicIncludes(sf); - } } else if (this->Uic.Enabled && (extLower == kw.ui)) { // .ui file + bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN); + bool const skipUic = + (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC)); if (!skipUic) { // Check if the .ui file has uic options std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS); @@ -956,22 +942,35 @@ bool cmQtAutoGenInitializer::InitScanFiles() this->Uic.UiFilesWithOptions.emplace_back(fullPath, cmExpandedList(uicOpts)); } + + auto uiHeaderRelativePath = cmSystemTools::RelativePath( + this->LocalGen->GetCurrentSourceDirectory(), + cmSystemTools::GetFilenamePath(fullPath)); + + // Avoid creating a path containing adjacent slashes + if (!uiHeaderRelativePath.empty() && + uiHeaderRelativePath.back() != '/') { + uiHeaderRelativePath += '/'; + } + + auto uiHeaderFilePath = cmStrCat( + '/', uiHeaderRelativePath, "ui_"_s, + cmSystemTools::GetFilenameWithoutLastExtension(fullPath), ".h"_s); + + ConfigString uiHeader; + std::string uiHeaderGenex; + this->ConfigFileNamesAndGenex( + uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s), + uiHeaderFilePath); + + this->Uic.UiHeaders.emplace_back( + std::make_pair(uiHeader, uiHeaderGenex)); } else { // Register skipped .ui file this->Uic.SkipUi.insert(fullPath); } } } - - for (const auto& include : uicIncludes) { - ConfigString uiHeader; - std::string uiHeaderGenex; - this->ConfigFileNamesAndGenex(uiHeader, uiHeaderGenex, - cmStrCat(this->Dir.Build, "/include"_s), - cmStrCat("/"_s, include)); - this->Uic.UiHeaders.emplace_back( - std::make_pair(uiHeader, uiHeaderGenex)); - } } // Process GENERATED sources and headers diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index 3ec87d2..e76817b 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -17,7 +17,6 @@ #include "cmFilePathChecksum.h" #include "cmQtAutoGen.h" -#include "cmQtAutoUicHelpers.h" class cmGeneratorTarget; class cmGlobalGenerator; @@ -171,7 +170,6 @@ private: std::string ConfigDefault; std::vector<std::string> ConfigsList; std::string TargetsFolder; - cmQtAutoUicHelpers AutoUicHelpers; /** Common directories. */ struct diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index 0c6b5e6..568926e 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -121,6 +121,43 @@ bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename) return success; } +bool cmQtAutoGenerator::FileRead(std::string& content, + std::string const& filename, + std::string* error) +{ + content.clear(); + if (!cmSystemTools::FileExists(filename, true)) { + if (error != nullptr) { + *error = "Not a file."; + } + return false; + } + + unsigned long const length = cmSystemTools::FileLength(filename); + cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary)); + + // Use lambda to save destructor calls of ifs + return [&ifs, length, &content, error]() -> bool { + if (!ifs) { + if (error != nullptr) { + *error = "Opening the file for reading failed."; + } + return false; + } + content.reserve(length); + using IsIt = std::istreambuf_iterator<char>; + content.assign(IsIt{ ifs }, IsIt{}); + if (!ifs) { + content.clear(); + if (error != nullptr) { + *error = "Reading from the file failed."; + } + return false; + } + return true; + }(); +} + bool cmQtAutoGenerator::FileWrite(std::string const& filename, std::string const& content, std::string* error) diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 66399d7..5c3a8ad 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -70,6 +70,8 @@ public: // -- File system methods static bool MakeParentDirectory(std::string const& filename); + static bool FileRead(std::string& content, std::string const& filename, + std::string* error = nullptr); static bool FileWrite(std::string const& filename, std::string const& content, std::string* error = nullptr); diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 86d54f9..2753fd5 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -30,7 +30,6 @@ #include "cmGeneratedFileStream.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenerator.h" -#include "cmQtAutoUicHelpers.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmWorkerPool.h" @@ -282,7 +281,7 @@ public: std::vector<std::string> Options; std::unordered_map<std::string, UiFile> UiFiles; std::vector<std::string> SearchPaths; - cmQtAutoUicHelpers AutoUicHelpers; + cmsys::RegularExpression RegExpInclude; }; /** Uic shared variables. */ @@ -762,7 +761,11 @@ std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const return res; } -cmQtAutoMocUicT::UicSettingsT::UicSettingsT() = default; +cmQtAutoMocUicT::UicSettingsT::UicSettingsT() +{ + this->RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); +} cmQtAutoMocUicT::UicSettingsT::~UicSettingsT() = default; @@ -1053,7 +1056,16 @@ void cmQtAutoMocUicT::JobParseT::UicIncludes() } std::set<std::string> includes; - this->UicConst().AutoUicHelpers.CollectUicIncludes(includes, this->Content); + { + const char* contentChars = this->Content.c_str(); + cmsys::RegularExpression const& regExp = this->UicConst().RegExpInclude; + cmsys::RegularExpressionMatch match; + while (regExp.find(contentChars, match)) { + includes.emplace(match.match(2)); + // Forward content pointer + contentChars += match.end(); + } + } this->CreateKeys(this->FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength); } diff --git a/Source/cmQtAutoUicHelpers.cxx b/Source/cmQtAutoUicHelpers.cxx deleted file mode 100644 index 751ae08..0000000 --- a/Source/cmQtAutoUicHelpers.cxx +++ /dev/null @@ -1,25 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmQtAutoUicHelpers.h" - -cmQtAutoUicHelpers::cmQtAutoUicHelpers() -{ - RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); -} - -void cmQtAutoUicHelpers::CollectUicIncludes(std::set<std::string>& includes, - const std::string& content) const -{ - if (content.find("ui_") == std::string::npos) { - return; - } - - const char* contentChars = content.c_str(); - cmsys::RegularExpressionMatch match; - while (this->RegExpInclude.find(contentChars, match)) { - includes.emplace(match.match(2)); - // Forward content pointer - contentChars += match.end(); - } -} diff --git a/Source/cmQtAutoUicHelpers.h b/Source/cmQtAutoUicHelpers.h deleted file mode 100644 index 6b09a31..0000000 --- a/Source/cmQtAutoUicHelpers.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include <set> -#include <string> - -#include "cmsys/RegularExpression.hxx" - -class cmQtAutoUicHelpers -{ -public: - cmQtAutoUicHelpers(); - virtual ~cmQtAutoUicHelpers() = default; - void CollectUicIncludes(std::set<std::string>& includes, - const std::string& content) const; - -private: - cmsys::RegularExpression RegExpInclude; -}; diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index 3f3c8d5..f2b5cc4 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -342,7 +342,7 @@ cmProp cmSourceFile::GetPropertyForUser(const std::string& prop) // if it is requested by the user. if (prop == propLANGUAGE) { // The pointer is valid until `this->Language` is modified. - return &this->GetOrDetermineLanguage(); + return cmProp(this->GetOrDetermineLanguage()); } // Special handling for GENERATED property. @@ -355,9 +355,9 @@ cmProp cmSourceFile::GetPropertyForUser(const std::string& prop) (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD) ? CheckScope::GlobalAndLocal : CheckScope::Global)) { - return &propTRUE; + return cmProp(propTRUE); } - return &propFALSE; + return cmProp(propFALSE); } // Perform the normal property lookup. @@ -371,7 +371,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const if (this->FullPath.empty()) { return nullptr; } - return &this->FullPath; + return cmProp(this->FullPath); } // Check for the properties with backtraces. @@ -382,7 +382,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->IncludeDirectories, ";"); - return &output; + return cmProp(output); } if (prop == propCOMPILE_OPTIONS) { @@ -392,7 +392,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->CompileOptions, ";"); - return &output; + return cmProp(output); } if (prop == propCOMPILE_DEFINITIONS) { @@ -402,7 +402,7 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->CompileDefinitions, ";"); - return &output; + return cmProp(output); } cmProp retVal = this->Properties.GetPropertyValue(prop); diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index 37ed4c1..499317d 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -57,10 +57,10 @@ int ParseStd(std::string const& level) return -1; } -struct StanardLevelComputer +struct StandardLevelComputer { - explicit StanardLevelComputer(std::string lang, std::vector<int> levels, - std::vector<std::string> levelsStr) + explicit StandardLevelComputer(std::string lang, std::vector<int> levels, + std::vector<std::string> levelsStr) : Language(std::move(lang)) , Levels(std::move(levels)) , LevelsAsStrings(std::move(levelsStr)) @@ -308,31 +308,33 @@ struct StanardLevelComputer std::vector<std::string> LevelsAsStrings; }; -std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping = - { { "C", - StanardLevelComputer{ +std::unordered_map<std::string, StandardLevelComputer> + StandardComputerMapping = { + { "C", + StandardLevelComputer{ "C", std::vector<int>{ 90, 99, 11, 17, 23 }, std::vector<std::string>{ "90", "99", "11", "17", "23" } } }, { "CXX", - StanardLevelComputer{ + StandardLevelComputer{ "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }, { "CUDA", - StanardLevelComputer{ + StandardLevelComputer{ "CUDA", std::vector<int>{ 03, 11, 14, 17, 20, 23 }, std::vector<std::string>{ "03", "11", "14", "17", "20", "23" } } }, { "OBJC", - StanardLevelComputer{ + StandardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11, 17, 23 }, std::vector<std::string>{ "90", "99", "11", "17", "23" } } }, { "OBJCXX", - StanardLevelComputer{ + StandardLevelComputer{ "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }, { "HIP", - StanardLevelComputer{ + StandardLevelComputer{ "HIP", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, - std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } } }; + std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } } + }; } std::string cmStandardLevelResolver::GetCompileOptionDef( @@ -387,7 +389,11 @@ bool cmStandardLevelResolver::CheckCompileFeaturesAvailable( return false; } - const char* features = this->CompileFeaturesAvailable(lang, error); + if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) { + return true; + } + + cmProp features = this->CompileFeaturesAvailable(lang, error); if (!features) { return false; } @@ -465,7 +471,7 @@ bool cmStandardLevelResolver::CompileFeatureKnown( return false; } -const char* cmStandardLevelResolver::CompileFeaturesAvailable( +cmProp cmStandardLevelResolver::CompileFeaturesAvailable( const std::string& lang, std::string* error) const { if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) { @@ -507,7 +513,7 @@ const char* cmStandardLevelResolver::CompileFeaturesAvailable( } return nullptr; } - return cmToCStr(featuresKnown); + return featuresKnown; } bool cmStandardLevelResolver::GetNewRequiredStandard( diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h index d84fbcb..c01a3b1 100644 --- a/Source/cmStandardLevelResolver.h +++ b/Source/cmStandardLevelResolver.h @@ -30,8 +30,8 @@ public: const std::string& feature, std::string& lang, std::string* error) const; - const char* CompileFeaturesAvailable(const std::string& lang, - std::string* error) const; + cmProp CompileFeaturesAvailable(const std::string& lang, + std::string* error) const; bool GetNewRequiredStandard(const std::string& targetName, const std::string& feature, diff --git a/Source/cmState.cxx b/Source/cmState.cxx index ce6eb31..bde3e2e 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -26,7 +26,9 @@ #include "cmSystemTools.h" #include "cmake.h" -cmState::cmState() +cmState::cmState(Mode mode, ProjectKind projectKind) + : StateMode(mode) + , StateProjectKind(projectKind) { this->CacheManager = cm::make_unique<cmCacheManager>(); this->GlobVerificationManager = cm::make_unique<cmGlobVerificationManager>(); @@ -381,16 +383,6 @@ void cmState::ClearEnabledLanguages() this->EnabledLanguages.clear(); } -bool cmState::GetIsInTryCompile() const -{ - return this->IsInTryCompile; -} - -void cmState::SetIsInTryCompile(bool b) -{ - this->IsInTryCompile = b; -} - bool cmState::GetIsGeneratorMultiConfig() const { return this->IsGeneratorMultiConfig; @@ -593,8 +585,9 @@ cmProp cmState::GetGlobalProperty(const std::string& prop) std::vector<std::string> commands = this->GetCommandNames(); this->SetGlobalProperty("COMMANDS", cmJoin(commands, ";").c_str()); } else if (prop == "IN_TRY_COMPILE") { - this->SetGlobalProperty("IN_TRY_COMPILE", - this->IsInTryCompile ? "1" : "0"); + this->SetGlobalProperty( + "IN_TRY_COMPILE", + this->StateProjectKind == ProjectKind::TryCompile ? "1" : "0"); } else if (prop == "GENERATOR_IS_MULTI_CONFIG") { this->SetGlobalProperty("GENERATOR_IS_MULTI_CONFIG", this->IsGeneratorMultiConfig ? "1" : "0"); @@ -610,47 +603,47 @@ cmProp cmState::GetGlobalProperty(const std::string& prop) if (prop == "CMAKE_C_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_C90_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_C99_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_C11_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_CXX_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_CXX98_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_CXX11_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_CXX14_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } if (prop == "CMAKE_CUDA_KNOWN_FEATURES") { static const std::string s_out( &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]); - return &s_out; + return cmProp(s_out); } #undef STRING_LIST_ELEMENT @@ -771,17 +764,12 @@ unsigned int cmState::GetCacheMinorVersion() const cmState::Mode cmState::GetMode() const { - return this->CurrentMode; + return this->StateMode; } std::string cmState::GetModeString() const { - return ModeToString(this->CurrentMode); -} - -void cmState::SetMode(cmState::Mode mode) -{ - this->CurrentMode = mode; + return ModeToString(this->StateMode); } std::string cmState::ModeToString(cmState::Mode mode) @@ -803,6 +791,11 @@ std::string cmState::ModeToString(cmState::Mode mode) return "UNKNOWN"; } +cmState::ProjectKind cmState::GetProjectKind() const +{ + return this->StateProjectKind; +} + std::string const& cmState::GetBinaryDirectory() const { return this->BinaryDirectory; diff --git a/Source/cmState.h b/Source/cmState.h index 9951b9a..8561fc0 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -35,12 +35,6 @@ class cmState friend class cmStateSnapshot; public: - cmState(); - ~cmState(); - - cmState(const cmState&) = delete; - cmState& operator=(const cmState&) = delete; - enum Mode { Unknown, @@ -51,6 +45,18 @@ public: CPack, }; + enum class ProjectKind + { + Normal, + TryCompile, + }; + + cmState(Mode mode, ProjectKind projectKind = ProjectKind::Normal); + ~cmState(); + + cmState(const cmState&) = delete; + cmState& operator=(const cmState&) = delete; + static const std::string& GetTargetTypeName( cmStateEnums::TargetType targetType); @@ -141,9 +147,6 @@ public: void SetEnabledLanguages(std::vector<std::string> const& langs); void ClearEnabledLanguages(); - bool GetIsInTryCompile() const; - void SetIsInTryCompile(bool b); - bool GetIsGeneratorMultiConfig() const; void SetIsGeneratorMultiConfig(bool b); @@ -207,10 +210,11 @@ public: Mode GetMode() const; std::string GetModeString() const; - void SetMode(Mode mode); static std::string ModeToString(Mode mode); + ProjectKind GetProjectKind() const; + private: friend class cmake; void AddCacheEntry(const std::string& key, const char* value, @@ -248,7 +252,6 @@ private: std::string SourceDirectory; std::string BinaryDirectory; - bool IsInTryCompile = false; bool IsGeneratorMultiConfig = false; bool WindowsShell = false; bool WindowsVSIDE = false; @@ -258,5 +261,6 @@ private: bool NMake = false; bool MSYSShell = false; bool NinjaMulti = false; - Mode CurrentMode = Unknown; + Mode StateMode = Unknown; + ProjectKind StateProjectKind = ProjectKind::Normal; }; diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index c898dd4..b90cf7e 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -450,17 +450,17 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const if (prop == "PARENT_DIRECTORY") { cmStateSnapshot parent = this->Snapshot_.GetBuildsystemDirectoryParent(); if (parent.IsValid()) { - return &parent.GetDirectory().GetCurrentSource(); + return cmProp(parent.GetDirectory().GetCurrentSource()); } - return &output; + return cmProp(output); } if (prop == kBINARY_DIR) { output = this->GetCurrentBinary(); - return &output; + return cmProp(output); } if (prop == kSOURCE_DIR) { output = this->GetCurrentSource(); - return &output; + return cmProp(output); } if (prop == kSUBDIRECTORIES) { std::vector<std::string> child_dirs; @@ -471,15 +471,15 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const child_dirs.push_back(ci.GetDirectory().GetCurrentSource()); } output = cmJoin(child_dirs, ";"); - return &output; + return cmProp(output); } if (prop == kBUILDSYSTEM_TARGETS) { output = cmJoin(this->DirectoryState->NormalTargetNames, ";"); - return &output; + return cmProp(output); } if (prop == "IMPORTED_TARGETS"_s) { output = cmJoin(this->DirectoryState->ImportedTargetNames, ";"); - return &output; + return cmProp(output); } if (prop == "LISTFILE_STACK") { @@ -491,38 +491,38 @@ cmProp cmStateDirectory::GetProperty(const std::string& prop, bool chain) const } std::reverse(listFiles.begin(), listFiles.end()); output = cmJoin(listFiles, ";"); - return &output; + return cmProp(output); } if (prop == "CACHE_VARIABLES") { output = cmJoin(this->Snapshot_.State->GetCacheEntryKeys(), ";"); - return &output; + return cmProp(output); } if (prop == "VARIABLES") { std::vector<std::string> res = this->Snapshot_.ClosureKeys(); cm::append(res, this->Snapshot_.State->GetCacheEntryKeys()); std::sort(res.begin(), res.end()); output = cmJoin(res, ";"); - return &output; + return cmProp(output); } if (prop == "INCLUDE_DIRECTORIES") { output = cmJoin(this->GetIncludeDirectoriesEntries(), ";"); - return &output; + return cmProp(output); } if (prop == "COMPILE_OPTIONS") { output = cmJoin(this->GetCompileOptionsEntries(), ";"); - return &output; + return cmProp(output); } if (prop == "COMPILE_DEFINITIONS") { output = cmJoin(this->GetCompileDefinitionsEntries(), ";"); - return &output; + return cmProp(output); } if (prop == "LINK_OPTIONS") { output = cmJoin(this->GetLinkOptionsEntries(), ";"); - return &output; + return cmProp(output); } if (prop == "LINK_DIRECTORIES") { output = cmJoin(this->GetLinkDirectoriesEntries(), ";"); - return &output; + return cmProp(output); } cmProp retVal = this->DirectoryState->Properties.GetPropertyValue(prop); diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index fbf47ef..6f13d89 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -201,8 +201,7 @@ bool cmStateSnapshot::HasDefinedPolicyCMP0011() return !this->Position->Policies->IsEmpty(); } -std::string const* cmStateSnapshot::GetDefinition( - std::string const& name) const +cmProp cmStateSnapshot::GetDefinition(std::string const& name) const { assert(this->Position->Vars.IsValid()); return cmDefinitions::Get(name, this->Position->Vars, this->Position->Root); diff --git a/Source/cmStateSnapshot.h b/Source/cmStateSnapshot.h index d06cba3..a5fe7e2 100644 --- a/Source/cmStateSnapshot.h +++ b/Source/cmStateSnapshot.h @@ -12,6 +12,7 @@ #include "cmLinkedTree.h" #include "cmPolicies.h" +#include "cmProperty.h" #include "cmStateTypes.h" class cmState; @@ -23,7 +24,7 @@ public: cmStateSnapshot(cmState* state = nullptr); cmStateSnapshot(cmState* state, cmStateDetail::PositionType position); - std::string const* GetDefinition(std::string const& name) const; + cmProp GetDefinition(std::string const& name) const; bool IsInitialized(std::string const& name) const; void SetDefinition(std::string const& name, cm::string_view value); void RemoveDefinition(std::string const& name); diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index 5bb6e7b..acb5e5b 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -227,76 +227,6 @@ bool cmIsInternallyOn(cm::string_view val) (val[3] == 'N' || val[3] == 'n'); } -bool cmIsNOTFOUND(cm::string_view val) -{ - return (val == "NOTFOUND") || cmHasLiteralSuffix(val, "-NOTFOUND"); -} - -bool cmIsOn(cm::string_view val) -{ - switch (val.size()) { - case 1: - return val[0] == '1' || val[0] == 'Y' || val[0] == 'y'; - case 2: - return // - (val[0] == 'O' || val[0] == 'o') && // - (val[1] == 'N' || val[1] == 'n'); - case 3: - return // - (val[0] == 'Y' || val[0] == 'y') && // - (val[1] == 'E' || val[1] == 'e') && // - (val[2] == 'S' || val[2] == 's'); - case 4: - return // - (val[0] == 'T' || val[0] == 't') && // - (val[1] == 'R' || val[1] == 'r') && // - (val[2] == 'U' || val[2] == 'u') && // - (val[3] == 'E' || val[3] == 'e'); - default: - break; - } - - return false; -} - -bool cmIsOff(cm::string_view val) -{ - switch (val.size()) { - case 0: - return true; - case 1: - return val[0] == '0' || val[0] == 'N' || val[0] == 'n'; - case 2: - return // - (val[0] == 'N' || val[0] == 'n') && // - (val[1] == 'O' || val[1] == 'o'); - case 3: - return // - (val[0] == 'O' || val[0] == 'o') && // - (val[1] == 'F' || val[1] == 'f') && // - (val[2] == 'F' || val[2] == 'f'); - case 5: - return // - (val[0] == 'F' || val[0] == 'f') && // - (val[1] == 'A' || val[1] == 'a') && // - (val[2] == 'L' || val[2] == 'l') && // - (val[3] == 'S' || val[3] == 's') && // - (val[4] == 'E' || val[4] == 'e'); - case 6: - return // - (val[0] == 'I' || val[0] == 'i') && // - (val[1] == 'G' || val[1] == 'g') && // - (val[2] == 'N' || val[2] == 'n') && // - (val[3] == 'O' || val[3] == 'o') && // - (val[4] == 'R' || val[4] == 'r') && // - (val[5] == 'E' || val[5] == 'e'); - default: - break; - } - - return cmIsNOTFOUND(val); -} - bool cmStrToLong(const char* str, long* value) { errno = 0; diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 6b458ec..531678a 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -14,25 +14,12 @@ #include <cm/string_view> +#include "cmProperty.h" #include "cmRange.h" /** String range type. */ using cmStringRange = cmRange<std::vector<std::string>::const_iterator>; -/** Check for non-empty string. */ -inline bool cmNonempty(const char* str) -{ - return str && *str; -} -inline bool cmNonempty(cm::string_view str) -{ - return !str.empty(); -} -inline bool cmNonempty(std::string const* str) -{ - return str && !str->empty(); -} - /** Returns length of a literal string. */ template <size_t N> constexpr size_t cmStrLen(const char (&/*str*/)[N]) @@ -175,6 +162,10 @@ public: cmAlphaNum(unsigned long long int val); cmAlphaNum(float val); cmAlphaNum(double val); + cmAlphaNum(cmProp value) + : View_(*value) + { + } cm::string_view View() const { return this->View_; } @@ -227,20 +218,44 @@ inline bool cmIsInternallyOn(const char* val) return cmIsInternallyOn(cm::string_view(val)); } +/** Check for non-empty Property/Variable value. */ +inline bool cmNonempty(cm::string_view val) +{ + return !cmProp::IsEmpty(val); +} +inline bool cmNonempty(const char* val) +{ + return !cmProp::IsEmpty(val); +} +inline bool cmNonempty(cmProp val) +{ + return !val.IsEmpty(); +} + /** Return true if value is NOTFOUND or ends in -NOTFOUND. */ -bool cmIsNOTFOUND(cm::string_view val); +inline bool cmIsNOTFOUND(cm::string_view val) +{ + return cmProp::IsNOTFOUND(val); +} +inline bool cmIsNOTFOUND(cmProp val) +{ + return val.IsNOTFOUND(); +} /** * Does a string indicate a true or ON value? This is not the same as ifdef. */ -bool cmIsOn(cm::string_view val); +inline bool cmIsOn(cm::string_view val) +{ + return cmProp::IsOn(val); +} inline bool cmIsOn(const char* val) { - return val && cmIsOn(cm::string_view(val)); + return cmProp::IsOn(val); } -inline bool cmIsOn(std::string const* val) +inline bool cmIsOn(cmProp val) { - return val && cmIsOn(*val); + return val.IsOn(); } /** @@ -250,14 +265,17 @@ inline bool cmIsOn(std::string const* val) * IsON and IsOff both returning false. Note that the special path * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true. */ -bool cmIsOff(cm::string_view val); +inline bool cmIsOff(cm::string_view val) +{ + return cmProp::IsOff(val); +} inline bool cmIsOff(const char* val) { - return !val || cmIsOff(cm::string_view(val)); + return cmProp::IsOff(val); } -inline bool cmIsOff(std::string const* val) +inline bool cmIsOff(cmProp val) { - return !val || cmIsOff(*val); + return val.IsOff(); } /** Returns true if string @a str starts with the character @a prefix. */ diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 10d2e50..54fe7a1 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -20,6 +20,7 @@ #include <cm3p/uv.h> #include "cmDuration.h" +#include "cmELF.h" #include "cmMessageMetadata.h" #include "cmProcessOutput.h" #include "cmRange.h" @@ -46,10 +47,6 @@ # include "cmCryptoHash.h" #endif -#if defined(CMake_USE_ELF_PARSER) -# include "cmELF.h" -#endif - #if defined(CMake_USE_MACH_PARSER) # include "cmMachO.h" #endif @@ -1632,7 +1629,10 @@ bool cmSystemTools::CreateTar(const std::string& outFileName, cmArchiveWrite a(fout, compress, format.empty() ? "paxr" : format, compressionLevel); - a.Open(); + if (!a.Open()) { + cmSystemTools::Error(a.GetError()); + return false; + } a.SetMTime(mtime); a.SetVerbose(verbose); bool tarCreatedSuccessfully = true; @@ -2446,14 +2446,12 @@ void cmSystemTools::MakefileColorEcho(int color, const char* message, bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath, std::string& soname) { -// For ELF shared libraries use a real parser to get the correct -// soname. -#if defined(CMake_USE_ELF_PARSER) + // For ELF shared libraries use a real parser to get the correct + // soname. cmELF elf(fullPath.c_str()); if (elf) { return elf.GetSOName(soname); } -#endif // If the file is not a symlink we have no guess for its soname. if (!cmSystemTools::FileIsSymlink(fullPath)) { @@ -2491,7 +2489,6 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath, return false; } -#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER) std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have, cm::string_view const& want) { @@ -2523,9 +2520,7 @@ std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have, // The desired rpath was not found. return std::string::npos; } -#endif -#if defined(CMake_USE_ELF_PARSER) namespace { struct cmSystemToolsRPathInfo { @@ -2539,10 +2534,10 @@ using EmptyCallback = std::function<bool(std::string*, const cmELF&)>; using AdjustCallback = std::function<bool( cm::optional<std::string>&, const std::string&, const char*, std::string*)>; -// FIXME: Dispatch if multiple formats are supported. -bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback, - const AdjustCallback& adjustCallback, std::string* emsg, - bool* changed) +cm::optional<bool> AdjustRPathELF(std::string const& file, + const EmptyCallback& emptyCallback, + const AdjustCallback& adjustCallback, + std::string* emsg, bool* changed) { if (changed) { *changed = false; @@ -2553,6 +2548,9 @@ bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback, { // Parse the ELF binary. cmELF elf(file.c_str()); + if (!elf) { + return cm::nullopt; // Not a valid ELF file. + } // Get the RPATH and RUNPATH entries from it. int se_count = 0; @@ -2686,14 +2684,14 @@ std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback( } return false; }; -}; +} } -bool cmSystemTools::ChangeRPath(std::string const& file, - std::string const& oldRPath, - std::string const& newRPath, - bool removeEnvironmentRPath, std::string* emsg, - bool* changed) +cm::optional<bool> ChangeRPathELF(std::string const& file, + std::string const& oldRPath, + std::string const& newRPath, + bool removeEnvironmentRPath, + std::string* emsg, bool* changed) { auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath]( cm::optional<std::string>& outRPath, @@ -2741,13 +2739,13 @@ bool cmSystemTools::ChangeRPath(std::string const& file, return true; }; - return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg, - changed); + return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback, + emsg, changed); } -bool cmSystemTools::SetRPath(std::string const& file, - std::string const& newRPath, std::string* emsg, - bool* changed) +static cm::optional<bool> SetRPathELF(std::string const& file, + std::string const& newRPath, + std::string* emsg, bool* changed) { auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath, const std::string& inRPath, @@ -2759,22 +2757,31 @@ bool cmSystemTools::SetRPath(std::string const& file, return true; }; - return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg, - changed); + return AdjustRPathELF(file, MakeEmptyCallback(newRPath), adjustCallback, + emsg, changed); } -#elif defined(CMake_USE_XCOFF_PARSER) -bool cmSystemTools::ChangeRPath(std::string const& file, - std::string const& oldRPath, - std::string const& newRPath, - bool removeEnvironmentRPath, std::string* emsg, - bool* changed) +static cm::optional<bool> ChangeRPathXCOFF(std::string const& file, + std::string const& oldRPath, + std::string const& newRPath, + bool removeEnvironmentRPath, + std::string* emsg, bool* changed) { if (changed) { *changed = false; } - +#if !defined(CMake_USE_XCOFF_PARSER) + (void)file; + (void)oldRPath; + (void)newRPath; + (void)removeEnvironmentRPath; + (void)emsg; + return cm::nullopt; +#else bool chg = false; cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite); + if (!xcoff) { + return cm::nullopt; // Not a valid XCOFF file + } if (cm::optional<cm::string_view> maybeLibPath = xcoff.GetLibPath()) { cm::string_view libPath = *maybeLibPath; // Make sure the current rpath contains the old rpath. @@ -2830,31 +2837,47 @@ bool cmSystemTools::ChangeRPath(std::string const& file, *changed = chg; } return true; +#endif } -bool cmSystemTools::SetRPath(std::string const& /*file*/, - std::string const& /*newRPath*/, - std::string* /*emsg*/, bool* /*changed*/) +static cm::optional<bool> SetRPathXCOFF(std::string const& /*file*/, + std::string const& /*newRPath*/, + std::string* /*emsg*/, + bool* /*changed*/) { - return false; + return cm::nullopt; // Not implemented. } -#else -bool cmSystemTools::ChangeRPath(std::string const& /*file*/, - std::string const& /*oldRPath*/, - std::string const& /*newRPath*/, - bool /*removeEnvironmentRPath*/, - std::string* /*emsg*/, bool* /*changed*/) + +bool cmSystemTools::ChangeRPath(std::string const& file, + std::string const& oldRPath, + std::string const& newRPath, + bool removeEnvironmentRPath, std::string* emsg, + bool* changed) { + if (cm::optional<bool> result = ChangeRPathELF( + file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) { + return result.value(); + } + if (cm::optional<bool> result = ChangeRPathXCOFF( + file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) { + return result.value(); + } return false; } -bool cmSystemTools::SetRPath(std::string const& /*file*/, - std::string const& /*newRPath*/, - std::string* /*emsg*/, bool* /*changed*/) +bool cmSystemTools::SetRPath(std::string const& file, + std::string const& newRPath, std::string* emsg, + bool* changed) { + if (cm::optional<bool> result = SetRPathELF(file, newRPath, emsg, changed)) { + return result.value(); + } + if (cm::optional<bool> result = + SetRPathXCOFF(file, newRPath, emsg, changed)) { + return result.value(); + } return false; } -#endif bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op, const char* lhss, const char* rhss) @@ -2989,10 +3012,8 @@ int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs) return cm_strverscmp(lhs.c_str(), rhs.c_str()); } -// FIXME: Dispatch if multiple formats are supported. -#if defined(CMake_USE_ELF_PARSER) -bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, - bool* removed) +static cm::optional<bool> RemoveRPathELF(std::string const& file, + std::string* emsg, bool* removed) { if (removed) { *removed = false; @@ -3005,6 +3026,9 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, { // Parse the ELF binary. cmELF elf(file.c_str()); + if (!elf) { + return cm::nullopt; // Not a valid ELF file. + } // Get the RPATH and RUNPATH entries from it and sort them by index // in the dynamic section header. @@ -3054,8 +3078,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, entriesErased++; continue; } - if (cmELF::TagMipsRldMapRel != 0 && - it->first == cmELF::TagMipsRldMapRel) { + if (it->first == cmELF::TagMipsRldMapRel && elf.IsMIPS()) { // Background: debuggers need to know the "linker map" which contains // the addresses each dynamic object is loaded at. Most arches use // the DT_DEBUG tag which the dynamic linker writes to (directly) and @@ -3131,15 +3154,22 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, } return true; } -#elif defined(CMake_USE_XCOFF_PARSER) -bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, - bool* removed) + +static cm::optional<bool> RemoveRPathXCOFF(std::string const& file, + std::string* emsg, bool* removed) { if (removed) { *removed = false; } - +#if !defined(CMake_USE_XCOFF_PARSER) + (void)file; + (void)emsg; + return cm::nullopt; // Cannot handle XCOFF files. +#else cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite); + if (!xcoff) { + return cm::nullopt; // Not a valid XCOFF file. + } bool rm = xcoff.RemoveLibPath(); if (!xcoff) { if (emsg) { @@ -3152,55 +3182,60 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, *removed = rm; } return true; +#endif } -#else -bool cmSystemTools::RemoveRPath(std::string const& /*file*/, - std::string* /*emsg*/, bool* /*removed*/) +bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, + bool* removed) { + if (cm::optional<bool> result = RemoveRPathELF(file, emsg, removed)) { + return result.value(); + } + if (cm::optional<bool> result = RemoveRPathXCOFF(file, emsg, removed)) { + return result.value(); + } return false; } -#endif -// FIXME: Dispatch if multiple formats are supported. bool cmSystemTools::CheckRPath(std::string const& file, std::string const& newRPath) { -#if defined(CMake_USE_ELF_PARSER) // Parse the ELF binary. cmELF elf(file.c_str()); - - // Get the RPATH or RUNPATH entry from it. - cmELF::StringEntry const* se = elf.GetRPath(); - if (!se) { - se = elf.GetRunPath(); - } - - // Make sure the current rpath contains the new rpath. - if (newRPath.empty()) { + if (elf) { + // Get the RPATH or RUNPATH entry from it. + cmELF::StringEntry const* se = elf.GetRPath(); if (!se) { - return true; + se = elf.GetRunPath(); } - } else { - if (se && - cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) { - return true; + + // Make sure the current rpath contains the new rpath. + if (newRPath.empty()) { + if (!se) { + return true; + } + } else { + if (se && + cmSystemToolsFindRPath(se->Value, newRPath) != std::string::npos) { + return true; + } } + return false; } - return false; -#elif defined(CMake_USE_XCOFF_PARSER) +#if defined(CMake_USE_XCOFF_PARSER) // Parse the XCOFF binary. cmXCOFF xcoff(file.c_str()); - if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) { - if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) { - return true; + if (xcoff) { + if (cm::optional<cm::string_view> libPath = xcoff.GetLibPath()) { + if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) { + return true; + } } + return false; } - return false; -#else +#endif (void)file; (void)newRPath; return false; -#endif } bool cmSystemTools::RepeatedRemoveDirectory(const std::string& dir) diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 7622700..656afc6 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -157,7 +157,7 @@ cmProp cmTargetPropertyComputer::GetSources<cmTarget>( } static std::string srcs; srcs = ss.str(); - return &srcs; + return cmProp(srcs); } class cmTargetInternals @@ -189,6 +189,7 @@ public: std::map<std::string, BTs<std::string>> LanguageStandardProperties; std::vector<std::string> IncludeDirectoriesEntries; std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces; + std::vector<std::string> InstallIncludeDirectoriesEntries; std::vector<std::string> CompileOptionsEntries; std::vector<cmListFileBacktrace> CompileOptionsBacktraces; std::vector<std::string> CompileFeaturesEntries; @@ -1075,6 +1076,17 @@ std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const return this->impl->SystemIncludeDirectories; } +void cmTarget::AddInstallIncludeDirectories(cmStringRange const& incs) +{ + std::copy(incs.begin(), incs.end(), + std::back_inserter(this->impl->InstallIncludeDirectoriesEntries)); +} + +cmStringRange cmTarget::GetInstallIncludeDirectoriesEntries() const +{ + return cmMakeRange(this->impl->InstallIncludeDirectoriesEntries); +} + cmStringRange cmTarget::GetIncludeDirectoriesEntries() const { return cmMakeRange(this->impl->IncludeDirectoriesEntries); @@ -1737,7 +1749,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const if (propertyIter == this->impl->LanguageStandardProperties.end()) { return nullptr; } - return &(propertyIter->second.Value); + return cmProp(propertyIter->second.Value); } if (prop == propLINK_LIBRARIES) { if (this->impl->LinkImplementationPropertyEntries.empty()) { @@ -1746,11 +1758,11 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";"); - return &output; + return cmProp(output); } // the type property returns what type the target is if (prop == propTYPE) { - return &cmState::GetTargetTypeName(this->GetType()); + return cmProp(cmState::GetTargetTypeName(this->GetType())); } if (prop == propINCLUDE_DIRECTORIES) { if (this->impl->IncludeDirectoriesEntries.empty()) { @@ -1759,7 +1771,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->IncludeDirectoriesEntries, ";"); - return &output; + return cmProp(output); } if (prop == propCOMPILE_FEATURES) { if (this->impl->CompileFeaturesEntries.empty()) { @@ -1768,7 +1780,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->CompileFeaturesEntries, ";"); - return &output; + return cmProp(output); } if (prop == propCOMPILE_OPTIONS) { if (this->impl->CompileOptionsEntries.empty()) { @@ -1777,7 +1789,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->CompileOptionsEntries, ";"); - return &output; + return cmProp(output); } if (prop == propCOMPILE_DEFINITIONS) { if (this->impl->CompileDefinitionsEntries.empty()) { @@ -1786,7 +1798,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->CompileDefinitionsEntries, ";"); - return &output; + return cmProp(output); } if (prop == propLINK_OPTIONS) { if (this->impl->LinkOptionsEntries.empty()) { @@ -1795,7 +1807,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->LinkOptionsEntries, ";"); - return &output; + return cmProp(output); } if (prop == propLINK_DIRECTORIES) { if (this->impl->LinkDirectoriesEntries.empty()) { @@ -1805,7 +1817,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->LinkDirectoriesEntries, ";"); - return &output; + return cmProp(output); } if (prop == propMANUALLY_ADDED_DEPENDENCIES) { if (this->impl->Utilities.empty()) { @@ -1822,7 +1834,7 @@ cmProp cmTarget::GetProperty(const std::string& prop) const return item.Value.first; }); output = cmJoin(utilities, ";"); - return &output; + return cmProp(output); } if (prop == propPRECOMPILE_HEADERS) { if (this->impl->PrecompileHeadersEntries.empty()) { @@ -1831,26 +1843,27 @@ cmProp cmTarget::GetProperty(const std::string& prop) const static std::string output; output = cmJoin(this->impl->PrecompileHeadersEntries, ";"); - return &output; + return cmProp(output); } if (prop == propIMPORTED) { - return this->IsImported() ? &propTRUE : &propFALSE; + return this->IsImported() ? cmProp(propTRUE) : cmProp(propFALSE); } if (prop == propIMPORTED_GLOBAL) { - return this->IsImportedGloballyVisible() ? &propTRUE : &propFALSE; + return this->IsImportedGloballyVisible() ? cmProp(propTRUE) + : cmProp(propFALSE); } if (prop == propNAME) { - return &this->GetName(); + return cmProp(this->GetName()); } if (prop == propBINARY_DIR) { - return &this->impl->Makefile->GetStateSnapshot() - .GetDirectory() - .GetCurrentBinary(); + return cmProp(this->impl->Makefile->GetStateSnapshot() + .GetDirectory() + .GetCurrentBinary()); } if (prop == propSOURCE_DIR) { - return &this->impl->Makefile->GetStateSnapshot() - .GetDirectory() - .GetCurrentSource(); + return cmProp(this->impl->Makefile->GetStateSnapshot() + .GetDirectory() + .GetCurrentSource()); } } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 30d9f5d..29130c7 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -237,6 +237,9 @@ public: void AddSystemIncludeDirectories(std::set<std::string> const& incs); std::set<std::string> const& GetSystemIncludeDirectories() const; + void AddInstallIncludeDirectories(cmStringRange const& incs); + cmStringRange GetInstallIncludeDirectoriesEntries() const; + BTs<std::string> const* GetLanguageStandardProperty( const std::string& propertyName) const; diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h index 1e38d84..19fc931 100644 --- a/Source/cmTargetExport.h +++ b/Source/cmTargetExport.h @@ -29,7 +29,6 @@ public: cmInstallTargetGenerator* FrameworkGenerator; cmInstallTargetGenerator* BundleGenerator; cmInstallFilesGenerator* HeaderGenerator; - std::string InterfaceIncludeDirectories; ///@} bool NamelinkOnly = false; diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h index f2be318..a749b53 100644 --- a/Source/cmTargetPropertyComputer.h +++ b/Source/cmTargetPropertyComputer.h @@ -65,7 +65,7 @@ private: context)) { return nullptr; } - return &ComputeLocationForBuild(tgt); + return cmProp(ComputeLocationForBuild(tgt)); } // Support "LOCATION_<CONFIG>". @@ -76,7 +76,7 @@ private: return nullptr; } std::string configName = prop.substr(9); - return &ComputeLocation(tgt, configName); + return cmProp(ComputeLocation(tgt, configName)); } // Support "<CONFIG>_LOCATION". @@ -89,7 +89,7 @@ private: context)) { return nullptr; } - return &ComputeLocation(tgt, configName); + return cmProp(ComputeLocation(tgt, configName)); } } } diff --git a/Source/cmTest.cxx b/Source/cmTest.cxx index a26bef3..5bc10c2 100644 --- a/Source/cmTest.cxx +++ b/Source/cmTest.cxx @@ -32,7 +32,7 @@ void cmTest::SetCommand(std::vector<std::string> const& command) this->Command = command; } -const char* cmTest::GetProperty(const std::string& prop) const +cmProp cmTest::GetProperty(const std::string& prop) const { cmProp retVal = this->Properties.GetPropertyValue(prop); if (!retVal) { @@ -40,12 +40,12 @@ const char* cmTest::GetProperty(const std::string& prop) const this->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TEST); if (chain) { if (cmProp p = this->Makefile->GetProperty(prop, chain)) { - return p->c_str(); + return p; } } return nullptr; } - return retVal->c_str(); + return retVal; } bool cmTest::GetPropertyAsBool(const std::string& prop) const diff --git a/Source/cmTest.h b/Source/cmTest.h index f33b7e2..63e5e87 100644 --- a/Source/cmTest.h +++ b/Source/cmTest.h @@ -8,6 +8,7 @@ #include <vector> #include "cmListFileCache.h" +#include "cmProperty.h" #include "cmPropertyMap.h" class cmMakefile; @@ -36,7 +37,7 @@ public: void SetProperty(const std::string& prop, const char* value); void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); - const char* GetProperty(const std::string& prop) const; + cmProp GetProperty(const std::string& prop) const; bool GetPropertyAsBool(const std::string& prop) const; cmPropertyMap& GetProperties() { return this->Properties; } diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 056696d..cfea4cf 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -18,6 +18,10 @@ #include <cstring> #include <sstream> +#ifdef __MINGW32__ +# include <libloaderapi.h> +#endif + #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -159,6 +163,7 @@ std::string cmTimestamp::AddTimestampComponent(char flag, case 'M': case 'S': case 'U': + case 'V': case 'w': case 'y': case 'Y': @@ -187,6 +192,24 @@ std::string cmTimestamp::AddTimestampComponent(char flag, } } +#ifdef __MINGW32__ + /* See a bug in MinGW: https://sourceforge.net/p/mingw-w64/bugs/793/. A work + * around is to try to use strftime() from ucrtbase.dll. */ + using T = size_t(WINAPI*)(char*, size_t, const char*, const struct tm*); + auto loadStrftime = [] { + auto handle = + LoadLibraryExA("ucrtbase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (handle) { +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-function-type" + return reinterpret_cast<T>(GetProcAddress(handle, "strftime")); +# pragma GCC diagnostic pop + } + return strftime; + }; + static T strftime = loadStrftime(); +#endif + char buffer[16]; size_t size = diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index bda2f91..03d1bbb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -490,10 +490,7 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Element("Platform", this->Platform); cmProp projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL"); - if (!projLabel) { - projLabel = &this->Name; - } - e1.Element("ProjectName", *projLabel); + e1.Element("ProjectName", projLabel ? projLabel : this->Name); { cmProp targetFramework = this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK"); @@ -3543,8 +3540,6 @@ void cmVisualStudio10TargetGenerator::WriteNasmOptions( } Elem e2(e1, "NASM"); - std::vector<std::string> includes = - this->GetIncludes(configName, "ASM_NASM"); OptionsHelper nasmOptions(*(this->NasmOptions[configName]), e2); nasmOptions.OutputAdditionalIncludeDirectories("ASM_NASM"); nasmOptions.OutputFlagMap(); diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 327c1c7..b8297ce 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -16,13 +16,14 @@ #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmOutputConverter.h" #include "cmSystemTools.h" #include "cmake.h" class cmWhileFunctionBlocker : public cmFunctionBlocker { public: - cmWhileFunctionBlocker(cmMakefile* mf); + cmWhileFunctionBlocker(cmMakefile* mf, std::vector<cmListFileArgument> args); ~cmWhileFunctionBlocker() override; cm::string_view StartCommandName() const override { return "while"_s; } @@ -34,14 +35,15 @@ public: bool Replay(std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus) override; - std::vector<cmListFileArgument> Args; - private: cmMakefile* Makefile; + std::vector<cmListFileArgument> Args; }; -cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf) - : Makefile(mf) +cmWhileFunctionBlocker::cmWhileFunctionBlocker( + cmMakefile* const mf, std::vector<cmListFileArgument> args) + : Makefile{ mf } + , Args{ std::move(args) } { this->Makefile->PushLoopBlock(); } @@ -60,39 +62,29 @@ bool cmWhileFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus) { - cmMakefile& mf = inStatus.GetMakefile(); - std::string errorString; - - std::vector<cmExpandedCommandArgument> expandedArguments; - mf.ExpandArguments(this->Args, expandedArguments); - MessageType messageType; + auto& mf = inStatus.GetMakefile(); cmListFileBacktrace whileBT = mf.GetBacktrace().Push(this->GetStartingContext()); - cmConditionEvaluator conditionEvaluator(mf, whileBT); - - 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.GetCMakeInstance()->IssueMessage(messageType, err, whileBT); - if (messageType == MessageType::FATAL_ERROR) { - cmSystemTools::SetFatalErrorOccured(); - return true; - } - } + std::vector<cmExpandedCommandArgument> expandedArguments; + // At least same size expected for `expandedArguments` as `Args` + expandedArguments.reserve(this->Args.size()); + + auto expandArgs = [&mf](std::vector<cmListFileArgument> const& args, + std::vector<cmExpandedCommandArgument>& out) + -> std::vector<cmExpandedCommandArgument>& { + out.clear(); + mf.ExpandArguments(args, out); + return out; + }; + + std::string errorString; + MessageType messageType; + + for (cmConditionEvaluator conditionEvaluator(mf, whileBT); + conditionEvaluator.IsTrue(expandArgs(this->Args, expandedArguments), + errorString, messageType);) { // Invoke all the functions that were collected in the block. for (cmListFileFunction const& fn : functions) { cmExecutionStatus status(mf); @@ -111,11 +103,22 @@ bool cmWhileFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, return true; } } - expandedArguments.clear(); - mf.ExpandArguments(this->Args, expandedArguments); - isTrue = - conditionEvaluator.IsTrue(expandedArguments, errorString, messageType); } + + if (!errorString.empty()) { + std::string err = "had incorrect arguments:\n "; + for (auto const& i : expandedArguments) { + err += " "; + err += cmOutputConverter::EscapeForCMake(i.GetValue()); + } + err += "\n"; + err += errorString; + mf.GetCMakeInstance()->IssueMessage(messageType, err, whileBT); + if (messageType == MessageType::FATAL_ERROR) { + cmSystemTools::SetFatalErrorOccured(); + } + } + return true; } @@ -128,11 +131,9 @@ bool cmWhileCommand(std::vector<cmListFileArgument> const& args, } // create a function blocker - { - cmMakefile& makefile = status.GetMakefile(); - auto fb = cm::make_unique<cmWhileFunctionBlocker>(&makefile); - fb->Args = args; - makefile.AddFunctionBlocker(std::move(fb)); - } + auto& makefile = status.GetMakefile(); + makefile.AddFunctionBlocker( + cm::make_unique<cmWhileFunctionBlocker>(&makefile, args)); + return true; } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 73f5ad5..7f8f654 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -114,7 +114,9 @@ # include "cmExtraSublimeTextGenerator.h" #endif -#if defined(__linux__) || defined(_WIN32) +// NOTE: the __linux__ macro is predefined on Android host too, but +// main CMakeLists.txt filters out this generator by host name. +#if (defined(__linux__) && !defined(__ANDROID__)) || defined(_WIN32) # include "cmGlobalGhsMultiGenerator.h" #endif @@ -156,17 +158,16 @@ static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, } #endif -cmake::cmake(Role role, cmState::Mode mode) +cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) : CMakeWorkingDirectory(cmSystemTools::GetCurrentWorkingDirectory()) , FileTimeCache(cm::make_unique<cmFileTimeCache>()) #ifndef CMAKE_BOOTSTRAP , VariableWatch(cm::make_unique<cmVariableWatch>()) #endif - , State(cm::make_unique<cmState>()) + , State(cm::make_unique<cmState>(mode, projectKind)) , Messenger(cm::make_unique<cmMessenger>()) { this->TraceFile.close(); - this->State->SetMode(mode); this->CurrentSnapshot = this->State->CreateBaseSnapshot(); #ifdef __APPLE__ @@ -1843,7 +1844,7 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) std::vector<std::string> argsSplit = cmExpandedList(var, true); // erase the property to avoid infinite recursion this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", ""); - if (this->State->GetIsInTryCompile()) { + if (this->GetIsInTryCompile()) { return 0; } std::vector<SaveCacheEntry> saved; @@ -2111,7 +2112,7 @@ int cmake::ActualConfigure() // reset any system configuration information, except for when we are // InTryCompile. With TryCompile the system info is taken from the parent's // info to save time - if (!this->State->GetIsInTryCompile()) { + if (!this->GetIsInTryCompile()) { this->GlobalGenerator->ClearEnabledLanguages(); this->TruncateOutputLog("CMakeOutput.log"); @@ -2529,7 +2530,7 @@ void cmake::AddDefaultGenerators() this->Generators.push_back(cmGlobalMinGWMakefileGenerator::NewFactory()); #endif #if !defined(CMAKE_BOOTSTRAP) -# if defined(__linux__) || defined(_WIN32) +# if (defined(__linux__) && !defined(__ANDROID__)) || defined(_WIN32) this->Generators.push_back(cmGlobalGhsMultiGenerator::NewFactory()); # endif this->Generators.push_back(cmGlobalUnixMakefileGenerator3::NewFactory()); @@ -2622,19 +2623,14 @@ void cmake::SetProgressCallback(ProgressCallbackType f) void cmake::UpdateProgress(const std::string& msg, float prog) { - if (this->ProgressCallback && !this->State->GetIsInTryCompile()) { + if (this->ProgressCallback && !this->GetIsInTryCompile()) { this->ProgressCallback(msg, prog); } } bool cmake::GetIsInTryCompile() const { - return this->State->GetIsInTryCompile(); -} - -void cmake::SetIsInTryCompile(bool b) -{ - this->State->SetIsInTryCompile(b); + return this->State->GetProjectKind() == cmState::ProjectKind::TryCompile; } void cmake::AppendGlobalGeneratorsDocumentation( diff --git a/Source/cmake.h b/Source/cmake.h index 5a2a88f..12cce7e 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -168,7 +168,8 @@ public: static const int DEFAULT_BUILD_PARALLEL_LEVEL = 0; /// Default constructor - cmake(Role role, cmState::Mode mode); + cmake(Role role, cmState::Mode mode, + cmState::ProjectKind projectKind = cmState::ProjectKind::Normal); /// Destructor ~cmake(); @@ -356,7 +357,6 @@ public: //! Is this cmake running as a result of a TRY_COMPILE command bool GetIsInTryCompile() const; - void SetIsInTryCompile(bool b); #ifndef CMAKE_BOOTSTRAP void SetWarningFromPreset(const std::string& name, diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 1f4c0b8..1e0f497 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -385,18 +385,15 @@ int HandleTidy(const std::string& runCmd, const std::string& sourceFile, return ret; } -int HandleLWYU(const std::string& runCmd, const std::string& /* sourceFile */, +int HandleLWYU(const std::string& runCmd, const std::string& sourceFile, const std::vector<std::string>&) { // Construct the ldd -r -u (link what you use lwyu) command line // ldd -u -r lwuy target - std::vector<std::string> lwyu_cmd; - lwyu_cmd.emplace_back("ldd"); - lwyu_cmd.emplace_back("-u"); - lwyu_cmd.emplace_back("-r"); - lwyu_cmd.push_back(runCmd); + std::vector<std::string> lwyu_cmd = cmExpandedList(runCmd, true); + lwyu_cmd.push_back(sourceFile); - // Run the ldd -u -r command line. + // Run the lwyu check command line, currently ldd is expected. // Capture its stdout and hide its stderr. // Ignore its return code because the tool always returns non-zero // if there are any warnings, but we just want to warn. |