diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2021-01-11 19:46:12 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2021-01-11 20:00:51 (GMT) |
commit | 9f48a468cd68d69e16302174ff202e9e51035023 (patch) | |
tree | 2fe4a4c3ba4b9eb2d6996014536faebd2036e458 /Source | |
parent | e20560a2dc9668bb9fd55bea79ef7508ab72c746 (diff) | |
parent | 06dfa5a7b6c0174bfcb4691a9aaf00809bd7271d (diff) | |
download | CMake-9f48a468cd68d69e16302174ff202e9e51035023.zip CMake-9f48a468cd68d69e16302174ff202e9e51035023.tar.gz CMake-9f48a468cd68d69e16302174ff202e9e51035023.tar.bz2 |
Merge branch 'master' into cmake-gui-qrc-fix
Diffstat (limited to 'Source')
228 files changed, 8670 insertions, 8437 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index ca56d3a..c5b67c0 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -181,8 +181,6 @@ set(SRCS cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h cmCacheManager.cxx cmCacheManager.h - cmCheckCustomOutputs.h - cmCheckCustomOutputs.cxx cmCLocaleEnvironmentScope.h cmCLocaleEnvironmentScope.cxx cmCMakePath.h @@ -227,6 +225,8 @@ set(SRCS cmDependsJava.h cmDependsJavaParserHelper.cxx cmDependsJavaParserHelper.h + cmDependsCompiler.cxx + cmDependsCompiler.h cmDocumentation.cxx cmDocumentationFormatter.cxx cmDocumentationSection.cxx @@ -444,6 +444,8 @@ set(SRCS cmTest.h cmTestGenerator.cxx cmTestGenerator.h + cmTransformDepfile.cxx + cmTransformDepfile.h cmUuid.cxx cmUVHandlePtr.cxx cmUVHandlePtr.h @@ -508,6 +510,8 @@ set(SRCS cmCMakeLanguageCommand.h cmCMakeMinimumRequired.cxx cmCMakeMinimumRequired.h + cmCMakePathCommand.h + cmCMakePathCommand.cxx cmCMakePolicyCommand.cxx cmCMakePolicyCommand.h cmConditionEvaluator.cxx @@ -833,6 +837,7 @@ endif() # Ninja support set(SRCS ${SRCS} + cmScanDepFormat.cxx cmGlobalNinjaGenerator.cxx cmGlobalNinjaGenerator.h cmNinjaTypes.h @@ -1157,20 +1162,6 @@ add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE}) list(APPEND _tools cmake) target_link_libraries(cmake CMakeLib) -add_library(CMakeServerLib - cmConnection.h cmConnection.cxx - cmFileMonitor.cxx cmFileMonitor.h - cmJsonObjectDictionary.h - cmJsonObjects.h - cmJsonObjects.cxx - cmPipeConnection.cxx cmPipeConnection.h - cmServer.cxx cmServer.h - cmServerConnection.cxx cmServerConnection.h - cmServerProtocol.cxx cmServerProtocol.h - ) -target_link_libraries(CMakeServerLib CMakeLib) -target_link_libraries(cmake CMakeServerLib) - # Build CTest executable add_executable(ctest ctest.cxx ${MANIFEST_FILE}) list(APPEND _tools ctest) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 799b2fc..a92003f 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 19) -set(CMake_VERSION_PATCH 2) +set(CMake_VERSION_PATCH 20210111) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index 4bad598..359fc56 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -66,7 +66,7 @@ void cmCPackIFWInstaller::ConfigureFromOptions() this->GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) { this->Publisher = optIFW_PACKAGE_PUBLISHER; } else if (const char* optPACKAGE_VENDOR = - GetOption("CPACK_PACKAGE_VENDOR")) { + this->GetOption("CPACK_PACKAGE_VENDOR")) { this->Publisher = optPACKAGE_VENDOR; } @@ -174,6 +174,26 @@ void cmCPackIFWInstaller::ConfigureFromOptions() this->WizardDefaultHeight = option; } + // WizardShowPageList + if (const char* option = + this->GetOption("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) { + if (!this->IsVersionLess("4.0")) { + if (this->IsSetToOff("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) { + this->WizardShowPageList = "false"; + } else if (this->IsOn("CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST")) { + this->WizardShowPageList = "true"; + } else { + this->WizardShowPageList.clear(); + } + } else { + cmCPackIFWLogger( + WARNING, + "Option CPACK_IFW_PACKAGE_WIZARD_SHOW_PAGE_LIST is set to value \"" + << option << "\". But has no any effect for QtIFW less than 4.0 " + << "and will be skipped." << std::endl); + } + } + // TitleColor if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_TITLE_COLOR")) { this->TitleColor = option; @@ -184,7 +204,7 @@ void cmCPackIFWInstaller::ConfigureFromOptions() this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) { this->StartMenuDir = optIFW_START_MENU_DIR; } else { - this->StartMenuDir = Name; + this->StartMenuDir = this->Name; } // Default target directory for installation @@ -283,7 +303,7 @@ protected: void StartElement(const std::string& name, const char** /*atts*/) override { this->file = name == "file"; - if (file) { + if (this->file) { this->hasFiles = true; } } @@ -317,7 +337,7 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.StartDocument(); - WriteGeneratedByToStrim(xout); + this->WriteGeneratedByToStrim(xout); xout.StartElement("Installer"); @@ -408,6 +428,11 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.Element("WizardDefaultHeight", this->WizardDefaultHeight); } + // WizardShowPageList + if (!this->IsVersionLess("4.0") && !this->WizardShowPageList.empty()) { + xout.Element("WizardShowPageList", this->WizardShowPageList); + } + // TitleColor if (!this->TitleColor.empty()) { xout.Element("TitleColor", this->TitleColor); @@ -510,7 +535,7 @@ void cmCPackIFWInstaller::GeneratePackageFiles() package.ConfigureFromGroup(option); std::string forcedOption = "CPACK_IFW_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(option) + "_FORCED_INSTALLATION"; - if (!GetOption(forcedOption)) { + if (!this->GetOption(forcedOption)) { package.ForcedInstallation = "true"; } } else { diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h index 6f398e3..a031fc2 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.h +++ b/Source/CPack/IFW/cmCPackIFWInstaller.h @@ -80,6 +80,10 @@ public: /// Wizard height std::string WizardDefaultHeight; + /// Set to false if the widget listing installer pages on the left side + /// of the wizard should not be shown + std::string WizardShowPageList; + /// Title color std::string TitleColor; diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx index 56a74c5..c4bd7f1 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.cxx +++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx @@ -337,7 +337,7 @@ int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName) group.Name = groupName; - if (Generator) { + if (this->Generator) { this->Name = this->Generator->GetGroupPackageName(&group); } else { this->Name = group.Name; @@ -530,7 +530,7 @@ void cmCPackIFWPackage::GeneratePackageFile() xout.StartDocument(); - WriteGeneratedByToStrim(xout); + this->WriteGeneratedByToStrim(xout); xout.StartElement("Package"); @@ -577,7 +577,7 @@ void cmCPackIFWPackage::GeneratePackageFile() } // User Interfaces (copy to meta dir) - std::vector<std::string> userInterfaces = UserInterfaces; + std::vector<std::string> userInterfaces = this->UserInterfaces; for (std::string& userInterface : userInterfaces) { std::string name = cmSystemTools::GetFilenameName(userInterface); std::string path = this->Directory + "/meta/" + name; @@ -593,7 +593,7 @@ void cmCPackIFWPackage::GeneratePackageFile() } // Translations (copy to meta dir) - std::vector<std::string> translations = Translations; + std::vector<std::string> translations = this->Translations; for (std::string& translation : translations) { std::string name = cmSystemTools::GetFilenameName(translation); std::string path = this->Directory + "/meta/" + name; diff --git a/Source/CPack/IFW/cmCPackIFWPackage.h b/Source/CPack/IFW/cmCPackIFWPackage.h index dbd5540..0cc6f2f 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.h +++ b/Source/CPack/IFW/cmCPackIFWPackage.h @@ -53,7 +53,7 @@ public: bool operator<(const DependenceStruct& other) const { - return Name < other.Name; + return this->Name < other.Name; } }; diff --git a/Source/CPack/IFW/cmCPackIFWRepository.cxx b/Source/CPack/IFW/cmCPackIFWRepository.cxx index f5e8744..1287907 100644 --- a/Source/CPack/IFW/cmCPackIFWRepository.cxx +++ b/Source/CPack/IFW/cmCPackIFWRepository.cxx @@ -46,9 +46,9 @@ bool cmCPackIFWRepository::ConfigureFromOptions() // Update if (this->IsOn(prefix + "ADD")) { this->Update = cmCPackIFWRepository::Add; - } else if (IsOn(prefix + "REMOVE")) { + } else if (this->IsOn(prefix + "REMOVE")) { this->Update = cmCPackIFWRepository::Remove; - } else if (IsOn(prefix + "REPLACE")) { + } else if (this->IsOn(prefix + "REPLACE")) { this->Update = cmCPackIFWRepository::Replace; } else { this->Update = cmCPackIFWRepository::None; @@ -247,7 +247,7 @@ void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout) if (this->Update == cmCPackIFWRepository::Add || this->Update == cmCPackIFWRepository::Remove) { xout.Attribute("url", this->Url); - } else if (Update == cmCPackIFWRepository::Replace) { + } else if (this->Update == cmCPackIFWRepository::Replace) { xout.Attribute("oldUrl", this->OldUrl); xout.Attribute("newUrl", this->NewUrl); } diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 967cc60..5348f86 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -80,10 +80,10 @@ std::string cmCPackArchiveGenerator::GetArchiveComponentFileName( packageFileName += this->GetOption("CPACK_ARCHIVE_" + componentUpper + "_FILE_NAME"); } else if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) { - packageFileName += GetComponentPackageFileName( + packageFileName += this->GetComponentPackageFileName( this->GetOption("CPACK_ARCHIVE_FILE_NAME"), component, isGroupName); } else { - packageFileName += GetComponentPackageFileName( + packageFileName += this->GetComponentPackageFileName( this->GetOption("CPACK_PACKAGE_FILE_NAME"), component, isGroupName); } @@ -181,7 +181,7 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) { - packageFileNames.clear(); + this->packageFileNames.clear(); // The default behavior is to have one package by component group // unless CPACK_COMPONENTS_IGNORE_GROUP is specified. if (!ignoreGroup) { @@ -189,7 +189,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: " << compG.first << std::endl); // Begin the archive for this group - std::string packageFileName = std::string(toplevel) + "/" + + std::string packageFileName = std::string(this->toplevel) + "/" + this->GetArchiveComponentFileName(compG.first, true); // open a block in order to automatically close archive @@ -199,11 +199,11 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) // now iterate over the component of this group for (cmCPackComponent* comp : (compG.second).Components) { // Add the files of this component to the archive - addOneComponentToArchive(archive, comp); + this->addOneComponentToArchive(archive, comp); } } // add the generated package to package file names list - packageFileNames.push_back(std::move(packageFileName)); + this->packageFileNames.push_back(std::move(packageFileName)); } // Handle Orphan components (components not belonging to any groups) for (auto& comp : this->Components) { @@ -217,7 +217,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) << std::endl); std::string localToplevel( this->GetOption("CPACK_TEMPORARY_DIRECTORY")); - std::string packageFileName = std::string(toplevel); + std::string packageFileName = std::string(this->toplevel); localToplevel += "/" + comp.first; packageFileName += @@ -226,10 +226,10 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) { DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive); // Add the files of this component to the archive - addOneComponentToArchive(archive, &(comp.second)); + this->addOneComponentToArchive(archive, &(comp.second)); } // add the generated package to package file names list - packageFileNames.push_back(std::move(packageFileName)); + this->packageFileNames.push_back(std::move(packageFileName)); } } } @@ -238,7 +238,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) else { for (auto& comp : this->Components) { std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); - std::string packageFileName = std::string(toplevel); + std::string packageFileName = std::string(this->toplevel); localToplevel += "/" + comp.first; packageFileName += @@ -247,10 +247,10 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) { DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive); // Add the files of this component to the archive - addOneComponentToArchive(archive, &(comp.second)); + this->addOneComponentToArchive(archive, &(comp.second)); } // add the generated package to package file names list - packageFileNames.push_back(std::move(packageFileName)); + this->packageFileNames.push_back(std::move(packageFileName)); } } return 1; @@ -259,17 +259,17 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) int cmCPackArchiveGenerator::PackageComponentsAllInOne() { // reset the package file names - packageFileNames.clear(); - packageFileNames.emplace_back(toplevel); - packageFileNames[0] += "/"; + this->packageFileNames.clear(); + this->packageFileNames.emplace_back(this->toplevel); + this->packageFileNames[0] += "/"; if (this->IsSet("CPACK_ARCHIVE_FILE_NAME")) { - packageFileNames[0] += this->GetOption("CPACK_ARCHIVE_FILE_NAME"); + this->packageFileNames[0] += this->GetOption("CPACK_ARCHIVE_FILE_NAME"); } else { - packageFileNames[0] += this->GetOption("CPACK_PACKAGE_FILE_NAME"); + this->packageFileNames[0] += this->GetOption("CPACK_PACKAGE_FILE_NAME"); } - packageFileNames[0] += this->GetOutputExtension(); + this->packageFileNames[0] += this->GetOutputExtension(); cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging all groups in one package..." @@ -280,7 +280,7 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne() // The ALL COMPONENTS in ONE package case for (auto& comp : this->Components) { // Add the files of this component to the archive - addOneComponentToArchive(archive, &(comp.second)); + this->addOneComponentToArchive(archive, &(comp.second)); } // archive goes out of scope so it will finalized and closed. @@ -289,41 +289,42 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne() int cmCPackArchiveGenerator::PackageFiles() { - cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Toplevel: " << this->toplevel << std::endl); - if (WantsComponentInstallation()) { + if (this->WantsComponentInstallation()) { // CASE 1 : COMPONENT ALL-IN-ONE package // If ALL COMPONENTS in ONE package has been requested // then the package file is unique and should be open here. - if (componentPackageMethod == ONE_PACKAGE) { - return PackageComponentsAllInOne(); + if (this->componentPackageMethod == ONE_PACKAGE) { + return this->PackageComponentsAllInOne(); } // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one) // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - return PackageComponents(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); + return this->PackageComponents(this->componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } // CASE 3 : NON COMPONENT package. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive); - cmWorkingDirectory workdir(toplevel); + cmWorkingDirectory workdir(this->toplevel); if (workdir.Failed()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed to change working directory to " - << toplevel << " : " + << this->toplevel << " : " << std::strerror(workdir.GetLastResult()) << std::endl); return 0; } - for (std::string const& file : files) { + for (std::string const& file : this->files) { // Get the relative path to the file - std::string rp = cmSystemTools::RelativePath(toplevel, file); + std::string rp = cmSystemTools::RelativePath(this->toplevel, file); archive.Add(rp, 0, nullptr, false); if (!archive) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem while adding file <" - << file << "> to archive <" << packageFileNames[0] + << file << "> to archive <" << this->packageFileNames[0] << ">, ERROR = " << archive.GetError() << std::endl); return 0; } @@ -342,7 +343,7 @@ bool cmCPackArchiveGenerator::SupportsComponentInstallation() const // The Component installation support should only // be activated if explicitly requested by the user // (for backward compatibility reason) - return IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL"); + return this->IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL"); } bool cmCPackArchiveGenerator::SetArchiveOptions(cmArchiveWrite* archive) diff --git a/Source/CPack/cmCPackComponentGroup.cxx b/Source/CPack/cmCPackComponentGroup.cxx index d40e5fc..4305c7e 100644 --- a/Source/CPack/cmCPackComponentGroup.cxx +++ b/Source/CPack/cmCPackComponentGroup.cxx @@ -25,6 +25,6 @@ unsigned long cmCPackComponent::GetInstalledSize( unsigned long cmCPackComponent::GetInstalledSizeInKbytes( const std::string& installDir) const { - unsigned long result = (GetInstalledSize(installDir) + 512) / 1024; + unsigned long result = (this->GetInstalledSize(installDir) + 512) / 1024; return result ? result : 1; } diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 560e5c1..43dbdb5 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -96,20 +96,20 @@ DebGenerator::DebGenerator( } if (!strcmp(debianCompressionType, "lzma")) { - CompressionSuffix = ".lzma"; - TarCompressionType = cmArchiveWrite::CompressLZMA; + this->CompressionSuffix = ".lzma"; + this->TarCompressionType = cmArchiveWrite::CompressLZMA; } else if (!strcmp(debianCompressionType, "xz")) { - CompressionSuffix = ".xz"; - TarCompressionType = cmArchiveWrite::CompressXZ; + this->CompressionSuffix = ".xz"; + this->TarCompressionType = cmArchiveWrite::CompressXZ; } else if (!strcmp(debianCompressionType, "bzip2")) { - CompressionSuffix = ".bz2"; - TarCompressionType = cmArchiveWrite::CompressBZip2; + this->CompressionSuffix = ".bz2"; + this->TarCompressionType = cmArchiveWrite::CompressBZip2; } else if (!strcmp(debianCompressionType, "gzip")) { - CompressionSuffix = ".gz"; - TarCompressionType = cmArchiveWrite::CompressGZip; + this->CompressionSuffix = ".gz"; + this->TarCompressionType = cmArchiveWrite::CompressGZip; } else if (!strcmp(debianCompressionType, "none")) { - CompressionSuffix.clear(); - TarCompressionType = cmArchiveWrite::CompressNone; + this->CompressionSuffix.clear(); + this->TarCompressionType = cmArchiveWrite::CompressNone; } else { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error unrecognized compression type: " @@ -119,22 +119,22 @@ DebGenerator::DebGenerator( bool DebGenerator::generate() const { - generateDebianBinaryFile(); - generateControlFile(); - if (!generateDataTar()) { + this->generateDebianBinaryFile(); + this->generateControlFile(); + if (!this->generateDataTar()) { return false; } - std::string md5Filename = generateMD5File(); - if (!generateControlTar(md5Filename)) { + std::string md5Filename = this->generateMD5File(); + if (!this->generateControlTar(md5Filename)) { return false; } - return generateDeb(); + return this->generateDeb(); } void DebGenerator::generateDebianBinaryFile() const { // debian-binary file - const std::string dbfilename = WorkDir + "/debian-binary"; + const std::string dbfilename = this->WorkDir + "/debian-binary"; cmGeneratedFileStream out; out.Open(dbfilename, false, true); out << "2.0\n"; // required for valid debian package @@ -142,18 +142,18 @@ void DebGenerator::generateDebianBinaryFile() const void DebGenerator::generateControlFile() const { - std::string ctlfilename = WorkDir + "/control"; + std::string ctlfilename = this->WorkDir + "/control"; cmGeneratedFileStream out; out.Open(ctlfilename, false, true); - for (auto const& kv : ControlValues) { + for (auto const& kv : this->ControlValues) { out << kv.first << ": " << kv.second << "\n"; } unsigned long totalSize = 0; { - std::string dirName = cmStrCat(TemporaryDir, '/'); - for (std::string const& file : PackageFiles) { + std::string dirName = cmStrCat(this->TemporaryDir, '/'); + for (std::string const& file : this->PackageFiles) { totalSize += cmSystemTools::FileLength(file); } } @@ -162,7 +162,8 @@ void DebGenerator::generateControlFile() const bool DebGenerator::generateDataTar() const { - std::string filename_data_tar = WorkDir + "/data.tar" + CompressionSuffix; + std::string filename_data_tar = + this->WorkDir + "/data.tar" + this->CompressionSuffix; cmGeneratedFileStream fileStream_data_tar; fileStream_data_tar.Open(filename_data_tar, false, true); if (!fileStream_data_tar) { @@ -171,8 +172,8 @@ bool DebGenerator::generateDataTar() const << filename_data_tar << "\" for writing" << std::endl); return false; } - cmArchiveWrite data_tar(fileStream_data_tar, TarCompressionType, - DebianArchiveType); + cmArchiveWrite data_tar(fileStream_data_tar, this->TarCompressionType, + this->DebianArchiveType); data_tar.Open(); // uid/gid should be the one of the root user, and this root user has @@ -184,16 +185,16 @@ bool DebGenerator::generateDataTar() const // collect all top level install dirs for that // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would // give /usr and /opt - size_t topLevelLength = WorkDir.length(); + size_t topLevelLength = this->WorkDir.length(); cmCPackLogger(cmCPackLog::LOG_DEBUG, - "WDIR: \"" << WorkDir << "\", length = " << topLevelLength - << std::endl); + "WDIR: \"" << this->WorkDir + << "\", length = " << topLevelLength << std::endl); std::set<std::string> orderedFiles; // we have to reconstruct the parent folders as well - for (std::string currentPath : PackageFiles) { - while (currentPath != WorkDir) { + for (std::string currentPath : this->PackageFiles) { + while (currentPath != this->WorkDir) { // the last one IS WorkDir, but we do not want this one: // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application // should not add XXX/application @@ -235,7 +236,7 @@ bool DebGenerator::generateDataTar() const cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem adding file to tar:" << std::endl - << "#top level directory: " << WorkDir << std::endl + << "#top level directory: " << this->WorkDir << std::endl << "#file: " << file << std::endl << "#error:" << data_tar.GetError() << std::endl); return false; @@ -246,13 +247,13 @@ bool DebGenerator::generateDataTar() const std::string DebGenerator::generateMD5File() const { - std::string md5filename = WorkDir + "/md5sums"; + std::string md5filename = this->WorkDir + "/md5sums"; cmGeneratedFileStream out; out.Open(md5filename, false, true); - std::string topLevelWithTrailingSlash = cmStrCat(TemporaryDir, '/'); - for (std::string const& file : PackageFiles) { + std::string topLevelWithTrailingSlash = cmStrCat(this->TemporaryDir, '/'); + for (std::string const& file : this->PackageFiles) { // hash only regular files if (cmSystemTools::FileIsDirectory(file) || cmSystemTools::FileIsSymlink(file)) { @@ -281,7 +282,7 @@ std::string DebGenerator::generateMD5File() const bool DebGenerator::generateControlTar(std::string const& md5Filename) const { - std::string filename_control_tar = WorkDir + "/control.tar.gz"; + std::string filename_control_tar = this->WorkDir + "/control.tar.gz"; cmGeneratedFileStream fileStream_control_tar; fileStream_control_tar.Open(filename_control_tar, false, true); @@ -292,7 +293,8 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const return false; } cmArchiveWrite control_tar(fileStream_control_tar, - cmArchiveWrite::CompressGZip, DebianArchiveType); + cmArchiveWrite::CompressGZip, + this->DebianArchiveType); control_tar.Open(); // sets permissions and uid/gid for the files @@ -314,24 +316,25 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const control_tar.SetPermissions(permission644); // adds control and md5sums - if (!control_tar.Add(md5Filename, WorkDir.length(), ".") || - !control_tar.Add(WorkDir + "/control", WorkDir.length(), ".")) { + if (!control_tar.Add(md5Filename, this->WorkDir.length(), ".") || + !control_tar.Add(this->WorkDir + "/control", this->WorkDir.length(), + ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:" << std::endl - << "#top level directory: " << WorkDir << std::endl + << "#top level directory: " << this->WorkDir << std::endl << "#file: \"control\" or \"md5sums\"" << std::endl << "#error:" << control_tar.GetError() << std::endl); return false; } // adds generated shlibs file - if (GenShLibs) { - if (!control_tar.Add(ShLibsFilename, WorkDir.length(), ".")) { + 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: " << WorkDir << std::endl + << "#top level directory: " << this->WorkDir << std::endl << "#file: \"shlibs\"" << std::endl << "#error:" << control_tar.GetError() << std::endl); return false; @@ -339,13 +342,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const } // adds LDCONFIG related files - if (GenPostInst) { + if (this->GenPostInst) { control_tar.SetPermissions(permission755); - if (!control_tar.Add(PostInst, WorkDir.length(), ".")) { + if (!control_tar.Add(this->PostInst, this->WorkDir.length(), ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:" << std::endl - << "#top level directory: " << WorkDir << std::endl + << "#top level directory: " << this->WorkDir << std::endl << "#file: \"postinst\"" << std::endl << "#error:" << control_tar.GetError() << std::endl); return false; @@ -353,13 +356,13 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const control_tar.SetPermissions(permission644); } - if (GenPostRm) { + if (this->GenPostRm) { control_tar.SetPermissions(permission755); - if (!control_tar.Add(PostRm, WorkDir.length(), ".")) { + if (!control_tar.Add(this->PostRm, this->WorkDir.length(), ".")) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:" << std::endl - << "#top level directory: " << WorkDir << std::endl + << "#top level directory: " << this->WorkDir << std::endl << "#file: \"postinst\"" << std::endl << "#error:" << control_tar.GetError() << std::endl); return false; @@ -370,7 +373,7 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const // for the other files, we use // -either the original permission on the files // -either a permission strictly defined by the Debian policies - if (ControlExtra) { + if (this->ControlExtra) { // permissions are now controlled by the original file permissions static const char* strictFiles[] = { "config", "postinst", "postrm", @@ -381,19 +384,20 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const // default control_tar.ClearPermissions(); - std::vector<std::string> controlExtraList = cmExpandedList(ControlExtra); + std::vector<std::string> controlExtraList = + cmExpandedList(this->ControlExtra); for (std::string const& i : controlExtraList) { std::string filenamename = cmsys::SystemTools::GetFilenameName(i); - std::string localcopy = WorkDir + "/" + filenamename; + std::string localcopy = this->WorkDir + "/" + filenamename; - if (PermissionStrictPolicy) { + if (this->PermissionStrictPolicy) { control_tar.SetPermissions( setStrictFiles.count(filenamename) ? permission755 : permission644); } // if we can copy the file, it means it does exist, let's add it: if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) { - control_tar.Add(localcopy, WorkDir.length(), "."); + control_tar.Add(localcopy, this->WorkDir.length(), "."); } } } @@ -408,8 +412,8 @@ bool DebGenerator::generateDeb() const // difference is that debian uses the BSD ar style archive whereas most // Linux distro have a GNU ar. // See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info - std::string const outputPath = TopLevelDir + "/" + OutputName; - std::string const tlDir = WorkDir + "/"; + std::string const outputPath = this->TopLevelDir + "/" + this->OutputName; + std::string const tlDir = this->WorkDir + "/"; cmGeneratedFileStream debStream; debStream.Open(outputPath, false, true); cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd"); @@ -422,12 +426,13 @@ bool DebGenerator::generateDeb() const if (!deb.Add(tlDir + "debian-binary", tlDir.length()) || !deb.Add(tlDir + "control.tar.gz", tlDir.length()) || - !deb.Add(tlDir + "data.tar" + CompressionSuffix, tlDir.length())) { + !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error creating debian package:" << std::endl - << "#top level directory: " << TopLevelDir << std::endl - << "#file: " << OutputName << std::endl + << "#top level directory: " << this->TopLevelDir + << std::endl + << "#file: " << this->OutputName << std::endl << "#error:" << deb.GetError() << std::endl); return false; } @@ -455,7 +460,8 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, int retval = 1; // Begin the archive for this pack std::string localToplevel(initialTopLevel); - std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel)); + std::string packageFileName( + cmSystemTools::GetParentDirectory(this->toplevel)); std::string outputFileName( std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" + packageName + this->GetOutputExtension()); @@ -495,19 +501,20 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, << std::endl); return 0; } - packageFiles = gl.GetFiles(); + this->packageFiles = gl.GetFiles(); } - int res = createDeb(); + 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")); - packageFileNames.push_back(std::move(packageFileName)); + this->packageFileNames.push_back(std::move(packageFileName)); - if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE")) { + if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE") && + this->GetOption("GEN_DBGSYMDIR")) { cmsys::Glob gl; std::string findExpr(this->GetOption("GEN_DBGSYMDIR")); findExpr += "/*"; @@ -520,9 +527,9 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, << std::endl); return 0; } - packageFiles = gl.GetFiles(); + this->packageFiles = gl.GetFiles(); - res = createDbgsymDDeb(); + res = this->createDbgsymDDeb(); if (res != 1) { retval = 0; } @@ -530,7 +537,7 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel, packageFileName = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), '/', this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME")); - packageFileNames.push_back(std::move(packageFileName)); + this->packageFileNames.push_back(std::move(packageFileName)); } return retval; @@ -541,7 +548,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup) int retval = 1; /* Reset package file name list it will be populated during the * component packaging run*/ - packageFileNames.clear(); + this->packageFileNames.clear(); std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); // The default behavior is to have one package by component group @@ -551,7 +558,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup) cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: " << compG.first << std::endl); // Begin the archive for this group - retval &= PackageOnePack(initialTopLevel, compG.first); + retval &= this->PackageOnePack(initialTopLevel, compG.first); } // Handle Orphan components (components not belonging to any groups) for (auto const& comp : this->Components) { @@ -564,7 +571,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup) << "> does not belong to any group, package it separately." << std::endl); // Begin the archive for this orphan component - retval &= PackageOnePack(initialTopLevel, comp.first); + retval &= this->PackageOnePack(initialTopLevel, comp.first); } } } @@ -572,7 +579,7 @@ int cmCPackDebGenerator::PackageComponents(bool ignoreGroup) // We build 1 package per component else { for (auto const& comp : this->Components) { - retval &= PackageOnePack(initialTopLevel, comp.first); + retval &= this->PackageOnePack(initialTopLevel, comp.first); } } return retval; @@ -585,7 +592,7 @@ int cmCPackDebGenerator::PackageComponentsAllInOne( int retval = 1; /* Reset package file name list it will be populated during the * component packaging run*/ - packageFileNames.clear(); + this->packageFileNames.clear(); std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); cmCPackLogger(cmCPackLog::LOG_VERBOSE, @@ -595,7 +602,8 @@ int cmCPackDebGenerator::PackageComponentsAllInOne( // The ALL GROUPS in ONE package case std::string localToplevel(initialTopLevel); - std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel)); + std::string packageFileName( + cmSystemTools::GetParentDirectory(this->toplevel)); std::string outputFileName( std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + this->GetOutputExtension()); @@ -640,38 +648,38 @@ int cmCPackDebGenerator::PackageComponentsAllInOne( << std::endl); return 0; } - packageFiles = gl.GetFiles(); + this->packageFiles = gl.GetFiles(); - int res = createDeb(); + 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")); - packageFileNames.push_back(std::move(packageFileName)); + this->packageFileNames.push_back(std::move(packageFileName)); return retval; } int cmCPackDebGenerator::PackageFiles() { /* Are we in the component packaging case */ - if (WantsComponentInstallation()) { + if (this->WantsComponentInstallation()) { // CASE 1 : COMPONENT ALL-IN-ONE package // If ALL GROUPS or ALL COMPONENTS in ONE package has been requested // then the package file is unique and should be open here. - if (componentPackageMethod == ONE_PACKAGE) { - return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE"); + if (this->componentPackageMethod == ONE_PACKAGE) { + return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE"); } // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one) // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - return PackageComponents(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); + return this->PackageComponents(this->componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } // CASE 3 : NON COMPONENT package. - return PackageComponentsAllInOne(""); + return this->PackageComponentsAllInOne(""); } int cmCPackDebGenerator::createDeb() @@ -786,7 +794,7 @@ int cmCPackDebGenerator::createDeb() } DebGenerator gen( - Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR, + this->Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR, this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), this->GetOption("CPACK_TEMPORARY_DIRECTORY"), this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"), @@ -795,7 +803,7 @@ int cmCPackDebGenerator::createDeb() this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM"), postrm, this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"), this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"), - packageFiles); + this->packageFiles); if (!gen.generate()) { return 0; @@ -841,7 +849,7 @@ int cmCPackDebGenerator::createDbgsymDDeb() } DebGenerator gen( - Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"), + this->Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"), this->GetOption("GEN_DBGSYMDIR"), this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), @@ -850,7 +858,7 @@ int cmCPackDebGenerator::createDbgsymDDeb() this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "", false, "", false, "", nullptr, this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"), - packageFiles); + this->packageFiles); if (!gen.generate()) { return 0; @@ -860,25 +868,25 @@ int cmCPackDebGenerator::createDbgsymDDeb() bool cmCPackDebGenerator::SupportsComponentInstallation() const { - return IsOn("CPACK_DEB_COMPONENT_INSTALL"); + return this->IsOn("CPACK_DEB_COMPONENT_INSTALL"); } std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix( const std::string& componentName) { - if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) { + if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) { return componentName; } - if (componentPackageMethod == ONE_PACKAGE) { + if (this->componentPackageMethod == ONE_PACKAGE) { return std::string("ALL_COMPONENTS_IN_ONE"); } // We have to find the name of the COMPONENT GROUP // the current COMPONENT belongs to. std::string groupVar = "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP"; - if (nullptr != GetOption(groupVar)) { - return std::string(GetOption(groupVar)); + if (nullptr != this->GetOption(groupVar)) { + return std::string(this->GetOption(groupVar)); } return componentName; } diff --git a/Source/CPack/cmCPackExternalGenerator.cxx b/Source/CPack/cmCPackExternalGenerator.cxx index 0bc8456..e3521a0 100644 --- a/Source/CPack/cmCPackExternalGenerator.cxx +++ b/Source/CPack/cmCPackExternalGenerator.cxx @@ -95,7 +95,7 @@ int cmCPackExternalGenerator::InstallProjectViaInstallCommands( bool setDestDir, const std::string& tempInstallDirectory) { if (this->StagingEnabled()) { - return cmCPackGenerator::InstallProjectViaInstallCommands( + return this->cmCPackGenerator::InstallProjectViaInstallCommands( setDestDir, tempInstallDirectory); } @@ -106,7 +106,7 @@ int cmCPackExternalGenerator::InstallProjectViaInstallScript( bool setDestDir, const std::string& tempInstallDirectory) { if (this->StagingEnabled()) { - return cmCPackGenerator::InstallProjectViaInstallScript( + return this->cmCPackGenerator::InstallProjectViaInstallScript( setDestDir, tempInstallDirectory); } @@ -118,7 +118,7 @@ int cmCPackExternalGenerator::InstallProjectViaInstalledDirectories( const mode_t* default_dir_mode) { if (this->StagingEnabled()) { - return cmCPackGenerator::InstallProjectViaInstalledDirectories( + return this->cmCPackGenerator::InstallProjectViaInstalledDirectories( setDestDir, tempInstallDirectory, default_dir_mode); } @@ -130,7 +130,7 @@ int cmCPackExternalGenerator::RunPreinstallTarget( cmGlobalGenerator* globalGenerator, const std::string& buildConfig) { if (this->StagingEnabled()) { - return cmCPackGenerator::RunPreinstallTarget( + return this->cmCPackGenerator::RunPreinstallTarget( installProjectName, installDirectory, globalGenerator, buildConfig); } @@ -145,7 +145,7 @@ int cmCPackExternalGenerator::InstallCMakeProject( std::string& absoluteDestFiles) { if (this->StagingEnabled()) { - return cmCPackGenerator::InstallCMakeProject( + return this->cmCPackGenerator::InstallCMakeProject( setDestDir, installDirectory, baseTempInstallDirectory, default_dir_mode, component, componentInstall, installSubDirectory, buildConfig, absoluteDestFiles); diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index a9fe91c..3db4162 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -60,18 +60,18 @@ int cmCPackGenerator::PrepareNames() cmCPackLogger(cmCPackLog::LOG_DEBUG, "Create temp directory." << std::endl); // checks CPACK_SET_DESTDIR support - if (IsOn("CPACK_SET_DESTDIR")) { - if (SETDESTDIR_UNSUPPORTED == SupportsSetDestdir()) { + if (this->IsOn("CPACK_SET_DESTDIR")) { + if (SETDESTDIR_UNSUPPORTED == this->SupportsSetDestdir()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_SET_DESTDIR is set to ON but the '" - << Name << "' generator does NOT support it." + << this->Name << "' generator does NOT support it." << std::endl); return 0; } - if (SETDESTDIR_SHOULD_NOT_BE_USED == SupportsSetDestdir()) { + if (SETDESTDIR_SHOULD_NOT_BE_USED == this->SupportsSetDestdir()) { cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_SET_DESTDIR is set to ON but it is " - << "usually a bad idea to do that with '" << Name + << "usually a bad idea to do that with '" << this->Name << "' generator. Use at your own risk." << std::endl); } } @@ -380,8 +380,8 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( << std::endl); return 0; } - files = gl.GetFiles(); - for (std::string const& gf : files) { + this->files = gl.GetFiles(); + for (std::string const& gf : this->files) { bool skip = false; std::string inFile = gf; if (cmSystemTools::FileIsDirectory(gf)) { @@ -763,7 +763,7 @@ int cmCPackGenerator::InstallCMakeProject( // one install directory for each component **GROUP** // instead of the default // one install directory for each component. - tempInstallDirectory += GetComponentInstallDirNameSuffix(component); + tempInstallDirectory += this->GetComponentInstallDirNameSuffix(component); if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) { tempInstallDirectory += "/"; tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME"); @@ -897,7 +897,7 @@ int cmCPackGenerator::InstallCMakeProject( // ABSOLUTE INSTALL DESTINATION or CPack has been asked for // then ask cmake_install.cmake script to error out // as soon as it occurs (before installing file) - if (!SupportsAbsoluteDestination() || + if (!this->SupportsAbsoluteDestination() || this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) { mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1"); } @@ -933,7 +933,7 @@ int cmCPackGenerator::InstallCMakeProject( localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit); localFileName = localFileName.substr(localFileName.find_first_not_of('/')); - Components[component].Files.push_back(localFileName); + this->Components[component].Files.push_back(localFileName); cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file <" << localFileName << "> to component <" << component << ">" << std::endl); @@ -952,7 +952,7 @@ int cmCPackGenerator::InstallCMakeProject( if (componentInstall) { std::string absoluteDestFileComponent = std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" + - GetComponentInstallDirNameSuffix(component); + this->GetComponentInstallDirNameSuffix(component); if (nullptr != this->GetOption(absoluteDestFileComponent)) { std::string absoluteDestFilesListComponent = cmStrCat(this->GetOption(absoluteDestFileComponent), ';', *d); @@ -1073,17 +1073,17 @@ int cmCPackGenerator::DoPackage() } // The files to be installed - files = gl.GetFiles(); + this->files = gl.GetFiles(); - packageFileNames.clear(); + this->packageFileNames.clear(); /* Put at least one file name into the list of * wanted packageFileNames. The specific generator * may update this during PackageFiles. * (either putting several names or updating the provided one) */ - packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName - : ""); - toplevel = tempDirectory; + this->packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName + : ""); + this->toplevel = tempDirectory; { // scope that enables package generators to run internal scripts with // latest CMake policies enabled cmMakefile::ScopePushPop pp{ this->MakefileMap }; @@ -1127,10 +1127,10 @@ int cmCPackGenerator::DoPackage() * (because the specific generator did 'normalize' it) */ cmCPackLogger(cmCPackLog::LOG_VERBOSE, - "Copying final package(s) [" << packageFileNames.size() + "Copying final package(s) [" << this->packageFileNames.size() << "]:" << std::endl); /* now copy package one by one */ - for (std::string const& pkgFileName : packageFileNames) { + for (std::string const& pkgFileName : this->packageFileNames) { std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); std::string filename(cmSystemTools::GetFilenameName(pkgFileName)); tempPackageFileName = pkgFileName.c_str(); @@ -1211,7 +1211,7 @@ bool cmCPackGenerator::IsSet(const std::string& name) const bool cmCPackGenerator::IsOn(const std::string& name) const { - return cmIsOn(GetOption(name)); + return cmIsOn(this->GetOption(name)); } bool cmCPackGenerator::IsSetToOff(const std::string& op) const @@ -1329,7 +1329,7 @@ bool cmCPackGenerator::ConfigureFile(const std::string& inName, bool copyOnly /* = false */) { return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true, - false, true) == 1; + false) == 1; } int cmCPackGenerator::CleanTemporaryDirectory() @@ -1405,7 +1405,7 @@ int cmCPackGenerator::PrepareGroupingKind() // fallback to default if not group based if (method == ONE_PACKAGE_PER_GROUP && this->ComponentGroups.empty() && !this->Components.empty()) { - if (componentPackageMethod == ONE_PACKAGE) { + if (this->componentPackageMethod == ONE_PACKAGE) { method = ONE_PACKAGE; } else { method = ONE_PACKAGE_PER_COMPONENT; @@ -1421,7 +1421,7 @@ int cmCPackGenerator::PrepareGroupingKind() // if user specified packaging method, override the default packaging // method if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) { - componentPackageMethod = method; + this->componentPackageMethod = method; } const char* method_names[] = { "ALL_COMPONENTS_IN_ONE", "IGNORE_GROUPS", @@ -1430,7 +1430,8 @@ int cmCPackGenerator::PrepareGroupingKind() cmCPackLogger(cmCPackLog::LOG_VERBOSE, "[" << this->Name << "]" << " requested component grouping = " - << method_names[componentPackageMethod] << std::endl); + << method_names[this->componentPackageMethod] + << std::endl); return 1; } @@ -1451,13 +1452,14 @@ std::string cmCPackGenerator::GetComponentPackageFileName( */ std::string suffix = "-" + groupOrComponentName; /* check if we should use DISPLAY name */ - std::string dispNameVar = "CPACK_" + Name + "_USE_DISPLAY_NAME_IN_FILENAME"; - if (IsOn(dispNameVar)) { + std::string dispNameVar = + "CPACK_" + this->Name + "_USE_DISPLAY_NAME_IN_FILENAME"; + if (this->IsOn(dispNameVar)) { /* the component Group case */ if (isGroupName) { std::string groupDispVar = "CPACK_COMPONENT_GROUP_" + cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME"; - const char* groupDispName = GetOption(groupDispVar); + const char* groupDispName = this->GetOption(groupDispVar); if (groupDispName) { suffix = "-" + std::string(groupDispName); } @@ -1466,7 +1468,7 @@ std::string cmCPackGenerator::GetComponentPackageFileName( else { std::string dispVar = "CPACK_COMPONENT_" + cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME"; - const char* dispName = GetOption(dispVar); + const char* dispName = this->GetOption(dispVar); if (dispName) { suffix = "-" + std::string(dispName); } @@ -1493,8 +1495,8 @@ bool cmCPackGenerator::SupportsComponentInstallation() const bool cmCPackGenerator::WantsComponentInstallation() const { - return (!IsOn("CPACK_MONOLITHIC_INSTALL") && - SupportsComponentInstallation() + return (!this->IsOn("CPACK_MONOLITHIC_INSTALL") && + this->SupportsComponentInstallation() // check that we have at least one group or component && (!this->ComponentGroups.empty() || !this->Components.empty())); } @@ -1557,7 +1559,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent( const char* groupName = this->GetOption(macroPrefix + "_GROUP"); if (cmNonempty(groupName)) { - component->Group = GetComponentGroup(projectName, groupName); + component->Group = this->GetComponentGroup(projectName, groupName); component->Group->Components.push_back(component); } else { component->Group = nullptr; @@ -1584,7 +1586,7 @@ cmCPackComponent* cmCPackGenerator::GetComponent( if (cmNonempty(depends)) { std::vector<std::string> dependsVector = cmExpandedList(depends); for (std::string const& depend : dependsVector) { - cmCPackComponent* child = GetComponent(projectName, depend); + cmCPackComponent* child = this->GetComponent(projectName, depend); component->Dependencies.push_back(child); child->ReverseDependencies.push_back(component); } @@ -1620,7 +1622,8 @@ cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup( const char* parentGroupName = this->GetOption(macroPrefix + "_PARENT_GROUP"); if (cmNonempty(parentGroupName)) { - group->ParentGroup = GetComponentGroup(projectName, parentGroupName); + group->ParentGroup = + this->GetComponentGroup(projectName, parentGroupName); group->ParentGroup->Subgroups.push_back(group); } else { group->ParentGroup = nullptr; diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index 2109b4e..435f0ec 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -31,7 +31,7 @@ cmCPackNSISGenerator::cmCPackNSISGenerator(bool nsis64) { - Nsis64 = nsis64; + this->Nsis64 = nsis64; } cmCPackNSISGenerator::~cmCPackNSISGenerator() = default; @@ -61,18 +61,18 @@ int cmCPackNSISGenerator::PackageFiles() std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini"; nsisFileName += "/project.nsi"; std::ostringstream str; - for (std::string const& file : files) { + for (std::string const& file : this->files) { std::string outputDir = "$INSTDIR"; - std::string fileN = cmSystemTools::RelativePath(toplevel, file); + std::string fileN = cmSystemTools::RelativePath(this->toplevel, file); if (!this->Components.empty()) { const std::string::size_type pos = fileN.find('/'); // Use the custom component install directory if we have one if (pos != std::string::npos) { auto componentName = cm::string_view(fileN).substr(0, pos); - outputDir = CustomComponentInstallDirectory(componentName); + outputDir = this->CustomComponentInstallDirectory(componentName); } else { - outputDir = CustomComponentInstallDirectory(fileN); + outputDir = this->CustomComponentInstallDirectory(fileN); } // Strip off the component part of the path. @@ -86,15 +86,15 @@ int cmCPackNSISGenerator::PackageFiles() "Uninstall Files: " << str.str() << std::endl); this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str()); std::vector<std::string> dirs; - this->GetListOfSubdirectories(toplevel.c_str(), dirs); + this->GetListOfSubdirectories(this->toplevel.c_str(), dirs); std::ostringstream dstr; for (std::string const& dir : dirs) { std::string componentName; - std::string fileN = cmSystemTools::RelativePath(toplevel, dir); + std::string fileN = cmSystemTools::RelativePath(this->toplevel, dir); if (fileN.empty()) { continue; } - if (!Components.empty()) { + if (!this->Components.empty()) { // If this is a component installation, strip off the component // part of the path. std::string::size_type slash = fileN.find('/'); @@ -110,7 +110,7 @@ int cmCPackNSISGenerator::PackageFiles() std::replace(fileN.begin(), fileN.end(), '/', '\\'); const std::string componentOutputDir = - CustomComponentInstallDirectory(componentName); + this->CustomComponentInstallDirectory(componentName); dstr << " RMDir \"" << componentOutputDir << "\\" << fileN << "\"" << std::endl; @@ -677,7 +677,7 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( } const std::string componentOutputDir = - CustomComponentInstallDirectory(component->Name); + this->CustomComponentInstallDirectory(component->Name); componentCode += cmStrCat(" SetOutPath \"", componentOutputDir, "\"\n"); // Create the actual installation commands @@ -833,14 +833,16 @@ std::string cmCPackNSISGenerator::CreateComponentDescription( // depends on. std::set<cmCPackComponent*> visited; macrosOut << "!macro Select_" << component->Name << "_depends\n"; - macrosOut << CreateSelectionDependenciesDescription(component, visited); + macrosOut << this->CreateSelectionDependenciesDescription(component, + visited); macrosOut << "!macroend\n"; // Macro used to deselect each of the components that depend on this // component. visited.clear(); macrosOut << "!macro Deselect_required_by_" << component->Name << "\n"; - macrosOut << CreateDeselectionDependenciesDescription(component, visited); + macrosOut << this->CreateDeselectionDependenciesDescription(component, + visited); macrosOut << "!macroend\n"; return componentCode; } @@ -862,7 +864,8 @@ std::string cmCPackNSISGenerator::CreateSelectionDependenciesDescription( out << " SectionSetFlags ${" << depend->Name << "} $0\n"; out << " IntOp $" << depend->Name << "_selected 0 + ${SF_SELECTED}\n"; // Recurse - out << CreateSelectionDependenciesDescription(depend, visited).c_str(); + out + << this->CreateSelectionDependenciesDescription(depend, visited).c_str(); } return out.str(); @@ -887,7 +890,8 @@ std::string cmCPackNSISGenerator::CreateDeselectionDependenciesDescription( out << " IntOp $" << depend->Name << "_selected 0 + 0\n"; // Recurse - out << CreateDeselectionDependenciesDescription(depend, visited).c_str(); + out << this->CreateDeselectionDependenciesDescription(depend, visited) + .c_str(); } return out.str(); diff --git a/Source/CPack/cmCPackNuGetGenerator.cxx b/Source/CPack/cmCPackNuGetGenerator.cxx index 60faecd..98dc890 100644 --- a/Source/CPack/cmCPackNuGetGenerator.cxx +++ b/Source/CPack/cmCPackNuGetGenerator.cxx @@ -17,32 +17,33 @@ bool cmCPackNuGetGenerator::SupportsComponentInstallation() const { - return IsOn("CPACK_NUGET_COMPONENT_INSTALL"); + return this->IsOn("CPACK_NUGET_COMPONENT_INSTALL"); } int cmCPackNuGetGenerator::PackageFiles() { - cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Toplevel: " << this->toplevel << std::endl); /* Reset package file name list it will be populated after the * `CPackNuGet.cmake` run */ - packageFileNames.clear(); + this->packageFileNames.clear(); /* Are we in the component packaging case */ - if (WantsComponentInstallation()) { - if (componentPackageMethod == ONE_PACKAGE) { + if (this->WantsComponentInstallation()) { + if (this->componentPackageMethod == ONE_PACKAGE) { // CASE 1 : COMPONENT ALL-IN-ONE package // Meaning that all per-component pre-installed files // goes into the single package. this->SetOption("CPACK_NUGET_ALL_IN_ONE", "TRUE"); - SetupGroupComponentVariables(true); + this->SetupGroupComponentVariables(true); } else { // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one) // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - SetupGroupComponentVariables(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); + this->SetupGroupComponentVariables(this->componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } } else { // CASE 3 : NON COMPONENT package. @@ -51,7 +52,7 @@ int cmCPackNuGetGenerator::PackageFiles() auto retval = this->ReadListFile("Internal/CPack/CPackNuGet.cmake"); if (retval) { - AddGeneratedPackageNames(); + this->AddGeneratedPackageNames(); } else { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackNuGet.cmake" << std::endl); @@ -133,9 +134,9 @@ void cmCPackNuGetGenerator::AddGeneratedPackageNames() std::string::size_type pos1 = 0; std::string::size_type pos2 = fileNames.find(sep, pos1 + 1); while (pos2 != std::string::npos) { - packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); + this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); pos1 = pos2 + 1; pos2 = fileNames.find(sep, pos1 + 1); } - packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); + this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); } diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx index 0c1cecf..c3f6d59 100644 --- a/Source/CPack/cmCPackRPMGenerator.cxx +++ b/Source/CPack/cmCPackRPMGenerator.cxx @@ -51,11 +51,11 @@ void cmCPackRPMGenerator::AddGeneratedPackageNames() std::string::size_type pos1 = 0; std::string::size_type pos2 = fileNames.find(sep, pos1 + 1); while (pos2 != std::string::npos) { - packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); + this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); pos1 = pos2 + 1; pos2 = fileNames.find(sep, pos1 + 1); } - packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); + this->packageFileNames.push_back(fileNames.substr(pos1, pos2 - pos1)); } int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel, @@ -64,10 +64,11 @@ int cmCPackRPMGenerator::PackageOnePack(std::string const& initialToplevel, int retval = 1; // Begin the archive for this pack std::string localToplevel(initialToplevel); - std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel)); + std::string packageFileName( + cmSystemTools::GetParentDirectory(this->toplevel)); std::string outputFileName( - GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"), - packageName, true) + + this->GetComponentPackageFileName( + this->GetOption("CPACK_PACKAGE_FILE_NAME"), packageName, true) + this->GetOutputExtension()); localToplevel += "/" + packageName; @@ -99,7 +100,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) int retval = 1; /* Reset package file name list it will be populated during the * component packaging run*/ - packageFileNames.clear(); + this->packageFileNames.clear(); std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); const char* mainComponent = this->GetOption("CPACK_RPM_MAIN_COMPONENT"); @@ -202,7 +203,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: " << compGIt->first << std::endl); - retval &= PackageOnePack(initialTopLevel, compGIt->first); + retval &= this->PackageOnePack(initialTopLevel, compGIt->first); } // Handle Orphan components (components not belonging to any groups) auto mainCompIt = this->Components.end(); @@ -227,7 +228,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) << compIt->second.Name << "> does not belong to any group, package it separately." << std::endl); - retval &= PackageOnePack(initialTopLevel, compIt->first); + retval &= this->PackageOnePack(initialTopLevel, compIt->first); } } @@ -235,9 +236,9 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) this->SetOption("GENERATE_SPEC_PARTS", "OFF"); if (mainCompGIt != this->ComponentGroups.end()) { - retval &= PackageOnePack(initialTopLevel, mainCompGIt->first); + retval &= this->PackageOnePack(initialTopLevel, mainCompGIt->first); } else if (mainCompIt != this->Components.end()) { - retval &= PackageOnePack(initialTopLevel, mainCompIt->first); + retval &= this->PackageOnePack(initialTopLevel, mainCompIt->first); } else { cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_RPM_MAIN_COMPONENT set" @@ -264,14 +265,14 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) continue; } - retval &= PackageOnePack(initialTopLevel, compIt->first); + retval &= this->PackageOnePack(initialTopLevel, compIt->first); } if (retval) { this->SetOption("GENERATE_SPEC_PARTS", "OFF"); if (mainCompIt != this->Components.end()) { - retval &= PackageOnePack(initialTopLevel, mainCompIt->first); + retval &= this->PackageOnePack(initialTopLevel, mainCompIt->first); } else { cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_RPM_MAIN_COMPONENT set" @@ -291,7 +292,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: " << compGIt->first << std::endl); - retval &= PackageOnePack(initialTopLevel, compGIt->first); + retval &= this->PackageOnePack(initialTopLevel, compGIt->first); } // Handle Orphan components (components not belonging to any groups) std::map<std::string, cmCPackComponent>::iterator compIt; @@ -305,7 +306,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) << compIt->second.Name << "> does not belong to any group, package it separately." << std::endl); - retval &= PackageOnePack(initialTopLevel, compIt->first); + retval &= this->PackageOnePack(initialTopLevel, compIt->first); } } } @@ -315,7 +316,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) std::map<std::string, cmCPackComponent>::iterator compIt; for (compIt = this->Components.begin(); compIt != this->Components.end(); ++compIt) { - retval &= PackageOnePack(initialTopLevel, compIt->first); + retval &= this->PackageOnePack(initialTopLevel, compIt->first); } } } else { @@ -328,7 +329,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) } if (retval) { - AddGeneratedPackageNames(); + this->AddGeneratedPackageNames(); } return retval; @@ -340,7 +341,7 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne( int retval = 1; /* Reset package file name list it will be populated during the * component packaging run*/ - packageFileNames.clear(); + this->packageFileNames.clear(); std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); if (this->IsOn("CPACK_RPM_DEBUGINFO_SINGLE_PACKAGE")) { @@ -354,7 +355,8 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne( // The ALL GROUPS in ONE package case std::string localToplevel(initialTopLevel); - std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel)); + std::string packageFileName( + cmSystemTools::GetParentDirectory(this->toplevel)); std::string outputFileName( std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + this->GetOutputExtension()); @@ -378,7 +380,7 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne( } if (this->ReadListFile("Internal/CPack/CPackRPM.cmake")) { - AddGeneratedPackageNames(); + this->AddGeneratedPackageNames(); } else { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackRPM.cmake" << std::endl); @@ -390,48 +392,49 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne( int cmCPackRPMGenerator::PackageFiles() { - cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Toplevel: " << this->toplevel << std::endl); /* Are we in the component packaging case */ - if (WantsComponentInstallation()) { + if (this->WantsComponentInstallation()) { // CASE 1 : COMPONENT ALL-IN-ONE package // If ALL COMPONENTS in ONE package has been requested // then the package file is unique and should be open here. - if (componentPackageMethod == ONE_PACKAGE) { - return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE"); + if (this->componentPackageMethod == ONE_PACKAGE) { + return this->PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE"); } // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one) // There will be 1 package for each component group // however one may require to ignore component group and // in this case you'll get 1 package for each component. - return PackageComponents(componentPackageMethod == - ONE_PACKAGE_PER_COMPONENT); + return this->PackageComponents(this->componentPackageMethod == + ONE_PACKAGE_PER_COMPONENT); } // CASE 3 : NON COMPONENT package. - return PackageComponentsAllInOne(""); + return this->PackageComponentsAllInOne(""); } bool cmCPackRPMGenerator::SupportsComponentInstallation() const { - return IsOn("CPACK_RPM_COMPONENT_INSTALL"); + return this->IsOn("CPACK_RPM_COMPONENT_INSTALL"); } std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix( const std::string& componentName) { - if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) { + if (this->componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) { return componentName; } - if (componentPackageMethod == ONE_PACKAGE) { + if (this->componentPackageMethod == ONE_PACKAGE) { return std::string("ALL_COMPONENTS_IN_ONE"); } // We have to find the name of the COMPONENT GROUP // the current COMPONENT belongs to. std::string groupVar = "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP"; - if (nullptr != GetOption(groupVar)) { - return std::string(GetOption(groupVar)); + if (nullptr != this->GetOption(groupVar)) { + return std::string(this->GetOption(groupVar)); } return componentName; } diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx index a4a5e6f..3e36e8c 100644 --- a/Source/CPack/cmCPackSTGZGenerator.cxx +++ b/Source/CPack/cmCPackSTGZGenerator.cxx @@ -50,7 +50,7 @@ int cmCPackSTGZGenerator::PackageFiles() * have generated several packages (component packaging) * so we must iterate over generated packages. */ - for (std::string const& pfn : packageFileNames) { + for (std::string const& pfn : this->packageFileNames) { retval &= cmSystemTools::SetPermissions(pfn.c_str(), #if defined(_MSC_VER) || defined(__MINGW32__) S_IREAD | S_IWRITE | S_IEXEC diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index c533cd7..a353435 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -104,8 +104,8 @@ private: { if (this->RegexCheckOut.find(this->Line)) { this->BZR->URL = this->RegexCheckOut.match(1); - CheckOutFound = true; - } else if (!CheckOutFound && this->RegexParent.find(this->Line)) { + this->CheckOutFound = true; + } else if (!this->CheckOutFound && this->RegexParent.find(this->Line)) { this->BZR->URL = this->RegexParent.match(1); } return true; @@ -191,7 +191,7 @@ public: int InitializeParser() override { - int res = cmXMLParser::InitializeParser(); + int res = this->cmXMLParser::InitializeParser(); if (res) { XML_SetUnknownEncodingHandler(static_cast<XML_Parser>(this->Parser), cmBZRXMLParserUnknownEncodingHandler, diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx index 1cc267e..88e2871 100644 --- a/Source/CTest/cmCTestBuildCommand.cxx +++ b/Source/CTest/cmCTestBuildCommand.cxx @@ -54,22 +54,21 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() // cmProp ctestBuildConfiguration = this->Makefile->GetDefinition("CTEST_BUILD_CONFIGURATION"); - const std::string* cmakeBuildConfiguration = !this->Configuration.empty() - ? &this->Configuration - : (cmNonempty(ctestBuildConfiguration) ? ctestBuildConfiguration - : &this->CTest->GetConfigType()); - - const std::string* cmakeBuildAdditionalFlags = !this->Flags.empty() - ? &this->Flags - : this->Makefile->GetDefinition("CTEST_BUILD_FLAGS"); - const std::string* cmakeBuildTarget = !this->Target.empty() - ? &this->Target - : this->Makefile->GetDefinition("CTEST_BUILD_TARGET"); + std::string cmakeBuildConfiguration = cmNonempty(this->Configuration) + ? this->Configuration + : cmNonempty(ctestBuildConfiguration) ? *ctestBuildConfiguration + : this->CTest->GetConfigType(); + + const std::string& cmakeBuildAdditionalFlags = cmNonempty(this->Flags) + ? this->Flags + : this->Makefile->GetSafeDefinition("CTEST_BUILD_FLAGS"); + const std::string& cmakeBuildTarget = cmNonempty(this->Target) + ? this->Target + : this->Makefile->GetSafeDefinition("CTEST_BUILD_TARGET"); if (cmNonempty(cmakeGeneratorName)) { - if (!cmakeBuildConfiguration) { - static const std::string sRelease = "Release"; - cmakeBuildConfiguration = &sRelease; + if (cmakeBuildConfiguration.empty()) { + cmakeBuildConfiguration = "Release"; } if (this->GlobalGenerator) { if (this->GlobalGenerator->GetName() != *cmakeGeneratorName) { @@ -88,24 +87,18 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() return nullptr; } } - if (cmakeBuildConfiguration->empty()) { - const std::string* config = nullptr; + if (cmakeBuildConfiguration.empty()) { #ifdef CMAKE_INTDIR - static const std::string sIntDir = CMAKE_INTDIR; - config = &sIntDir; + cmakeBuildConfiguration = CMAKE_INTDIR; +#else + cmakeBuildConfiguration = "Debug"; #endif - if (!config) { - static const std::string sDebug = "Debug"; - config = &sDebug; - } - cmakeBuildConfiguration = config; } std::string dir = this->CTest->GetCTestConfiguration("BuildDirectory"); std::string buildCommand = this->GlobalGenerator->GenerateCMakeBuildCommand( - cmakeBuildTarget ? *cmakeBuildTarget : "", *cmakeBuildConfiguration, - cmakeBuildAdditionalFlags ? *cmakeBuildAdditionalFlags : "", + cmakeBuildTarget, cmakeBuildConfiguration, cmakeBuildAdditionalFlags, this->Makefile->IgnoreErrorsCMP0061()); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "SetMakeCommand:" << buildCommand << "\n", @@ -144,7 +137,7 @@ cmCTestGenericHandler* cmCTestBuildCommand::InitializeHandler() bool cmCTestBuildCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus& status) { - bool ret = cmCTestHandlerCommand::InitialPass(args, status); + bool ret = this->cmCTestHandlerCommand::InitialPass(args, status); if (!this->NumberErrors.empty()) { this->Makefile->AddDefinition( this->NumberErrors, std::to_string(this->Handler->GetTotalErrors())); diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 093b2d1..5fb52bf 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -778,16 +778,16 @@ struct cmCTestCoverageHandlerLocale { std::string l; if (cmSystemTools::GetEnv("LC_ALL", l)) { - lc_all = l; + this->lc_all = l; } - if (lc_all != "C") { + if (this->lc_all != "C") { cmSystemTools::PutEnv("LC_ALL=C"); } } ~cmCTestCoverageHandlerLocale() { - if (!lc_all.empty()) { - cmSystemTools::PutEnv("LC_ALL=" + lc_all); + if (!this->lc_all.empty()) { + cmSystemTools::PutEnv("LC_ALL=" + this->lc_all); } else { cmSystemTools::UnsetEnv("LC_ALL"); } diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx index 6ec7d0e..f89fc9b 100644 --- a/Source/CTest/cmCTestLaunchReporter.cxx +++ b/Source/CTest/cmCTestLaunchReporter.cxx @@ -284,7 +284,7 @@ void cmCTestLaunchReporter::DumpFileToXML(cmXMLElement& e3, const char* tag, cmXMLElement e4(e3, tag); while (cmSystemTools::GetLineFromStream(fin, line)) { - if (MatchesFilterPrefix(line)) { + if (this->MatchesFilterPrefix(line)) { continue; } if (this->Match(line, this->RegexWarningSuppress)) { diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index a08cb34..9793c5b 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -56,8 +56,8 @@ public: // Sorts tests in descending order of cost bool operator()(int index1, int index2) const { - return Handler->Properties[index1]->Cost > - Handler->Properties[index2]->Cost; + return this->Handler->Properties[index1]->Cost > + this->Handler->Properties[index2]->Cost; } private: @@ -169,7 +169,7 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test) this->TestRunningMap[test] = true; // mark the test as running // now remove the test itself this->EraseTest(test); - this->RunningCount += GetProcessorsUsed(test); + this->RunningCount += this->GetProcessorsUsed(test); auto testRun = cm::make_unique<cmCTestRunTest>(*this); @@ -552,12 +552,12 @@ void cmCTestMultiProcessHandler::StartNextTests() continue; } - size_t processors = GetProcessorsUsed(test); + size_t processors = this->GetProcessorsUsed(test); bool testLoadOk = true; if (this->TestLoad > 0) { if (processors <= spareLoad) { cmCTestLog(this->CTest, DEBUG, - "OK to run " << GetName(test) << ", it requires " + "OK to run " << this->GetName(test) << ", it requires " << processors << " procs & system load is: " << systemLoad << std::endl); allTestsFailedTestLoadCheck = false; @@ -568,7 +568,7 @@ void cmCTestMultiProcessHandler::StartNextTests() if (processors <= minProcessorsRequired) { minProcessorsRequired = processors; - testWithMinProcessors = GetName(test); + testWithMinProcessors = this->GetName(test); } if (testLoadOk && processors <= numToStart && this->StartTest(test)) { @@ -660,7 +660,7 @@ void cmCTestMultiProcessHandler::FinishTestProcess( this->WriteCheckpoint(test); this->DeallocateResources(test); this->UnlockResources(test); - this->RunningCount -= GetProcessorsUsed(test); + this->RunningCount -= this->GetProcessorsUsed(test); for (auto p : properties->Affinity) { this->ProcessorsAvailable.insert(p); @@ -793,9 +793,9 @@ int cmCTestMultiProcessHandler::SearchByName(std::string const& name) void cmCTestMultiProcessHandler::CreateTestCostList() { if (this->ParallelLevel > 1) { - CreateParallelTestCostList(); + this->CreateParallelTestCostList(); } else { - CreateSerialTestCostList(); + this->CreateSerialTestCostList(); } } @@ -862,7 +862,7 @@ void cmCTestMultiProcessHandler::GetAllTestDependencies(int test, { TestSet const& dependencySet = this->Tests[test]; for (int i : dependencySet) { - GetAllTestDependencies(i, dependencies); + this->GetAllTestDependencies(i, dependencies); dependencies.push_back(i); } } @@ -886,7 +886,7 @@ void cmCTestMultiProcessHandler::CreateSerialTestCostList() } TestList dependencies; - GetAllTestDependencies(test, dependencies); + this->GetAllTestDependencies(test, dependencies); for (int testDependency : dependencies) { if (!cm::contains(alreadySortedTests, testDependency)) { @@ -1274,7 +1274,7 @@ void cmCTestMultiProcessHandler::PrintOutputAsJson() void cmCTestMultiProcessHandler::PrintTestList() { if (this->CTest->GetOutputAsJson()) { - PrintOutputAsJson(); + this->PrintOutputAsJson(); return; } diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index 1375be4..50c9c16 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -56,7 +56,7 @@ public: ChangesParser(cmCTestP4* p4, const char* prefix) : P4(p4) { - this->SetLog(&P4->Log, prefix); + this->SetLog(&this->P4->Log, prefix); this->RegexIdentify.compile("^Change ([0-9]+) on"); } @@ -67,7 +67,7 @@ private: bool ProcessLine() override { if (this->RegexIdentify.find(this->Line)) { - P4->ChangeLists.push_back(this->RegexIdentify.match(1)); + this->P4->ChangeLists.push_back(this->RegexIdentify.match(1)); } return true; } @@ -79,7 +79,7 @@ public: UserParser(cmCTestP4* p4, const char* prefix) : P4(p4) { - this->SetLog(&P4->Log, prefix); + this->SetLog(&this->P4->Log, prefix); this->RegexUser.compile("^(.+) <(.*)> \\((.*)\\) accessed (.*)$"); } @@ -96,7 +96,7 @@ private: NewUser.EMail = this->RegexUser.match(2); NewUser.Name = this->RegexUser.match(3); NewUser.AccessTime = this->RegexUser.match(4); - P4->Users[this->RegexUser.match(1)] = NewUser; + this->P4->Users[this->RegexUser.match(1)] = NewUser; return false; } @@ -120,7 +120,7 @@ public: : P4(p4) , AlreadyNotified(false) { - this->SetLog(&P4->Log, prefix); + this->SetLog(&this->P4->Log, prefix); this->RegexDiff.compile("^==== (.*)#[0-9]+ - (.*)"); } @@ -134,12 +134,12 @@ private: { if (!this->Line.empty() && this->Line[0] == '=' && this->RegexDiff.find(this->Line)) { - CurrentPath = this->RegexDiff.match(1); - AlreadyNotified = false; + this->CurrentPath = this->RegexDiff.match(1); + this->AlreadyNotified = false; } else { - if (!AlreadyNotified) { - P4->DoModification(PathModified, CurrentPath); - AlreadyNotified = true; + if (!this->AlreadyNotified) { + this->P4->DoModification(PathModified, this->CurrentPath); + this->AlreadyNotified = true; } } return true; @@ -148,11 +148,11 @@ private: cmCTestP4::User cmCTestP4::GetUserData(const std::string& username) { - auto it = Users.find(username); + auto it = this->Users.find(username); - if (it == Users.end()) { + if (it == this->Users.end()) { std::vector<char const*> p4_users; - SetP4Options(p4_users); + this->SetP4Options(p4_users); p4_users.push_back("users"); p4_users.push_back("-m"); p4_users.push_back("1"); @@ -161,11 +161,11 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username) UserParser out(this, "users-out> "); OutputLogger err(this->Log, "users-err> "); - RunChild(&p4_users[0], &out, &err); + this->RunChild(&p4_users[0], &out, &err); // The user should now be added to the map. Search again. - it = Users.find(username); - if (it == Users.end()) { + it = this->Users.find(username); + if (it == this->Users.end()) { return cmCTestP4::User(); } } @@ -195,7 +195,7 @@ public: , P4(p4) , Section(SectionHeader) { - this->SetLog(&P4->Log, prefix); + this->SetLog(&this->P4->Log, prefix); this->RegexHeader.compile("^Change ([0-9]+) by (.+)@(.+) on (.*)$"); this->RegexDiff.compile(R"(^\.\.\. (.*)#[0-9]+ ([^ ]+)$)"); } @@ -259,7 +259,7 @@ private: this->Rev.Rev = this->RegexHeader.match(1); this->Rev.Date = this->RegexHeader.match(4); - cmCTestP4::User user = P4->GetUserData(this->RegexHeader.match(2)); + cmCTestP4::User user = this->P4->GetUserData(this->RegexHeader.match(2)); this->Rev.Author = user.Name; this->Rev.EMail = user.EMail; @@ -300,38 +300,38 @@ private: change.Action = 'M'; } - Changes.push_back(change); + this->Changes.push_back(change); } } }; void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions) { - if (P4Options.empty()) { + if (this->P4Options.empty()) { const char* p4 = this->CommandLineTool.c_str(); - P4Options.emplace_back(p4); + this->P4Options.emplace_back(p4); // The CTEST_P4_CLIENT variable sets the P4 client used when issuing // Perforce commands, if it's different from the default one. std::string client = this->CTest->GetCTestConfiguration("P4Client"); if (!client.empty()) { - P4Options.emplace_back("-c"); - P4Options.push_back(client); + this->P4Options.emplace_back("-c"); + this->P4Options.push_back(client); } // Set the message language to be English, in case the P4 admin // has localized them - P4Options.emplace_back("-L"); - P4Options.emplace_back("en"); + this->P4Options.emplace_back("-L"); + this->P4Options.emplace_back("en"); // The CTEST_P4_OPTIONS variable adds additional Perforce command line // options before the main command std::string opts = this->CTest->GetCTestConfiguration("P4Options"); - cm::append(P4Options, cmSystemTools::ParseArguments(opts)); + cm::append(this->P4Options, cmSystemTools::ParseArguments(opts)); } CommandOptions.clear(); - for (std::string const& o : P4Options) { + for (std::string const& o : this->P4Options) { CommandOptions.push_back(o.c_str()); } } @@ -339,7 +339,7 @@ void cmCTestP4::SetP4Options(std::vector<char const*>& CommandOptions) std::string cmCTestP4::GetWorkingRevision() { std::vector<char const*> p4_identify; - SetP4Options(p4_identify); + this->SetP4Options(p4_identify); p4_identify.push_back("changes"); p4_identify.push_back("-m"); @@ -354,7 +354,7 @@ std::string cmCTestP4::GetWorkingRevision() IdentifyParser out(this, "p4_changes-out> ", rev); OutputLogger err(this->Log, "p4_changes-err> "); - bool result = RunChild(&p4_identify[0], &out, &err); + bool result = this->RunChild(&p4_identify[0], &out, &err); // If there was a problem contacting the server return "<unknown>" if (!result) { @@ -391,7 +391,7 @@ bool cmCTestP4::NoteNewRevision() bool cmCTestP4::LoadRevisions() { std::vector<char const*> p4_changes; - SetP4Options(p4_changes); + this->SetP4Options(p4_changes); // Use 'p4 changes ...@old,new' to get a list of changelists std::string range = this->SourceDirectory + "/..."; @@ -417,17 +417,17 @@ bool cmCTestP4::LoadRevisions() ChangesParser out(this, "p4_changes-out> "); OutputLogger err(this->Log, "p4_changes-err> "); - ChangeLists.clear(); + this->ChangeLists.clear(); this->RunChild(&p4_changes[0], &out, &err); - if (ChangeLists.empty()) { + if (this->ChangeLists.empty()) { return true; } // p4 describe -s ...@1111111,2222222 std::vector<char const*> p4_describe; - for (std::string const& i : cmReverseRange(ChangeLists)) { - SetP4Options(p4_describe); + for (std::string const& i : cmReverseRange(this->ChangeLists)) { + this->SetP4Options(p4_describe); p4_describe.push_back("describe"); p4_describe.push_back("-s"); p4_describe.push_back(i.c_str()); @@ -443,7 +443,7 @@ bool cmCTestP4::LoadRevisions() bool cmCTestP4::LoadModifications() { std::vector<char const*> p4_diff; - SetP4Options(p4_diff); + this->SetP4Options(p4_diff); p4_diff.push_back("diff"); @@ -491,7 +491,7 @@ bool cmCTestP4::UpdateImpl() } std::vector<char const*> p4_sync; - SetP4Options(p4_sync); + this->SetP4Options(p4_sync); p4_sync.push_back("sync"); diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 4d65c9b..5a6c775 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -139,7 +139,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) s << "SKIP_RETURN_CODE=" << this->TestProperties->SkipReturnCode; } this->TestResult.CompletionStatus = s.str(); - cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Skipped "); + outputStream << "***Skipped "; skipped = true; } else if (success != this->TestProperties->WillFail) { this->TestResult.Status = cmCTestTestHandler::COMPLETED; @@ -195,10 +195,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime().count()); outputStream << buf << "\n"; + bool passedOrSkipped = passed || skipped; if (this->CTest->GetTestProgressOutput()) { - if (!passed) { + if (!passedOrSkipped) { // If the test did not pass, reprint test name and error - std::string output = GetTestPrefix(completed, total); + std::string output = this->GetTestPrefix(completed, total); std::string testName = this->TestProperties->Name; const int maxTestNameWidth = this->CTest->GetMaxTestNameWidth(); testName.resize(maxTestNameWidth + 4, '.'); @@ -211,12 +212,12 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, "\n"); // flush } if (completed == total) { - std::string testName = - GetTestPrefix(completed, total) + this->TestProperties->Name + "\n"; + std::string testName = this->GetTestPrefix(completed, total) + + this->TestProperties->Name + "\n"; cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, testName); } } - if (!this->CTest->GetTestProgressOutput() || !passed) { + if (!this->CTest->GetTestProgressOutput() || !passedOrSkipped) { cmCTestLog(this->CTest, HANDLER_OUTPUT, outputStream.str()); } @@ -485,8 +486,8 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total) << this->TestProperties->Index << ": " << this->TestProperties->Name << std::endl); } else { - std::string testName = - GetTestPrefix(completed, total) + this->TestProperties->Name + "\n"; + std::string testName = this->GetTestPrefix(completed, total) + + this->TestProperties->Name + "\n"; cmCTestLog(this->CTest, HANDLER_TEST_PROGRESS_OUTPUT, testName); } diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 44dfab2..4692dbd 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -286,9 +286,9 @@ bool cmCTestSVN::RunSVNCommand(std::vector<char const*> const& parameters, args.push_back(nullptr); if (strcmp(parameters[0], "update") == 0) { - return RunUpdateCommand(&args[0], out, err); + return this->RunUpdateCommand(&args[0], out, err); } - return RunChild(&args[0], out, err); + return this->RunChild(&args[0], out, err); } class cmCTestSVN::LogParser @@ -328,7 +328,7 @@ private: this->CData.clear(); if (name == "logentry") { this->Rev = Revision(); - this->Rev.SVNInfo = &SVNRepo; + this->Rev.SVNInfo = &this->SVNRepo; if (const char* rev = cmCTestSVN::LogParser::FindAttribute(atts, "revision")) { this->Rev.Rev = rev; @@ -354,7 +354,7 @@ private: this->SVN->DoRevisionSVN(this->Rev, this->Changes); } else if (!this->CData.empty() && name == "path") { std::string orig_path(&this->CData[0], this->CData.size()); - std::string new_path = SVNRepo.BuildLocalPath(orig_path); + std::string new_path = this->SVNRepo.BuildLocalPath(orig_path); this->CurChange.Path.assign(new_path); this->Changes.push_back(this->CurChange); } else if (!this->CData.empty() && name == "author") { diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 4d1a589..a8c9df6 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -122,7 +122,7 @@ bool cmCTestSubdirCommand(std::vector<std::string> const& args, readit = status.GetMakefile().ReadDependentFile(fname); } if (!readit) { - status.SetError(cmStrCat("Could not find include file: ", fname)); + status.SetError(cmStrCat("Could not load include file: ", fname)); return false; } } @@ -340,7 +340,7 @@ void cmCTestTestHandler::Initialize() this->ExcludeFixtureSetupRegExp.clear(); this->ExcludeFixtureCleanupRegExp.clear(); - TestsToRunString.clear(); + this->TestsToRunString.clear(); this->UseUnion = false; this->TestList.clear(); } @@ -877,7 +877,7 @@ bool cmCTestTestHandler::ComputeTestList() finalList.push_back(tp); } - UpdateForFixtures(finalList); + this->UpdateForFixtures(finalList); // Save the total number of tests before exclusions this->TotalNumberOfTests = this->TestList.size(); @@ -906,7 +906,7 @@ void cmCTestTestHandler::ComputeTestListForRerunFailed() finalList.push_back(tp); } - UpdateForFixtures(finalList); + this->UpdateForFixtures(finalList); // Save the total number of tests before exclusions this->TotalNumberOfTests = this->TestList.size(); diff --git a/Source/CTest/cmCTestUpdateCommand.cxx b/Source/CTest/cmCTestUpdateCommand.cxx index 6fef90a..0ba2c41 100644 --- a/Source/CTest/cmCTestUpdateCommand.cxx +++ b/Source/CTest/cmCTestUpdateCommand.cxx @@ -5,7 +5,6 @@ #include "cmCTest.h" #include "cmCTestUpdateHandler.h" #include "cmMakefile.h" -#include "cmProperty.h" #include "cmSystemTools.h" cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() @@ -18,7 +17,7 @@ cmCTestGenericHandler* cmCTestUpdateCommand::InitializeHandler() this->CTest->SetCTestConfiguration( "SourceDirectory", cmSystemTools::CollapseFullPath( - cmToCStrSafe(this->Makefile->GetDefinition("CTEST_SOURCE_DIRECTORY"))), + this->Makefile->GetSafeDefinition("CTEST_SOURCE_DIRECTORY")), this->Quiet); } std::string source_dir = diff --git a/Source/CTest/cmParseBlanketJSCoverage.cxx b/Source/CTest/cmParseBlanketJSCoverage.cxx index 409025f..3a6651f 100644 --- a/Source/CTest/cmParseBlanketJSCoverage.cxx +++ b/Source/CTest/cmParseBlanketJSCoverage.cxx @@ -66,7 +66,7 @@ public: } foundFile = true; inSource = false; - filename = getValue(line, 0); + filename = this->getValue(line, 0); } else if ((line.find("coverage") != std::string::npos) && foundFile && inSource) { /* @@ -78,7 +78,7 @@ public: * FoundFile and foundSource ensure that * only the value of the line coverage is captured */ - std::string result = getValue(line, 1); + std::string result = this->getValue(line, 1); result = result.substr(2); if (result == "\"\"") { // Empty quotation marks indicate that the diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx index 711a856..9311769 100644 --- a/Source/CTest/cmParseCoberturaCoverage.cxx +++ b/Source/CTest/cmParseCoberturaCoverage.cxx @@ -66,7 +66,7 @@ protected: // Check if this is an absolute path that falls within our // source or binary directories. - for (std::string const& filePath : FilePaths) { + for (std::string const& filePath : this->FilePaths) { if (cmHasPrefix(filename, filePath)) { this->CurFileName = filename; break; @@ -76,7 +76,7 @@ protected: if (this->CurFileName.empty()) { // Check if this is a path that is relative to our source or // binary directories. - for (std::string const& filePath : FilePaths) { + for (std::string const& filePath : this->FilePaths) { finalpath = cmStrCat(filePath, "/", filename); if (cmSystemTools::FileExists(finalpath)) { this->CurFileName = finalpath; diff --git a/Source/CTest/cmParseDelphiCoverage.cxx b/Source/CTest/cmParseDelphiCoverage.cxx index 016e90c..640873e 100644 --- a/Source/CTest/cmParseDelphiCoverage.cxx +++ b/Source/CTest/cmParseDelphiCoverage.cxx @@ -133,7 +133,7 @@ public: cmsys::Glob gl; gl.RecurseOn(); gl.RecurseThroughSymlinksOff(); - std::string glob = Coverage.SourceDir + "*/" + filename; + std::string glob = this->Coverage.SourceDir + "*/" + filename; gl.FindFiles(glob); std::vector<std::string> const& files = gl.GetFiles(); if (files.empty()) { diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 9ee1c17..c7cbd34 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -177,7 +177,7 @@ bool cmProcess::Buffer::GetLine(std::string& line) // Start a new range for the next line. ++this->Last; - this->First = Last; + this->First = this->Last; // Return the line extracted. return true; diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx index a98969d..3630f4e 100644 --- a/Source/LexerParser/cmGccDepfileLexer.cxx +++ b/Source/LexerParser/cmGccDepfileLexer.cxx @@ -994,7 +994,7 @@ case 5: YY_RULE_SETUP { // A line continuation ends the current file name. - yyextra->newDependency(); + yyextra->newRuleOrDependency(); } YY_BREAK case 6: diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l index 08f8577..c83cb75 100644 --- a/Source/LexerParser/cmGccDepfileLexer.in.l +++ b/Source/LexerParser/cmGccDepfileLexer.in.l @@ -42,7 +42,7 @@ NEWLINE \r?\n } {WSPACE}*\\{NEWLINE} { // A line continuation ends the current file name. - yyextra->newDependency(); + yyextra->newRuleOrDependency(); } {NEWLINE} { // A newline ends the current file name and the current rule. diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 0f0c39a..0c263bb 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -3,20 +3,52 @@ project(QtDialog) CMake_OPTIONAL_COMPONENT(cmake-gui) -find_package(Qt5Widgets REQUIRED) +set (QT_COMPONENTS + Core + Widgets + Gui +) + +set(CMake_QT_MAJOR_VERSION "A" CACHE + STRING "Expected Qt major version. Valid values are A (auto-select), 5, 6.") +set(SUPPORTED_QT_VERSIONS "A" 5 6) +set_property(CACHE CMake_QT_MAJOR_VERSION PROPERTY STRINGS ${SUPPORTED_QT_VERSIONS}) +if(NOT CMake_QT_MAJOR_VERSION STREQUAL "A") + if(NOT CMake_QT_MAJOR_VERSION IN_LIST SUPPORTED_QT_VERSIONS) + message(FATAL_ERROR "Supported Qt versions are \"${SUPPORTED_QT_VERSIONS}\"." + " But CMake_QT_MAJOR_VERSION is set to ${CMake_QT_MAJOR_VERSION}.") + endif() + set(INSTALLED_QT_VERSION ${CMake_QT_MAJOR_VERSION}) +else() + find_package(Qt6Widgets QUIET) + set(INSTALLED_QT_VERSION 6) + if(NOT Qt6Widgets_FOUND) + find_package(Qt5Widgets QUIET) + if(NOT Qt5Widgets_FOUND) + message(FATAL_ERROR "Could not find a valid Qt installation.") + endif() + set(INSTALLED_QT_VERSION 5) + endif() +endif() + +find_package(Qt${INSTALLED_QT_VERSION} + COMPONENTS ${QT_COMPONENTS} + REQUIRED QUIET +) set(CMake_QT_EXTRA_LIBRARIES) # Try to find the package WinExtras for the task bar progress if(WIN32) - find_package(Qt5WinExtras QUIET) - if (Qt5WinExtras_FOUND) + find_package(Qt${INSTALLED_QT_VERSION}WinExtras QUIET) + if (Qt${INSTALLED_QT_VERSION}WinExtras_FOUND) add_definitions(-DQT_WINEXTRAS) - list(APPEND CMake_QT_EXTRA_LIBRARIES Qt5::WinExtras) + list(APPEND CMake_QT_EXTRA_LIBRARIES Qt${INSTALLED_QT_VERSION}::WinExtras) + list(APPEND QT_COMPONENTS WinExtras) endif() endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt${INSTALLED_QT_VERSION}Widgets_EXECUTABLE_COMPILE_FLAGS}") if(CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES) list(APPEND CMake_QT_EXTRA_LIBRARIES ${CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES}) @@ -31,11 +63,25 @@ if(CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES) endif() # We need to install platform plugin and add qt.conf for Qt5 on Mac and Windows. -# FIXME: This should be part of Qt5 CMake scripts, but unfortunately -# Qt5 support is missing there. if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) - macro(install_qt5_plugin _qt_plugin_name _qt_plugins_var) - get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + function(_qt_get_plugin_name_with_version target out_var) + string(REGEX REPLACE "^Qt::(.+)" "Qt${INSTALLED_QT_VERSION}::\\1" + qt_plugin_with_version "${target}") + if(TARGET "${qt_plugin_with_version}") + set("${out_var}" "${qt_plugin_with_version}" PARENT_SCOPE) + else() + set("${out_var}" "" PARENT_SCOPE) + endif() + endfunction() + macro(install_qt_plugin _qt_plugin_name _qt_plugins_var) + if(TARGET "${_qt_plugin_name}") + get_target_property(_qt_plugin_path "${_qt_plugin_name}" LOCATION) + else() + _qt_get_plugin_name_with_version("Qt::${_qt_plugin_name}" _qt_plugin_with_version_name) + if(TARGET "${_qt_plugin_with_version_name}") + get_target_property(_qt_plugin_path "${_qt_plugin_with_version_name}" LOCATION) + endif() + endif() if(EXISTS "${_qt_plugin_path}") get_filename_component(_qt_plugin_file "${_qt_plugin_path}" NAME) get_filename_component(_qt_plugin_type "${_qt_plugin_path}" PATH) @@ -51,14 +97,34 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) ${COMPONENT}) set(${_qt_plugins_var} "${${_qt_plugins_var}};\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${_qt_plugin_dest}/${_qt_plugin_file}") - else() - message(FATAL_ERROR "QT plugin ${_qt_plugin_name} not found") endif() endmacro() + macro(install_qt_plugins _comps _plugins_var) + foreach(_qt_comp ${${_comps}}) + if (INSTALLED_QT_VERSION VERSION_LESS 6) + set(_qt_module_plugins ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_PLUGINS}) + else() + get_target_property(_qt_module_plugins Qt${INSTALLED_QT_VERSION}::${_qt_comp} QT_PLUGINS) + endif() + foreach(_qt_plugin ${_qt_module_plugins}) + if (INSTALLED_QT_VERSION VERSION_GREATER_EQUAL 6) + # Qt6 provides the plugins as individual packages that need to be found. + find_package(Qt${INSTALLED_QT_VERSION}${_qt_plugin} QUIET + PATHS ${Qt${INSTALLED_QT_VERSION}${_qt_comp}_DIR}) + endif() + install_qt_plugin("${_qt_plugin}" "${_plugins_var}") + endforeach() + endforeach() + endmacro() if(APPLE) - install_qt5_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS) - if(TARGET Qt5::QMacStylePlugin) - install_qt5_plugin("Qt5::QMacStylePlugin" QT_PLUGINS) + if (INSTALLED_QT_VERSION VERSION_EQUAL 5) + install_qt_plugin("Qt5::QCocoaIntegrationPlugin" QT_PLUGINS) + if(TARGET Qt5::QMacStylePlugin) + install_qt_plugin("Qt5::QMacStylePlugin" QT_PLUGINS) + endif() + else() + # FIXME: Minimize plugins for Qt6. + install_qt_plugins(QT_COMPONENTS QT_PLUGINS) endif() file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" "[Paths]\nPlugins = ${_qt_plugin_dir}\n") @@ -66,7 +132,12 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) DESTINATION "${CMAKE_INSTALL_PREFIX}/Resources" ${COMPONENT}) elseif(WIN32 AND NOT CMake_QT_STATIC_QWindowsIntegrationPlugin_LIBRARIES) - install_qt5_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS) + if (INSTALLED_QT_VERSION VERSION_EQUAL 5) + install_qt_plugin("Qt5::QWindowsIntegrationPlugin" QT_PLUGINS) + else() + # FIXME: Minimize plugins for Qt6. + install_qt_plugins(QT_COMPONENTS QT_PLUGINS) + endif() file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" "[Paths]\nPlugins = ../${_qt_plugin_dir}\n") install(FILES "${CMAKE_CURRENT_BINARY_DIR}/qt.conf" @@ -75,8 +146,8 @@ if(CMake_INSTALL_DEPENDENCIES AND (APPLE OR WIN32)) endif() endif() -get_property(_Qt5_Core_LOCATION TARGET Qt5::Core PROPERTY LOCATION) -get_filename_component(Qt_BIN_DIR "${_Qt5_Core_LOCATION}" PATH) +get_property(_Qt_Core_LOCATION TARGET Qt${INSTALLED_QT_VERSION}::Core PROPERTY LOCATION) +get_filename_component(Qt_BIN_DIR "${_Qt_Core_LOCATION}" PATH) if(APPLE) get_filename_component(Qt_BIN_DIR "${Qt_BIN_DIR}" PATH) endif() @@ -108,7 +179,7 @@ set(SRCS WarningMessagesDialog.cxx WarningMessagesDialog.h ) -qt5_wrap_ui(UI_SRCS +set(UI_SRCS CMakeSetupDialog.ui Compilers.ui CrossCompiler.ui @@ -117,7 +188,7 @@ qt5_wrap_ui(UI_SRCS RegexExplorer.ui WarningMessagesDialog.ui ) -qt5_wrap_cpp(MOC_SRCS +set(MOC_SRCS AddCacheEntry.h Compilers.h CMakeSetupDialog.h @@ -131,8 +202,18 @@ qt5_wrap_cpp(MOC_SRCS RegexExplorer.h WarningMessagesDialog.h ) -qt5_add_resources(RC_SRCS CMakeSetup.qrc) -add_library(CMakeGUIQRCLib OBJECT ${RC_SRCS}) +set(QRC_SRCS CMakeSetup.qrc) + +if (INSTALLED_QT_VERSION VERSION_LESS 6) + qt5_wrap_ui(UI_BUILT_SRCS ${UI_SRCS}) + qt5_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS}) + qt5_add_resources(QRC_BUILT_SRCS ${QRC_SRCS}) +else() + qt_wrap_ui(UI_BUILT_SRCS ${UI_SRCS}) + qt_wrap_cpp(MOC_BUILT_SRCS ${MOC_SRCS}) + qt_add_resources(QRC_BUILT_SRCS ${QRC_SRCS}) +endif() +add_library(CMakeGUIQRCLib OBJECT ${QRC_BUILT_SRCS}) if (FALSE) # CMake's bootstrap binary does not support automoc set(CMAKE_AUTOMOC 1) @@ -140,8 +221,8 @@ if (FALSE) # CMake's bootstrap binary does not support automoc set(CMAKE_AUTOUIC 1) else () list(APPEND SRCS - ${UI_SRCS} - ${MOC_SRCS}) + ${UI_BUILT_SRCS} + ${MOC_BUILT_SRCS}) endif () if(USE_LGPL) @@ -156,13 +237,14 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_library(CMakeGUILib STATIC ${SRCS}) # CMake_QT_EXTRA_LIBRARIES have to come before the main libraries on the link line -target_link_libraries(CMakeGUILib PUBLIC CMakeLib ${CMake_QT_EXTRA_LIBRARIES} Qt5::Core Qt5::Widgets) +target_link_libraries(CMakeGUILib PUBLIC CMakeLib ${CMake_QT_EXTRA_LIBRARIES} + Qt${INSTALLED_QT_VERSION}::Core Qt${INSTALLED_QT_VERSION}::Widgets) add_library(CMakeGUIMainLib STATIC CMakeSetup.cxx) target_link_libraries(CMakeGUIMainLib PUBLIC CMakeGUILib) add_executable(cmake-gui WIN32 MACOSX_BUNDLE CMakeGUIExec.cxx ${MANIFEST_FILE}) -target_link_libraries(cmake-gui CMakeGUIMainLib Qt5::Core) +target_link_libraries(cmake-gui CMakeGUIMainLib Qt${INSTALLED_QT_VERSION}::Core) target_sources(CMakeGUIMainLib INTERFACE $<TARGET_OBJECTS:CMakeGUIQRCLib>) if(WIN32) diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index c1555a2..5debdb8 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -7,7 +7,6 @@ #include <QDir> #include <QLocale> #include <QString> -#include <QTextCodec> #include <QTranslator> #include <QtPlugin> @@ -122,9 +121,6 @@ int main(int argc, char** argv) setlocale(LC_NUMERIC, "C"); - QTextCodec* utf8_codec = QTextCodec::codecForName("UTF-8"); - QTextCodec::setCodecForLocale(utf8_codec); - // tell the cmake library where cmake is QDir cmExecDir(QApplication::applicationDirPath()); #if defined(Q_OS_MAC) @@ -146,7 +142,7 @@ int main(int argc, char** argv) QIcon appIcon; appIcon.addFile(":/Icons/CMakeSetup32.png"); appIcon.addFile(":/Icons/CMakeSetup128.png"); - QApplication::setWindowIcon(appIcon); + QApplication::setWindowIcon(QIcon::fromTheme("cmake-gui", appIcon)); CMakeSetupDialog dialog; dialog.show(); diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx index 846456c..d4f978c 100644 --- a/Source/QtDialog/EnvironmentDialog.cxx +++ b/Source/QtDialog/EnvironmentDialog.cxx @@ -81,7 +81,11 @@ bool EnvironmentSearchFilter::filterAcceptsRow(int row, auto* model = this->sourceModel(); auto key = model->data(model->index(row, 0, parent), Qt::DisplayRole).toString(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + return key.contains(this->filterRegularExpression()); +#else return key.contains(this->filterRegExp()); +#endif } EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment, diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index 22f5be1..7c9032e 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -47,7 +47,11 @@ protected: // check all strings for a match foreach (QString const& str, strs) { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + if (str.contains(this->filterRegularExpression())) { +#else if (str.contains(this->filterRegExp())) { +#endif return true; } } diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx index e68faba..ca65d13 100644 --- a/Source/QtDialog/QCMakeWidgets.cxx +++ b/Source/QtDialog/QCMakeWidgets.cxx @@ -1,20 +1,23 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -// FIXME: Port to QFileSystemModel from the deprecated QDirModel. -// Be sure completion works when incrementally editing existing paths. #define QT_DEPRECATED_WARNINGS_SINCE QT_VERSION_CHECK(5, 14, 0) #include "QCMakeWidgets.h" #include <utility> -#include <QDirModel> #include <QFileDialog> #include <QFileInfo> #include <QResizeEvent> #include <QToolButton> +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +# include <QFileSystemModel> +#else +# include <QDirModel> +#endif + QCMakeFileEditor::QCMakeFileEditor(QWidget* p, QString var) : QLineEdit(p) , Variable(std::move(var)) @@ -93,8 +96,30 @@ void QCMakePathEditor::chooseFile() } } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +// use same QFileSystemModel for all completers +static QFileSystemModel* fileDirModel() + +{ + static QFileSystemModel* m = nullptr; + if (!m) { + m = new QFileSystemModel(); + } + return m; +} +static QFileSystemModel* pathDirModel() +{ + static QFileSystemModel* m = nullptr; + if (!m) { + m = new QFileSystemModel(); + m->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot); + } + return m; +} +#else // use same QDirModel for all completers static QDirModel* fileDirModel() + { static QDirModel* m = nullptr; if (!m) { @@ -111,12 +136,19 @@ static QDirModel* pathDirModel() } return m; } +#endif QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs) : QCompleter(o) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QFileSystemModel* m = dirs ? pathDirModel() : fileDirModel(); + this->setModel(m); + m->setRootPath(QString()); +#else QDirModel* m = dirs ? pathDirModel() : fileDirModel(); this->setModel(m); +#endif } QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index 8435740..0dc954a 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx @@ -467,7 +467,7 @@ bool DumpFile(std::string const& nmPath, const char* filename, bool bindexplib::AddObjectFile(const char* filename) { - return DumpFile(NmPath, filename, this->Symbols, this->DataSymbols); + return DumpFile(this->NmPath, filename, this->Symbols, this->DataSymbols); } bool bindexplib::AddDefinitionFile(const char* filename) @@ -511,5 +511,5 @@ void bindexplib::WriteFile(FILE* file) void bindexplib::SetNmPath(std::string const& nm) { - NmPath = nm; + this->NmPath = nm; } diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 231a2d6..ff2cc3e 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -5,11 +5,11 @@ #include <sstream> #include <unordered_set> -#include "cmCheckCustomOutputs.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmCustomCommandTypes.h" #include "cmExecutionStatus.h" +#include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -188,17 +188,10 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, case doing_output: case doing_outputs: case doing_byproducts: - if (!cmSystemTools::FileIsFullPath(copy)) { + if (!cmSystemTools::FileIsFullPath(copy) && + cmGeneratorExpression::Find(copy) != 0) { // This is an output to be generated, so it should be - // under the build tree. CMake 2.4 placed this under the - // source tree. However the only case that this change - // will break is when someone writes - // - // add_custom_command(OUTPUT out.txt ...) - // - // and later references "${CMAKE_CURRENT_SOURCE_DIR}/out.txt". - // This is fairly obscure so we can wait for someone to - // complain. + // under the build tree. filename = cmStrCat(mf.GetCurrentBinaryDirectory(), '/'); } filename += copy; @@ -215,8 +208,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, } if (cmSystemTools::FileIsFullPath(filename)) { - filename = cmSystemTools::CollapseFullPath( - filename, status.GetMakefile().GetHomeOutputDirectory()); + filename = cmSystemTools::CollapseFullPath(filename); } switch (doing) { case doing_depfile: @@ -304,26 +296,18 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, status.SetError("given APPEND option with no OUTPUT."); return false; } - - // Make sure the output names and locations are safe. - if (!cmCheckCustomOutputs(output, "OUTPUT", status) || - !cmCheckCustomOutputs(outputs, "OUTPUTS", status) || - !cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) { + if (!implicit_depends.empty() && !depfile.empty() && + mf.GetGlobalGenerator()->GetName() != "Ninja") { + // Makefiles generators does not support both at the same time + status.SetError("IMPLICIT_DEPENDS and DEPFILE can not both be specified."); return false; } // Check for an append request. if (append) { - if (mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends, - commandLines)) { - return true; - } - - // No command for this output exists. - status.SetError( - cmStrCat("given APPEND option with output\n ", output[0], - "\nwhich is not already a custom command output.")); - return false; + mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends, + commandLines); + return true; } if (uses_terminal && !job_pool.empty()) { diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index aa98d89..104065f 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -4,7 +4,6 @@ #include <utility> -#include "cmCheckCustomOutputs.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" @@ -120,12 +119,16 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args, break; case doing_byproducts: { std::string filename; - if (!cmSystemTools::FileIsFullPath(copy)) { + if (!cmSystemTools::FileIsFullPath(copy) && + cmGeneratorExpression::Find(copy) != 0) { filename = cmStrCat(mf.GetCurrentBinaryDirectory(), '/'); } filename += copy; cmSystemTools::ConvertToUnixSlashes(filename); - byproducts.push_back(cmSystemTools::CollapseFullPath(filename)); + if (cmSystemTools::FileIsFullPath(filename)) { + filename = cmSystemTools::CollapseFullPath(filename); + } + byproducts.push_back(filename); } break; case doing_depends: { std::string dep = copy; @@ -206,11 +209,6 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args, return false; } - // Make sure the byproduct names and locations are safe. - if (!cmCheckCustomOutputs(byproducts, "BYPRODUCTS", status)) { - return false; - } - // Add the utility target to the makefile. bool escapeOldStyle = !verbatim; cmTarget* target = mf.AddUtilityCommand( diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h index 87000da..c192e2a 100644 --- a/Source/cmAlgorithms.h +++ b/Source/cmAlgorithms.h @@ -47,7 +47,8 @@ struct BinarySearcher bool operator()(argument_type const& item) const { - return std::binary_search(m_range.begin(), m_range.end(), item); + return std::binary_search(this->m_range.begin(), this->m_range.end(), + item); } private: diff --git a/Source/cmArchiveWrite.h b/Source/cmArchiveWrite.h index 0d33758..168d30e 100644 --- a/Source/cmArchiveWrite.h +++ b/Source/cmArchiveWrite.h @@ -26,7 +26,7 @@ public: } void Clear() { this->IsValueSet = false; } bool IsSet() const { return this->IsValueSet; } - T Get() const { return Value; } + T Get() const { return this->Value; } private: T Value; diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx index 720f582..e9bf84a 100644 --- a/Source/cmCMakePathCommand.cxx +++ b/Source/cmCMakePathCommand.cxx @@ -37,7 +37,7 @@ public: template <typename T> CMakePathArgumentParser& Bind(cm::static_string_view name, T Result::*member) { - cmArgumentParser<Result>::Bind(name, member); + this->cmArgumentParser<Result>::Bind(name, member); return *this; } @@ -48,12 +48,12 @@ public: { this->Inputs.clear(); - return cmArgumentParser<Result>::Parse(cmMakeRange(args).advance(Advance), - &this->Inputs, keywordsMissingValue, - parsedKeywords); + return this->cmArgumentParser<Result>::Parse( + cmMakeRange(args).advance(Advance), &this->Inputs, keywordsMissingValue, + parsedKeywords); } - const std::vector<std::string>& GetInputs() const { return Inputs; } + const std::vector<std::string>& GetInputs() const { return this->Inputs; } protected: mutable std::vector<std::string> Inputs; @@ -74,7 +74,7 @@ public: ArgumentParserWithOutputVariable& Bind(cm::static_string_view name, T Result::*member) { - cmArgumentParser<Result>::Bind(name, member); + this->cmArgumentParser<Result>::Bind(name, member); return *this; } @@ -84,7 +84,7 @@ public: this->KeywordsMissingValue.clear(); this->ParsedKeywords.clear(); - return CMakePathArgumentParser<Result>::template Parse<Advance>( + return this->CMakePathArgumentParser<Result>::template Parse<Advance>( args, &this->KeywordsMissingValue, &this->ParsedKeywords); } @@ -250,9 +250,48 @@ bool HandleGetCommand(std::vector<std::string> const& args, return true; } +bool HandleSetCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.size() < 3 || args.size() > 4) { + status.SetError("SET must be called with two or three arguments."); + return false; + } + + if (args[1].empty()) { + status.SetError("Invalid name for path variable."); + return false; + } + + static NormalizeParser const parser; + + const auto arguments = parser.Parse(args); + + if (parser.GetInputs().size() != 1) { + status.SetError("SET called with unexpected arguments."); + return false; + } + + auto path = + cmCMakePath(parser.GetInputs().front(), cmCMakePath::native_format); + + if (arguments.Normalize) { + path = path.Normal(); + } + + status.GetMakefile().AddDefinition(args[1], path.GenericString()); + + return true; +} + bool HandleAppendCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { + if (args[1].empty()) { + status.SetError("Invalid name for path variable."); + return false; + } + static OutputVariableParser const parser{}; const auto arguments = parser.Parse(args); @@ -272,8 +311,8 @@ bool HandleAppendCommand(std::vector<std::string> const& args, return true; } -bool HandleConcatCommand(std::vector<std::string> const& args, - cmExecutionStatus& status) +bool HandleAppendStringCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) { static OutputVariableParser const parser{}; @@ -546,16 +585,6 @@ bool HandleRelativePathCommand(std::vector<std::string> const& args, }); } -bool HandleProximatePathCommand(std::vector<std::string> const& args, - cmExecutionStatus& status) -{ - return HandleTransformPathCommand( - args, status, - [](const cmCMakePath& path, const std::string& base) -> cmCMakePath { - return path.Proximate(base); - }); -} - bool HandleAbsolutePathCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -567,40 +596,6 @@ bool HandleAbsolutePathCommand(std::vector<std::string> const& args, true); } -bool HandleCMakePathCommand(std::vector<std::string> const& args, - cmExecutionStatus& status) -{ - if (args.size() < 3 || args.size() > 4) { - status.SetError("CMAKE_PATH must be called with two or three arguments."); - return false; - } - - static NormalizeParser const parser; - - const auto arguments = parser.Parse(args); - - if (parser.GetInputs().size() != 1) { - status.SetError("CMAKE_PATH called with unexpected arguments."); - return false; - } - - if (args[1].empty()) { - status.SetError("Invalid name for output variable."); - return false; - } - - auto path = - cmCMakePath(parser.GetInputs().front(), cmCMakePath::native_format); - - if (arguments.Normalize) { - path = path.Normal(); - } - - status.GetMakefile().AddDefinition(args[1], path.GenericString()); - - return true; -} - bool HandleNativePathCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -737,12 +732,7 @@ bool HandleCompareCommand(std::vector<std::string> const& args, return false; } - std::string inputPath; - if (!getInputPath(args[1], status, inputPath)) { - return false; - } - - cmCMakePath path1(inputPath); + cmCMakePath path1(args[1]); cmCMakePath path2(args[3]); auto result = op->second(path1, path2); @@ -987,17 +977,16 @@ bool cmCMakePathCommand(std::vector<std::string> const& args, static cmSubcommandTable const subcommand{ { "GET"_s, HandleGetCommand }, + { "SET"_s, HandleSetCommand }, { "APPEND"_s, HandleAppendCommand }, - { "CONCAT"_s, HandleConcatCommand }, + { "APPEND_STRING"_s, HandleAppendStringCommand }, { "REMOVE_FILENAME"_s, HandleRemoveFilenameCommand }, { "REPLACE_FILENAME"_s, HandleReplaceFilenameCommand }, { "REMOVE_EXTENSION"_s, HandleRemoveExtensionCommand }, { "REPLACE_EXTENSION"_s, HandleReplaceExtensionCommand }, { "NORMAL_PATH"_s, HandleNormalPathCommand }, { "RELATIVE_PATH"_s, HandleRelativePathCommand }, - { "PROXIMATE_PATH"_s, HandleProximatePathCommand }, { "ABSOLUTE_PATH"_s, HandleAbsolutePathCommand }, - { "CMAKE_PATH"_s, HandleCMakePathCommand }, { "NATIVE_PATH"_s, HandleNativePathCommand }, { "CONVERT"_s, HandleConvertCommand }, { "COMPARE"_s, HandleCompareCommand }, diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx index b7f08d2..1f99043 100644 --- a/Source/cmCMakePolicyCommand.cxx +++ b/Source/cmCMakePolicyCommand.cxx @@ -191,8 +191,7 @@ bool HandleVersionMode(std::vector<std::string> const& args, return false; } - status.GetMakefile().SetPolicyVersion(version_min, version_max); - return true; + return status.GetMakefile().SetPolicyVersion(version_min, version_max); } bool HandleGetWarningMode(std::vector<std::string> const& args, diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 8ebf6d2..9e3582c 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -550,6 +550,11 @@ void* CCONV cmAddSource(void* arg, void* arg2) // Create the real cmSourceFile instance and copy over saved information. cmSourceFile* rsf = mf->GetOrCreateSource(osf->FullPath); rsf->SetProperties(osf->Properties); + // In case the properties contain the GENERATED property, + // mark the real cmSourceFile as generated. + if (rsf->GetIsGenerated()) { + rsf->MarkAsGenerated(); + } for (std::string const& d : osf->Depends) { rsf->AddDepend(d); } @@ -583,14 +588,12 @@ const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { - cmProp p = rsf->GetProperty(prop); - return cmToCStr(p); + return cmToCStr(rsf->GetProperty(prop)); } if (!strcmp(prop, "LOCATION")) { return sf->FullPath.c_str(); } - cmProp retVal = sf->Properties.GetPropertyValue(prop); - return cmToCStr(retVal); + return cmToCStr(sf->Properties.GetPropertyValue(prop)); } int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 8cf5ae9..6c1071d 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -4,6 +4,7 @@ #include <algorithm> #include <cctype> +#include <cerrno> #include <chrono> #include <cstdio> #include <cstdlib> @@ -179,6 +180,7 @@ struct cmCTest::Private // information for the --build-and-test options std::string BinaryDir; + std::string TestDir; std::string NotesFiles; @@ -1017,6 +1019,17 @@ int cmCTest::ProcessSteps() } if (res != 0) { cmCTestLog(this, ERROR_MESSAGE, "Errors while running CTest" << std::endl); + if (!this->Impl->OutputTestOutputOnTestFailure) { + const std::string lastTestLog = + this->GetBinaryDir() + "/Testing/Temporary/LastTest.log"; + cmCTestLog(this, ERROR_MESSAGE, + "Output from these tests are in: " << lastTestLog + << std::endl); + cmCTestLog(this, ERROR_MESSAGE, + "Use \"--rerun-failed --output-on-failure\" to re-run the " + "failed cases verbosely." + << std::endl); + } } return res; } @@ -1313,11 +1326,11 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, if (result == cmsysProcess_State_Exited) { *retVal = cmsysProcess_GetExitValue(cp); if (*retVal != 0 && this->Impl->OutputTestOutputOnTestFailure) { - OutputTestErrors(tempOutput); + this->OutputTestErrors(tempOutput); } } else if (result == cmsysProcess_State_Exception) { if (this->Impl->OutputTestOutputOnTestFailure) { - OutputTestErrors(tempOutput); + this->OutputTestErrors(tempOutput); } *retVal = cmsysProcess_GetExitException(cp); std::string outerr = cmStrCat("\n*** Exception executing: ", @@ -2048,6 +2061,13 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, i++; this->SetNotesFiles(args[i]); return true; + } else if (this->CheckArgument(arg, "--test-dir"_s)) { + if (i >= args.size() - 1) { + errormsg = "'--test-dir' requires an argument"; + return false; + } + i++; + this->Impl->TestDir = std::string(args[i]); } cm::string_view noTestsPrefix = "--no-tests="; @@ -2456,8 +2476,26 @@ int cmCTest::ExecuteTests() handler->SetVerbose(this->Impl->Verbose); handler->SetSubmitIndex(this->Impl->SubmitIndex); } - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - if (!this->Initialize(cwd.c_str(), nullptr)) { + + const std::string currDir = cmSystemTools::GetCurrentWorkingDirectory(); + std::string workDir = currDir; + if (!this->Impl->TestDir.empty()) { + workDir = cmSystemTools::CollapseFullPath(this->Impl->TestDir); + } + + if (currDir != workDir) { + cmCTestLog(this, OUTPUT, + "Internal ctest changing into directory: " << workDir + << std::endl); + if (cmSystemTools::ChangeDirectory(workDir) != 0) { + auto msg = "Failed to change working directory to \"" + workDir + + "\" : " + std::strerror(errno) + "\n"; + cmCTestLog(this, ERROR_MESSAGE, msg); + return 1; + } + } + + if (!this->Initialize(workDir.c_str(), nullptr)) { res = 12; cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard." << std::endl); @@ -2465,6 +2503,10 @@ int cmCTest::ExecuteTests() res = this->ProcessSteps(); } this->Finalize(); + + if (currDir != workDir) { + cmSystemTools::ChangeDirectory(currDir); + } } if (res != 0) { cmCTestLog(this, DEBUG, @@ -2859,7 +2901,7 @@ bool cmCTest::GetFailover() const bool cmCTest::GetTestProgressOutput() const { - return this->Impl->TestProgressOutput; + return this->Impl->TestProgressOutput && !GetExtraVerbose(); } bool cmCTest::GetVerbose() const diff --git a/Source/cmCheckCustomOutputs.cxx b/Source/cmCheckCustomOutputs.cxx deleted file mode 100644 index 7645c88..0000000 --- a/Source/cmCheckCustomOutputs.cxx +++ /dev/null @@ -1,36 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCheckCustomOutputs.h" - -#include "cmExecutionStatus.h" -#include "cmMakefile.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" - -bool cmCheckCustomOutputs(const std::vector<std::string>& outputs, - cm::string_view keyword, cmExecutionStatus& status) -{ - cmMakefile& mf = status.GetMakefile(); - - for (std::string const& o : outputs) { - // Make sure the file will not be generated into the source - // directory during an out of source build. - if (!mf.CanIWriteThisFile(o)) { - status.SetError( - cmStrCat("attempted to have a file\n ", o, - "\nin a source directory as an output of custom command.")); - cmSystemTools::SetFatalErrorOccured(); - return false; - } - - // Make sure the output file name has no invalid characters. - std::string::size_type pos = o.find_first_of("#<>"); - if (pos != std::string::npos) { - status.SetError(cmStrCat("called with ", keyword, " containing a \"", - o[pos], "\". This character is not allowed.")); - return false; - } - } - - return true; -} diff --git a/Source/cmCheckCustomOutputs.h b/Source/cmCheckCustomOutputs.h deleted file mode 100644 index 2752ed4..0000000 --- a/Source/cmCheckCustomOutputs.h +++ /dev/null @@ -1,15 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <string> -#include <vector> - -#include <cm/string_view> - -class cmExecutionStatus; - -bool cmCheckCustomOutputs(const std::vector<std::string>& outputs, - cm::string_view keyword, cmExecutionStatus& status); diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index d4f5022..6d5e064 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -240,7 +240,7 @@ int cmCommandArgumentParserHelper::ParseString(std::string const& str, this->CleanupParser(); - if (Verbose) { + if (this->Verbose) { std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]" << std::endl; } diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h new file mode 100644 index 0000000..cbedf0a --- /dev/null +++ b/Source/cmCommandLineArgument.h @@ -0,0 +1,159 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +template <typename FunctionSignature> +struct cmCommandLineArgument +{ + enum class Values + { + Zero, + One, + Two, + ZeroOrOne, + OneOrMore + }; + + std::string InvalidSyntaxMessage; + std::string InvalidValueMessage; + std::string Name; + Values Type; + std::function<FunctionSignature> StoreCall; + + template <typename FunctionType> + cmCommandLineArgument(std::string n, Values t, FunctionType&& func) + : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n)) + , InvalidValueMessage(cmStrCat("Invalid value used with ", n)) + , Name(std::move(n)) + , Type(t) + , StoreCall(std::forward<FunctionType>(func)) + { + } + + template <typename FunctionType> + cmCommandLineArgument(std::string n, std::string failedMsg, Values t, + FunctionType&& func) + : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n)) + , InvalidValueMessage(std::move(failedMsg)) + , Name(std::move(n)) + , Type(t) + , StoreCall(std::forward<FunctionType>(func)) + { + } + + bool matches(std::string const& input) const + { + return (this->Type == Values::Zero) ? (input == this->Name) + : cmHasPrefix(input, this->Name); + } + + template <typename T, typename... CallState> + bool parse(std::string const& input, T& index, + std::vector<std::string> const& allArgs, + CallState&&... state) const + { + enum class ParseMode + { + Valid, + Invalid, + SyntaxError, + ValueError + }; + ParseMode parseState = ParseMode::Valid; + + if (this->Type == Values::Zero) { + if (input.size() == this->Name.size()) { + parseState = + this->StoreCall(std::string{}, std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } else { + parseState = ParseMode::SyntaxError; + } + + } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) { + if (input.size() == this->Name.size()) { + ++index; + if (index >= allArgs.size() || allArgs[index][0] == '-') { + if (this->Type == Values::ZeroOrOne) { + parseState = + this->StoreCall(std::string{}, std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } else { + parseState = ParseMode::ValueError; + } + } else { + parseState = + this->StoreCall(allArgs[index], std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } + } else { + // parse the string to get the value + auto possible_value = cm::string_view(input).substr(this->Name.size()); + if (possible_value.empty()) { + parseState = ParseMode::SyntaxError; + parseState = ParseMode::ValueError; + } else if (possible_value[0] == '=') { + possible_value.remove_prefix(1); + if (possible_value.empty()) { + parseState = ParseMode::ValueError; + } else { + parseState = this->StoreCall(std::string(possible_value), + std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } + } + if (parseState == ParseMode::Valid) { + parseState = this->StoreCall(std::string(possible_value), + std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } + } + } else if (this->Type == Values::Two) { + if (input.size() == this->Name.size()) { + if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' || + allArgs[index + 2][0] == '-') { + parseState = ParseMode::ValueError; + } else { + index += 2; + parseState = + this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]), + std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } + } + } else if (this->Type == Values::OneOrMore) { + if (input.size() == this->Name.size()) { + auto nextValueIndex = index + 1; + if (nextValueIndex >= allArgs.size() || allArgs[index + 1][0] == '-') { + parseState = ParseMode::ValueError; + } else { + std::string buffer = allArgs[nextValueIndex++]; + while (nextValueIndex < allArgs.size() && + allArgs[nextValueIndex][0] != '-') { + buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]); + } + parseState = + this->StoreCall(buffer, std::forward<CallState>(state)...) + ? ParseMode::Valid + : ParseMode::Invalid; + } + } + } + + if (parseState == ParseMode::SyntaxError) { + cmSystemTools::Error(this->InvalidSyntaxMessage); + } else if (parseState == ParseMode::ValueError) { + cmSystemTools::Error(this->InvalidValueMessage); + } + return (parseState == ParseMode::Valid); + } +}; diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index c94f128..9e5b783 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -17,6 +17,7 @@ #include "cmBreakCommand.h" #include "cmBuildCommand.h" #include "cmCMakeMinimumRequired.h" +#include "cmCMakePathCommand.h" #include "cmCMakePolicyCommand.h" #include "cmCommand.h" #include "cmConfigureFileCommand.h" @@ -118,11 +119,19 @@ void GetScriptingCommands(cmState* state) { - state->AddBuiltinCommand("break", cmBreakCommand); + state->AddFlowControlCommand("break", cmBreakCommand); + state->AddFlowControlCommand("continue", cmContinueCommand); + state->AddFlowControlCommand("foreach", cmForEachCommand); + state->AddFlowControlCommand("function", cmFunctionCommand); + state->AddFlowControlCommand("if", cmIfCommand); + state->AddFlowControlCommand("macro", cmMacroCommand); + state->AddFlowControlCommand("return", cmReturnCommand); + state->AddFlowControlCommand("while", cmWhileCommand); + state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired); + state->AddBuiltinCommand("cmake_path", cmCMakePathCommand); state->AddBuiltinCommand("cmake_policy", cmCMakePolicyCommand); state->AddBuiltinCommand("configure_file", cmConfigureFileCommand); - state->AddBuiltinCommand("continue", cmContinueCommand); state->AddBuiltinCommand("exec_program", cmExecProgramCommand); state->AddBuiltinCommand("execute_process", cmExecuteProcessCommand); state->AddBuiltinCommand("file", cmFileCommand); @@ -131,26 +140,21 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("find_package", cmFindPackage); state->AddBuiltinCommand("find_path", cmFindPath); state->AddBuiltinCommand("find_program", cmFindProgram); - state->AddBuiltinCommand("foreach", cmForEachCommand); - state->AddBuiltinCommand("function", cmFunctionCommand); state->AddBuiltinCommand("get_cmake_property", cmGetCMakePropertyCommand); state->AddBuiltinCommand("get_directory_property", cmGetDirectoryPropertyCommand); state->AddBuiltinCommand("get_filename_component", cmGetFilenameComponentCommand); state->AddBuiltinCommand("get_property", cmGetPropertyCommand); - state->AddBuiltinCommand("if", cmIfCommand); state->AddBuiltinCommand("include", cmIncludeCommand); state->AddBuiltinCommand("include_guard", cmIncludeGuardCommand); state->AddBuiltinCommand("list", cmListCommand); - state->AddBuiltinCommand("macro", cmMacroCommand); state->AddBuiltinCommand("make_directory", cmMakeDirectoryCommand); state->AddBuiltinCommand("mark_as_advanced", cmMarkAsAdvancedCommand); state->AddBuiltinCommand("math", cmMathCommand); state->AddBuiltinCommand("message", cmMessageCommand); state->AddBuiltinCommand("option", cmOptionCommand); state->AddBuiltinCommand("cmake_parse_arguments", cmParseArgumentsCommand); - state->AddBuiltinCommand("return", cmReturnCommand); state->AddBuiltinCommand("separate_arguments", cmSeparateArgumentsCommand); state->AddBuiltinCommand("set", cmSetCommand); state->AddBuiltinCommand("set_directory_properties", @@ -159,7 +163,6 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("site_name", cmSiteNameCommand); state->AddBuiltinCommand("string", cmStringCommand); state->AddBuiltinCommand("unset", cmUnsetCommand); - state->AddBuiltinCommand("while", cmWhileCommand); state->AddUnexpectedCommand( "else", diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 2b7c9f6..228cff7 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -27,7 +27,7 @@ cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt) static_cast<cmLocalCommonGenerator*>(gt->LocalGenerator)) , GlobalCommonGenerator(static_cast<cmGlobalCommonGenerator*>( gt->LocalGenerator->GetGlobalGenerator())) - , ConfigNames(LocalCommonGenerator->GetConfigNames()) + , ConfigNames(this->LocalCommonGenerator->GetConfigNames()) { } diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 201a9d9..6e1fac0 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -699,9 +699,13 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item, } else { // This is not a CMake target. Use the name given. if (cmSystemTools::FileIsFullPath(item.Value)) { - if (cmSystemTools::FileIsDirectory(item.Value)) { + if (cmSystemTools::IsPathToFramework(item.Value) && + this->Makefile->IsOn("APPLE")) { + // This is a framework. + this->AddFrameworkItem(item.Value); + } else if (cmSystemTools::FileIsDirectory(item.Value)) { // This is a directory. - this->AddDirectoryItem(item.Value); + this->DropDirectoryItem(item.Value); } else { // Use the full path given to the library file. this->Depends.push_back(item.Value); @@ -1306,16 +1310,6 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) } } -void cmComputeLinkInformation::AddDirectoryItem(std::string const& item) -{ - if (this->Makefile->IsOn("APPLE") && - cmSystemTools::IsPathToFramework(item)) { - this->AddFrameworkItem(item); - } else { - this->DropDirectoryItem(item); - } -} - void cmComputeLinkInformation::DropDirectoryItem(std::string const& item) { // A full path to a directory was found as a link item. Warn the diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 543b6d7..ec8d73c 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -155,7 +155,6 @@ private: void AddFullItem(BT<std::string> const& item); bool CheckImplicitDirItem(std::string const& item); void AddUserItem(BT<std::string> const& item, bool pathNotKnown); - void AddDirectoryItem(std::string const& item); void AddFrameworkItem(std::string const& item); void DropDirectoryItem(std::string const& item); bool CheckSharedLibNoSOName(std::string const& item); diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 1f22ce6..85a9d9c 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -525,7 +525,7 @@ void cmComputeTargetDepends::DisplayGraph(Graph const& graph, void cmComputeTargetDepends::DisplaySideEffects() { fprintf(stderr, "The side effects are:\n"); - int n = static_cast<int>(SideEffects.size()); + int n = static_cast<int>(this->SideEffects.size()); for (int depender_index = 0; depender_index < n; ++depender_index) { cmGeneratorTarget const* depender = this->Targets[depender_index]; fprintf(stderr, "target %d is [%s]\n", depender_index, diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 14f10bd74..62bc526 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -271,10 +271,10 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( { // Use the policy if it is set. if (this->Policy12Status == cmPolicies::NEW) { - return GetBooleanValue(newArg); + return this->GetBooleanValue(newArg); } if (this->Policy12Status == cmPolicies::OLD) { - return GetBooleanValueOld(newArg, oneArg); + return this->GetBooleanValueOld(newArg, oneArg); } // Check policy only if old and new results differ. @@ -367,7 +367,7 @@ bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs, reducible = 0; auto arg = newArgs.begin(); while (arg != newArgs.end()) { - if (IsKeyword(keyParenL, *arg)) { + if (this->IsKeyword(keyParenL, *arg)) { // search for the closing paren for this opening one cmArgumentList::iterator argClose; argClose = arg; @@ -531,7 +531,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, argP1 = arg; this->IncrementArguments(newArgs, argP1, argP2); if (argP1 != newArgs.end() && argP2 != newArgs.end() && - IsKeyword(keyMATCHES, *argP1)) { + this->IsKeyword(keyMATCHES, *argP1)) { def = this->GetDefinitionIfUnquoted(*arg); if (!def) { def = &arg->GetValue(); @@ -707,8 +707,8 @@ bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs, cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; - IncrementArguments(newArgs, argP1, argP2); - if (argP1 != newArgs.end() && IsKeyword(keyNOT, *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); @@ -735,8 +735,8 @@ bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs, cmArgumentList::iterator argP2; while (arg != newArgs.end()) { argP1 = arg; - IncrementArguments(newArgs, argP1, argP2); - if (argP1 != newArgs.end() && IsKeyword(keyAND, *argP1) && + this->IncrementArguments(newArgs, argP1, argP2); + if (argP1 != newArgs.end() && this->IsKeyword(keyAND, *argP1) && argP2 != newArgs.end()) { lhs = this->GetBooleanValueWithAutoDereference(*arg, errorString, status); diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx index 68322cc..edd261d 100644 --- a/Source/cmConfigureFileCommand.cxx +++ b/Source/cmConfigureFileCommand.cxx @@ -3,11 +3,15 @@ #include "cmConfigureFileCommand.h" #include <set> +#include <sstream> #include <cm/string_view> #include <cmext/string_view> +#include <sys/types.h> + #include "cmExecutionStatus.h" +#include "cmFSPermissions.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmNewLineStyle.h" @@ -60,7 +64,19 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, } bool copyOnly = false; bool escapeQuotes = false; - bool use_source_permissions = true; + bool useSourcePermissions = false; + bool noSourcePermissions = false; + bool filePermissions = false; + std::vector<std::string> filePermissionOptions; + + enum class Doing + { + DoingNone, + DoingFilePermissions, + DoneFilePermissions + }; + + Doing doing = Doing::DoingNone; static std::set<cm::string_view> noopOptions = { /* Legacy. */ @@ -78,6 +94,9 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, bool atOnly = false; for (unsigned int i = 2; i < args.size(); ++i) { if (args[i] == "COPYONLY") { + if (doing == Doing::DoingFilePermissions) { + doing = Doing::DoneFilePermissions; + } copyOnly = true; if (newLineStyle.IsValid()) { status.SetError("COPYONLY could not be used in combination " @@ -85,13 +104,49 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, return false; } } else if (args[i] == "ESCAPE_QUOTES") { + if (doing == Doing::DoingFilePermissions) { + doing = Doing::DoneFilePermissions; + } escapeQuotes = true; } else if (args[i] == "@ONLY") { + if (doing == Doing::DoingFilePermissions) { + doing = Doing::DoneFilePermissions; + } atOnly = true; } else if (args[i] == "NO_SOURCE_PERMISSIONS") { - use_source_permissions = false; + if (doing == Doing::DoingFilePermissions) { + status.SetError(" given both FILE_PERMISSIONS and " + "NO_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + noSourcePermissions = true; + } else if (args[i] == "USE_SOURCE_PERMISSIONS") { + if (doing == Doing::DoingFilePermissions) { + status.SetError(" given both FILE_PERMISSIONS and " + "USE_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + useSourcePermissions = true; + } else if (args[i] == "FILE_PERMISSIONS") { + if (useSourcePermissions) { + status.SetError(" given both FILE_PERMISSIONS and " + "USE_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + if (noSourcePermissions) { + status.SetError(" given both FILE_PERMISSIONS and " + "NO_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + + if (doing == Doing::DoingNone) { + doing = Doing::DoingFilePermissions; + filePermissions = true; + } } else if (noopOptions.find(args[i]) != noopOptions.end()) { /* Ignore no-op options. */ + } else if (doing == Doing::DoingFilePermissions) { + filePermissionOptions.push_back(args[i]); } else { unknown_args += " "; unknown_args += args[i]; @@ -104,9 +159,53 @@ bool cmConfigureFileCommand(std::vector<std::string> const& args, status.GetMakefile().IssueMessage(MessageType::AUTHOR_WARNING, msg); } - if (!status.GetMakefile().ConfigureFile( - inputFile, outputFile, copyOnly, atOnly, escapeQuotes, - use_source_permissions, newLineStyle)) { + if (useSourcePermissions && noSourcePermissions) { + status.SetError(" given both USE_SOURCE_PERMISSIONS and " + "NO_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + + mode_t permisiions = 0; + + if (filePermissions) { + if (filePermissionOptions.empty()) { + status.SetError(" given FILE_PERMISSIONS without any options."); + return false; + } + + std::vector<std::string> invalidOptions; + for (auto const& e : filePermissionOptions) { + if (!cmFSPermissions::stringToModeT(e, permisiions)) { + invalidOptions.push_back(e); + } + } + + if (!invalidOptions.empty()) { + std::ostringstream oss; + oss << " given invalid permission "; + for (auto i = 0u; i < invalidOptions.size(); i++) { + if (i == 0u) { + oss << "\"" << invalidOptions[i] << "\""; + } else { + oss << ",\"" << invalidOptions[i] << "\""; + } + } + oss << "."; + status.SetError(oss.str()); + return false; + } + } + + if (noSourcePermissions) { + permisiions |= cmFSPermissions::mode_owner_read; + permisiions |= cmFSPermissions::mode_owner_write; + permisiions |= cmFSPermissions::mode_group_read; + permisiions |= cmFSPermissions::mode_world_read; + } + + if (!status.GetMakefile().ConfigureFile(inputFile, outputFile, copyOnly, + atOnly, escapeQuotes, permisiions, + newLineStyle)) { status.SetError("Problem configuring file"); return false; } diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx deleted file mode 100644 index e4d0cf1..0000000 --- a/Source/cmConnection.cxx +++ /dev/null @@ -1,173 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmConnection.h" - -#include <cassert> -#include <cstring> - -#include <cm3p/uv.h> - -#include "cmServer.h" - -struct write_req_t -{ - uv_write_t req; - uv_buf_t buf; -}; - -void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, - size_t suggested_size, - uv_buf_t* buf) -{ - (void)(handle); -#ifndef __clang_analyzer__ - char* rawBuffer = new char[suggested_size]; - *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size)); -#else - (void)(suggested_size); - (void)(buf); -#endif /* __clang_analyzer__ */ -} - -void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, - const uv_buf_t* buf) -{ - auto conn = static_cast<cmEventBasedConnection*>(stream->data); - if (conn) { - if (nread >= 0) { - conn->ReadData(std::string(buf->base, buf->base + nread)); - } else { - conn->OnDisconnect(static_cast<int>(nread)); - } - } - - delete[](buf->base); -} - -void cmEventBasedConnection::on_close(uv_handle_t* /*handle*/) -{ -} - -void cmEventBasedConnection::on_write(uv_write_t* req, int status) -{ - (void)(status); - - // Free req and buffer - write_req_t* wr = reinterpret_cast<write_req_t*>(req); - delete[](wr->buf.base); - delete wr; -} - -void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status) -{ - (void)(status); - auto conn = static_cast<cmEventBasedConnection*>(stream->data); - - if (conn) { - conn->Connect(stream); - } -} - -bool cmEventBasedConnection::IsOpen() const -{ - return this->WriteStream != nullptr; -} - -void cmEventBasedConnection::WriteData(const std::string& _data) -{ -#ifndef NDEBUG - auto curr_thread_id = uv_thread_self(); - assert(this->Server); - assert(uv_thread_equal(&curr_thread_id, &this->Server->ServeThreadId)); -#endif - -#ifndef __clang_analyzer__ - auto data = _data; - assert(this->WriteStream.get()); - if (BufferStrategy) { - data = BufferStrategy->BufferOutMessage(data); - } - - auto ds = data.size(); - - write_req_t* req = new write_req_t; - req->req.data = this; - req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds)); - memcpy(req->buf.base, data.c_str(), ds); - uv_write(reinterpret_cast<uv_write_t*>(req), this->WriteStream, &req->buf, 1, - on_write); -#else - (void)(_data); -#endif /* __clang_analyzer__ */ -} - -void cmEventBasedConnection::ReadData(const std::string& data) -{ - this->RawReadBuffer += data; - if (BufferStrategy) { - std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer); - while (!packet.empty()) { - ProcessRequest(packet); - packet = BufferStrategy->BufferMessage(this->RawReadBuffer); - } - } else { - ProcessRequest(this->RawReadBuffer); - this->RawReadBuffer.clear(); - } -} - -cmEventBasedConnection::cmEventBasedConnection( - cmConnectionBufferStrategy* bufferStrategy) - : BufferStrategy(bufferStrategy) -{ -} - -void cmEventBasedConnection::Connect(uv_stream_t* server) -{ - (void)server; - Server->OnConnected(nullptr); -} - -void cmEventBasedConnection::OnDisconnect(int onerror) -{ - (void)onerror; - this->OnConnectionShuttingDown(); - if (this->Server) { - this->Server->OnDisconnect(this); - } -} - -cmConnection::~cmConnection() = default; - -bool cmConnection::OnConnectionShuttingDown() -{ - this->Server = nullptr; - return true; -} - -void cmConnection::SetServer(cmServerBase* s) -{ - Server = s; -} - -void cmConnection::ProcessRequest(const std::string& request) -{ - Server->ProcessRequest(this, request); -} - -bool cmConnection::OnServeStart(std::string* errString) -{ - (void)errString; - return true; -} - -bool cmEventBasedConnection::OnConnectionShuttingDown() -{ - if (this->WriteStream.get()) { - this->WriteStream->data = nullptr; - } - - WriteStream.reset(); - - return true; -} diff --git a/Source/cmConnection.h b/Source/cmConnection.h deleted file mode 100644 index 5335a7f..0000000 --- a/Source/cmConnection.h +++ /dev/null @@ -1,137 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <cstddef> -#include <memory> -#include <string> - -#include <cm3p/uv.h> - -#include "cmUVHandlePtr.h" - -class cmServerBase; - -/*** - * Given a sequence of bytes with any kind of buffering, instances of this - * class arrange logical chunks according to whatever the use case is for - * the connection. - */ -class cmConnectionBufferStrategy -{ -public: - virtual ~cmConnectionBufferStrategy(); - - /*** - * Called whenever with an active raw buffer. If a logical chunk - * becomes available, that chunk is returned and that portion is - * removed from the rawBuffer - * - * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is - * free to manipulate this buffer anyway it needs to. - * - * @return Next chunk from the stream. Returns the empty string if a chunk - * isn't ready yet. Users of this interface should repeatedly call this - * function until an empty string is returned since its entirely possible - * multiple chunks come in a single raw buffer. - */ - virtual std::string BufferMessage(std::string& rawBuffer) = 0; - - /*** - * Called to properly buffer an outgoing message. - * - * @param rawBuffer Message to format in the correct way - * - * @return Formatted message - */ - virtual std::string BufferOutMessage(const std::string& rawBuffer) const - { - return rawBuffer; - }; - /*** - * Resets the internal state of the buffering - */ - virtual void clear(); - - // TODO: There should be a callback / flag set for errors -}; - -class cmConnection -{ -public: - cmConnection() = default; - - cmConnection(cmConnection const&) = delete; - cmConnection& operator=(cmConnection const&) = delete; - - virtual void WriteData(const std::string& data) = 0; - - virtual ~cmConnection(); - - virtual bool OnConnectionShuttingDown(); - - virtual bool IsOpen() const = 0; - - virtual void SetServer(cmServerBase* s); - - virtual void ProcessRequest(const std::string& request); - - virtual bool OnServeStart(std::string* pString); - -protected: - cmServerBase* Server = nullptr; -}; - -/*** - * Abstraction of a connection; ties in event callbacks from libuv and notifies - * the server when appropriate - */ -class cmEventBasedConnection : public cmConnection -{ - -public: - /*** - * @param bufferStrategy If no strategy is given, it will process the raw - * chunks as they come in. The connection - * owns the pointer given. - */ - cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr); - - virtual void Connect(uv_stream_t* server); - - virtual void ReadData(const std::string& data); - - bool IsOpen() const override; - - void WriteData(const std::string& data) override; - bool OnConnectionShuttingDown() override; - - virtual void OnDisconnect(int errorCode); - - static void on_close(uv_handle_t* handle); - - template <typename T> - static void on_close_delete(uv_handle_t* handle) - { - delete reinterpret_cast<T*>(handle); - } - -protected: - cm::uv_stream_ptr WriteStream; - - std::string RawReadBuffer; - - std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy; - - static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); - - static void on_write(uv_write_t* req, int status); - - static void on_new_connection(uv_stream_t* stream, int status); - - static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, - uv_buf_t* buf); -}; diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx index 9c4deea..3001ae0 100644 --- a/Source/cmCreateTestSourceList.cxx +++ b/Source/cmCreateTestSourceList.cxx @@ -125,9 +125,9 @@ bool cmCreateTestSourceList(std::vector<std::string> const& args, mf.AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function); } mf.AddDefinition("CMAKE_FORWARD_DECLARE_TESTS", forwardDeclareCode); - mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES", functionMapCode); + mf.AddDefinition("CMAKE_FUNCTION_TABLE_ENTRIES", functionMapCode); bool res = true; - if (!mf.ConfigureFile(configFile, driver, false, true, false, true)) { + if (!mf.ConfigureFile(configFile, driver, false, true, false)) { res = false; } diff --git a/Source/cmCryptoHash.cxx b/Source/cmCryptoHash.cxx index b1e63ba..b331862 100644 --- a/Source/cmCryptoHash.cxx +++ b/Source/cmCryptoHash.cxx @@ -36,7 +36,7 @@ static rhash cmCryptoHash_rhash_init(unsigned int id) cmCryptoHash::cmCryptoHash(Algo algo) : Id(cmCryptoHashAlgoToId[algo]) - , CTX(cmCryptoHash_rhash_init(Id)) + , CTX(cmCryptoHash_rhash_init(this->Id)) { } diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 60504ba..c67497a 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -6,45 +6,147 @@ #include <memory> #include <utility> +#include <cm/optional> +#include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> +#include "cmCryptoHash.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTransformDepfile.h" namespace { -void AppendPaths(const std::vector<std::string>& inputs, - cmGeneratorExpression const& ge, cmLocalGenerator* lg, - std::string const& config, std::vector<std::string>& output) +std::string EvaluateSplitConfigGenex( + cm::string_view input, cmGeneratorExpression const& ge, cmLocalGenerator* lg, + bool useOutputConfig, std::string const& outputConfig, + std::string const& commandConfig, + std::set<BT<std::pair<std::string, bool>>>* utils = nullptr) { - for (std::string const& in : inputs) { - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(in); - std::vector<std::string> result = - cmExpandedList(cge->Evaluate(lg, config)); - for (std::string& it : result) { - cmSystemTools::ConvertToUnixSlashes(it); - if (cmSystemTools::FileIsFullPath(it)) { - it = cmSystemTools::CollapseFullPath( - it, lg->GetMakefile()->GetHomeOutputDirectory()); + std::string result; + + while (!input.empty()) { + // Copy non-genex content directly to the result. + std::string::size_type pos = input.find("$<"); + result += input.substr(0, pos); + if (pos == std::string::npos) { + break; + } + input = input.substr(pos); + + // Find the balanced end of this regex. + size_t nestingLevel = 1; + for (pos = 2; pos < input.size(); ++pos) { + cm::string_view cur = input.substr(pos); + if (cmHasLiteralPrefix(cur, "$<")) { + ++nestingLevel; + ++pos; + continue; + } + if (cmHasLiteralPrefix(cur, ">")) { + --nestingLevel; + if (nestingLevel == 0) { + ++pos; + break; + } + } + } + + // Split this genex from following input. + cm::string_view genex = input.substr(0, pos); + input = input.substr(pos); + + // Convert an outer COMMAND_CONFIG or OUTPUT_CONFIG to the matching config. + std::string const* config = + useOutputConfig ? &outputConfig : &commandConfig; + if (nestingLevel == 0) { + static cm::string_view const COMMAND_CONFIG = "$<COMMAND_CONFIG:"_s; + static cm::string_view const OUTPUT_CONFIG = "$<OUTPUT_CONFIG:"_s; + if (cmHasPrefix(genex, COMMAND_CONFIG)) { + genex.remove_prefix(COMMAND_CONFIG.size()); + genex.remove_suffix(1); + useOutputConfig = false; + config = &commandConfig; + } else if (cmHasPrefix(genex, OUTPUT_CONFIG)) { + genex.remove_prefix(OUTPUT_CONFIG.size()); + genex.remove_suffix(1); + useOutputConfig = true; + config = &outputConfig; + } + } + + // Evaluate this genex in the selected configuration. + std::unique_ptr<cmCompiledGeneratorExpression> cge = + ge.Parse(std::string(genex)); + result += cge->Evaluate(lg, *config); + + // Record targets referenced by the genex. + if (utils) { + // FIXME: What is the proper condition for a cross-dependency? + bool const cross = !useOutputConfig; + for (cmGeneratorTarget* gt : cge->GetTargets()) { + utils->emplace(BT<std::pair<std::string, bool>>( + { gt->GetName(), cross }, cge->GetBacktrace())); } } - cm::append(output, result); } + + return result; +} + +std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths, + cmGeneratorExpression const& ge, + cmLocalGenerator* lg, + std::string const& outputConfig, + std::string const& commandConfig) +{ + std::vector<std::string> depends; + for (std::string const& p : paths) { + std::string const& ep = + EvaluateSplitConfigGenex(p, ge, lg, /*useOutputConfig=*/true, + /*outputConfig=*/outputConfig, + /*commandConfig=*/commandConfig); + cm::append(depends, cmExpandedList(ep)); + } + for (std::string& p : depends) { + if (cmSystemTools::FileIsFullPath(p)) { + p = cmSystemTools::CollapseFullPath(p); + } else { + cmSystemTools::ConvertToUnixSlashes(p); + } + } + return depends; +} + +std::vector<std::string> EvaluateOutputs(std::vector<std::string> const& paths, + cmGeneratorExpression const& ge, + cmLocalGenerator* lg, + std::string const& config) +{ + std::vector<std::string> outputs; + for (std::string const& p : paths) { + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p); + cm::append(outputs, lg->ExpandCustomCommandOutputPaths(*cge, config)); + } + return outputs; } } -cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, - std::string config, - cmLocalGenerator* lg) - : CC(cc) - , Config(std::move(config)) +cmCustomCommandGenerator::cmCustomCommandGenerator( + cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg, + bool transformDepfile, cm::optional<std::string> crossConfig) + : CC(&cc) + , OutputConfig(crossConfig ? *crossConfig : config) + , CommandConfig(std::move(config)) , LG(lg) , OldStyle(cc.GetEscapeOldStyle()) , MakeVars(cc.GetEscapeAllowMakeVars()) @@ -52,38 +154,87 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, { cmGeneratorExpression ge(cc.GetBacktrace()); - const cmCustomCommandLines& cmdlines = this->CC.GetCommandLines(); + const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines(); for (cmCustomCommandLine const& cmdline : cmdlines) { cmCustomCommandLine argv; + // For the command itself, we default to the COMMAND_CONFIG. + bool useOutputConfig = false; for (std::string const& clarg : cmdline) { - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(clarg); - std::string parsed_arg = cge->Evaluate(this->LG, this->Config); - if (this->CC.GetCommandExpandLists()) { + std::string parsed_arg = EvaluateSplitConfigGenex( + clarg, ge, this->LG, useOutputConfig, this->OutputConfig, + this->CommandConfig, &this->Utilities); + if (this->CC->GetCommandExpandLists()) { cm::append(argv, cmExpandedList(parsed_arg)); } else { argv.push_back(std::move(parsed_arg)); } + + // For remaining arguments, we default to the OUTPUT_CONFIG. + useOutputConfig = true; } - // Later code assumes at least one entry exists, but expanding - // lists on an empty command may have left this empty. - // FIXME: Should we define behavior for removing empty commands? - if (argv.empty()) { + if (!argv.empty()) { + // If the command references an executable target by name, + // collect the target to add a target-level dependency on it. + cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front()); + if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) { + // FIXME: What is the proper condition for a cross-dependency? + bool const cross = true; + this->Utilities.emplace(BT<std::pair<std::string, bool>>( + { gt->GetName(), cross }, cc.GetBacktrace())); + } + } else { + // Later code assumes at least one entry exists, but expanding + // lists on an empty command may have left this empty. + // FIXME: Should we define behavior for removing empty commands? argv.emplace_back(); } this->CommandLines.push_back(std::move(argv)); } - AppendPaths(cc.GetByproducts(), ge, this->LG, this->Config, - this->Byproducts); - AppendPaths(cc.GetDepends(), ge, this->LG, this->Config, this->Depends); + if (transformDepfile && !this->CommandLines.empty() && + !cc.GetDepfile().empty() && + this->LG->GetGlobalGenerator()->DepfileFormat()) { + cmCustomCommandLine argv; + argv.push_back(cmSystemTools::GetCMakeCommand()); + argv.emplace_back("-E"); + argv.emplace_back("cmake_transform_depfile"); + switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { + case cmDepfileFormat::GccDepfile: + argv.emplace_back("gccdepfile"); + break; + case cmDepfileFormat::VsTlog: + argv.emplace_back("vstlog"); + break; + } + if (this->LG->GetCurrentBinaryDirectory() == + this->LG->GetBinaryDirectory()) { + argv.emplace_back("./"); + } else { + argv.push_back(cmStrCat(this->LG->MaybeConvertToRelativePath( + this->LG->GetBinaryDirectory(), + this->LG->GetCurrentBinaryDirectory()), + '/')); + } + argv.push_back(this->GetFullDepfile()); + argv.push_back(this->GetInternalDepfile()); + + this->CommandLines.push_back(std::move(argv)); + } + + this->Outputs = + EvaluateOutputs(cc.GetOutputs(), ge, this->LG, this->OutputConfig); + this->Byproducts = + EvaluateOutputs(cc.GetByproducts(), ge, this->LG, this->OutputConfig); + this->Depends = EvaluateDepends(cc.GetDepends(), ge, this->LG, + this->OutputConfig, this->CommandConfig); - const std::string& workingdirectory = this->CC.GetWorkingDirectory(); + const std::string& workingdirectory = this->CC->GetWorkingDirectory(); if (!workingdirectory.empty()) { - std::unique_ptr<cmCompiledGeneratorExpression> cge = - ge.Parse(workingdirectory); - this->WorkingDirectory = cge->Evaluate(this->LG, this->Config); + this->WorkingDirectory = + EvaluateSplitConfigGenex(workingdirectory, ge, this->LG, true, + this->OutputConfig, this->CommandConfig); // Convert working directory to a full path. if (!this->WorkingDirectory.empty()) { std::string const& build_dir = this->LG->GetCurrentBinaryDirectory(); @@ -97,7 +248,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const { - return static_cast<unsigned int>(this->CC.GetCommandLines().size()); + return static_cast<unsigned int>(this->CommandLines.size()); } void cmCustomCommandGenerator::FillEmulatorsWithArguments() @@ -140,7 +291,7 @@ const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const (target->IsImported() || target->GetProperty("CROSSCOMPILING_EMULATOR") || !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) { - return target->GetLocation(this->Config).c_str(); + return target->GetLocation(this->CommandConfig).c_str(); } return nullptr; } @@ -234,9 +385,43 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, } } +std::string cmCustomCommandGenerator::GetFullDepfile() const +{ + std::string depfile = this->CC->GetDepfile(); + if (depfile.empty()) { + return ""; + } + + if (!cmSystemTools::FileIsFullPath(depfile)) { + depfile = cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', depfile); + } + return cmSystemTools::CollapseFullPath(depfile); +} + +std::string cmCustomCommandGenerator::GetInternalDepfile() const +{ + std::string depfile = this->GetFullDepfile(); + if (depfile.empty()) { + return ""; + } + + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + std::string extension; + switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { + case cmDepfileFormat::GccDepfile: + extension = ".d"; + break; + case cmDepfileFormat::VsTlog: + extension = ".tlog"; + break; + } + return cmStrCat(this->LG->GetBinaryDirectory(), "/CMakeFiles/d/", + hash.HashString(depfile), extension); +} + const char* cmCustomCommandGenerator::GetComment() const { - return this->CC.GetComment(); + return this->CC->GetComment(); } std::string cmCustomCommandGenerator::GetWorkingDirectory() const @@ -246,7 +431,7 @@ std::string cmCustomCommandGenerator::GetWorkingDirectory() const std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const { - return this->CC.GetOutputs(); + return this->Outputs; } std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const @@ -258,3 +443,9 @@ std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const { return this->Depends; } + +std::set<BT<std::pair<std::string, bool>>> const& +cmCustomCommandGenerator::GetUtilities() const +{ + return this->Utilities; +} diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index 412eba8..4be5b3f 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -4,26 +4,34 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <set> #include <string> +#include <utility> #include <vector> +#include <cm/optional> + #include "cmCustomCommandLines.h" +#include "cmListFileCache.h" class cmCustomCommand; class cmLocalGenerator; class cmCustomCommandGenerator { - cmCustomCommand const& CC; - std::string Config; + cmCustomCommand const* CC; + std::string OutputConfig; + std::string CommandConfig; cmLocalGenerator* LG; bool OldStyle; bool MakeVars; cmCustomCommandLines CommandLines; std::vector<std::vector<std::string>> EmulatorsWithArguments; + std::vector<std::string> Outputs; std::vector<std::string> Byproducts; std::vector<std::string> Depends; std::string WorkingDirectory; + std::set<BT<std::pair<std::string, bool>>> Utilities; void FillEmulatorsWithArguments(); std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const; @@ -31,11 +39,14 @@ class cmCustomCommandGenerator public: cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config, - cmLocalGenerator* lg); + cmLocalGenerator* lg, bool transformDepfile = true, + cm::optional<std::string> crossConfig = {}); cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete; + cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default; cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) = delete; - cmCustomCommand const& GetCC() const { return this->CC; } + cmCustomCommandGenerator& operator=(cmCustomCommandGenerator&&) = default; + cmCustomCommand const& GetCC() const { return *(this->CC); } unsigned int GetNumberOfCommands() const; std::string GetCommand(unsigned int c) const; void AppendArguments(unsigned int c, std::string& cmd) const; @@ -44,5 +55,11 @@ public: std::vector<std::string> const& GetOutputs() const; std::vector<std::string> const& GetByproducts() const; std::vector<std::string> const& GetDepends() const; + std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const; bool HasOnlyEmptyCommandLines() const; + std::string GetFullDepfile() const; + std::string GetInternalDepfile() const; + + const std::string& GetOutputConfig() const { return this->OutputConfig; } + const std::string& GetCommandConfig() const { return this->CommandConfig; } }; diff --git a/Source/cmCustomCommandTypes.h b/Source/cmCustomCommandTypes.h index 5c900ce..324da9e 100644 --- a/Source/cmCustomCommandTypes.h +++ b/Source/cmCustomCommandTypes.h @@ -27,10 +27,3 @@ enum class cmObjectLibraryCommands Reject, Accept }; - -/** Utility target output source file name. */ -struct cmUtilityOutput -{ - std::string Name; - std::string NameCMP0049; -}; diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index e6aef92..60e8cbf 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -7,6 +7,7 @@ #include "cmsys/FStream.hxx" #include "cmFileTime.h" +#include "cmGlobalUnixMakefileGenerator3.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmProperty.h" @@ -215,16 +216,28 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // directory. We must do the same here. std::string obj_m = this->LocalGenerator->ConvertToMakefilePath(obj_i); internalDepends << obj_i << '\n'; - - for (std::string const& dep : dependencies) { - makeDepends << obj_m << ": " - << this->LocalGenerator->ConvertToMakefilePath( - this->LocalGenerator->MaybeConvertToRelativePath(binDir, - dep)) - << '\n'; - internalDepends << ' ' << dep << '\n'; + if (!dependencies.empty()) { + const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()) + ->LineContinueDirective; + bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()) + ->SupportsLongLineDependencies(); + if (supportLongLineDepend) { + makeDepends << obj_m << ':'; + } + for (std::string const& dep : dependencies) { + std::string dependee = this->LocalGenerator->ConvertToMakefilePath( + this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep)); + if (supportLongLineDepend) { + makeDepends << ' ' << lineContinue << ' ' << dependee; + } else { + makeDepends << obj_m << ": " << dependee << '\n'; + } + internalDepends << ' ' << dep << '\n'; + } + makeDepends << '\n'; } - makeDepends << '\n'; return true; } diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx new file mode 100644 index 0000000..ec31f68 --- /dev/null +++ b/Source/cmDependsCompiler.cxx @@ -0,0 +1,261 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmDependsCompiler.h" + +#include <algorithm> +#include <map> +#include <memory> +#include <string> +#include <unordered_set> +#include <utility> + +#include <cm/optional> +#include <cm/string_view> +#include <cm/vector> +#include <cmext/string_view> + +#include "cmsys/FStream.hxx" + +#include "cmFileTime.h" +#include "cmGccDepfileReader.h" +#include "cmGccDepfileReaderTypes.h" +#include "cmGlobalUnixMakefileGenerator3.h" +#include "cmLocalUnixMakefileGenerator3.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +bool cmDependsCompiler::CheckDependencies( + const std::string& internalDepFile, const std::vector<std::string>& depFiles, + cmDepends::DependencyMap& dependencies, + const std::function<bool(const std::string&)>& isValidPath) +{ + bool status = true; + bool forceReadDeps = true; + + cmFileTime internalDepFileTime; + // read cached dependencies stored in internal file + if (cmSystemTools::FileExists(internalDepFile)) { + internalDepFileTime.Load(internalDepFile); + forceReadDeps = false; + + // read current dependencies + cmsys::ifstream fin(internalDepFile.c_str()); + if (fin) { + std::string line; + std::string depender; + std::vector<std::string>* currentDependencies = nullptr; + while (std::getline(fin, line)) { + if (line.empty() || line.front() == '#') { + continue; + } + // Drop carriage return character at the end + if (line.back() == '\r') { + line.pop_back(); + if (line.empty()) { + continue; + } + } + // Check if this a depender line + if (line.front() != ' ') { + depender = std::move(line); + currentDependencies = &dependencies[depender]; + continue; + } + // This is a dependee line + if (currentDependencies != nullptr) { + currentDependencies->emplace_back(line.substr(1)); + } + } + fin.close(); + } + } + + // Now, update dependencies map with all new compiler generated + // dependencies files + cmFileTime depFileTime; + for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) { + const auto& source = *dep++; + const auto& target = *dep++; + const auto& format = *dep++; + const auto& depFile = *dep; + + if (!cmSystemTools::FileExists(depFile)) { + continue; + } + + if (!forceReadDeps) { + depFileTime.Load(depFile); + } + if (forceReadDeps || depFileTime.Compare(internalDepFileTime) >= 0) { + status = false; + if (this->Verbose) { + cmSystemTools::Stdout(cmStrCat("Dependencies file \"", depFile, + "\" is newer than depends file \"", + internalDepFile, "\".\n")); + } + + std::vector<std::string> depends; + if (format == "custom"_s) { + std::string prefix; + if (this->LocalGenerator->GetCurrentBinaryDirectory() != + this->LocalGenerator->GetBinaryDirectory()) { + prefix = + cmStrCat(this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->LocalGenerator->GetCurrentBinaryDirectory()), + '/'); + } + + auto deps = cmReadGccDepfile(depFile.c_str(), prefix); + if (!deps) { + continue; + } + + for (auto& entry : *deps) { + depends = std::move(entry.paths); + if (isValidPath) { + cm::erase_if(depends, isValidPath); + } + // copy depends for each target, except first one, which can be + // moved + for (auto index = entry.rules.size() - 1; index > 0; --index) { + dependencies[entry.rules[index]] = depends; + } + dependencies[entry.rules.front()] = std::move(depends); + } + } else { + if (format == "msvc"_s) { + cmsys::ifstream fin(depFile.c_str()); + if (!fin) { + continue; + } + + std::string line; + if (!isValidPath) { + // insert source as first dependency + depends.push_back(source); + } + while (cmSystemTools::GetLineFromStream(fin, line)) { + depends.emplace_back(std::move(line)); + } + } else if (format == "gcc"_s) { + auto deps = cmReadGccDepfile(depFile.c_str()); + if (!deps) { + continue; + } + + // dependencies generated by the compiler contains only one target + depends = std::move(deps->front().paths); + if (depends.empty()) { + // unexpectedly empty, ignore it and continue + continue; + } + + // depending of the effective format of the dependencies file + // generated by the compiler, the target can be wrongly identified + // as a dependency so remove it from the list + if (depends.front() == target) { + depends.erase(depends.begin()); + } + + // ensure source file is the first dependency + if (depends.front() != source) { + cm::erase(depends, source); + if (!isValidPath) { + depends.insert(depends.begin(), source); + } + } else if (isValidPath) { + // remove first dependency because it must not be filtered out + depends.erase(depends.begin()); + } + } else { + // unknown format, ignore it + continue; + } + + if (isValidPath) { + cm::erase_if(depends, isValidPath); + // insert source as first dependency + depends.insert(depends.begin(), source); + } + + dependencies[target] = std::move(depends); + } + } + } + + return status; +} + +void cmDependsCompiler::WriteDependencies( + const cmDepends::DependencyMap& dependencies, std::ostream& makeDepends, + std::ostream& internalDepends) +{ + // dependencies file consumed by make tool + const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()) + ->LineContinueDirective; + bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()) + ->SupportsLongLineDependencies(); + const auto& binDir = this->LocalGenerator->GetBinaryDirectory(); + cmDepends::DependencyMap makeDependencies(dependencies); + std::unordered_set<cm::string_view> phonyTargets; + + // external dependencies file + for (auto& node : makeDependencies) { + auto target = this->LocalGenerator->ConvertToMakefilePath( + this->LocalGenerator->MaybeConvertToRelativePath(binDir, node.first)); + auto& deps = node.second; + std::transform( + deps.cbegin(), deps.cend(), deps.begin(), + [this, &binDir](const std::string& dep) { + return this->LocalGenerator->ConvertToMakefilePath( + this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep)); + }); + + bool first_dep = true; + if (supportLongLineDepend) { + makeDepends << target << ": "; + } + for (const auto& dep : deps) { + if (supportLongLineDepend) { + if (first_dep) { + first_dep = false; + makeDepends << dep; + } else { + makeDepends << ' ' << lineContinue << " " << dep; + } + } else { + makeDepends << target << ": " << dep << std::endl; + } + + phonyTargets.emplace(dep.data(), dep.length()); + } + makeDepends << std::endl << std::endl; + } + + // add phony targets + for (const auto& target : phonyTargets) { + makeDepends << std::endl << target << ':' << std::endl; + } + + // internal dependencies file + for (const auto& node : dependencies) { + internalDepends << node.first << std::endl; + for (const auto& dep : node.second) { + internalDepends << ' ' << dep << std::endl; + } + internalDepends << std::endl; + } +} + +void cmDependsCompiler::ClearDependencies( + const std::vector<std::string>& depFiles) +{ + for (auto dep = depFiles.begin(); dep != depFiles.end(); dep++) { + dep += 3; + cmSystemTools::RemoveFile(*dep); + } +} diff --git a/Source/cmDependsCompiler.h b/Source/cmDependsCompiler.h new file mode 100644 index 0000000..838156d --- /dev/null +++ b/Source/cmDependsCompiler.h @@ -0,0 +1,60 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <functional> +#include <iosfwd> +#include <string> +#include <vector> + +#include "cmDepends.h" + +class cmLocalUnixMakefileGenerator3; + +/** \class cmDepends + * \brief Dependencies files manager. + * + * This class is responsible for maintaining a compiler_depends.make file in + * the build tree corresponding to an object file. + */ +class cmDependsCompiler +{ +public: + cmDependsCompiler() = default; + ~cmDependsCompiler() = default; + + /** should this be verbose in its output */ + void SetVerbose(bool verb) { this->Verbose = verb; } + + /** Set the local generator for the directory in which we are + scanning dependencies. This is not a full local generator; it + has been setup to do relative path conversions for the current + directory. */ + void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg) + { + this->LocalGenerator = lg; + } + + /** Read dependencies for the target file. Return true if + dependencies didn't changed and false if not. + Up-to-date Dependencies will be stored in deps. */ + bool CheckDependencies( + const std::string& internalDepFile, + const std::vector<std::string>& depFiles, + cmDepends::DependencyMap& dependencies, + const std::function<bool(const std::string&)>& isValidPath); + + /** Write dependencies for the target file. */ + void WriteDependencies(const cmDepends::DependencyMap& dependencies, + std::ostream& makeDepends, + std::ostream& internalDepends); + + /** Clear dependencies for the target so they will be regenerated. */ + void ClearDependencies(const std::vector<std::string>& depFiles); + +private: + bool Verbose = false; + cmLocalUnixMakefileGenerator3* LocalGenerator = nullptr; +}; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index a239418..1a06f31 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -12,6 +12,7 @@ #include "cmFortranParser.h" /* Interface to parser object. */ #include "cmGeneratedFileStream.h" +#include "cmGlobalUnixMakefileGenerator3.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -320,14 +321,28 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj, std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj); std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i); internalDepends << obj_i << "\n " << src << '\n'; - for (std::string const& i : info.Includes) { - makeDepends << obj_m << ": " - << cmSystemTools::ConvertToOutputPath( - this->MaybeConvertToRelativePath(binDir, i)) - << '\n'; - internalDepends << ' ' << i << '\n'; + if (!info.Includes.empty()) { + const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()) + ->LineContinueDirective; + bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>( + this->LocalGenerator->GetGlobalGenerator()) + ->SupportsLongLineDependencies(); + if (supportLongLineDepend) { + makeDepends << obj_m << ':'; + } + for (std::string const& i : info.Includes) { + std::string dependee = cmSystemTools::ConvertToOutputPath( + this->MaybeConvertToRelativePath(binDir, i)); + if (supportLongLineDepend) { + makeDepends << ' ' << lineContinue << ' ' << dependee; + } else { + makeDepends << obj_m << ": " << dependee << '\n'; + } + internalDepends << ' ' << i << '\n'; + } + makeDepends << '\n'; } - makeDepends << '\n'; // Write module requirements to the output stream. for (std::string const& i : info.Requires) { diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 1bc453d..3619ade 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -194,7 +194,7 @@ void cmDocumentation::addCTestStandardDocSections() { // This is currently done for backward compatibility reason // We may suppress some of these. - addCMakeStandardDocSections(); + this->addCMakeStandardDocSections(); } void cmDocumentation::addCPackStandardDocSections() diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index a8d81f7..deffdb6 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -379,7 +379,7 @@ private: // Fix the byte order of the header. if (this->NeedSwap) { - ByteSwap(x); + this->ByteSwap(x); } return true; } @@ -387,7 +387,7 @@ private: { if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && this->NeedSwap) { - ByteSwap(x); + this->ByteSwap(x); } return !this->Stream->fail(); } @@ -395,7 +395,7 @@ private: { if (this->Stream->read(reinterpret_cast<char*>(&x), sizeof(x)) && this->NeedSwap) { - ByteSwap(x); + this->ByteSwap(x); } return !this->Stream->fail(); } @@ -573,7 +573,7 @@ std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries( dyn.d_un.d_val = static_cast<tagtype>(entry.second); if (this->NeedSwap) { - ByteSwap(dyn); + this->ByteSwap(dyn); } char* pdyn = reinterpret_cast<char*>(&dyn); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index cbae4e5..113751a 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -707,7 +707,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( break; } input.replace(pos, endPos - pos + 1, targetName); - lastPos = endPos; + lastPos = pos + targetName.size(); } pos = 0; @@ -924,13 +924,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) // 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.17 (this upper limit may be reviewed + // policy settings for up to CMake 3.18 (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.17)\n"; + << "cmake_policy(VERSION 2.6...3.18)\n"; /* clang-format on */ } diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx index 56dfc6c..cc8b8b7 100644 --- a/Source/cmExprParserHelper.cxx +++ b/Source/cmExprParserHelper.cxx @@ -42,20 +42,22 @@ int cmExprParserHelper::ParseString(const char* str, int verb) try { int res = cmExpr_yyparse(yyscanner); if (res != 0) { - std::string e = cmStrCat("cannot parse the expression: \"", InputBuffer, - "\": ", ErrorString, '.'); + std::string e = + cmStrCat("cannot parse the expression: \"", this->InputBuffer, + "\": ", this->ErrorString, '.'); this->SetError(std::move(e)); } } catch (std::runtime_error const& fail) { - std::string e = cmStrCat("cannot evaluate the expression: \"", InputBuffer, - "\": ", fail.what(), '.'); + std::string e = cmStrCat("cannot evaluate the expression: \"", + this->InputBuffer, "\": ", fail.what(), '.'); this->SetError(std::move(e)); } catch (std::out_of_range const&) { - std::string e = "cannot evaluate the expression: \"" + InputBuffer + + std::string e = "cannot evaluate the expression: \"" + this->InputBuffer + "\": a numeric value is out of range."; this->SetError(std::move(e)); } catch (...) { - std::string e = "cannot parse the expression: \"" + InputBuffer + "\"."; + std::string e = + "cannot parse the expression: \"" + this->InputBuffer + "\"."; this->SetError(std::move(e)); } cmExpr_yylex_destroy(yyscanner); @@ -63,7 +65,7 @@ int cmExprParserHelper::ParseString(const char* str, int verb) return 0; } - if (Verbose) { + if (this->Verbose) { std::cerr << "Expanding [" << str << "] produced: [" << this->Result << "]" << std::endl; } diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index 3ade67b..311a2ef 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -52,8 +52,8 @@ public: //! Generate the project files, the Makefiles have already been generated virtual void Generate() = 0; - void SetName(const std::string& n) { Name = n; } - std::string GetName() const { return Name; } + void SetName(const std::string& n) { this->Name = n; } + std::string GetName() const { return this->Name; } virtual bool Open(const std::string& bindir, const std::string& projectName, bool dryRun); @@ -104,7 +104,7 @@ public: CreateExternalMakefileProjectGenerator() const override { std::unique_ptr<cmExternalMakefileProjectGenerator> p(new T); - p->SetName(GetName()); + p->SetName(this->GetName()); return p; } }; diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 87b8f9b..800db8a 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -112,10 +112,10 @@ void Tree::InsertPath(const std::vector<std::string>& split, const std::string& fileName) { if (start == split.size()) { - files.insert(fileName); + this->files.insert(fileName); return; } - for (Tree& folder : folders) { + for (Tree& folder : this->folders) { if (folder.path == split[start]) { if (start + 1 < split.size()) { folder.InsertPath(split, start + 1, fileName); @@ -131,19 +131,19 @@ void Tree::InsertPath(const std::vector<std::string>& split, newFolder.path = split[start]; if (start + 1 < split.size()) { newFolder.InsertPath(split, start + 1, fileName); - folders.push_back(newFolder); + this->folders.push_back(newFolder); return; } // last part of split newFolder.files.insert(fileName); - folders.push_back(newFolder); + this->folders.push_back(newFolder); } void Tree::BuildVirtualFolder(cmXMLWriter& xml) const { xml.StartElement("Option"); std::string virtualFolders = "CMake Files\\;"; - for (Tree const& folder : folders) { + for (Tree const& folder : this->folders) { folder.BuildVirtualFolderImpl(virtualFolders, ""); } xml.Attribute("virtualFolders", virtualFolders); @@ -153,15 +153,15 @@ void Tree::BuildVirtualFolder(cmXMLWriter& xml) const void Tree::BuildVirtualFolderImpl(std::string& virtualFolders, const std::string& prefix) const { - virtualFolders += "CMake Files\\" + prefix + path + "\\;"; - for (Tree const& folder : folders) { - folder.BuildVirtualFolderImpl(virtualFolders, prefix + path + "\\"); + virtualFolders += "CMake Files\\" + prefix + this->path + "\\;"; + for (Tree const& folder : this->folders) { + folder.BuildVirtualFolderImpl(virtualFolders, prefix + this->path + "\\"); } } void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const { - for (std::string const& f : files) { + for (std::string const& f : this->files) { xml.StartElement("Unit"); xml.Attribute("filename", fsPath + f); @@ -171,7 +171,7 @@ void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const xml.EndElement(); } - for (Tree const& folder : folders) { + for (Tree const& folder : this->folders) { folder.BuildUnitImpl(xml, "", fsPath); } } @@ -180,20 +180,21 @@ void Tree::BuildUnitImpl(cmXMLWriter& xml, const std::string& virtualFolderPath, const std::string& fsPath) const { - for (std::string const& f : files) { + for (std::string const& f : this->files) { xml.StartElement("Unit"); - xml.Attribute("filename", cmStrCat(fsPath, path, "/", f)); + xml.Attribute("filename", cmStrCat(fsPath, this->path, "/", f)); xml.StartElement("Option"); - xml.Attribute("virtualFolder", - cmStrCat("CMake Files\\", virtualFolderPath, path, "\\")); + xml.Attribute( + "virtualFolder", + cmStrCat("CMake Files\\", virtualFolderPath, this->path, "\\")); xml.EndElement(); xml.EndElement(); } - for (Tree const& folder : folders) { - folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, path, "\\"), - cmStrCat(fsPath, path, "/")); + for (Tree const& folder : this->folders) { + folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, this->path, "\\"), + cmStrCat(fsPath, this->path, "/")); } } diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index 95cfb0a..549b08b 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -64,7 +64,7 @@ void cmExtraCodeLiteGenerator::Generate() for (auto const& it : projectMap) { cmLocalGenerator* lg = it.second[0]; const cmMakefile* mf = lg->GetMakefile(); - this->ConfigName = GetConfigurationName(mf); + this->ConfigName = this->GetConfigurationName(mf); if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) { workspaceOutputDir = lg->GetCurrentBinaryDirectory(); @@ -89,9 +89,9 @@ void cmExtraCodeLiteGenerator::Generate() std::vector<std::string> ProjectNames; if (targetsAreProjects) { - ProjectNames = CreateProjectsByTarget(&xml); + ProjectNames = this->CreateProjectsByTarget(&xml); } else { - ProjectNames = CreateProjectsByProjectMaps(&xml); + ProjectNames = this->CreateProjectsByProjectMaps(&xml); } xml.StartElement("BuildMatrix"); @@ -142,7 +142,7 @@ std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget( xml->Attribute("Active", "No"); xml->EndElement(); - CreateNewProjectFile(lt.get(), filename); + this->CreateNewProjectFile(lt.get(), filename); break; default: break; @@ -268,7 +268,7 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile( cmMakefile* makefile = lg->GetMakefile(); for (const auto& target : lg->GetGeneratorTargets()) { projectType = - CollectSourceFiles(makefile, target.get(), cFiles, otherFiles); + this->CollectSourceFiles(makefile, target.get(), cFiles, otherFiles); } } @@ -276,8 +276,8 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile( // their relative path) std::string projectPath = cmSystemTools::GetFilenamePath(filename); - CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf, - projectType, ""); + this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf, + projectType, ""); xml.EndElement(); // CodeLite_Project } @@ -402,7 +402,7 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( const std::string& projectType, const std::string& targetName) { cmXMLWriter& xml(*_xml); - FindMatchingHeaderfiles(cFiles, otherFiles); + this->FindMatchingHeaderfiles(cFiles, otherFiles); // Create 2 virtual folders: src and include // and place all the implementation files into the src // folder, the rest goes to the include folder @@ -498,10 +498,10 @@ void cmExtraCodeLiteGenerator::CreateProjectSourceEntries( xml.StartElement("CustomBuild"); xml.Attribute("Enabled", "yes"); - xml.Element("RebuildCommand", GetRebuildCommand(mf, targetName)); - xml.Element("CleanCommand", GetCleanCommand(mf, targetName)); - xml.Element("BuildCommand", GetBuildCommand(mf, targetName)); - xml.Element("SingleFileCommand", GetSingleFileBuildCommand(mf)); + xml.Element("RebuildCommand", this->GetRebuildCommand(mf, targetName)); + xml.Element("CleanCommand", this->GetCleanCommand(mf, targetName)); + xml.Element("BuildCommand", this->GetBuildCommand(mf, targetName)); + xml.Element("SingleFileCommand", this->GetSingleFileBuildCommand(mf)); xml.Element("PreprocessFileCommand"); xml.Element("WorkingDirectory", "$(WorkspacePath)"); xml.EndElement(); // CustomBuild @@ -570,14 +570,14 @@ void cmExtraCodeLiteGenerator::CreateNewProjectFile( std::map<std::string, cmSourceFile*> cFiles; std::set<std::string> otherFiles; - projectType = CollectSourceFiles(mf, gt, cFiles, otherFiles); + projectType = this->CollectSourceFiles(mf, gt, cFiles, otherFiles); // Get the project path ( we need it later to convert files to // their relative path) std::string projectPath = cmSystemTools::GetFilenamePath(filename); - CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf, - projectType, targetName); + this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf, + projectType, targetName); xml.EndElement(); // CodeLite_Project } @@ -648,7 +648,7 @@ std::string cmExtraCodeLiteGenerator::GetCleanCommand( { std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR"); std::ostringstream ss; - std::string buildcommand = GetBuildCommand(mf, ""); + std::string buildcommand = this->GetBuildCommand(mf, ""); if (!targetName.empty() && generator == "Ninja") { ss << buildcommand << " -t clean " << targetName; } else { @@ -660,8 +660,8 @@ std::string cmExtraCodeLiteGenerator::GetCleanCommand( std::string cmExtraCodeLiteGenerator::GetRebuildCommand( const cmMakefile* mf, const std::string& targetName) const { - return GetCleanCommand(mf, targetName) + " && " + - GetBuildCommand(mf, targetName); + return this->GetCleanCommand(mf, targetName) + " && " + + this->GetBuildCommand(mf, targetName); } std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand( diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 7c36144..a92f6e3 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -132,7 +132,7 @@ void cmExtraSublimeTextGenerator::CreateNewProjectFile( // doesn't currently support these settings per build system, only project // wide MapSourceFileFlags sourceFileFlags; - AppendAllTargets(lgs, mf, fout, sourceFileFlags); + this->AppendAllTargets(lgs, mf, fout, sourceFileFlags); // End of build_systems fout << "\n\t]"; @@ -349,6 +349,11 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject( if (language.empty()) { language = "C"; } + + // Explicitly add the explicit language flag before any other flag + // so user flags can override it. + gtgt->AddExplicitLanguageFlags(flags, *source); + std::string const& config = lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); diff --git a/Source/cmFileAPICMakeFiles.cxx b/Source/cmFileAPICMakeFiles.cxx index 1e4f3b6..e208ca8 100644 --- a/Source/cmFileAPICMakeFiles.cxx +++ b/Source/cmFileAPICMakeFiles.cxx @@ -41,7 +41,7 @@ CMakeFiles::CMakeFiles(cmFileAPI& fileAPI, unsigned long version) , CMakeModules(cmSystemTools::GetCMakeRoot() + "/Modules") , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory()) , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory()) - , OutOfSource(TopBuild != TopSource) + , OutOfSource(this->TopBuild != this->TopSource) { static_cast<void>(this->Version); } @@ -50,7 +50,7 @@ Json::Value CMakeFiles::Dump() { Json::Value cmakeFiles = Json::objectValue; cmakeFiles["paths"] = this->DumpPaths(); - cmakeFiles["inputs"] = DumpInputs(); + cmakeFiles["inputs"] = this->DumpInputs(); return cmakeFiles; } diff --git a/Source/cmFileAPICache.cxx b/Source/cmFileAPICache.cxx index 3ba943a..ddae527 100644 --- a/Source/cmFileAPICache.cxx +++ b/Source/cmFileAPICache.cxx @@ -44,7 +44,7 @@ Cache::Cache(cmFileAPI& fileAPI, unsigned long version) Json::Value Cache::Dump() { Json::Value cache = Json::objectValue; - cache["entries"] = DumpEntries(); + cache["entries"] = this->DumpEntries(); return cache; } diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 4a53c8a..7fcc3dc 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -145,7 +145,7 @@ class JBTIndex { public: JBTIndex() = default; - explicit operator bool() const { return Index != None; } + explicit operator bool() const { return this->Index != None; } Json::ArrayIndex Index = None; static Json::ArrayIndex const None = static_cast<Json::ArrayIndex>(-1); }; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 8a3aad2..9815d9d 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -15,6 +15,7 @@ #include <vector> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -2290,7 +2291,7 @@ void AddEvaluationFile(const std::string& inputName, const std::string& targetName, const std::string& outputExpr, const std::string& condition, bool inputIsContent, - cmExecutionStatus& status) + mode_t permissions, cmExecutionStatus& status) { cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace(); @@ -2304,7 +2305,7 @@ void AddEvaluationFile(const std::string& inputName, status.GetMakefile().AddEvaluationFile( inputName, targetName, std::move(outputCge), std::move(conditionCge), - inputIsContent); + permissions, inputIsContent); } bool HandleGenerateCommand(std::vector<std::string> const& args, @@ -2314,49 +2315,156 @@ bool HandleGenerateCommand(std::vector<std::string> const& args, status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - if (args[1] != "OUTPUT") { + + struct Arguments + { + std::string Output; + std::string Input; + std::string Content; + std::string Condition; + std::string Target; + bool NoSourcePermissions = false; + bool UseSourcePermissions = false; + std::vector<std::string> FilePermissions; + }; + + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("OUTPUT"_s, &Arguments::Output) + .Bind("INPUT"_s, &Arguments::Input) + .Bind("CONTENT"_s, &Arguments::Content) + .Bind("CONDITION"_s, &Arguments::Condition) + .Bind("TARGET"_s, &Arguments::Target) + .Bind("NO_SOURCE_PERMISSIONS"_s, &Arguments::NoSourcePermissions) + .Bind("USE_SOURCE_PERMISSIONS"_s, &Arguments::UseSourcePermissions) + .Bind("FILE_PERMISSIONS"_s, &Arguments::FilePermissions); + + std::vector<std::string> unparsedArguments; + std::vector<std::string> keywordsMissingValues; + std::vector<std::string> parsedKeywords; + Arguments const arguments = + parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments, + &keywordsMissingValues, &parsedKeywords); + + if (!keywordsMissingValues.empty()) { status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - std::string condition; - std::string target; - - for (std::size_t i = 5; i < args.size();) { - const std::string& arg = args[i++]; + if (!unparsedArguments.empty()) { + status.SetError("Unknown argument to GENERATE subcommand."); + return false; + } - if (args.size() - i == 0) { - status.SetError("Incorrect arguments to GENERATE subcommand."); - return false; + bool mandatoryOptionsSpecified = false; + if (parsedKeywords.size() > 1) { + const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s; + const bool inputOrContentSpecified = + parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s; + if (outputOprionSpecified && inputOrContentSpecified) { + mandatoryOptionsSpecified = true; } + } + if (!mandatoryOptionsSpecified) { + status.SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + + const bool conditionOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) != + parsedKeywords.end(); + if (conditionOptionSpecified && arguments.Condition.empty()) { + status.SetError("CONDITION of sub-command GENERATE must not be empty " + "if specified."); + return false; + } - const std::string& value = args[i++]; + const bool targetOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) != + parsedKeywords.end(); + if (targetOptionSpecified && arguments.Target.empty()) { + status.SetError("TARGET of sub-command GENERATE must not be empty " + "if specified."); + return false; + } - if (value.empty()) { - status.SetError( - arg + " of sub-command GENERATE must not be empty if specified."); + const bool outputOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) != + parsedKeywords.end(); + if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) { + status.SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } + + const bool inputIsContent = parsedKeywords[1] != "INPUT"_s; + if (inputIsContent && parsedKeywords[1] != "CONTENT") { + status.SetError("Unknown argument to GENERATE subcommand."); + } + + std::string input = arguments.Input; + if (inputIsContent) { + input = arguments.Content; + } + + if (arguments.NoSourcePermissions && arguments.UseSourcePermissions) { + status.SetError("given both NO_SOURCE_PERMISSIONS and " + "USE_SOURCE_PERMISSIONS. Only one option allowed."); + return false; + } + + if (!arguments.FilePermissions.empty()) { + if (arguments.NoSourcePermissions) { + status.SetError("given both NO_SOURCE_PERMISSIONS and " + "FILE_PERMISSIONS. Only one option allowed."); return false; } + if (arguments.UseSourcePermissions) { + status.SetError("given both USE_SOURCE_PERMISSIONS and " + "FILE_PERMISSIONS. Only one option allowed."); + return false; + } + } - if (arg == "CONDITION") { - condition = value; - } else if (arg == "TARGET") { - target = value; - } else { - status.SetError("Unknown argument to GENERATE subcommand."); + if (arguments.UseSourcePermissions) { + if (inputIsContent) { + status.SetError("given USE_SOURCE_PERMISSIONS without a file INPUT."); return false; } } - std::string output = args[2]; - const bool inputIsContent = args[3] != "INPUT"; - if (inputIsContent && args[3] != "CONTENT") { - status.SetError("Incorrect arguments to GENERATE subcommand."); - return false; + mode_t permisiions = 0; + if (arguments.NoSourcePermissions) { + permisiions |= cmFSPermissions::mode_owner_read; + permisiions |= cmFSPermissions::mode_owner_write; + permisiions |= cmFSPermissions::mode_group_read; + permisiions |= cmFSPermissions::mode_world_read; + } + + if (!arguments.FilePermissions.empty()) { + std::vector<std::string> invalidOptions; + for (auto const& e : arguments.FilePermissions) { + if (!cmFSPermissions::stringToModeT(e, permisiions)) { + invalidOptions.push_back(e); + } + } + if (!invalidOptions.empty()) { + std::ostringstream oss; + oss << "given invalid permission "; + for (auto i = 0u; i < invalidOptions.size(); i++) { + if (i == 0u) { + oss << "\"" << invalidOptions[i] << "\""; + } else { + oss << ",\"" << invalidOptions[i] << "\""; + } + } + oss << "."; + status.SetError(oss.str()); + return false; + } } - std::string input = args[4]; - AddEvaluationFile(input, target, output, condition, inputIsContent, status); + AddEvaluationFile(input, arguments.Target, arguments.Output, + arguments.Condition, inputIsContent, permisiions, status); return true; } @@ -2902,17 +3010,60 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args, bool HandleConfigureCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { - if (args.size() < 5) { - status.SetError("Incorrect arguments to CONFIGURE subcommand."); + struct Arguments + { + std::string Output; + std::string Content; + bool EscapeQuotes = false; + bool AtOnly = false; + std::string NewlineStyle; + }; + + static auto const parser = + cmArgumentParser<Arguments>{} + .Bind("OUTPUT"_s, &Arguments::Output) + .Bind("CONTENT"_s, &Arguments::Content) + .Bind("ESCAPE_QUOTES"_s, &Arguments::EscapeQuotes) + .Bind("@ONLY"_s, &Arguments::AtOnly) + .Bind("NEWLINE_STYLE"_s, &Arguments::NewlineStyle); + + std::vector<std::string> unrecognizedArguments; + std::vector<std::string> keywordsMissingArguments; + std::vector<std::string> parsedKeywords; + auto parsedArgs = + parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments, + &keywordsMissingArguments, &parsedKeywords); + + auto argIt = unrecognizedArguments.begin(); + if (argIt != unrecognizedArguments.end()) { + status.SetError( + cmStrCat("CONFIGURE Unrecognized argument: \"", *argIt, "\"")); + cmSystemTools::SetFatalErrorOccured(); return false; } - if (args[1] != "OUTPUT") { - status.SetError("Incorrect arguments to CONFIGURE subcommand."); - return false; + + std::vector<std::string> mandatoryOptions{ "OUTPUT", "CONTENT" }; + for (auto const& e : mandatoryOptions) { + const bool optionHasNoValue = + std::find(keywordsMissingArguments.begin(), + keywordsMissingArguments.end(), + e) != keywordsMissingArguments.end(); + if (optionHasNoValue) { + status.SetError(cmStrCat("CONFIGURE ", e, " option needs a value.")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } } - if (args[3] != "CONTENT") { - status.SetError("Incorrect arguments to CONFIGURE subcommand."); - return false; + + for (auto const& e : mandatoryOptions) { + const bool optionGiven = + std::find(parsedKeywords.begin(), parsedKeywords.end(), e) != + parsedKeywords.end(); + if (!optionGiven) { + status.SetError(cmStrCat("CONFIGURE ", e, " option is mandatory.")); + cmSystemTools::SetFatalErrorOccured(); + return false; + } } std::string errorMessage; @@ -2922,28 +3073,9 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, return false; } - bool escapeQuotes = false; - bool atOnly = false; - for (unsigned int i = 5; i < args.size(); ++i) { - if (args[i] == "@ONLY") { - atOnly = true; - } else if (args[i] == "ESCAPE_QUOTES") { - escapeQuotes = true; - } else if (args[i] == "NEWLINE_STYLE" || args[i] == "LF" || - args[i] == "UNIX" || args[i] == "CRLF" || args[i] == "WIN32" || - args[i] == "DOS") { - /* Options handled by NewLineStyle member above. */ - } else { - status.SetError( - cmStrCat("CONFIGURE Unrecognized argument \"", args[i], "\"")); - return false; - } - } - // Check for generator expressions - const std::string input = args[4]; std::string outputFile = cmSystemTools::CollapseFullPath( - args[2], status.GetMakefile().GetCurrentBinaryDirectory()); + parsedArgs.Output, status.GetMakefile().GetCurrentBinaryDirectory()); std::string::size_type pos = outputFile.find_first_of("<>"); if (pos != std::string::npos) { @@ -2992,12 +3124,13 @@ bool HandleConfigureCommand(std::vector<std::string> const& args, fout.SetCopyIfDifferent(true); // copy input to output and expand variables from input at the same time - std::stringstream sin(input, std::ios::in); + std::stringstream sin(parsedArgs.Content, std::ios::in); std::string inLine; std::string outLine; while (cmSystemTools::GetLineFromStream(sin, inLine)) { outLine.clear(); - makeFile.ConfigureString(inLine, outLine, atOnly, escapeQuotes); + makeFile.ConfigureString(inLine, outLine, parsedArgs.AtOnly, + parsedArgs.EscapeQuotes); fout << outLine << newLineCharacters; } diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx deleted file mode 100644 index 8cfdb2d..0000000 --- a/Source/cmFileMonitor.cxx +++ /dev/null @@ -1,383 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmFileMonitor.h" - -#include <cassert> -#include <cstddef> -#include <unordered_map> -#include <utility> - -#include <cm/memory> - -#include "cmsys/SystemTools.hxx" - -namespace { -void on_directory_change(uv_fs_event_t* handle, const char* filename, - int events, int status); -void on_fs_close(uv_handle_t* handle); -} // namespace - -class cmIBaseWatcher -{ -public: - virtual ~cmIBaseWatcher() = default; - - virtual void Trigger(const std::string& pathSegment, int events, - int status) const = 0; - virtual std::string Path() const = 0; - virtual uv_loop_t* Loop() const = 0; - - virtual void StartWatching() = 0; - virtual void StopWatching() = 0; - - virtual std::vector<std::string> WatchedFiles() const = 0; - virtual std::vector<std::string> WatchedDirectories() const = 0; -}; - -class cmVirtualDirectoryWatcher : public cmIBaseWatcher -{ -public: - ~cmVirtualDirectoryWatcher() override = default; - - cmIBaseWatcher* Find(const std::string& ps) - { - const auto i = this->Children.find(ps); - return (i == this->Children.end()) ? nullptr : i->second.get(); - } - - void Trigger(const std::string& pathSegment, int events, - int status) const final - { - if (pathSegment.empty()) { - for (auto const& child : this->Children) { - child.second->Trigger(std::string(), events, status); - } - } else { - const auto i = this->Children.find(pathSegment); - if (i != this->Children.end()) { - i->second->Trigger(std::string(), events, status); - } - } - } - - void StartWatching() override - { - for (auto const& child : this->Children) { - child.second->StartWatching(); - } - } - - void StopWatching() override - { - for (auto const& child : this->Children) { - child.second->StopWatching(); - } - } - - std::vector<std::string> WatchedFiles() const final - { - std::vector<std::string> result; - for (auto const& child : this->Children) { - for (std::string const& f : child.second->WatchedFiles()) { - result.push_back(f); - } - } - return result; - } - - std::vector<std::string> WatchedDirectories() const override - { - std::vector<std::string> result; - for (auto const& child : this->Children) { - for (std::string const& dir : child.second->WatchedDirectories()) { - result.push_back(dir); - } - } - return result; - } - - void Reset() { this->Children.clear(); } - - void AddChildWatcher(const std::string& ps, cmIBaseWatcher* watcher) - { - assert(!ps.empty()); - assert(this->Children.find(ps) == this->Children.end()); - assert(watcher); - - this->Children.emplace(ps, std::unique_ptr<cmIBaseWatcher>(watcher)); - } - -private: - std::unordered_map<std::string, std::unique_ptr<cmIBaseWatcher>> - Children; // owned! -}; - -// Root of all the different (on windows!) root directories: -class cmRootWatcher : public cmVirtualDirectoryWatcher -{ -public: - cmRootWatcher(uv_loop_t* loop) - : mLoop(loop) - { - assert(loop); - } - - std::string Path() const final - { - assert(false); - return std::string(); - } - uv_loop_t* Loop() const final { return this->mLoop; } - -private: - uv_loop_t* const mLoop; // no ownership! -}; - -// Real directories: -class cmRealDirectoryWatcher : public cmVirtualDirectoryWatcher -{ -public: - cmRealDirectoryWatcher(cmVirtualDirectoryWatcher* p, const std::string& ps) - : Parent(p) - , PathSegment(ps) - { - assert(p); - assert(!ps.empty()); - - p->AddChildWatcher(ps, this); - } - - void StartWatching() final - { - if (!this->Handle) { - this->Handle = new uv_fs_event_t; - - uv_fs_event_init(this->Loop(), this->Handle); - this->Handle->data = this; - uv_fs_event_start(this->Handle, &on_directory_change, Path().c_str(), 0); - } - cmVirtualDirectoryWatcher::StartWatching(); - } - - void StopWatching() final - { - if (this->Handle) { - uv_fs_event_stop(this->Handle); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(this->Handle))) { - uv_close(reinterpret_cast<uv_handle_t*>(this->Handle), &on_fs_close); - } - this->Handle = nullptr; - } - cmVirtualDirectoryWatcher::StopWatching(); - } - - uv_loop_t* Loop() const final { return this->Parent->Loop(); } - - std::vector<std::string> WatchedDirectories() const override - { - std::vector<std::string> result = { Path() }; - for (std::string const& dir : - cmVirtualDirectoryWatcher::WatchedDirectories()) { - result.push_back(dir); - } - return result; - } - -protected: - cmVirtualDirectoryWatcher* const Parent; - const std::string PathSegment; - -private: - uv_fs_event_t* Handle = nullptr; // owner! -}; - -// Root directories: -class cmRootDirectoryWatcher : public cmRealDirectoryWatcher -{ -public: - cmRootDirectoryWatcher(cmRootWatcher* p, const std::string& ps) - : cmRealDirectoryWatcher(p, ps) - { - } - - std::string Path() const final { return this->PathSegment; } -}; - -// Normal directories below root: -class cmDirectoryWatcher : public cmRealDirectoryWatcher -{ -public: - cmDirectoryWatcher(cmRealDirectoryWatcher* p, const std::string& ps) - : cmRealDirectoryWatcher(p, ps) - { - } - - std::string Path() const final - { - return this->Parent->Path() + this->PathSegment + "/"; - } -}; - -class cmFileWatcher : public cmIBaseWatcher -{ -public: - cmFileWatcher(cmRealDirectoryWatcher* p, const std::string& ps, - cmFileMonitor::Callback cb) - : Parent(p) - , PathSegment(ps) - , CbList({ std::move(cb) }) - { - assert(p); - assert(!ps.empty()); - p->AddChildWatcher(ps, this); - } - - void StartWatching() final {} - - void StopWatching() final {} - - void AppendCallback(cmFileMonitor::Callback const& cb) - { - this->CbList.push_back(cb); - } - - std::string Path() const final - { - return this->Parent->Path() + this->PathSegment; - } - - std::vector<std::string> WatchedDirectories() const final { return {}; } - - std::vector<std::string> WatchedFiles() const final - { - return { this->Path() }; - } - - void Trigger(const std::string& ps, int events, int status) const final - { - assert(ps.empty()); - assert(status == 0); - static_cast<void>(ps); - - const std::string path = this->Path(); - for (cmFileMonitor::Callback const& cb : this->CbList) { - cb(path, events, status); - } - } - - uv_loop_t* Loop() const final { return this->Parent->Loop(); } - -private: - cmRealDirectoryWatcher* Parent; - const std::string PathSegment; - std::vector<cmFileMonitor::Callback> CbList; -}; - -namespace { - -void on_directory_change(uv_fs_event_t* handle, const char* filename, - int events, int status) -{ - const cmIBaseWatcher* const watcher = - static_cast<const cmIBaseWatcher*>(handle->data); - const std::string pathSegment(filename ? filename : ""); - watcher->Trigger(pathSegment, events, status); -} - -void on_fs_close(uv_handle_t* handle) -{ - delete reinterpret_cast<uv_fs_event_t*>(handle); -} - -} // namespace - -cmFileMonitor::cmFileMonitor(uv_loop_t* l) - : Root(cm::make_unique<cmRootWatcher>(l)) -{ -} - -cmFileMonitor::~cmFileMonitor() = default; - -void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths, - Callback const& cb) -{ - for (std::string const& p : paths) { - std::vector<std::string> pathSegments; - cmsys::SystemTools::SplitPath(p, pathSegments, true); - const bool pathIsFile = !cmsys::SystemTools::FileIsDirectory(p); - - const size_t segmentCount = pathSegments.size(); - if (segmentCount < 2) { // Expect at least rootdir and filename - continue; - } - cmVirtualDirectoryWatcher* currentWatcher = this->Root.get(); - for (size_t i = 0; i < segmentCount; ++i) { - assert(currentWatcher); - - const bool fileSegment = (i == segmentCount - 1 && pathIsFile); - const bool rootSegment = (i == 0); - assert( - !(fileSegment && - rootSegment)); // Can not be both filename and root part of the path! - - const std::string& currentSegment = pathSegments[i]; - if (currentSegment.empty()) { - continue; - } - - cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment); - if (!nextWatcher) { - if (rootSegment) { // Root part - assert(currentWatcher == this->Root.get()); - nextWatcher = - new cmRootDirectoryWatcher(this->Root.get(), currentSegment); - assert(currentWatcher->Find(currentSegment) == nextWatcher); - } else if (fileSegment) { // File part - assert(currentWatcher != this->Root.get()); - nextWatcher = new cmFileWatcher( - dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher), - currentSegment, cb); - assert(currentWatcher->Find(currentSegment) == nextWatcher); - } else { // Any normal directory in between - nextWatcher = new cmDirectoryWatcher( - dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher), - currentSegment); - assert(currentWatcher->Find(currentSegment) == nextWatcher); - } - } else { - if (fileSegment) { - auto filePtr = dynamic_cast<cmFileWatcher*>(nextWatcher); - assert(filePtr); - filePtr->AppendCallback(cb); - continue; - } - } - currentWatcher = dynamic_cast<cmVirtualDirectoryWatcher*>(nextWatcher); - } - } - this->Root->StartWatching(); -} - -void cmFileMonitor::StopMonitoring() -{ - this->Root->StopWatching(); - this->Root->Reset(); -} - -std::vector<std::string> cmFileMonitor::WatchedFiles() const -{ - std::vector<std::string> result; - if (this->Root) { - result = this->Root->WatchedFiles(); - } - return result; -} - -std::vector<std::string> cmFileMonitor::WatchedDirectories() const -{ - std::vector<std::string> result; - if (this->Root) { - result = this->Root->WatchedDirectories(); - } - return result; -} diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h deleted file mode 100644 index fc75b0c..0000000 --- a/Source/cmFileMonitor.h +++ /dev/null @@ -1,35 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <functional> -#include <memory> -#include <string> -#include <vector> - -#include <cm3p/uv.h> - -class cmRootWatcher; - -class cmFileMonitor -{ - -public: - cmFileMonitor(uv_loop_t* l); - ~cmFileMonitor(); - - cmFileMonitor(cmFileMonitor const&) = delete; - cmFileMonitor& operator=(cmFileMonitor const&) = delete; - - using Callback = std::function<void(const std::string&, int, int)>; - void MonitorPaths(const std::vector<std::string>& paths, Callback const& cb); - void StopMonitoring(); - - std::vector<std::string> WatchedFiles() const; - std::vector<std::string> WatchedDirectories() const; - -private: - std::unique_ptr<cmRootWatcher> Root; -}; diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx index bb3f610..6b52230 100644 --- a/Source/cmFilePathChecksum.cxx +++ b/Source/cmFilePathChecksum.cxx @@ -16,15 +16,16 @@ cmFilePathChecksum::cmFilePathChecksum(std::string const& currentSrcDir, std::string const& projectSrcDir, std::string const& projectBinDir) { - setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); + this->setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, + projectBinDir); } cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile) { - setupParentDirs(makefile->GetCurrentSourceDirectory(), - makefile->GetCurrentBinaryDirectory(), - makefile->GetHomeDirectory(), - makefile->GetHomeOutputDirectory()); + this->setupParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); } void cmFilePathChecksum::setupParentDirs(std::string const& currentSrcDir, @@ -81,5 +82,5 @@ std::string cmFilePathChecksum::get(std::string const& filePath) const std::string cmFilePathChecksum::getPart(std::string const& filePath, size_t length) const { - return get(filePath).substr(0, length); + return this->get(filePath).substr(0, length); } diff --git a/Source/cmFileTimes.cxx b/Source/cmFileTimes.cxx index d8fe24c..bd896f5 100644 --- a/Source/cmFileTimes.cxx +++ b/Source/cmFileTimes.cxx @@ -62,14 +62,14 @@ public: cmFileTimes::cmFileTimes() = default; cmFileTimes::cmFileTimes(std::string const& fileName) { - Load(fileName); + this->Load(fileName); } cmFileTimes::~cmFileTimes() = default; bool cmFileTimes::Load(std::string const& fileName) { std::unique_ptr<Times> ptr; - if (IsValid()) { + if (this->IsValid()) { // Invalidate this and re-use times ptr.swap(this->times); } else { @@ -103,7 +103,7 @@ bool cmFileTimes::Load(std::string const& fileName) bool cmFileTimes::Store(std::string const& fileName) const { - if (!IsValid()) { + if (!this->IsValid()) { return false; } diff --git a/Source/cmFileTimes.h b/Source/cmFileTimes.h index f1916f7..50d64fd 100644 --- a/Source/cmFileTimes.h +++ b/Source/cmFileTimes.h @@ -19,7 +19,7 @@ public: ~cmFileTimes(); //! @return true, if file times were loaded successfully - bool IsValid() const { return (times != nullptr); } + bool IsValid() const { return (this->times != nullptr); } //! Try to load the file times from @a fileName and @return IsValid() bool Load(std::string const& fileName); //! Stores the file times at @a fileName (if IsValid()) diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index dee91d7..d2f9619 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -182,7 +182,7 @@ void cmFindCommon::SelectDefaultSearchModes() { this->NoCMakeSystemPath, "CMAKE_FIND_USE_CMAKE_SYSTEM_PATH" } } }; - for (auto& path : search_paths) { + for (auto const& path : search_paths) { cmProp def = this->Makefile->GetDefinition(path.second); if (def) { path.first = !cmIsOn(*def); @@ -289,7 +289,7 @@ void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore) void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore) { std::vector<std::string> ignoreVec; - GetIgnoredPaths(ignoreVec); + this->GetIgnoredPaths(ignoreVec); ignore.insert(ignoreVec.begin(), ignoreVec.end()); } diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index b87dfe3..49b1bd7 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -31,7 +31,7 @@ cmFindLibraryCommand::cmFindLibraryCommand(cmExecutionStatus& status) // cmFindLibraryCommand bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn) { - this->DebugMode = ComputeIfDebugModeWanted(); + this->DebugMode = this->ComputeIfDebugModeWanted(); this->VariableDocumentation = "Path to a library."; this->CMakePathName = "LIBRARY"; if (!this->ParseArguments(argsIn)) { diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 92b1e80..3b7cf4c 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -144,7 +144,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]); } - this->DebugMode = ComputeIfDebugModeWanted(); + this->DebugMode = this->ComputeIfDebugModeWanted(); this->DebugBuffer.clear(); // Lookup target architecture, if any. @@ -534,7 +534,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) loadedPackage = true; } else { // The package was not loaded. Report errors. - if (HandlePackageMode(HandlePackageModeType::Module)) { + if (this->HandlePackageMode(HandlePackageModeType::Module)) { loadedPackage = true; } } @@ -2070,8 +2070,8 @@ public: void SetSort(cmFindPackageCommand::SortOrderType o, cmFindPackageCommand::SortDirectionType d) { - SortOrder = o; - SortDirection = d; + this->SortOrder = o; + this->SortDirection = d; } protected: @@ -2102,8 +2102,8 @@ private: // before testing the matches check if there is a specific sorting order to // perform if (this->SortOrder != cmFindPackageCommand::None) { - cmFindPackageCommand::Sort(matches.begin(), matches.end(), SortOrder, - SortDirection); + cmFindPackageCommand::Sort(matches.begin(), matches.end(), + this->SortOrder, this->SortDirection); } for (std::string const& i : matches) { diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx index 4bab469..bece33b 100644 --- a/Source/cmFindPathCommand.cxx +++ b/Source/cmFindPathCommand.cxx @@ -22,7 +22,7 @@ cmFindPathCommand::cmFindPathCommand(cmExecutionStatus& status) // cmFindPathCommand bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn) { - this->DebugMode = ComputeIfDebugModeWanted(); + this->DebugMode = this->ComputeIfDebugModeWanted(); this->VariableDocumentation = "Path to a file."; this->CMakePathName = "INCLUDE"; if (!this->ParseArguments(argsIn)) { diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 77728ec..5bb4234 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -152,7 +152,7 @@ cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status) // cmFindProgramCommand bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn) { - this->DebugMode = ComputeIfDebugModeWanted(); + this->DebugMode = this->ComputeIfDebugModeWanted(); this->VariableDocumentation = "Path to a program."; this->CMakePathName = "PROGRAM"; // call cmFindBase::ParseArguments @@ -171,7 +171,7 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn) return true; } - std::string const result = FindProgram(); + std::string const result = this->FindProgram(); if (!result.empty()) { // Save the value in the cache this->Makefile->AddCacheDefinition(this->VariableName, result, @@ -198,7 +198,7 @@ std::string cmFindProgramCommand::FindProgram() std::string program; if (this->SearchAppBundleFirst || this->SearchAppBundleOnly) { - program = FindAppBundle(); + program = this->FindAppBundle(); } if (program.empty() && !this->SearchAppBundleOnly) { program = this->FindNormalProgram(); @@ -274,7 +274,7 @@ std::string cmFindProgramCommand::FindAppBundle() cmSystemTools::FindDirectory(appName, this->SearchPaths, true); if (!appPath.empty()) { - std::string executable = GetBundleExecutable(appPath); + std::string executable = this->GetBundleExecutable(appPath); if (!executable.empty()) { return cmSystemTools::CollapseFullPath(executable); } diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 71c82d6..1359009 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -163,8 +163,11 @@ bool cmFunctionFunctionBlocker::Replay( f.FilePath = this->GetStartingContext().FilePath; f.Line = this->GetStartingContext().Line; mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f)); - return true; + return mf.GetState()->AddScriptedCommand( + this->Args.front(), + BT<cmState::Command>(std::move(f), + mf.GetBacktrace().Push(this->GetStartingContext())), + mf); } } // anonymous namespace diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx index 957896f..c782bcd 100644 --- a/Source/cmGccDepfileLexerHelper.cxx +++ b/Source/cmGccDepfileLexerHelper.cxx @@ -27,23 +27,30 @@ bool cmGccDepfileLexerHelper::readFile(const char* filePath) if (!file) { return false; } - newEntry(); + this->newEntry(); yyscan_t scanner; cmGccDepfile_yylex_init(&scanner); cmGccDepfile_yyset_extra(this, scanner); cmGccDepfile_yyrestart(file, scanner); cmGccDepfile_yylex(scanner); cmGccDepfile_yylex_destroy(scanner); - sanitizeContent(); + this->sanitizeContent(); fclose(file); - return true; + return this->HelperState != State::Failed; } void cmGccDepfileLexerHelper::newEntry() { + if (this->HelperState == State::Rule && !this->Content.empty()) { + if (!this->Content.back().rules.empty() && + !this->Content.back().rules.back().empty()) { + this->HelperState = State::Failed; + } + return; + } this->HelperState = State::Rule; this->Content.emplace_back(); - newRule(); + this->newRule(); } void cmGccDepfileLexerHelper::newRule() @@ -56,20 +63,22 @@ void cmGccDepfileLexerHelper::newRule() void cmGccDepfileLexerHelper::newDependency() { - // printf("NEW DEP\n"); + if (this->HelperState == State::Failed) { + return; + } this->HelperState = State::Dependency; - if (this->Content.back().paths.empty() || - !this->Content.back().paths.back().empty()) { - this->Content.back().paths.emplace_back(); + auto& entry = this->Content.back(); + if (entry.paths.empty() || !entry.paths.back().empty()) { + entry.paths.emplace_back(); } } void cmGccDepfileLexerHelper::newRuleOrDependency() { if (this->HelperState == State::Rule) { - newRule(); - } else { - newDependency(); + this->newRule(); + } else if (this->HelperState == State::Dependency) { + this->newDependency(); } } @@ -93,6 +102,8 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) } dst = &dep->paths.back(); } break; + case State::Failed: + return; } dst->append(s); } diff --git a/Source/cmGccDepfileLexerHelper.h b/Source/cmGccDepfileLexerHelper.h index 07ca61d..91132f5 100644 --- a/Source/cmGccDepfileLexerHelper.h +++ b/Source/cmGccDepfileLexerHelper.h @@ -29,7 +29,8 @@ private: enum class State { Rule, - Dependency + Dependency, + Failed, }; State HelperState = State::Rule; }; diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx index 9d70ede..8253375 100644 --- a/Source/cmGccDepfileReader.cxx +++ b/Source/cmGccDepfileReader.cxx @@ -4,15 +4,43 @@ #include <type_traits> #include <utility> +#include <vector> + +#include <cm/optional> #include "cmGccDepfileLexerHelper.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" -cmGccDepfileContent cmReadGccDepfile(const char* filePath) +cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath, + const std::string& prefix) { - cmGccDepfileContent result; cmGccDepfileLexerHelper helper; - if (helper.readFile(filePath)) { - result = std::move(helper).extractContent(); + if (!helper.readFile(filePath)) { + return cm::nullopt; + } + auto deps = cm::make_optional(std::move(helper).extractContent()); + + for (auto& dep : *deps) { + for (auto& rule : dep.rules) { + if (!prefix.empty() && !cmSystemTools::FileIsFullPath(rule)) { + rule = cmStrCat(prefix, rule); + } + if (cmSystemTools::FileIsFullPath(rule)) { + rule = cmSystemTools::CollapseFullPath(rule); + } + cmSystemTools::ConvertToLongPath(rule); + } + for (auto& path : dep.paths) { + if (!prefix.empty() && !cmSystemTools::FileIsFullPath(path)) { + path = cmStrCat(prefix, path); + } + if (cmSystemTools::FileIsFullPath(path)) { + path = cmSystemTools::CollapseFullPath(path); + } + cmSystemTools::ConvertToLongPath(path); + } } - return result; + + return deps; } diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h index 395dd77..c8a3748 100644 --- a/Source/cmGccDepfileReader.h +++ b/Source/cmGccDepfileReader.h @@ -2,6 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <string> + +#include <cm/optional> + #include "cmGccDepfileReaderTypes.h" -cmGccDepfileContent cmReadGccDepfile(const char* filePath); +/* + * Read dependencies file and append prefix to all relative paths + */ +cm::optional<cmGccDepfileContent> cmReadGccDepfile( + const char* filePath, const std::string& prefix = {}); diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 2768547..43f384a 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -14,11 +14,11 @@ #endif cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding) - : OriginalLocale(getloc()) + : OriginalLocale(this->getloc()) { #ifndef CMAKE_BOOTSTRAP if (encoding != codecvt::None) { - imbue(std::locale(OriginalLocale, new codecvt(encoding))); + this->imbue(std::locale(this->OriginalLocale, new codecvt(encoding))); } #else static_cast<void>(encoding); @@ -28,7 +28,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding) cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name, bool quiet, Encoding encoding) : cmGeneratedFileStreamBase(name) - , Stream(TempName.c_str()) + , Stream(this->TempName.c_str()) { // Check if the file opened. if (!*this && !quiet) { @@ -37,7 +37,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name, } #ifndef CMAKE_BOOTSTRAP if (encoding != codecvt::None) { - imbue(std::locale(getloc(), new codecvt(encoding))); + this->imbue(std::locale(this->getloc(), new codecvt(encoding))); } #else static_cast<void>(encoding); diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index e223f15..a1fce55 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -28,7 +28,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( , Backtrace(std::move(backtrace)) , TransitivePropertiesOnly(false) { - Initialize(); + this->Initialize(); } cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( @@ -42,7 +42,7 @@ cmGeneratorExpressionDAGChecker::cmGeneratorExpressionDAGChecker( , Backtrace() , TransitivePropertiesOnly(false) { - Initialize(); + this->Initialize(); } void cmGeneratorExpressionDAGChecker::Initialize() @@ -52,7 +52,7 @@ void cmGeneratorExpressionDAGChecker::Initialize() #define TEST_TRANSITIVE_PROPERTY_METHOD(METHOD) top->METHOD() || - if (CheckResult == DAG && + if (this->CheckResult == DAG && (CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD( TEST_TRANSITIVE_PROPERTY_METHOD) false)) // NOLINT(*) #undef TEST_TRANSITIVE_PROPERTY_METHOD diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index 9e5023d..ec44df3 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -15,20 +15,21 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSourceFile.h" -#include "cmSourceFileLocationKind.h" #include "cmSystemTools.h" cmGeneratorExpressionEvaluationFile::cmGeneratorExpressionEvaluationFile( std::string input, std::string target, std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr, std::unique_ptr<cmCompiledGeneratorExpression> condition, - bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070) + bool inputIsContent, mode_t permissions, + cmPolicies::PolicyStatus policyStatusCMP0070) : Input(std::move(input)) , Target(std::move(target)) , OutputFileExpr(std::move(outputFileExpr)) , Condition(std::move(condition)) , InputIsContent(inputIsContent) , PolicyStatusCMP0070(policyStatusCMP0070) + , Permissions(permissions) { } @@ -38,7 +39,7 @@ void cmGeneratorExpressionEvaluationFile::Generate( std::map<std::string, std::string>& outputFiles, mode_t perm) { std::string rawCondition = this->Condition->GetInput(); - cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(Target); + cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target); if (!rawCondition.empty()) { std::string condResult = this->Condition->Evaluate(lg, config, target, nullptr, nullptr, lang); @@ -94,16 +95,12 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile( { std::vector<std::string> enabledLanguages; cmGlobalGenerator* gg = lg->GetGlobalGenerator(); - cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(Target); + cmGeneratorTarget* target = lg->FindGeneratorTargetToUse(this->Target); gg->GetEnabledLanguages(enabledLanguages); for (std::string const& le : enabledLanguages) { std::string const name = this->GetOutputFileName(lg, target, config, le); - cmSourceFile* sf = lg->GetMakefile()->GetOrCreateSource( - name, false, cmSourceFileLocationKind::Known); - // Tell TraceDependencies that the file is not expected to exist - // on disk yet. We generate it after that runs. - sf->SetProperty("GENERATED", "1"); + cmSourceFile* sf = lg->GetMakefile()->GetOrCreateGeneratedSource(name); // Tell the build system generators that there is no build rule // to generate the file. @@ -116,14 +113,15 @@ void cmGeneratorExpressionEvaluationFile::CreateOutputFile( void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg) { - mode_t perm = 0; std::string inputContent; if (this->InputIsContent) { inputContent = this->Input; } else { const std::string inputFileName = this->GetInputFileName(lg); lg->GetMakefile()->AddCMakeDependFile(inputFileName); - cmSystemTools::GetPermissions(inputFileName.c_str(), perm); + if (!this->Permissions) { + cmSystemTools::GetPermissions(inputFileName.c_str(), this->Permissions); + } cmsys::ifstream fin(inputFileName.c_str()); if (!fin) { std::ostringstream e; @@ -157,7 +155,8 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg) for (std::string const& le : enabledLanguages) { for (std::string const& li : allConfigs) { - this->Generate(lg, li, le, inputExpression.get(), outputFiles, perm); + this->Generate(lg, li, le, inputExpression.get(), outputFiles, + this->Permissions); if (cmSystemTools::GetFatalErrorOccured()) { return; } diff --git a/Source/cmGeneratorExpressionEvaluationFile.h b/Source/cmGeneratorExpressionEvaluationFile.h index 2cd35ae..5ad5e23 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.h +++ b/Source/cmGeneratorExpressionEvaluationFile.h @@ -24,7 +24,8 @@ public: std::string input, std::string target, std::unique_ptr<cmCompiledGeneratorExpression> outputFileExpr, std::unique_ptr<cmCompiledGeneratorExpression> condition, - bool inputIsContent, cmPolicies::PolicyStatus policyStatusCMP0070); + bool inputIsContent, mode_t permissions, + cmPolicies::PolicyStatus policyStatusCMP0070); void Generate(cmLocalGenerator* lg); @@ -59,4 +60,5 @@ private: std::vector<std::string> Files; const bool InputIsContent; cmPolicies::PolicyStatus PolicyStatusCMP0070; + mode_t Permissions; }; diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 3e7737e..af2afd6 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -60,7 +60,7 @@ struct TextContent : public cmGeneratorExpressionEvaluator void Extend(size_t length) { this->Length += length; } - size_t GetLength() { return this->Length; } + size_t GetLength() const { return this->Length; } private: const char* Content; diff --git a/Source/cmGeneratorExpressionLexer.cxx b/Source/cmGeneratorExpressionLexer.cxx index a7f090a..b8c38c0 100644 --- a/Source/cmGeneratorExpressionLexer.cxx +++ b/Source/cmGeneratorExpressionLexer.cxx @@ -35,14 +35,14 @@ std::vector<cmGeneratorExpressionToken> cmGeneratorExpressionLexer::Tokenize( 2); upto = c + 2; ++c; - SawBeginExpression = true; + this->SawBeginExpression = true; } break; case '>': InsertText(upto, c, result); result.emplace_back(cmGeneratorExpressionToken::EndExpression, c, 1); upto = c + 1; - SawGeneratorExpression = SawBeginExpression; + this->SawGeneratorExpression = this->SawBeginExpression; break; case ':': InsertText(upto, c, result); diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 4ca7405..e40316e 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -677,7 +677,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode } static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$"); - for (auto& param : parameters) { + for (auto const& param : parameters) { if (!compilerIdValidator.find(param)) { reportError(context, content->GetOriginalExpression(), @@ -805,7 +805,7 @@ struct PlatformIdNode : public cmGeneratorExpressionNode return parameters.front().empty() ? "1" : "0"; } - for (auto& param : parameters) { + for (auto const& param : parameters) { if (param == platformId) { return "1"; } @@ -901,7 +901,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode return std::string(); } context->HadContextSensitiveCondition = true; - for (auto& param : parameters) { + for (auto const& param : parameters) { if (context->Config.empty()) { if (param.empty()) { return "1"; @@ -927,7 +927,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) { cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs); - for (auto& param : parameters) { + for (auto const& param : parameters) { if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) { return "1"; } @@ -995,7 +995,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode return context->Language; } - for (auto& param : parameters) { + for (auto const& param : parameters) { if (context->Language == param) { return "1"; } @@ -1101,7 +1101,7 @@ static const struct LinkLanguageNode : public cmGeneratorExpressionNode return context->Language; } - for (auto& param : parameters) { + for (auto const& param : parameters) { if (context->Language == param) { return "1"; } @@ -1129,7 +1129,7 @@ struct LinkerId } static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$"); - for (auto& param : parameters) { + for (auto const& param : parameters) { if (!linkerIdValidator.find(param)) { reportError(context, content->GetOriginalExpression(), "Expression syntax not recognized."); diff --git a/Source/cmGeneratorExpressionParser.cxx b/Source/cmGeneratorExpressionParser.cxx index c2c9ef7..794c1a1 100644 --- a/Source/cmGeneratorExpressionParser.cxx +++ b/Source/cmGeneratorExpressionParser.cxx @@ -22,7 +22,7 @@ cmGeneratorExpressionParser::cmGeneratorExpressionParser( void cmGeneratorExpressionParser::Parse( cmGeneratorExpressionEvaluatorVector& result) { - it = this->Tokens.begin(); + this->it = this->Tokens.begin(); while (this->it != this->Tokens.end()) { this->ParseContent(result); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index c299dad..17d211e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -24,9 +24,7 @@ #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" -#include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" -#include "cmCustomCommandLines.h" #include "cmFileTimes.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" @@ -254,7 +252,7 @@ EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries( { EvaluatedTargetPropertyEntries out; out.Entries.reserve(in.size()); - for (auto& entry : in) { + for (auto const& entry : in) { out.Entries.emplace_back(EvaluateTargetPropertyEntry( thisTarget, config, lang, dagChecker, *entry)); } @@ -332,7 +330,7 @@ cmGeneratorTarget::~cmGeneratorTarget() = default; const std::string& cmGeneratorTarget::GetSourcesProperty() const { std::vector<std::string> values; - for (auto& se : this->SourceEntries) { + for (auto const& se : this->SourceEntries) { values.push_back(se->GetInput()); } static std::string value; @@ -559,7 +557,7 @@ std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const // Frameworks created by multi config generators can have a special // framework postfix. - frameworkPostfix = GetFrameworkMultiConfigPostfix(config); + frameworkPostfix = this->GetFrameworkMultiConfigPostfix(config); if (!frameworkPostfix.empty()) { postfix = &frameworkPostfix; } @@ -578,7 +576,7 @@ std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix( if (!this->IsImported() && postfix && (this->IsFrameworkOnApple() && - !GetGlobalGenerator()->IsMultiConfig())) { + !this->GetGlobalGenerator()->IsMultiConfig())) { postfix = nullptr; } } @@ -992,9 +990,8 @@ cmProp cmGeneratorTarget::GetLanguageExtensions(std::string const& lang) const bool cmGeneratorTarget::GetLanguageStandardRequired( std::string const& lang) const { - cmProp p = - this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED"); - return cmIsOn(p); + return cmIsOn( + this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED")); } void cmGeneratorTarget::GetModuleDefinitionSources( @@ -1539,10 +1536,14 @@ bool processSources(cmGeneratorTarget const* tgt, for (std::string& src : entry.Values) { cmSourceFile* sf = mf->GetOrCreateSource(src); std::string e; - std::string fullPath = sf->ResolveFullPath(&e); + std::string w; + std::string fullPath = sf->ResolveFullPath(&e, &w); + cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); + if (!w.empty()) { + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace()); + } if (fullPath.empty()) { if (!e.empty()) { - cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace()); } return contextDependent; @@ -2500,9 +2501,9 @@ public: } } - bool GetHadLinkLanguageSensitiveCondition() + bool GetHadLinkLanguageSensitiveCondition() const { - return HadLinkLanguageSensitiveCondition; + return this->HadLinkLanguageSensitiveCondition; } private: @@ -2888,9 +2889,6 @@ private: bool IsUtility(std::string const& dep); void CheckCustomCommand(cmCustomCommand const& cc); void CheckCustomCommands(const std::vector<cmCustomCommand>& commands); - void FollowCommandDepends(cmCustomCommand const& cc, - const std::string& config, - std::set<std::string>& emitted); }; cmTargetTraceDependencies::cmTargetTraceDependencies(cmGeneratorTarget* target) @@ -2986,7 +2984,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name) auto i = this->NameMap.lower_bound(name); if (i == this->NameMap.end() || i->first != name) { // Check if we know how to generate this file. - cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name); + cmSourcesWithOutput sources = + this->LocalGenerator->GetSourcesWithOutput(name); // If we failed to find a target or source and we have a relative path, it // might be a valid source if made relative to the current binary // directory. @@ -2996,7 +2995,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name) cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name); fullname = cmSystemTools::CollapseFullPath( fullname, this->Makefile->GetHomeOutputDirectory()); - sources = this->Makefile->GetSourcesWithOutput(fullname); + sources = this->LocalGenerator->GetSourcesWithOutput(fullname); } i = this->NameMap.emplace_hint(i, name, sources); } @@ -3065,7 +3064,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep) } else { // The original name of the dependency was not a full path. It // must name a target, so add the target-level dependency. - this->GeneratorTarget->Target->AddUtility(util, false); + this->GeneratorTarget->Target->AddUtility(util, true); return true; } } @@ -3076,71 +3075,28 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep) void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc) { - // Transform command names that reference targets built in this - // project to corresponding target-level dependencies. - cmGeneratorExpression ge(cc.GetBacktrace()); - - // Add target-level dependencies referenced by generator expressions. - std::set<cmGeneratorTarget*> targets; - - for (cmCustomCommandLine const& cCmdLine : cc.GetCommandLines()) { - std::string const& command = cCmdLine.front(); - // Check for a target with this name. - if (cmGeneratorTarget* t = - this->LocalGenerator->FindGeneratorTargetToUse(command)) { - if (t->GetType() == cmStateEnums::EXECUTABLE) { - // The command refers to an executable target built in - // this project. Add the target-level dependency to make - // sure the executable is up to date before this custom - // command possibly runs. - this->GeneratorTarget->Target->AddUtility(command, true); + // Collect dependencies referenced by all configurations. + std::set<std::string> depends; + for (std::string const& config : + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) { + for (cmCustomCommandGenerator const& ccg : + this->LocalGenerator->MakeCustomCommandGenerators(cc, config)) { + // Collect target-level dependencies referenced in command lines. + for (auto const& util : ccg.GetUtilities()) { + this->GeneratorTarget->Target->AddUtility(util); } - } - // Check for target references in generator expressions. - std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - for (std::string const& c : configs) { - for (std::string const& cl : cCmdLine) { - const std::unique_ptr<cmCompiledGeneratorExpression> cge = - ge.Parse(cl); - cge->SetQuiet(true); - cge->Evaluate(this->GeneratorTarget->GetLocalGenerator(), c); - std::set<cmGeneratorTarget*> geTargets = cge->GetTargets(); - targets.insert(geTargets.begin(), geTargets.end()); - } + // Collect file-level dependencies referenced in DEPENDS. + depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end()); } } - for (cmGeneratorTarget* target : targets) { - this->GeneratorTarget->Target->AddUtility(target->GetName(), true); - } - - // Queue the custom command dependencies. - std::set<std::string> emitted; - std::vector<std::string> const& configs = - this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - for (std::string const& conf : configs) { - this->FollowCommandDepends(cc, conf, emitted); - } -} - -void cmTargetTraceDependencies::FollowCommandDepends( - cmCustomCommand const& cc, const std::string& config, - std::set<std::string>& emitted) -{ - cmCustomCommandGenerator ccg(cc, config, - this->GeneratorTarget->LocalGenerator); - - const std::vector<std::string>& depends = ccg.GetDepends(); - + // Queue file-level dependencies. for (std::string const& dep : depends) { - if (emitted.insert(dep).second) { - if (!this->IsUtility(dep)) { - // The dependency does not name a target and may be a file we - // know how to generate. Queue it. - this->FollowName(dep); - } + if (!this->IsUtility(dep)) { + // The dependency does not name a target and may be a file we + // know how to generate. Queue it. + this->FollowName(dep); } } } @@ -3200,6 +3156,30 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config, } } +void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags, + cmSourceFile const& sf) const +{ + cmProp lang = sf.GetProperty("LANGUAGE"); + if (!lang) { + return; + } + + switch (this->GetPolicyStatusCMP0119()) { + case cmPolicies::WARN: + case cmPolicies::OLD: + // The OLD behavior is to not add explicit language flags. + return; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + // The NEW behavior is to add explicit language flags. + break; + } + + this->LocalGenerator->AppendFeatureOptions(flags, *lang, + "EXPLICIT_LANGUAGE"); +} + void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const { const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES"); @@ -3298,7 +3278,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const flags += " --cuda-gpu-arch=sm_" + architecture.name; if (!architecture.real) { - Makefile->IssueMessage( + this->Makefile->IssueMessage( MessageType::WARNING, "Clang doesn't support disabling CUDA real code generation."); } @@ -4988,7 +4968,7 @@ void cmGeneratorTarget::GetFullNameInternal( // the base, because the suffix ends up being used in Xcode's // EXECUTABLE_SUFFIX attribute. if (this->IsFrameworkOnApple() && - GetGlobalGenerator()->GetName() == "Xcode") { + this->GetGlobalGenerator()->GetName() == "Xcode") { targetSuffix = &configPostfix; } else { outBase += configPostfix; @@ -7059,7 +7039,7 @@ const cmLinkImplementation* cmGeneratorTarget::GetLinkImplementation( return &impl; } -bool cmGeneratorTarget::GetConfigCommonSourceFiles( +bool cmGeneratorTarget::GetConfigCommonSourceFilesForXcode( std::vector<cmSourceFile*>& files) const { std::vector<std::string> const& configs = diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 2517b72..8fe70ab 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -430,8 +430,9 @@ public: /** Get source files common to all configurations and diagnose cases with per-config sources. Excludes sources added by a TARGET_OBJECTS - generator expression. */ - bool GetConfigCommonSourceFiles(std::vector<cmSourceFile*>& files) const; + generator expression. Do not use outside the Xcode generator. */ + bool GetConfigCommonSourceFilesForXcode( + std::vector<cmSourceFile*>& files) const; bool HaveBuildTreeRPATH(const std::string& config) const; @@ -447,6 +448,9 @@ public: void GetAppleArchs(const std::string& config, std::vector<std::string>& archVec) const; + void AddExplicitLanguageFlags(std::string& flags, + cmSourceFile const& sf) const; + void AddCUDAArchitectureFlags(std::string& flags) const; void AddCUDAToolkitFlags(std::string& flags) const; @@ -581,7 +585,8 @@ public: std::string PdbDir; bool empty() const { - return OutDir.empty() && ImpDir.empty() && PdbDir.empty(); + return this->OutDir.empty() && this->ImpDir.empty() && + this->PdbDir.empty(); } }; diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx index c2098c0..7fbd479 100644 --- a/Source/cmGetDirectoryPropertyCommand.cxx +++ b/Source/cmGetDirectoryPropertyCommand.cxx @@ -50,6 +50,10 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args, return false; } ++i; + if (i == args.end()) { + status.SetError("called with incorrect number of arguments"); + return false; + } } // OK, now we have the directory to process, we just get the requested @@ -67,27 +71,30 @@ bool cmGetDirectoryPropertyCommand(std::vector<std::string> const& args, return true; } + if (i->empty()) { + status.SetError("given empty string for the property name to get"); + return false; + } + const char* prop = nullptr; - if (!i->empty()) { - if (*i == "DEFINITIONS") { - switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0059)) { - case cmPolicies::WARN: - status.GetMakefile().IssueMessage( - MessageType::AUTHOR_WARNING, - cmPolicies::GetPolicyWarning(cmPolicies::CMP0059)); - CM_FALLTHROUGH; - case cmPolicies::OLD: - StoreResult(status.GetMakefile(), variable, - status.GetMakefile().GetDefineFlagsCMP0059()); - return true; - case cmPolicies::NEW: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::REQUIRED_IF_USED: - break; - } + if (*i == "DEFINITIONS") { + switch (status.GetMakefile().GetPolicyStatus(cmPolicies::CMP0059)) { + case cmPolicies::WARN: + status.GetMakefile().IssueMessage( + MessageType::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0059)); + CM_FALLTHROUGH; + case cmPolicies::OLD: + StoreResult(status.GetMakefile(), variable, + status.GetMakefile().GetDefineFlagsCMP0059()); + return true; + case cmPolicies::NEW: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + break; } - prop = cmToCStr(dir->GetProperty(*i)); } + prop = cmToCStr(dir->GetProperty(*i)); StoreResult(status.GetMakefile(), variable, prop); return true; } diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 3a5b39d..cb657f9 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -172,7 +172,7 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, std::vector<cmMakefile*> source_file_directory_makefiles; bool file_scopes_handled = - SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes( status, source_file_directory_option_enabled, source_file_target_option_enabled, source_file_directories, source_file_target_directories, source_file_directory_makefiles); @@ -280,8 +280,9 @@ bool HandleGlobalMode(cmExecutionStatus& status, const std::string& name, // Get the property. cmake* cm = status.GetMakefile().GetCMakeInstance(); - cmProp p = cm->GetState()->GetGlobalProperty(propertyName); - return StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(p)); + return StoreResult( + infoType, status.GetMakefile(), variable, + cmToCStr(cm->GetState()->GetGlobalProperty(propertyName))); } bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, @@ -327,8 +328,8 @@ bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name, } // Get the property. - cmProp p = mf->GetProperty(propertyName); - return StoreResult(infoType, status.GetMakefile(), variable, cmToCStr(p)); + return StoreResult(infoType, status.GetMakefile(), variable, + cmToCStr(mf->GetProperty(propertyName))); } bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, @@ -358,15 +359,14 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, } return StoreResult(infoType, status.GetMakefile(), variable, nullptr); } - cmProp prop_cstr = nullptr; cmListFileBacktrace bt = status.GetMakefile().GetBacktrace(); cmMessenger* messenger = status.GetMakefile().GetMessenger(); - prop_cstr = target->GetComputedProperty(propertyName, messenger, bt); - if (!prop_cstr) { - prop_cstr = target->GetProperty(propertyName); + cmProp prop = target->GetComputedProperty(propertyName, messenger, bt); + if (!prop) { + prop = target->GetProperty(propertyName); } return StoreResult(infoType, status.GetMakefile(), variable, - prop_cstr ? prop_cstr->c_str() : nullptr); + cmToCStr(prop)); } status.SetError(cmStrCat("could not find TARGET ", name, ". Perhaps it has not yet been created.")); @@ -391,7 +391,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, - sf->GetPropertyForUser(propertyName)); + cmToCStr(sf->GetPropertyForUser(propertyName))); } status.SetError( cmStrCat("given SOURCE name that could not be found or created: ", diff --git a/Source/cmGetSourceFilePropertyCommand.cxx b/Source/cmGetSourceFilePropertyCommand.cxx index 5395bc8..5301b66 100644 --- a/Source/cmGetSourceFilePropertyCommand.cxx +++ b/Source/cmGetSourceFilePropertyCommand.cxx @@ -4,6 +4,7 @@ #include "cmExecutionStatus.h" #include "cmMakefile.h" +#include "cmProperty.h" #include "cmSetPropertyCommand.h" #include "cmSourceFile.h" @@ -34,7 +35,7 @@ bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args, std::vector<cmMakefile*> source_file_directory_makefiles; bool file_scopes_handled = - SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes( status, source_file_directory_option_enabled, source_file_target_option_enabled, source_file_directories, source_file_target_directories, source_file_directory_makefiles); @@ -57,14 +58,14 @@ bool cmGetSourceFilePropertyCommand(std::vector<std::string> const& args, } if (sf) { - const char* prop = nullptr; + cmProp prop = nullptr; if (!args[property_arg_index].empty()) { prop = sf->GetPropertyForUser(args[property_arg_index]); } if (prop) { // Set the value on the original Makefile scope, not the scope of the // requested directory. - status.GetMakefile().AddDefinition(var, prop); + status.GetMakefile().AddDefinition(var, *prop); return true; } } diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index a8f8f57..a7658f2 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -62,7 +62,7 @@ void cmGhsMultiTargetGenerator::Generate() // Get the name of the executable to generate. this->TargetNameReal = this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real; - if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) { + if (this->cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) { this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION; } else { this->TagType = GhsMultiGpj::PROGRAM; @@ -631,7 +631,7 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) } } else { std::vector<cmSourceFile const*> customCommands; - if (ComputeCustomCommandOrder(customCommands)) { + if (this->ComputeCustomCommandOrder(customCommands)) { std::string message = "The custom commands for target [" + this->GeneratorTarget->GetName() + "] had a cycle.\n"; cmSystemTools::Error(message); @@ -721,8 +721,7 @@ void cmGhsMultiTargetGenerator::WriteObjectLangOverride( bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp() { - cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app"); - if (p) { + if (cmProp p = this->GeneratorTarget->GetProperty("ghs_integrity_app")) { return cmIsOn(*p); } std::vector<cmSourceFile*> sources; @@ -746,7 +745,7 @@ bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder( this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName); for (cmSourceFile const* si : customCommands) { - bool r = VisitCustomCommand(temp, perm, order, si); + bool r = this->VisitCustomCommand(temp, perm, order, si); if (r) { return r; } @@ -763,9 +762,9 @@ bool cmGhsMultiTargetGenerator::VisitCustomCommand( /* set temporary mark; check if revisit*/ if (temp.insert(si).second) { for (auto& di : si->GetCustomCommand()->GetDepends()) { - cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator() - ->GetMakefile() - ->GetSourceFileWithOutput(di); + cmSourceFile const* sf = + this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput( + di); /* if sf exists then visit */ if (sf && this->VisitCustomCommand(temp, perm, order, sf)) { return true; diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index 06943e7..996fcff 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -26,6 +26,15 @@ cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator(cmake* cm) this->DefineWindowsNULL = true; this->PassMakeflags = true; this->UnixCD = false; + + /* + * Borland Make does not support long line depend rule, as we have tested + * generate one source file includes 40000 header files, and generate + * depend.make in one line(use line continued tag), and error occured: + * ** Fatal CMakeFiles\main.dir\depend.make 1224: Rule line too long ** + * we disable long line dependencies rule generation for Borland make + */ + this->ToolSupportsLongLineDependencies = false; } void cmGlobalBorlandMakefileGenerator::EnableLanguage( diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index fc40d63..63aaf27 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1821,6 +1821,7 @@ void cmGlobalGenerator::ClearGeneratorMembers() this->RuleHashes.clear(); this->DirectoryContentMap.clear(); this->BinaryDirectories.clear(); + this->GeneratedFiles.clear(); } void cmGlobalGenerator::ComputeTargetObjectDirectory( @@ -2146,6 +2147,16 @@ void cmGlobalGenerator::AddInstallComponent(const std::string& component) } } +void cmGlobalGenerator::MarkAsGeneratedFile(const std::string& filepath) +{ + this->GeneratedFiles.insert(filepath); +} + +bool cmGlobalGenerator::IsGeneratedFile(const std::string& filepath) +{ + return this->GeneratedFiles.find(filepath) != this->GeneratedFiles.end(); +} + void cmGlobalGenerator::EnableInstallTarget() { this->InstallTargetEnabled = true; @@ -2608,7 +2619,7 @@ void cmGlobalGenerator::AddGlobalTarget_Test( } void cmGlobalGenerator::AddGlobalTarget_EditCache( - std::vector<GlobalTargetInfo>& targets) + std::vector<GlobalTargetInfo>& targets) const { const char* editCacheTargetName = this->GetEditCacheTargetName(); if (!editCacheTargetName) { @@ -2642,7 +2653,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( } void cmGlobalGenerator::AddGlobalTarget_RebuildCache( - std::vector<GlobalTargetInfo>& targets) + std::vector<GlobalTargetInfo>& targets) const { const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName(); if (!rebuildCacheTargetName) { @@ -2765,7 +2776,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( } } -std::string cmGlobalGenerator::GetPredefinedTargetsFolder() +std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const { cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty( "PREDEFINED_TARGETS_FOLDER"); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index c106258..86fb228 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -11,9 +11,11 @@ #include <set> #include <string> #include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> +#include <cm/optional> #include <cmext/algorithm> #include "cm_codecvt.hxx" @@ -26,6 +28,7 @@ #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetDepend.h" +#include "cmTransformDepfile.h" #if !defined(CMAKE_BOOTSTRAP) # include <cm3p/json/value.h> @@ -66,17 +69,17 @@ struct GeneratedMakeCommand void Add(T&&... args) { // iterate the args and append each one - AppendStrs(PrimaryCommand, std::forward<T>(args)...); + AppendStrs(this->PrimaryCommand, std::forward<T>(args)...); } // Add each value in the iterators as a separate element to the vector void Add(std::vector<std::string>::const_iterator start, std::vector<std::string>::const_iterator end) { - cm::append(PrimaryCommand, start, end); + cm::append(this->PrimaryCommand, start, end); } - std::string Printable() const { return cmJoin(PrimaryCommand, " "); } + std::string Printable() const { return cmJoin(this->PrimaryCommand, " "); } std::vector<std::string> PrimaryCommand; bool RequiresOutputForward = false; @@ -288,6 +291,11 @@ public: void AddInstallComponent(const std::string& component); + /** Mark the (absolute path to a) file as generated. */ + void MarkAsGeneratedFile(const std::string& filepath); + /** Determine if the absolute filepath belongs to a generated file. */ + bool IsGeneratedFile(const std::string& filepath); + const std::set<std::string>* GetInstallComponents() const { return &this->InstallComponents; @@ -452,6 +460,10 @@ public: virtual bool ShouldStripResourcePath(cmMakefile*) const; virtual bool SupportsCustomCommandDepfile() const { return false; } + virtual cm::optional<cmDepfileFormat> DepfileFormat() const + { + return cm::nullopt; + } std::string GetSharedLibFlagsForLanguage(std::string const& lang) const; @@ -489,7 +501,7 @@ public: cmSourceFile* sf) const; #if !defined(CMAKE_BOOTSTRAP) - cmFileLockPool& GetFileLockPool() { return FileLockPool; } + cmFileLockPool& GetFileLockPool() { return this->FileLockPool; } #endif bool GetConfigureDoneCMP0026() const @@ -568,8 +580,9 @@ protected: void AddGlobalTarget_Package(std::vector<GlobalTargetInfo>& targets); void AddGlobalTarget_PackageSource(std::vector<GlobalTargetInfo>& targets); void AddGlobalTarget_Test(std::vector<GlobalTargetInfo>& targets); - void AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo>& targets); - void AddGlobalTarget_RebuildCache(std::vector<GlobalTargetInfo>& targets); + void AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo>& targets) const; + void AddGlobalTarget_RebuildCache( + std::vector<GlobalTargetInfo>& targets) const; void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets); cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf); @@ -595,7 +608,7 @@ protected: cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const; - std::string GetPredefinedTargetsFolder(); + std::string GetPredefinedTargetsFolder() const; enum class FindMakeProgramStage { @@ -726,6 +739,8 @@ private: std::map<std::string, std::string> RealPaths; + std::unordered_set<std::string> GeneratedFiles; + #if !defined(CMAKE_BOOTSTRAP) // Pool of file locks cmFileLockPool FileLockPool; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index c08c9cf..0ddfe77 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -366,7 +366,7 @@ void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout, target->GetType() == cmStateEnums::MODULE_LIBRARY || target->GetType() == cmStateEnums::SHARED_LIBRARY || (target->GetType() == cmStateEnums::GLOBAL_TARGET && - target->GetName() != GetInstallTargetName())) { + target->GetName() != this->GetInstallTargetName())) { continue; } fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION @@ -415,7 +415,7 @@ void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root) target->GetType() == cmStateEnums::MODULE_LIBRARY || target->GetType() == cmStateEnums::SHARED_LIBRARY || (target->GetType() == cmStateEnums::GLOBAL_TARGET && - target->GetName() != GetInstallTargetName())) { + target->GetName() != this->GetInstallTargetName())) { continue; } @@ -427,13 +427,13 @@ void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root) this->WriteFileHeader(fbld); GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld); std::vector<cmGeneratorTarget const*> build; - if (ComputeTargetBuildOrder(target, build)) { + if (this->ComputeTargetBuildOrder(target, build)) { cmSystemTools::Error( cmStrCat("The inter-target dependency graph for target [", target->GetName(), "] had a cycle.\n")); } else { for (auto& tgt : build) { - WriteProjectLine(fbld, tgt, root, rootBinaryDir); + this->WriteProjectLine(fbld, tgt, root, rootBinaryDir); } } fbld.Close(); @@ -471,12 +471,12 @@ void cmGlobalGhsMultiGenerator::WriteAllTarget( if (!t->IsInBuildSystem()) { continue; } - if (!IsExcluded(t->GetLocalGenerator(), t)) { + if (!this->IsExcluded(t->GetLocalGenerator(), t)) { defaultTargets.push_back(t); } } std::vector<cmGeneratorTarget const*> build; - if (ComputeTargetBuildOrder(defaultTargets, build)) { + if (this->ComputeTargetBuildOrder(defaultTargets, build)) { std::string message = "The inter-target dependency graph for project [" + root->GetProjectName() + "] had a cycle.\n"; cmSystemTools::Error(message); @@ -694,7 +694,7 @@ bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder( cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build) { std::vector<cmGeneratorTarget const*> t{ tgt }; - return ComputeTargetBuildOrder(t, build); + return this->ComputeTargetBuildOrder(t, build); } bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder( @@ -704,8 +704,8 @@ bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder( std::set<cmGeneratorTarget const*> temp; std::set<cmGeneratorTarget const*> perm; - for (auto ti : tgt) { - bool r = VisitTarget(temp, perm, build, ti); + for (auto const ti : tgt) { + bool r = this->VisitTarget(temp, perm, build, ti); if (r) { return r; } @@ -726,7 +726,7 @@ bool cmGlobalGhsMultiGenerator::VisitTarget( * in the same order */ OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti), ""); - for (auto& di : sortedTargets) { + for (auto const& di : sortedTargets) { if (this->VisitTarget(temp, perm, order, di)) { return true; } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 02ffaf7..4f17408 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -34,6 +34,7 @@ #include "cmOutputConverter.h" #include "cmProperty.h" #include "cmRange.h" +#include "cmScanDepFormat.h" #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" @@ -55,6 +56,52 @@ std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd ."; std::string const cmGlobalNinjaGenerator::SHELL_NOOP = ":"; #endif +bool operator==( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return lhs.Target == rhs.Target && lhs.Config == rhs.Config && + lhs.GenexOutput == rhs.GenexOutput; +} + +bool operator!=( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return !(lhs == rhs); +} + +bool operator<( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return lhs.Target < rhs.Target || + (lhs.Target == rhs.Target && + (lhs.Config < rhs.Config || + (lhs.Config == rhs.Config && lhs.GenexOutput < rhs.GenexOutput))); +} + +bool operator>( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return rhs < lhs; +} + +bool operator<=( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return !(lhs > rhs); +} + +bool operator>=( + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, + const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) +{ + return rhs <= lhs; +} + void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count) { for (int i = 0; i < count; ++i) { @@ -135,7 +182,7 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path) else std::replace(result.begin(), result.end(), '/', '\\'); #endif - result = EncodeLiteral(result); + result = this->EncodeLiteral(result); cmSystemTools::ReplaceString(result, " ", "$ "); cmSystemTools::ReplaceString(result, ":", "$:"); return result; @@ -167,7 +214,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, { // Write explicit outputs for (std::string const& output : build.Outputs) { - buildStr += cmStrCat(' ', EncodePath(output)); + buildStr += cmStrCat(' ', this->EncodePath(output)); if (this->ComputingUnknownDependencies) { this->CombinedBuildOutputs.insert(output); } @@ -176,7 +223,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, if (!build.ImplicitOuts.empty()) { buildStr += " |"; for (std::string const& implicitOut : build.ImplicitOuts) { - buildStr += cmStrCat(' ', EncodePath(implicitOut)); + buildStr += cmStrCat(' ', this->EncodePath(implicitOut)); } } buildStr += ':'; @@ -191,14 +238,14 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, // Write explicit dependencies. for (std::string const& explicitDep : build.ExplicitDeps) { - arguments += cmStrCat(' ', EncodePath(explicitDep)); + arguments += cmStrCat(' ', this->EncodePath(explicitDep)); } // Write implicit dependencies. if (!build.ImplicitDeps.empty()) { arguments += " |"; for (std::string const& implicitDep : build.ImplicitDeps) { - arguments += cmStrCat(' ', EncodePath(implicitDep)); + arguments += cmStrCat(' ', this->EncodePath(implicitDep)); } } @@ -206,7 +253,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, if (!build.OrderOnlyDeps.empty()) { arguments += " ||"; for (std::string const& orderOnlyDep : build.OrderOnlyDeps) { - arguments += cmStrCat(' ', EncodePath(orderOnlyDep)); + arguments += cmStrCat(' ', this->EncodePath(orderOnlyDep)); } } @@ -284,11 +331,11 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( #endif vars["COMMAND"] = std::move(cmd); } - vars["DESC"] = EncodeLiteral(description); + vars["DESC"] = this->EncodeLiteral(description); if (restat) { vars["restat"] = "1"; } - if (uses_terminal && SupportsConsolePool()) { + if (uses_terminal && this->SupportsConsolePool()) { vars["pool"] = "console"; } else if (!job_pool.empty()) { vars["pool"] = job_pool; @@ -315,7 +362,7 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( void cmGlobalNinjaGenerator::AddMacOSXContentRule() { cmNinjaRule rule("COPY_OSX_CONTENT"); - rule.Command = cmStrCat(CMakeCmd(), " -E copy $in $out"); + rule.Command = cmStrCat(this->CMakeCmd(), " -E copy $in $out"); rule.Description = "Copying OS X Content $out"; rule.Comment = "Rule for copying OS X bundle content file."; this->AddRule(rule); @@ -508,6 +555,7 @@ void cmGlobalNinjaGenerator::Generate() this->TargetAll = this->NinjaOutputPath("all"); this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt"); this->DisableCleandead = false; + this->DiagnosedCxxModuleSupport = false; this->PolicyCMP0058 = this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus( @@ -708,6 +756,37 @@ bool cmGlobalNinjaGenerator::CheckLanguages( return true; } +bool cmGlobalNinjaGenerator::CheckCxxModuleSupport() +{ + bool const diagnose = !this->DiagnosedCxxModuleSupport && + !this->CMakeInstance->GetIsInTryCompile(); + if (diagnose) { + this->DiagnosedCxxModuleSupport = true; + this->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, + "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP " + "is experimental. It is meant only for compiler developers to try."); + } + if (this->NinjaSupportsDyndeps) { + return true; + } + if (diagnose) { + std::ostringstream e; + /* clang-format off */ + e << + "The Ninja generator does not support C++20 modules " + "using Ninja version \n" + " " << this->NinjaVersion << "\n" + "due to lack of required features. " + "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required." + ; + /* clang-format on */ + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str()); + cmSystemTools::SetFatalErrorOccured(); + } + return false; +} + bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const { if (this->NinjaSupportsDyndeps) { @@ -719,7 +798,8 @@ bool cmGlobalNinjaGenerator::CheckFortran(cmMakefile* mf) const e << "The Ninja generator does not support Fortran using Ninja version\n" " " << this->NinjaVersion << "\n" - "due to lack of required features. Ninja 1.10 or higher is required." + "due to lack of required features. " + "Ninja " << RequiredNinjaVersionForDyndeps() << " or higher is required." ; /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); @@ -738,7 +818,9 @@ bool cmGlobalNinjaGenerator::CheckISPC(cmMakefile* mf) const e << "The Ninja generator does not support ISPC using Ninja version\n" " " << this->NinjaVersion << "\n" - "due to lack of required features. Ninja 1.10 or higher is required." + "due to lack of required features. " + "Ninja " << RequiredNinjaVersionForMultipleOutputs() << + " or higher is required." ; /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); @@ -985,8 +1067,8 @@ static void EnsureTrailingSlash(std::string& path) std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( const std::string& path) const { - auto const f = ConvertToNinjaPathCache.find(path); - if (f != ConvertToNinjaPathCache.end()) { + auto const f = this->ConvertToNinjaPathCache.find(path); + if (f != this->ConvertToNinjaPathCache.end()) { return f->second; } @@ -998,7 +1080,7 @@ std::string const& cmGlobalNinjaGenerator::ConvertToNinjaPath( #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); #endif - return ConvertToNinjaPathCache.emplace(path, std::move(convPath)) + return this->ConvertToNinjaPathCache.emplace(path, std::move(convPath)) .first->second; } @@ -1056,7 +1138,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream() } } -void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) +void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) const { os << "# CMAKE generated file: DO NOT EDIT!\n" << "# Generated by \"" << this->GetName() << "\"" @@ -1070,12 +1152,13 @@ void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() cmNinjaDeps orderOnlyDeps; std::copy(asd.second.begin(), asd.second.end(), std::back_inserter(orderOnlyDeps)); - WriteCustomCommandBuild(/*command=*/"", /*description=*/"", - "Assume dependencies for generated source file.", - /*depfile*/ "", /*job_pool*/ "", - /*uses_terminal*/ false, - /*restat*/ true, cmNinjaDeps(1, asd.first), "", - cmNinjaDeps(), orderOnlyDeps); + this->WriteCustomCommandBuild( + /*command=*/"", /*description=*/"", + "Assume dependencies for generated source file.", + /*depfile*/ "", /*job_pool*/ "", + /*uses_terminal*/ false, + /*restat*/ true, cmNinjaDeps(1, asd.first), "", cmNinjaDeps(), + orderOnlyDeps); } } @@ -1087,7 +1170,7 @@ std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget( void cmGlobalNinjaGenerator::AppendTargetOutputs( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, cmNinjaTargetDepends depends) + const std::string& config, cmNinjaTargetDepends depends) const { // for frameworks, we want the real name, not smple name // frameworks always appear versioned, and the build.ninja @@ -1100,7 +1183,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target, config)); + outputs.push_back(this->OrderDependsTargetForTarget(target, config)); break; } } @@ -1112,7 +1195,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( } case cmStateEnums::OBJECT_LIBRARY: { if (depends == DependOnTargetOrdering) { - outputs.push_back(OrderDependsTargetForTarget(target, config)); + outputs.push_back(this->OrderDependsTargetForTarget(target, config)); break; } } @@ -1193,23 +1276,30 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config) + const std::string& config, const std::string& fileConfig, bool genexOutput) { cmNinjaOuts outs; - this->AppendTargetDependsClosure(target, outs, config, true); + this->AppendTargetDependsClosure(target, outs, config, fileConfig, + genexOutput, true); cm::append(outputs, outs); } void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmGeneratorTarget const* target, cmNinjaOuts& outputs, - const std::string& config, bool omit_self) + const std::string& config, const std::string& fileConfig, bool genexOutput, + bool omit_self) { // try to locate the target in the cache - auto find = this->Configs[config].TargetDependsClosures.lower_bound(target); + ByConfig::TargetDependsClosureKey key{ + target, + config, + genexOutput, + }; + auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key); - if (find == this->Configs[config].TargetDependsClosures.end() || - find->first != target) { + if (find == this->Configs[fileConfig].TargetDependsClosures.end() || + find->first != key) { // We now calculate the closure outputs by inspecting the dependent // targets recursively. // For that we have to distinguish between a local result set that is only @@ -1219,18 +1309,27 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure( cmNinjaOuts this_outs; // this will be the new cache entry for (auto const& dep_target : this->GetTargetDirectDepends(target)) { - if (!dep_target->IsInBuildSystem() || - (target->GetType() != cmStateEnums::UTILITY && - dep_target->GetType() != cmStateEnums::UTILITY && - this->EnableCrossConfigBuild() && !dep_target.IsCross())) { + if (!dep_target->IsInBuildSystem()) { continue; } - // Collect the dependent targets for _this_ target - this->AppendTargetDependsClosure(dep_target, this_outs, config, false); + if (!this->IsSingleConfigUtility(target) && + !this->IsSingleConfigUtility(dep_target) && + this->EnableCrossConfigBuild() && !dep_target.IsCross() && + !genexOutput) { + continue; + } + + if (dep_target.IsCross()) { + this->AppendTargetDependsClosure(dep_target, this_outs, fileConfig, + fileConfig, genexOutput, false); + } else { + this->AppendTargetDependsClosure(dep_target, this_outs, config, + fileConfig, genexOutput, false); + } } - find = this->Configs[config].TargetDependsClosures.emplace_hint( - find, target, std::move(this_outs)); + find = this->Configs[fileConfig].TargetDependsClosures.emplace_hint( + find, key, std::move(this_outs)); } // now fill the outputs of the final result from the newly generated cache @@ -1413,7 +1512,7 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config); configDeps.emplace_back(build.Outputs.front()); for (DirectoryTarget::Target const& t : dt.Targets) { - if (!IsExcludedFromAllInConfig(t, config)) { + if (!this->IsExcludedFromAllInConfig(t, config)) { this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config, DependOnTargetArtifact); } @@ -1626,7 +1725,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) { cmNinjaRule rule("RERUN_CMAKE"); rule.Command = - cmStrCat(CMakeCmd(), " --regenerate-during-build -S", + cmStrCat(this->CMakeCmd(), " --regenerate-during-build -S", lg->ConvertToOutputFormat(lg->GetSourceDirectory(), cmOutputConverter::SHELL), " -B", @@ -1651,7 +1750,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 (SupportsConsolePool()) { + if (this->SupportsConsolePool()) { reBuild.Variables["pool"] = "console"; } @@ -1660,7 +1759,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) { cmNinjaRule rule("VERIFY_GLOBS"); rule.Command = - cmStrCat(CMakeCmd(), " -P ", + cmStrCat(this->CMakeCmd(), " -P ", lg->ConvertToOutputFormat(cm->GetGlobVerifyScript(), cmOutputConverter::SHELL)); rule.Description = "Re-checking globbed directories..."; @@ -1721,8 +1820,8 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) build.Comment = "A missing CMake input file is not an error."; std::set_difference(std::make_move_iterator(reBuild.ImplicitDeps.begin()), std::make_move_iterator(reBuild.ImplicitDeps.end()), - CustomCommandOutputs.begin(), - CustomCommandOutputs.end(), + this->CustomCommandOutputs.begin(), + this->CustomCommandOutputs.end(), std::back_inserter(build.Outputs)); this->WriteBuild(os, build); } @@ -1806,7 +1905,8 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) fout << " file(REMOVE_RECURSE\n"; for (std::string const& acf : it->second.AdditionalCleanFiles) { fout << " " - << cmOutputConverter::EscapeForCMake(ConvertToNinjaPath(acf)) + << cmOutputConverter::EscapeForCMake( + this->ConvertToNinjaPath(acf)) << '\n'; } fout << " )\n"; @@ -1821,7 +1921,7 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) { cmNinjaRule rule("CLEAN_ADDITIONAL"); rule.Command = cmStrCat( - CMakeCmd(), " -DCONFIG=$CONFIG -P ", + this->CMakeCmd(), " -DCONFIG=$CONFIG -P ", lgr->ConvertToOutputFormat(this->NinjaOutputPath(cleanScriptRel), cmOutputConverter::SHELL)); rule.Description = "Cleaning additional files..."; @@ -1838,13 +1938,13 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) build.Outputs.front() = this->BuildAlias( this->NinjaOutputPath(this->GetAdditionalCleanTargetName()), config); build.Variables["CONFIG"] = config; - WriteBuild(os, build); + this->WriteBuild(os, build); } if (this->IsMultiConfig()) { build.Outputs.front() = this->NinjaOutputPath(this->GetAdditionalCleanTargetName()); build.Variables["CONFIG"] = ""; - WriteBuild(os, build); + this->WriteBuild(os, build); } } // Return success @@ -1854,13 +1954,13 @@ bool cmGlobalNinjaGenerator::WriteTargetCleanAdditional(std::ostream& os) void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) { // -- Additional clean target - bool additionalFiles = WriteTargetCleanAdditional(os); + bool additionalFiles = this->WriteTargetCleanAdditional(os); // -- Default clean target // Write rule { cmNinjaRule rule("CLEAN"); - rule.Command = cmStrCat(NinjaCmd(), " $FILE_ARG -t clean $TARGETS"); + rule.Command = cmStrCat(this->NinjaCmd(), " $FILE_ARG -t clean $TARGETS"); rule.Description = "Cleaning all built files..."; rule.Comment = "Rule for cleaning all built files."; WriteRule(*this->RulesFileStream, rule); @@ -1961,13 +2061,13 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) build.Outputs.emplace_back( this->ConvertToNinjaPath(GetByproductsForCleanTargetName())); build.ExplicitDeps = this->ByproductsForCleanTarget; - WriteBuild(os, build); + this->WriteBuild(os, build); for (auto const& config : configs) { build.Outputs.front() = this->BuildAlias( this->ConvertToNinjaPath(GetByproductsForCleanTargetName()), config); build.ExplicitDeps = this->Configs[config].ByproductsForCleanTarget; - WriteBuild(os, build); + this->WriteBuild(os, build); } } } @@ -1976,7 +2076,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) { { cmNinjaRule rule("HELP"); - rule.Command = cmStrCat(NinjaCmd(), " -t targets"); + rule.Command = cmStrCat(this->NinjaCmd(), " -t targets"); rule.Description = "All primary targets available:"; rule.Comment = "Rule for printing all primary targets available."; WriteRule(*this->RulesFileStream, rule); @@ -1985,7 +2085,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) cmNinjaBuild build("HELP"); build.Comment = "Print all primary targets available."; build.Outputs.push_back(this->NinjaOutputPath("help")); - WriteBuild(os, build); + this->WriteBuild(os, build); } } @@ -2016,6 +2116,8 @@ void cmGlobalNinjaGenerator::StripNinjaOutputPathPrefixAsSuffix( cmStripSuffixIfExists(path, this->OutputPathPrefix); } +#if !defined(CMAKE_BOOTSTRAP) + /* We use the following approach to support Fortran. Each target already @@ -2095,16 +2197,6 @@ Compilation of source files within a target is split into the following steps: (because the latter consumes the module). */ -struct cmSourceInfo -{ - // Set of provided and required modules. - std::set<std::string> Provides; - std::set<std::string> Requires; - - // Set of files included in the translation unit. - std::set<std::string> Includes; -}; - static std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran( std::string const& arg_tdi, std::string const& arg_pp); @@ -2112,6 +2204,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd) { std::string arg_tdi; + std::string arg_src; std::string arg_pp; std::string arg_dep; std::string arg_obj; @@ -2120,6 +2213,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, for (std::string const& arg : cmMakeRange(argBeg, argEnd)) { if (cmHasLiteralPrefix(arg, "--tdi=")) { arg_tdi = arg.substr(6); + } else if (cmHasLiteralPrefix(arg, "--src=")) { + arg_src = arg.substr(6); } else if (cmHasLiteralPrefix(arg, "--pp=")) { arg_pp = arg.substr(5); } else if (cmHasLiteralPrefix(arg, "--dep=")) { @@ -2160,6 +2255,9 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, cmSystemTools::Error("-E cmake_ninja_depends requires value for --lang="); return 1; } + if (arg_src.empty()) { + arg_src = cmStrCat("<", arg_obj, " input file>"); + } std::unique_ptr<cmSourceInfo> info; if (arg_lang == "Fortran") { @@ -2176,6 +2274,8 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, return 1; } + info->PrimaryOutput = arg_obj; + { cmGeneratedFileStream depfile(arg_dep); depfile << cmSystemTools::ConvertToUnixOutputPath(arg_pp) << ":"; @@ -2185,24 +2285,7 @@ int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, depfile << "\n"; } - Json::Value ddi(Json::objectValue); - ddi["object"] = arg_obj; - - Json::Value& ddi_provides = ddi["provides"] = Json::arrayValue; - for (std::string const& provide : info->Provides) { - ddi_provides.append(provide); - } - Json::Value& ddi_requires = ddi["requires"] = Json::arrayValue; - for (std::string const& r : info->Requires) { - // Require modules not provided in the same source. - if (!info->Provides.count(r)) { - ddi_requires.append(r); - } - } - - cmGeneratedFileStream ddif(arg_ddi); - ddif << ddi; - if (!ddif) { + if (!cmScanDepFormat_P1689_Write(arg_ddi, arg_src, *info)) { cmSystemTools::Error( cmStrCat("-E cmake_ninja_depends failed to write ", arg_ddi)); return 1; @@ -2260,26 +2343,35 @@ std::unique_ptr<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran( } auto info = cm::make_unique<cmSourceInfo>(); - info->Provides = finfo.Provides; - info->Requires = finfo.Requires; - info->Includes = finfo.Includes; + for (std::string const& provide : finfo.Provides) { + cmSourceReqInfo src_info; + src_info.LogicalName = provide; + src_info.CompiledModulePath = provide; + info->Provides.emplace_back(src_info); + } + for (std::string const& require : finfo.Requires) { + // Require modules not provided in the same source. + if (finfo.Provides.count(require)) { + continue; + } + cmSourceReqInfo src_info; + src_info.LogicalName = require; + src_info.CompiledModulePath = require; + info->Requires.emplace_back(src_info); + } + for (std::string const& include : finfo.Includes) { + info->Includes.push_back(include); + } return info; } -struct cmDyndepObjectInfo -{ - std::string Object; - std::vector<std::string> Provides; - std::vector<std::string> Requires; -}; - bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& dir_top_src, std::string const& dir_top_bld, std::string const& dir_cur_src, std::string const& dir_cur_bld, std::string const& arg_dd, std::vector<std::string> const& arg_ddis, std::string const& module_dir, std::vector<std::string> const& linked_target_dirs, - std::string const& arg_lang) + std::string const& arg_lang, std::string const& arg_modmapfmt) { // Setup path conversions. { @@ -2294,34 +2386,14 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( this->LocalGenerators.push_back(std::move(lgd)); } - std::vector<cmDyndepObjectInfo> objects; + std::vector<cmSourceInfo> objects; for (std::string const& arg_ddi : arg_ddis) { - // Load the ddi file and compute the module file paths it provides. - Json::Value ddio; - Json::Value const& ddi = ddio; - cmsys::ifstream ddif(arg_ddi.c_str(), std::ios::in | std::ios::binary); - Json::Reader reader; - if (!reader.parse(ddif, ddio, false)) { - cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", - arg_ddi, - reader.getFormattedErrorMessages())); + cmSourceInfo info; + if (!cmScanDepFormat_P1689_Parse(arg_ddi, &info)) { + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_dyndep failed to parse ddi file ", arg_ddi)); return false; } - - cmDyndepObjectInfo info; - info.Object = ddi["object"].asString(); - Json::Value const& ddi_provides = ddi["provides"]; - if (ddi_provides.isArray()) { - for (auto const& ddi_provide : ddi_provides) { - info.Provides.push_back(ddi_provide.asString()); - } - } - Json::Value const& ddi_requires = ddi["requires"]; - if (ddi_requires.isArray()) { - for (auto const& ddi_require : ddi_requires) { - info.Requires.push_back(ddi_require.asString()); - } - } objects.push_back(std::move(info)); } @@ -2352,11 +2424,12 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // We do this after loading the modules provided by linked targets // in case we have one of the same name that must be preferred. Json::Value tm = Json::objectValue; - for (cmDyndepObjectInfo const& object : objects) { - for (std::string const& p : object.Provides) { - std::string const mod = cmStrCat(module_dir, p); - mod_files[p] = mod; - tm[p] = mod; + for (cmSourceInfo const& object : objects) { + for (auto const& p : object.Provides) { + std::string const mod = cmStrCat( + module_dir, cmSystemTools::GetFilenameName(p.CompiledModulePath)); + mod_files[p.LogicalName] = mod; + tm[p.LogicalName] = mod; } } @@ -2366,15 +2439,16 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( { cmNinjaBuild build("dyndep"); build.Outputs.emplace_back(""); - for (cmDyndepObjectInfo const& object : objects) { - build.Outputs[0] = object.Object; + for (cmSourceInfo const& object : objects) { + build.Outputs[0] = this->ConvertToNinjaPath(object.PrimaryOutput); build.ImplicitOuts.clear(); - for (std::string const& p : object.Provides) { - build.ImplicitOuts.push_back(this->ConvertToNinjaPath(mod_files[p])); + for (auto const& p : object.Provides) { + build.ImplicitOuts.push_back( + this->ConvertToNinjaPath(mod_files[p.LogicalName])); } build.ImplicitDeps.clear(); - for (std::string const& r : object.Requires) { - auto mit = mod_files.find(r); + for (auto const& r : object.Requires) { + auto mit = mod_files.find(r.LogicalName); if (mit != mod_files.end()) { build.ImplicitDeps.push_back(this->ConvertToNinjaPath(mit->second)); } @@ -2384,6 +2458,48 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( build.Variables.emplace("restat", "1"); } + if (arg_modmapfmt.empty()) { + // nothing to do. + } else { + std::stringstream mm; + if (arg_modmapfmt == "gcc") { + // Documented in GCC's documentation. The format is a series of lines + // with a module name and the associated filename separated by + // spaces. The first line may use `$root` as the module name to + // specify a "repository root". That is used to anchor any relative + // paths present in the file (CMake should never generate any). + + // Write the root directory to use for module paths. + mm << "$root .\n"; + + for (auto const& l : object.Provides) { + auto m = mod_files.find(l.LogicalName); + if (m != mod_files.end()) { + mm << l.LogicalName << " " << this->ConvertToNinjaPath(m->second) + << "\n"; + } + } + for (auto const& r : object.Requires) { + auto m = mod_files.find(r.LogicalName); + if (m != mod_files.end()) { + mm << r.LogicalName << " " << this->ConvertToNinjaPath(m->second) + << "\n"; + } + } + } else { + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_dyndep does not understand the ", + arg_modmapfmt, " module map format")); + return false; + } + + // XXX(modmap): If changing this path construction, change + // `cmNinjaTargetGenerator::WriteObjectBuildStatements` to generate the + // corresponding file path. + cmGeneratedFileStream mmf(cmStrCat(object.PrimaryOutput, ".modmap")); + mmf << mm.str(); + } + this->WriteBuild(ddf, build); } } @@ -2398,11 +2514,6 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( return true; } -bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const -{ - return !this->CrossConfigs.empty(); -} - int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd) { @@ -2412,6 +2523,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::string arg_dd; std::string arg_lang; std::string arg_tdi; + std::string arg_modmapfmt; std::vector<std::string> arg_ddis; for (std::string const& arg : arg_full) { if (cmHasLiteralPrefix(arg, "--tdi=")) { @@ -2420,6 +2532,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, arg_lang = arg.substr(7); } else if (cmHasLiteralPrefix(arg, "--dd=")) { arg_dd = arg.substr(5); + } else if (cmHasLiteralPrefix(arg, "--modmapfmt=")) { + arg_modmapfmt = arg.substr(12); } else if (!cmHasLiteralPrefix(arg, "--") && cmHasLiteralSuffix(arg, ".ddi")) { arg_ddis.push_back(arg); @@ -2478,12 +2592,19 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, if (!ggd || !cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile( dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis, - module_dir, linked_target_dirs, arg_lang)) { + module_dir, linked_target_dirs, arg_lang, arg_modmapfmt)) { return 1; } return 0; } +#endif + +bool cmGlobalNinjaGenerator::EnableCrossConfigBuild() const +{ + return !this->CrossConfigs.empty(); +} + void cmGlobalNinjaGenerator::AppendDirectoryForConfig( const std::string& prefix, const std::string& config, const std::string& suffix, std::string& dir) @@ -2501,6 +2622,13 @@ std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs( return result; } +bool cmGlobalNinjaGenerator::IsSingleConfigUtility( + cmGeneratorTarget const* target) const +{ + return target->GetType() == cmStateEnums::UTILITY && + !this->PerConfigUtilityTargets.count(target->GetName()); +} + const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE = "CMakeFiles/common.ninja"; const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja"; @@ -2651,30 +2779,17 @@ void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() { - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE"); - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS"); - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS"); - return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState()); -} - -std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const -{ - return ""; -} - -bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( - const cmState& state) -{ std::vector<std::string> configsVec; - cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"), - configsVec); + cmExpandList( + this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"), + configsVec); if (configsVec.empty()) { configsVec.emplace_back(); } std::set<std::string> configs(configsVec.cbegin(), configsVec.cend()); this->DefaultFileConfig = - state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE"); + this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE"); if (this->DefaultFileConfig.empty()) { this->DefaultFileConfig = configsVec.front(); } @@ -2689,8 +2804,9 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( } std::vector<std::string> crossConfigsVec; - cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"), - crossConfigsVec); + cmExpandList( + this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"), + crossConfigsVec); auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec); if (!crossConfigs) { std::ostringstream msg; @@ -2703,7 +2819,7 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( this->CrossConfigs = *crossConfigs; auto defaultConfigsString = - state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS"); + this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_CONFIGS"); if (defaultConfigsString.empty()) { defaultConfigsString = this->DefaultFileConfig; } @@ -2737,6 +2853,11 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( return true; } +std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const +{ + return ""; +} + std::string cmGlobalNinjaMultiGenerator::OrderDependsTargetForTarget( cmGeneratorTarget const* target, const std::string& config) const { diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index b668773..fd8542f 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -24,6 +24,7 @@ #include "cmNinjaTypes.h" #include "cmPolicies.h" #include "cmStringAlgorithms.h" +#include "cmTransformDepfile.h" class cmCustomCommand; class cmGeneratorTarget; @@ -31,7 +32,6 @@ class cmLinkLineComputer; class cmLocalGenerator; class cmMakefile; class cmOutputConverter; -class cmState; class cmStateDirectory; class cmake; struct cmDocumentationEntry; @@ -150,7 +150,7 @@ public: static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets, const std::string& comment = ""); - bool IsGCCOnWindows() const { return UsingGCCOnWindows; } + bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; } public: cmGlobalNinjaGenerator(cmake* cm); @@ -211,6 +211,10 @@ public: const char* GetCleanTargetName() const override { return "clean"; } bool SupportsCustomCommandDepfile() const override { return true; } + cm::optional<cmDepfileFormat> DepfileFormat() const override + { + return cmDepfileFormat::GccDepfile; + } virtual cmGeneratedFileStream* GetImplFileStream( const std::string& /*config*/) const @@ -248,7 +252,7 @@ public: : GG(gg) { } - std::string operator()(std::string const& path) + std::string operator()(std::string const& path) const { return this->GG->ConvertToNinjaPath(path); } @@ -319,17 +323,21 @@ public: void AppendTargetOutputs(cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config, - cmNinjaTargetDepends depends); + cmNinjaTargetDepends depends) const; void AppendTargetDepends(cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config, const std::string& fileConfig, cmNinjaTargetDepends depends); void AppendTargetDependsClosure(cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config); + const std::string& config, + const std::string& fileConfig, + bool genexOutput); void AppendTargetDependsClosure(cmGeneratorTarget const* target, cmNinjaOuts& outputs, - const std::string& config, bool omit_self); + const std::string& config, + const std::string& fileConfig, + bool genexOutput, bool omit_self); void AppendDirectoryForConfig(const std::string& prefix, const std::string& config, @@ -346,7 +354,10 @@ public: outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE)); } - int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; } + int GetRuleCmdLength(const std::string& name) + { + return this->RuleCmdLength[name]; + } void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target, const std::string& config); @@ -385,15 +396,13 @@ public: bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } void StripNinjaOutputPathPrefixAsSuffix(std::string& path); - bool WriteDyndepFile(std::string const& dir_top_src, - std::string const& dir_top_bld, - std::string const& dir_cur_src, - std::string const& dir_cur_bld, - std::string const& arg_dd, - std::vector<std::string> const& arg_ddis, - std::string const& module_dir, - std::vector<std::string> const& linked_target_dirs, - std::string const& arg_lang); + bool WriteDyndepFile( + std::string const& dir_top_src, std::string const& dir_top_bld, + std::string const& dir_cur_src, std::string const& dir_cur_bld, + std::string const& arg_dd, std::vector<std::string> const& arg_ddis, + std::string const& module_dir, + std::vector<std::string> const& linked_target_dirs, + std::string const& arg_lang, std::string const& arg_modmapfmt); virtual std::string BuildAlias(const std::string& alias, const std::string& /*config*/) const @@ -425,6 +434,20 @@ public: return this->DefaultConfigs; } + const std::set<std::string>& GetPerConfigUtilityTargets() const + { + return this->PerConfigUtilityTargets; + } + + void AddPerConfigUtilityTarget(const std::string& name) + { + this->PerConfigUtilityTargets.insert(name); + } + + bool IsSingleConfigUtility(cmGeneratorTarget const* target) const; + + bool CheckCxxModuleSupport(); + protected: void Generate() override; @@ -462,7 +485,7 @@ private: void CleanMetaData(); /// Write the common disclaimer text at the top of each build file. - void WriteDisclaimer(std::ostream& os); + void WriteDisclaimer(std::ostream& os) const; void WriteAssumedSourceDependencies(); @@ -518,6 +541,9 @@ private: /// The mapping from source file to assumed dependencies. std::map<std::string, std::set<std::string>> AssumedSourceDependencies; + /// Utility targets which have per-config outputs + std::set<std::string> PerConfigUtilityTargets; + struct TargetAlias { cmGeneratorTarget* GeneratorTarget; @@ -542,6 +568,8 @@ private: bool NinjaSupportsMultipleOutputs = false; bool NinjaSupportsMetadataOnRegeneration = false; + bool DiagnosedCxxModuleSupport = false; + private: void InitOutputPathPrefix(); @@ -557,7 +585,14 @@ private: /// The set of custom commands we have seen. std::set<cmCustomCommand const*> CustomCommands; - std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures; + struct TargetDependsClosureKey + { + cmGeneratorTarget const* Target; + std::string Config; + bool GenexOutput; + }; + + std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures; TargetAliasMap TargetAliases; @@ -566,6 +601,19 @@ private: std::map<std::string, ByConfig> Configs; cmNinjaDeps ByproductsForCleanTarget; + + friend bool operator==(const ByConfig::TargetDependsClosureKey& lhs, + const ByConfig::TargetDependsClosureKey& rhs); + friend bool operator!=(const ByConfig::TargetDependsClosureKey& lhs, + const ByConfig::TargetDependsClosureKey& rhs); + friend bool operator<(const ByConfig::TargetDependsClosureKey& lhs, + const ByConfig::TargetDependsClosureKey& rhs); + friend bool operator>(const ByConfig::TargetDependsClosureKey& lhs, + const ByConfig::TargetDependsClosureKey& rhs); + friend bool operator<=(const ByConfig::TargetDependsClosureKey& lhs, + const ByConfig::TargetDependsClosureKey& rhs); + friend bool operator>=(const ByConfig::TargetDependsClosureKey& lhs, + const ByConfig::TargetDependsClosureKey& rhs); }; class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator @@ -651,8 +699,6 @@ public: std::string GetDefaultBuildConfig() const override; - bool ReadCacheEntriesForBuild(const cmState& state) override; - bool SupportsDefaultBuildType() const override { return true; } bool SupportsCrossConfigs() const override { return true; } bool SupportsDefaultConfigs() const override { return true; } diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 2c934e1..97384cd 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -44,6 +44,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm) #endif this->IncludeDirective = "include"; + this->LineContinueDirective = "\\\n"; this->DefineWindowsNULL = false; this->PassMakeflags = false; this->UnixCD = true; @@ -589,10 +590,16 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( } makeCommand.Add(this->SelectMakeProgram(makeProgram)); + // Explicitly tell the make tool to use the Makefile written by + // cmLocalUnixMakefileGenerator3::WriteLocalMakefile + makeCommand.Add("-f"); + makeCommand.Add("Makefile"); + if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) { - makeCommand.Add("-j"); - if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) { - makeCommand.Add(std::to_string(jobs)); + if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) { + makeCommand.Add("-j"); + } else { + makeCommand.Add("-j" + std::to_string(jobs)); } } @@ -831,7 +838,7 @@ void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks() for (const auto& gt : lg->GetGeneratorTargets()) { cmLocalGenerator* tlg = gt->GetLocalGenerator(); - if (!gt->IsInBuildSystem() || IsExcluded(lg.get(), gt.get())) { + if (!gt->IsInBuildSystem() || this->IsExcluded(lg.get(), gt.get())) { continue; } diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 77d0827..c15f491 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -93,6 +93,12 @@ public: */ static bool SupportsPlatform() { return false; } + /** + * Utilized to determine if this generator + * supports DEPFILE option. + */ + bool SupportsCustomCommandDepfile() const override { return true; } + /** Get the documentation entry for this generator. */ static void GetDocumentation(cmDocumentationEntry& entry); @@ -127,6 +133,18 @@ public: void WriteConvenienceRules(std::ostream& ruleFileStream, std::set<std::string>& emitted); + // Make tool supports dependency files generated by compiler + bool SupportsCompilerDependencies() + { + return this->ToolSupportsCompilerDependencies; + } + + // Make tool supports long line dependencies + bool SupportsLongLineDependencies() + { + return this->ToolSupportsLongLineDependencies; + } + /** Get the command to use for a target that has no rule. This is used for multiple output dependencies and for cmake_force. */ std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; } @@ -170,6 +188,7 @@ public: void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; std::string IncludeDirective; + std::string LineContinueDirective; bool DefineWindowsNULL; bool PassMakeflags; bool UnixCD; @@ -218,6 +237,14 @@ protected: bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; } + // Specify if the make tool is able to consume dependency files + // generated by the compiler + bool ToolSupportsCompilerDependencies = true; + + // some Make generator, such as Borland not support long line dependencies, + // we add SupportsLongLineDependencies to predicate. + bool ToolSupportsLongLineDependencies = true; + // Some make programs (Borland) do not keep a rule if there are no // dependencies or commands. This is a problem for creating rules // that might not do anything but might have other dependencies diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 6267205..75cd714 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -380,9 +380,10 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( std::string project = target->GetName(); std::string location = *expath; - cmProp p = target->GetProperty("VS_PROJECT_TYPE"); - this->WriteExternalProject(fout, project, location, cmToCStr(p), - target->GetUtilities()); + this->WriteExternalProject( + fout, project, location, + cmToCStr(target->GetProperty("VS_PROJECT_TYPE")), + target->GetUtilities()); written = true; } else { cmProp vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index d6a7afa..3e2d92d 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -25,6 +25,7 @@ cmGlobalWatcomWMakeGenerator::cmGlobalWatcomWMakeGenerator(cmake* cm) #endif cm->GetState()->SetWatcomWMake(true); this->IncludeDirective = "!include"; + this->LineContinueDirective = "&\n"; this->DefineWindowsNULL = true; this->UnixCD = false; this->MakeSilentFlag = "-h"; @@ -37,7 +38,6 @@ void cmGlobalWatcomWMakeGenerator::EnableLanguage( mf->AddDefinition("WATCOM", "1"); mf->AddDefinition("CMAKE_QUOTE_INCLUDE_PATHS", "1"); mf->AddDefinition("CMAKE_MANGLE_OBJECT_FILE_NAMES", "1"); - mf->AddDefinition("CMAKE_MAKE_LINE_CONTINUE", "&"); mf->AddDefinition("CMAKE_MAKE_SYMBOLIC_RULE", ".SYMBOLIC"); mf->AddDefinition("CMAKE_GENERATOR_CC", "wcl386"); mf->AddDefinition("CMAKE_GENERATOR_CXX", "wcl386"); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index df45b35..8a1ccd1 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -504,16 +504,15 @@ cmGlobalXCodeGenerator::GenerateBuildCommand( } } - if (this->XcodeBuildSystem >= BuildSystem::Twelve) { + if ((this->XcodeBuildSystem >= BuildSystem::Twelve) || + (jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) { makeCommand.Add("-parallelizeTargets"); } makeCommand.Add("-configuration", (config.empty() ? "Debug" : config)); - if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) { - makeCommand.Add("-jobs"); - if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) { - makeCommand.Add(std::to_string(jobs)); - } + if ((jobs != cmake::NO_BUILD_PARALLEL_LEVEL) && + (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL)) { + makeCommand.Add("-jobs", std::to_string(jobs)); } if (this->XcodeVersion >= 70) { @@ -775,7 +774,9 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects() this->TargetGroup.clear(); this->FileRefs.clear(); this->ExternalLibRefs.clear(); + this->EmbeddedLibRefs.clear(); this->FileRefToBuildFileMap.clear(); + this->FileRefToEmbedBuildFileMap.clear(); this->CommandsVisited.clear(); } @@ -941,6 +942,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( default: break; } + + // Explicitly add the explicit language flag before any other flag + // so user flags can override it. + gtgt->AddExplicitLanguageFlags(flags, *sf); + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) { lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); @@ -1202,7 +1208,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( } } // Make a copy so that we can override it later - std::string path = fullpath; + std::string path = cmSystemTools::CollapseFullPath(fullpath); // Compute the extension without leading '.'. std::string ext = cmSystemTools::GetFilenameLastExtension(path); if (!ext.empty()) { @@ -1382,7 +1388,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( // organize the sources std::vector<cmSourceFile*> commonSourceFiles; - if (!gtgt->GetConfigCommonSourceFiles(commonSourceFiles)) { + if (!gtgt->GetConfigCommonSourceFilesForXcode(commonSourceFiles)) { return false; } @@ -1647,6 +1653,14 @@ void cmGlobalXCodeGenerator::ForceLinkerLanguage(cmGeneratorTarget* gtgt) } } + // Allow empty source file list for iOS Sticker packs + if (const char* productType = GetTargetProductType(gtgt)) { + if (strcmp(productType, + "com.apple.product-type.app-extension.messages-sticker-pack") == + 0) + return; + } + // Add an empty source file to the target that compiles with the // linker language. This should convince Xcode to choose the proper // language. @@ -1738,7 +1752,7 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( gtgt, postbuild); } else { std::vector<cmSourceFile*> classes; - if (!gtgt->GetConfigCommonSourceFiles(classes)) { + if (!gtgt->GetConfigCommonSourceFilesForXcode(classes)) { return; } // add all the sources @@ -1798,6 +1812,10 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( if (frameworkBuildPhase) { buildPhases->AddObject(frameworkBuildPhase); } + + // When this build phase is present, it must be last. More build phases may + // be added later for embedding things and they will insert themselves just + // before this last build phase. if (postBuildPhase) { buildPhases->AddObject(postBuildPhase); } @@ -1807,7 +1825,7 @@ void cmGlobalXCodeGenerator::CreateRunScriptBuildPhases( cmXCodeObject* buildPhases, cmGeneratorTarget const* gt) { std::vector<cmSourceFile*> sources; - if (!gt->GetConfigCommonSourceFiles(sources)) { + if (!gt->GetConfigCommonSourceFilesForXcode(sources)) { return; } auto& visited = this->CommandsVisited[gt]; @@ -2953,7 +2971,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget( if (gtgt->GetType() != cmStateEnums::GLOBAL_TARGET && gtgt->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { std::vector<cmSourceFile*> sources; - if (!gtgt->GetConfigCommonSourceFiles(sources)) { + if (!gtgt->GetConfigCommonSourceFilesForXcode(sources)) { return nullptr; } @@ -3228,36 +3246,43 @@ void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings, if (!attr) { settings->AddAttribute(attribute, value); } else { - if (value->GetType() != cmXCodeObject::OBJECT_LIST && - value->GetType() != cmXCodeObject::STRING) { - cmSystemTools::Error("Unsupported value type for appending: " + - std::string(attribute)); - return; - } - if (attr->GetType() == cmXCodeObject::OBJECT_LIST) { - if (value->GetType() == cmXCodeObject::OBJECT_LIST) { - for (auto* obj : value->GetObjectList()) { - attr->AddObject(obj); - } - } else { - attr->AddObject(value); - } - } else if (attr->GetType() == cmXCodeObject::STRING) { - if (value->GetType() == cmXCodeObject::OBJECT_LIST) { - // Add old value as a list item to new object list - // and replace the attribute with the new list - value->PrependObject(attr); - settings->AddAttribute(attribute, value); - } else { - std::string newValue = - cmStrCat(attr->GetString(), ' ', value->GetString()); - attr->SetString(newValue); - } - } else { - cmSystemTools::Error("Unsupported attribute type for appending: " + - std::string(attribute)); + this->AppendBuildSettingAttribute(settings, attribute, attr, value); + } + } +} + +void cmGlobalXCodeGenerator::AppendBuildSettingAttribute( + cmXCodeObject* settings, const char* attribute, cmXCodeObject* attr, + cmXCodeObject* value) +{ + if (value->GetType() != cmXCodeObject::OBJECT_LIST && + value->GetType() != cmXCodeObject::STRING) { + cmSystemTools::Error("Unsupported value type for appending: " + + std::string(attribute)); + return; + } + if (attr->GetType() == cmXCodeObject::OBJECT_LIST) { + if (value->GetType() == cmXCodeObject::OBJECT_LIST) { + for (auto* obj : value->GetObjectList()) { + attr->AddObject(obj); } + } else { + attr->AddObject(value); + } + } else if (attr->GetType() == cmXCodeObject::STRING) { + if (value->GetType() == cmXCodeObject::OBJECT_LIST) { + // Add old value as a list item to new object list + // and replace the attribute with the new list + value->PrependObject(attr); + settings->AddAttribute(attribute, value); + } else { + std::string newValue = + cmStrCat(attr->GetString(), ' ', value->GetString()); + attr->SetString(newValue); } + } else { + cmSystemTools::Error("Unsupported attribute type for appending: " + + std::string(attribute)); } } @@ -3280,6 +3305,24 @@ void cmGlobalXCodeGenerator::AppendBuildSettingAttribute( } } +void cmGlobalXCodeGenerator::InheritBuildSettingAttribute( + cmXCodeObject* target, const char* attribute) +{ + cmXCodeObject* configurationList = + target->GetAttribute("buildConfigurationList")->GetObject(); + cmXCodeObject* buildConfigs = + configurationList->GetAttribute("buildConfigurations"); + for (auto obj : buildConfigs->GetObjectList()) { + cmXCodeObject* settings = obj->GetAttribute("buildSettings"); + if (cmXCodeObject* attr = settings->GetAttribute(attribute)) { + BuildObjectListOrString inherited(this, true); + inherited.Add("$(inherited)"); + this->AppendBuildSettingAttribute(settings, attribute, attr, + inherited.CreateList()); + } + } +} + void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) { cmGeneratorTarget* gt = target->GetTarget(); @@ -3596,11 +3639,11 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) for (auto& libDir : linkSearchPaths) { libSearchPaths.Add(this->XCodeEscapePath(libDir)); } - // Add paths defined in project-wide build settings - libSearchPaths.Add("$(inherited)"); - this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS", - libSearchPaths.CreateList(), - configName); + if (!libSearchPaths.IsEmpty()) { + this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS", + libSearchPaths.CreateList(), + configName); + } } // add framework search paths @@ -3611,11 +3654,11 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) for (auto& fwDir : frameworkSearchPaths) { fwSearchPaths.Add(this->XCodeEscapePath(fwDir)); } - // Add paths defined in project-wide build settings - fwSearchPaths.Add("$(inherited)"); - this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS", - fwSearchPaths.CreateList(), - configName); + if (!fwSearchPaths.IsEmpty()) { + this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS", + fwSearchPaths.CreateList(), + configName); + } } // now add the left-over link libraries @@ -3666,6 +3709,130 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } } +void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target) +{ + cmGeneratorTarget* gt = target->GetTarget(); + if (!gt) { + cmSystemTools::Error("Error no target on xobject\n"); + return; + } + if (!gt->IsInBuildSystem()) { + return; + } + bool isFrameworkTarget = gt->IsFrameworkOnApple(); + bool isBundleTarget = gt->GetPropertyAsBool("MACOSX_BUNDLE"); + bool isCFBundleTarget = gt->IsCFBundleOnApple(); + if (!(isFrameworkTarget || isBundleTarget || isCFBundleTarget)) { + return; + } + cmProp files = gt->GetProperty("XCODE_EMBED_FRAMEWORKS"); + if (!files) { + return; + } + + // Create an "Embedded Frameworks" build phase + auto* copyFilesBuildPhase = + this->CreateObject(cmXCodeObject::PBXCopyFilesBuildPhase); + std::string copyFilesBuildPhaseName = "Embed Frameworks"; + std::string destinationFrameworks = "10"; + copyFilesBuildPhase->SetComment(copyFilesBuildPhaseName); + copyFilesBuildPhase->AddAttribute("buildActionMask", + this->CreateString("2147483647")); + copyFilesBuildPhase->AddAttribute("dstSubfolderSpec", + this->CreateString(destinationFrameworks)); + copyFilesBuildPhase->AddAttribute( + "name", this->CreateString(copyFilesBuildPhaseName)); + if (cmProp fwEmbedPath = gt->GetProperty("XCODE_EMBED_FRAMEWORKS_PATH")) { + copyFilesBuildPhase->AddAttribute("dstPath", + this->CreateString(*fwEmbedPath)); + } else { + copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString("")); + } + copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", + this->CreateString("0")); + cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); + // Collect all embedded frameworks and add them to build phase + std::vector<std::string> relFiles = cmExpandedList(*files); + for (std::string const& relFile : relFiles) { + cmXCodeObject* buildFile{ nullptr }; + std::string filePath = relFile; + auto* genTarget = FindGeneratorTarget(relFile); + if (genTarget) { + // This is a target - get it's product path reference + auto* xcTarget = FindXCodeTarget(genTarget); + if (!xcTarget) { + cmSystemTools::Error("Can not find a target for " + + genTarget->GetName()); + continue; + } + // Add the target output file as a build reference for other targets + // to link against + auto* fileRefObject = xcTarget->GetAttribute("productReference"); + if (!fileRefObject) { + cmSystemTools::Error("Target " + genTarget->GetName() + + " is missing product reference"); + continue; + } + auto it = FileRefToEmbedBuildFileMap.find(fileRefObject); + if (it == FileRefToEmbedBuildFileMap.end()) { + buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); + buildFile->AddAttribute("fileRef", fileRefObject); + FileRefToEmbedBuildFileMap[fileRefObject] = buildFile; + } else { + buildFile = it->second; + } + } else if (cmSystemTools::IsPathToFramework(relFile)) { + // This is a regular string path - create file reference + auto it = EmbeddedLibRefs.find(relFile); + if (it == EmbeddedLibRefs.end()) { + cmXCodeObject* fileRef = + this->CreateXCodeFileReferenceFromPath(relFile, gt, "", nullptr); + if (fileRef) { + buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); + buildFile->SetComment(fileRef->GetComment()); + buildFile->AddAttribute("fileRef", + this->CreateObjectReference(fileRef)); + } + if (!buildFile) { + cmSystemTools::Error("Can't create build file for " + relFile); + continue; + } + this->EmbeddedLibRefs.emplace(filePath, buildFile); + } else { + buildFile = it->second; + } + } + if (!buildFile) { + cmSystemTools::Error("Can't find a build file for " + relFile); + continue; + } + // Set build file configuration + cmXCodeObject* settings = + this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); + cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST); + const auto& rmHeadersProp = + gt->GetSafeProperty("XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY"); + if (cmIsOn(rmHeadersProp)) { + attrs->AddObject(this->CreateString("RemoveHeadersOnCopy")); + } + const auto& codeSignProp = + gt->GetSafeProperty("XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY"); + if (cmIsOn(codeSignProp)) { + attrs->AddObject(this->CreateString("CodeSignOnCopy")); + } + settings->AddAttributeIfNotEmpty("ATTRIBUTES", attrs); + buildFile->AddAttributeIfNotEmpty("settings", settings); + if (!buildFiles->HasObject(buildFile)) { + buildFiles->AddObject(buildFile); + } + } + copyFilesBuildPhase->AddAttribute("files", buildFiles); + auto* buildPhases = target->GetAttribute("buildPhases"); + // Insert embed build phase right before the post-build command + buildPhases->InsertObject(buildPhases->GetObjectCount() - 1, + copyFilesBuildPhase); +} + bool cmGlobalXCodeGenerator::CreateGroups( std::vector<cmLocalGenerator*>& generators) { @@ -4044,7 +4211,16 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( // loop over all targets and add link and depend info for (auto t : targets) { this->AddDependAndLinkInformation(t); + this->AddEmbeddedFrameworks(t); + // Inherit project-wide values for any target-specific search paths. + this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS"); + this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS"); + this->InheritBuildSettingAttribute(t, "FRAMEWORK_SEARCH_PATHS"); + this->InheritBuildSettingAttribute(t, "SYSTEM_FRAMEWORK_SEARCH_PATHS"); + this->InheritBuildSettingAttribute(t, "LIBRARY_SEARCH_PATHS"); + this->InheritBuildSettingAttribute(t, "LD_RUNPATH_SEARCH_PATHS"); } + if (this->XcodeBuildSystem == BuildSystem::One) { this->CreateXCodeDependHackMakefile(targets); } diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 8ff6846..1ab56e2 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -186,11 +186,17 @@ private: cmGeneratorTarget* gtgt); void AppendOrAddBuildSetting(cmXCodeObject* settings, const char* attr, cmXCodeObject* value); + void AppendBuildSettingAttribute(cmXCodeObject* settings, + const char* attribute, cmXCodeObject* attr, + cmXCodeObject* value); void AppendBuildSettingAttribute(cmXCodeObject* target, const char* attr, cmXCodeObject* value, const std::string& configName); + void InheritBuildSettingAttribute(cmXCodeObject* target, + const char* attribute); cmXCodeObject* CreateUtilityTarget(cmGeneratorTarget* gtgt); void AddDependAndLinkInformation(cmXCodeObject* target); + void AddEmbeddedFrameworks(cmXCodeObject* target); void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target, cmXCodeObject* buildSettings, const std::string& configName); @@ -329,8 +335,10 @@ private: std::map<std::string, cmXCodeObject*> TargetGroup; std::map<std::string, cmXCodeObject*> FileRefs; std::map<std::string, cmXCodeObject*> ExternalLibRefs; + std::map<std::string, cmXCodeObject*> EmbeddedLibRefs; std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap; std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap; + std::map<cmXCodeObject*, cmXCodeObject*> FileRefToEmbedBuildFileMap; std::vector<std::string> Architectures; std::string ObjectDirArchDefault; std::string ObjectDirArch; diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index cf4ba93..92ffe29 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -131,8 +131,8 @@ cmGraphVizWriter::~cmGraphVizWriter() void cmGraphVizWriter::VisitGraph(std::string const&) { - this->WriteHeader(GlobalFileStream, this->GraphName); - this->WriteLegend(GlobalFileStream); + this->WriteHeader(this->GlobalFileStream, this->GraphName); + this->WriteLegend(this->GlobalFileStream); } void cmGraphVizWriter::OnItem(cmLinkItem const& item) @@ -141,8 +141,9 @@ void cmGraphVizWriter::OnItem(cmLinkItem const& item) return; } - NodeNames[item.AsStr()] = cmStrCat(GraphNodePrefix, NextNodeId); - ++NextNodeId; + this->NodeNames[item.AsStr()] = + cmStrCat(this->GraphNodePrefix, this->NextNodeId); + ++this->NextNodeId; this->WriteNode(this->GlobalFileStream, item); } @@ -191,12 +192,13 @@ void cmGraphVizWriter::VisitLink(cmLinkItem const& depender, this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType); if (this->GeneratePerTarget) { - PerTargetConnections[depender].emplace_back(depender, dependee, scopeType); + this->PerTargetConnections[depender].emplace_back(depender, dependee, + scopeType); } if (this->GenerateDependers) { - TargetDependersConnections[dependee].emplace_back(dependee, depender, - scopeType); + this->TargetDependersConnections[dependee].emplace_back(dependee, depender, + scopeType); } } @@ -307,12 +309,12 @@ void cmGraphVizWriter::Write() } if (this->GeneratePerTarget) { - WritePerTargetConnections<DependeesDir>(PerTargetConnections); + this->WritePerTargetConnections<DependeesDir>(this->PerTargetConnections); } if (this->GenerateDependers) { - WritePerTargetConnections<DependersDir>(TargetDependersConnections, - ".dependers"); + this->WritePerTargetConnections<DependersDir>( + this->TargetDependersConnections, ".dependers"); } } @@ -336,7 +338,8 @@ void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, bool const visited = visitedItems.find(dstItem) != visitedItems.cend(); if (!visited) { visitedItems.insert(dstItem); - FindAllConnections(connectionMap, dstItem, extendedCons, visitedItems); + this->FindAllConnections(connectionMap, dstItem, extendedCons, + visitedItems); } } } @@ -346,7 +349,8 @@ void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap, Connections& extendedCons) { std::set<cmLinkItem> visitedItems = { rootItem }; - FindAllConnections(connectionMap, rootItem, extendedCons, visitedItems); + this->FindAllConnections(connectionMap, rootItem, extendedCons, + visitedItems); } template <typename DirFunc> @@ -358,7 +362,7 @@ void cmGraphVizWriter::WritePerTargetConnections( for (auto const& conPerTarget : connections) { const cmLinkItem& rootItem = conPerTarget.first; Connections& extendedCons = extendedConnections[conPerTarget.first]; - FindAllConnections(connections, rootItem, extendedCons); + this->FindAllConnections(connections, rootItem, extendedCons); } for (auto const& conPerTarget : extendedConnections) { @@ -451,7 +455,7 @@ void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs, auto const& itemName = item.AsStr(); auto const& nodeName = this->NodeNames[itemName]; - auto const itemNameWithAliases = ItemNameWithAliases(itemName); + auto const itemNameWithAliases = this->ItemNameWithAliases(itemName); auto const escapedLabel = EscapeForDotFile(itemNameWithAliases); fs << " \"" << nodeName << "\" [ label = \"" << escapedLabel diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index ae801bb..ce1f030 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -21,6 +21,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args, static std::map<std::string, cmPolicies::PolicyID> DeprecatedModules; if (DeprecatedModules.empty()) { DeprecatedModules["Documentation"] = cmPolicies::CMP0106; + DeprecatedModules["WriteCompilerDetectionHeader"] = cmPolicies::CMP0120; } if (args.empty() || args.size() > 4) { @@ -146,11 +147,24 @@ bool cmIncludeCommand(std::vector<std::string> const& args, std::string listFile = cmSystemTools::CollapseFullPath( fname, status.GetMakefile().GetCurrentSourceDirectory()); - if (optional && !cmSystemTools::FileExists(listFile)) { + + const bool fileDoesnotExist = !cmSystemTools::FileExists(listFile); + const bool fileIsDirectory = cmSystemTools::FileIsDirectory(listFile); + if (fileDoesnotExist || fileIsDirectory) { if (!resultVarName.empty()) { status.GetMakefile().AddDefinition(resultVarName, "NOTFOUND"); } - return true; + if (optional) { + return true; + } + if (fileDoesnotExist) { + status.SetError(cmStrCat("could not find requested file:\n ", fname)); + return false; + } + if (fileIsDirectory) { + status.SetError(cmStrCat("requested file is a directory:\n ", fname)); + return false; + } } bool readit = @@ -163,9 +177,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args, } if (!optional && !readit && !cmSystemTools::GetFatalErrorOccured()) { - std::string m = cmStrCat("could not find load file:\n" - " ", - fname); + std::string m = cmStrCat("could not load requested file:\n ", fname); status.SetError(m); return false; } diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index 175e7cf..0b45f28 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -27,7 +27,7 @@ cmInstallDirectoryGenerator::cmInstallDirectoryGenerator( , Optional(optional) { // We need per-config actions if destination have generator expressions. - if (cmGeneratorExpression::Find(Destination) != std::string::npos) { + if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) { this->ActionsPerConfig = true; } diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 6e3508c..3683ada 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -122,10 +122,10 @@ size_t cmInstallExportGenerator::GetMaxConfigLength() const void cmInstallExportGenerator::GenerateScript(std::ostream& os) { // Skip empty sets. - if (ExportSet->GetTargetExports().empty()) { + if (this->ExportSet->GetTargetExports().empty()) { std::ostringstream e; - e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName() - << "\""; + e << "INSTALL(EXPORT) given unknown export \"" + << this->ExportSet->GetName() << "\""; cmSystemTools::Error(e.str()); return; } diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index ad2f84e..c45000d 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -26,7 +26,7 @@ cmInstallFilesGenerator::cmInstallFilesGenerator( , Optional(optional) { // We need per-config actions if the destination has generator expressions. - if (cmGeneratorExpression::Find(Destination) != std::string::npos) { + if (cmGeneratorExpression::Find(this->Destination) != std::string::npos) { this->ActionsPerConfig = true; } diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx index 7cdf3b4..ce2472d 100644 --- a/Source/cmInstallScriptGenerator.cxx +++ b/Source/cmInstallScriptGenerator.cxx @@ -22,7 +22,7 @@ cmInstallScriptGenerator::cmInstallScriptGenerator( , AllowGenex(false) { // We need per-config actions if the script has generator expressions. - if (cmGeneratorExpression::Find(Script) != std::string::npos) { + if (cmGeneratorExpression::Find(this->Script) != std::string::npos) { this->ActionsPerConfig = true; } } diff --git a/Source/cmJsonObjectDictionary.h b/Source/cmJsonObjectDictionary.h deleted file mode 100644 index 8a2b529..0000000 --- a/Source/cmJsonObjectDictionary.h +++ /dev/null @@ -1,45 +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 <string> - -// Vocabulary: - -static const std::string kARTIFACTS_KEY = "artifacts"; -static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; -static const std::string kCOMPILE_FLAGS_KEY = "compileFlags"; -static const std::string kCONFIGURATIONS_KEY = "configurations"; -static const std::string kDEFINES_KEY = "defines"; -static const std::string kFILE_GROUPS_KEY = "fileGroups"; -static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath"; -static const std::string kFULL_NAME_KEY = "fullName"; -static const std::string kINCLUDE_PATH_KEY = "includePath"; -static const std::string kIS_CMAKE_KEY = "isCMake"; -static const std::string kIS_GENERATED_KEY = "isGenerated"; -static const std::string kIS_SYSTEM_KEY = "isSystem"; -static const std::string kIS_TEMPORARY_KEY = "isTemporary"; -static const std::string kKEY_KEY = "key"; -static const std::string kLANGUAGE_KEY = "language"; -static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; -static const std::string kLINK_FLAGS_KEY = "linkFlags"; -static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags"; -static const std::string kLINK_LIBRARIES_KEY = "linkLibraries"; -static const std::string kLINK_PATH_KEY = "linkPath"; -static const std::string kNAME_KEY = "name"; -static const std::string kPATH_KEY = "path"; -static const std::string kPROJECTS_KEY = "projects"; -static const std::string kPROPERTIES_KEY = "properties"; -static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; -static const std::string kSOURCES_KEY = "sources"; -static const std::string kSYSROOT_KEY = "sysroot"; -static const std::string kTARGETS_KEY = "targets"; -static const std::string kTYPE_KEY = "type"; -static const std::string kVALUE_KEY = "value"; -static const std::string kHAS_INSTALL_RULE = "hasInstallRule"; -static const std::string kINSTALL_PATHS = "installPaths"; -static const std::string kCTEST_NAME = "ctestName"; -static const std::string kCTEST_COMMAND = "ctestCommand"; -static const std::string kCTEST_INFO = "ctestInfo"; -static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; -static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx deleted file mode 100644 index 3a7ae0c..0000000 --- a/Source/cmJsonObjects.cxx +++ /dev/null @@ -1,692 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmJsonObjects.h" // IWYU pragma: keep - -#include <algorithm> -#include <cassert> -#include <cstddef> -#include <functional> -#include <limits> -#include <map> -#include <memory> -#include <set> -#include <string> -#include <unordered_map> -#include <utility> -#include <vector> - -#include <cmext/algorithm> - -#include "cmGeneratorExpression.h" -#include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" -#include "cmInstallGenerator.h" -#include "cmInstallSubdirectoryGenerator.h" -#include "cmInstallTargetGenerator.h" -#include "cmJsonObjectDictionary.h" -#include "cmJsonObjects.h" -#include "cmLinkLineComputer.h" -#include "cmLocalGenerator.h" -#include "cmMakefile.h" -#include "cmProperty.h" -#include "cmPropertyMap.h" -#include "cmSourceFile.h" -#include "cmState.h" -#include "cmStateDirectory.h" -#include "cmStateSnapshot.h" -#include "cmStateTypes.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" -#include "cmTarget.h" -#include "cmTest.h" -#include "cmake.h" - -namespace { - -std::vector<std::string> getConfigurations(const cmake* cm) -{ - std::vector<std::string> configurations; - const auto& makefiles = cm->GetGlobalGenerator()->GetMakefiles(); - if (makefiles.empty()) { - return configurations; - } - - return makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); -} - -bool hasString(const Json::Value& v, const std::string& s) -{ - return !v.isNull() && - std::any_of(v.begin(), v.end(), - [s](const Json::Value& i) { return i.asString() == s; }); -} - -template <class T> -Json::Value fromStringList(const T& in) -{ - Json::Value result = Json::arrayValue; - for (std::string const& i : in) { - result.append(i); - } - return result; -} - -} // namespace - -void cmGetCMakeInputs(const cmGlobalGenerator* gg, - const std::string& sourceDir, - const std::string& buildDir, - std::vector<std::string>* internalFiles, - std::vector<std::string>* explicitFiles, - std::vector<std::string>* tmpFiles) -{ - const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/'; - auto const& makefiles = gg->GetMakefiles(); - for (const auto& mf : makefiles) { - for (std::string const& lf : mf->GetListFiles()) { - - const std::string startOfFile = lf.substr(0, cmakeRootDir.size()); - const bool isInternal = (startOfFile == cmakeRootDir); - const bool isTemporary = - !isInternal && (cmHasPrefix(lf, buildDir + '/')); - - std::string toAdd = lf; - if (!sourceDir.empty()) { - const std::string& relative = - cmSystemTools::RelativePath(sourceDir, lf); - if (toAdd.size() > relative.size()) { - toAdd = relative; - } - } - - if (isInternal) { - if (internalFiles) { - internalFiles->push_back(std::move(toAdd)); - } - } else { - if (isTemporary) { - if (tmpFiles) { - tmpFiles->push_back(std::move(toAdd)); - } - } else { - if (explicitFiles) { - explicitFiles->push_back(std::move(toAdd)); - } - } - } - } - } -} - -Json::Value cmDumpCMakeInputs(const cmake* cm) -{ - const cmGlobalGenerator* gg = cm->GetGlobalGenerator(); - const std::string& buildDir = cm->GetHomeOutputDirectory(); - const std::string& sourceDir = cm->GetHomeDirectory(); - - std::vector<std::string> internalFiles; - std::vector<std::string> explicitFiles; - std::vector<std::string> tmpFiles; - cmGetCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles, - &tmpFiles); - - Json::Value array = Json::arrayValue; - - Json::Value tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = true; - tmp[kIS_TEMPORARY_KEY] = false; - tmp[kSOURCES_KEY] = fromStringList(internalFiles); - array.append(tmp); - - tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = false; - tmp[kIS_TEMPORARY_KEY] = false; - tmp[kSOURCES_KEY] = fromStringList(explicitFiles); - array.append(tmp); - - tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = false; - tmp[kIS_TEMPORARY_KEY] = true; - tmp[kSOURCES_KEY] = fromStringList(tmpFiles); - array.append(tmp); - - return array; -} - -class LanguageData -{ -public: - bool operator==(const LanguageData& other) const; - - void SetDefines(const std::set<std::string>& defines); - - bool IsGenerated = false; - std::string Language; - std::string Flags; - std::vector<std::string> Defines; - std::vector<std::pair<std::string, bool>> IncludePathList; -}; - -bool LanguageData::operator==(const LanguageData& other) const -{ - return Language == other.Language && Defines == other.Defines && - Flags == other.Flags && IncludePathList == other.IncludePathList && - IsGenerated == other.IsGenerated; -} - -void LanguageData::SetDefines(const std::set<std::string>& defines) -{ - std::vector<std::string> result; - result.reserve(defines.size()); - for (std::string const& i : defines) { - result.push_back(i); - } - std::sort(result.begin(), result.end()); - Defines = std::move(result); -} - -namespace std { - -template <> -struct hash<LanguageData> -{ - std::size_t operator()(const LanguageData& in) const - { - using std::hash; - size_t result = - hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags); - for (auto const& i : in.IncludePathList) { - result = result ^ - (hash<std::string>()(i.first) ^ - (i.second ? std::numeric_limits<size_t>::max() : 0)); - } - for (auto const& i : in.Defines) { - result = result ^ hash<std::string>()(i); - } - result = - result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0); - return result; - } -}; - -} // namespace std - -static Json::Value DumpSourceFileGroup(const LanguageData& data, - const std::vector<std::string>& files, - const std::string& baseDir) -{ - Json::Value result = Json::objectValue; - - if (!data.Language.empty()) { - result[kLANGUAGE_KEY] = data.Language; - if (!data.Flags.empty()) { - result[kCOMPILE_FLAGS_KEY] = data.Flags; - } - if (!data.IncludePathList.empty()) { - Json::Value includes = Json::arrayValue; - for (auto const& i : data.IncludePathList) { - Json::Value tmp = Json::objectValue; - tmp[kPATH_KEY] = i.first; - if (i.second) { - tmp[kIS_SYSTEM_KEY] = i.second; - } - includes.append(tmp); - } - result[kINCLUDE_PATH_KEY] = includes; - } - if (!data.Defines.empty()) { - result[kDEFINES_KEY] = fromStringList(data.Defines); - } - } - - result[kIS_GENERATED_KEY] = data.IsGenerated; - - Json::Value sourcesValue = Json::arrayValue; - for (auto const& i : files) { - const std::string relPath = cmSystemTools::RelativePath(baseDir, i); - sourcesValue.append(relPath.size() < i.size() ? relPath : i); - } - - result[kSOURCES_KEY] = sourcesValue; - return result; -} - -static Json::Value DumpSourceFilesList( - cmGeneratorTarget* target, const std::string& config, - const std::map<std::string, LanguageData>& languageDataMap) -{ - // Collect sourcefile groups: - - std::vector<cmSourceFile*> files; - target->GetSourceFiles(files, config); - - std::unordered_map<LanguageData, std::vector<std::string>> fileGroups; - for (cmSourceFile* file : files) { - LanguageData fileData; - fileData.Language = file->GetOrDetermineLanguage(); - if (!fileData.Language.empty()) { - const LanguageData& ld = languageDataMap.at(fileData.Language); - cmLocalGenerator* lg = target->GetLocalGenerator(); - cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target, - fileData.Language); - - std::string compileFlags = ld.Flags; - const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (cmProp cflags = file->GetProperty(COMPILE_FLAGS)) { - lg->AppendFlags(compileFlags, - genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); - } - const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (cmProp coptions = file->GetProperty(COMPILE_OPTIONS)) { - lg->AppendCompileOptions( - compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); - } - fileData.Flags = compileFlags; - - // Add include directories from source file properties. - std::vector<std::string> includes; - - const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (cmProp cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { - const std::string& evaluatedIncludes = - genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES); - lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file); - - for (const auto& include : includes) { - fileData.IncludePathList.emplace_back( - include, - target->IsSystemIncludeDirectory(include, config, - fileData.Language)); - } - } - - fileData.IncludePathList.insert(fileData.IncludePathList.end(), - ld.IncludePathList.begin(), - ld.IncludePathList.end()); - - const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - std::set<std::string> defines; - if (cmProp defs = file->GetProperty(COMPILE_DEFINITIONS)) { - lg->AppendDefines( - defines, genexInterpreter.Evaluate(*defs, COMPILE_DEFINITIONS)); - } - - const std::string defPropName = - "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - if (cmProp config_defs = file->GetProperty(defPropName)) { - lg->AppendDefines( - defines, - genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS)); - } - - defines.insert(ld.Defines.begin(), ld.Defines.end()); - - fileData.SetDefines(defines); - } - - fileData.IsGenerated = file->GetIsGenerated(); - std::vector<std::string>& groupFileList = fileGroups[fileData]; - groupFileList.push_back(file->ResolveFullPath()); - } - - const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory(); - Json::Value result = Json::arrayValue; - for (auto const& it : fileGroups) { - Json::Value group = DumpSourceFileGroup(it.first, it.second, baseDir); - if (!group.isNull()) { - result.append(group); - } - } - - return result; -} - -static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kCTEST_NAME] = testInfo->GetName(); - - // Concat command entries together. After the first should be the arguments - // for the command - std::string command; - for (auto const& cmd : testInfo->GetCommand()) { - command.append(cmd); - command.append(" "); - } - - // Remove any config specific variables from the output. - result[kCTEST_COMMAND] = - cmGeneratorExpression::Evaluate(command, lg, config); - - // Build up the list of properties that may have been specified - Json::Value properties = Json::arrayValue; - for (auto& prop : testInfo->GetProperties().GetList()) { - Json::Value entry = Json::objectValue; - entry[kKEY_KEY] = prop.first; - - // Remove config variables from the value too. - entry[kVALUE_KEY] = - cmGeneratorExpression::Evaluate(prop.second, lg, config); - properties.append(entry); - } - result[kPROPERTIES_KEY] = properties; - - return result; -} - -static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config, - Json::Value* result) -{ - auto mf = lg->GetMakefile(); - std::vector<cmTest*> tests; - mf->GetTests(config, tests); - for (auto test : tests) { - Json::Value tmp = DumpCTestInfo(lg, test, config); - if (!tmp.isNull()) { - result->append(tmp); - } - } -} - -static Json::Value DumpCTestProjectList(const cmake* cm, - std::string const& config) -{ - Json::Value result = Json::arrayValue; - - auto globalGen = cm->GetGlobalGenerator(); - - for (const auto& projectIt : globalGen->GetProjectMap()) { - Json::Value pObj = Json::objectValue; - pObj[kNAME_KEY] = projectIt.first; - - Json::Value tests = Json::arrayValue; - - // Gather tests for every generator - for (const auto& lg : projectIt.second) { - // Make sure they're generated. - lg->GenerateTestFiles(); - DumpMakefileTests(lg, config, &tests); - } - - pObj[kCTEST_INFO] = tests; - - result.append(pObj); - } - - return result; -} - -static Json::Value DumpCTestConfiguration(const cmake* cm, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kNAME_KEY] = config; - - result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config); - - return result; -} - -static Json::Value DumpCTestConfigurationsList(const cmake* cm) -{ - Json::Value result = Json::arrayValue; - - for (const std::string& c : getConfigurations(cm)) { - result.append(DumpCTestConfiguration(cm, c)); - } - - return result; -} - -Json::Value cmDumpCTestInfo(const cmake* cm) -{ - Json::Value result = Json::objectValue; - result[kCONFIGURATIONS_KEY] = DumpCTestConfigurationsList(cm); - return result; -} - -static Json::Value DumpTarget(cmGeneratorTarget* target, - const std::string& config) -{ - cmLocalGenerator* lg = target->GetLocalGenerator(); - - const cmStateEnums::TargetType type = target->GetType(); - const std::string typeName = cmState::GetTargetTypeName(type); - - Json::Value ttl = Json::arrayValue; - ttl.append("EXECUTABLE"); - ttl.append("STATIC_LIBRARY"); - ttl.append("SHARED_LIBRARY"); - ttl.append("MODULE_LIBRARY"); - ttl.append("OBJECT_LIBRARY"); - ttl.append("UTILITY"); - ttl.append("INTERFACE_LIBRARY"); - - if (!hasString(ttl, typeName) || target->IsImported()) { - return Json::Value(); - } - - Json::Value result = Json::objectValue; - result[kNAME_KEY] = target->GetName(); - result[kIS_GENERATOR_PROVIDED_KEY] = - target->Target->GetIsGeneratorProvided(); - result[kTYPE_KEY] = typeName; - result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory(); - result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory(); - - if (type == cmStateEnums::INTERFACE_LIBRARY) { - return result; - } - - result[kFULL_NAME_KEY] = target->GetFullName(config); - - if (target->Target->GetHaveInstallRule()) { - result[kHAS_INSTALL_RULE] = true; - - Json::Value installPaths = Json::arrayValue; - for (const auto& installGenerator : - target->Makefile->GetInstallGenerators()) { - auto installTargetGenerator = - dynamic_cast<cmInstallTargetGenerator*>(installGenerator.get()); - if (installTargetGenerator != nullptr && - installTargetGenerator->GetTarget()->Target == target->Target) { - auto dest = installTargetGenerator->GetDestination(config); - - std::string installPath; - if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) { - installPath = dest; - } else { - installPath = cmStrCat( - target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"), '/', - dest); - } - - installPaths.append(installPath); - } - } - - result[kINSTALL_PATHS] = installPaths; - } - - if (target->HaveWellDefinedOutputFiles()) { - Json::Value artifacts = Json::arrayValue; - artifacts.append( - target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact)); - if (target->HasImportLibrary(config)) { - artifacts.append( - target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); - } - if (target->IsDLLPlatform()) { - const cmGeneratorTarget::OutputInfo* output = - target->GetOutputInfo(config); - if (output && !output->PdbDir.empty()) { - artifacts.append(output->PdbDir + '/' + target->GetPDBName(config)); - } - } - result[kARTIFACTS_KEY] = artifacts; - - result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config); - - std::string linkLibs; - std::string linkFlags; - std::string linkLanguageFlags; - std::string frameworkPath; - std::string linkPath; - cmLinkLineComputer linkLineComputer(lg, - lg->GetStateSnapshot().GetDirectory()); - lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags, - linkFlags, frameworkPath, linkPath, target); - - linkLibs = cmTrimWhitespace(linkLibs); - linkFlags = cmTrimWhitespace(linkFlags); - linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags); - frameworkPath = cmTrimWhitespace(frameworkPath); - linkPath = cmTrimWhitespace(linkPath); - - if (!cmTrimWhitespace(linkLibs).empty()) { - result[kLINK_LIBRARIES_KEY] = linkLibs; - } - if (!cmTrimWhitespace(linkFlags).empty()) { - result[kLINK_FLAGS_KEY] = linkFlags; - } - if (!cmTrimWhitespace(linkLanguageFlags).empty()) { - result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags; - } - if (!frameworkPath.empty()) { - result[kFRAMEWORK_PATH_KEY] = frameworkPath; - } - if (!linkPath.empty()) { - result[kLINK_PATH_KEY] = linkPath; - } - const std::string sysroot = - lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT"); - if (!sysroot.empty()) { - result[kSYSROOT_KEY] = sysroot; - } - } - - std::set<std::string> languages; - target->GetLanguages(languages, config); - std::map<std::string, LanguageData> languageDataMap; - - for (std::string const& lang : languages) { - LanguageData& ld = languageDataMap[lang]; - ld.Language = lang; - lg->GetTargetCompileFlags(target, config, lang, ld.Flags); - std::set<std::string> defines; - lg->GetTargetDefines(target, config, lang, defines); - ld.SetDefines(defines); - std::vector<std::string> includePathList; - lg->GetIncludeDirectories(includePathList, target, lang, config); - for (std::string const& i : includePathList) { - ld.IncludePathList.emplace_back( - i, target->IsSystemIncludeDirectory(i, config, lang)); - } - } - - Json::Value sourceGroupsValue = - DumpSourceFilesList(target, config, languageDataMap); - if (!sourceGroupsValue.empty()) { - result[kFILE_GROUPS_KEY] = sourceGroupsValue; - } - - return result; -} - -static Json::Value DumpTargetsList( - const std::vector<cmLocalGenerator*>& generators, const std::string& config) -{ - Json::Value result = Json::arrayValue; - - std::vector<cmGeneratorTarget*> targetList; - for (auto const& lgIt : generators) { - cm::append(targetList, lgIt->GetGeneratorTargets()); - } - std::sort(targetList.begin(), targetList.end()); - - for (cmGeneratorTarget* target : targetList) { - Json::Value tmp = DumpTarget(target, config); - if (!tmp.isNull()) { - result.append(tmp); - } - } - - return result; -} - -static Json::Value DumpProjectList(const cmake* cm, std::string const& config) -{ - Json::Value result = Json::arrayValue; - - auto globalGen = cm->GetGlobalGenerator(); - - for (auto const& projectIt : globalGen->GetProjectMap()) { - Json::Value pObj = Json::objectValue; - pObj[kNAME_KEY] = projectIt.first; - - // All Projects must have at least one local generator - assert(!projectIt.second.empty()); - const cmLocalGenerator* lg = projectIt.second.at(0); - - // Project structure information: - const cmMakefile* mf = lg->GetMakefile(); - auto minVersion = mf->GetSafeDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); - pObj[kMINIMUM_CMAKE_VERSION] = minVersion; - pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory(); - pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory(); - pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config); - - // For a project-level install rule it might be defined in any of its - // associated generators. - bool hasInstallRule = false; - for (const auto generator : projectIt.second) { - for (const auto& installGen : - generator->GetMakefile()->GetInstallGenerators()) { - if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen.get())) { - hasInstallRule = true; - break; - } - } - - if (hasInstallRule) { - break; - } - } - - pObj[kHAS_INSTALL_RULE] = hasInstallRule; - - result.append(pObj); - } - - return result; -} - -static Json::Value DumpConfiguration(const cmake* cm, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kNAME_KEY] = config; - - result[kPROJECTS_KEY] = DumpProjectList(cm, config); - - return result; -} - -static Json::Value DumpConfigurationsList(const cmake* cm) -{ - Json::Value result = Json::arrayValue; - - for (std::string const& c : getConfigurations(cm)) { - result.append(DumpConfiguration(cm, c)); - } - - return result; -} - -Json::Value cmDumpCodeModel(const cmake* cm) -{ - Json::Value result = Json::objectValue; - result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(cm); - return result; -} diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h deleted file mode 100644 index 80a4834..0000000 --- a/Source/cmJsonObjects.h +++ /dev/null @@ -1,24 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <string> -#include <vector> - -#include <cm3p/json/value.h> - -class cmake; -class cmGlobalGenerator; - -extern void cmGetCMakeInputs(const cmGlobalGenerator* gg, - const std::string& sourceDir, - const std::string& buildDir, - std::vector<std::string>* internalFiles, - std::vector<std::string>* explicitFiles, - std::vector<std::string>* tmpFiles); - -extern Json::Value cmDumpCodeModel(const cmake* cm); -extern Json::Value cmDumpCTestInfo(const cmake* cm); -extern Json::Value cmDumpCMakeInputs(const cmake* cm); diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h index d70176d..616bf7e 100644 --- a/Source/cmLinkedTree.h +++ b/Source/cmLinkedTree.h @@ -133,9 +133,9 @@ public: return iterator(const_cast<cmLinkedTree*>(this), 0); } - iterator Push(iterator it) { return Push_impl(it, T()); } + iterator Push(iterator it) { return this->Push_impl(it, T()); } - iterator Push(iterator it, T t) { return Push_impl(it, std::move(t)); } + iterator Push(iterator it, T t) { return this->Push_impl(it, std::move(t)); } bool IsLast(iterator it) { return it.Position == this->Data.size(); } diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index a2c14bd..53c871b 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -609,9 +609,9 @@ public: bool Validate(std::size_t count) override { - decltype(Indexes) indexes; + decltype(this->Indexes) indexes; - for (auto index : Indexes) { + for (auto index : this->Indexes) { indexes.push_back(this->NormalizeIndex(index, count)); } this->Indexes = std::move(indexes); @@ -750,7 +750,7 @@ bool HandleTransformCommand(std::vector<std::string> const& args, { } - operator const std::string&() const { return Name; } + operator const std::string&() const { return this->Name; } std::string Name; int Arity = 0; @@ -1093,8 +1093,9 @@ protected: public: cmStringSorter(Compare compare, CaseSensitivity caseSensitivity, Order desc = Order::ASCENDING) - : filters{ GetCompareFilter(compare), GetCaseFilter(caseSensitivity) } - , sortMethod(GetComparisonFunction(compare)) + : filters{ this->GetCompareFilter(compare), + this->GetCaseFilter(caseSensitivity) } + , sortMethod(this->GetComparisonFunction(compare)) , descending(desc == Order::DESCENDING) { } @@ -1102,7 +1103,7 @@ public: std::string ApplyFilter(const std::string& argument) { std::string result = argument; - for (auto filter : filters) { + for (auto filter : this->filters) { if (filter != nullptr) { result = filter(result); } @@ -1112,13 +1113,13 @@ public: bool operator()(const std::string& a, const std::string& b) { - std::string af = ApplyFilter(a); - std::string bf = ApplyFilter(b); + std::string af = this->ApplyFilter(a); + std::string bf = this->ApplyFilter(b); bool result; - if (descending) { - result = sortMethod(bf, af); + if (this->descending) { + result = this->sortMethod(bf, af); } else { - result = sortMethod(af, bf); + result = this->sortMethod(af, bf); } return result; } @@ -1424,7 +1425,7 @@ public: bool operator()(const std::string& target) { - return regex.find(target) ^ includeMatches; + return this->regex.find(target) ^ this->includeMatches; } private: diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 70ef5af..36a1372 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -30,6 +30,7 @@ struct cmListFileParser bool ParseFunction(const char* name, long line); bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); + cm::optional<cmListFileContext> CheckNesting(); cmListFile* ListFile; cmListFileBacktrace Backtrace; cmMessenger* Messenger; @@ -104,7 +105,7 @@ bool cmListFileParser::ParseFile(const char* filename) return false; } - return Parse(); + return this->Parse(); } bool cmListFileParser::ParseString(const char* str, @@ -117,7 +118,7 @@ bool cmListFileParser::ParseString(const char* str, return false; } - return Parse(); + return this->Parse(); } bool cmListFileParser::Parse() @@ -158,6 +159,17 @@ bool cmListFileParser::Parse() return false; } } + + // Check if all functions are nested properly. + if (auto badNesting = this->CheckNesting()) { + this->Messenger->IssueMessage( + MessageType::FATAL_ERROR, + "Flow control statements are not properly nested.", + this->Backtrace.Push(*badNesting)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + return true; } @@ -317,6 +329,112 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, return true; } +namespace { +enum class NestingStateEnum +{ + If, + Else, + While, + Foreach, + Function, + Macro, +}; + +struct NestingState +{ + NestingStateEnum State; + cmListFileContext Context; +}; + +bool TopIs(std::vector<NestingState>& stack, NestingStateEnum state) +{ + return !stack.empty() && stack.back().State == state; +} +} + +cm::optional<cmListFileContext> cmListFileParser::CheckNesting() +{ + std::vector<NestingState> stack; + + for (auto const& func : this->ListFile->Functions) { + auto const& name = func.LowerCaseName(); + if (name == "if") { + stack.push_back({ + NestingStateEnum::If, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "elseif") { + if (!TopIs(stack, NestingStateEnum::If)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.back() = { + NestingStateEnum::If, + cmListFileContext::FromCommandContext(func, this->FileName), + }; + } else if (name == "else") { + if (!TopIs(stack, NestingStateEnum::If)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.back() = { + NestingStateEnum::Else, + cmListFileContext::FromCommandContext(func, this->FileName), + }; + } else if (name == "endif") { + if (!TopIs(stack, NestingStateEnum::If) && + !TopIs(stack, NestingStateEnum::Else)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "while") { + stack.push_back({ + NestingStateEnum::While, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endwhile") { + if (!TopIs(stack, NestingStateEnum::While)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "foreach") { + stack.push_back({ + NestingStateEnum::Foreach, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endforeach") { + if (!TopIs(stack, NestingStateEnum::Foreach)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "function") { + stack.push_back({ + NestingStateEnum::Function, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endfunction") { + if (!TopIs(stack, NestingStateEnum::Function)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "macro") { + stack.push_back({ + NestingStateEnum::Macro, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endmacro") { + if (!TopIs(stack, NestingStateEnum::Macro)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } + } + + if (!stack.empty()) { + return stack.back().Context; + } + + return cm::nullopt; +} + // We hold either the bottom scope of a directory or a call/file context. // Discriminate these cases via the parent pointer. struct cmListFileBacktrace::Entry diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 727fc60..98cb4a7 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -89,6 +89,14 @@ public: { } +#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) + cmListFileContext(const cmListFileContext& /*other*/) = default; + cmListFileContext(cmListFileContext&& /*other*/) = default; + + cmListFileContext& operator=(const cmListFileContext& /*other*/) = default; + cmListFileContext& operator=(cmListFileContext&& /*other*/) = delete; +#endif + static cmListFileContext FromCommandContext( cmCommandContext const& lfcc, std::string const& fileName, cm::optional<std::string> deferId = {}) @@ -241,7 +249,7 @@ public: BTs(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) : Value(std::move(v)) { - Backtraces.emplace_back(std::move(bt)); + this->Backtraces.emplace_back(std::move(bt)); } T Value; std::vector<cmListFileBacktrace> Backtraces; diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 5790e16..adebe02 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -24,6 +24,7 @@ #include "cmCommand.h" #include "cmDynamicLoader.h" #include "cmExecutionStatus.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -36,8 +37,6 @@ # include <malloc.h> /* for malloc/free on QNX */ #endif -class cmListFileBacktrace; - namespace { const char* LastName = nullptr; @@ -256,10 +255,12 @@ bool cmLoadCommandCommand(std::vector<std::string> const& args, // if the symbol is found call it to set the name on the // function blocker if (initFunction) { - status.GetMakefile().GetState()->AddScriptedCommand( + return status.GetMakefile().GetState()->AddScriptedCommand( args[0], - cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction))); - return true; + BT<cmState::Command>( + cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction)), + status.GetMakefile().GetBacktrace()), + status.GetMakefile()); } status.SetError("Attempt to load command failed. " "No init function found."); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 2239192..86eddc2 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3,6 +3,7 @@ #include "cmLocalGenerator.h" #include <algorithm> +#include <array> #include <cassert> #include <cstdio> #include <cstdlib> @@ -16,9 +17,11 @@ #include <cm/memory> #include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" +#include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" @@ -279,7 +282,7 @@ static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs, }); } -void cmLocalGenerator::TraceDependencies() +void cmLocalGenerator::TraceDependencies() const { // Generate the rule files for each target. const auto& targets = this->GetGeneratorTargets(); @@ -823,16 +826,13 @@ cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const return this->Makefile->GetStateSnapshot(); } -const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, - const std::string& prop) +cmProp cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, + const std::string& prop) { - cmProp p; if (target) { - p = target->GetProperty(prop); - } else { - p = this->Makefile->GetProperty(prop); + return target->GetProperty(prop); } - return p ? p->c_str() : nullptr; + return this->Makefile->GetProperty(prop); } std::string cmLocalGenerator::ConvertToIncludeReference( @@ -1129,9 +1129,8 @@ cmTarget* cmLocalGenerator::AddUtilityCommand( detail::AddUtilityCommand( *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target, - this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends, - commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists, - job_pool, stdPipesUTF8); + workingDir, byproducts, depends, commandLines, escapeOldStyle, comment, + uses_terminal, command_expand_lists, job_pool, stdPipesUTF8); return target; } @@ -2498,8 +2497,10 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) target->GetSourceFiles(sources, config); const std::string configUpper = cmSystemTools::UpperCase(config); + static const std::array<std::string, 4> langs = { { "C", "CXX", "OBJC", + "OBJCXX" } }; - for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) { + for (const std::string& lang : langs) { auto langSources = std::count_if( sources.begin(), sources.end(), [lang](cmSourceFile* sf) { return lang == sf->GetLanguage() && @@ -2606,11 +2607,11 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) } if (editAndContinueDebugInfo || msvc2008OrLess) { - CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget, - { ".pdb", ".idb" }); + this->CopyPchCompilePdb(config, target, *ReuseFrom, + reuseTarget, { ".pdb", ".idb" }); } else if (enableDebuggingInformation) { - CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget, - { ".pdb" }); + this->CopyPchCompilePdb(config, target, *ReuseFrom, + reuseTarget, { ".pdb" }); } } @@ -2633,14 +2634,16 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) // Add pchHeader to source files, which will // be grouped as "Precompile Header File" auto pchHeader_sf = this->Makefile->GetOrCreateSource( - pchHeader, true, cmSourceFileLocationKind::Known); + pchHeader, false, cmSourceFileLocationKind::Known); std::string err; pchHeader_sf->ResolveFullPath(&err); - - // The pch file is generated, but mark it as not generated - // so that a clean operation will not remove it from disk - pchHeader_sf->SetProperty("GENERATED", "0"); - + if (!err.empty()) { + std::ostringstream msg; + msg << "Unable to resolve full path of PCH-header '" << pchHeader + << "' assigned to target " << target->GetName() + << ", although its path is supposed to be known!"; + this->IssueMessage(MessageType::FATAL_ERROR, msg.str()); + } target->AddSource(pchHeader); } } @@ -2769,8 +2772,15 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, inline void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file, std::string const& sf_full_path, cmProp beforeInclude, - cmProp afterInclude) + cmProp afterInclude, cmProp uniqueIdName) { + + if (uniqueIdName && !uniqueIdName->empty()) { + unity_file << "#undef " << *uniqueIdName << "\n" + << "#define " << *uniqueIdName << " unity_" + << cmSystemTools::ComputeStringMD5(sf_full_path) << "\n"; + } + if (beforeInclude) { unity_file << *beforeInclude << "\n"; } @@ -2791,6 +2801,8 @@ std::vector<std::string> AddUnityFilesModeAuto( batchSize = filtered_sources.size(); } + cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); + std::vector<std::string> unity_files; for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; itemsLeft > 0; itemsLeft -= chunk, ++batch) { @@ -2814,7 +2826,7 @@ std::vector<std::string> AddUnityFilesModeAuto( cmSourceFile* sf = filtered_sources[begin]; RegisterUnitySources(target, sf, filename); IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude); + afterInclude, uniqueIdName); } } cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); @@ -2845,6 +2857,8 @@ std::vector<std::string> AddUnityFilesModeGroup( } } + cmProp uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); + for (auto const& item : explicit_mapping) { auto const& name = item.first; std::string filename = cmStrCat(filename_base, "unity_", name, @@ -2860,7 +2874,7 @@ std::vector<std::string> AddUnityFilesModeGroup( for (cmSourceFile* sf : item.second) { RegisterUnitySources(target, sf, filename); IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude); + afterInclude, uniqueIdName); } } cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); @@ -3233,7 +3247,7 @@ std::string cmLocalGenerator::GetProjectName() const } std::string cmLocalGenerator::ConstructComment( - cmCustomCommandGenerator const& ccg, const char* default_comment) + cmCustomCommandGenerator const& ccg, const char* default_comment) const { // Check for a comment provided with the command. if (ccg.GetComment()) { @@ -3549,11 +3563,11 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( // we don't end up having: // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj cmProp unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE"); - cmProp psExtension = source.GetProperty("PCH_EXTENSION"); + cmProp pchExtension = source.GetProperty("PCH_EXTENSION"); const bool isPchObject = objectName.find("cmake_pch") != std::string::npos; - if (unitySourceFile || psExtension || isPchObject) { - if (psExtension) { - customOutputExtension = psExtension->c_str(); + if (unitySourceFile || pchExtension || isPchObject) { + if (pchExtension) { + customOutputExtension = pchExtension->c_str(); } cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)"); @@ -3791,7 +3805,7 @@ void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target, cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING"); cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION"); cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT"); - mf->ConfigureFile(inFile, fname, false, false, false, true); + mf->ConfigureFile(inFile, fname, false, false, false); } void cmLocalGenerator::GenerateFrameworkInfoPList( @@ -3826,42 +3840,99 @@ void cmLocalGenerator::GenerateFrameworkInfoPList( cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER"); cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING"); cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION"); - mf->ConfigureFile(inFile, fname, false, false, false, true); + mf->ConfigureFile(inFile, fname, false, false, false); } namespace { +cm::string_view CustomOutputRoleKeyword(cmLocalGenerator::OutputRole role) +{ + return (role == cmLocalGenerator::OutputRole::Primary ? "OUTPUT"_s + : "BYPRODUCTS"_s); +} + void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output, + cmLocalGenerator::OutputRole role, cmCommandOrigin origin, const cmListFileBacktrace& lfbt) { - if (cmGeneratorExpression::Find(output) == std::string::npos) { - // Outputs without generator expressions from the project are already - // created and marked as generated. Do not mark them again, because - // other commands might have overwritten the property. - if (origin == cmCommandOrigin::Generator) { - lg.GetMakefile()->GetOrCreateGeneratedSource(output); - } - } else { + if (cmGeneratorExpression::Find(output) != std::string::npos) { lg.GetCMakeInstance()->IssueMessage( MessageType::FATAL_ERROR, "Generator expressions in custom command outputs are not implemented!", lfbt); + return; + } + + // Make sure the file will not be generated into the source + // directory during an out of source build. + if (!lg.GetMakefile()->CanIWriteThisFile(output)) { + lg.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(CustomOutputRoleKeyword(role), " path\n ", output, + "\nin a source directory as an output of custom command."), + lfbt); + return; + } + + // Make sure the output file name has no invalid characters. + std::string::size_type pos = output.find_first_of("#<>"); + if (pos != std::string::npos) { + lg.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat(CustomOutputRoleKeyword(role), " containing a \"", output[pos], + "\" is not allowed."), + lfbt); + return; + } + + // Outputs without generator expressions from the project are already + // created and marked as generated. Do not mark them again, because + // other commands might have overwritten the property. + if (origin == cmCommandOrigin::Generator) { + lg.GetMakefile()->GetOrCreateGeneratedSource(output); } } -void CreateGeneratedSources(cmLocalGenerator& lg, - const std::vector<std::string>& outputs, - cmCommandOrigin origin, - const cmListFileBacktrace& lfbt) +std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg, + cmListFileBacktrace const& bt, + std::string const& output) { - for (std::string const& o : outputs) { - CreateGeneratedSource(lg, o, origin, lfbt); + // If the output path has no generator expressions, use it directly. + if (cmGeneratorExpression::Find(output) == std::string::npos) { + return output; + } + + // The output path contains a generator expression, but we must choose + // a single source file path to which to attach the custom command. + // Use some heuristics to provie a nice-looking name when possible. + + // If the only genex is $<CONFIG>, replace that gracefully. + { + std::string simple = output; + cmSystemTools::ReplaceString(simple, "$<CONFIG>", "(CONFIG)"); + if (cmGeneratorExpression::Find(simple) == std::string::npos) { + return simple; + } } + + // If the genex evaluates to the same value in all configurations, use that. + { + std::vector<std::string> allConfigOutputs = + lg.ExpandCustomCommandOutputGenex(output, bt); + if (allConfigOutputs.size() == 1) { + return allConfigOutputs.front(); + } + } + + // Fall back to a deterministic unique name. + cmCryptoHash h(cmCryptoHash::AlgoSHA256); + return cmStrCat(lg.GetCurrentBinaryDirectory(), "/CMakeFiles/", + h.HashString(output).substr(0, 16)); } cmSourceFile* AddCustomCommand( cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - const std::vector<std::string>& outputs, + cmCommandOrigin origin, const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const std::string& main_dependency, const cmImplicitDependsList& implicit_depends, @@ -3898,7 +3969,8 @@ cmSourceFile* AddCustomCommand( cmGlobalGenerator* gg = lg.GetGlobalGenerator(); // Construct a rule file associated with the first output produced. - std::string outName = gg->GenerateRuleFile(outputs[0]); + std::string outName = gg->GenerateRuleFile( + ComputeCustomCommandRuleFileName(lg, lfbt, outputs[0])); // Check if the rule file already exists. file = mf->GetSource(outName, cmSourceFileLocationKind::Known); @@ -3941,10 +4013,38 @@ cmSourceFile* AddCustomCommand( cc->SetJobPool(job_pool); file->SetCustomCommand(std::move(cc)); - mf->AddSourceOutputs(file, outputs, byproducts); + lg.AddSourceOutputs(file, outputs, cmLocalGenerator::OutputRole::Primary, + lfbt, origin); + lg.AddSourceOutputs(file, byproducts, + cmLocalGenerator::OutputRole::Byproduct, lfbt, origin); } return file; } + +bool AnyOutputMatches(const std::string& name, + const std::vector<std::string>& outputs) +{ + for (std::string const& output : outputs) { + std::string::size_type pos = output.rfind(name); + // If the output matches exactly + if (pos != std::string::npos && pos == output.size() - name.size() && + (pos == 0 || output[pos - 1] == '/')) { + return true; + } + } + return false; +} + +bool AnyTargetCommandOutputMatches( + const std::string& name, const std::vector<cmCustomCommand>& commands) +{ + for (cmCustomCommand const& command : commands) { + if (AnyOutputMatches(name, command.GetByproducts())) { + return true; + } + } + return false; +} } namespace detail { @@ -3960,11 +4060,6 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, const std::string& job_pool, bool command_expand_lists, bool stdPipesUTF8) { - cmMakefile* mf = lg.GetMakefile(); - - // Always create the byproduct sources and mark them generated. - CreateGeneratedSources(lg, byproducts, origin, lfbt); - // Add the command to the appropriate build step for the target. std::vector<std::string> no_output; cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt, @@ -3987,7 +4082,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, break; } - mf->AddTargetByproducts(target, byproducts); + lg.AddTargetByproducts(target, byproducts, lfbt, origin); } cmSourceFile* AddCustomCommandToOutput( @@ -4001,14 +4096,11 @@ cmSourceFile* AddCustomCommandToOutput( bool uses_terminal, bool command_expand_lists, const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8) { - // Always create the output sources and mark them generated. - CreateGeneratedSources(lg, outputs, origin, lfbt); - CreateGeneratedSources(lg, byproducts, origin, lfbt); - - return AddCustomCommand( - lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends, - commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal, - command_expand_lists, depfile, job_pool, stdPipesUTF8); + return AddCustomCommand(lg, lfbt, origin, outputs, byproducts, depends, + main_dependency, implicit_depends, commandLines, + comment, workingDir, replace, escapeOldStyle, + uses_terminal, command_expand_lists, depfile, + job_pool, stdPipesUTF8); } void AppendCustomCommandToOutput(cmLocalGenerator& lg, @@ -4019,7 +4111,22 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, const cmCustomCommandLines& commandLines) { // Lookup an existing command. - if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) { + cmSourceFile* sf = nullptr; + if (cmGeneratorExpression::Find(output) == std::string::npos) { + sf = lg.GetSourceFileWithOutput(output); + } else { + // This output path has a generator expression. Evaluate it to + // find the output for any configurations. + for (std::string const& out : + lg.ExpandCustomCommandOutputGenex(output, lfbt)) { + sf = lg.GetSourceFileWithOutput(out); + if (sf) { + break; + } + } + } + + if (sf) { if (cmCustomCommand* cc = sf->GetCustomCommand()) { cc->AppendCommands(commandLines); cc->AppendDepends(depends); @@ -4031,14 +4138,14 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, // No existing command found. lg.GetCMakeInstance()->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("Attempt to append to output\n ", output, + cmStrCat("Attempt to APPEND to custom command with output\n ", output, "\nwhich is not already a custom command output."), lfbt); } void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, cmCommandOrigin origin, cmTarget* target, - const cmUtilityOutput& force, const char* workingDir, + const char* workingDir, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, @@ -4046,29 +4153,27 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, bool uses_terminal, bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8) { - // Always create the byproduct sources and mark them generated. - CreateGeneratedSource(lg, force.Name, origin, lfbt); - CreateGeneratedSources(lg, byproducts, origin, lfbt); - // Use an empty comment to avoid generation of default comment. if (!comment) { comment = ""; } + // Create the generated symbolic output name of the utility target. + std::string output = + lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt); + std::string no_main_dependency; cmImplicitDependsList no_implicit_depends; cmSourceFile* rule = AddCustomCommand( - lg, lfbt, { force.Name }, byproducts, depends, no_main_dependency, + lg, lfbt, origin, { output }, byproducts, depends, no_main_dependency, no_implicit_depends, commandLines, comment, workingDir, /*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists, /*depfile=*/"", job_pool, stdPipesUTF8); if (rule) { - lg.GetMakefile()->AddTargetByproducts(target, byproducts); + lg.AddTargetByproducts(target, byproducts, lfbt, origin); } - if (!force.NameCMP0049.empty()) { - target->AddSource(force.NameCMP0049); - } + target->AddSource(output); } std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target) @@ -4119,3 +4224,247 @@ std::vector<std::string> ComputeISPCExtraObjects( return computedObjects; } } + +cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput( + const std::string& name) const +{ + // Linear search? Also see GetSourceFileWithOutput for detail. + if (!cmSystemTools::FileIsFullPath(name)) { + cmSourcesWithOutput sources; + sources.Target = this->LinearGetTargetWithOutput(name); + sources.Source = this->LinearGetSourceFileWithOutput( + name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct); + return sources; + } + // Otherwise we use an efficient lookup map. + auto o = this->OutputToSource.find(name); + if (o != this->OutputToSource.end()) { + return o->second.Sources; + } + return {}; +} + +cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput( + const std::string& name, cmSourceOutputKind kind) const +{ + // If the queried path is not absolute we use the backward compatible + // linear-time search for an output with a matching suffix. + if (!cmSystemTools::FileIsFullPath(name)) { + bool byproduct = false; + return this->LinearGetSourceFileWithOutput(name, kind, byproduct); + } + // Otherwise we use an efficient lookup map. + auto o = this->OutputToSource.find(name); + if (o != this->OutputToSource.end() && + (!o->second.Sources.SourceIsByproduct || + kind == cmSourceOutputKind::OutputOrByproduct)) { + // Source file could also be null pointer for example if we found the + // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD + // command of a target, or a not yet created custom command. + return o->second.Sources.Source; + } + return nullptr; +} + +std::string cmLocalGenerator::CreateUtilityOutput( + std::string const& targetName, std::vector<std::string> const&, + cmListFileBacktrace const&) +{ + std::string force = + cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", targetName); + // The output is not actually created so mark it symbolic. + if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) { + sf->SetProperty("SYMBOLIC", "1"); + } else { + cmSystemTools::Error("Could not get source file entry for " + force); + } + return force; +} + +std::vector<cmCustomCommandGenerator> +cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc, + std::string const& config) +{ + std::vector<cmCustomCommandGenerator> ccgs; + ccgs.emplace_back(cc, config, this); + return ccgs; +} + +std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths( + cmCompiledGeneratorExpression const& cge, std::string const& config) +{ + std::vector<std::string> paths = cmExpandedList(cge.Evaluate(this, config)); + for (std::string& p : paths) { + p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory()); + } + return paths; +} + +std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex( + std::string const& o, cmListFileBacktrace const& bt) +{ + std::vector<std::string> allConfigOutputs; + cmGeneratorExpression ge(bt); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o); + std::vector<std::string> configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (std::string const& config : configs) { + std::vector<std::string> configOutputs = + this->ExpandCustomCommandOutputPaths(*cge, config); + allConfigOutputs.reserve(allConfigOutputs.size() + configOutputs.size()); + std::move(configOutputs.begin(), configOutputs.end(), + std::back_inserter(allConfigOutputs)); + } + auto endUnique = + cmRemoveDuplicates(allConfigOutputs.begin(), allConfigOutputs.end()); + allConfigOutputs.erase(endUnique, allConfigOutputs.end()); + return allConfigOutputs; +} + +void cmLocalGenerator::AddTargetByproducts( + cmTarget* target, const std::vector<std::string>& byproducts, + cmListFileBacktrace const& bt, cmCommandOrigin origin) +{ + for (std::string const& o : byproducts) { + if (cmGeneratorExpression::Find(o) == std::string::npos) { + this->UpdateOutputToSourceMap(o, target, bt, origin); + continue; + } + + // This byproduct path has a generator expression. Evaluate it to + // register the byproducts for all configurations. + for (std::string const& b : this->ExpandCustomCommandOutputGenex(o, bt)) { + this->UpdateOutputToSourceMap(b, target, bt, cmCommandOrigin::Generator); + } + } +} + +void cmLocalGenerator::AddSourceOutputs( + cmSourceFile* source, const std::vector<std::string>& outputs, + OutputRole role, cmListFileBacktrace const& bt, cmCommandOrigin origin) +{ + for (std::string const& o : outputs) { + if (cmGeneratorExpression::Find(o) == std::string::npos) { + this->UpdateOutputToSourceMap(o, source, role, bt, origin); + continue; + } + + // This output path has a generator expression. Evaluate it to + // register the outputs for all configurations. + for (std::string const& out : + this->ExpandCustomCommandOutputGenex(o, bt)) { + this->UpdateOutputToSourceMap(out, source, role, bt, + cmCommandOrigin::Generator); + } + } +} + +void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct, + cmTarget* target, + cmListFileBacktrace const& bt, + cmCommandOrigin origin) +{ + SourceEntry entry; + entry.Sources.Target = target; + + auto pr = this->OutputToSource.emplace(byproduct, entry); + if (pr.second) { + CreateGeneratedSource(*this, byproduct, OutputRole::Byproduct, origin, bt); + } else { + SourceEntry& current = pr.first->second; + // Has the target already been set? + if (!current.Sources.Target) { + current.Sources.Target = target; + } else { + // Multiple custom commands/targets produce the same output (source file + // or target). See also comment in other UpdateOutputToSourceMap + // overload. + // + // TODO: Warn the user about this case. + } + } +} + +void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output, + cmSourceFile* source, + OutputRole role, + cmListFileBacktrace const& bt, + cmCommandOrigin origin) +{ + SourceEntry entry; + entry.Sources.Source = source; + entry.Sources.SourceIsByproduct = role == OutputRole::Byproduct; + + auto pr = this->OutputToSource.emplace(output, entry); + if (pr.second) { + CreateGeneratedSource(*this, output, role, origin, bt); + } else { + SourceEntry& current = pr.first->second; + // Outputs take precedence over byproducts + if (!current.Sources.Source || + (current.Sources.SourceIsByproduct && role == OutputRole::Primary)) { + current.Sources.Source = source; + current.Sources.SourceIsByproduct = false; + } else { + // Multiple custom commands produce the same output but may + // be attached to a different source file (MAIN_DEPENDENCY). + // LinearGetSourceFileWithOutput would return the first one, + // so keep the mapping for the first one. + // + // TODO: Warn the user about this case. However, the VS 8 generator + // triggers it for separate generate.stamp rules in ZERO_CHECK and + // individual targets. + } + } +} + +cmTarget* cmLocalGenerator::LinearGetTargetWithOutput( + const std::string& name) const +{ + // We go through the ordered vector of targets to get reproducible results + // should multiple names match. + for (cmTarget* t : this->Makefile->GetOrderedTargets()) { + // Does the output of any command match the source file name? + if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) { + return t; + } + if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) { + return t; + } + if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) { + return t; + } + } + return nullptr; +} + +cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput( + const std::string& name, cmSourceOutputKind kind, bool& byproduct) const +{ + // Outputs take precedence over byproducts. + byproduct = false; + cmSourceFile* fallback = nullptr; + + // Look through all the source files that have custom commands and see if the + // custom command has the passed source file as an output. + for (const auto& src : this->Makefile->GetSourceFiles()) { + // Does this source file have a custom command? + if (src->GetCustomCommand()) { + // Does the output of the custom command match the source file name? + if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) { + // Return the first matching output. + return src.get(); + } + if (kind == cmSourceOutputKind::OutputOrByproduct) { + if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) { + // Do not return the source yet as there might be a matching output. + fallback = src.get(); + } + } + } + } + + // Did we find a byproduct? + byproduct = fallback != nullptr; + return fallback; +} diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 22d3599..91dd8ae 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -22,7 +22,9 @@ #include "cmProperty.h" #include "cmStateSnapshot.h" +class cmCompiledGeneratorExpression; class cmComputeLinkInformation; +class cmCustomCommand; class cmCustomCommandGenerator; class cmCustomCommandLines; class cmGeneratorTarget; @@ -36,6 +38,31 @@ class cmState; class cmTarget; class cmake; +/** Flag if byproducts shall also be considered. */ +enum class cmSourceOutputKind +{ + OutputOnly, + OutputOrByproduct +}; + +/** What scanner to use for dependencies lookup. */ +enum class cmDependencyScannerKind +{ + CMake, + Compiler +}; + +/** Target and source file which have a specific output. */ +struct cmSourcesWithOutput +{ + /** Target with byproduct. */ + cmTarget* Target = nullptr; + + /** Source file with output or byproduct. */ + cmSourceFile* Source = nullptr; + bool SourceIsByproduct = false; +}; + /** \class cmLocalGenerator * \brief Create required build files for a directory. * @@ -59,7 +86,7 @@ public: /** * Calls TraceVSDependencies() on all targets of this generator. */ - void TraceDependencies(); + void TraceDependencies() const; virtual void AddHelperCommands() {} @@ -337,6 +364,55 @@ public: bool command_expand_lists = false, const std::string& job_pool = "", bool stdPipesUTF8 = false); + virtual std::string CreateUtilityOutput( + std::string const& targetName, std::vector<std::string> const& byproducts, + cmListFileBacktrace const& bt); + + virtual std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators( + cmCustomCommand const& cc, std::string const& config); + + std::vector<std::string> ExpandCustomCommandOutputPaths( + cmCompiledGeneratorExpression const& cge, std::string const& config); + std::vector<std::string> ExpandCustomCommandOutputGenex( + std::string const& o, cmListFileBacktrace const& bt); + + /** + * Add target byproducts. + */ + void AddTargetByproducts(cmTarget* target, + const std::vector<std::string>& byproducts, + cmListFileBacktrace const& bt, + cmCommandOrigin origin); + + enum class OutputRole + { + Primary, + Byproduct, + }; + + /** + * Add source file outputs. + */ + void AddSourceOutputs(cmSourceFile* source, + std::vector<std::string> const& outputs, + OutputRole role, cmListFileBacktrace const& bt, + cmCommandOrigin origin); + + /** + * Return the target if the provided source name is a byproduct of a utility + * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command. + * Return the source file which has the provided source name as output. + */ + cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const; + + /** + * Is there a source file that has the provided source name as an output? + * If so then return it. + */ + cmSourceFile* GetSourceFileWithOutput( + const std::string& name, + cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const; + std::string GetProjectName() const; /** Compute the language used to compile the given source file. */ @@ -405,7 +481,7 @@ public: const std::string& fname); /** Construct a comment for a custom command. */ std::string ConstructComment(cmCustomCommandGenerator const& ccg, - const char* default_comment = ""); + const char* default_comment = "") const; // Compute object file names. std::string GetObjectFileNameWithoutTarget( const cmSourceFile& source, std::string const& dir_max, @@ -473,8 +549,7 @@ public: void CreateEvaluationFileOutputs(const std::string& config); void ProcessEvaluationFiles(std::vector<std::string>& generatedFiles); - const char* GetRuleLauncher(cmGeneratorTarget* target, - const std::string& prop); + cmProp GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop); protected: //! put all the libraries for a target on into the given stream @@ -532,6 +607,36 @@ protected: bool BackwardsCompatibilityFinal; private: + /** + * See LinearGetSourceFileWithOutput for background information + */ + cmTarget* LinearGetTargetWithOutput(const std::string& name) const; + + /** + * Generalized old version of GetSourceFileWithOutput kept for + * backward-compatibility. It implements a linear search and supports + * relative file paths. It is used as a fall back by GetSourceFileWithOutput + * and GetSourcesWithOutput. + */ + cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name, + cmSourceOutputKind kind, + bool& byproduct) const; + struct SourceEntry + { + cmSourcesWithOutput Sources; + }; + + // A map for fast output to input look up. + using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>; + OutputToSourceMap OutputToSource; + + void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target, + cmListFileBacktrace const& bt, + cmCommandOrigin origin); + void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source, + OutputRole role, cmListFileBacktrace const& bt, + cmCommandOrigin origin); + void AddSharedFlags(std::string& flags, const std::string& lang, bool shared); bool GetShouldUseOldFlags(bool shared, const std::string& lang) const; @@ -587,7 +692,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, cmCommandOrigin origin, cmTarget* target, - const cmUtilityOutput& force, const char* workingDir, + const char* workingDir, const std::vector<std::string>& byproducts, const std::vector<std::string>& depends, const cmCustomCommandLines& commandLines, diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index ad782ee..5a747e5 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -10,6 +10,8 @@ #include <sstream> #include <utility> +#include <cmext/string_view> + #include "cmsys/FStream.hxx" #include "cmCryptoHash.h" @@ -22,7 +24,9 @@ #include "cmGlobalNinjaGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmNinjaTargetGenerator.h" +#include "cmPolicies.h" #include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -553,9 +557,13 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines( std::string launcher = this->MakeCustomLauncher(ccg); for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) { + std::string c = ccg.GetCommand(i); + if (c.empty()) { + continue; + } cmdLines.push_back(launcher + this->ConvertToOutputFormat( - ccg.GetCommand(i), + c, gg->IsMultiConfig() ? cmOutputConverter::NINJAMULTI : cmOutputConverter::SHELL)); @@ -565,71 +573,253 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines( } void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( - cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps, - const std::string& config) + cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets, + const std::string& fileConfig) { cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator(); - if (gg->SeenCustomCommand(cc, config)) { + if (gg->SeenCustomCommand(cc, fileConfig)) { return; } - cmCustomCommandGenerator ccg(*cc, config, this); + auto ccgs = this->MakeCustomCommandGenerators(*cc, fileConfig); + for (cmCustomCommandGenerator const& ccg : ccgs) { + cmNinjaDeps orderOnlyDeps; - const std::vector<std::string>& outputs = ccg.GetOutputs(); - const std::vector<std::string>& byproducts = ccg.GetByproducts(); - - bool symbolic = false; - for (std::string const& output : outputs) { - if (cmSourceFile* sf = this->Makefile->GetSource(output)) { - if (sf->GetPropertyAsBool("SYMBOLIC")) { - symbolic = true; - break; + // A custom command may appear on multiple targets. However, some build + // systems exist where the target dependencies on some of the targets are + // overspecified, leading to a dependency cycle. If we assume all target + // dependencies are a superset of the true target dependencies for this + // custom command, we can take the set intersection of all target + // dependencies to obtain a correct dependency list. + // + // FIXME: This won't work in certain obscure scenarios involving indirect + // dependencies. + auto j = targets.begin(); + assert(j != targets.end()); + this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure( + *j, orderOnlyDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1); + std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end()); + ++j; + + for (; j != targets.end(); ++j) { + std::vector<std::string> jDeps; + std::vector<std::string> depsIntersection; + this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure( + *j, jDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1); + std::sort(jDeps.begin(), jDeps.end()); + std::set_intersection(orderOnlyDeps.begin(), orderOnlyDeps.end(), + jDeps.begin(), jDeps.end(), + std::back_inserter(depsIntersection)); + orderOnlyDeps = depsIntersection; + } + + const std::vector<std::string>& outputs = ccg.GetOutputs(); + const std::vector<std::string>& byproducts = ccg.GetByproducts(); + + bool symbolic = false; + for (std::string const& output : outputs) { + if (cmSourceFile* sf = this->Makefile->GetSource(output)) { + if (sf->GetPropertyAsBool("SYMBOLIC")) { + symbolic = true; + break; + } + } + } + + cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()); + std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(), + gg->MapToNinjaPath()); + std::transform(byproducts.begin(), byproducts.end(), + ninjaOutputs.begin() + outputs.size(), + gg->MapToNinjaPath()); + + for (std::string const& ninjaOutput : ninjaOutputs) { + gg->SeenCustomCommandOutput(ninjaOutput); + } + + cmNinjaDeps ninjaDeps; + this->AppendCustomCommandDeps(ccg, ninjaDeps, fileConfig); + + std::vector<std::string> cmdLines; + this->AppendCustomCommandLines(ccg, cmdLines); + + if (cmdLines.empty()) { + cmNinjaBuild build("phony"); + build.Comment = "Phony custom command for " + ninjaOutputs[0]; + build.Outputs = std::move(ninjaOutputs); + build.ExplicitDeps = std::move(ninjaDeps); + build.OrderOnlyDeps = orderOnlyDeps; + gg->WriteBuild(this->GetImplFileStream(fileConfig), build); + } else { + std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]); + // Hash full path to make unique. + customStep += '-'; + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7); + + std::string depfile = cc->GetDepfile(); + if (!depfile.empty()) { + switch (this->GetPolicyStatus(cmPolicies::CMP0116)) { + case cmPolicies::WARN: + if (this->GetCurrentBinaryDirectory() != + this->GetBinaryDirectory() || + this->Makefile->PolicyOptionalWarningEnabled( + "CMAKE_POLICY_WARNING_CMP0116")) { + this->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0116), + cc->GetBacktrace()); + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + cmSystemTools::MakeDirectory( + cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d")); + depfile = ccg.GetInternalDepfile(); + break; + } } + + gg->WriteCustomCommandBuild( + this->BuildCommandLine(cmdLines, customStep), + this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], + depfile, cc->GetJobPool(), cc->GetUsesTerminal(), + /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, fileConfig, + ninjaDeps, orderOnlyDeps); } } +} -#if 0 -# error TODO: Once CC in an ExternalProject target must provide the \ - file of each imported target that has an add_dependencies pointing \ - at us. How to know which ExternalProject step actually provides it? -#endif - cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size()); - std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(), - gg->MapToNinjaPath()); - std::transform(byproducts.begin(), byproducts.end(), - ninjaOutputs.begin() + outputs.size(), gg->MapToNinjaPath()); +namespace { +bool HasUniqueByproducts(cmLocalGenerator& lg, + std::vector<std::string> const& byproducts, + cmListFileBacktrace const& bt) +{ + std::vector<std::string> configs = + lg.GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + cmGeneratorExpression ge(bt); + for (std::string const& p : byproducts) { + if (cmGeneratorExpression::Find(p) == std::string::npos) { + return false; + } + std::set<std::string> seen; + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p); + for (std::string const& config : configs) { + for (std::string const& b : + lg.ExpandCustomCommandOutputPaths(*cge, config)) { + if (!seen.insert(b).second) { + return false; + } + } + } + } + return true; +} - for (std::string const& ninjaOutput : ninjaOutputs) { - gg->SeenCustomCommandOutput(ninjaOutput); +bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs) +{ + std::set<std::string> allOutputs; + std::set<std::string> allByproducts; + for (cmCustomCommandGenerator const& ccg : ccgs) { + for (std::string const& output : ccg.GetOutputs()) { + if (!allOutputs.insert(output).second) { + return false; + } + } + for (std::string const& byproduct : ccg.GetByproducts()) { + if (!allByproducts.insert(byproduct).second) { + return false; + } + } + } + return true; +} +} + +std::string cmLocalNinjaGenerator::CreateUtilityOutput( + std::string const& targetName, std::vector<std::string> const& byproducts, + cmListFileBacktrace const& bt) +{ + // In Ninja Multi-Config, we can only produce cross-config utility + // commands if all byproducts are per-config. + if (!this->GetGlobalGenerator()->IsMultiConfig() || + !HasUniqueByproducts(*this, byproducts, bt)) { + return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts, + bt); + } + + std::string const base = cmStrCat(this->GetCurrentBinaryDirectory(), + "/CMakeFiles/", targetName, '-'); + // The output is not actually created so mark it symbolic. + for (std::string const& config : + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) { + std::string const force = cmStrCat(base, config); + if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) { + sf->SetProperty("SYMBOLIC", "1"); + } else { + cmSystemTools::Error("Could not get source file entry for " + force); + } } + this->GetGlobalNinjaGenerator()->AddPerConfigUtilityTarget(targetName); + return cmStrCat(base, "$<CONFIG>"_s); +} + +std::vector<cmCustomCommandGenerator> +cmLocalNinjaGenerator::MakeCustomCommandGenerators( + cmCustomCommand const& cc, std::string const& fileConfig) +{ + cmGlobalNinjaGenerator const* gg = this->GetGlobalNinjaGenerator(); - cmNinjaDeps ninjaDeps; - this->AppendCustomCommandDeps(ccg, ninjaDeps, config); + bool transformDepfile = false; + switch (this->GetPolicyStatus(cmPolicies::CMP0116)) { + case cmPolicies::OLD: + case cmPolicies::WARN: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + transformDepfile = true; + break; + } - std::vector<std::string> cmdLines; - this->AppendCustomCommandLines(ccg, cmdLines); + // Start with the build graph's configuration. + std::vector<cmCustomCommandGenerator> ccgs; + ccgs.emplace_back(cc, fileConfig, this, transformDepfile); - if (cmdLines.empty()) { - cmNinjaBuild build("phony"); - build.Comment = "Phony custom command for " + ninjaOutputs[0]; - build.Outputs = std::move(ninjaOutputs); - build.ExplicitDeps = std::move(ninjaDeps); - build.OrderOnlyDeps = orderOnlyDeps; - gg->WriteBuild(this->GetImplFileStream(config), build); - } else { - std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]); - // Hash full path to make unique. - customStep += '-'; - cmCryptoHash hash(cmCryptoHash::AlgoSHA256); - customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7); + // Consider adding cross configurations. + if (!gg->EnableCrossConfigBuild()) { + return ccgs; + } + + // Outputs and byproducts must be expressed using generator expressions. + for (std::string const& output : cc.GetOutputs()) { + if (cmGeneratorExpression::Find(output) == std::string::npos) { + return ccgs; + } + } + for (std::string const& byproduct : cc.GetByproducts()) { + if (cmGeneratorExpression::Find(byproduct) == std::string::npos) { + return ccgs; + } + } - gg->WriteCustomCommandBuild( - this->BuildCommandLine(cmdLines, customStep), - this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], - cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(), - /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config, - ninjaDeps, orderOnlyDeps); + // Tentatively add the other cross configurations. + for (std::string const& config : gg->GetCrossConfigs(fileConfig)) { + if (fileConfig != config) { + ccgs.emplace_back(cc, fileConfig, this, transformDepfile, config); + } + } + + // If outputs and byproducts are not unique to each configuration, + // drop the cross configurations. + if (!HasUniqueOutputs(ccgs)) { + ccgs.erase(ccgs.begin() + 1, ccgs.end()); } + + return ccgs; } void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc, @@ -645,42 +835,13 @@ void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc, } void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements( - const std::string& config) + const std::string& fileConfig) { for (cmCustomCommand const* customCommand : this->CustomCommands) { auto i = this->CustomCommandTargets.find(customCommand); assert(i != this->CustomCommandTargets.end()); - // A custom command may appear on multiple targets. However, some build - // systems exist where the target dependencies on some of the targets are - // overspecified, leading to a dependency cycle. If we assume all target - // dependencies are a superset of the true target dependencies for this - // custom command, we can take the set intersection of all target - // dependencies to obtain a correct dependency list. - // - // FIXME: This won't work in certain obscure scenarios involving indirect - // dependencies. - auto j = i->second.begin(); - assert(j != i->second.end()); - std::vector<std::string> ccTargetDeps; - this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure( - *j, ccTargetDeps, config); - std::sort(ccTargetDeps.begin(), ccTargetDeps.end()); - ++j; - - for (; j != i->second.end(); ++j) { - std::vector<std::string> jDeps; - std::vector<std::string> depsIntersection; - this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps, - config); - std::sort(jDeps.begin(), jDeps.end()); - std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(), - jDeps.begin(), jDeps.end(), - std::back_inserter(depsIntersection)); - ccTargetDeps = depsIntersection; - } - - this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps, config); + this->WriteCustomCommandBuildStatement(i->first, i->second, fileConfig); } } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index e81402c..87d5e53 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -10,6 +10,7 @@ #include <string> #include <vector> +#include "cmListFileCache.h" #include "cmLocalCommonGenerator.h" #include "cmNinjaTypes.h" #include "cmOutputConverter.h" @@ -70,6 +71,13 @@ public: const std::string& fileConfig, cmNinjaTargetDepends depends); + std::string CreateUtilityOutput(std::string const& targetName, + std::vector<std::string> const& byproducts, + cmListFileBacktrace const& bt) override; + + std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators( + cmCustomCommand const& cc, std::string const& config) override; + void AddCustomCommandTarget(cmCustomCommand const* cc, cmGeneratorTarget* target); void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg, @@ -99,9 +107,9 @@ private: void WriteProcessedMakefile(std::ostream& os); void WritePools(std::ostream& os); - void WriteCustomCommandBuildStatement(cmCustomCommand const* cc, - const cmNinjaDeps& orderOnlyDeps, - const std::string& config); + void WriteCustomCommandBuildStatement( + cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets, + const std::string& config); void WriteCustomCommandBuildStatements(const std::string& config); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index c877cf8..df7952c 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -5,18 +5,23 @@ #include <algorithm> #include <cassert> #include <cstdio> +#include <functional> #include <sstream> #include <utility> #include <cm/memory> +#include <cm/string_view> #include <cm/vector> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/FStream.hxx" #include "cmsys/Terminal.h" +#include "cmCMakePath.h" #include "cmCustomCommand.h" // IWYU pragma: keep #include "cmCustomCommandGenerator.h" +#include "cmDependsCompiler.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" @@ -50,8 +55,9 @@ # include "cmDependsJava.h" #endif +namespace { // Helper function used below. -static std::string cmSplitExtension(std::string const& in, std::string& base) +std::string cmSplitExtension(std::string const& in, std::string& base) { std::string ext; std::string::size_type dot_pos = in.rfind('.'); @@ -65,6 +71,43 @@ static std::string cmSplitExtension(std::string const& in, std::string& base) return ext; } +// Helper predicate for removing absolute paths that don't point to the +// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY +// is set ON, to only consider in-project dependencies during the build. +class NotInProjectDir +{ +public: + // Constructor with the source and binary directory's path + NotInProjectDir(cm::string_view sourceDir, cm::string_view binaryDir) + : SourceDir(sourceDir) + , BinaryDir(binaryDir) + { + } + + // Operator evaluating the predicate + bool operator()(const std::string& p) const + { + auto path = cmCMakePath(p).Normal(); + + // Keep all relative paths: + if (path.IsRelative()) { + return false; + } + + // If it's an absolute path, check if it starts with the source + // directory: + return !(cmCMakePath(this->SourceDir).IsPrefix(path) || + cmCMakePath(this->BinaryDir).IsPrefix(path)); + } + +private: + // The path to the source directory + cm::string_view SourceDir; + // The path to the binary directory + cm::string_view BinaryDir; +}; +} + cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3( cmGlobalGenerator* gg, cmMakefile* mf) : cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory()) @@ -552,8 +595,10 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } } - // Write the list of commands. - os << cmWrap("\t", commands, "", "\n") << "\n"; + if (!commands.empty()) { + // Write the list of commands. + os << cmWrap("\t", commands, "", "\n") << "\n"; + } if (symbolic && !this->IsWatcomWMake()) { os << ".PHONY : " << tgt << "\n"; } @@ -960,7 +1005,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( std::string launcher; // Short-circuit if there is no launcher. - const char* val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM"); + cmProp val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM"); if (cmNonempty(val)) { // Expand rule variables referenced in the given launcher command. cmRulePlaceholderExpander::RuleVariables vars; @@ -980,7 +1025,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( } vars.Output = output.c_str(); - launcher = val; + launcher = *val; rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars); if (!launcher.empty()) { launcher += " "; @@ -1298,91 +1343,153 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( cmSystemTools::Error("Target DependInfo.cmake file not found"); } + bool status = true; + // Check if any multiple output pairs have a missing file. this->CheckMultipleOutputs(verbose); std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo); - std::string const internalDependFile = targetDir + "/depend.internal"; - std::string const dependFile = targetDir + "/depend.make"; - - // If the target DependInfo.cmake file has changed since the last - // time dependencies were scanned then force rescanning. This may - // happen when a new source file is added and CMake regenerates the - // project but no other sources were touched. - bool needRescanDependInfo = false; - cmFileTimeCache* ftc = - this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache(); - { - int result; - if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) { - if (verbose) { - cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo, - "\" is newer than depender \"", - internalDependFile, "\".\n")); + if (!this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) { + // dependencies are managed by CMake itself + + std::string const internalDependFile = targetDir + "/depend.internal"; + std::string const dependFile = targetDir + "/depend.make"; + + // If the target DependInfo.cmake file has changed since the last + // time dependencies were scanned then force rescanning. This may + // happen when a new source file is added and CMake regenerates the + // project but no other sources were touched. + bool needRescanDependInfo = false; + cmFileTimeCache* ftc = + this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache(); + { + int result; + if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) { + if (verbose) { + cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo, + "\" is newer than depender \"", + internalDependFile, "\".\n")); + } + needRescanDependInfo = true; } - needRescanDependInfo = true; } - } - // If the directory information is newer than depend.internal, include dirs - // may have changed. In this case discard all old dependencies. - bool needRescanDirInfo = false; - { - std::string dirInfoFile = - cmStrCat(this->GetCurrentBinaryDirectory(), - "/CMakeFiles/CMakeDirectoryInformation.cmake"); - int result; - if (!ftc->Compare(internalDependFile, dirInfoFile, &result) || - result < 0) { - if (verbose) { - cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile, - "\" is newer than depender \"", - internalDependFile, "\".\n")); + // If the directory information is newer than depend.internal, include + // dirs may have changed. In this case discard all old dependencies. + bool needRescanDirInfo = false; + { + std::string dirInfoFile = + cmStrCat(this->GetCurrentBinaryDirectory(), + "/CMakeFiles/CMakeDirectoryInformation.cmake"); + int result; + if (!ftc->Compare(internalDependFile, dirInfoFile, &result) || + result < 0) { + if (verbose) { + cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile, + "\" is newer than depender \"", + internalDependFile, "\".\n")); + } + needRescanDirInfo = true; } - needRescanDirInfo = true; + } + + // Check the implicit dependencies to see if they are up to date. + // The build.make file may have explicit dependencies for the object + // files but these will not affect the scanning process so they need + // not be considered. + cmDepends::DependencyMap validDependencies; + bool needRescanDependencies = false; + if (!needRescanDirInfo) { + cmDependsC checker; + checker.SetVerbose(verbose); + checker.SetFileTimeCache(ftc); + // cmDependsC::Check() fills the vector validDependencies() with the + // dependencies for those files where they are still valid, i.e. + // neither the files themselves nor any files they depend on have + // changed. We don't do that if the CMakeDirectoryInformation.cmake + // file has changed, because then potentially all dependencies have + // changed. This information is given later on to cmDependsC, which + // then only rescans the files where it did not get valid dependencies + // via this dependency vector. This means that in the normal case, when + // only few or one file have been edited, then also only this one file + // is actually scanned again, instead of all files for this target. + needRescanDependencies = + !checker.Check(dependFile, internalDependFile, validDependencies); + } + + if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) { + // The dependencies must be regenerated. + std::string targetName = cmSystemTools::GetFilenameName(targetDir); + targetName = targetName.substr(0, targetName.length() - 4); + std::string message = + cmStrCat("Scanning dependencies of target ", targetName); + cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta | + cmsysTerminal_Color_ForegroundBold, + message.c_str(), true, color); + + status = this->ScanDependencies(targetDir, dependFile, + internalDependFile, validDependencies); } } - // Check the implicit dependencies to see if they are up to date. - // The build.make file may have explicit dependencies for the object - // files but these will not affect the scanning process so they need - // not be considered. - cmDepends::DependencyMap validDependencies; - bool needRescanDependencies = false; - if (!needRescanDirInfo) { - cmDependsC checker; - checker.SetVerbose(verbose); - checker.SetFileTimeCache(ftc); - // cmDependsC::Check() fills the vector validDependencies() with the - // dependencies for those files where they are still valid, i.e. neither - // the files themselves nor any files they depend on have changed. - // We don't do that if the CMakeDirectoryInformation.cmake file has - // changed, because then potentially all dependencies have changed. - // This information is given later on to cmDependsC, which then only - // rescans the files where it did not get valid dependencies via this - // dependency vector. This means that in the normal case, when only - // few or one file have been edited, then also only this one file is - // actually scanned again, instead of all files for this target. - needRescanDependencies = - !checker.Check(dependFile, internalDependFile, validDependencies); - } - - if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) { - // The dependencies must be regenerated. - std::string targetName = cmSystemTools::GetFilenameName(targetDir); - targetName = targetName.substr(0, targetName.length() - 4); - std::string message = - cmStrCat("Scanning dependencies of target ", targetName); - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta | - cmsysTerminal_Color_ForegroundBold, - message.c_str(), true, color); - - return this->ScanDependencies(targetDir, dependFile, internalDependFile, - validDependencies); + auto depends = + this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES"); + if (!depends.empty()) { + // dependencies are managed by compiler + auto depFiles = cmExpandedList(depends, true); + std::string const internalDepFile = + targetDir + "/compiler_depend.internal"; + std::string const depFile = targetDir + "/compiler_depend.make"; + cmDepends::DependencyMap dependencies; + cmDependsCompiler depsManager; + bool projectOnly = cmIsOn( + this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_IN_PROJECT_ONLY")); + + depsManager.SetVerbose(verbose); + depsManager.SetLocalGenerator(this); + + if (!depsManager.CheckDependencies( + internalDepFile, depFiles, dependencies, + projectOnly ? NotInProjectDir(this->GetSourceDirectory(), + this->GetBinaryDirectory()) + : std::function<bool(const std::string&)>())) { + // regenerate dependencies files + std::string targetName = + cmCMakePath(targetDir).GetFileName().RemoveExtension().GenericString(); + auto message = cmStrCat( + "Consolidate compiler generated dependencies of target ", targetName); + cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta | + cmsysTerminal_Color_ForegroundBold, + message.c_str(), true, color); + + // Open the make depends file. This should be copy-if-different + // because the make tool may try to reload it needlessly otherwise. + cmGeneratedFileStream ruleFileStream( + depFile, false, this->GlobalGenerator->GetMakefileEncoding()); + ruleFileStream.SetCopyIfDifferent(true); + if (!ruleFileStream) { + return false; + } + + // Open the cmake dependency tracking file. This should not be + // copy-if-different because dependencies are re-scanned when it is + // older than the DependInfo.cmake. + cmGeneratedFileStream internalRuleFileStream( + internalDepFile, false, this->GlobalGenerator->GetMakefileEncoding()); + if (!internalRuleFileStream) { + return false; + } + + this->WriteDisclaimer(ruleFileStream); + this->WriteDisclaimer(internalRuleFileStream); + + depsManager.WriteDependencies(dependencies, ruleFileStream, + internalRuleFileStream); + } } // The dependencies are already up-to-date. - return true; + return status; } bool cmLocalUnixMakefileGenerator3::ScanDependencies( @@ -1721,178 +1828,207 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf, cmDepends clearer; clearer.SetVerbose(verbose); for (std::string const& file : files) { - std::string dir = cmSystemTools::GetFilenamePath(file); + auto snapshot = mf->GetState()->CreateBaseSnapshot(); + cmMakefile lmf(mf->GetGlobalGenerator(), snapshot); + lmf.ReadListFile(file); - // Clear the implicit dependency makefile. - std::string dependFile = dir + "/depend.make"; - clearer.Clear(dependFile); + if (!lmf.GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES").empty()) { + std::string dir = cmSystemTools::GetFilenamePath(file); - // Remove the internal dependency check file to force - // regeneration. - std::string internalDependFile = dir + "/depend.internal"; - cmSystemTools::RemoveFile(internalDependFile); - } -} - -namespace { -// Helper predicate for removing absolute paths that don't point to the -// source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY -// is set ON, to only consider in-project dependencies during the build. -class NotInProjectDir -{ -public: - // Constructor with the source and binary directory's path - NotInProjectDir(std::string sourceDir, std::string binaryDir) - : SourceDir(std::move(sourceDir)) - , BinaryDir(std::move(binaryDir)) - { - } + // Clear the implicit dependency makefile. + std::string dependFile = dir + "/depend.make"; + clearer.Clear(dependFile); - // Operator evaluating the predicate - bool operator()(const std::string& path) const - { - // Keep all relative paths: - if (!cmSystemTools::FileIsFullPath(path)) { - return false; + // Remove the internal dependency check file to force + // regeneration. + std::string internalDependFile = dir + "/depend.internal"; + cmSystemTools::RemoveFile(internalDependFile); } - // If it's an absolute path, check if it starts with the source - // directory: - return ( - !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path))); - } -private: - // Helper function used by the predicate - static bool IsInDirectory(const std::string& baseDir, - const std::string& testDir) - { - // First check if the test directory "starts with" the base directory: - if (!cmHasPrefix(testDir, baseDir)) { - return false; + auto depsFiles = lmf.GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES"); + if (!depsFiles.empty()) { + auto dir = cmCMakePath(file).GetParentPath(); + // Clear the implicit dependency makefile. + auto depFile = cmCMakePath(dir).Append("compiler_depend.make"); + clearer.Clear(depFile.GenericString()); + + // Remove the internal dependency check file + auto internalDepFile = + cmCMakePath(dir).Append("compiler_depend.internal"); + cmSystemTools::RemoveFile(internalDepFile.GenericString()); + + // Touch timestamp file to force dependencies regeneration + auto DepTimestamp = cmCMakePath(dir).Append("compiler_depend.ts"); + cmSystemTools::Touch(DepTimestamp.GenericString(), true); + + // clear the dependencies files generated by the compiler + std::vector<std::string> dependencies = cmExpandedList(depsFiles); + cmDependsCompiler depsManager; + depsManager.SetVerbose(verbose); + depsManager.ClearDependencies(dependencies); } - // If it does, then check that it's either the same string, or that the - // next character is a slash: - return ((testDir.size() == baseDir.size()) || - (testDir[baseDir.size()] == '/')); } - - // The path to the source directory - std::string SourceDir; - // The path to the binary directory - std::string BinaryDir; -}; } void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( std::ostream& cmakefileStream, cmGeneratorTarget* target) { - ImplicitDependLanguageMap const& implicitLangs = - this->GetImplicitDepends(target); + // To enable dependencies filtering + cmakefileStream << "\n" + << "# Consider dependencies only in project.\n" + << "set(CMAKE_DEPENDS_IN_PROJECT_ONLY " + << (cmIsOn(this->Makefile->GetSafeDefinition( + "CMAKE_DEPENDS_IN_PROJECT_ONLY")) + ? "ON" + : "OFF") + << ")\n\n"; + + auto const& implicitLangs = + this->GetImplicitDepends(target, cmDependencyScannerKind::CMake); // list the languages - cmakefileStream - << "# The set of languages for which implicit dependencies are needed:\n"; + cmakefileStream << "# The set of languages for which implicit " + "dependencies are needed:\n"; cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n"; for (auto const& implicitLang : implicitLangs) { cmakefileStream << " \"" << implicitLang.first << "\"\n"; } cmakefileStream << " )\n"; - // now list the files for each language - cmakefileStream - << "# The set of files for implicit dependencies of each language:\n"; - for (auto const& implicitLang : implicitLangs) { - cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << implicitLang.first - << "\n"; - ImplicitDependFileMap const& implicitPairs = implicitLang.second; - - // for each file pair - for (auto const& implicitPair : implicitPairs) { - for (auto const& di : implicitPair.second) { - cmakefileStream << " \"" << di << "\" "; - cmakefileStream << "\"" << implicitPair.first << "\"\n"; + if (!implicitLangs.empty()) { + // now list the files for each language + cmakefileStream + << "# The set of files for implicit dependencies of each language:\n"; + for (auto const& implicitLang : implicitLangs) { + const auto& lang = implicitLang.first; + + cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << lang << "\n"; + auto const& implicitPairs = implicitLang.second; + + // for each file pair + for (auto const& implicitPair : implicitPairs) { + for (auto const& di : implicitPair.second) { + cmakefileStream << " \"" << di << "\" "; + cmakefileStream << "\"" << implicitPair.first << "\"\n"; + } } - } - cmakefileStream << " )\n"; - - // Tell the dependency scanner what compiler is used. - std::string cidVar = - cmStrCat("CMAKE_", implicitLang.first, "_COMPILER_ID"); - cmProp cid = this->Makefile->GetDefinition(cidVar); - if (cmNonempty(cid)) { - cmakefileStream << "set(CMAKE_" << implicitLang.first - << "_COMPILER_ID \"" << *cid << "\")\n"; - } + cmakefileStream << " )\n"; - if (implicitLang.first == "Fortran") { - std::string smodSep = - this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP"); - std::string smodExt = - this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT"); - cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep - << "\")\n"; - cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt - << "\")\n"; - } + // Tell the dependency scanner what compiler is used. + std::string cidVar = cmStrCat("CMAKE_", lang, "_COMPILER_ID"); + cmProp cid = this->Makefile->GetDefinition(cidVar); + if (cmNonempty(cid)) { + cmakefileStream << "set(CMAKE_" << lang << "_COMPILER_ID \"" << *cid + << "\")\n"; + } - // Build a list of preprocessor definitions for the target. - std::set<std::string> defines; - this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first, - defines); - if (!defines.empty()) { - /* clang-format off */ + if (lang == "Fortran") { + std::string smodSep = + this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP"); + std::string smodExt = + this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT"); + cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep + << "\")\n"; + cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt + << "\")\n"; + } + + // Build a list of preprocessor definitions for the target. + std::set<std::string> defines; + this->GetTargetDefines(target, this->GetConfigName(), lang, defines); + if (!defines.empty()) { + /* clang-format off */ cmakefileStream << "\n" << "# Preprocessor definitions for this target.\n" - << "set(CMAKE_TARGET_DEFINITIONS_" << implicitLang.first << "\n"; - /* clang-format on */ - for (std::string const& define : defines) { - cmakefileStream << " " << cmOutputConverter::EscapeForCMake(define) - << "\n"; + << "set(CMAKE_TARGET_DEFINITIONS_" << lang << "\n"; + /* clang-format on */ + for (std::string const& define : defines) { + cmakefileStream << " " << cmOutputConverter::EscapeForCMake(define) + << "\n"; + } + cmakefileStream << " )\n"; + } + + // Target-specific include directories: + cmakefileStream << "\n" + << "# The include file search paths:\n"; + cmakefileStream << "set(CMAKE_" << lang << "_TARGET_INCLUDE_PATH\n"; + std::vector<std::string> includes; + + this->GetIncludeDirectories(includes, target, lang, + this->GetConfigName()); + std::string const& binaryDir = this->GetState()->GetBinaryDirectory(); + if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) { + std::string const& sourceDir = this->GetState()->GetSourceDirectory(); + cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir)); + } + for (std::string const& include : includes) { + cmakefileStream << " \"" + << this->MaybeConvertToRelativePath(binaryDir, include) + << "\"\n"; } cmakefileStream << " )\n"; } - // Target-specific include directories: - cmakefileStream << "\n" - << "# The include file search paths:\n"; - cmakefileStream << "set(CMAKE_" << implicitLang.first - << "_TARGET_INCLUDE_PATH\n"; - std::vector<std::string> includes; - - this->GetIncludeDirectories(includes, target, implicitLang.first, - this->GetConfigName()); - std::string binaryDir = this->GetState()->GetBinaryDirectory(); - if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) { - std::string const& sourceDir = this->GetState()->GetSourceDirectory(); - cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir)); + // Store include transform rule properties. Write the directory + // rules first because they may be overridden by later target rules. + std::vector<std::string> transformRules; + if (cmProp xform = + this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { + cmExpandList(*xform, transformRules); } - for (std::string const& include : includes) { - cmakefileStream << " \"" - << this->MaybeConvertToRelativePath(binaryDir, include) - << "\"\n"; + if (cmProp xform = + target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { + cmExpandList(*xform, transformRules); + } + if (!transformRules.empty()) { + cmakefileStream << "\nset(CMAKE_INCLUDE_TRANSFORMS\n"; + for (std::string const& tr : transformRules) { + cmakefileStream << " " << cmOutputConverter::EscapeForCMake(tr) + << "\n"; + } + cmakefileStream << " )\n"; } - cmakefileStream << " )\n"; } - // Store include transform rule properties. Write the directory - // rules first because they may be overridden by later target rules. - std::vector<std::string> transformRules; - if (cmProp xform = - this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { - cmExpandList(*xform, transformRules); - } - if (cmProp xform = - target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { - cmExpandList(*xform, transformRules); - } - if (!transformRules.empty()) { - cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n"; - for (std::string const& tr : transformRules) { - cmakefileStream << " " << cmOutputConverter::EscapeForCMake(tr) << "\n"; + auto const& compilerLangs = + this->GetImplicitDepends(target, cmDependencyScannerKind::Compiler); + + // list the dependency files managed by the compiler + cmakefileStream << "\n# The set of dependency files which are needed:\n"; + cmakefileStream << "set(CMAKE_DEPENDS_DEPENDENCY_FILES\n"; + for (auto const& compilerLang : compilerLangs) { + auto const& compilerPairs = compilerLang.second; + if (compilerLang.first == "CUSTOM"_s) { + for (auto const& compilerPair : compilerPairs) { + for (auto const& src : compilerPair.second) { + cmakefileStream << R"( "" ")" + << this->MaybeConvertToRelativePath( + this->GetBinaryDirectory(), compilerPair.first) + << R"(" "custom" ")" + << this->MaybeConvertToRelativePath( + this->GetBinaryDirectory(), src) + << "\"\n"; + } + } + } else { + auto depFormat = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT")); + for (auto const& compilerPair : compilerPairs) { + for (auto const& src : compilerPair.second) { + cmakefileStream << " \"" << src << "\" \"" + << this->MaybeConvertToRelativePath( + this->GetBinaryDirectory(), compilerPair.first) + << "\" \"" << depFormat << "\" \"" + << this->MaybeConvertToRelativePath( + this->GetBinaryDirectory(), compilerPair.first) + << ".d\"\n"; + } + } } - cmakefileStream << " )\n"; } + cmakefileStream << " )\n"; } void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os) @@ -2049,16 +2185,18 @@ std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory( } cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const& -cmLocalUnixMakefileGenerator3::GetImplicitDepends(const cmGeneratorTarget* tgt) +cmLocalUnixMakefileGenerator3::GetImplicitDepends( + const cmGeneratorTarget* tgt, cmDependencyScannerKind scanner) { - return this->ImplicitDepends[tgt->GetName()]; + return this->ImplicitDepends[tgt->GetName()][scanner]; } void cmLocalUnixMakefileGenerator3::AddImplicitDepends( const cmGeneratorTarget* tgt, const std::string& lang, - const std::string& obj, const std::string& src) + const std::string& obj, const std::string& src, + cmDependencyScannerKind scanner) { - this->ImplicitDepends[tgt->GetName()][lang][obj].push_back(src); + this->ImplicitDepends[tgt->GetName()][scanner][lang][obj].push_back(src); } void cmLocalUnixMakefileGenerator3::CreateCDCommand( diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 8286d67..14dd0ba 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -13,6 +13,7 @@ #include "cmDepends.h" #include "cmLocalCommonGenerator.h" +#include "cmLocalGenerator.h" class cmCustomCommand; class cmCustomCommandGenerator; @@ -152,23 +153,21 @@ public: // File pairs for implicit dependency scanning. The key of the map // is the depender and the value is the explicit dependee. - struct ImplicitDependFileMap : public cmDepends::DependencyMap - { - }; - struct ImplicitDependLanguageMap - : public std::map<std::string, ImplicitDependFileMap> - { - }; - struct ImplicitDependTargetMap - : public std::map<std::string, ImplicitDependLanguageMap> - { - }; + using ImplicitDependFileMap = cmDepends::DependencyMap; + using ImplicitDependLanguageMap = + std::map<std::string, ImplicitDependFileMap>; + using ImplicitDependScannerMap = + std::map<cmDependencyScannerKind, ImplicitDependLanguageMap>; + using ImplicitDependTargetMap = + std::map<std::string, ImplicitDependScannerMap>; ImplicitDependLanguageMap const& GetImplicitDepends( - cmGeneratorTarget const* tgt); + cmGeneratorTarget const* tgt, + cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake); - void AddImplicitDepends(cmGeneratorTarget const* tgt, - const std::string& lang, const std::string& obj, - const std::string& src); + void AddImplicitDepends( + cmGeneratorTarget const* tgt, const std::string& lang, + const std::string& obj, const std::string& src, + cmDependencyScannerKind scanner = cmDependencyScannerKind::CMake); // write the target rules for the local Makefile into the stream void WriteLocalAllRules(std::ostream& ruleFileStream); @@ -178,11 +177,11 @@ public: /** Get whether to create rules to generate preprocessed and assembly sources. This could be converted to a variable lookup later. */ - bool GetCreatePreprocessedSourceRules() + bool GetCreatePreprocessedSourceRules() const { return !this->SkipPreprocessedSourceRules; } - bool GetCreateAssemblySourceRules() + bool GetCreateAssemblySourceRules() const { return !this->SkipAssemblySourceRules; } diff --git a/Source/cmMSVC60LinkLineComputer.cxx b/Source/cmMSVC60LinkLineComputer.cxx index 74c9435..8cf3765 100644 --- a/Source/cmMSVC60LinkLineComputer.cxx +++ b/Source/cmMSVC60LinkLineComputer.cxx @@ -36,5 +36,5 @@ std::string cmMSVC60LinkLineComputer::ConvertToLinkReference( } #endif - return cmLinkLineComputer::ConvertToLinkReference(lib); + return this->cmLinkLineComputer::ConvertToLinkReference(lib); } diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 98f88c1..8c4b2a7 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -171,8 +171,11 @@ bool cmMacroFunctionBlocker::Replay(std::vector<cmListFileFunction> functions, f.Functions = std::move(functions); f.FilePath = this->GetStartingContext().FilePath; mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - return true; + return mf.GetState()->AddScriptedCommand( + this->Args[0], + BT<cmState::Command>(std::move(f), + mf.GetBacktrace().Push(this->GetStartingContext())), + mf); } } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 0e4f888..e4c8e4b 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -29,15 +29,12 @@ #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" -#include "cm_sys_stat.h" - #include "cmCommandArgumentParserHelper.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmExpandedCommandArgument.h" // IWYU pragma: keep #include "cmExportBuildFileGenerator.h" -#include "cmFSPermissions.h" #include "cmFileLockPool.h" #include "cmFunctionBlocker.h" #include "cmGeneratedFileStream.h" @@ -72,8 +69,6 @@ class cmMessenger; -using namespace cmFSPermissions; - cmDirectoryId::cmDirectoryId(std::string s) : String(std::move(s)) { @@ -870,13 +865,14 @@ void cmMakefile::EnforceDirectoryLevelRules() const void cmMakefile::AddEvaluationFile( const std::string& inputFile, const std::string& targetName, std::unique_ptr<cmCompiledGeneratorExpression> outputName, - std::unique_ptr<cmCompiledGeneratorExpression> condition, + std::unique_ptr<cmCompiledGeneratorExpression> condition, mode_t permissions, bool inputIsContent) { this->EvaluationFiles.push_back( cm::make_unique<cmGeneratorExpressionEvaluationFile>( inputFile, targetName, std::move(outputName), std::move(condition), - inputIsContent, this->GetPolicyStatus(cmPolicies::CMP0070))); + inputIsContent, permissions, + this->GetPolicyStatus(cmPolicies::CMP0070))); } const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>& @@ -939,8 +935,6 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg) action.Value(lg, action.Backtrace); } this->GeneratorActionsInvoked = true; - this->DelayedOutputFiles.clear(); - this->DelayedOutputFilesHaveGenex = false; // go through all configured files and see which ones still exist. // we don't want cmake to re-run if a configured file is created and deleted @@ -984,7 +978,7 @@ struct BacktraceGuard this->Backtrace = std::move(current); } - ~BacktraceGuard() { this->Backtrace = std::move(Previous); } + ~BacktraceGuard() { this->Backtrace = std::move(this->Previous); } private: cmListFileBacktrace& Backtrace; @@ -1104,7 +1098,7 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( } // Always create the byproduct sources and mark them generated. - this->CreateGeneratedByproducts(byproducts); + this->CreateGeneratedOutputs(byproducts); // Strings could be moved into the callback function with C++14. cm::optional<std::string> commentStr = MakeOptionalString(comment); @@ -1163,7 +1157,7 @@ void cmMakefile::AddCustomCommandToOutput( // Always create the output sources and mark them generated. this->CreateGeneratedOutputs(outputs); - this->CreateGeneratedByproducts(byproducts); + this->CreateGeneratedOutputs(byproducts); // Strings could be moved into the callback function with C++14. cm::optional<std::string> commentStr = MakeOptionalString(comment); @@ -1222,9 +1216,10 @@ void cmMakefile::AddCustomCommandOldStyle( }; // Each output must get its own copy of this rule. - cmsys::RegularExpression sourceFiles("\\.(C|M|c|c\\+\\+|cc|cpp|cxx|cu|m|mm|" - "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|" - "hm|hpp|hxx|in|txx|inl)$"); + cmsys::RegularExpression sourceFiles( + "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|cu|m|mm|" + "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|" + "hm|hpp|hxx|in|txx|inl)$"); // Choose whether to use a main dependency. if (sourceFiles.find(source)) { @@ -1247,16 +1242,11 @@ void cmMakefile::AddCustomCommandOldStyle( } } -bool cmMakefile::AppendCustomCommandToOutput( +void cmMakefile::AppendCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines) { - // Check as good as we can if there will be a command for this output. - if (!this->MightHaveCustomCommand(output)) { - return false; - } - // Validate custom commands. if (this->ValidateCustomCommand(commandLines)) { // Dispatch command creation to allow generator expressions in outputs. @@ -1267,29 +1257,6 @@ bool cmMakefile::AppendCustomCommandToOutput( implicit_depends, commandLines); }); } - - return true; -} - -cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target) -{ - std::string force = cmStrCat(this->GetCurrentBinaryDirectory(), - "/CMakeFiles/", target->GetName()); - std::string forceCMP0049 = target->GetSourceCMP0049(force); - { - cmSourceFile* sf = nullptr; - if (!forceCMP0049.empty()) { - sf = this->GetOrCreateSource(forceCMP0049, false, - cmSourceFileLocationKind::Known); - } - // The output is not actually created so mark it symbolic. - if (sf) { - sf->SetProperty("SYMBOLIC", "1"); - } else { - cmSystemTools::Error("Could not get source file entry for " + force); - } - } - return { std::move(force), std::move(forceCMP0049) }; } cmTarget* cmMakefile::AddUtilityCommand( @@ -1308,12 +1275,8 @@ cmTarget* cmMakefile::AddUtilityCommand( return target; } - // Get the output name of the utility target and mark it generated. - cmUtilityOutput force = this->GetUtilityOutput(target); - this->GetOrCreateGeneratedSource(force.Name); - // Always create the byproduct sources and mark them generated. - this->CreateGeneratedByproducts(byproducts); + this->CreateGeneratedOutputs(byproducts); // Strings could be moved into the callback function with C++14. cm::optional<std::string> commentStr = MakeOptionalString(comment); @@ -1324,8 +1287,8 @@ cmTarget* cmMakefile::AddUtilityCommand( [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { BacktraceGuard guard(this->Backtrace, lfbt); detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target, - force, GetCStrOrNull(workingStr), byproducts, - depends, commandLines, escapeOldStyle, + GetCStrOrNull(workingStr), byproducts, depends, + commandLines, escapeOldStyle, GetCStrOrNull(commentStr), uses_terminal, command_expand_lists, job_pool, stdPipesUTF8); }); @@ -1496,15 +1459,14 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent) // Include transform property. There is no per-config version. { const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM"; - cmProp p = parent->GetProperty(prop); - this->SetProperty(prop, cmToCStr(p)); + this->SetProperty(prop, cmToCStr(parent->GetProperty(prop))); } // compile definitions property and per-config versions cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043); if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) { - cmProp p = parent->GetProperty("COMPILE_DEFINITIONS"); - this->SetProperty("COMPILE_DEFINITIONS", cmToCStr(p)); + this->SetProperty("COMPILE_DEFINITIONS", + cmToCStr(parent->GetProperty("COMPILE_DEFINITIONS"))); std::vector<std::string> configs = this->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); for (std::string const& config : configs) { @@ -1516,12 +1478,11 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent) } // labels - cmProp p = parent->GetProperty("LABELS"); - this->SetProperty("LABELS", cmToCStr(p)); + this->SetProperty("LABELS", cmToCStr(parent->GetProperty("LABELS"))); // link libraries - p = parent->GetProperty("LINK_LIBRARIES"); - this->SetProperty("LINK_LIBRARIES", cmToCStr(p)); + this->SetProperty("LINK_LIBRARIES", + cmToCStr(parent->GetProperty("LINK_LIBRARIES"))); // the initial project name this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName()); @@ -2038,7 +1999,7 @@ void cmMakefile::RemoveDefinition(const std::string& name) #endif } -void cmMakefile::RemoveCacheDefinition(const std::string& name) +void cmMakefile::RemoveCacheDefinition(const std::string& name) const { this->GetState()->RemoveCacheEntry(name); } @@ -2154,213 +2115,6 @@ cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName, } namespace { -bool AnyOutputMatches(const std::string& name, - const std::vector<std::string>& outputs) -{ - for (std::string const& output : outputs) { - std::string::size_type pos = output.rfind(name); - // If the output matches exactly - if (pos != std::string::npos && pos == output.size() - name.size() && - (pos == 0 || output[pos - 1] == '/')) { - return true; - } - } - return false; -} - -bool AnyTargetCommandOutputMatches( - const std::string& name, const std::vector<cmCustomCommand>& commands) -{ - for (cmCustomCommand const& command : commands) { - if (AnyOutputMatches(name, command.GetByproducts())) { - return true; - } - } - return false; -} -} - -cmTarget* cmMakefile::LinearGetTargetWithOutput(const std::string& name) const -{ - // We go through the ordered vector of targets to get reproducible results - // should multiple names match. - for (cmTarget* t : this->OrderedTargets) { - // Does the output of any command match the source file name? - if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) { - return t; - } - if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) { - return t; - } - if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) { - return t; - } - } - return nullptr; -} - -cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput( - const std::string& name, cmSourceOutputKind kind, bool& byproduct) const -{ - // Outputs take precedence over byproducts. - byproduct = false; - cmSourceFile* fallback = nullptr; - - // Look through all the source files that have custom commands and see if the - // custom command has the passed source file as an output. - for (const auto& src : this->SourceFiles) { - // Does this source file have a custom command? - if (src->GetCustomCommand()) { - // Does the output of the custom command match the source file name? - if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) { - // Return the first matching output. - return src.get(); - } - if (kind == cmSourceOutputKind::OutputOrByproduct) { - if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) { - // Do not return the source yet as there might be a matching output. - fallback = src.get(); - } - } - } - } - - // Did we find a byproduct? - byproduct = fallback != nullptr; - return fallback; -} - -cmSourcesWithOutput cmMakefile::GetSourcesWithOutput( - const std::string& name) const -{ - // Linear search? Also see GetSourceFileWithOutput for detail. - if (!cmSystemTools::FileIsFullPath(name)) { - cmSourcesWithOutput sources; - sources.Target = this->LinearGetTargetWithOutput(name); - sources.Source = this->LinearGetSourceFileWithOutput( - name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct); - return sources; - } - // Otherwise we use an efficient lookup map. - auto o = this->OutputToSource.find(name); - if (o != this->OutputToSource.end()) { - return o->second.Sources; - } - return {}; -} - -cmSourceFile* cmMakefile::GetSourceFileWithOutput( - const std::string& name, cmSourceOutputKind kind) const -{ - // If the queried path is not absolute we use the backward compatible - // linear-time search for an output with a matching suffix. - if (!cmSystemTools::FileIsFullPath(name)) { - bool byproduct = false; - return this->LinearGetSourceFileWithOutput(name, kind, byproduct); - } - // Otherwise we use an efficient lookup map. - auto o = this->OutputToSource.find(name); - if (o != this->OutputToSource.end() && - (!o->second.Sources.SourceIsByproduct || - kind == cmSourceOutputKind::OutputOrByproduct)) { - // Source file could also be null pointer for example if we found the - // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD - // command of a target, or a not yet created custom command. - return o->second.Sources.Source; - } - return nullptr; -} - -bool cmMakefile::MightHaveCustomCommand(const std::string& name) const -{ - if (this->DelayedOutputFilesHaveGenex || - cmGeneratorExpression::Find(name) != std::string::npos) { - // Could be more restrictive, but for now we assume that there could always - // be a match when generator expressions are involved. - return true; - } - // Also see LinearGetSourceFileWithOutput. - if (!cmSystemTools::FileIsFullPath(name)) { - return AnyOutputMatches(name, this->DelayedOutputFiles); - } - // Otherwise we use an efficient lookup map. - auto o = this->OutputToSource.find(name); - if (o != this->OutputToSource.end()) { - return o->second.SourceMightBeOutput; - } - return false; -} - -void cmMakefile::AddTargetByproducts( - cmTarget* target, const std::vector<std::string>& byproducts) -{ - for (std::string const& o : byproducts) { - this->UpdateOutputToSourceMap(o, target); - } -} - -void cmMakefile::AddSourceOutputs(cmSourceFile* source, - const std::vector<std::string>& outputs, - const std::vector<std::string>& byproducts) -{ - for (std::string const& o : outputs) { - this->UpdateOutputToSourceMap(o, source, false); - } - for (std::string const& o : byproducts) { - this->UpdateOutputToSourceMap(o, source, true); - } -} - -void cmMakefile::UpdateOutputToSourceMap(std::string const& byproduct, - cmTarget* target) -{ - SourceEntry entry; - entry.Sources.Target = target; - - auto pr = this->OutputToSource.emplace(byproduct, entry); - if (!pr.second) { - SourceEntry& current = pr.first->second; - // Has the target already been set? - if (!current.Sources.Target) { - current.Sources.Target = target; - } else { - // Multiple custom commands/targets produce the same output (source file - // or target). See also comment in other UpdateOutputToSourceMap - // overload. - // - // TODO: Warn the user about this case. - } - } -} - -void cmMakefile::UpdateOutputToSourceMap(std::string const& output, - cmSourceFile* source, bool byproduct) -{ - SourceEntry entry; - entry.Sources.Source = source; - entry.Sources.SourceIsByproduct = byproduct; - entry.SourceMightBeOutput = !byproduct; - - auto pr = this->OutputToSource.emplace(output, entry); - if (!pr.second) { - SourceEntry& current = pr.first->second; - // Outputs take precedence over byproducts - if (!current.Sources.Source || - (current.Sources.SourceIsByproduct && !byproduct)) { - current.Sources.Source = source; - current.Sources.SourceIsByproduct = false; - current.SourceMightBeOutput = true; - } else { - // Multiple custom commands produce the same output but may - // be attached to a different source file (MAIN_DEPENDENCY). - // LinearGetSourceFileWithOutput would return the first one, - // so keep the mapping for the first one. - // - // TODO: Warn the user about this case. However, the VS 8 generator - // triggers it for separate generate.stamp rules in ZERO_CHECK and - // individual targets. - } - } } #if !defined(CMAKE_BOOTSTRAP) @@ -2685,7 +2439,7 @@ cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const bool cmMakefile::PlatformIsAppleEmbedded() const { - return GetAppleSDKType() != AppleSDK::MacOS; + return this->GetAppleSDKType() != AppleSDK::MacOS; } const char* cmMakefile::GetSONameFlag(const std::string& language) const @@ -2696,7 +2450,7 @@ const char* cmMakefile::GetSONameFlag(const std::string& language) const name += language; } name += "_FLAG"; - return cmToCStr(GetDefinition(name)); + return cmToCStr(this->GetDefinition(name)); } bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const @@ -2719,7 +2473,7 @@ const std::string& cmMakefile::GetRequiredDefinition( const std::string& name) const { static std::string const empty; - const std::string* def = GetDefinition(name); + const std::string* def = this->GetDefinition(name); if (!def) { cmSystemTools::Error("Error required internal CMake variable not " "set, cmake may not be built correctly.\n" @@ -2779,7 +2533,7 @@ cmProp cmMakefile::GetDefinition(const std::string& name) const const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const { static std::string const empty; - const std::string* def = GetDefinition(name); + const std::string* def = this->GetDefinition(name); if (!def) { return empty; } @@ -2845,24 +2599,24 @@ const std::string& cmMakefile::ExpandVariablesInString( // Suppress variable watches to avoid calling hooks twice. Suppress new // dereferences since the OLD behavior is still what is actually used. this->SuppressSideEffects = true; - newError = ExpandVariablesInStringNew(newErrorstr, newResult, - escapeQuotes, noEscapes, atOnly, - filename, line, replaceAt); + newError = this->ExpandVariablesInStringNew( + newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename, + line, replaceAt); this->SuppressSideEffects = false; CM_FALLTHROUGH; } case cmPolicies::OLD: - mtype = - ExpandVariablesInStringOld(errorstr, source, escapeQuotes, noEscapes, - atOnly, filename, line, removeEmpty, true); + mtype = this->ExpandVariablesInStringOld(errorstr, source, escapeQuotes, + noEscapes, atOnly, filename, + line, removeEmpty, true); break; case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: // Messaging here would be *very* verbose. case cmPolicies::NEW: - mtype = - ExpandVariablesInStringNew(errorstr, source, escapeQuotes, noEscapes, - atOnly, filename, line, replaceAt); + mtype = this->ExpandVariablesInStringNew(errorstr, source, escapeQuotes, + noEscapes, atOnly, filename, + line, replaceAt); break; } @@ -3055,7 +2809,7 @@ void cmMakefile::SetRecursionDepth(int recursionDepth) this->RecursionDepth = recursionDepth; } -std::string cmMakefile::NewDeferId() +std::string cmMakefile::NewDeferId() const { return this->GetGlobalGenerator()->NewDeferId(); } @@ -3629,11 +3383,7 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, bool generated, cmSourceFileLocationKind kind) { - auto sf = cm::make_unique<cmSourceFile>(this, sourceName, kind); - if (generated) { - sf->SetProperty("GENERATED", "1"); - } - + auto sf = cm::make_unique<cmSourceFile>(this, sourceName, generated, kind); auto name = this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName()); #if defined(_WIN32) || defined(__APPLE__) @@ -3665,7 +3415,7 @@ cmSourceFile* cmMakefile::GetOrCreateGeneratedSource( { cmSourceFile* sf = this->GetOrCreateSource(sourceName, true, cmSourceFileLocationKind::Known); - sf->SetProperty("GENERATED", "1"); + sf->MarkAsGenerated(); // In case we did not create the source file. return sf; } @@ -3675,38 +3425,10 @@ void cmMakefile::CreateGeneratedOutputs( for (std::string const& o : outputs) { if (cmGeneratorExpression::Find(o) == std::string::npos) { this->GetOrCreateGeneratedSource(o); - this->AddDelayedOutput(o); - } else { - this->DelayedOutputFilesHaveGenex = true; } } } -void cmMakefile::CreateGeneratedByproducts( - const std::vector<std::string>& byproducts) -{ - for (std::string const& o : byproducts) { - if (cmGeneratorExpression::Find(o) == std::string::npos) { - this->GetOrCreateGeneratedSource(o); - } - } -} - -void cmMakefile::AddDelayedOutput(std::string const& output) -{ - // Note that this vector might contain the output names in a different order - // than in source file iteration order. - this->DelayedOutputFiles.push_back(output); - - SourceEntry entry; - entry.SourceMightBeOutput = true; - - auto pr = this->OutputToSource.emplace(output, entry); - if (!pr.second) { - pr.first->second.SourceMightBeOutput = true; - } -} - void cmMakefile::AddTargetObject(std::string const& tgtName, std::string const& objFile) { @@ -4094,8 +3816,7 @@ void cmMakefile::ConfigureString(const std::string& input, std::string& output, int cmMakefile::ConfigureFile(const std::string& infile, const std::string& outfile, bool copyonly, bool atOnly, bool escapeQuotes, - bool use_source_permissions, - cmNewLineStyle newLine) + mode_t permissions, cmNewLineStyle newLine) { int res = 1; if (!this->CanIWriteThisFile(outfile)) { @@ -4117,12 +3838,8 @@ int cmMakefile::ConfigureFile(const std::string& infile, // output files that now don't exist. this->AddCMakeOutputFile(soutfile); - mode_t perm = 0; - if (!use_source_permissions) { - perm = perm | mode_owner_read | mode_owner_write | mode_group_read | - mode_world_read; - } else { - cmSystemTools::GetPermissions(sinfile, perm); + if (permissions == 0) { + cmSystemTools::GetPermissions(sinfile, permissions); } std::string::size_type pos = soutfile.rfind('/'); @@ -4137,7 +3854,7 @@ int cmMakefile::ConfigureFile(const std::string& infile, cmSystemTools::GetLastSystemError()); return 0; } - if (!cmSystemTools::SetPermissions(soutfile, perm)) { + if (!cmSystemTools::SetPermissions(soutfile, permissions)) { this->IssueMessage(MessageType::FATAL_ERROR, cmSystemTools::GetLastSystemError()); return 0; @@ -4194,7 +3911,7 @@ int cmMakefile::ConfigureFile(const std::string& infile, cmSystemTools::GetLastSystemError()); res = 0; } else { - if (!cmSystemTools::SetPermissions(soutfile, perm)) { + if (!cmSystemTools::SetPermissions(soutfile, permissions)) { this->IssueMessage(MessageType::FATAL_ERROR, cmSystemTools::GetLastSystemError()); res = 0; @@ -4283,7 +4000,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const } void cmMakefile::GetTests(const std::string& config, - std::vector<cmTest*>& tests) + std::vector<cmTest*>& tests) const { for (const auto& generator : this->GetTestGenerators()) { if (generator->TestsForConfig(config)) { @@ -4633,7 +4350,7 @@ cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id, return this->StateSnapshot.GetPolicy(id, parent_scope); } -bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) +bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const { // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting. if (cmProp val = this->GetDefinition(var)) { @@ -4670,7 +4387,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, // Deprecate old policies, especially those that require a lot // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0072 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0075 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. @@ -4738,7 +4455,7 @@ bool cmMakefile::HasCMP0054AlreadyBeenReported( return !this->CMP0054ReportedIds.insert(context).second; } -void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) +void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const { /* Record the setting of every policy. */ using PolicyID = cmPolicies::PolicyID; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index c7940fb..60b66a2 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -20,6 +20,8 @@ #include "cmsys/RegularExpression.hxx" +#include "cm_sys_stat.h" + #include "cmAlgorithms.h" #include "cmCustomCommandTypes.h" #include "cmListFileCache.h" @@ -59,24 +61,6 @@ class cmTestGenerator; class cmVariableWatch; class cmake; -/** Flag if byproducts shall also be considered. */ -enum class cmSourceOutputKind -{ - OutputOnly, - OutputOrByproduct -}; - -/** Target and source file which have a specific output. */ -struct cmSourcesWithOutput -{ - /** Target with byproduct. */ - cmTarget* Target = nullptr; - - /** Source file with output or byproduct. */ - cmSourceFile* Source = nullptr; - bool SourceIsByproduct = false; -}; - /** A type-safe wrapper for a string representing a directory id. */ class cmDirectoryId { @@ -225,25 +209,12 @@ public: const std::string& source, const cmCustomCommandLines& commandLines, const char* comment); - bool AppendCustomCommandToOutput( + void AppendCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines); /** - * Add target byproducts. - */ - void AddTargetByproducts(cmTarget* target, - const std::vector<std::string>& byproducts); - - /** - * Add source file outputs. - */ - void AddSourceOutputs(cmSourceFile* source, - const std::vector<std::string>& outputs, - const std::vector<std::string>& byproducts); - - /** * Add a define flag to the build. */ void AddDefineFlag(std::string const& definition); @@ -272,11 +243,6 @@ public: bool excludeFromAll = false); /** - * Return the utility target output source file name and the CMP0049 name. - */ - cmUtilityOutput GetUtilityOutput(cmTarget* target); - - /** * Dispatch adding a utility to the build. A utility target is a command * that is run every time the target is built. */ @@ -326,7 +292,7 @@ public: const char* doc, cmStateEnums::CacheEntryType type, bool force = false) { - AddCacheDefinition(name, value.c_str(), doc, type, force); + this->AddCacheDefinition(name, value.c_str(), doc, type, force); } /** @@ -335,7 +301,7 @@ public: */ void RemoveDefinition(const std::string& name); //! Remove a definition from the cache. - void RemoveCacheDefinition(const std::string& name); + void RemoveCacheDefinition(const std::string& name) const; /** * Specify the name of the project for this build. @@ -376,7 +342,7 @@ public: bool parent_scope = false) const; bool SetPolicyVersion(std::string const& version_min, std::string const& version_max); - void RecordPolicies(cmPolicies::PolicyMap& pm); + void RecordPolicies(cmPolicies::PolicyMap& pm) const; //@} /** Helper class to push and pop policies automatically. */ @@ -430,8 +396,7 @@ public: } const char* GetIncludeRegularExpression() const { - cmProp p = this->GetProperty("INCLUDE_REGULAR_EXPRESSION"); - return p ? p->c_str() : nullptr; + return cmToCStr(this->GetProperty("INCLUDE_REGULAR_EXPRESSION")); } /** @@ -690,8 +655,7 @@ public: */ int ConfigureFile(const std::string& infile, const std::string& outfile, bool copyonly, bool atOnly, bool escapeQuotes, - bool use_source_permissions, - cmNewLineStyle = cmNewLineStyle()); + mode_t permissions = 0, cmNewLineStyle = cmNewLineStyle()); /** * Print a command's invocation @@ -753,20 +717,10 @@ public: return this->SourceFiles; } - /** - * Return the target if the provided source name is a byproduct of a utility - * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command. - * Return the source file which has the provided source name as output. - */ - cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const; - - /** - * Is there a source file that has the provided source name as an output? - * If so then return it. - */ - cmSourceFile* GetSourceFileWithOutput( - const std::string& name, - cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const; + std::vector<cmTarget*> const& GetOrderedTargets() const + { + return this->OrderedTargets; + } //! Add a new cmTest to the list of tests for this makefile. cmTest* CreateTest(const std::string& testName); @@ -779,7 +733,7 @@ public: /** * Get all tests that run under the given configuration. */ - void GetTests(const std::string& config, std::vector<cmTest*>& tests); + void GetTests(const std::string& config, std::vector<cmTest*>& tests) const; /** * Return a location of a file in cmake or custom modules directory @@ -926,7 +880,7 @@ public: return this->SystemIncludeDirectories; } - bool PolicyOptionalWarningEnabled(std::string const& var); + bool PolicyOptionalWarningEnabled(std::string const& var) const; void PushLoopBlock(); void PopLoopBlock(); @@ -945,7 +899,7 @@ public: const std::string& inputFile, const std::string& targetName, std::unique_ptr<cmCompiledGeneratorExpression> outputName, std::unique_ptr<cmCompiledGeneratorExpression> condition, - bool inputIsContent); + mode_t permissions, bool inputIsContent); const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>& GetEvaluationFiles() const; @@ -967,7 +921,7 @@ public: int GetRecursionDepth() const; void SetRecursionDepth(int recursionDepth); - std::string NewDeferId(); + std::string NewDeferId() const; bool DeferCall(std::string id, std::string fileName, cmListFileFunction lff); bool DeferCancelCall(std::string const& id); cm::optional<std::string> DeferGetCallIds() const; @@ -983,8 +937,7 @@ protected: mutable cmTargetMap Targets; std::map<std::string, std::string> AliasTargets; - using TargetsVec = std::vector<cmTarget*>; - TargetsVec OrderedTargets; + std::vector<cmTarget*> OrderedTargets; std::vector<std::unique_ptr<cmSourceFile>> SourceFiles; @@ -1129,48 +1082,9 @@ private: bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const; void CreateGeneratedOutputs(const std::vector<std::string>& outputs); - void CreateGeneratedByproducts(const std::vector<std::string>& byproducts); std::vector<BT<GeneratorAction>> GeneratorActions; bool GeneratorActionsInvoked = false; - bool DelayedOutputFilesHaveGenex = false; - std::vector<std::string> DelayedOutputFiles; - - void AddDelayedOutput(std::string const& output); - - /** - * See LinearGetSourceFileWithOutput for background information - */ - cmTarget* LinearGetTargetWithOutput(const std::string& name) const; - - /** - * Generalized old version of GetSourceFileWithOutput kept for - * backward-compatibility. It implements a linear search and supports - * relative file paths. It is used as a fall back by GetSourceFileWithOutput - * and GetSourcesWithOutput. - */ - cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name, - cmSourceOutputKind kind, - bool& byproduct) const; - - struct SourceEntry - { - cmSourcesWithOutput Sources; - bool SourceMightBeOutput = false; - }; - - // A map for fast output to input look up. - using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>; - OutputToSourceMap OutputToSource; - - void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target); - void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source, - bool byproduct); - - /** - * Return if the provided source file might have a custom command. - */ - bool MightHaveCustomCommand(const std::string& name) const; bool CheckSystemVars; bool CheckCMP0000; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 871878c..1750e37 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -21,6 +21,7 @@ #include "cmMakefile.h" #include "cmOSXBundleGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -232,10 +233,10 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( std::string launcher; - const char* val = this->LocalGenerator->GetRuleLauncher( - this->GeneratorTarget, "RULE_LAUNCH_LINK"); + cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget, + "RULE_LAUNCH_LINK"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( @@ -591,10 +592,10 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string launcher; - const char* val = this->LocalGenerator->GetRuleLauncher( - this->GeneratorTarget, "RULE_LAUNCH_LINK"); + cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget, + "RULE_LAUNCH_LINK"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index b32ea6a..ce64e2c 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -21,6 +21,7 @@ #include "cmMakefile.h" #include "cmOSXBundleGenerator.h" #include "cmOutputConverter.h" +#include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -366,10 +367,10 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); std::string launcher; - const char* val = this->LocalGenerator->GetRuleLauncher( - this->GeneratorTarget, "RULE_LAUNCH_LINK"); + cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget, + "RULE_LAUNCH_LINK"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( @@ -816,10 +817,10 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.LanguageCompileFlags = langFlags.c_str(); std::string launcher; - const char* val = this->LocalGenerator->GetRuleLauncher( - this->GeneratorTarget, "RULE_LAUNCH_LINK"); + cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget, + "RULE_LAUNCH_LINK"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index c6d6c99..adf40b0 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -12,7 +12,9 @@ #include <utility> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" @@ -23,6 +25,7 @@ #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" // IWYU pragma: keep #include "cmLocalCommonGenerator.h" +#include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmMakefileExecutableTargetGenerator.h" @@ -68,7 +71,8 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target) this->CMP0113New = true; break; } - MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this); + this->MacOSXContentGenerator = + cm::make_unique<MacOSXContentGeneratorType>(this); } cmMakefileTargetGenerator::~cmMakefileTargetGenerator() = default; @@ -325,28 +329,80 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() << cmSystemTools::ConvertToOutputPath( this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetBinaryDirectory(), dependFileNameFull)) - << "\n\n"; + << "\n"; - if (!this->NoRuleMessages) { - // Include the progress variables for the target. + std::string depsUseCompiler = "CMAKE_DEPENDS_USE_COMPILER"; + if (!this->Makefile->IsDefinitionSet(depsUseCompiler) || + this->Makefile->IsOn(depsUseCompiler)) { + std::string compilerDependFile = + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make"); *this->BuildFileStream - << "# Include the progress variables for this target.\n" + << "# Include any dependencies generated by the " + "compiler for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root << cmSystemTools::ConvertToOutputPath( this->LocalGenerator->MaybeConvertToRelativePath( - this->LocalGenerator->GetBinaryDirectory(), - this->ProgressFileNameFull)) + this->LocalGenerator->GetBinaryDirectory(), compilerDependFile)) << "\n\n"; - } - // make sure the depend file exists - if (!cmSystemTools::FileExists(dependFileNameFull)) { // Write an empty dependency file. cmGeneratedFileStream depFileStream( - dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding()); - depFileStream << "# Empty dependencies file for " + compilerDependFile, false, this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# Empty compiler generated dependencies file for " << this->GeneratorTarget->GetName() << ".\n" << "# This may be replaced when dependencies are built.\n"; + // remove internal dependency file + cmSystemTools::RemoveFile( + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.internal")); + + std::string compilerDependTimestamp = + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"); + if (!cmSystemTools::FileExists(compilerDependTimestamp)) { + // Write a dependency timestamp file. + cmGeneratedFileStream timestampFileStream( + compilerDependTimestamp, false, + this->GlobalGenerator->GetMakefileEncoding()); + timestampFileStream + << "# CMAKE generated file: DO NOT EDIT!\n" + << "# Timestamp file for compiler generated dependencies " + "management for " + << this->GeneratorTarget->GetName() << ".\n"; + } + + // deactivate no longer needed legacy dependency files + // Write an empty dependency file. + cmGeneratedFileStream legacyDepFileStream( + dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding()); + legacyDepFileStream + << "# Empty dependencies file for " << this->GeneratorTarget->GetName() + << ".\n" + << "# This may be replaced when dependencies are built.\n"; + // remove internal dependency file + cmSystemTools::RemoveFile( + cmStrCat(this->TargetBuildDirectoryFull, "/depend.internal")); + } else { + // make sure the depend file exists + if (!cmSystemTools::FileExists(dependFileNameFull)) { + // Write an empty dependency file. + cmGeneratedFileStream depFileStream( + dependFileNameFull, false, + this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# Empty dependencies file for " + << this->GeneratorTarget->GetName() << ".\n" + << "# This may be replaced when dependencies are built.\n"; + } + } + + if (!this->NoRuleMessages) { + // Include the progress variables for the target. + *this->BuildFileStream + << "# Include the progress variables for this target.\n" + << this->GlobalGenerator->IncludeDirective << " " << root + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->ProgressFileNameFull)) + << "\n\n"; } // Open the flags file. This should be copy-if-different because the @@ -472,6 +528,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( return; } + // Use compiler to generate dependencies, if supported. + bool compilerGenerateDeps = + this->GlobalGenerator->SupportsCompilerDependencies() && + cmIsOn(this->Makefile->GetDefinition( + cmStrCat("CMAKE_", lang, "_DEPENDS_USE_COMPILER"))); + auto scanner = compilerGenerateDeps ? cmDependencyScannerKind::Compiler + : cmDependencyScannerKind::CMake; + // Get the full path name of the object file. std::string const& objectName = this->GeneratorTarget->GetObjectName(&source); @@ -511,7 +575,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string srcFullPath = cmSystemTools::CollapseFullPath(source.GetFullPath()); this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang, - objFullPath, srcFullPath); + objFullPath, srcFullPath, scanner); this->LocalGenerator->AppendRuleDepend(depends, this->FlagFileNameFull.c_str()); @@ -553,8 +617,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( depends.push_back( this->GeneratorTarget->GetPchFile(config, lang, arch)); } - this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, lang, - objFullPath, pchHeader); + this->LocalGenerator->AddImplicitDepends( + this->GeneratorTarget, lang, objFullPath, pchHeader, scanner); } } @@ -573,6 +637,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Build the set of compiler flags. std::string flags; + // Explicitly add the explicit language flag before any other flag + // so user flags can override it. + this->GeneratorTarget->AddExplicitLanguageFlags(flags, source); + // Add language-specific flags. std::string langFlags = cmStrCat("$(", lang, "_FLAGS", filterArch, ")"); this->LocalGenerator->AppendFlags(flags, langFlags); @@ -693,7 +761,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( source.GetFullPath(), cmOutputConverter::SHELL); // Construct the build message. - std::vector<std::string> no_commands; + std::vector<std::string> no_depends; std::vector<std::string> commands; // add in a progress call if needed @@ -787,13 +855,34 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( "$(" + lang + "_INCLUDES)"); vars.Includes = includesString.c_str(); + std::string dependencyTarget; + std::string shellDependencyFile; + std::string dependencyTimestamp; + if (compilerGenerateDeps) { + dependencyTarget = this->LocalGenerator->EscapeForShell( + this->LocalGenerator->ConvertToMakefilePath( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), relativeObj))); + vars.DependencyTarget = dependencyTarget.c_str(); + + auto depFile = cmStrCat(obj, ".d"); + shellDependencyFile = this->LocalGenerator->ConvertToOutputFormat( + depFile, cmOutputConverter::SHELL); + vars.DependencyFile = shellDependencyFile.c_str(); + this->CleanFiles.insert(depFile); + + dependencyTimestamp = this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")); + } + // At the moment, it is assumed that C, C++, Fortran, and CUDA have both // assembly and preprocessor capabilities. The same is true for the // ability to export compile commands bool lang_has_preprocessor = ((lang == "C") || (lang == "CXX") || (lang == "OBJC") || (lang == "OBJCXX") || (lang == "Fortran") || (lang == "CUDA") || - lang == "ISPC"); + lang == "ISPC" || lang == "ASM"); bool const lang_has_assembly = lang_has_preprocessor; bool const lang_can_export_cmds = lang_has_preprocessor; @@ -824,7 +913,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmExpandList(compileRule, compileCommands); } - if (this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS") && + if (this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS") && lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; @@ -875,15 +964,21 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } // Maybe insert an include-what-you-use runner. - if (!compileCommands.empty() && (lang == "C" || lang == "CXX")) { - std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; - cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + if (!compileCommands.empty() && + (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) { std::string const tidy_prop = lang + "_CLANG_TIDY"; cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop); - std::string const cpplint_prop = lang + "_CPPLINT"; - cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); - std::string const cppcheck_prop = lang + "_CPPCHECK"; - cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + cmProp iwyu = nullptr; + cmProp cpplint = nullptr; + cmProp cppcheck = nullptr; + if (lang == "C" || lang == "CXX") { + std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; + iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + std::string const cpplint_prop = lang + "_CPPLINT"; + cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); + std::string const cppcheck_prop = lang + "_CPPCHECK"; + cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + } if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) { std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile"; @@ -945,10 +1040,57 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string launcher; { - const char* val = this->LocalGenerator->GetRuleLauncher( + cmProp val = this->LocalGenerator->GetRuleLauncher( this->GeneratorTarget, "RULE_LAUNCH_COMPILE"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); + } + } + + std::string flagsWithDeps(flags); + + if (compilerGenerateDeps) { + // Injects dependency computation + auto depFlags = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_DEPFILE_FLAGS_", lang)); + + if (!depFlags.empty()) { + // Add dependency flags + rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, + depFlags, vars); + flagsWithDeps.append(1, ' '); + flagsWithDeps.append(depFlags); + } + vars.Flags = flagsWithDeps.c_str(); + + const auto& extraCommands = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS")); + if (!extraCommands.empty()) { + auto commandList = cmExpandedList(extraCommands); + compileCommands.insert(compileCommands.end(), commandList.cbegin(), + commandList.cend()); + } + + const auto& depFormat = this->Makefile->GetRequiredDefinition( + cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT")); + + if (depFormat == "msvc"_s) { + // compiler must be launched through a wrapper to pick-up dependencies + std::string depFilter = + "$(CMAKE_COMMAND) -E cmake_cl_compile_depends "; + depFilter += cmStrCat("--dep-file=", shellDependencyFile); + depFilter += + cmStrCat(" --working-dir=", + this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->GetCurrentBinaryDirectory(), + cmOutputConverter::SHELL)); + const auto& prefix = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_CL_SHOWINCLUDES_PREFIX")); + depFilter += cmStrCat(" --filter-prefix=", + this->LocalGenerator->ConvertToOutputFormat( + prefix, cmOutputConverter::SHELL)); + depFilter += " -- "; + compileCommands.front().insert(0, depFilter); } } @@ -977,8 +1119,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmExpandList(evaluated_outputs, outputs); } } - if (!ispcHeaderRelative - .empty()) { // can't move ispcHeader as vars is using it + if (!ispcHeaderRelative.empty()) { + // can't move ispcHeader as vars is using it outputs.emplace_back(ispcHeaderRelative); } @@ -986,10 +1128,19 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( this->CleanFiles.insert(outputs.begin() + 1, outputs.end()); } + if (compilerGenerateDeps) { + depends.push_back(dependencyTimestamp); + } + // Write the rule. this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, commands); + if (compilerGenerateDeps) { + // set back flags without dependency generation + vars.Flags = flags.c_str(); + } + bool do_preprocess_rules = lang_has_preprocessor && this->LocalGenerator->GetCreatePreprocessedSourceRules(); bool do_assembly_rules = @@ -1386,10 +1537,10 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( std::string registerFileCmd; - // The generated register file contains macros that when expanded register - // the device routines. Because the routines are the same for all - // architectures the register file will be the same too. Thus generate it - // only on the first invocation to reduce overhead. + // The generated register file contains macros that when expanded + // register the device routines. Because the routines are the same for + // all architectures the register file will be the same too. Thus + // generate it only on the first invocation to reduce overhead. if (fatbinaryDepends.size() == 1) { std::string registerFileRel = this->LocalGenerator->MaybeConvertToRelativePath( @@ -1424,7 +1575,8 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( fatbinaryOutputRel, fatbinaryDepends, { fatbinaryCommand }, false); - // Compile the stub that registers the kernels and contains the fatbinaries. + // Compile the stub that registers the kernels and contains the + // fatbinaries. cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = @@ -1481,6 +1633,16 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( std::vector<std::string> depends; this->LocalGenerator->AppendCustomDepend(depends, ccg); + if (!ccg.GetCC().GetDepfile().empty()) { + // Add dependency over timestamp file for dependencies management + auto dependTimestamp = cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"))); + + depends.push_back(dependTimestamp); + } + // Write the rule. const std::vector<std::string>& outputs = ccg.GetOutputs(); bool symbolic = this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, @@ -1517,6 +1679,15 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile( objFullPath, srcFullPath); } + // Setup implicit depend for depfile if any + if (!ccg.GetCC().GetDepfile().empty()) { + std::string objFullPath = cmSystemTools::CollapseFullPath( + outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory()); + this->LocalGenerator->AddImplicitDepends( + this->GeneratorTarget, "CUSTOM", objFullPath, ccg.GetFullDepfile(), + cmDependencyScannerKind::Compiler); + } + this->CustomCommandOutputs.insert(outputs.begin(), outputs.end()); } @@ -1542,12 +1713,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( << this->GeneratorTarget->GetName() << "\n" << variableName << " ="; std::string object; - std::string lineContinue; - if (cmProp p = this->Makefile->GetDefinition("CMAKE_MAKE_LINE_CONTINUE")) { - lineContinue = *p; - } else { - lineContinue = "\\"; - } + const auto& lineContinue = this->GlobalGenerator->LineContinueDirective; cmProp pchExtension = this->Makefile->GetDefinition("CMAKE_PCH_EXTENSION"); @@ -1555,7 +1721,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( if (cmSystemTools::StringEndsWith(obj, cmToCStr(pchExtension))) { continue; } - *this->BuildFileStream << " " << lineContinue << "\n"; + *this->BuildFileStream << " " << lineContinue; *this->BuildFileStream << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( obj, useWatcomQuote); @@ -1578,7 +1744,7 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( for (std::string const& obj : this->ExternalObjects) { object = this->LocalGenerator->MaybeConvertToRelativePath(currentBinDir, obj); - *this->BuildFileStream << " " << lineContinue << "\n"; + *this->BuildFileStream << " " << lineContinue; *this->BuildFileStream << cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath( obj, useWatcomQuote); @@ -1842,9 +2008,9 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects( if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) { // Compute the total length of our list of object files with room // for argument separation and quoting. This does not convert paths - // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the - // actual list will likely be much shorter than this. However, in the - // worst case all objects will remain as absolute paths. + // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so + // the actual list will likely be much shorter than this. However, in + // the worst case all objects will remain as absolute paths. size_t length = 0; for (std::string const& obj : this->Objects) { length += obj.size() + 3; diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index 6c18e48..a885b17 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -15,6 +15,7 @@ #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmOSXBundleGenerator.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator( @@ -36,10 +37,42 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles() *this->BuildFileStream << "# Utility rule file for " << this->GeneratorTarget->GetName() << ".\n\n"; + const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT") + ? "$(CMAKE_BINARY_DIR)/" + : ""); + + // Include the dependencies for the target. + std::string dependFile = + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make"); + *this->BuildFileStream + << "# Include any custom commands dependencies for this target.\n" + << this->GlobalGenerator->IncludeDirective << " " << root + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->MaybeConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), dependFile)) + << "\n\n"; + if (!cmSystemTools::FileExists(dependFile)) { + // Write an empty dependency file. + cmGeneratedFileStream depFileStream( + dependFile, false, this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# Empty custom commands generated dependencies file for " + << this->GeneratorTarget->GetName() << ".\n" + << "# This may be replaced when dependencies are built.\n"; + } + + std::string dependTimestamp = + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts"); + if (!cmSystemTools::FileExists(dependTimestamp)) { + // Write a dependency timestamp file. + cmGeneratedFileStream depFileStream( + dependTimestamp, false, this->GlobalGenerator->GetMakefileEncoding()); + depFileStream << "# CMAKE generated file: DO NOT EDIT!\n" + << "# Timestamp file for custom commands dependencies " + "management for " + << this->GeneratorTarget->GetName() << ".\n"; + } + if (!this->NoRuleMessages) { - const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT") - ? "$(CMAKE_BINARY_DIR)/" - : ""); // Include the progress variables for the target. *this->BuildFileStream << "# Include the progress variables for this target.\n" diff --git a/Source/cmNewLineStyle.cxx b/Source/cmNewLineStyle.cxx index a121332..28baeb6 100644 --- a/Source/cmNewLineStyle.cxx +++ b/Source/cmNewLineStyle.cxx @@ -8,13 +8,13 @@ cmNewLineStyle::cmNewLineStyle() = default; bool cmNewLineStyle::IsValid() const { - return NewLineStyle != Invalid; + return this->NewLineStyle != Invalid; } bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args, std::string& errorString) { - NewLineStyle = Invalid; + this->NewLineStyle = Invalid; for (size_t i = 0; i < args.size(); i++) { if (args[i] == "NEWLINE_STYLE") { @@ -22,11 +22,11 @@ bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args, if (args.size() > styleIndex) { std::string const& eol = args[styleIndex]; if (eol == "LF" || eol == "UNIX") { - NewLineStyle = LF; + this->NewLineStyle = LF; return true; } if (eol == "CRLF" || eol == "WIN32" || eol == "DOS") { - NewLineStyle = CRLF; + this->NewLineStyle = CRLF; return true; } errorString = "NEWLINE_STYLE sets an unknown style, only LF, " @@ -43,7 +43,7 @@ bool cmNewLineStyle::ReadFromArguments(const std::vector<std::string>& args, std::string cmNewLineStyle::GetCharacters() const { - switch (NewLineStyle) { + switch (this->NewLineStyle) { case Invalid: return ""; case LF: @@ -56,10 +56,10 @@ std::string cmNewLineStyle::GetCharacters() const void cmNewLineStyle::SetStyle(Style style) { - NewLineStyle = style; + this->NewLineStyle = style; } cmNewLineStyle::Style cmNewLineStyle::GetStyle() const { - return NewLineStyle; + return this->NewLineStyle; } diff --git a/Source/cmNinjaLinkLineComputer.cxx b/Source/cmNinjaLinkLineComputer.cxx index 7fbeeea..2304ad2 100644 --- a/Source/cmNinjaLinkLineComputer.cxx +++ b/Source/cmNinjaLinkLineComputer.cxx @@ -18,5 +18,5 @@ cmNinjaLinkLineComputer::cmNinjaLinkLineComputer( std::string cmNinjaLinkLineComputer::ConvertToLinkReference( std::string const& lib) const { - return GG->ConvertToNinjaPath(lib); + return this->GG->ConvertToNinjaPath(lib); } diff --git a/Source/cmNinjaLinkLineDeviceComputer.cxx b/Source/cmNinjaLinkLineDeviceComputer.cxx index 84c1b37..f66e2f5 100644 --- a/Source/cmNinjaLinkLineDeviceComputer.cxx +++ b/Source/cmNinjaLinkLineDeviceComputer.cxx @@ -16,5 +16,5 @@ cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer( std::string cmNinjaLinkLineDeviceComputer::ConvertToLinkReference( std::string const& lib) const { - return GG->ConvertToNinjaPath(lib); + return this->GG->ConvertToNinjaPath(lib); } diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index ccb959b..620b8ff 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -49,7 +49,7 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator( // on Windows the output dir is already needed at compile time // ensure the directory exists (OutDir test) for (auto const& config : this->GetConfigNames()) { - EnsureDirectoryExists(target->GetDirectory(config)); + this->EnsureDirectoryExists(target->GetDirectory(config)); } } @@ -266,10 +266,10 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule( vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS"; std::string launcher; - const char* val = this->GetLocalGenerator()->GetRuleLauncher( + cmProp val = this->GetLocalGenerator()->GetRuleLauncher( this->GetGeneratorTarget(), "RULE_LAUNCH_LINK"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( @@ -306,7 +306,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules( { const cmMakefile* mf = this->GetMakefile(); - cmNinjaRule rule(LanguageLinkerCudaDeviceRule(config)); + cmNinjaRule rule(this->LanguageLinkerCudaDeviceRule(config)); rule.Command = this->GetLocalGenerator()->BuildCommandLine( { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_DEVICE_LINKER"), " -arch=$ARCH $REGISTER -o=$out $in") }); @@ -334,13 +334,13 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules( rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), compileCmd, vars); - rule.Name = LanguageLinkerCudaDeviceCompileRule(config); + rule.Name = this->LanguageLinkerCudaDeviceCompileRule(config); rule.Command = this->GetLocalGenerator()->BuildCommandLine({ compileCmd }); rule.Comment = "Rule for compiling CUDA device stubs."; rule.Description = "Compiling CUDA device stub $out"; this->GetGlobalGenerator()->AddRule(rule); - rule.Name = LanguageLinkerCudaFatbinaryRule(config); + rule.Name = this->LanguageLinkerCudaFatbinaryRule(config); rule.Command = this->GetLocalGenerator()->BuildCommandLine( { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_FATBINARY"), " -64 -cmdline=--compile-only -compress-all -link " @@ -385,7 +385,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, // build response file name std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG"; - cmProp flag = GetMakefile()->GetDefinition(cmakeLinkVar); + cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar); if (flag) { responseFlag = *flag; @@ -452,10 +452,10 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, } std::string launcher; - const char* val = this->GetLocalGenerator()->GetRuleLauncher( + cmProp val = this->GetLocalGenerator()->GetRuleLauncher( this->GetGeneratorTarget(), "RULE_LAUNCH_LINK"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( @@ -673,7 +673,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( targetOutputDir = globalGen->ExpandCFGIntDir(targetOutputDir, config); std::string targetOutputReal = - ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt); + this->ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt); if (firstForConfig) { globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal); @@ -730,7 +730,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements( this->GetGlobalGenerator()->ConfigDirectory(config)); const std::string ninjaOutputDir = this->ConvertToNinjaPath(objectDir); - cmNinjaBuild fatbinary(LanguageLinkerCudaFatbinaryRule(config)); + cmNinjaBuild fatbinary(this->LanguageLinkerCudaFatbinaryRule(config)); // Link device code for each architecture. for (const std::string& architectureKind : architectures) { @@ -744,7 +744,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements( cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin); fatbinary.ExplicitDeps.emplace_back(cubin); - cmNinjaBuild dlink(LanguageLinkerCudaDeviceRule(config)); + cmNinjaBuild dlink(this->LanguageLinkerCudaDeviceRule(config)); dlink.ExplicitDeps = explicitDeps; dlink.Outputs = { cubin }; dlink.Variables["ARCH"] = cmStrCat("sm_", architecture); @@ -767,7 +767,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements( fatbinary); // Compile the stub that registers the kernels and contains the fatbinaries. - cmNinjaBuild dcompile(LanguageLinkerCudaDeviceCompileRule(config)); + cmNinjaBuild dcompile(this->LanguageLinkerCudaDeviceCompileRule(config)); dcompile.Outputs = { output }; dcompile.ExplicitDeps = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") }; dcompile.Variables["FATBIN"] = @@ -787,7 +787,7 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement( cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator(); - std::string targetOutputImplib = ConvertToNinjaPath( + std::string targetOutputImplib = this->ConvertToNinjaPath( genTarget->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); if (config != fileConfig) { @@ -806,7 +806,7 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement( ->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact) .empty() && targetOutputImplib == - ConvertToNinjaPath(genTarget->GetFullPath( + this->ConvertToNinjaPath(genTarget->GetFullPath( fileConfig, cmStateEnums::ImportLibraryArtifact))) { return; } @@ -882,16 +882,16 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement( const std::string impLibPath = localGen.ConvertToOutputFormat( targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; - EnsureParentDirectoryExists(impLibPath); + this->EnsureParentDirectoryExists(impLibPath); } const std::string objPath = - cmStrCat(GetGeneratorTarget()->GetSupportDirectory(), + cmStrCat(this->GetGeneratorTarget()->GetSupportDirectory(), globalGen->ConfigDirectory(config)); vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); - EnsureDirectoryExists(objPath); + this->EnsureDirectoryExists(objPath); this->SetMsvcTargetPdbVariable(vars, config); @@ -933,21 +933,22 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator(); cmGeneratorTarget* gt = this->GetGeneratorTarget(); - std::string targetOutput = ConvertToNinjaPath(gt->GetFullPath(config)); - std::string targetOutputReal = ConvertToNinjaPath( + std::string targetOutput = this->ConvertToNinjaPath(gt->GetFullPath(config)); + std::string targetOutputReal = this->ConvertToNinjaPath( gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, /*realname=*/true)); - std::string targetOutputImplib = ConvertToNinjaPath( + std::string targetOutputImplib = this->ConvertToNinjaPath( gt->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); if (config != fileConfig) { - if (targetOutput == ConvertToNinjaPath(gt->GetFullPath(fileConfig))) { + if (targetOutput == + this->ConvertToNinjaPath(gt->GetFullPath(fileConfig))) { return; } if (targetOutputReal == - ConvertToNinjaPath(gt->GetFullPath(fileConfig, - cmStateEnums::RuntimeBinaryArtifact, - /*realname=*/true))) { + this->ConvertToNinjaPath( + gt->GetFullPath(fileConfig, cmStateEnums::RuntimeBinaryArtifact, + /*realname=*/true))) { return; } if (!gt->GetFullName(config, cmStateEnums::ImportLibraryArtifact) @@ -955,7 +956,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( !gt->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact) .empty() && targetOutputImplib == - ConvertToNinjaPath(gt->GetFullPath( + this->ConvertToNinjaPath(gt->GetFullPath( fileConfig, cmStateEnums::ImportLibraryArtifact))) { return; } @@ -1095,7 +1096,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( std::vector<std::string> extraISPCObjects = this->GetGeneratorTarget()->GetGeneratedISPCObjects(config); std::transform(extraISPCObjects.begin(), extraISPCObjects.end(), - std::back_inserter(linkBuild.ExplicitDeps), MapToNinjaPath()); + std::back_inserter(linkBuild.ExplicitDeps), + this->MapToNinjaPath()); linkBuild.ImplicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage(config), config); @@ -1189,7 +1191,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( const std::string impLibPath = localGen.ConvertToOutputFormat( targetOutputImplib, cmOutputConverter::SHELL); vars["TARGET_IMPLIB"] = impLibPath; - EnsureParentDirectoryExists(impLibPath); + this->EnsureParentDirectoryExists(impLibPath); if (gt->HasImportLibrary(config)) { byproducts.push_back(targetOutputImplib); if (firstForConfig) { @@ -1218,7 +1220,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmStrCat(gt->GetSupportDirectory(), globalGen->ConfigDirectory(config)); vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); - EnsureDirectoryExists(objPath); + this->EnsureDirectoryExists(objPath); std::string& linkLibraries = vars["LINK_LIBRARIES"]; std::string& link_path = vars["LINK_PATH"]; @@ -1247,11 +1249,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]); std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); std::transform(ccByproducts.begin(), ccByproducts.end(), - std::back_inserter(byproducts), MapToNinjaPath()); + std::back_inserter(byproducts), this->MapToNinjaPath()); std::transform( ccByproducts.begin(), ccByproducts.end(), std::back_inserter(globalGen->GetByproductsForCleanTarget()), - MapToNinjaPath()); + this->MapToNinjaPath()); } } } @@ -1272,7 +1274,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmd += this->GetLocalGenerator()->ConvertToOutputFormat( obj_list_file, cmOutputConverter::SHELL); - cmProp nm_executable = GetMakefile()->GetDefinition("CMAKE_NM"); + cmProp nm_executable = this->GetMakefile()->GetDefinition("CMAKE_NM"); if (cmNonempty(nm_executable)) { cmd += " --nm="; cmd += this->LocalCommonGenerator->ConvertToOutputFormat( @@ -1325,7 +1327,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( // build response file name std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG"; - cmProp flag = GetMakefile()->GetDefinition(cmakeLinkVar); + cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar); bool const lang_supports_response = !(this->TargetLinkLanguage(config) == "RC" || diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index d41cbd2..672b579 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -12,7 +12,9 @@ #include <utility> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> #include <cm3p/json/value.h> #include <cm3p/json/writer.h> @@ -33,6 +35,7 @@ #include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" +#include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -105,7 +108,7 @@ std::string cmNinjaTargetGenerator::LanguageCompilerRule( '_', config); } -std::string cmNinjaTargetGenerator::LanguagePreprocessRule( +std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule( std::string const& lang, const std::string& config) const { return cmStrCat( @@ -114,7 +117,7 @@ std::string cmNinjaTargetGenerator::LanguagePreprocessRule( '_', config); } -std::string cmNinjaTargetGenerator::LanguageDependencyRule( +std::string cmNinjaTargetGenerator::LanguageScanRule( std::string const& lang, const std::string& config) const { return cmStrCat( @@ -129,14 +132,7 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing( return lang == "Fortran"; } -bool cmNinjaTargetGenerator::UsePreprocessedSource( - std::string const& lang) const -{ - return lang == "Fortran"; -} - -bool cmNinjaTargetGenerator::CompilePreprocessedSourceWithDefines( - std::string const& lang) const +bool cmNinjaTargetGenerator::CompileWithDefines(std::string const& lang) const { return this->Makefile->IsOn( cmStrCat("CMAKE_", lang, "_COMPILE_WITH_DEFINES")); @@ -151,9 +147,26 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule( '_', config); } -bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const +bool cmNinjaTargetGenerator::NeedCxxModuleSupport( + std::string const& lang, std::string const& config) const { - return lang == "Fortran"; + if (lang != "CXX") { + return false; + } + if (!this->Makefile->IsOn("CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP")) { + return false; + } + cmGeneratorTarget const* tgt = this->GetGeneratorTarget(); + cmStandardLevelResolver standardResolver(this->Makefile); + bool const uses_cxx20 = + standardResolver.HaveStandardAvailable(tgt, "CXX", config, "cxx_std_20"); + return uses_cxx20 && this->GetGlobalGenerator()->CheckCxxModuleSupport(); +} + +bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang, + std::string const& config) const +{ + return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config); } std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget( @@ -190,7 +203,15 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( } } - std::string flags = this->GetFlags(language, config, filterArch); + std::string flags; + // Explicitly add the explicit language flag before any other flag + // so user flags can override it. + this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source); + + if (!flags.empty()) { + flags += " "; + } + flags += this->GetFlags(language, config, filterArch); // Add Fortran format flags. if (language == "Fortran") { @@ -252,32 +273,6 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, this->LocalGenerator->AppendFlags(languageFlags, includeFlags); } -bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const -{ - std::string const& deptype = this->GetMakefile()->GetSafeDefinition( - cmStrCat("CMAKE_NINJA_DEPTYPE_", lang)); - if (deptype == "msvc") { - return true; - } - if (deptype == "intel") { - // Ninja does not really define "intel", but we use it to switch based - // on whether this environment supports "gcc" or "msvc" deptype. - if (!this->GetGlobalGenerator()->SupportsMultilineDepfile()) { - // This ninja version is too old to support the Intel depfile format. - // Fall back to msvc deptype. - return true; - } - if ((this->Makefile->GetHomeDirectory().find(' ') != std::string::npos) || - (this->Makefile->GetHomeOutputDirectory().find(' ') != - std::string::npos)) { - // The Intel compiler does not properly escape spaces in a depfile. - // Fall back to msvc deptype. - return true; - } - } - return false; -} - // TODO: Refactor with // void cmMakefileTargetGenerator::WriteTargetLanguageFlags(). std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, @@ -355,7 +350,8 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( const std::vector<std::string>& deps = cli->GetDepends(); cmNinjaDeps result(deps.size()); - std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath()); + std::transform(deps.begin(), deps.end(), result.begin(), + this->MapToNinjaPath()); // Add a dependency on the link definitions file, if any. if (cmGeneratorTarget::ModuleDefinitionInfo const* mdi = @@ -376,7 +372,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( std::vector<std::string> linkDeps; this->GeneratorTarget->GetLinkDepends(linkDeps, config, linkLanguage); std::transform(linkDeps.begin(), linkDeps.end(), std::back_inserter(result), - MapToNinjaPath()); + this->MapToNinjaPath()); return result; } @@ -384,7 +380,7 @@ cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps( std::string cmNinjaTargetGenerator::GetSourceFilePath( cmSourceFile const* source) const { - return ConvertToNinjaPath(source->GetFullPath()); + return this->ConvertToNinjaPath(source->GetFullPath()); } std::string cmNinjaTargetGenerator::GetObjectFilePath( @@ -465,7 +461,7 @@ std::string cmNinjaTargetGenerator::GetTargetOutputDir( const std::string& config) const { std::string dir = this->GeneratorTarget->GetDirectory(config); - return ConvertToNinjaPath(dir); + return this->ConvertToNinjaPath(dir); } std::string cmNinjaTargetGenerator::GetTargetFilePath( @@ -502,13 +498,13 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable( } vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( - ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL); + this->ConvertToNinjaPath(pdbPath), cmOutputConverter::SHELL); vars["TARGET_COMPILE_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( - ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL); + this->ConvertToNinjaPath(compilePdbPath), cmOutputConverter::SHELL); - EnsureParentDirectoryExists(pdbPath); - EnsureParentDirectoryExists(compilePdbPath); + this->EnsureParentDirectoryExists(pdbPath); + this->EnsureParentDirectoryExists(compilePdbPath); return true; } return false; @@ -527,82 +523,62 @@ namespace { // Create the command to run the dependency scanner std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi, const std::string& lang, const std::string& ppFile, - bool needDyndep, const std::string& ddiFile) + const std::string& ddiFile) { - std::string ccmd = - cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, " --lang=", lang, - " --pp=", ppFile, " --dep=$DEP_FILE"); - if (needDyndep) { - ccmd = cmStrCat(ccmd, " --obj=$OBJ_FILE --ddi=", ddiFile); - } - return ccmd; + return cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, + " --lang=", lang, " --src=$in", " --pp=", ppFile, + " --dep=$DEP_FILE --obj=$OBJ_FILE --ddi=", ddiFile); } -// Helper function to create dependency scanning rule, with optional -// explicit preprocessing step if preprocessCommand is non-empty -cmNinjaRule GetPreprocessScanRule( - const std::string& ruleName, cmRulePlaceholderExpander::RuleVariables& vars, +// Helper function to create dependency scanning rule that may or may +// not perform explicit preprocessing too. +cmNinjaRule GetScanRule( + const std::string& ruleName, + cmRulePlaceholderExpander::RuleVariables const& vars, const std::string& responseFlag, const std::string& flags, - const std::string& launcher, cmRulePlaceholderExpander* const rulePlaceholderExpander, - std::string scanCommand, cmLocalNinjaGenerator* generator, - const std::string& preprocessCommand = "") + cmLocalNinjaGenerator* generator, std::vector<std::string> scanCmds) { cmNinjaRule rule(ruleName); - // Explicit preprocessing always uses a depfile. + // Scanning always uses a depfile for preprocessor dependencies. rule.DepType = ""; // no deps= for multiple outputs rule.DepFile = "$DEP_FILE"; - cmRulePlaceholderExpander::RuleVariables ppVars; - ppVars.CMTargetName = vars.CMTargetName; - ppVars.CMTargetType = vars.CMTargetType; - ppVars.Language = vars.Language; - ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE - ppVars.PreprocessedSource = "$out"; - ppVars.DependencyFile = rule.DepFile.c_str(); - - // Preprocessing uses the original source, compilation uses - // preprocessed output or original source - ppVars.Source = vars.Source; - vars.Source = "$in"; - - // Copy preprocessor definitions to the preprocessor rule. - ppVars.Defines = vars.Defines; + cmRulePlaceholderExpander::RuleVariables scanVars; + scanVars.CMTargetName = vars.CMTargetName; + scanVars.CMTargetType = vars.CMTargetType; + scanVars.Language = vars.Language; + scanVars.Object = "$OBJ_FILE"; + scanVars.PreprocessedSource = "$out"; + scanVars.DynDepFile = "$DYNDEP_INTERMEDIATE_FILE"; + scanVars.DependencyFile = rule.DepFile.c_str(); + scanVars.DependencyTarget = "$out"; - // Copy include directories to the preprocessor rule. The Fortran - // compilation rule still needs them for the INCLUDE directive. - ppVars.Includes = vars.Includes; + // Scanning needs the same preprocessor settings as direct compilation would. + scanVars.Source = vars.Source; + scanVars.Defines = vars.Defines; + scanVars.Includes = vars.Includes; - // Preprocessing and compilation use the same flags. - std::string ppFlags = flags; + // Scanning needs the compilation flags too. + std::string scanFlags = flags; // If using a response file, move defines, includes, and flags into it. if (!responseFlag.empty()) { rule.RspFile = "$RSP_FILE"; rule.RspContent = - cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags); - ppFlags = cmStrCat(responseFlag, rule.RspFile); - ppVars.Defines = ""; - ppVars.Includes = ""; + cmStrCat(' ', scanVars.Defines, ' ', scanVars.Includes, ' ', scanFlags); + scanFlags = cmStrCat(responseFlag, rule.RspFile); + scanVars.Defines = ""; + scanVars.Includes = ""; } - ppVars.Flags = ppFlags.c_str(); - - // Rule for preprocessing source file. - std::vector<std::string> ppCmds; + scanVars.Flags = scanFlags.c_str(); - if (!preprocessCommand.empty()) { - // Lookup the explicit preprocessing rule. - cmExpandList(preprocessCommand, ppCmds); - for (std::string& i : ppCmds) { - i = cmStrCat(launcher, i); - rulePlaceholderExpander->ExpandRuleVariables(generator, i, ppVars); - } + // Rule for scanning a source file. + for (std::string& scanCmd : scanCmds) { + rulePlaceholderExpander->ExpandRuleVariables(generator, scanCmd, scanVars); } - - // Run CMake dependency scanner on either preprocessed output or source file - ppCmds.emplace_back(std::move(scanCommand)); - rule.Command = generator->BuildCommandLine(ppCmds); + rule.Command = generator->BuildCommandLine(scanCmds); return rule; } @@ -628,11 +604,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, cmMakefile* mf = this->GetMakefile(); - // For some cases we do an explicit preprocessor invocation. - bool const explicitPP = this->NeedExplicitPreprocessing(lang); - bool const compilePPWithDefines = this->UsePreprocessedSource(lang) && - this->CompilePreprocessedSourceWithDefines(lang); - bool const needDyndep = this->NeedDyndep(lang); + // For some cases we scan to dynamically discover dependencies. + bool const needDyndep = this->NeedDyndep(lang, config); + bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang); std::string flags = "$FLAGS"; @@ -646,65 +620,97 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, responseFlag = "@"; } } + std::string const modmapFormatVar = + cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FORMAT"); + std::string const modmapFormat = + this->Makefile->GetSafeDefinition(modmapFormatVar); std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( this->GetLocalGenerator()->CreateRulePlaceholderExpander()); std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat( - ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)), + this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)), cmLocalGenerator::SHELL); std::string launcher; - const char* val = this->GetLocalGenerator()->GetRuleLauncher( + cmProp val = this->GetLocalGenerator()->GetRuleLauncher( this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE"); if (cmNonempty(val)) { - launcher = cmStrCat(val, ' '); + launcher = cmStrCat(*val, ' '); } std::string const cmakeCmd = this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); - if (explicitPP) { - // Combined preprocessing and dependency scanning - const auto ppScanCommand = GetScanCommand( - cmakeCmd, tdi, lang, "$out", needDyndep, "$DYNDEP_INTERMEDIATE_FILE"); - const auto ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE"); - - auto ppRule = GetPreprocessScanRule( - this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags, - launcher, rulePlaceholderExpander.get(), ppScanCommand, - this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar)); - - // Write the rule for preprocessing file of the given language. - ppRule.Comment = cmStrCat("Rule for preprocessing ", lang, " files."); - ppRule.Description = cmStrCat("Building ", lang, " preprocessed $out"); + if (needDyndep) { + // Rule to scan dependencies of sources that need preprocessing. + { + std::vector<std::string> scanCommands; + std::string scanRuleName; + if (compilationPreprocesses) { + scanRuleName = this->LanguageScanRule(lang, config); + std::string const& scanCommand = mf->GetRequiredDefinition( + cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE")); + cmExpandList(scanCommand, scanCommands); + for (std::string& i : scanCommands) { + i = cmStrCat(launcher, i); + } + } else { + scanRuleName = this->LanguagePreprocessAndScanRule(lang, config); + std::string const& ppCommmand = mf->GetRequiredDefinition( + cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE")); + cmExpandList(ppCommmand, scanCommands); + for (std::string& i : scanCommands) { + i = cmStrCat(launcher, i); + } + scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out", + "$DYNDEP_INTERMEDIATE_FILE")); + } - this->GetGlobalGenerator()->AddRule(ppRule); + auto scanRule = GetScanRule( + scanRuleName, vars, responseFlag, flags, rulePlaceholderExpander.get(), + this->GetLocalGenerator(), std::move(scanCommands)); + + scanRule.Comment = + cmStrCat("Rule for generating ", lang, " dependencies."); + if (compilationPreprocesses) { + scanRule.Description = + cmStrCat("Scanning $in for ", lang, " dependencies"); + } else { + scanRule.Description = + cmStrCat("Building ", lang, " preprocessed $out"); + } - if (!compilePPWithDefines) { - // Remove preprocessor definitions from compilation step - vars.Defines = ""; + this->GetGlobalGenerator()->AddRule(scanRule); } - // Just dependency scanning for files that have preprocessing turned off - const auto scanCommand = - GetScanCommand(cmakeCmd, tdi, lang, "$in", needDyndep, "$out"); + if (!compilationPreprocesses) { + // Compilation will not preprocess, so it does not need the defines + // unless the compiler wants them for some other purpose. + if (!this->CompileWithDefines(lang)) { + vars.Defines = ""; + } - auto scanRule = GetPreprocessScanRule( - this->LanguageDependencyRule(lang, config), vars, "", flags, launcher, - rulePlaceholderExpander.get(), scanCommand, this->GetLocalGenerator()); + // Rule to scan dependencies of sources that do not need preprocessing. + std::string const& scanRuleName = this->LanguageScanRule(lang, config); + std::vector<std::string> scanCommands; + scanCommands.emplace_back( + GetScanCommand(cmakeCmd, tdi, lang, "$in", "$out")); - // Write the rule for generating dependencies for the given language. - scanRule.Comment = cmStrCat("Rule for generating ", lang, - " dependencies on non-preprocessed files."); - scanRule.Description = - cmStrCat("Generating ", lang, " dependencies for $in"); + auto scanRule = GetScanRule( + scanRuleName, vars, "", flags, rulePlaceholderExpander.get(), + this->GetLocalGenerator(), std::move(scanCommands)); - this->GetGlobalGenerator()->AddRule(scanRule); - } + // Write the rule for generating dependencies for the given language. + scanRule.Comment = cmStrCat("Rule for generating ", lang, + " dependencies on non-preprocessed files."); + scanRule.Description = + cmStrCat("Generating ", lang, " dependencies for $in"); + + this->GetGlobalGenerator()->AddRule(scanRule); + } - if (needDyndep) { // Write the rule for ninja dyndep file generation. cmNinjaRule rule(this->LanguageDyndepRule(lang, config)); // Command line length is almost always limited -> use response file for @@ -714,12 +720,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, // Run CMake dependency scanner on the source file (using the preprocessed // source if that was performed). + std::string ddModmapArg; + if (!modmapFormat.empty()) { + ddModmapArg += cmStrCat(" --modmapfmt=", modmapFormat); + } { std::vector<std::string> ddCmds; { - std::string ccmd = - cmStrCat(cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi, - " --lang=", lang, " --dd=$out @", rule.RspFile); + std::string ccmd = cmStrCat( + cmakeCmd, " -E cmake_ninja_dyndep --tdi=", tdi, " --lang=", lang, + ddModmapArg, " --dd=$out @", rule.RspFile); ddCmds.emplace_back(std::move(ccmd)); } rule.Command = this->GetLocalGenerator()->BuildCommandLine(ddCmds); @@ -743,12 +753,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, // Tell ninja dependency format so all deps can be loaded into a database std::string cldeps; - if (explicitPP) { - // The explicit preprocessing step will handle dependency scanning. - } else if (this->NeedDepTypeMSVC(lang)) { - rule.DepType = "msvc"; - rule.DepFile.clear(); - flags += " /showIncludes"; + if (!compilationPreprocesses) { + // The compiler will not do preprocessing, so it has no such dependencies. } else if (mf->IsOn(cmStrCat("CMAKE_NINJA_CMCLDEPS_", lang))) { // For the MS resource compiler we need cmcldeps, but skip dependencies // for source-file try_compile cases because they are always fresh. @@ -764,20 +770,35 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, "\" \"", cl, "\" "); } } else { - rule.DepType = "gcc"; - rule.DepFile = "$DEP_FILE"; + const auto& depType = this->GetMakefile()->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_DEPFILE_FORMAT")); + if (depType == "msvc"_s) { + rule.DepType = "msvc"; + rule.DepFile.clear(); + } else { + rule.DepType = "gcc"; + rule.DepFile = "$DEP_FILE"; + } + vars.DependencyFile = rule.DepFile.c_str(); + vars.DependencyTarget = "$out"; + const std::string flagsName = cmStrCat("CMAKE_DEPFILE_FLAGS_", lang); std::string depfileFlags = mf->GetSafeDefinition(flagsName); if (!depfileFlags.empty()) { - cmSystemTools::ReplaceString(depfileFlags, "<DEPFILE>", "$DEP_FILE"); - cmSystemTools::ReplaceString(depfileFlags, "<OBJECT>", "$out"); - cmSystemTools::ReplaceString( - depfileFlags, "<CMAKE_C_COMPILER>", - cmToCStr(mf->GetDefinition("CMAKE_C_COMPILER"))); + rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), + depfileFlags, vars); flags += cmStrCat(' ', depfileFlags); } } + if (needDyndep && !modmapFormat.empty()) { + std::string modmapFlags = mf->GetRequiredDefinition( + cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG")); + cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>", + "$DYNDEP_MODULE_MAP_FILE"); + flags += cmStrCat(' ', modmapFlags); + } + vars.Flags = flags.c_str(); vars.DependencyFile = rule.DepFile.c_str(); @@ -815,15 +836,21 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } // Maybe insert an include-what-you-use runner. - if (!compileCmds.empty() && (lang == "C" || lang == "CXX")) { - std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE"); - cmProp iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + if (!compileCmds.empty() && + (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) { std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY"); cmProp tidy = this->GeneratorTarget->GetProperty(tidy_prop); - std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT"); - cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); - std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK"); - cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + cmProp iwyu = nullptr; + cmProp cpplint = nullptr; + cmProp cppcheck = nullptr; + if (lang == "C" || lang == "CXX") { + std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE"); + iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT"); + cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); + std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK"); + cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + } if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) { std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile"); @@ -887,6 +914,14 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, compileCmds.front().insert(0, cldeps); } + const auto& extraCommands = this->GetMakefile()->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS")); + if (!extraCommands.empty()) { + auto commandList = cmExpandedList(extraCommands); + compileCmds.insert(compileCmds.end(), commandList.cbegin(), + commandList.cend()); + } + for (std::string& i : compileCmds) { i = cmStrCat(launcher, i); rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i, @@ -939,7 +974,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( config); } if (firstForConfig) { - cmProp pchExtension = GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); + cmProp pchExtension = + this->GetMakefile()->GetDefinition("CMAKE_PCH_EXTENSION"); std::vector<cmSourceFile const*> externalObjects; this->GeneratorTarget->GetExternalObjects(externalObjects, config); @@ -973,9 +1009,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( const std::vector<std::string>& ccoutputs = ccg.GetOutputs(); const std::vector<std::string>& ccbyproducts = ccg.GetByproducts(); std::transform(ccoutputs.begin(), ccoutputs.end(), - std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + std::back_inserter(orderOnlyDeps), + this->MapToNinjaPath()); std::transform(ccbyproducts.begin(), ccbyproducts.end(), - std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + std::back_inserter(orderOnlyDeps), + this->MapToNinjaPath()); } std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end()); @@ -1062,78 +1100,91 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( } namespace { -cmNinjaBuild GetPreprocessOrScanBuild( - const std::string& ruleName, const std::string& ppFileName, bool compilePP, - bool compilePPWithDefines, cmNinjaBuild& objBuild, cmNinjaVars& vars, - const std::string& depFileName, bool needDyndep, - const std::string& objectFileName) +cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, + const std::string& ppFileName, + bool compilePP, bool compilePPWithDefines, + cmNinjaBuild& objBuild, cmNinjaVars& vars, + std::string const& modmapFormat, + const std::string& objectFileName, + cmLocalGenerator* lg) { - // Explicit preprocessing and dependency - cmNinjaBuild ppBuild(ruleName); + cmNinjaBuild scanBuild(ruleName); if (!ppFileName.empty()) { - ppBuild.Outputs.push_back(ppFileName); - ppBuild.RspFile = cmStrCat(ppFileName, ".rsp"); + scanBuild.RspFile = cmStrCat(ppFileName, ".rsp"); } else { - ppBuild.RspFile = "$out.rsp"; + scanBuild.RspFile = "$out.rsp"; } if (compilePP) { - // Move compilation dependencies to the preprocessing build statement. - std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps); - std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps); - std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps); - std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]); + // Move compilation dependencies to the scan/preprocessing build statement. + std::swap(scanBuild.ExplicitDeps, objBuild.ExplicitDeps); + std::swap(scanBuild.ImplicitDeps, objBuild.ImplicitDeps); + std::swap(scanBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps); + std::swap(scanBuild.Variables["IN_ABS"], vars["IN_ABS"]); // The actual compilation will now use the preprocessed source. objBuild.ExplicitDeps.push_back(ppFileName); } else { - // Copy compilation dependencies to the preprocessing build statement. - ppBuild.ExplicitDeps = objBuild.ExplicitDeps; - ppBuild.ImplicitDeps = objBuild.ImplicitDeps; - ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps; - ppBuild.Variables["IN_ABS"] = vars["IN_ABS"]; + // Copy compilation dependencies to the scan/preprocessing build statement. + scanBuild.ExplicitDeps = objBuild.ExplicitDeps; + scanBuild.ImplicitDeps = objBuild.ImplicitDeps; + scanBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps; + scanBuild.Variables["IN_ABS"] = vars["IN_ABS"]; } - // Preprocessing and compilation generally use the same flags. - ppBuild.Variables["FLAGS"] = vars["FLAGS"]; + // Scanning and compilation generally use the same flags. + scanBuild.Variables["FLAGS"] = vars["FLAGS"]; if (compilePP && !compilePPWithDefines) { - // Move preprocessor definitions to the preprocessor build statement. - std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]); + // Move preprocessor definitions to the scan/preprocessor build statement. + std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]); } else { - // Copy preprocessor definitions to the preprocessor build statement. - ppBuild.Variables["DEFINES"] = vars["DEFINES"]; + // Copy preprocessor definitions to the scan/preprocessor build statement. + scanBuild.Variables["DEFINES"] = vars["DEFINES"]; } // Copy include directories to the preprocessor build statement. The // Fortran compilation build statement still needs them for the INCLUDE // directive. - ppBuild.Variables["INCLUDES"] = vars["INCLUDES"]; + scanBuild.Variables["INCLUDES"] = vars["INCLUDES"]; - // Explicit preprocessing always uses a depfile. - ppBuild.Variables["DEP_FILE"] = depFileName; + // Tell dependency scanner the object file that will result from + // compiling the source. + scanBuild.Variables["OBJ_FILE"] = objectFileName; + + // Tell dependency scanner where to store dyndep intermediate results. + std::string const& ddiFile = cmStrCat(objectFileName, ".ddi"); + scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; + + // Outputs of the scan/preprocessor build statement. + if (!ppFileName.empty()) { + scanBuild.Outputs.push_back(ppFileName); + scanBuild.ImplicitOuts.push_back(ddiFile); + } else { + scanBuild.Outputs.push_back(ddiFile); + } + + // Scanning always uses a depfile for preprocessor dependencies. + std::string const& depFileName = cmStrCat(scanBuild.Outputs.front(), ".d"); + scanBuild.Variables["DEP_FILE"] = + lg->ConvertToOutputFormat(depFileName, cmOutputConverter::SHELL); if (compilePP) { // The actual compilation does not need a depfile because it // depends on the already-preprocessed source. vars.erase("DEP_FILE"); } - if (needDyndep) { - // Tell dependency scanner the object file that will result from - // compiling the source. - ppBuild.Variables["OBJ_FILE"] = objectFileName; - - // Tell dependency scanner where to store dyndep intermediate results. - std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); - if (ppFileName.empty()) { - ppBuild.Outputs.push_back(ddiFile); - } else { - ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile; - ppBuild.ImplicitOuts.push_back(ddiFile); - } + if (!modmapFormat.empty()) { + // XXX(modmap): If changing this path construction, change + // `cmGlobalNinjaGenerator::WriteDyndep` to expect the corresponding + // file path. + std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap"); + scanBuild.Variables["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile; + scanBuild.ImplicitOuts.push_back(ddModmapFile); } - return ppBuild; + + return scanBuild; } } @@ -1157,7 +1208,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // build response file name std::string cmakeLinkVar = cmStrCat(cmakeVarLang, "_RESPONSE_FILE_FLAG"); - cmProp flag = GetMakefile()->GetDefinition(cmakeLinkVar); + cmProp flag = this->GetMakefile()->GetDefinition(cmakeLinkVar); bool const lang_supports_response = !(language == "RC" || (language == "CUDA" && !flag)); @@ -1170,7 +1221,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( vars["DEFINES"] = this->ComputeDefines(source, language, config); vars["INCLUDES"] = this->ComputeIncludes(source, language, config); - if (!this->NeedDepTypeMSVC(language)) { + if (this->GetMakefile()->GetSafeDefinition( + cmStrCat("CMAKE_", language, "_DEPFILE_FORMAT")) != "msvc"_s) { bool replaceExt(false); if (!language.empty()) { std::string repVar = @@ -1253,7 +1305,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } std::transform(depList.begin(), depList.end(), std::back_inserter(objBuild.ImplicitDeps), - MapToNinjaPath()); + this->MapToNinjaPath()); } objBuild.OrderOnlyDeps.push_back(this->OrderDependsTargetForTarget(config)); @@ -1270,13 +1322,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( sourceFileName, objBuild.OrderOnlyDeps); } - // For some cases we need to generate a ninja dyndep file. - bool const needDyndep = this->NeedDyndep(language); + // For some cases we scan to dynamically discover dependencies. + bool const needDyndep = this->NeedDyndep(language, config); + bool const compilationPreprocesses = + !this->NeedExplicitPreprocessing(language); - // For some cases we do an explicit preprocessor invocation. - bool const explicitPP = this->NeedExplicitPreprocessing(language); - if (explicitPP) { + std::string modmapFormat; + if (needDyndep) { + std::string const modmapFormatVar = + cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT"); + modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); + } + if (needDyndep) { // If source/target has preprocessing turned off, we still need to // generate an explicit dependency step const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS"); @@ -1288,27 +1346,24 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp); } - bool const compilePP = this->UsePreprocessedSource(language) && + bool const compilePP = !compilationPreprocesses && (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded); bool const compilePPWithDefines = - compilePP && this->CompilePreprocessedSourceWithDefines(language); - - std::string const ppFileName = compilePP - ? this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config)) - : ""; + compilePP && this->CompileWithDefines(language); - std::string const buildName = compilePP - ? this->LanguagePreprocessRule(language, config) - : this->LanguageDependencyRule(language, config); - - const auto depExtension = compilePP ? ".pp.d" : ".d"; - const std::string depFileName = - this->GetLocalGenerator()->ConvertToOutputFormat( - cmStrCat(objectFileName, depExtension), cmOutputConverter::SHELL); + std::string scanRuleName; + std::string ppFileName; + if (compilePP) { + scanRuleName = this->LanguagePreprocessAndScanRule(language, config); + ppFileName = this->ConvertToNinjaPath( + this->GetPreprocessedFilePath(source, config)); + } else { + scanRuleName = this->LanguageScanRule(language, config); + } - cmNinjaBuild ppBuild = GetPreprocessOrScanBuild( - buildName, ppFileName, compilePP, compilePPWithDefines, objBuild, vars, - depFileName, needDyndep, objectFileName); + cmNinjaBuild ppBuild = GetScanBuildStatement( + scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild, + vars, modmapFormat, objectFileName, this->LocalGenerator); if (compilePP) { // In case compilation requires flags that are incompatible with @@ -1330,7 +1385,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]); } - if (firstForConfig && needDyndep) { + if (firstForConfig) { std::string const ddiFile = cmStrCat(objectFileName, ".ddi"); this->Configs[config].DDIFiles[language].push_back(ddiFile); } @@ -1340,14 +1395,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), ppBuild, commandLineLengthLimit); - } - if (needDyndep) { + std::string const dyndep = this->GetDyndepFilePath(language, config); objBuild.OrderOnlyDeps.push_back(dyndep); vars["dyndep"] = dyndep; + + if (!modmapFormat.empty()) { + std::string const ddModmapFile = cmStrCat(objectFileName, ".modmap"); + vars["DYNDEP_MODULE_MAP_FILE"] = ddModmapFile; + objBuild.OrderOnlyDeps.push_back(ddModmapFile); + } } - EnsureParentDirectoryExists(objectFileName); + this->EnsureParentDirectoryExists(objectFileName); vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat( objectDir, cmOutputConverter::SHELL); @@ -1420,7 +1480,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( auto headers = this->GeneratorTarget->GetGeneratedISPCHeaders(config); if (!headers.empty()) { std::transform(headers.begin(), headers.end(), headers.begin(), - MapToNinjaPath()); + this->MapToNinjaPath()); objBuild.OrderOnlyDeps.insert(objBuild.OrderOnlyDeps.end(), headers.begin(), headers.end()); } @@ -1442,7 +1502,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( build.Comment = "Additional output files."; build.Outputs = cmExpandedList(evaluatedObjectOutputs); std::transform(build.Outputs.begin(), build.Outputs.end(), - build.Outputs.begin(), MapToNinjaPath()); + build.Outputs.begin(), this->MapToNinjaPath()); build.ExplicitDeps = objBuild.Outputs; this->GetGlobalGenerator()->WriteBuild( this->GetImplFileStream(fileConfig), build); @@ -1458,17 +1518,26 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, tdi["compiler-id"] = this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_COMPILER_ID")); + std::string mod_dir; if (lang == "Fortran") { - std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory( + mod_dir = this->GeneratorTarget->GetFortranModuleDirectory( this->Makefile->GetHomeOutputDirectory()); - if (mod_dir.empty()) { - mod_dir = this->Makefile->GetCurrentBinaryDirectory(); - } - tdi["module-dir"] = mod_dir; + } else if (lang == "CXX") { + mod_dir = + cmSystemTools::CollapseFullPath(this->GeneratorTarget->ObjectDirectory); + } + if (mod_dir.empty()) { + mod_dir = this->Makefile->GetCurrentBinaryDirectory(); + } + tdi["module-dir"] = mod_dir; + + if (lang == "Fortran") { tdi["submodule-sep"] = this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP"); tdi["submodule-ext"] = this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT"); + } else if (lang == "CXX") { + // No extra information necessary. } tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory(); @@ -1550,7 +1619,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( std::string const& objectFileDir, std::string const& flags, std::string const& defines, std::string const& includes) { - if (!this->Makefile->IsOn("CMAKE_EXPORT_COMPILE_COMMANDS")) { + if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) { return; } @@ -1662,7 +1731,7 @@ void cmNinjaTargetGenerator::EnsureDirectoryExists( void cmNinjaTargetGenerator::EnsureParentDirectoryExists( const std::string& path) const { - EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path)); + this->EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path)); } void cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()( diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index a27c9b4..79dc622 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -42,8 +42,6 @@ public: std::string GetTargetName() const; - bool NeedDepTypeMSVC(const std::string& lang) const; - protected: bool SetMsvcTargetPdbVariable(cmNinjaVars&, const std::string& config) const; @@ -67,16 +65,17 @@ protected: std::string LanguageCompilerRule(const std::string& lang, const std::string& config) const; - std::string LanguagePreprocessRule(std::string const& lang, - const std::string& config) const; - std::string LanguageDependencyRule(std::string const& lang, - const std::string& config) const; - bool NeedExplicitPreprocessing(std::string const& lang) const; + std::string LanguagePreprocessAndScanRule(std::string const& lang, + const std::string& config) const; + std::string LanguageScanRule(std::string const& lang, + const std::string& config) const; std::string LanguageDyndepRule(std::string const& lang, const std::string& config) const; - bool NeedDyndep(std::string const& lang) const; - bool UsePreprocessedSource(std::string const& lang) const; - bool CompilePreprocessedSourceWithDefines(std::string const& lang) const; + bool NeedDyndep(std::string const& lang, std::string const& config) const; + bool NeedExplicitPreprocessing(std::string const& lang) const; + bool CompileWithDefines(std::string const& lang) const; + bool NeedCxxModuleSupport(std::string const& lang, + std::string const& config) const; std::string OrderDependsTargetForTarget(const std::string& config); diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index ad1d5f1..3995624 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -5,6 +5,7 @@ #include <algorithm> #include <array> #include <iterator> +#include <set> #include <string> #include <utility> #include <vector> @@ -34,13 +35,30 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default; void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) { + for (auto const& fileConfig : this->GetConfigNames()) { + if (!this->GetGlobalGenerator() + ->GetCrossConfigs(fileConfig) + .count(config)) { + continue; + } + if (fileConfig != config && + this->GetGeneratorTarget()->GetType() == cmStateEnums::GLOBAL_TARGET) { + continue; + } + this->WriteUtilBuildStatements(config, fileConfig); + } +} + +void cmNinjaUtilityTargetGenerator::WriteUtilBuildStatements( + std::string const& config, std::string const& fileConfig) +{ cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator(); cmLocalNinjaGenerator* lg = this->GetLocalGenerator(); cmGeneratorTarget* genTarget = this->GetGeneratorTarget(); std::string configDir; if (genTarget->Target->IsPerConfig()) { - configDir = gg->ConfigDirectory(config); + configDir = gg->ConfigDirectory(fileConfig); } std::string utilCommandName = cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles", configDir, "/", @@ -60,12 +78,13 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) for (std::vector<cmCustomCommand> const* cmdList : cmdLists) { for (cmCustomCommand const& ci : *cmdList) { - cmCustomCommandGenerator ccg(ci, config, lg); - lg->AppendCustomCommandDeps(ccg, deps, config); + cmCustomCommandGenerator ccg(ci, fileConfig, lg); + lg->AppendCustomCommandDeps(ccg, deps, fileConfig); lg->AppendCustomCommandLines(ccg, commands); std::vector<std::string> const& ccByproducts = ccg.GetByproducts(); std::transform(ccByproducts.begin(), ccByproducts.end(), - std::back_inserter(util_outputs), MapToNinjaPath()); + std::back_inserter(util_outputs), + this->MapToNinjaPath()); if (ci.GetUsesTerminal()) { uses_terminal = true; } @@ -85,9 +104,9 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) const std::vector<std::string>& ccOutputs = ccg.GetOutputs(); const std::vector<std::string>& ccByproducts = ccg.GetByproducts(); std::transform(ccOutputs.begin(), ccOutputs.end(), - std::back_inserter(deps), MapToNinjaPath()); + std::back_inserter(deps), this->MapToNinjaPath()); std::transform(ccByproducts.begin(), ccByproducts.end(), - std::back_inserter(deps), MapToNinjaPath()); + std::back_inserter(deps), this->MapToNinjaPath()); } } } @@ -103,13 +122,19 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) std::copy(util_outputs.begin(), util_outputs.end(), std::back_inserter(gg->GetByproductsForCleanTarget())); } - lg->AppendTargetDepends(genTarget, deps, config, config, + // TODO: Does this need an output config? + // Does this need to go in impl-<config>.ninja? + lg->AppendTargetDepends(genTarget, deps, config, fileConfig, DependOnTargetArtifact); if (commands.empty()) { phonyBuild.Comment = "Utility command for " + this->GetTargetName(); phonyBuild.ExplicitDeps = std::move(deps); - gg->WriteBuild(this->GetCommonFileStream(), phonyBuild); + if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { + gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild); + } else { + gg->WriteBuild(this->GetCommonFileStream(), phonyBuild); + } } else { std::string command = lg->BuildCommandLine(commands, "utility", this->GeneratorTarget); @@ -145,15 +170,22 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config) std::string ccConfig; if (genTarget->Target->IsPerConfig() && genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { - ccConfig = config; + ccConfig = fileConfig; + } + if (config == fileConfig || + gg->GetPerConfigUtilityTargets().count(genTarget->GetName())) { + gg->WriteCustomCommandBuild( + command, desc, "Utility command for " + this->GetTargetName(), + /*depfile*/ "", /*job_pool*/ "", uses_terminal, + /*restat*/ true, util_outputs, ccConfig, deps); } - gg->WriteCustomCommandBuild(command, desc, - "Utility command for " + this->GetTargetName(), - /*depfile*/ "", /*job_pool*/ "", uses_terminal, - /*restat*/ true, util_outputs, ccConfig, deps); phonyBuild.ExplicitDeps.push_back(utilCommandName); - gg->WriteBuild(this->GetCommonFileStream(), phonyBuild); + if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) { + gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild); + } else { + gg->WriteBuild(this->GetCommonFileStream(), phonyBuild); + } } // Find ADDITIONAL_CLEAN_FILES diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h index 24b47f8..dbd3797 100644 --- a/Source/cmNinjaUtilityTargetGenerator.h +++ b/Source/cmNinjaUtilityTargetGenerator.h @@ -17,4 +17,8 @@ public: ~cmNinjaUtilityTargetGenerator() override; void Generate(const std::string& config) override; + +private: + void WriteUtilBuildStatements(std::string const& config, + std::string const& fileConfig); }; diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx deleted file mode 100644 index 1eede13..0000000 --- a/Source/cmPipeConnection.cxx +++ /dev/null @@ -1,71 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmPipeConnection.h" - -#include <utility> - -#include "cmServer.h" - -cmPipeConnection::cmPipeConnection(std::string name, - cmConnectionBufferStrategy* bufferStrategy) - : cmEventBasedConnection(bufferStrategy) - , PipeName(std::move(name)) -{ -} - -void cmPipeConnection::Connect(uv_stream_t* server) -{ - if (this->WriteStream.get()) { - // Accept and close all pipes but the first: - cm::uv_pipe_ptr rejectPipe; - - rejectPipe.init(*this->Server->GetLoop(), 0); - uv_accept(server, rejectPipe); - - return; - } - - cm::uv_pipe_ptr ClientPipe; - ClientPipe.init(*this->Server->GetLoop(), 0, - static_cast<cmEventBasedConnection*>(this)); - - if (uv_accept(server, ClientPipe) != 0) { - return; - } - - uv_read_start(ClientPipe, on_alloc_buffer, on_read); - WriteStream = std::move(ClientPipe); - Server->OnConnected(this); -} - -bool cmPipeConnection::OnServeStart(std::string* errorMessage) -{ - this->ServerPipe.init(*this->Server->GetLoop(), 0, - static_cast<cmEventBasedConnection*>(this)); - - int r; - if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) { - *errorMessage = std::string("Internal Error with ") + this->PipeName + - ": " + uv_err_name(r); - return false; - } - - if ((r = uv_listen(this->ServerPipe, 1, on_new_connection)) != 0) { - *errorMessage = std::string("Internal Error listening on ") + - this->PipeName + ": " + uv_err_name(r); - return false; - } - - return cmConnection::OnServeStart(errorMessage); -} - -bool cmPipeConnection::OnConnectionShuttingDown() -{ - if (this->WriteStream.get()) { - this->WriteStream->data = nullptr; - } - - this->ServerPipe.reset(); - - return cmEventBasedConnection::OnConnectionShuttingDown(); -} diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h deleted file mode 100644 index 1215716..0000000 --- a/Source/cmPipeConnection.h +++ /dev/null @@ -1,29 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <string> - -#include <cm3p/uv.h> - -#include "cmConnection.h" -#include "cmUVHandlePtr.h" - -class cmPipeConnection : public cmEventBasedConnection -{ -public: - cmPipeConnection(std::string name, - cmConnectionBufferStrategy* bufferStrategy = nullptr); - - bool OnServeStart(std::string* pString) override; - - bool OnConnectionShuttingDown() override; - - void Connect(uv_stream_t* server) override; - -private: - const std::string PipeName; - cm::uv_pipe_ptr ServerPipe; -}; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 18ce9c3..2194b0f 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -340,6 +340,25 @@ class cmMakefile; 3, 19, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0114, \ "ExternalProject step targets fully adopt their steps.", 3, 19, 0, \ + cmPolicies::WARN) \ + SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20, \ + 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0116, \ + "Ninja generators transform DEPFILEs from add_custom_command().", 3, \ + 20, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0117, \ + "MSVC RTTI flag /GR is not added to CMAKE_CXX_FLAGS by default.", 3, \ + 20, 0, cmPolicies::WARN) \ + SELECT( \ + POLICY, CMP0118, \ + "The GENERATED source file property is now visible in all directories.", \ + 3, 20, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0119, \ + "LANGUAGE source file property explicitly compiles as specified " \ + "language.", \ + 3, 20, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0120, \ + "The WriteCompilerDetectionHeader module is removed.", 3, 20, 0, \ cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) @@ -375,7 +394,8 @@ class cmMakefile; F(CMP0105) \ F(CMP0108) \ F(CMP0112) \ - F(CMP0113) + F(CMP0113) \ + F(CMP0119) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmProcessOutput.cxx b/Source/cmProcessOutput.cxx index 0fb4ff7..2d2676e 100644 --- a/Source/cmProcessOutput.cxx +++ b/Source/cmProcessOutput.cxx @@ -126,7 +126,7 @@ bool cmProcessOutput::DecodeText(std::string raw, std::string& decoded, bool cmProcessOutput::DecodeText(const char* data, size_t length, std::string& decoded, size_t id) { - return DecodeText(std::string(data, length), decoded, id); + return this->DecodeText(std::string(data, length), decoded, id); } bool cmProcessOutput::DecodeText(std::vector<char> raw, @@ -134,7 +134,7 @@ bool cmProcessOutput::DecodeText(std::vector<char> raw, { std::string str; const bool success = - DecodeText(std::string(raw.begin(), raw.end()), str, id); + this->DecodeText(std::string(raw.begin(), raw.end()), str, id); decoded.assign(str.begin(), str.end()); return success; } diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 0cfba63..ed32de9 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -358,6 +358,17 @@ static bool IncludeByVariable(cmExecutionStatus& status, return true; } + std::string includeFile = + cmSystemTools::CollapseFullPath(*include, mf.GetCurrentSourceDirectory()); + if (!cmSystemTools::FileExists(includeFile)) { + status.SetError(cmStrCat("could not find requested file:\n ", *include)); + return false; + } + if (cmSystemTools::FileIsDirectory(includeFile)) { + status.SetError(cmStrCat("requested file is a directory:\n ", *include)); + return false; + } + const bool readit = mf.ReadDependentFile(*include); if (readit) { return true; @@ -367,7 +378,7 @@ static bool IncludeByVariable(cmExecutionStatus& status, return true; } - status.SetError(cmStrCat("could not find file:\n ", *include)); + status.SetError(cmStrCat("could not load requested file:\n ", *include)); return false; } diff --git a/Source/cmPropertyMap.cxx b/Source/cmPropertyMap.cxx index f22f36d..06e151a 100644 --- a/Source/cmPropertyMap.cxx +++ b/Source/cmPropertyMap.cxx @@ -7,17 +7,17 @@ void cmPropertyMap::Clear() { - Map_.clear(); + this->Map_.clear(); } void cmPropertyMap::SetProperty(const std::string& name, const char* value) { if (!value) { - Map_.erase(name); + this->Map_.erase(name); return; } - Map_[name] = value; + this->Map_[name] = value; } void cmPropertyMap::AppendProperty(const std::string& name, @@ -29,7 +29,7 @@ void cmPropertyMap::AppendProperty(const std::string& name, } { - std::string& pVal = Map_[name]; + std::string& pVal = this->Map_[name]; if (!pVal.empty() && !asString) { pVal += ';'; } @@ -39,13 +39,13 @@ void cmPropertyMap::AppendProperty(const std::string& name, void cmPropertyMap::RemoveProperty(const std::string& name) { - Map_.erase(name); + this->Map_.erase(name); } cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const { - auto it = Map_.find(name); - if (it != Map_.end()) { + auto it = this->Map_.find(name); + if (it != this->Map_.end()) { return &it->second; } return nullptr; @@ -54,8 +54,8 @@ cmProp cmPropertyMap::GetPropertyValue(const std::string& name) const std::vector<std::string> cmPropertyMap::GetKeys() const { std::vector<std::string> keyList; - keyList.reserve(Map_.size()); - for (auto const& item : Map_) { + keyList.reserve(this->Map_.size()); + for (auto const& item : this->Map_) { keyList.push_back(item.first); } std::sort(keyList.begin(), keyList.end()); @@ -66,8 +66,8 @@ std::vector<std::pair<std::string, std::string>> cmPropertyMap::GetList() const { using StringPair = std::pair<std::string, std::string>; std::vector<StringPair> kvList; - kvList.reserve(Map_.size()); - for (auto const& item : Map_) { + kvList.reserve(this->Map_.size()); + for (auto const& item : this->Map_) { kvList.emplace_back(item.first, item.second); } std::sort(kvList.begin(), kvList.end(), diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx index de462db..e058176 100644 --- a/Source/cmQTWrapCPPCommand.cxx +++ b/Source/cmQTWrapCPPCommand.cxx @@ -40,8 +40,7 @@ bool cmQTWrapCPPCommand(std::vector<std::string> const& args, cmStrCat(mf.GetCurrentBinaryDirectory(), "/moc_", srcName, ".cxx"); cmSourceFile* sf = mf.GetOrCreateSource(newName, true); if (curr) { - cmProp p = curr->GetProperty("ABSTRACT"); - sf->SetProperty("ABSTRACT", cmToCStr(p)); + sf->SetProperty("ABSTRACT", cmToCStr(curr->GetProperty("ABSTRACT"))); } // Compute the name of the header from which to generate the file. diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index cf90417..e12a653 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -29,13 +29,13 @@ public: { } - bool operator>(IntegerVersion const version) + bool operator>(IntegerVersion const version) const { return (this->Major > version.Major) || ((this->Major == version.Major) && (this->Minor > version.Minor)); } - bool operator>=(IntegerVersion const version) + bool operator>=(IntegerVersion const version) const { return (this->Major > version.Major) || ((this->Major == version.Major) && (this->Minor >= version.Minor)); @@ -111,20 +111,20 @@ public: RccLister(std::string rccExecutable, std::vector<std::string> listOptions); //! The rcc executable - std::string const& RccExcutable() const { return RccExcutable_; } + std::string const& RccExcutable() const { return this->RccExcutable_; } void SetRccExecutable(std::string const& rccExecutable) { - RccExcutable_ = rccExecutable; + this->RccExcutable_ = rccExecutable; } //! The rcc executable list options std::vector<std::string> const& ListOptions() const { - return ListOptions_; + return this->ListOptions_; } void SetListOptions(std::vector<std::string> const& listOptions) { - ListOptions_ = listOptions; + this->ListOptions_ = listOptions; } /** diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index fac2bbf..62b879f 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenGlobalInitializer.h" +#include <set> #include <utility> #include <cm/memory> @@ -56,7 +57,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( if (targetName.empty()) { targetName = "autogen"; } - GlobalAutoGenTargets_.emplace(localGen.get(), std::move(targetName)); + this->GlobalAutoGenTargets_.emplace(localGen.get(), + std::move(targetName)); globalAutoGenTarget = true; } @@ -67,7 +69,8 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( if (targetName.empty()) { targetName = "autorcc"; } - GlobalAutoRccTargets_.emplace(localGen.get(), std::move(targetName)); + this->GlobalAutoRccTargets_.emplace(localGen.get(), + std::move(targetName)); globalAutoRccTarget = true; } } @@ -91,17 +94,23 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( // Don't process target continue; } + std::set<std::string> const& languages = + target->GetAllConfigCompileLanguages(); + if (languages.count("CSharp")) { + // Don't process target if it's a CSharp target + continue; + } - bool const moc = target->GetPropertyAsBool(kw().AUTOMOC); - bool const uic = target->GetPropertyAsBool(kw().AUTOUIC); - bool const rcc = target->GetPropertyAsBool(kw().AUTORCC); + bool const moc = target->GetPropertyAsBool(this->kw().AUTOMOC); + bool const uic = target->GetPropertyAsBool(this->kw().AUTOUIC); + bool const rcc = target->GetPropertyAsBool(this->kw().AUTORCC); if (moc || uic || rcc) { std::string const& mocExec = - target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE); + target->GetSafeProperty(this->kw().AUTOMOC_EXECUTABLE); std::string const& uicExec = - target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE); + target->GetSafeProperty(this->kw().AUTOUIC_EXECUTABLE); std::string const& rccExec = - target->GetSafeProperty(kw().AUTORCC_EXECUTABLE); + target->GetSafeProperty(this->kw().AUTORCC_EXECUTABLE); // We support Qt4, Qt5 and Qt6 auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get()); @@ -134,9 +143,10 @@ cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( } if (mocIsValid || uicIsValid || rccIsValid) { // Create autogen target initializer - Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>( - this, target.get(), qtVersion.first, mocIsValid, uicIsValid, - rccIsValid, globalAutoGenTarget, globalAutoRccTarget)); + this->Initializers_.emplace_back( + cm::make_unique<cmQtAutoGenInitializer>( + this, target.get(), qtVersion.first, mocIsValid, uicIsValid, + rccIsValid, globalAutoGenTarget, globalAutoRccTarget)); } } } @@ -177,8 +187,8 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget( void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen( cmLocalGenerator* localGen, std::string const& targetName) { - auto it = GlobalAutoGenTargets_.find(localGen); - if (it != GlobalAutoGenTargets_.end()) { + auto it = this->GlobalAutoGenTargets_.find(localGen); + if (it != this->GlobalAutoGenTargets_.end()) { cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); if (target != nullptr) { target->Target->AddUtility(targetName, false, localGen->GetMakefile()); @@ -189,8 +199,8 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen( void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc( cmLocalGenerator* localGen, std::string const& targetName) { - auto it = GlobalAutoRccTargets_.find(localGen); - if (it != GlobalAutoRccTargets_.end()) { + auto it = this->GlobalAutoRccTargets_.find(localGen); + if (it != this->GlobalAutoRccTargets_.end()) { cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); if (target != nullptr) { target->Target->AddUtility(targetName, false, localGen->GetMakefile()); @@ -251,7 +261,7 @@ cmQtAutoGenGlobalInitializer::GetCompilerFeatures( bool cmQtAutoGenGlobalInitializer::generate() { - return (InitializeCustomTargets() && SetupCustomTargets()); + return (this->InitializeCustomTargets() && this->SetupCustomTargets()); } bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets() @@ -259,19 +269,19 @@ bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets() // Initialize global autogen targets { std::string const comment = "Global AUTOGEN target"; - for (auto const& pair : GlobalAutoGenTargets_) { - GetOrCreateGlobalTarget(pair.first, pair.second, comment); + for (auto const& pair : this->GlobalAutoGenTargets_) { + this->GetOrCreateGlobalTarget(pair.first, pair.second, comment); } } // Initialize global autorcc targets { std::string const comment = "Global AUTORCC target"; - for (auto const& pair : GlobalAutoRccTargets_) { - GetOrCreateGlobalTarget(pair.first, pair.second, comment); + for (auto const& pair : this->GlobalAutoRccTargets_) { + this->GetOrCreateGlobalTarget(pair.first, pair.second, comment); } } // Initialize per target autogen targets - for (auto& initializer : Initializers_) { + for (auto& initializer : this->Initializers_) { if (!initializer->InitCustomTargets()) { return false; } @@ -281,7 +291,7 @@ bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets() bool cmQtAutoGenGlobalInitializer::SetupCustomTargets() { - for (auto& initializer : Initializers_) { + for (auto& initializer : this->Initializers_) { if (!initializer->SetupCustomTargets()) { return false; } diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h index cdae137..ea3821d 100644 --- a/Source/cmQtAutoGenGlobalInitializer.h +++ b/Source/cmQtAutoGenGlobalInitializer.h @@ -50,7 +50,7 @@ public: std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators); ~cmQtAutoGenGlobalInitializer(); - Keywords const& kw() const { return Keywords_; }; + Keywords const& kw() const { return this->Keywords_; }; bool generate(); diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 3b62e9c..bfe174c 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -17,6 +17,7 @@ #include <cm/iterator> #include <cm/memory> #include <cmext/algorithm> +#include <cmext/string_view> #include <cm3p/json/value.h> #include <cm3p/json/writer.h> @@ -29,6 +30,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmGlobalNinjaGenerator.h" #include "cmLinkItem.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" @@ -150,7 +152,8 @@ std::vector<std::string> SearchPathSanitizer::operator()( res.reserve(paths.size()); for (std::string const& srcPath : paths) { // Collapse relative paths - std::string path = cmSystemTools::CollapseFullPath(srcPath, SourcePath_); + std::string path = + cmSystemTools::CollapseFullPath(srcPath, this->SourcePath_); // Remove suffix slashes while (cmHasSuffix(path, '/')) { path.pop_back(); @@ -170,14 +173,17 @@ public: // -- Single value void Set(std::string const& key, std::string const& value) { - Value_[key] = value; + this->Value_[key] = value; } void SetConfig(std::string const& key, cmQtAutoGenInitializer::ConfigString const& cfgStr); - void SetBool(std::string const& key, bool value) { Value_[key] = value; } + void SetBool(std::string const& key, bool value) + { + this->Value_[key] = value; + } void SetUInt(std::string const& key, unsigned int value) { - Value_[key] = value; + this->Value_[key] = value; } // -- Array utility @@ -209,9 +215,9 @@ private: void InfoWriter::SetConfig(std::string const& key, cmQtAutoGenInitializer::ConfigString const& cfgStr) { - Set(key, cfgStr.Default); + this->Set(key, cfgStr.Default); for (auto const& item : cfgStr.Config) { - Set(cmStrCat(key, '_', item.first), item.second); + this->Set(cmStrCat(key, '_', item.first), item.second); } } @@ -241,14 +247,14 @@ void InfoWriter::MakeStringArray(Json::Value& jval, CONT const& container) template <typename CONT> void InfoWriter::SetArray(std::string const& key, CONT const& container) { - MakeStringArray(Value_[key], container); + MakeStringArray(this->Value_[key], container); } template <typename CONT, typename FUNC> void InfoWriter::SetArrayArray(std::string const& key, CONT const& container, FUNC func) { - Json::Value& jval = Value_[key]; + Json::Value& jval = this->Value_[key]; if (MakeArray(jval, container)) { Json::ArrayIndex ii = 0; for (auto const& citem : container) { @@ -264,9 +270,9 @@ void InfoWriter::SetConfigArray( std::string const& key, cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr) { - SetArray(key, cfgStr.Default); + this->SetArray(key, cfgStr.Default); for (auto const& item : cfgStr.Config) { - SetArray(cmStrCat(key, '_', item.first), item.second); + this->SetArray(cmStrCat(key, '_', item.first), item.second); } } @@ -281,7 +287,7 @@ bool InfoWriter::Save(std::string const& filename) Json::StyledStreamWriter jsonWriter; try { - jsonWriter.write(fileStream, Value_); + jsonWriter.write(fileStream, this->Value_); } catch (...) { return false; } @@ -304,11 +310,11 @@ cmQtAutoGenInitializer::cmQtAutoGenInitializer( , PathCheckSum(genTarget->Makefile) , QtVersion(qtVersion) { - AutogenTarget.GlobalTarget = globalAutogenTarget; - Moc.Enabled = mocEnabled; - Uic.Enabled = uicEnabled; - Rcc.Enabled = rccEnabled; - Rcc.GlobalTarget = globalAutoRccTarget; + this->AutogenTarget.GlobalTarget = globalAutogenTarget; + this->Moc.Enabled = mocEnabled; + this->Uic.Enabled = uicEnabled; + this->Rcc.Enabled = rccEnabled; + this->Rcc.GlobalTarget = globalAutoRccTarget; } bool cmQtAutoGenInitializer::InitCustomTargets() @@ -414,8 +420,8 @@ bool cmQtAutoGenInitializer::InitCustomTargets() cmSystemTools::ConvertToUnixSlashes(this->Dir.Work); // Include directory - ConfigFileNames(this->Dir.Include, cmStrCat(this->Dir.Build, "/include"), - ""); + this->ConfigFileNames(this->Dir.Include, + cmStrCat(this->Dir.Build, "/include"), ""); this->Dir.IncludeGenExp = this->Dir.Include.Default; if (this->MultiConfig) { this->Dir.IncludeGenExp += "_$<CONFIG>"; @@ -425,12 +431,12 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Moc, Uic and _autogen target settings if (this->MocOrUicEnabled()) { // Init moc specific settings - if (this->Moc.Enabled && !InitMoc()) { + if (this->Moc.Enabled && !this->InitMoc()) { return false; } // Init uic specific settings - if (this->Uic.Enabled && !InitUic()) { + if (this->Uic.Enabled && !this->InitUic()) { return false; } @@ -457,14 +463,14 @@ bool cmQtAutoGenInitializer::InitCustomTargets() cmStrCat(this->Dir.Info, "/AutogenInfo.json"); // Used settings file - ConfigFileNames(this->AutogenTarget.SettingsFile, - cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt"); - ConfigFileClean(this->AutogenTarget.SettingsFile); + this->ConfigFileNames(this->AutogenTarget.SettingsFile, + cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt"); + this->ConfigFileClean(this->AutogenTarget.SettingsFile); // Parse cache file - ConfigFileNames(this->AutogenTarget.ParseCacheFile, - cmStrCat(this->Dir.Info, "/ParseCache"), ".txt"); - ConfigFileClean(this->AutogenTarget.ParseCacheFile); + this->ConfigFileNames(this->AutogenTarget.ParseCacheFile, + cmStrCat(this->Dir.Info, "/ParseCache"), ".txt"); + this->ConfigFileClean(this->AutogenTarget.ParseCacheFile); } // Autogen target: Compute user defined dependencies @@ -533,7 +539,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() } // Init rcc specific settings - if (this->Rcc.Enabled && !InitRcc()) { + if (this->Rcc.Enabled && !this->InitRcc()) { return false; } @@ -563,8 +569,23 @@ bool cmQtAutoGenInitializer::InitCustomTargets() bool cmQtAutoGenInitializer::InitMoc() { // Mocs compilation file - this->Moc.CompilationFile = - cmStrCat(this->Dir.Build, "/mocs_compilation.cpp"); + if (this->GlobalGen->IsXcode()) { + // XXX(xcode-per-cfg-src): Drop this Xcode-specific code path + // when the Xcode generator supports per-config sources. + this->Moc.CompilationFile.Default = + cmStrCat(this->Dir.Build, "/mocs_compilation.cpp"); + this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default; + } else { + this->ConfigFileNames(this->Moc.CompilationFile, + cmStrCat(this->Dir.Build, "/mocs_compilation"), + ".cpp"); + if (this->MultiConfig) { + this->Moc.CompilationFileGenex = + cmStrCat(this->Dir.Build, "/mocs_compilation_$<CONFIG>.cpp"_s); + } else { + this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default; + } + } // Moc predefs if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && @@ -574,8 +595,8 @@ bool cmQtAutoGenInitializer::InitMoc() this->Moc.PredefsCmd); // Header if (!this->Moc.PredefsCmd.empty()) { - ConfigFileNames(this->Moc.PredefsFile, - cmStrCat(this->Dir.Build, "/moc_predefs"), ".h"); + this->ConfigFileNames(this->Moc.PredefsFile, + cmStrCat(this->Dir.Build, "/moc_predefs"), ".h"); } } @@ -730,10 +751,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() auto const& kw = this->GlobalInitializer->kw(); auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath, + std::vector<size_t> const& configs, bool muIt) -> MUFileHandle { MUFileHandle muf = cm::make_unique<MUFile>(); muf->FullPath = fullPath; muf->SF = sf; + if (!configs.empty() && configs.size() != this->ConfigsList.size()) { + muf->Configs = configs; + } muf->Generated = sf->GetIsGenerated(); bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN); muf->SkipMoc = this->Moc.Enabled && @@ -772,42 +797,37 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Scan through target files { // Scan through target files - std::vector<cmSourceFile*> srcFiles; - this->GenTarget->GetConfigCommonSourceFiles(srcFiles); - for (cmSourceFile* sf : srcFiles) { - // sf->GetExtension() is only valid after sf->ResolveFullPath() ... - // Since we're iterating over source files that might be not in the - // target we need to check for path errors (not existing files). - std::string pathError; - std::string const& fullPath = sf->ResolveFullPath(&pathError); - if (!pathError.empty() || fullPath.empty()) { - continue; - } + for (cmGeneratorTarget::AllConfigSource const& acs : + this->GenTarget->GetAllConfigSources()) { + std::string const& fullPath = acs.Source->GetFullPath(); std::string const& extLower = - cmSystemTools::LowerCase(sf->GetExtension()); + cmSystemTools::LowerCase(acs.Source->GetExtension()); // Register files that will be scanned by moc or uic if (this->MocOrUicEnabled()) { if (cm->IsAHeaderExtension(extLower)) { - addMUHeader(makeMUFile(sf, fullPath, true), extLower); + addMUHeader(makeMUFile(acs.Source, fullPath, acs.Configs, true), + extLower); } else if (cm->IsACLikeSourceExtension(extLower)) { - addMUSource(makeMUFile(sf, fullPath, true)); + addMUSource(makeMUFile(acs.Source, fullPath, acs.Configs, true)); } } // Register rcc enabled files if (this->Rcc.Enabled) { - if ((extLower == kw.qrc) && !sf->GetPropertyAsBool(kw.SKIP_AUTOGEN) && - !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) { + if ((extLower == kw.qrc) && + !acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) && + !acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) { // Register qrc file Qrc qrc; qrc.QrcFile = fullPath; qrc.QrcName = cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile); - qrc.Generated = sf->GetIsGenerated(); + qrc.Generated = acs.Source->GetIsGenerated(); // RCC options { - std::string const opts = sf->GetSafeProperty(kw.AUTORCC_OPTIONS); + std::string const& opts = + acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS); if (!opts.empty()) { cmExpandList(opts, qrc.Options); } @@ -817,7 +837,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() } } } - // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's + // cmGeneratorTarget::GetAllConfigSources computes the target's // sources meta data cache. Clear it so that OBJECT library targets that // are AUTOGEN initialized after this target get their added // mocs_compilation.cpp source acknowledged by this target. @@ -861,7 +881,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() } if (sf != nullptr) { - auto eMuf = makeMUFile(sf, fullPath, true); + auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true); // Only process moc/uic when the parent is processed as well if (!muf.MocIt) { eMuf->MocIt = false; @@ -896,14 +916,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (cm->IsAHeaderExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Headers, sf.get())) { - auto muf = makeMUFile(sf.get(), fullPath, false); + auto muf = makeMUFile(sf.get(), fullPath, {}, false); if (muf->SkipMoc || muf->SkipUic) { addMUHeader(std::move(muf), extLower); } } } else if (cm->IsACLikeSourceExtension(extLower)) { if (!cm::contains(this->AutogenTarget.Sources, sf.get())) { - auto muf = makeMUFile(sf.get(), fullPath, false); + auto muf = makeMUFile(sf.get(), fullPath, {}, false); if (muf->SkipMoc || muf->SkipUic) { addMUSource(std::move(muf)); } @@ -1020,7 +1040,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() qrc.QrcName, '_', qrc.QrcPathChecksum); qrc.LockFile = cmStrCat(base, "_Lock.lock"); qrc.InfoFile = cmStrCat(base, "_Info.json"); - ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt"); + this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt"); } // rcc options for (Qrc& qrc : this->Rcc.Qrcs) { @@ -1066,10 +1086,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile); // Files provided by the autogen target - std::vector<std::string> autogenProvides; + std::vector<std::string> autogenByproducts; if (this->Moc.Enabled) { this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true); - autogenProvides.push_back(this->Moc.CompilationFile); + autogenByproducts.push_back(this->Moc.CompilationFileGenex); } // Compose target comment @@ -1090,8 +1110,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } // Compose command lines - // TODO: Refactor autogen to output a per-config mocs_compilation.cpp instead - // of fiddling with the include directories + // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp + // instead of fiddling with the include directories std::vector<std::string> configs; this->GlobalGen->GetQtAutoGenConfigs(configs); bool stdPipesUTF8 = true; @@ -1118,7 +1138,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() usePRE_BUILD = false; } // Cannot use PRE_BUILD when a global autogen target is in place - if (AutogenTarget.GlobalTarget) { + if (this->AutogenTarget.GlobalTarget) { usePRE_BUILD = false; } } @@ -1137,7 +1157,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // PRE_BUILD does not support file dependencies! const std::vector<std::string> no_output; const std::vector<std::string> no_deps; - cmCustomCommand cc(no_output, autogenProvides, no_deps, commandLines, + cmCustomCommand cc(no_output, autogenByproducts, no_deps, commandLines, this->Makefile->GetBacktrace(), autogenComment.c_str(), this->Dir.Work.c_str(), stdPipesUTF8); cc.SetEscapeOldStyle(false); @@ -1237,11 +1257,23 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() const std::string outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName); this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps"); - auto relativeBinaryDir = cmSystemTools::RelativePath( - this->LocalGen->GetBinaryDirectory(), - this->LocalGen->GetCurrentBinaryDirectory()); - if (!relativeBinaryDir.empty()) { - relativeBinaryDir = cmStrCat(relativeBinaryDir, "/"); + std::string relativeBinaryDir; + if (dynamic_cast<cmGlobalNinjaGenerator*>(this->GlobalGen)) { + switch (this->LocalGen->GetPolicyStatus(cmPolicies::CMP0116)) { + case cmPolicies::OLD: + case cmPolicies::WARN: + relativeBinaryDir = cmSystemTools::RelativePath( + this->LocalGen->GetBinaryDirectory(), + this->LocalGen->GetCurrentBinaryDirectory()); + if (!relativeBinaryDir.empty()) { + relativeBinaryDir = cmStrCat(relativeBinaryDir, "/"); + } + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + break; + } } this->AutogenTarget.DepFileRuleName = cmStrCat(relativeBinaryDir, this->GenTarget->GetName(), "_autogen/", @@ -1270,7 +1302,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Create autogen target cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand( this->AutogenTarget.Name, true, this->Dir.Work.c_str(), - /*byproducts=*/autogenProvides, + /*byproducts=*/autogenByproducts, /*depends=*/dependencies, commandLines, false, autogenComment.c_str()); // Create autogen generator target this->LocalGen->AddGeneratorTarget( @@ -1520,18 +1552,31 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles()); info.SetArray("HEADER_EXTENSIONS", this->Makefile->GetCMakeInstance()->GetHeaderExtensions()); + auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value { + Json::Value value; + if (!configs.empty()) { + value = Json::arrayValue; + for (size_t ci : configs) { + value.append(this->ConfigsList[ci]); + } + } + return value; + }; + info.SetArrayArray("HEADERS", headers, + [this, &cfgArray](Json::Value& jval, MUFile const* muf) { + jval.resize(4u); + jval[0u] = muf->FullPath; + jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', + muf->UicIt ? 'U' : 'u'); + jval[2u] = cfgArray(muf->Configs); + jval[3u] = this->GetMocBuildPath(*muf); + }); info.SetArrayArray( - "HEADERS", headers, [this](Json::Value& jval, MUFile const* muf) { + "SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) { jval.resize(3u); jval[0u] = muf->FullPath; jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u'); - jval[2u] = this->GetMocBuildPath(*muf); - }); - info.SetArrayArray( - "SOURCES", sources, [](Json::Value& jval, MUFile const* muf) { - jval.resize(2u); - jval[0u] = muf->FullPath; - jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u'); + jval[2u] = cfgArray(muf->Configs); }); // Write moc settings @@ -1550,7 +1595,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() jval[0u] = pair.first; jval[1u] = pair.second; }); - info.Set("MOC_COMPILATION_FILE", this->Moc.CompilationFile); + info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile); info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd); info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile); } @@ -1624,7 +1669,7 @@ cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource( std::string const& filename) { cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true); - gFile->SetProperty("GENERATED", "1"); + gFile->MarkAsGenerated(); gFile->SetProperty("SKIP_AUTOGEN", "1"); return gFile; } @@ -1643,6 +1688,28 @@ cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource( return gFile; } +void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename, + GenVarsT const& genVars, + bool prepend) +{ + // XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition + // when the Xcode generator supports per-config sources. + if (!this->MultiConfig || this->GlobalGen->IsXcode()) { + this->AddGeneratedSource(filename.Default, genVars, prepend); + return; + } + for (auto const& cfg : this->ConfigsList) { + std::string const& filenameCfg = filename.Config.at(cfg); + // Register source at makefile + this->RegisterGeneratedSource(filenameCfg); + // Add source file to target for this configuration. + this->GenTarget->AddSource( + cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend); + // Add source file to source group + this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper); + } +} + void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, cm::string_view genNameUpper) { diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index 3ab303a..e0e66f1 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <memory> #include <set> #include <string> @@ -70,6 +71,7 @@ public: { std::string FullPath; cmSourceFile* SF = nullptr; + std::vector<size_t> Configs; bool Generated = false; bool SkipMoc = false; bool SkipUic = false; @@ -132,6 +134,8 @@ private: cmSourceFile* AddGeneratedSource(std::string const& filename, GenVarsT const& genVars, bool prepend = false); + void AddGeneratedSource(ConfigString const& filename, + GenVarsT const& genVars, bool prepend = false); void AddToSourceGroup(std::string const& fileName, cm::string_view genNameUpper); void AddCleanFile(std::string const& fileName); @@ -207,7 +211,8 @@ private: bool RelaxedMode = false; bool PathPrefix = false; - std::string CompilationFile; + ConfigString CompilationFile; + std::string CompilationFileGenex; // Compiler implicit pre defines std::vector<std::string> PredefsCmd; ConfigString PredefsFile; diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index ee2bc09..ebb6bd7 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -18,10 +18,10 @@ cmQtAutoGenerator::Logger::Logger() if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) { unsigned long iVerbose = 0; if (cmStrToULong(verbose, &iVerbose)) { - SetVerbosity(static_cast<unsigned int>(iVerbose)); + this->SetVerbosity(static_cast<unsigned int>(iVerbose)); } else { // Non numeric verbosity - SetVerbose(cmIsOn(verbose)); + this->SetVerbose(cmIsOn(verbose)); } } } @@ -29,9 +29,9 @@ cmQtAutoGenerator::Logger::Logger() std::string colorEnv; cmSystemTools::GetEnv("COLOR", colorEnv); if (!colorEnv.empty()) { - SetColorOutput(cmIsOn(colorEnv)); + this->SetColorOutput(cmIsOn(colorEnv)); } else { - SetColorOutput(true); + this->SetColorOutput(true); } } } @@ -47,7 +47,7 @@ void cmQtAutoGenerator::Logger::RaiseVerbosity(unsigned int value) void cmQtAutoGenerator::Logger::SetColorOutput(bool value) { - ColorOutput_ = value; + this->ColorOutput_ = value; } std::string cmQtAutoGenerator::Logger::HeadLine(cm::string_view title) @@ -61,7 +61,7 @@ void cmQtAutoGenerator::Logger::Info(GenT genType, std::string msg = cmStrCat(GeneratorName(genType), ": ", message, cmHasSuffix(message, '\n') ? "" : "\n"); { - std::lock_guard<std::mutex> lock(Mutex_); + std::lock_guard<std::mutex> lock(this->Mutex_); cmSystemTools::Stdout(msg); } } @@ -80,7 +80,7 @@ void cmQtAutoGenerator::Logger::Warning(GenT genType, message, cmHasSuffix(message, '\n') ? "\n" : "\n\n"); } { - std::lock_guard<std::mutex> lock(Mutex_); + std::lock_guard<std::mutex> lock(this->Mutex_); cmSystemTools::Stdout(msg); } } @@ -92,7 +92,7 @@ void cmQtAutoGenerator::Logger::Error(GenT genType, cmStrCat('\n', HeadLine(cmStrCat(GeneratorName(genType), " error")), message, cmHasSuffix(message, '\n') ? "\n" : "\n\n"); { - std::lock_guard<std::mutex> lock(Mutex_); + std::lock_guard<std::mutex> lock(this->Mutex_); cmSystemTools::Stderr(msg); } } @@ -108,7 +108,7 @@ void cmQtAutoGenerator::Logger::ErrorCommand( msg += cmStrCat(HeadLine("Output"), output, cmHasSuffix(output, '\n') ? "\n" : "\n\n"); { - std::lock_guard<std::mutex> lock(Mutex_); + std::lock_guard<std::mutex> lock(this->Mutex_); cmSystemTools::Stderr(msg); } } @@ -215,7 +215,7 @@ cmQtAutoGenerator::~cmQtAutoGenerator() = default; bool cmQtAutoGenerator::InfoT::Read(std::istream& istr) { try { - istr >> Json_; + istr >> this->Json_; } catch (...) { return false; } @@ -264,22 +264,22 @@ bool cmQtAutoGenerator::InfoT::GetJsonArray( std::string cmQtAutoGenerator::InfoT::ConfigKey(cm::string_view key) const { - return cmStrCat(key, '_', Gen_.InfoConfig()); + return cmStrCat(key, '_', this->Gen_.InfoConfig()); } bool cmQtAutoGenerator::InfoT::GetString(std::string const& key, std::string& value, bool required) const { - Json::Value const& jval = Json_[key]; + Json::Value const& jval = this->Json_[key]; if (!jval.isString()) { if (!jval.isNull() || required) { - return LogError(cmStrCat(key, " is not a string.")); + return this->LogError(cmStrCat(key, " is not a string.")); } } else { value = jval.asString(); if (value.empty() && required) { - return LogError(cmStrCat(key, " is empty.")); + return this->LogError(cmStrCat(key, " is empty.")); } } return true; @@ -290,32 +290,32 @@ bool cmQtAutoGenerator::InfoT::GetStringConfig(std::string const& key, bool required) const { { // Try config - std::string const configKey = ConfigKey(key); - Json::Value const& jval = Json_[configKey]; + std::string const configKey = this->ConfigKey(key); + Json::Value const& jval = this->Json_[configKey]; if (!jval.isNull()) { if (!jval.isString()) { - return LogError(cmStrCat(configKey, " is not a string.")); + return this->LogError(cmStrCat(configKey, " is not a string.")); } value = jval.asString(); if (required && value.empty()) { - return LogError(cmStrCat(configKey, " is empty.")); + return this->LogError(cmStrCat(configKey, " is empty.")); } return true; } } // Try plain - return GetString(key, value, required); + return this->GetString(key, value, required); } bool cmQtAutoGenerator::InfoT::GetBool(std::string const& key, bool& value, bool required) const { - Json::Value const& jval = Json_[key]; + Json::Value const& jval = this->Json_[key]; if (jval.isBool()) { value = jval.asBool(); } else { if (!jval.isNull() || required) { - return LogError(cmStrCat(key, " is not a boolean.")); + return this->LogError(cmStrCat(key, " is not a boolean.")); } } return true; @@ -325,12 +325,12 @@ bool cmQtAutoGenerator::InfoT::GetUInt(std::string const& key, unsigned int& value, bool required) const { - Json::Value const& jval = Json_[key]; + Json::Value const& jval = this->Json_[key]; if (jval.isUInt()) { value = jval.asUInt(); } else { if (!jval.isNull() || required) { - return LogError(cmStrCat(key, " is not an unsigned integer.")); + return this->LogError(cmStrCat(key, " is not an unsigned integer.")); } } return true; @@ -340,10 +340,10 @@ bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key, std::vector<std::string>& list, bool required) const { - Json::Value const& jval = Json_[key]; + Json::Value const& jval = this->Json_[key]; if (!jval.isArray()) { if (!jval.isNull() || required) { - return LogError(cmStrCat(key, " is not an array.")); + return this->LogError(cmStrCat(key, " is not an array.")); } } return GetJsonArray(list, jval) || !required; @@ -353,10 +353,10 @@ bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key, std::unordered_set<std::string>& list, bool required) const { - Json::Value const& jval = Json_[key]; + Json::Value const& jval = this->Json_[key]; if (!jval.isArray()) { if (!jval.isNull() || required) { - return LogError(cmStrCat(key, " is not an array.")); + return this->LogError(cmStrCat(key, " is not an array.")); } } return GetJsonArray(list, jval) || !required; @@ -367,34 +367,35 @@ bool cmQtAutoGenerator::InfoT::GetArrayConfig(std::string const& key, bool required) const { { // Try config - std::string const configKey = ConfigKey(key); - Json::Value const& jval = Json_[configKey]; + std::string const configKey = this->ConfigKey(key); + Json::Value const& jval = this->Json_[configKey]; if (!jval.isNull()) { if (!jval.isArray()) { - return LogError(cmStrCat(configKey, " is not an array string.")); + return this->LogError(cmStrCat(configKey, " is not an array string.")); } if (!GetJsonArray(list, jval) && required) { - return LogError(cmStrCat(configKey, " is empty.")); + return this->LogError(cmStrCat(configKey, " is empty.")); } return true; } } // Try plain - return GetArray(key, list, required); + return this->GetArray(key, list, required); } bool cmQtAutoGenerator::InfoT::LogError(GenT genType, cm::string_view message) const { - Gen_.Log().Error(genType, - cmStrCat("Info error in info file\n", - Quoted(Gen_.InfoFile()), ":\n", message)); + this->Gen_.Log().Error(genType, + cmStrCat("Info error in info file\n", + Quoted(this->Gen_.InfoFile()), ":\n", + message)); return false; } bool cmQtAutoGenerator::InfoT::LogError(cm::string_view message) const { - return LogError(Gen_.GenType_, message); + return this->LogError(this->Gen_.GenType_, message); } std::string cmQtAutoGenerator::SettingsFind(cm::string_view content, @@ -418,10 +419,10 @@ std::string cmQtAutoGenerator::SettingsFind(cm::string_view content, std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const { std::string res; - if (cmHasPrefix(path, ProjectDirs().Source)) { - res = cmStrCat("SRC:", path.substr(ProjectDirs().Source.size())); - } else if (cmHasPrefix(path, ProjectDirs().Binary)) { - res = cmStrCat("BIN:", path.substr(ProjectDirs().Binary.size())); + if (cmHasPrefix(path, this->ProjectDirs().Source)) { + res = cmStrCat("SRC:", path.substr(this->ProjectDirs().Source.size())); + } else if (cmHasPrefix(path, this->ProjectDirs().Binary)) { + res = cmStrCat("BIN:", path.substr(this->ProjectDirs().Binary.size())); } else { res = std::string(path); } @@ -431,17 +432,18 @@ std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config) { // Info config - InfoConfig_ = std::string(config); + this->InfoConfig_ = std::string(config); // Info file - InfoFile_ = std::string(infoFile); - cmSystemTools::CollapseFullPath(InfoFile_); - InfoDir_ = cmSystemTools::GetFilenamePath(InfoFile_); + this->InfoFile_ = std::string(infoFile); + cmSystemTools::CollapseFullPath(this->InfoFile_); + this->InfoDir_ = cmSystemTools::GetFilenamePath(this->InfoFile_); // Load info file time - if (!InfoFileTime_.Load(InfoFile_)) { + if (!this->InfoFileTime_.Load(this->InfoFile_)) { cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ", - Quoted(InfoFile_), " is not readable\n")); + Quoted(this->InfoFile_), + " is not readable\n")); return false; } @@ -450,17 +452,18 @@ bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config) // Read info file { - cmsys::ifstream ifs(InfoFile_.c_str(), + cmsys::ifstream ifs(this->InfoFile_.c_str(), (std::ios::in | std::ios::binary)); if (!ifs) { - Log().Error( - GenType_, - cmStrCat("Could not to open info file ", Quoted(InfoFile_))); + this->Log().Error( + this->GenType_, + cmStrCat("Could not to open info file ", Quoted(this->InfoFile_))); return false; } if (!info.Read(ifs)) { - Log().Error(GenType_, - cmStrCat("Could not read info file ", Quoted(InfoFile_))); + this->Log().Error( + this->GenType_, + cmStrCat("Could not read info file ", Quoted(this->InfoFile_))); return false; } } @@ -470,15 +473,17 @@ bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config) unsigned int verbosity = 0; // Info: setup project directories if (!info.GetUInt("VERBOSITY", verbosity, false) || - !info.GetString("CMAKE_SOURCE_DIR", ProjectDirs_.Source, true) || - !info.GetString("CMAKE_BINARY_DIR", ProjectDirs_.Binary, true) || + !info.GetString("CMAKE_SOURCE_DIR", this->ProjectDirs_.Source, + true) || + !info.GetString("CMAKE_BINARY_DIR", this->ProjectDirs_.Binary, + true) || !info.GetString("CMAKE_CURRENT_SOURCE_DIR", - ProjectDirs_.CurrentSource, true) || + this->ProjectDirs_.CurrentSource, true) || !info.GetString("CMAKE_CURRENT_BINARY_DIR", - ProjectDirs_.CurrentBinary, true)) { + this->ProjectDirs_.CurrentBinary, true)) { return false; } - Logger_.RaiseVerbosity(verbosity); + this->Logger_.RaiseVerbosity(verbosity); } // -- Call virtual init from info method. diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index b4f057d..53fbd69 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -88,10 +88,10 @@ public: cmQtAutoGenerator& operator=(cmQtAutoGenerator const&) = delete; // -- Info options - std::string const& InfoFile() const { return InfoFile_; } - std::string const& InfoDir() const { return InfoDir_; } - cmFileTime const& InfoFileTime() const { return InfoFileTime_; } - std::string const& InfoConfig() const { return InfoConfig_; } + std::string const& InfoFile() const { return this->InfoFile_; } + std::string const& InfoDir() const { return this->InfoDir_; } + cmFileTime const& InfoFileTime() const { return this->InfoFileTime_; } + std::string const& InfoConfig() const { return this->InfoConfig_; } // -- Info file parsing /** Info file reader class. */ @@ -124,7 +124,7 @@ public: Json::Value const& GetValue(std::string const& key) const { - return Json_[key]; + return this->Json_[key]; } /** Returns true if strings were appended to the list. */ @@ -150,7 +150,7 @@ public: cm::string_view key); // -- Directories - ProjectDirsT const& ProjectDirs() const { return ProjectDirs_; } + ProjectDirsT const& ProjectDirs() const { return this->ProjectDirs_; } std::string MessagePath(cm::string_view path) const; // -- Run @@ -161,7 +161,7 @@ protected: virtual bool InitFromInfo(InfoT const& info) = 0; virtual bool Process() = 0; // - Utility classes - Logger const& Log() const { return Logger_; } + Logger const& Log() const { return this->Logger_; } private: // -- Generator type diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 9cb172b..3556051 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -15,6 +15,7 @@ #include <vector> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #include <cmext/algorithm> @@ -26,7 +27,6 @@ #include "cmCryptoHash.h" #include "cmFileTime.h" #include "cmGccDepfileReader.h" -#include "cmGccDepfileReaderTypes.h" #include "cmGeneratedFileStream.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenerator.h" @@ -313,22 +313,22 @@ public: //! Get the generator. Only valid during Process() call! cmQtAutoMocUicT* Gen() const { - return static_cast<cmQtAutoMocUicT*>(UserData()); + return static_cast<cmQtAutoMocUicT*>(this->UserData()); }; // -- Accessors. Only valid during Process() call! - Logger const& Log() const { return Gen()->Log(); } - BaseSettingsT const& BaseConst() const { return Gen()->BaseConst(); } - BaseEvalT& BaseEval() const { return Gen()->BaseEval(); } - MocSettingsT const& MocConst() const { return Gen()->MocConst(); } - MocEvalT& MocEval() const { return Gen()->MocEval(); } - UicSettingsT const& UicConst() const { return Gen()->UicConst(); } - UicEvalT& UicEval() const { return Gen()->UicEval(); } + Logger const& Log() const { return this->Gen()->Log(); } + BaseSettingsT const& BaseConst() const { return this->Gen()->BaseConst(); } + BaseEvalT& BaseEval() const { return this->Gen()->BaseEval(); } + MocSettingsT const& MocConst() const { return this->Gen()->MocConst(); } + MocEvalT& MocEval() const { return this->Gen()->MocEval(); } + UicSettingsT const& UicConst() const { return this->Gen()->UicConst(); } + UicEvalT& UicEval() const { return this->Gen()->UicEval(); } // -- Logging std::string MessagePath(cm::string_view path) const { - return Gen()->MessagePath(path); + return this->Gen()->MessagePath(path); } // - Error logging with automatic abort void LogError(GenT genType, cm::string_view message) const; @@ -522,6 +522,7 @@ public: class JobDepFilesMergeT : public JobFenceT { private: + std::vector<std::string> initialDependencies() const; void Process() override; }; @@ -541,9 +542,9 @@ public: UicEvalT& UicEval() { return this->UicEval_; } // -- Parallel job processing interface - cmWorkerPool& WorkerPool() { return WorkerPool_; } - void AbortError() { Abort(true); } - void AbortSuccess() { Abort(false); } + cmWorkerPool& WorkerPool() { return this->WorkerPool_; } + void AbortError() { this->Abort(true); } + void AbortSuccess() { this->Abort(false); } // -- Utility std::string AbsoluteBuildPath(cm::string_view relativePath) const; @@ -597,19 +598,19 @@ cmQtAutoMocUicT::IncludeKeyT::IncludeKeyT(std::string const& key, , Base(cmSystemTools::GetFilenameWithoutLastExtension(key)) { if (basePrefixLength != 0) { - Base = Base.substr(basePrefixLength); + this->Base = this->Base.substr(basePrefixLength); } } void cmQtAutoMocUicT::ParseCacheT::FileT::Clear() { - Moc.Macro.clear(); - Moc.Include.Underscore.clear(); - Moc.Include.Dot.clear(); - Moc.Depends.clear(); + this->Moc.Macro.clear(); + this->Moc.Include.Underscore.clear(); + this->Moc.Include.Dot.clear(); + this->Moc.Depends.clear(); - Uic.Include.clear(); - Uic.Depends.clear(); + this->Uic.Include.clear(); + this->Uic.Depends.clear(); } cmQtAutoMocUicT::ParseCacheT::GetOrInsertT @@ -617,15 +618,15 @@ cmQtAutoMocUicT::ParseCacheT::GetOrInsert(std::string const& fileName) { // Find existing entry { - auto it = Map_.find(fileName); - if (it != Map_.end()) { + auto it = this->Map_.find(fileName); + if (it != this->Map_.end()) { return GetOrInsertT{ it->second, false }; } } // Insert new entry return GetOrInsertT{ - Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true + this->Map_.emplace(fileName, std::make_shared<FileT>()).first->second, true }; } @@ -655,7 +656,7 @@ bool cmQtAutoMocUicT::ParseCacheT::ReadFromFile(std::string const& fileName) } // Check if this a file name line if (line.front() != ' ') { - fileHandle = GetOrInsert(line).first; + fileHandle = this->GetOrInsert(line).first; continue; } @@ -702,7 +703,7 @@ bool cmQtAutoMocUicT::ParseCacheT::WriteToFile(std::string const& fileName) return false; } ofs << "# Generated by CMake. Changes will be overwritten.\n"; - for (auto const& pair : Map_) { + for (auto const& pair : this->Map_) { ofs << pair.first << '\n'; FileT const& file = *pair.second; if (!file.Moc.Macro.empty()) { @@ -732,7 +733,7 @@ cmQtAutoMocUicT::BaseSettingsT::~BaseSettingsT() = default; cmQtAutoMocUicT::MocSettingsT::MocSettingsT() { - RegExpInclude.compile( + this->RegExpInclude.compile( "(^|\n)[ \t]*#[ \t]*include[ \t]+" "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); } @@ -741,14 +742,15 @@ cmQtAutoMocUicT::MocSettingsT::~MocSettingsT() = default; bool cmQtAutoMocUicT::MocSettingsT::skipped(std::string const& fileName) const { - return (!Enabled || (SkipList.find(fileName) != SkipList.end())); + return (!this->Enabled || + (this->SkipList.find(fileName) != this->SkipList.end())); } std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const { std::string res; - const auto itB = MacroFilters.cbegin(); - const auto itE = MacroFilters.cend(); + const auto itB = this->MacroFilters.cbegin(); + const auto itE = this->MacroFilters.cend(); const auto itL = itE - 1; auto itC = itB; for (; itC != itE; ++itC) { @@ -768,30 +770,31 @@ std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const cmQtAutoMocUicT::UicSettingsT::UicSettingsT() { - RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); + this->RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); } cmQtAutoMocUicT::UicSettingsT::~UicSettingsT() = default; bool cmQtAutoMocUicT::UicSettingsT::skipped(std::string const& fileName) const { - return (!Enabled || (SkipList.find(fileName) != SkipList.end())); + return (!this->Enabled || + (this->SkipList.find(fileName) != this->SkipList.end())); } void cmQtAutoMocUicT::JobT::LogError(GenT genType, cm::string_view message) const { - Gen()->AbortError(); - Gen()->Log().Error(genType, message); + this->Gen()->AbortError(); + this->Gen()->Log().Error(genType, message); } void cmQtAutoMocUicT::JobT::LogCommandError( GenT genType, cm::string_view message, std::vector<std::string> const& command, std::string const& output) const { - Gen()->AbortError(); - Gen()->Log().ErrorCommand(genType, message, command, output); + this->Gen()->AbortError(); + this->Gen()->Log().ErrorCommand(genType, message, command, output); } bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType, @@ -800,48 +803,48 @@ bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType, std::string* infoMessage) { // Log command - if (Log().Verbose()) { + if (this->Log().Verbose()) { cm::string_view info; if (infoMessage != nullptr) { info = *infoMessage; } - Log().Info(genType, - cmStrCat(info, - info.empty() || cmHasSuffix(info, '\n') ? "" : "\n", - QuotedCommand(command), '\n')); + this->Log().Info( + genType, + cmStrCat(info, info.empty() || cmHasSuffix(info, '\n') ? "" : "\n", + QuotedCommand(command), '\n')); } // Run command - return cmWorkerPool::JobT::RunProcess(result, command, - BaseConst().AutogenBuildDir); + return this->cmWorkerPool::JobT::RunProcess( + result, command, this->BaseConst().AutogenBuildDir); } void cmQtAutoMocUicT::JobMocPredefsT::Process() { // (Re)generate moc_predefs.h on demand std::unique_ptr<std::string> reason; - if (Log().Verbose()) { + if (this->Log().Verbose()) { reason = cm::make_unique<std::string>(); } - if (!Update(reason.get())) { + if (!this->Update(reason.get())) { return; } - std::string const& predefsFileAbs = MocConst().PredefsFileAbs; + std::string const& predefsFileAbs = this->MocConst().PredefsFileAbs; { cmWorkerPool::ProcessResultT result; { // Compose command - std::vector<std::string> cmd = MocConst().PredefsCmd; + std::vector<std::string> cmd = this->MocConst().PredefsCmd; // Add definitions - cm::append(cmd, MocConst().OptionsDefinitions); + cm::append(cmd, this->MocConst().OptionsDefinitions); // Add includes - cm::append(cmd, MocConst().OptionsIncludes); + cm::append(cmd, this->MocConst().OptionsIncludes); // Execute command - if (!RunProcess(GenT::MOC, result, cmd, reason.get())) { - LogCommandError(GenT::MOC, - cmStrCat("The content generation command for ", - MessagePath(predefsFileAbs), " failed.\n", - result.ErrorMessage), - cmd, result.StdOut); + if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) { + this->LogCommandError(GenT::MOC, + cmStrCat("The content generation command for ", + this->MessagePath(predefsFileAbs), + " failed.\n", result.ErrorMessage), + cmd, result.StdOut); return; } } @@ -849,30 +852,31 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process() // (Re)write predefs file only on demand if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) { if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) { - LogError( + this->LogError( GenT::MOC, - cmStrCat("Writing ", MessagePath(predefsFileAbs), " failed.")); + cmStrCat("Writing ", this->MessagePath(predefsFileAbs), " failed.")); return; } } else { // Touch to update the time stamp - if (Log().Verbose()) { - Log().Info(GenT::MOC, "Touching " + MessagePath(predefsFileAbs)); + if (this->Log().Verbose()) { + this->Log().Info(GenT::MOC, + "Touching " + this->MessagePath(predefsFileAbs)); } if (!cmSystemTools::Touch(predefsFileAbs, false)) { - LogError( - GenT::MOC, - cmStrCat("Touching ", MessagePath(predefsFileAbs), " failed.")); + this->LogError(GenT::MOC, + cmStrCat("Touching ", this->MessagePath(predefsFileAbs), + " failed.")); return; } } } // Read file time afterwards - if (!MocEval().PredefsTime.Load(predefsFileAbs)) { - LogError(GenT::MOC, - cmStrCat("Reading the file time of ", MessagePath(predefsFileAbs), - " failed.")); + if (!this->MocEval().PredefsTime.Load(predefsFileAbs)) { + this->LogError(GenT::MOC, + cmStrCat("Reading the file time of ", + this->MessagePath(predefsFileAbs), " failed.")); return; } } @@ -880,18 +884,20 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process() bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const { // Test if the file exists - if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) { + if (!this->MocEval().PredefsTime.Load(this->MocConst().PredefsFileAbs)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs), + *reason = cmStrCat("Generating ", + this->MessagePath(this->MocConst().PredefsFileAbs), ", because it doesn't exist."); } return true; } // Test if the settings changed - if (MocConst().SettingsChanged) { + if (this->MocConst().SettingsChanged) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs), + *reason = cmStrCat("Generating ", + this->MessagePath(this->MocConst().PredefsFileAbs), ", because the moc settings changed."); } return true; @@ -899,14 +905,14 @@ bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const // Test if the executable is newer { - std::string const& exec = MocConst().PredefsCmd.at(0); + std::string const& exec = this->MocConst().PredefsCmd.at(0); cmFileTime execTime; if (execTime.Load(exec)) { - if (MocEval().PredefsTime.Older(execTime)) { + if (this->MocEval().PredefsTime.Older(execTime)) { if (reason != nullptr) { - *reason = - cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs), - " because it is older than ", MessagePath(exec), '.'); + *reason = cmStrCat( + "Generating ", this->MessagePath(this->MocConst().PredefsFileAbs), + " because it is older than ", this->MessagePath(exec), '.'); } return true; } @@ -919,25 +925,27 @@ bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const bool cmQtAutoMocUicT::JobParseT::ReadFile() { // Clear old parse information - FileHandle->ParseData->Clear(); - std::string const& fileName = FileHandle->FileName; + this->FileHandle->ParseData->Clear(); + std::string const& fileName = this->FileHandle->FileName; // Write info - if (Log().Verbose()) { - Log().Info(GenT::GEN, cmStrCat("Parsing ", MessagePath(fileName))); + if (this->Log().Verbose()) { + this->Log().Info(GenT::GEN, + cmStrCat("Parsing ", this->MessagePath(fileName))); } // Read file content { std::string error; - if (!cmQtAutoGenerator::FileRead(Content, fileName, &error)) { - LogError( - GenT::GEN, - cmStrCat("Could not read ", MessagePath(fileName), ".\n", error)); + if (!cmQtAutoGenerator::FileRead(this->Content, fileName, &error)) { + this->LogError(GenT::GEN, + cmStrCat("Could not read ", this->MessagePath(fileName), + ".\n", error)); return false; } } // Warn if empty - if (Content.empty()) { - Log().Warning(GenT::GEN, cmStrCat(MessagePath(fileName), " is empty.")); + if (this->Content.empty()) { + this->Log().Warning(GenT::GEN, + cmStrCat(this->MessagePath(fileName), " is empty.")); return false; } return true; @@ -958,16 +966,16 @@ void cmQtAutoMocUicT::JobParseT::CreateKeys( void cmQtAutoMocUicT::JobParseT::MocMacro() { - for (KeyExpT const& filter : MocConst().MacroFilters) { + for (KeyExpT const& filter : this->MocConst().MacroFilters) { // Run a simple find string check - if (Content.find(filter.Key) == std::string::npos) { + if (this->Content.find(filter.Key) == std::string::npos) { continue; } // Run the expensive regular expression check loop cmsys::RegularExpressionMatch match; - if (filter.Exp.find(Content.c_str(), match)) { + if (filter.Exp.find(this->Content.c_str(), match)) { // Keep detected macro name - FileHandle->ParseData->Moc.Macro = filter.Key; + this->FileHandle->ParseData->Moc.Macro = filter.Key; return; } } @@ -975,19 +983,20 @@ void cmQtAutoMocUicT::JobParseT::MocMacro() void cmQtAutoMocUicT::JobParseT::MocDependecies() { - if (MocConst().DependFilters.empty() || MocConst().CanOutputDependencies) { + if (this->MocConst().DependFilters.empty() || + this->MocConst().CanOutputDependencies) { return; } // Find dependency strings std::set<std::string> parseDepends; - for (KeyExpT const& filter : MocConst().DependFilters) { + for (KeyExpT const& filter : this->MocConst().DependFilters) { // Run a simple find string check - if (Content.find(filter.Key) == std::string::npos) { + if (this->Content.find(filter.Key) == std::string::npos) { continue; } // Run the expensive regular expression check loop - const char* contentChars = Content.c_str(); + const char* contentChars = this->Content.c_str(); cmsys::RegularExpressionMatch match; while (filter.Exp.find(contentChars, match)) { { @@ -1002,7 +1011,7 @@ void cmQtAutoMocUicT::JobParseT::MocDependecies() // Store dependency strings { - auto& Depends = FileHandle->ParseData->Moc.Depends; + auto& Depends = this->FileHandle->ParseData->Moc.Depends; Depends.reserve(parseDepends.size()); for (std::string const& item : parseDepends) { Depends.emplace_back(item); @@ -1016,15 +1025,15 @@ void cmQtAutoMocUicT::JobParseT::MocDependecies() void cmQtAutoMocUicT::JobParseT::MocIncludes() { - if (Content.find("moc") == std::string::npos) { + if (this->Content.find("moc") == std::string::npos) { return; } std::set<std::string> underscore; std::set<std::string> dot; { - const char* contentChars = Content.c_str(); - cmsys::RegularExpression const& regExp = MocConst().RegExpInclude; + const char* contentChars = this->Content.c_str(); + cmsys::RegularExpression const& regExp = this->MocConst().RegExpInclude; cmsys::RegularExpressionMatch match; while (regExp.find(contentChars, match)) { std::string incString = match.match(2); @@ -1042,21 +1051,21 @@ void cmQtAutoMocUicT::JobParseT::MocIncludes() contentChars += match.end(); } } - auto& Include = FileHandle->ParseData->Moc.Include; - CreateKeys(Include.Underscore, underscore, MocUnderscoreLength); - CreateKeys(Include.Dot, dot, 0); + auto& Include = this->FileHandle->ParseData->Moc.Include; + this->CreateKeys(Include.Underscore, underscore, MocUnderscoreLength); + this->CreateKeys(Include.Dot, dot, 0); } void cmQtAutoMocUicT::JobParseT::UicIncludes() { - if (Content.find("ui_") == std::string::npos) { + if (this->Content.find("ui_") == std::string::npos) { return; } std::set<std::string> includes; { - const char* contentChars = Content.c_str(); - cmsys::RegularExpression const& regExp = UicConst().RegExpInclude; + 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)); @@ -1064,39 +1073,40 @@ void cmQtAutoMocUicT::JobParseT::UicIncludes() contentChars += match.end(); } } - CreateKeys(FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength); + this->CreateKeys(this->FileHandle->ParseData->Uic.Include, includes, + UiUnderscoreLength); } void cmQtAutoMocUicT::JobParseHeaderT::Process() { - if (!ReadFile()) { + if (!this->ReadFile()) { return; } // Moc parsing - if (FileHandle->Moc) { - MocMacro(); - MocDependecies(); + if (this->FileHandle->Moc) { + this->MocMacro(); + this->MocDependecies(); } // Uic parsing - if (FileHandle->Uic) { - UicIncludes(); + if (this->FileHandle->Uic) { + this->UicIncludes(); } } void cmQtAutoMocUicT::JobParseSourceT::Process() { - if (!ReadFile()) { + if (!this->ReadFile()) { return; } // Moc parsing - if (FileHandle->Moc) { - MocMacro(); - MocDependecies(); - MocIncludes(); + if (this->FileHandle->Moc) { + this->MocMacro(); + this->MocDependecies(); + this->MocIncludes(); } // Uic parsing - if (FileHandle->Uic) { - UicIncludes(); + if (this->FileHandle->Uic) { + this->UicIncludes(); } } @@ -1104,9 +1114,9 @@ std::string cmQtAutoMocUicT::JobEvalCacheT::MessageSearchLocations() const { std::string res; res.reserve(512); - for (std::string const& path : SearchLocations) { + for (std::string const& path : this->SearchLocations) { res += " "; - res += MessagePath(path); + res += this->MessagePath(path); res += '\n'; } return res; @@ -1115,14 +1125,14 @@ std::string cmQtAutoMocUicT::JobEvalCacheT::MessageSearchLocations() const void cmQtAutoMocUicT::JobEvalCacheMocT::Process() { // Evaluate headers - for (auto const& pair : BaseEval().Headers) { - if (!EvalHeader(pair.second)) { + for (auto const& pair : this->BaseEval().Headers) { + if (!this->EvalHeader(pair.second)) { return; } } // Evaluate sources - for (auto const& pair : BaseEval().Sources) { - if (!EvalSource(pair.second)) { + for (auto const& pair : this->BaseEval().Sources) { + if (!this->EvalSource(pair.second)) { return; } } @@ -1142,14 +1152,16 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source) handle->SourceFile = std::move(source); // Absolute build path - if (BaseConst().MultiConfig) { - handle->OutputFile = Gen()->AbsoluteIncludePath(sourceFile.BuildPath); + if (this->BaseConst().MultiConfig) { + handle->OutputFile = + this->Gen()->AbsoluteIncludePath(sourceFile.BuildPath); } else { - handle->OutputFile = Gen()->AbsoluteBuildPath(sourceFile.BuildPath); + handle->OutputFile = + this->Gen()->AbsoluteBuildPath(sourceFile.BuildPath); } // Register mapping in headers map - RegisterMapping(handle); + this->RegisterMapping(handle); } return true; @@ -1171,7 +1183,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName); // For relaxed mode check if the own "moc_" or ".moc" file is included - bool const relaxedMode = MocConst().RelaxedMode; + bool const relaxedMode = this->MocConst().RelaxedMode; bool sourceIncludesMocUnderscore = false; bool sourceIncludesDotMoc = false; // Check if the sources own "moc_" or ".moc" file is included @@ -1193,12 +1205,13 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( // Check if this source needs to be moc processed but doesn't. if (!sourceIncludesDotMoc && !parseData.Macro.empty() && !(relaxedMode && sourceIncludesMocUnderscore)) { - LogError(GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), "\ncontains a ", - Quoted(parseData.Macro), " macro, but does not include ", - MessagePath(sourceBase + ".moc"), - "!\nConsider to\n - add #include \"", sourceBase, - ".moc\"\n - enable SKIP_AUTOMOC for this file")); + this->LogError(GenT::MOC, + cmStrCat(this->MessagePath(sourceFile.FileName), + "\ncontains a ", Quoted(parseData.Macro), + " macro, but does not include ", + this->MessagePath(sourceBase + ".moc"), + "!\nConsider to\n - add #include \"", sourceBase, + ".moc\"\n - enable SKIP_AUTOMOC for this file")); return false; } @@ -1207,14 +1220,16 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( SourceFileHandleT headerHandle; { std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base); - if (!FindIncludedHeader(headerHandle, sourceDirPrefix, headerBase)) { - LogError(GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), - "\nincludes the moc file ", MessagePath(incKey.Key), - ",\nbut a header ", MessageHeader(headerBase), - "\ncould not be found " - "in the following directories\n", - MessageSearchLocations())); + if (!this->FindIncludedHeader(headerHandle, sourceDirPrefix, + headerBase)) { + this->LogError( + GenT::MOC, + cmStrCat(this->MessagePath(sourceFile.FileName), + "\nincludes the moc file ", this->MessagePath(incKey.Key), + ",\nbut a header ", this->MessageHeader(headerBase), + "\ncould not be found " + "in the following directories\n", + this->MessageSearchLocations())); return false; } } @@ -1228,30 +1243,31 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( // used. This is for KDE4 compatibility. // Issue a warning - Log().Warning( + this->Log().Warning( GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), "\ncontains a ", + cmStrCat(this->MessagePath(sourceFile.FileName), "\ncontains a ", Quoted(parseData.Macro), " macro, but does not include ", - MessagePath(sourceBase + ".moc"), ".\nInstead it includes ", - MessagePath(incKey.Key), ".\nRunning moc on the source\n ", - MessagePath(sourceFile.FileName), "!\nBetter include ", - MessagePath(sourceBase + ".moc"), + this->MessagePath(sourceBase + ".moc"), + ".\nInstead it includes ", this->MessagePath(incKey.Key), + ".\nRunning moc on the source\n ", + this->MessagePath(sourceFile.FileName), "!\nBetter include ", + this->MessagePath(sourceBase + ".moc"), " for compatibility with regular mode.\n", "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); // Create mapping - if (!RegisterIncluded(incKey.Key, source, source)) { + if (!this->RegisterIncluded(incKey.Key, source, source)) { return false; } continue; } // Check if header is skipped - if (MocConst().skipped(headerHandle->FileName)) { + if (this->MocConst().skipped(headerHandle->FileName)) { continue; } // Create mapping - if (!RegisterIncluded(incKey.Key, source, std::move(headerHandle))) { + if (!this->RegisterIncluded(incKey.Key, source, std::move(headerHandle))) { return false; } } @@ -1264,7 +1280,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( bool const ownMoc = (incKey.Base == sourceBase); if (ownMoc && !parseData.Macro.empty()) { // Create mapping for the regular use case - if (!RegisterIncluded(incKey.Key, source, source)) { + if (!this->RegisterIncluded(incKey.Key, source, source)) { return false; } continue; @@ -1274,50 +1290,54 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( SourceFileHandleT headerHandle; { std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base); - if (!FindIncludedHeader(headerHandle, sourceDirPrefix, headerBase)) { - LogError( + if (!this->FindIncludedHeader(headerHandle, sourceDirPrefix, + headerBase)) { + this->LogError( GenT::MOC, cmStrCat( - MessagePath(sourceFile.FileName), "\nincludes the moc file ", - MessagePath(incKey.Key), + this->MessagePath(sourceFile.FileName), + "\nincludes the moc file ", this->MessagePath(incKey.Key), ",\nwhich seems to be the moc file from a different source " "file.\nCMAKE_AUTOMOC_RELAXED_MODE:\nAlso a matching header ", - MessageHeader(headerBase), + this->MessageHeader(headerBase), "\ncould not be found in the following directories\n", - MessageSearchLocations())); + this->MessageSearchLocations())); return false; } } // Check if header is skipped - if (MocConst().skipped(headerHandle->FileName)) { + if (this->MocConst().skipped(headerHandle->FileName)) { continue; } // Issue a warning if (ownMoc && parseData.Macro.empty()) { - Log().Warning( + this->Log().Warning( GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), - "\nincludes the moc file ", MessagePath(incKey.Key), - ", but does not contain a\n", MocConst().MacrosString(), - " macro.\nRunning moc on the header\n ", - MessagePath(headerHandle->FileName), "!\nBetter include ", - MessagePath("moc_" + incKey.Base + ".cpp"), - " for a compatibility with regular mode.\n", - "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); + cmStrCat( + this->MessagePath(sourceFile.FileName), "\nincludes the moc file ", + this->MessagePath(incKey.Key), ", but does not contain a\n", + this->MocConst().MacrosString(), + " macro.\nRunning moc on the header\n ", + this->MessagePath(headerHandle->FileName), "!\nBetter include ", + this->MessagePath("moc_" + incKey.Base + ".cpp"), + " for a compatibility with regular mode.\n", + "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); } else { - Log().Warning( + this->Log().Warning( GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), - "\nincludes the moc file ", MessagePath(incKey.Key), - " instead of ", MessagePath("moc_" + incKey.Base + ".cpp"), - ".\nRunning moc on the header\n ", - MessagePath(headerHandle->FileName), "!\nBetter include ", - MessagePath("moc_" + incKey.Base + ".cpp"), - " for compatibility with regular mode.\n", - "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); + cmStrCat( + this->MessagePath(sourceFile.FileName), "\nincludes the moc file ", + this->MessagePath(incKey.Key), " instead of ", + this->MessagePath("moc_" + incKey.Base + ".cpp"), + ".\nRunning moc on the header\n ", + this->MessagePath(headerHandle->FileName), "!\nBetter include ", + this->MessagePath("moc_" + incKey.Base + ".cpp"), + " for compatibility with regular mode.\n", + "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); } // Create mapping - if (!RegisterIncluded(incKey.Key, source, std::move(headerHandle))) { + if (!this->RegisterIncluded(incKey.Key, source, + std::move(headerHandle))) { return false; } } @@ -1328,26 +1348,27 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( bool const ownMoc = (incKey.Base == sourceBase); if (!ownMoc) { // Don't allow <BASE>.moc include other than own in regular mode - LogError(GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), - "\nincludes the moc file ", MessagePath(incKey.Key), - ",\nwhich seems to be the moc file from a different " - "source file.\nThis is not supported. Include ", - MessagePath(sourceBase + ".moc"), - " to run moc on this source file.")); + this->LogError( + GenT::MOC, + cmStrCat(this->MessagePath(sourceFile.FileName), + "\nincludes the moc file ", this->MessagePath(incKey.Key), + ",\nwhich seems to be the moc file from a different " + "source file.\nThis is not supported. Include ", + this->MessagePath(sourceBase + ".moc"), + " to run moc on this source file.")); return false; } // Accept but issue a warning if moc isn't required if (parseData.Macro.empty()) { - Log().Warning(GenT::MOC, - cmStrCat(MessagePath(sourceFile.FileName), - "\nincludes the moc file ", - MessagePath(incKey.Key), - ", but does not contain a ", - MocConst().MacrosString(), " macro.")); + this->Log().Warning( + GenT::MOC, + cmStrCat(this->MessagePath(sourceFile.FileName), + "\nincludes the moc file ", this->MessagePath(incKey.Key), + ", but does not contain a ", + this->MocConst().MacrosString(), " macro.")); } // Create mapping - if (!RegisterIncluded(incKey.Key, source, source)) { + if (!this->RegisterIncluded(incKey.Key, source, source)) { return false; } } @@ -1361,7 +1382,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader( cm::string_view includeBase) { // Clear search locations - SearchLocations.clear(); + this->SearchLocations.clear(); auto findHeader = [this, &headerHandle](std::string const& basePath) -> bool { @@ -1377,8 +1398,8 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader( // Return a known file if it exists already { - auto it = BaseEval().Headers.find(testPath); - if (it != BaseEval().Headers.end()) { + auto it = this->BaseEval().Headers.find(testPath); + if (it != this->BaseEval().Headers.end()) { headerHandle = it->second; found = true; break; @@ -1387,7 +1408,8 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader( // Created and return discovered file entry { - SourceFileHandleT& handle = MocEval().HeadersDiscovered[testPath]; + SourceFileHandleT& handle = + this->MocEval().HeadersDiscovered[testPath]; if (!handle) { handle = std::make_shared<SourceFileT>(testPath); handle->FileTime = fileTime; @@ -1410,7 +1432,7 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader( return true; } // Search in include directories - for (std::string const& path : MocConst().IncludePaths) { + for (std::string const& path : this->MocConst().IncludePaths) { if (findHeader(cmStrCat(path, '/', includeBase))) { return true; } @@ -1424,24 +1446,24 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded( SourceFileHandleT sourceFileHandle) const { // Check if this file is already included - MappingHandleT& handle = MocEval().Includes[includeString]; + MappingHandleT& handle = this->MocEval().Includes[includeString]; if (handle) { // Check if the output file would be generated from different source files if (handle->SourceFile != sourceFileHandle) { std::string files = - cmStrCat(" ", MessagePath(includerFileHandle->FileName), '\n'); + cmStrCat(" ", this->MessagePath(includerFileHandle->FileName), '\n'); for (auto const& item : handle->IncluderFiles) { - files += cmStrCat(" ", MessagePath(item->FileName), '\n'); + files += cmStrCat(" ", this->MessagePath(item->FileName), '\n'); } - LogError( + this->LogError( GenT::MOC, cmStrCat("The source files\n", files, "contain the same include string ", - MessagePath(includeString), + this->MessagePath(includeString), ", but\nthe moc file would be generated from different " "source files\n ", - MessagePath(sourceFileHandle->FileName), " and\n ", - MessagePath(handle->SourceFile->FileName), + this->MessagePath(sourceFileHandle->FileName), " and\n ", + this->MessagePath(handle->SourceFile->FileName), ".\nConsider to\n" " - not include the \"moc_<NAME>.cpp\" file\n" " - add a directory prefix to a \"<NAME>.moc\" include " @@ -1460,10 +1482,10 @@ bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded( handle->IncludeString = includeString; handle->IncluderFiles.emplace_back(std::move(includerFileHandle)); handle->SourceFile = std::move(sourceFileHandle); - handle->OutputFile = Gen()->AbsoluteIncludePath(includeString); + handle->OutputFile = this->Gen()->AbsoluteIncludePath(includeString); // Register mapping in sources/headers map - RegisterMapping(handle); + this->RegisterMapping(handle); return true; } @@ -1471,8 +1493,8 @@ void cmQtAutoMocUicT::JobEvalCacheMocT::RegisterMapping( MappingHandleT mappingHandle) const { auto& regMap = mappingHandle->SourceFile->IsHeader - ? MocEval().HeaderMappings - : MocEval().SourceMappings; + ? this->MocEval().HeaderMappings + : this->MocEval().SourceMappings; // Check if source file already gets mapped auto& regHandle = regMap[mappingHandle->SourceFile->FileName]; if (!regHandle) { @@ -1489,24 +1511,24 @@ void cmQtAutoMocUicT::JobEvalCacheMocT::RegisterMapping( std::string cmQtAutoMocUicT::JobEvalCacheMocT::MessageHeader( cm::string_view headerBase) const { - return MessagePath(cmStrCat( + return this->MessagePath(cmStrCat( headerBase, ".{", cmJoin(this->BaseConst().HeaderExtensions, ","), '}')); } void cmQtAutoMocUicT::JobEvalCacheUicT::Process() { // Prepare buffers - SearchLocations.reserve((UicConst().SearchPaths.size() + 1) * 2); + this->SearchLocations.reserve((this->UicConst().SearchPaths.size() + 1) * 2); // Evaluate headers - for (auto const& pair : BaseEval().Headers) { - if (!EvalFile(pair.second)) { + for (auto const& pair : this->BaseEval().Headers) { + if (!this->EvalFile(pair.second)) { return; } } // Evaluate sources - for (auto const& pair : BaseEval().Sources) { - if (!EvalFile(pair.second)) { + for (auto const& pair : this->BaseEval().Sources) { + if (!this->EvalFile(pair.second)) { return; } } @@ -1524,22 +1546,24 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::EvalFile( std::string const sourceDirPrefix = SubDirPrefix(sourceFile.FileName); for (IncludeKeyT const& incKey : Include) { // Find .ui file - UiName = cmStrCat(incKey.Base, ".ui"); - if (!FindIncludedUi(sourceDirPrefix, incKey.Dir)) { - LogError(GenT::UIC, - cmStrCat(MessagePath(sourceFile.FileName), - "\nincludes the uic file ", MessagePath(incKey.Key), - ",\nbut the user interface file ", MessagePath(UiName), - "\ncould not be found in the following directories\n", - MessageSearchLocations())); + this->UiName = cmStrCat(incKey.Base, ".ui"); + if (!this->FindIncludedUi(sourceDirPrefix, incKey.Dir)) { + this->LogError( + GenT::UIC, + cmStrCat(this->MessagePath(sourceFile.FileName), + "\nincludes the uic file ", this->MessagePath(incKey.Key), + ",\nbut the user interface file ", + this->MessagePath(this->UiName), + "\ncould not be found in the following directories\n", + this->MessageSearchLocations())); return false; } // Check if the file is skipped - if (UicConst().skipped(UiFileHandle->FileName)) { + if (this->UicConst().skipped(this->UiFileHandle->FileName)) { continue; } // Register mapping - if (!RegisterMapping(incKey.Key, sourceFileHandle)) { + if (!this->RegisterMapping(incKey.Key, sourceFileHandle)) { return false; } } @@ -1551,7 +1575,7 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi( cm::string_view sourceDirPrefix, cm::string_view includePrefix) { // Clear locations buffer - SearchLocations.clear(); + this->SearchLocations.clear(); auto findUi = [this](std::string const& testPath) -> bool { std::string const fullPath = this->Gen()->CollapseFullPathTS(testPath); @@ -1573,25 +1597,25 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi( }; // Vicinity of the source - if (findUi(cmStrCat(sourceDirPrefix, UiName))) { + if (findUi(cmStrCat(sourceDirPrefix, this->UiName))) { return true; } if (!includePrefix.empty()) { - if (findUi(cmStrCat(sourceDirPrefix, includePrefix, UiName))) { + if (findUi(cmStrCat(sourceDirPrefix, includePrefix, this->UiName))) { return true; } } // Additional AUTOUIC search paths - auto const& searchPaths = UicConst().SearchPaths; + auto const& searchPaths = this->UicConst().SearchPaths; if (!searchPaths.empty()) { for (std::string const& sPath : searchPaths) { - if (findUi(cmStrCat(sPath, '/', UiName))) { + if (findUi(cmStrCat(sPath, '/', this->UiName))) { return true; } } if (!includePrefix.empty()) { for (std::string const& sPath : searchPaths) { - if (findUi(cmStrCat(sPath, '/', includePrefix, UiName))) { + if (findUi(cmStrCat(sPath, '/', includePrefix, this->UiName))) { return true; } } @@ -1604,26 +1628,26 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi( bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping( std::string const& includeString, SourceFileHandleT includerFileHandle) { - auto& Includes = Gen()->UicEval().Includes; + auto& Includes = this->Gen()->UicEval().Includes; auto it = Includes.find(includeString); if (it != Includes.end()) { MappingHandleT const& handle = it->second; - if (handle->SourceFile != UiFileHandle) { + if (handle->SourceFile != this->UiFileHandle) { // The output file already gets generated - from a different .ui file! std::string files = - cmStrCat(" ", MessagePath(includerFileHandle->FileName), '\n'); + cmStrCat(" ", this->MessagePath(includerFileHandle->FileName), '\n'); for (auto const& item : handle->IncluderFiles) { - files += cmStrCat(" ", MessagePath(item->FileName), '\n'); + files += cmStrCat(" ", this->MessagePath(item->FileName), '\n'); } - LogError( + this->LogError( GenT::UIC, cmStrCat( "The source files\n", files, "contain the same include string ", Quoted(includeString), ", but\nthe uic file would be generated from different " "user interface files\n ", - MessagePath(UiFileHandle->FileName), " and\n ", - MessagePath(handle->SourceFile->FileName), + this->MessagePath(this->UiFileHandle->FileName), " and\n ", + this->MessagePath(handle->SourceFile->FileName), ".\nConsider to\n" " - add a directory prefix to a \"ui_<NAME>.h\" include " "(e.g \"sub/ui_<NAME>.h\")\n" @@ -1638,8 +1662,8 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping( MappingHandleT handle = std::make_shared<MappingT>(); handle->IncludeString = includeString; handle->IncluderFiles.emplace_back(std::move(includerFileHandle)); - handle->SourceFile = UiFileHandle; - handle->OutputFile = Gen()->AbsoluteIncludePath(includeString); + handle->SourceFile = this->UiFileHandle; + handle->OutputFile = this->Gen()->AbsoluteIncludePath(includeString); // Register mapping Includes.emplace(includeString, std::move(handle)); } @@ -1649,40 +1673,42 @@ bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping( void cmQtAutoMocUicT::JobEvalCacheFinishT::Process() { // Add discovered header parse jobs - Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered); + this->Gen()->CreateParseJobs<JobParseHeaderT>( + this->MocEval().HeadersDiscovered); // Add dependency probing jobs { // Add fence job to ensure all parsing has finished - Gen()->WorkerPool().EmplaceJob<JobFenceT>(); - if (MocConst().Enabled) { - Gen()->WorkerPool().EmplaceJob<JobProbeDepsMocT>(); + this->Gen()->WorkerPool().EmplaceJob<JobFenceT>(); + if (this->MocConst().Enabled) { + this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsMocT>(); } - if (UicConst().Enabled) { - Gen()->WorkerPool().EmplaceJob<JobProbeDepsUicT>(); + if (this->UicConst().Enabled) { + this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsUicT>(); } // Add probe finish job - Gen()->WorkerPool().EmplaceJob<JobProbeDepsFinishT>(); + this->Gen()->WorkerPool().EmplaceJob<JobProbeDepsFinishT>(); } } void cmQtAutoMocUicT::JobProbeDepsMocT::Process() { // Create moc header jobs - for (auto const& pair : MocEval().HeaderMappings) { + for (auto const& pair : this->MocEval().HeaderMappings) { // Register if this mapping is a candidate for mocs_compilation.cpp bool const compFile = pair.second->IncludeString.empty(); if (compFile) { - MocEval().CompFiles.emplace_back(pair.second->SourceFile->BuildPath); + this->MocEval().CompFiles.emplace_back( + pair.second->SourceFile->BuildPath); } - if (!Generate(pair.second, compFile)) { + if (!this->Generate(pair.second, compFile)) { return; } } // Create moc source jobs - for (auto const& pair : MocEval().SourceMappings) { - if (!Generate(pair.second, false)) { + for (auto const& pair : this->MocEval().SourceMappings) { + if (!this->Generate(pair.second, false)) { return; } } @@ -1692,22 +1718,23 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Generate(MappingHandleT const& mapping, bool compFile) const { std::unique_ptr<std::string> reason; - if (Log().Verbose()) { + if (this->Log().Verbose()) { reason = cm::make_unique<std::string>(); } - if (Probe(*mapping, reason.get())) { + if (this->Probe(*mapping, reason.get())) { // Register the parent directory for creation - MocEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile)); + this->MocEval().OutputDirs.emplace( + cmQtAutoGen::ParentDir(mapping->OutputFile)); // Fetch the cache entry for the source file std::string const& sourceFile = mapping->SourceFile->FileName; ParseCacheT::GetOrInsertT cacheEntry = - BaseEval().ParseCache.GetOrInsert(sourceFile); + this->BaseEval().ParseCache.GetOrInsert(sourceFile); // Add moc job - Gen()->WorkerPool().EmplaceJob<JobCompileMocT>( + this->Gen()->WorkerPool().EmplaceJob<JobCompileMocT>( mapping, std::move(reason), std::move(cacheEntry.first)); // Check if a moc job for a mocs_compilation.cpp entry was generated if (compFile) { - MocEval().CompUpdated = true; + this->MocEval().CompUpdated = true; } } return true; @@ -1723,19 +1750,19 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping, cmFileTime outputFileTime; if (!outputFileTime.Load(outputFile)) { if (reason != nullptr) { - *reason = - cmStrCat("Generating ", MessagePath(outputFile), - ", because it doesn't exist, from ", MessagePath(sourceFile)); + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), + ", because it doesn't exist, from ", + this->MessagePath(sourceFile)); } return true; } // Test if any setting changed - if (MocConst().SettingsChanged) { + if (this->MocConst().SettingsChanged) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because the uic settings changed, from ", - MessagePath(sourceFile)); + this->MessagePath(sourceFile)); } return true; } @@ -1743,32 +1770,32 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping, // Test if the source file is newer if (outputFileTime.Older(mapping.SourceFile->FileTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because it's older than its source file, from ", - MessagePath(sourceFile)); + this->MessagePath(sourceFile)); } return true; } // Test if the moc_predefs file is newer - if (!MocConst().PredefsFileAbs.empty()) { - if (outputFileTime.Older(MocEval().PredefsTime)) { + if (!this->MocConst().PredefsFileAbs.empty()) { + if (outputFileTime.Older(this->MocEval().PredefsTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because it's older than ", - MessagePath(MocConst().PredefsFileAbs), ", from ", - MessagePath(sourceFile)); + this->MessagePath(this->MocConst().PredefsFileAbs), + ", from ", this->MessagePath(sourceFile)); } return true; } } // Test if the moc executable is newer - if (outputFileTime.Older(MocConst().ExecutableTime)) { + if (outputFileTime.Older(this->MocConst().ExecutableTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because it's older than the moc executable, from ", - MessagePath(sourceFile)); + this->MessagePath(sourceFile)); } return true; } @@ -1782,26 +1809,26 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping, auto& dep = *it; // Find dependency file - auto const depMatch = FindDependency(sourceDir, dep); + auto const depMatch = this->FindDependency(sourceDir, dep); if (depMatch.first.empty()) { if (reason != nullptr) { - *reason = - cmStrCat("Generating ", MessagePath(outputFile), " from ", - MessagePath(sourceFile), ", because its dependency ", - MessagePath(dep), " vanished."); + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), + " from ", this->MessagePath(sourceFile), + ", because its dependency ", + this->MessagePath(dep), " vanished."); } dependencies.erase(it); - BaseEval().ParseCacheChanged = true; + this->BaseEval().ParseCacheChanged = true; return true; } // Test if dependency file is older if (outputFileTime.Older(depMatch.second)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because it's older than its dependency file ", - MessagePath(depMatch.first), ", from ", - MessagePath(sourceFile)); + this->MessagePath(depMatch.first), ", from ", + this->MessagePath(sourceFile)); } return true; } @@ -1817,7 +1844,7 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency( { using ResPair = std::pair<std::string, cmFileTime>; // moc's dependency file contains absolute paths - if (MocConst().CanOutputDependencies) { + if (this->MocConst().CanOutputDependencies) { ResPair res{ includeString, {} }; if (res.second.Load(res.first)) { return res; @@ -1832,7 +1859,7 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency( } } // Search in include directories - for (std::string const& includePath : MocConst().IncludePaths) { + for (std::string const& includePath : this->MocConst().IncludePaths) { ResPair res{ cmStrCat(includePath, '/', includeString), {} }; if (res.second.Load(res.first)) { return res; @@ -1844,20 +1871,22 @@ cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency( void cmQtAutoMocUicT::JobProbeDepsUicT::Process() { - for (auto const& pair : Gen()->UicEval().Includes) { + for (auto const& pair : this->Gen()->UicEval().Includes) { MappingHandleT const& mapping = pair.second; std::unique_ptr<std::string> reason; - if (Log().Verbose()) { + if (this->Log().Verbose()) { reason = cm::make_unique<std::string>(); } - if (!Probe(*mapping, reason.get())) { + if (!this->Probe(*mapping, reason.get())) { continue; } // Register the parent directory for creation - UicEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile)); + this->UicEval().OutputDirs.emplace( + cmQtAutoGen::ParentDir(mapping->OutputFile)); // Add uic job - Gen()->WorkerPool().EmplaceJob<JobCompileUicT>(mapping, std::move(reason)); + this->Gen()->WorkerPool().EmplaceJob<JobCompileUicT>(mapping, + std::move(reason)); } } @@ -1871,19 +1900,19 @@ bool cmQtAutoMocUicT::JobProbeDepsUicT::Probe(MappingT const& mapping, cmFileTime outputFileTime; if (!outputFileTime.Load(outputFile)) { if (reason != nullptr) { - *reason = - cmStrCat("Generating ", MessagePath(outputFile), - ", because it doesn't exist, from ", MessagePath(sourceFile)); + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), + ", because it doesn't exist, from ", + this->MessagePath(sourceFile)); } return true; } // Test if the uic settings changed - if (UicConst().SettingsChanged) { + if (this->UicConst().SettingsChanged) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because the uic settings changed, from ", - MessagePath(sourceFile)); + this->MessagePath(sourceFile)); } return true; } @@ -1891,19 +1920,19 @@ bool cmQtAutoMocUicT::JobProbeDepsUicT::Probe(MappingT const& mapping, // Test if the source file is newer if (outputFileTime.Older(mapping.SourceFile->FileTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), " because it's older than the source file ", - MessagePath(sourceFile)); + this->MessagePath(sourceFile)); } return true; } // Test if the uic executable is newer - if (outputFileTime.Older(UicConst().ExecutableTime)) { + if (outputFileTime.Older(this->UicConst().ExecutableTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", MessagePath(outputFile), + *reason = cmStrCat("Generating ", this->MessagePath(outputFile), ", because it's older than the uic executable, from ", - MessagePath(sourceFile)); + this->MessagePath(sourceFile)); } return true; } @@ -1919,64 +1948,64 @@ void cmQtAutoMocUicT::JobProbeDepsFinishT::Process() auto createDirs = [this](GenT genType, StringSet const& dirSet) { for (std::string const& dirName : dirSet) { if (!cmSystemTools::MakeDirectory(dirName)) { - this->LogError( - genType, - cmStrCat("Creating directory ", MessagePath(dirName), " failed.")); + this->LogError(genType, + cmStrCat("Creating directory ", + this->MessagePath(dirName), " failed.")); return; } } }; - if (MocConst().Enabled && UicConst().Enabled) { - StringSet outputDirs = MocEval().OutputDirs; - outputDirs.insert(UicEval().OutputDirs.begin(), - UicEval().OutputDirs.end()); + if (this->MocConst().Enabled && this->UicConst().Enabled) { + StringSet outputDirs = this->MocEval().OutputDirs; + outputDirs.insert(this->UicEval().OutputDirs.begin(), + this->UicEval().OutputDirs.end()); createDirs(GenT::GEN, outputDirs); - } else if (MocConst().Enabled) { - createDirs(GenT::MOC, MocEval().OutputDirs); - } else if (UicConst().Enabled) { - createDirs(GenT::UIC, UicEval().OutputDirs); + } else if (this->MocConst().Enabled) { + createDirs(GenT::MOC, this->MocEval().OutputDirs); + } else if (this->UicConst().Enabled) { + createDirs(GenT::UIC, this->UicEval().OutputDirs); } } - if (MocConst().Enabled) { + if (this->MocConst().Enabled) { // Add mocs compilations job - Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>(); + this->Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>(); } - if (!BaseConst().DepFile.empty()) { + if (!this->BaseConst().DepFile.empty()) { // Add job to merge dep files - Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>(); + this->Gen()->WorkerPool().EmplaceJob<JobDepFilesMergeT>(); } // Add finish job - Gen()->WorkerPool().EmplaceJob<JobFinishT>(); + this->Gen()->WorkerPool().EmplaceJob<JobFinishT>(); } void cmQtAutoMocUicT::JobCompileMocT::Process() { - std::string const& sourceFile = Mapping->SourceFile->FileName; - std::string const& outputFile = Mapping->OutputFile; + std::string const& sourceFile = this->Mapping->SourceFile->FileName; + std::string const& outputFile = this->Mapping->OutputFile; // Compose moc command std::vector<std::string> cmd; { // Reserve large enough - cmd.reserve(MocConst().OptionsDefinitions.size() + - MocConst().OptionsIncludes.size() + - MocConst().OptionsExtra.size() + 16); - cmd.push_back(MocConst().Executable); + cmd.reserve(this->MocConst().OptionsDefinitions.size() + + this->MocConst().OptionsIncludes.size() + + this->MocConst().OptionsExtra.size() + 16); + cmd.push_back(this->MocConst().Executable); // Add definitions - cm::append(cmd, MocConst().OptionsDefinitions); + cm::append(cmd, this->MocConst().OptionsDefinitions); // Add includes - cm::append(cmd, MocConst().OptionsIncludes); + cm::append(cmd, this->MocConst().OptionsIncludes); // Add predefs include - if (!MocConst().PredefsFileAbs.empty()) { + if (!this->MocConst().PredefsFileAbs.empty()) { cmd.emplace_back("--include"); - cmd.push_back(MocConst().PredefsFileAbs); + cmd.push_back(this->MocConst().PredefsFileAbs); } // Add path prefix on demand - if (MocConst().PathPrefix && Mapping->SourceFile->IsHeader) { - for (std::string const& dir : MocConst().IncludePaths) { + if (this->MocConst().PathPrefix && this->Mapping->SourceFile->IsHeader) { + for (std::string const& dir : this->MocConst().IncludePaths) { cm::string_view prefix = sourceFile; if (cmHasPrefix(prefix, dir)) { prefix.remove_prefix(dir.size()); @@ -1996,8 +2025,8 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() } } // Add extra options - cm::append(cmd, MocConst().OptionsExtra); - if (MocConst().CanOutputDependencies) { + cm::append(cmd, this->MocConst().OptionsExtra); + if (this->MocConst().CanOutputDependencies) { cmd.emplace_back("--output-dep-file"); } // Add output file @@ -2009,60 +2038,60 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() // Execute moc command cmWorkerPool::ProcessResultT result; - if (!RunProcess(GenT::MOC, result, cmd, Reason.get())) { + if (!this->RunProcess(GenT::MOC, result, cmd, this->Reason.get())) { // Moc command failed std::string includers; - if (!Mapping->IncluderFiles.empty()) { + if (!this->Mapping->IncluderFiles.empty()) { includers = "included by\n"; - for (auto const& item : Mapping->IncluderFiles) { - includers += cmStrCat(" ", MessagePath(item->FileName), '\n'); + for (auto const& item : this->Mapping->IncluderFiles) { + includers += cmStrCat(" ", this->MessagePath(item->FileName), '\n'); } } - LogCommandError(GenT::MOC, - cmStrCat("The moc process failed to compile\n ", - MessagePath(sourceFile), "\ninto\n ", - MessagePath(outputFile), '\n', includers, - result.ErrorMessage), - cmd, result.StdOut); + this->LogCommandError(GenT::MOC, + cmStrCat("The moc process failed to compile\n ", + this->MessagePath(sourceFile), "\ninto\n ", + this->MessagePath(outputFile), '\n', + includers, result.ErrorMessage), + cmd, result.StdOut); return; } // Moc command success. Print moc output. if (!result.StdOut.empty()) { - Log().Info(GenT::MOC, result.StdOut); + this->Log().Info(GenT::MOC, result.StdOut); } // Extract dependencies from the dep file moc generated for us - if (MocConst().CanOutputDependencies) { + if (this->MocConst().CanOutputDependencies) { const std::string depfile = outputFile + ".d"; - if (Log().Verbose()) { - Log().Info(GenT::MOC, - "Reading dependencies from " + MessagePath(depfile)); + if (this->Log().Verbose()) { + this->Log().Info( + GenT::MOC, "Reading dependencies from " + this->MessagePath(depfile)); } if (!cmSystemTools::FileExists(depfile)) { - Log().Warning(GenT::MOC, - "Dependency file " + MessagePath(depfile) + - " does not exist."); + this->Log().Warning(GenT::MOC, + "Dependency file " + this->MessagePath(depfile) + + " does not exist."); return; } - CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str()); + this->CacheEntry->Moc.Depends = dependenciesFromDepFile(depfile.c_str()); } } void cmQtAutoMocUicT::JobCompileUicT::Process() { - std::string const& sourceFile = Mapping->SourceFile->FileName; - std::string const& outputFile = Mapping->OutputFile; + std::string const& sourceFile = this->Mapping->SourceFile->FileName; + std::string const& outputFile = this->Mapping->OutputFile; // Compose uic command std::vector<std::string> cmd; - cmd.push_back(UicConst().Executable); + cmd.push_back(this->UicConst().Executable); { - std::vector<std::string> allOpts = UicConst().Options; - auto optionIt = UicConst().UiFiles.find(sourceFile); - if (optionIt != UicConst().UiFiles.end()) { + std::vector<std::string> allOpts = this->UicConst().Options; + auto optionIt = this->UicConst().UiFiles.find(sourceFile); + if (optionIt != this->UicConst().UiFiles.end()) { UicMergeOptions(allOpts, optionIt->second.Options, - (BaseConst().QtVersion.Major == 5)); + (this->BaseConst().QtVersion.Major == 5)); } cm::append(cmd, allOpts); } @@ -2071,24 +2100,25 @@ void cmQtAutoMocUicT::JobCompileUicT::Process() cmd.emplace_back(sourceFile); cmWorkerPool::ProcessResultT result; - if (RunProcess(GenT::UIC, result, cmd, Reason.get())) { + if (this->RunProcess(GenT::UIC, result, cmd, this->Reason.get())) { // Uic command success // Print uic output if (!result.StdOut.empty()) { - Log().Info(GenT::UIC, result.StdOut); + this->Log().Info(GenT::UIC, result.StdOut); } } else { // Uic command failed std::string includers; - for (auto const& item : Mapping->IncluderFiles) { - includers += cmStrCat(" ", MessagePath(item->FileName), '\n'); + for (auto const& item : this->Mapping->IncluderFiles) { + includers += cmStrCat(" ", this->MessagePath(item->FileName), '\n'); } - LogCommandError(GenT::UIC, - cmStrCat("The uic process failed to compile\n ", - MessagePath(sourceFile), "\ninto\n ", - MessagePath(outputFile), "\nincluded by\n", - includers, result.ErrorMessage), - cmd, result.StdOut); + this->LogCommandError(GenT::UIC, + cmStrCat("The uic process failed to compile\n ", + this->MessagePath(sourceFile), "\ninto\n ", + this->MessagePath(outputFile), + "\nincluded by\n", includers, + result.ErrorMessage), + cmd, result.StdOut); } } @@ -2098,41 +2128,41 @@ void cmQtAutoMocUicT::JobMocsCompilationT::Process() std::string content = "// This file is autogenerated. Changes will be overwritten.\n"; - if (MocEval().CompFiles.empty()) { + if (this->MocEval().CompFiles.empty()) { // Placeholder content content += "// No files found that require moc or the moc files are " "included\n" "enum some_compilers { need_more_than_nothing };\n"; } else { // Valid content - const bool mc = BaseConst().MultiConfig; + const bool mc = this->BaseConst().MultiConfig; cm::string_view const wrapFront = mc ? "#include <" : "#include \""; cm::string_view const wrapBack = mc ? ">\n" : "\"\n"; - content += cmWrap(wrapFront, MocEval().CompFiles, wrapBack, ""); + content += cmWrap(wrapFront, this->MocEval().CompFiles, wrapBack, ""); } - std::string const& compAbs = MocConst().CompFileAbs; + std::string const& compAbs = this->MocConst().CompFileAbs; if (cmQtAutoGenerator::FileDiffers(compAbs, content)) { // Actually write mocs compilation file - if (Log().Verbose()) { - Log().Info(GenT::MOC, - "Generating MOC compilation " + MessagePath(compAbs)); + if (this->Log().Verbose()) { + this->Log().Info( + GenT::MOC, "Generating MOC compilation " + this->MessagePath(compAbs)); } if (!FileWrite(compAbs, content)) { - LogError(GenT::MOC, - cmStrCat("Writing MOC compilation ", MessagePath(compAbs), - " failed.")); + this->LogError(GenT::MOC, + cmStrCat("Writing MOC compilation ", + this->MessagePath(compAbs), " failed.")); } - } else if (MocEval().CompUpdated) { + } else if (this->MocEval().CompUpdated) { // Only touch mocs compilation file - if (Log().Verbose()) { - Log().Info(GenT::MOC, - "Touching MOC compilation " + MessagePath(compAbs)); + if (this->Log().Verbose()) { + this->Log().Info( + GenT::MOC, "Touching MOC compilation " + this->MessagePath(compAbs)); } if (!cmSystemTools::Touch(compAbs, false)) { - LogError(GenT::MOC, - cmStrCat("Touching MOC compilation ", MessagePath(compAbs), - " failed.")); + this->LogError(GenT::MOC, + cmStrCat("Touching MOC compilation ", + this->MessagePath(compAbs), " failed.")); } } } @@ -2169,12 +2199,36 @@ std::string escapeDependencyPath(cm::string_view path) return escapedPath; } +/* + * Return the initial dependencies of the merged depfile. + * Those are dependencies from the project files, not from moc runs. + */ +std::vector<std::string> +cmQtAutoMocUicT::JobDepFilesMergeT::initialDependencies() const +{ + std::vector<std::string> dependencies; + dependencies.reserve(this->BaseConst().ListFiles.size() + + this->BaseEval().Headers.size() + + this->BaseEval().Sources.size()); + cm::append(dependencies, this->BaseConst().ListFiles); + auto append_file_path = + [&dependencies](const SourceFileMapT::value_type& p) { + dependencies.push_back(p.first); + }; + std::for_each(this->BaseEval().Headers.begin(), + this->BaseEval().Headers.end(), append_file_path); + std::for_each(this->BaseEval().Sources.begin(), + this->BaseEval().Sources.end(), append_file_path); + return dependencies; +} + void cmQtAutoMocUicT::JobDepFilesMergeT::Process() { - if (Log().Verbose()) { - Log().Info(GenT::MOC, - cmStrCat("Merging MOC dependencies into ", - MessagePath(BaseConst().DepFile.c_str()))); + if (this->Log().Verbose()) { + this->Log().Info( + GenT::MOC, + cmStrCat("Merging MOC dependencies into ", + this->MessagePath(this->BaseConst().DepFile.c_str()))); } auto processDepFile = [](const std::string& mocOutputFile) -> std::vector<std::string> { @@ -2185,8 +2239,8 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() return dependenciesFromDepFile(f.c_str()); }; - std::vector<std::string> dependencies = BaseConst().ListFiles; - ParseCacheT& parseCache = BaseEval().ParseCache; + std::vector<std::string> dependencies = this->initialDependencies(); + ParseCacheT& parseCache = this->BaseEval().ParseCache; auto processMappingEntry = [&](const MappingMapT::value_type& m) { auto cacheEntry = parseCache.GetOrInsert(m.first); if (cacheEntry.first->Moc.Depends.empty()) { @@ -2197,10 +2251,10 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() cacheEntry.first->Moc.Depends.end()); }; - std::for_each(MocEval().HeaderMappings.begin(), - MocEval().HeaderMappings.end(), processMappingEntry); - std::for_each(MocEval().SourceMappings.begin(), - MocEval().SourceMappings.end(), processMappingEntry); + std::for_each(this->MocEval().HeaderMappings.begin(), + this->MocEval().HeaderMappings.end(), processMappingEntry); + std::for_each(this->MocEval().SourceMappings.begin(), + this->MocEval().SourceMappings.end(), processMappingEntry); // Remove duplicates to make the depfile smaller std::sort(dependencies.begin(), dependencies.end()); @@ -2208,39 +2262,42 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() dependencies.end()); // Add form files - for (const auto& uif : UicEval().UiFiles) { + for (const auto& uif : this->UicEval().UiFiles) { dependencies.push_back(uif.first); } // Write the file cmsys::ofstream ofs; - ofs.open(BaseConst().DepFile.c_str(), + ofs.open(this->BaseConst().DepFile.c_str(), (std::ios::out | std::ios::binary | std::ios::trunc)); if (!ofs) { - LogError(GenT::GEN, - cmStrCat("Cannot open ", MessagePath(BaseConst().DepFile), - " for writing.")); + this->LogError(GenT::GEN, + cmStrCat("Cannot open ", + this->MessagePath(this->BaseConst().DepFile), + " for writing.")); return; } - ofs << BaseConst().DepFileRuleName << ": \\\n"; + ofs << this->BaseConst().DepFileRuleName << ": \\\n"; for (const std::string& file : dependencies) { ofs << '\t' << escapeDependencyPath(file) << " \\\n"; if (!ofs.good()) { - LogError(GenT::GEN, - cmStrCat("Writing depfile", MessagePath(BaseConst().DepFile), - " failed.")); + this->LogError(GenT::GEN, + cmStrCat("Writing depfile", + this->MessagePath(this->BaseConst().DepFile), + " failed.")); return; } } // Add the CMake executable to re-new cache data if necessary. // Also, this is the last entry, so don't add a backslash. - ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable) << '\n'; + ofs << '\t' << escapeDependencyPath(this->BaseConst().CMakeExecutable) + << '\n'; } void cmQtAutoMocUicT::JobFinishT::Process() { - Gen()->AbortSuccess(); + this->Gen()->AbortSuccess(); } cmQtAutoMocUicT::cmQtAutoMocUicT() @@ -2252,42 +2309,51 @@ cmQtAutoMocUicT::~cmQtAutoMocUicT() = default; bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) { // -- Required settings - if (!info.GetBool("MULTI_CONFIG", BaseConst_.MultiConfig, true) || - !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersion.Major, true) || - !info.GetUInt("QT_VERSION_MINOR", BaseConst_.QtVersion.Minor, true) || - !info.GetUInt("PARALLEL", BaseConst_.ThreadCount, false) || - !info.GetString("BUILD_DIR", BaseConst_.AutogenBuildDir, true) || - !info.GetStringConfig("INCLUDE_DIR", BaseConst_.AutogenIncludeDir, + if (!info.GetBool("MULTI_CONFIG", this->BaseConst_.MultiConfig, true) || + !info.GetUInt("QT_VERSION_MAJOR", this->BaseConst_.QtVersion.Major, + true) || + !info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor, + true) || + !info.GetUInt("PARALLEL", this->BaseConst_.ThreadCount, false) || + !info.GetString("BUILD_DIR", this->BaseConst_.AutogenBuildDir, true) || + !info.GetStringConfig("INCLUDE_DIR", this->BaseConst_.AutogenIncludeDir, true) || - !info.GetString("CMAKE_EXECUTABLE", BaseConst_.CMakeExecutable, true) || - !info.GetStringConfig("PARSE_CACHE_FILE", BaseConst_.ParseCacheFile, - true) || - !info.GetString("DEP_FILE", BaseConst_.DepFile, false) || - !info.GetString("DEP_FILE_RULE_NAME", BaseConst_.DepFileRuleName, + !info.GetString("CMAKE_EXECUTABLE", this->BaseConst_.CMakeExecutable, + true) || + !info.GetStringConfig("PARSE_CACHE_FILE", + this->BaseConst_.ParseCacheFile, true) || + !info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) || + !info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName, + false) || + !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) || + !info.GetArray("CMAKE_LIST_FILES", this->BaseConst_.ListFiles, true) || + !info.GetArray("HEADER_EXTENSIONS", this->BaseConst_.HeaderExtensions, + true) || + !info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable, false) || - !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || - !info.GetArray("CMAKE_LIST_FILES", BaseConst_.ListFiles, true) || - !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) || - !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) || - !info.GetString("QT_UIC_EXECUTABLE", UicConst_.Executable, false)) { + !info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable, + false)) { return false; } // -- Checks - if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) { - return info.LogError(cmStrCat("The CMake executable ", - MessagePath(BaseConst_.CMakeExecutable), - " does not exist.")); + if (!this->BaseConst_.CMakeExecutableTime.Load( + this->BaseConst_.CMakeExecutable)) { + return info.LogError( + cmStrCat("The CMake executable ", + this->MessagePath(this->BaseConst_.CMakeExecutable), + " does not exist.")); } // -- Evaluate values - BaseConst_.ThreadCount = std::min(BaseConst_.ThreadCount, ParallelMax); - WorkerPool_.SetThreadCount(BaseConst_.ThreadCount); + this->BaseConst_.ThreadCount = + std::min(this->BaseConst_.ThreadCount, ParallelMax); + this->WorkerPool_.SetThreadCount(this->BaseConst_.ThreadCount); // -- Moc - if (!MocConst_.Executable.empty()) { + if (!this->MocConst_.Executable.empty()) { // -- Moc is enabled - MocConst_.Enabled = true; + this->MocConst_.Enabled = true; // -- Temporary buffers struct @@ -2297,18 +2363,21 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) } tmp; // -- Required settings - if (!info.GetBool("MOC_RELAXED_MODE", MocConst_.RelaxedMode, false) || - !info.GetBool("MOC_PATH_PREFIX", MocConst_.PathPrefix, true) || - !info.GetArray("MOC_SKIP", MocConst_.SkipList, false) || - !info.GetArrayConfig("MOC_DEFINITIONS", MocConst_.Definitions, + if (!info.GetBool("MOC_RELAXED_MODE", this->MocConst_.RelaxedMode, + false) || + !info.GetBool("MOC_PATH_PREFIX", this->MocConst_.PathPrefix, true) || + !info.GetArray("MOC_SKIP", this->MocConst_.SkipList, false) || + !info.GetArrayConfig("MOC_DEFINITIONS", this->MocConst_.Definitions, + false) || + !info.GetArrayConfig("MOC_INCLUDES", this->MocConst_.IncludePaths, false) || - !info.GetArrayConfig("MOC_INCLUDES", MocConst_.IncludePaths, false) || - !info.GetArray("MOC_OPTIONS", MocConst_.OptionsExtra, false) || - !info.GetStringConfig("MOC_COMPILATION_FILE", MocConst_.CompFileAbs, - true) || - !info.GetArray("MOC_PREDEFS_CMD", MocConst_.PredefsCmd, false) || - !info.GetStringConfig("MOC_PREDEFS_FILE", MocConst_.PredefsFileAbs, - !MocConst_.PredefsCmd.empty()) || + !info.GetArray("MOC_OPTIONS", this->MocConst_.OptionsExtra, false) || + !info.GetStringConfig("MOC_COMPILATION_FILE", + this->MocConst_.CompFileAbs, true) || + !info.GetArray("MOC_PREDEFS_CMD", this->MocConst_.PredefsCmd, false) || + !info.GetStringConfig("MOC_PREDEFS_FILE", + this->MocConst_.PredefsFileAbs, + !this->MocConst_.PredefsCmd.empty()) || !info.GetArray("MOC_MACRO_NAMES", tmp.MacroNames, true) || !info.GetArray("MOC_DEPEND_FILTERS", tmp.DependFilters, false)) { return false; @@ -2316,12 +2385,12 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) // -- Evaluate settings for (std::string const& item : tmp.MacroNames) { - MocConst_.MacroFilters.emplace_back( + this->MocConst_.MacroFilters.emplace_back( item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]")); } // Can moc output dependencies or do we need to setup dependency filters? - if (BaseConst_.QtVersion >= IntegerVersion(5, 15)) { - MocConst_.CanOutputDependencies = true; + if (this->BaseConst_.QtVersion >= IntegerVersion(5, 15)) { + this->MocConst_.CanOutputDependencies = true; } else { Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS"); if (!val.isArray()) { @@ -2371,22 +2440,23 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) } } // Check if moc executable exists (by reading the file time) - if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) { - return info.LogError(cmStrCat("The moc executable ", - MessagePath(MocConst_.Executable), - " does not exist.")); + if (!this->MocConst_.ExecutableTime.Load(this->MocConst_.Executable)) { + return info.LogError(cmStrCat( + "The moc executable ", this->MessagePath(this->MocConst_.Executable), + " does not exist.")); } } // -- Uic - if (!UicConst_.Executable.empty()) { + if (!this->UicConst_.Executable.empty()) { // Uic is enabled - UicConst_.Enabled = true; + this->UicConst_.Enabled = true; // -- Required settings - if (!info.GetArray("UIC_SKIP", UicConst_.SkipList, false) || - !info.GetArray("UIC_SEARCH_PATHS", UicConst_.SearchPaths, false) || - !info.GetArrayConfig("UIC_OPTIONS", UicConst_.Options, false)) { + if (!info.GetArray("UIC_SKIP", this->UicConst_.SkipList, false) || + !info.GetArray("UIC_SEARCH_PATHS", this->UicConst_.SearchPaths, + false) || + !info.GetArrayConfig("UIC_OPTIONS", this->UicConst_.Options, false)) { return false; } // .ui files @@ -2420,17 +2490,17 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) return false; } - auto& uiFile = UicConst_.UiFiles[entryName.asString()]; + auto& uiFile = this->UicConst_.UiFiles[entryName.asString()]; InfoT::GetJsonArray(uiFile.Options, entryOptions); } } // -- Evaluate settings // Check if uic executable exists (by reading the file time) - if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) { - return info.LogError(cmStrCat("The uic executable ", - MessagePath(UicConst_.Executable), - " does not exist.")); + if (!this->UicConst_.ExecutableTime.Load(this->UicConst_.Executable)) { + return info.LogError(cmStrCat( + "The uic executable ", this->MessagePath(this->UicConst_.Executable), + " does not exist.")); } } @@ -2452,17 +2522,20 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) Json::Value const& entry = val[ii]; if (testEntry(entry.isArray(), "JSON value is not an array.") || - testEntry(entry.size() == 3, "JSON array size invalid.")) { + testEntry(entry.size() == 4, "JSON array size invalid.")) { return false; } Json::Value const& entryName = entry[0u]; Json::Value const& entryFlags = entry[1u]; - Json::Value const& entryBuild = entry[2u]; + Json::Value const& entryConfigs = entry[2u]; + Json::Value const& entryBuild = entry[3u]; if (testEntry(entryName.isString(), "JSON value for name is not a string.") || testEntry(entryFlags.isString(), "JSON value for flags is not a string.") || + testEntry(entryConfigs.isNull() || entryConfigs.isArray(), + "JSON value for configs is not null or array.") || testEntry(entryBuild.isString(), "JSON value for build path is not a string.")) { return false; @@ -2475,6 +2548,22 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) return false; } + if (entryConfigs.isArray()) { + bool configFound = false; + Json::ArrayIndex const configArraySize = entryConfigs.size(); + for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) { + Json::Value const& config = entryConfigs[ci]; + if (testEntry(config.isString(), + "JSON value in config array is not a string.")) { + return false; + } + configFound = configFound || config.asString() == this->InfoConfig(); + } + if (!configFound) { + continue; + } + } + cmFileTime fileTime; if (!fileTime.Load(name)) { return info.LogError(cmStrCat( @@ -2486,14 +2575,15 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) sourceHandle->IsHeader = true; sourceHandle->Moc = (flags[0] == 'M'); sourceHandle->Uic = (flags[1] == 'U'); - if (sourceHandle->Moc && MocConst().Enabled) { + if (sourceHandle->Moc && this->MocConst().Enabled) { if (build.empty()) { return info.LogError( cmStrCat("Header file ", ii, " build path is empty")); } sourceHandle->BuildPath = std::move(build); } - BaseEval().Headers.emplace(std::move(name), std::move(sourceHandle)); + this->BaseEval().Headers.emplace(std::move(name), + std::move(sourceHandle)); } } @@ -2515,16 +2605,19 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) Json::Value const& entry = val[ii]; if (testEntry(entry.isArray(), "JSON value is not an array.") || - testEntry(entry.size() == 2, "JSON array size invalid.")) { + testEntry(entry.size() == 3, "JSON array size invalid.")) { return false; } Json::Value const& entryName = entry[0u]; Json::Value const& entryFlags = entry[1u]; + Json::Value const& entryConfigs = entry[2u]; if (testEntry(entryName.isString(), "JSON value for name is not a string.") || testEntry(entryFlags.isString(), - "JSON value for flags is not a string.")) { + "JSON value for flags is not a string.") || + testEntry(entryConfigs.isNull() || entryConfigs.isArray(), + "JSON value for configs is not null or array.")) { return false; } @@ -2534,6 +2627,22 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) return false; } + if (entryConfigs.isArray()) { + bool configFound = false; + Json::ArrayIndex const configArraySize = entryConfigs.size(); + for (Json::ArrayIndex ci = 0; ci != configArraySize; ++ci) { + Json::Value const& config = entryConfigs[ci]; + if (testEntry(config.isString(), + "JSON value in config array is not a string.")) { + return false; + } + configFound = configFound || config.asString() == this->InfoConfig(); + } + if (!configFound) { + continue; + } + } + cmFileTime fileTime; if (!fileTime.Load(name)) { return info.LogError(cmStrCat( @@ -2545,18 +2654,19 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) sourceHandle->IsHeader = false; sourceHandle->Moc = (flags[0] == 'M'); sourceHandle->Uic = (flags[1] == 'U'); - BaseEval().Sources.emplace(std::move(name), std::move(sourceHandle)); + this->BaseEval().Sources.emplace(std::move(name), + std::move(sourceHandle)); } } // -- Init derived information // Moc variables - if (MocConst().Enabled) { + if (this->MocConst().Enabled) { // Compose moc includes list { // Compute framework paths std::set<std::string> frameworkPaths; - for (std::string const& path : MocConst().IncludePaths) { + for (std::string const& path : this->MocConst().IncludePaths) { // Extract framework path if (cmHasLiteralSuffix(path, ".framework/Headers")) { // Go up twice to get to the framework root @@ -2567,24 +2677,25 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) } } // Reserve options - MocConst_.OptionsIncludes.reserve(MocConst().IncludePaths.size() + - frameworkPaths.size() * 2); + this->MocConst_.OptionsIncludes.reserve( + this->MocConst().IncludePaths.size() + frameworkPaths.size() * 2); // Append includes - for (std::string const& path : MocConst().IncludePaths) { - MocConst_.OptionsIncludes.emplace_back("-I" + path); + for (std::string const& path : this->MocConst().IncludePaths) { + this->MocConst_.OptionsIncludes.emplace_back("-I" + path); } // Append framework includes for (std::string const& path : frameworkPaths) { - MocConst_.OptionsIncludes.emplace_back("-F"); - MocConst_.OptionsIncludes.push_back(path); + this->MocConst_.OptionsIncludes.emplace_back("-F"); + this->MocConst_.OptionsIncludes.push_back(path); } } // Compose moc definitions list { - MocConst_.OptionsDefinitions.reserve(MocConst().Definitions.size()); - for (std::string const& def : MocConst().Definitions) { - MocConst_.OptionsDefinitions.emplace_back("-D" + def); + this->MocConst_.OptionsDefinitions.reserve( + this->MocConst().Definitions.size()); + for (std::string const& def : this->MocConst().Definitions) { + this->MocConst_.OptionsDefinitions.emplace_back("-D" + def); } } } @@ -2595,16 +2706,16 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) template <class JOBTYPE> void cmQtAutoMocUicT::CreateParseJobs(SourceFileMapT const& sourceMap) { - cmFileTime const parseCacheTime = BaseEval().ParseCacheTime; - ParseCacheT& parseCache = BaseEval().ParseCache; + cmFileTime const parseCacheTime = this->BaseEval().ParseCacheTime; + ParseCacheT& parseCache = this->BaseEval().ParseCache; for (auto& src : sourceMap) { // Get or create the file parse data reference ParseCacheT::GetOrInsertT cacheEntry = parseCache.GetOrInsert(src.first); src.second->ParseData = std::move(cacheEntry.first); // Create a parse job if the cache file was missing or is older if (cacheEntry.second || src.second->FileTime.Newer(parseCacheTime)) { - BaseEval().ParseCacheChanged = true; - WorkerPool().EmplaceJob<JOBTYPE>(src.second); + this->BaseEval().ParseCacheChanged = true; + this->WorkerPool().EmplaceJob<JOBTYPE>(src.second); } } } @@ -2612,55 +2723,56 @@ void cmQtAutoMocUicT::CreateParseJobs(SourceFileMapT const& sourceMap) /** Concurrently callable implementation of cmSystemTools::CollapseFullPath */ std::string cmQtAutoMocUicT::CollapseFullPathTS(std::string const& path) const { - std::lock_guard<std::mutex> guard(CMakeLibMutex_); - return cmSystemTools::CollapseFullPath(path, ProjectDirs().CurrentSource); + std::lock_guard<std::mutex> guard(this->CMakeLibMutex_); + return cmSystemTools::CollapseFullPath(path, + this->ProjectDirs().CurrentSource); } void cmQtAutoMocUicT::InitJobs() { // Add moc_predefs.h job - if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) { - WorkerPool().EmplaceJob<JobMocPredefsT>(); + if (this->MocConst().Enabled && !this->MocConst().PredefsCmd.empty()) { + this->WorkerPool().EmplaceJob<JobMocPredefsT>(); } // Add header parse jobs - CreateParseJobs<JobParseHeaderT>(BaseEval().Headers); + this->CreateParseJobs<JobParseHeaderT>(this->BaseEval().Headers); // Add source parse jobs - CreateParseJobs<JobParseSourceT>(BaseEval().Sources); + this->CreateParseJobs<JobParseSourceT>(this->BaseEval().Sources); // Add parse cache evaluations jobs { // Add a fence job to ensure all parsing has finished - WorkerPool().EmplaceJob<JobFenceT>(); - if (MocConst().Enabled) { - WorkerPool().EmplaceJob<JobEvalCacheMocT>(); + this->WorkerPool().EmplaceJob<JobFenceT>(); + if (this->MocConst().Enabled) { + this->WorkerPool().EmplaceJob<JobEvalCacheMocT>(); } - if (UicConst().Enabled) { - WorkerPool().EmplaceJob<JobEvalCacheUicT>(); + if (this->UicConst().Enabled) { + this->WorkerPool().EmplaceJob<JobEvalCacheUicT>(); } // Add evaluate job - WorkerPool().EmplaceJob<JobEvalCacheFinishT>(); + this->WorkerPool().EmplaceJob<JobEvalCacheFinishT>(); } } bool cmQtAutoMocUicT::Process() { - SettingsFileRead(); - ParseCacheRead(); - if (!CreateDirectories()) { + this->SettingsFileRead(); + this->ParseCacheRead(); + if (!this->CreateDirectories()) { return false; } - InitJobs(); - if (!WorkerPool_.Process(this)) { + this->InitJobs(); + if (!this->WorkerPool_.Process(this)) { return false; } - if (JobError_) { + if (this->JobError_) { return false; } - if (!ParseCacheWrite()) { + if (!this->ParseCacheWrite()) { return false; } - if (!SettingsFileWrite()) { + if (!this->SettingsFileWrite()) { return false; } return true; @@ -2676,70 +2788,72 @@ void cmQtAutoMocUicT::SettingsFileRead() cryptoHash.Append(";"); }; - if (MocConst_.Enabled) { + if (this->MocConst_.Enabled) { cryptoHash.Initialize(); - cha(MocConst().Executable); - for (auto const& item : MocConst().OptionsDefinitions) { + cha(this->MocConst().Executable); + for (auto const& item : this->MocConst().OptionsDefinitions) { cha(item); } - for (auto const& item : MocConst().OptionsIncludes) { + for (auto const& item : this->MocConst().OptionsIncludes) { cha(item); } - for (auto const& item : MocConst().OptionsExtra) { + for (auto const& item : this->MocConst().OptionsExtra) { cha(item); } - for (auto const& item : MocConst().PredefsCmd) { + for (auto const& item : this->MocConst().PredefsCmd) { cha(item); } - for (auto const& filter : MocConst().DependFilters) { + for (auto const& filter : this->MocConst().DependFilters) { cha(filter.Key); } - for (auto const& filter : MocConst().MacroFilters) { + for (auto const& filter : this->MocConst().MacroFilters) { cha(filter.Key); } - SettingsStringMoc_ = cryptoHash.FinalizeHex(); + this->SettingsStringMoc_ = cryptoHash.FinalizeHex(); } - if (UicConst().Enabled) { + if (this->UicConst().Enabled) { cryptoHash.Initialize(); - cha(UicConst().Executable); - std::for_each(UicConst().Options.begin(), UicConst().Options.end(), cha); - for (const auto& item : UicConst().UiFiles) { + cha(this->UicConst().Executable); + std::for_each(this->UicConst().Options.begin(), + this->UicConst().Options.end(), cha); + for (const auto& item : this->UicConst().UiFiles) { cha(item.first); auto const& opts = item.second.Options; std::for_each(opts.begin(), opts.end(), cha); } - SettingsStringUic_ = cryptoHash.FinalizeHex(); + this->SettingsStringUic_ = cryptoHash.FinalizeHex(); } } // Read old settings and compare { std::string content; - if (cmQtAutoGenerator::FileRead(content, SettingsFile_)) { - if (MocConst().Enabled) { - if (SettingsStringMoc_ != SettingsFind(content, "moc")) { - MocConst_.SettingsChanged = true; + if (cmQtAutoGenerator::FileRead(content, this->SettingsFile_)) { + if (this->MocConst().Enabled) { + if (this->SettingsStringMoc_ != SettingsFind(content, "moc")) { + this->MocConst_.SettingsChanged = true; } } - if (UicConst().Enabled) { - if (SettingsStringUic_ != SettingsFind(content, "uic")) { - UicConst_.SettingsChanged = true; + if (this->UicConst().Enabled) { + if (this->SettingsStringUic_ != SettingsFind(content, "uic")) { + this->UicConst_.SettingsChanged = true; } } // In case any setting changed remove the old settings file. // This triggers a full rebuild on the next run if the current // build is aborted before writing the current settings in the end. - if (MocConst().SettingsChanged || UicConst().SettingsChanged) { - cmSystemTools::RemoveFile(SettingsFile_); + if (this->MocConst().SettingsChanged || + this->UicConst().SettingsChanged) { + cmSystemTools::RemoveFile(this->SettingsFile_); } } else { // Settings file read failed - if (MocConst().Enabled) { - MocConst_.SettingsChanged = true; + if (this->MocConst().Enabled) { + this->MocConst_.SettingsChanged = true; } - if (UicConst().Enabled) { - UicConst_.SettingsChanged = true; + if (this->UicConst().Enabled) { + this->UicConst_.SettingsChanged = true; } } } @@ -2748,11 +2862,11 @@ void cmQtAutoMocUicT::SettingsFileRead() bool cmQtAutoMocUicT::SettingsFileWrite() { // Only write if any setting changed - if (MocConst().SettingsChanged || UicConst().SettingsChanged) { - if (Log().Verbose()) { - Log().Info( - GenT::GEN, - cmStrCat("Writing the settings file ", MessagePath(SettingsFile_))); + if (this->MocConst().SettingsChanged || this->UicConst().SettingsChanged) { + if (this->Log().Verbose()) { + this->Log().Info(GenT::GEN, + cmStrCat("Writing the settings file ", + this->MessagePath(this->SettingsFile_))); } // Compose settings file content std::string content; @@ -2763,17 +2877,18 @@ bool cmQtAutoMocUicT::SettingsFileWrite() content += cmStrCat(key, ':', value, '\n'); } }; - SettingAppend("moc", SettingsStringMoc_); - SettingAppend("uic", SettingsStringUic_); + SettingAppend("moc", this->SettingsStringMoc_); + SettingAppend("uic", this->SettingsStringUic_); } // Write settings file std::string error; - if (!cmQtAutoGenerator::FileWrite(SettingsFile_, content, &error)) { - Log().Error(GenT::GEN, - cmStrCat("Writing the settings file ", - MessagePath(SettingsFile_), " failed.\n", error)); + if (!cmQtAutoGenerator::FileWrite(this->SettingsFile_, content, &error)) { + this->Log().Error(GenT::GEN, + cmStrCat("Writing the settings file ", + this->MessagePath(this->SettingsFile_), + " failed.\n", error)); // Remove old settings file to trigger a full rebuild on the next run - cmSystemTools::RemoveFile(SettingsFile_); + cmSystemTools::RemoveFile(this->SettingsFile_); return false; } } @@ -2784,41 +2899,46 @@ void cmQtAutoMocUicT::ParseCacheRead() { cm::string_view reason; // Don't read the cache if it is invalid - if (!BaseEval().ParseCacheTime.Load(BaseConst().ParseCacheFile)) { + if (!this->BaseEval().ParseCacheTime.Load( + this->BaseConst().ParseCacheFile)) { reason = "Refreshing parse cache because it doesn't exist."; - } else if (MocConst().SettingsChanged || UicConst().SettingsChanged) { + } else if (this->MocConst().SettingsChanged || + this->UicConst().SettingsChanged) { reason = "Refreshing parse cache because the settings changed."; - } else if (BaseEval().ParseCacheTime.Older( - BaseConst().CMakeExecutableTime)) { + } else if (this->BaseEval().ParseCacheTime.Older( + this->BaseConst().CMakeExecutableTime)) { reason = "Refreshing parse cache because it is older than the CMake executable."; } if (!reason.empty()) { // Don't read but refresh the complete parse cache - if (Log().Verbose()) { - Log().Info(GenT::GEN, reason); + if (this->Log().Verbose()) { + this->Log().Info(GenT::GEN, reason); } - BaseEval().ParseCacheChanged = true; + this->BaseEval().ParseCacheChanged = true; } else { // Read parse cache - BaseEval().ParseCache.ReadFromFile(BaseConst().ParseCacheFile); + this->BaseEval().ParseCache.ReadFromFile(this->BaseConst().ParseCacheFile); } } bool cmQtAutoMocUicT::ParseCacheWrite() { - if (BaseEval().ParseCacheChanged) { - if (Log().Verbose()) { - Log().Info(GenT::GEN, - cmStrCat("Writing the parse cache file ", - MessagePath(BaseConst().ParseCacheFile))); - } - if (!BaseEval().ParseCache.WriteToFile(BaseConst().ParseCacheFile)) { - Log().Error(GenT::GEN, - cmStrCat("Writing the parse cache file ", - MessagePath(BaseConst().ParseCacheFile), - " failed.")); + if (this->BaseEval().ParseCacheChanged) { + if (this->Log().Verbose()) { + this->Log().Info( + GenT::GEN, + cmStrCat("Writing the parse cache file ", + this->MessagePath(this->BaseConst().ParseCacheFile))); + } + if (!this->BaseEval().ParseCache.WriteToFile( + this->BaseConst().ParseCacheFile)) { + this->Log().Error( + GenT::GEN, + cmStrCat("Writing the parse cache file ", + this->MessagePath(this->BaseConst().ParseCacheFile), + " failed.")); return false; } } @@ -2828,11 +2948,12 @@ bool cmQtAutoMocUicT::ParseCacheWrite() bool cmQtAutoMocUicT::CreateDirectories() { // Create AUTOGEN include directory - if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) { - Log().Error(GenT::GEN, - cmStrCat("Creating the AUTOGEN include directory ", - MessagePath(BaseConst().AutogenIncludeDir), - " failed.")); + if (!cmSystemTools::MakeDirectory(this->BaseConst().AutogenIncludeDir)) { + this->Log().Error( + GenT::GEN, + cmStrCat("Creating the AUTOGEN include directory ", + this->MessagePath(this->BaseConst().AutogenIncludeDir), + " failed.")); return false; } return true; @@ -2841,34 +2962,34 @@ bool cmQtAutoMocUicT::CreateDirectories() std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile( const char* filePath) { - cmGccDepfileContent content = cmReadGccDepfile(filePath); - if (content.empty()) { + auto const content = cmReadGccDepfile(filePath); + if (!content || content->empty()) { return {}; } // Moc outputs a depfile with exactly one rule. // Discard the rule and return the dependencies. - return content.front().paths; + return content->front().paths; } void cmQtAutoMocUicT::Abort(bool error) { if (error) { - JobError_.store(true); + this->JobError_.store(true); } - WorkerPool_.Abort(); + this->WorkerPool_.Abort(); } std::string cmQtAutoMocUicT::AbsoluteBuildPath( cm::string_view relativePath) const { - return cmStrCat(BaseConst().AutogenBuildDir, '/', relativePath); + return cmStrCat(this->BaseConst().AutogenBuildDir, '/', relativePath); } std::string cmQtAutoMocUicT::AbsoluteIncludePath( cm::string_view relativePath) const { - return cmStrCat(BaseConst().AutogenIncludeDir, '/', relativePath); + return cmStrCat(this->BaseConst().AutogenIncludeDir, '/', relativePath); } } // End of unnamed namespace diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx index 08eb4b5..943cc93 100644 --- a/Source/cmQtAutoRcc.cxx +++ b/Source/cmQtAutoRcc.cxx @@ -35,7 +35,7 @@ public: private: // -- Utility - bool IsMultiConfig() const { return MultiConfig_; } + bool IsMultiConfig() const { return this->MultiConfig_; } std::string MultiConfigOutput() const; // -- Abstract processing interface @@ -93,38 +93,41 @@ cmQtAutoRccT::~cmQtAutoRccT() = default; bool cmQtAutoRccT::InitFromInfo(InfoT const& info) { // -- Required settings - if (!info.GetBool("MULTI_CONFIG", MultiConfig_, true) || - !info.GetString("BUILD_DIR", AutogenBuildDir_, true) || - !info.GetStringConfig("INCLUDE_DIR", IncludeDir_, true) || - !info.GetString("RCC_EXECUTABLE", RccExecutable_, true) || - !info.GetArray("RCC_LIST_OPTIONS", RccListOptions_, false) || - !info.GetString("LOCK_FILE", LockFile_, true) || - !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || - !info.GetString("SOURCE", QrcFile_, true) || - !info.GetString("OUTPUT_CHECKSUM", RccPathChecksum_, true) || - !info.GetString("OUTPUT_NAME", RccFileName_, true) || - !info.GetArray("OPTIONS", Options_, false) || - !info.GetArray("INPUTS", Inputs_, false)) { + if (!info.GetBool("MULTI_CONFIG", this->MultiConfig_, true) || + !info.GetString("BUILD_DIR", this->AutogenBuildDir_, true) || + !info.GetStringConfig("INCLUDE_DIR", this->IncludeDir_, true) || + !info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) || + !info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) || + !info.GetString("LOCK_FILE", this->LockFile_, true) || + !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) || + !info.GetString("SOURCE", this->QrcFile_, true) || + !info.GetString("OUTPUT_CHECKSUM", this->RccPathChecksum_, true) || + !info.GetString("OUTPUT_NAME", this->RccFileName_, true) || + !info.GetArray("OPTIONS", this->Options_, false) || + !info.GetArray("INPUTS", this->Inputs_, false)) { return false; } // -- Derive information - QrcFileName_ = cmSystemTools::GetFilenameName(QrcFile_); - QrcFileDir_ = cmSystemTools::GetFilenamePath(QrcFile_); - RccFilePublic_ = - cmStrCat(AutogenBuildDir_, '/', RccPathChecksum_, '/', RccFileName_); + this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_); + this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_); + this->RccFilePublic_ = + cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/', + this->RccFileName_); // rcc output file name - if (IsMultiConfig()) { - RccFileOutput_ = cmStrCat(IncludeDir_, '/', MultiConfigOutput()); + if (this->IsMultiConfig()) { + this->RccFileOutput_ = + cmStrCat(this->IncludeDir_, '/', this->MultiConfigOutput()); } else { - RccFileOutput_ = RccFilePublic_; + this->RccFileOutput_ = this->RccFilePublic_; } // -- Checks - if (!RccExecutableTime_.Load(RccExecutable_)) { - return info.LogError(cmStrCat( - "The rcc executable ", MessagePath(RccExecutable_), " does not exist.")); + if (!this->RccExecutableTime_.Load(this->RccExecutable_)) { + return info.LogError(cmStrCat("The rcc executable ", + this->MessagePath(this->RccExecutable_), + " does not exist.")); } return true; @@ -132,41 +135,41 @@ bool cmQtAutoRccT::InitFromInfo(InfoT const& info) bool cmQtAutoRccT::Process() { - if (!SettingsFileRead()) { + if (!this->SettingsFileRead()) { return false; } // Test if the rcc output needs to be regenerated bool generate = false; - if (!TestQrcRccFiles(generate)) { + if (!this->TestQrcRccFiles(generate)) { return false; } - if (!generate && !TestResources(generate)) { + if (!generate && !this->TestResources(generate)) { return false; } // Generate on demand if (generate) { - if (!GenerateRcc()) { + if (!this->GenerateRcc()) { return false; } } else { // Test if the info file is newer than the output file - if (!TestInfoFile()) { + if (!this->TestInfoFile()) { return false; } } - if (!GenerateWrapper()) { + if (!this->GenerateWrapper()) { return false; } - return SettingsFileWrite(); + return this->SettingsFileWrite(); } std::string cmQtAutoRccT::MultiConfigOutput() const { - return cmStrCat(RccPathChecksum_, '/', - AppendFilenameSuffix(RccFileName_, "_CMAKE_")); + return cmStrCat(this->RccPathChecksum_, '/', + AppendFilenameSuffix(this->RccFileName_, "_CMAKE_")); } bool cmQtAutoRccT::SettingsFileRead() @@ -178,23 +181,25 @@ bool cmQtAutoRccT::SettingsFileRead() cryptoHash.Append(value); cryptoHash.Append(";"); }; - cha(RccExecutable_); - std::for_each(RccListOptions_.begin(), RccListOptions_.end(), cha); - cha(QrcFile_); - cha(RccPathChecksum_); - cha(RccFileName_); - std::for_each(Options_.begin(), Options_.end(), cha); - std::for_each(Inputs_.begin(), Inputs_.end(), cha); - SettingsString_ = cryptoHash.FinalizeHex(); + cha(this->RccExecutable_); + std::for_each(this->RccListOptions_.begin(), this->RccListOptions_.end(), + cha); + cha(this->QrcFile_); + cha(this->RccPathChecksum_); + cha(this->RccFileName_); + std::for_each(this->Options_.begin(), this->Options_.end(), cha); + std::for_each(this->Inputs_.begin(), this->Inputs_.end(), cha); + this->SettingsString_ = cryptoHash.FinalizeHex(); } // Make sure the settings file exists - if (!cmSystemTools::FileExists(SettingsFile_, true)) { + if (!cmSystemTools::FileExists(this->SettingsFile_, true)) { // Touch the settings file to make sure it exists - if (!cmSystemTools::Touch(SettingsFile_, true)) { - Log().Error(GenT::RCC, - cmStrCat("Touching the settings file ", - MessagePath(SettingsFile_), " failed.")); + if (!cmSystemTools::Touch(this->SettingsFile_, true)) { + this->Log().Error(GenT::RCC, + cmStrCat("Touching the settings file ", + this->MessagePath(this->SettingsFile_), + " failed.")); return false; } } @@ -202,21 +207,23 @@ bool cmQtAutoRccT::SettingsFileRead() // Lock the lock file { // Make sure the lock file exists - if (!cmSystemTools::FileExists(LockFile_, true)) { - if (!cmSystemTools::Touch(LockFile_, true)) { - Log().Error(GenT::RCC, - cmStrCat("Touching the lock file ", MessagePath(LockFile_), - " failed.")); + if (!cmSystemTools::FileExists(this->LockFile_, true)) { + if (!cmSystemTools::Touch(this->LockFile_, true)) { + this->Log().Error(GenT::RCC, + cmStrCat("Touching the lock file ", + this->MessagePath(this->LockFile_), + " failed.")); return false; } } // Lock the lock file - cmFileLockResult lockResult = - LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1)); + cmFileLockResult lockResult = this->LockFileLock_.Lock( + this->LockFile_, static_cast<unsigned long>(-1)); if (!lockResult.IsOk()) { - Log().Error(GenT::RCC, - cmStrCat("Locking of the lock file ", MessagePath(LockFile_), - " failed.\n", lockResult.GetOutputMessage())); + this->Log().Error(GenT::RCC, + cmStrCat("Locking of the lock file ", + this->MessagePath(this->LockFile_), + " failed.\n", lockResult.GetOutputMessage())); return false; } } @@ -224,23 +231,24 @@ bool cmQtAutoRccT::SettingsFileRead() // Read old settings { std::string content; - if (FileRead(content, SettingsFile_)) { - SettingsChanged_ = (SettingsString_ != SettingsFind(content, "rcc")); + if (FileRead(content, this->SettingsFile_)) { + this->SettingsChanged_ = + (this->SettingsString_ != SettingsFind(content, "rcc")); // In case any setting changed clear the old settings file. // This triggers a full rebuild on the next run if the current // build is aborted before writing the current settings in the end. - if (SettingsChanged_) { + if (this->SettingsChanged_) { std::string error; - if (!FileWrite(SettingsFile_, "", &error)) { - Log().Error(GenT::RCC, - cmStrCat("Clearing of the settings file ", - MessagePath(SettingsFile_), " failed.\n", - error)); + if (!FileWrite(this->SettingsFile_, "", &error)) { + this->Log().Error(GenT::RCC, + cmStrCat("Clearing of the settings file ", + this->MessagePath(this->SettingsFile_), + " failed.\n", error)); return false; } } } else { - SettingsChanged_ = true; + this->SettingsChanged_ = true; } } @@ -250,26 +258,28 @@ bool cmQtAutoRccT::SettingsFileRead() bool cmQtAutoRccT::SettingsFileWrite() { // Only write if any setting changed - if (SettingsChanged_) { - if (Log().Verbose()) { - Log().Info(GenT::RCC, - "Writing settings file " + MessagePath(SettingsFile_)); + if (this->SettingsChanged_) { + if (this->Log().Verbose()) { + this->Log().Info(GenT::RCC, + "Writing settings file " + + this->MessagePath(this->SettingsFile_)); } // Write settings file - std::string content = cmStrCat("rcc:", SettingsString_, '\n'); + std::string content = cmStrCat("rcc:", this->SettingsString_, '\n'); std::string error; - if (!FileWrite(SettingsFile_, content, &error)) { - Log().Error(GenT::RCC, - cmStrCat("Writing of the settings file ", - MessagePath(SettingsFile_), " failed.\n", error)); + if (!FileWrite(this->SettingsFile_, content, &error)) { + this->Log().Error(GenT::RCC, + cmStrCat("Writing of the settings file ", + this->MessagePath(this->SettingsFile_), + " failed.\n", error)); // Remove old settings file to trigger a full rebuild on the next run - cmSystemTools::RemoveFile(SettingsFile_); + cmSystemTools::RemoveFile(this->SettingsFile_); return false; } } // Unlock the lock file - LockFileLock_.Release(); + this->LockFileLock_.Release(); return true; } @@ -277,52 +287,57 @@ bool cmQtAutoRccT::SettingsFileWrite() bool cmQtAutoRccT::TestQrcRccFiles(bool& generate) { // Test if the rcc input file exists - if (!QrcFileTime_.Load(QrcFile_)) { - Log().Error(GenT::RCC, - cmStrCat("The resources file ", MessagePath(QrcFile_), - " does not exist")); + if (!this->QrcFileTime_.Load(this->QrcFile_)) { + this->Log().Error(GenT::RCC, + cmStrCat("The resources file ", + this->MessagePath(this->QrcFile_), + " does not exist")); return false; } // Test if the rcc output file exists - if (!RccFileTime_.Load(RccFileOutput_)) { - if (Log().Verbose()) { - Reason = - cmStrCat("Generating ", MessagePath(RccFileOutput_), - ", because it doesn't exist, from ", MessagePath(QrcFile_)); + if (!this->RccFileTime_.Load(this->RccFileOutput_)) { + if (this->Log().Verbose()) { + this->Reason = + cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_), + ", because it doesn't exist, from ", + this->MessagePath(this->QrcFile_)); } generate = true; return true; } // Test if the settings changed - if (SettingsChanged_) { - if (Log().Verbose()) { - Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), - ", because the rcc settings changed, from ", - MessagePath(QrcFile_)); + if (this->SettingsChanged_) { + if (this->Log().Verbose()) { + this->Reason = + cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_), + ", because the rcc settings changed, from ", + this->MessagePath(this->QrcFile_)); } generate = true; return true; } // Test if the rcc output file is older than the .qrc file - if (RccFileTime_.Older(QrcFileTime_)) { - if (Log().Verbose()) { - Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), - ", because it is older than ", MessagePath(QrcFile_), - ", from ", MessagePath(QrcFile_)); + if (this->RccFileTime_.Older(this->QrcFileTime_)) { + if (this->Log().Verbose()) { + this->Reason = cmStrCat( + "Generating ", this->MessagePath(this->RccFileOutput_), + ", because it is older than ", this->MessagePath(this->QrcFile_), + ", from ", this->MessagePath(this->QrcFile_)); } generate = true; return true; } // Test if the rcc output file is older than the rcc executable - if (RccFileTime_.Older(RccExecutableTime_)) { - if (Log().Verbose()) { - Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), - ", because it is older than the rcc executable, from ", - MessagePath(QrcFile_)); + if (this->RccFileTime_.Older(this->RccExecutableTime_)) { + if (this->Log().Verbose()) { + this->Reason = + cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_), + ", because it is older than the rcc executable, from ", + this->MessagePath(this->QrcFile_)); } generate = true; return true; @@ -334,34 +349,38 @@ bool cmQtAutoRccT::TestQrcRccFiles(bool& generate) bool cmQtAutoRccT::TestResources(bool& generate) { // Read resource files list - if (Inputs_.empty()) { + if (this->Inputs_.empty()) { std::string error; - RccLister const lister(RccExecutable_, RccListOptions_); - if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) { - Log().Error( - GenT::RCC, - cmStrCat("Listing of ", MessagePath(QrcFile_), " failed.\n", error)); + RccLister const lister(this->RccExecutable_, this->RccListOptions_); + if (!lister.list(this->QrcFile_, this->Inputs_, error, + this->Log().Verbose())) { + this->Log().Error(GenT::RCC, + cmStrCat("Listing of ", + this->MessagePath(this->QrcFile_), + " failed.\n", error)); return false; } } // Check if any resource file is newer than the rcc output file - for (std::string const& resFile : Inputs_) { + for (std::string const& resFile : this->Inputs_) { // Check if the resource file exists cmFileTime fileTime; if (!fileTime.Load(resFile)) { - Log().Error(GenT::RCC, - cmStrCat("The resource file ", MessagePath(resFile), - " listed in ", MessagePath(QrcFile_), - " does not exist.")); + this->Log().Error(GenT::RCC, + cmStrCat("The resource file ", + this->MessagePath(resFile), " listed in ", + this->MessagePath(this->QrcFile_), + " does not exist.")); return false; } // Check if the resource file is newer than the rcc output file - if (RccFileTime_.Older(fileTime)) { - if (Log().Verbose()) { - Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), - ", because it is older than ", MessagePath(resFile), - ", from ", MessagePath(QrcFile_)); + if (this->RccFileTime_.Older(fileTime)) { + if (this->Log().Verbose()) { + this->Reason = + cmStrCat("Generating ", this->MessagePath(this->RccFileOutput_), + ", because it is older than ", this->MessagePath(resFile), + ", from ", this->MessagePath(this->QrcFile_)); } generate = true; break; @@ -373,21 +392,23 @@ bool cmQtAutoRccT::TestResources(bool& generate) bool cmQtAutoRccT::TestInfoFile() { // Test if the rcc output file is older than the info file - if (RccFileTime_.Older(InfoFileTime())) { - if (Log().Verbose()) { - Log().Info(GenT::RCC, - cmStrCat("Touching ", MessagePath(RccFileOutput_), - " because it is older than ", - MessagePath(InfoFile()))); + if (this->RccFileTime_.Older(this->InfoFileTime())) { + if (this->Log().Verbose()) { + this->Log().Info(GenT::RCC, + cmStrCat("Touching ", + this->MessagePath(this->RccFileOutput_), + " because it is older than ", + this->MessagePath(this->InfoFile()))); } // Touch build file - if (!cmSystemTools::Touch(RccFileOutput_, false)) { - Log().Error( - GenT::RCC, - cmStrCat("Touching ", MessagePath(RccFileOutput_), " failed.")); + if (!cmSystemTools::Touch(this->RccFileOutput_, false)) { + this->Log().Error(GenT::RCC, + cmStrCat("Touching ", + this->MessagePath(this->RccFileOutput_), + " failed.")); return false; } - BuildFileChanged_ = true; + this->BuildFileChanged_ = true; } return true; @@ -396,51 +417,53 @@ bool cmQtAutoRccT::TestInfoFile() bool cmQtAutoRccT::GenerateRcc() { // Make parent directory - if (!MakeParentDirectory(RccFileOutput_)) { - Log().Error(GenT::RCC, - cmStrCat("Could not create parent directory of ", - MessagePath(RccFileOutput_))); + if (!MakeParentDirectory(this->RccFileOutput_)) { + this->Log().Error(GenT::RCC, + cmStrCat("Could not create parent directory of ", + this->MessagePath(this->RccFileOutput_))); return false; } // Compose rcc command std::vector<std::string> cmd; - cmd.push_back(RccExecutable_); - cm::append(cmd, Options_); + cmd.push_back(this->RccExecutable_); + cm::append(cmd, this->Options_); cmd.emplace_back("-o"); - cmd.push_back(RccFileOutput_); - cmd.push_back(QrcFile_); + cmd.push_back(this->RccFileOutput_); + cmd.push_back(this->QrcFile_); // Log reason and command - if (Log().Verbose()) { - Log().Info(GenT::RCC, - cmStrCat(Reason, cmHasSuffix(Reason, '\n') ? "" : "\n", - QuotedCommand(cmd), '\n')); + if (this->Log().Verbose()) { + this->Log().Info(GenT::RCC, + cmStrCat(this->Reason, + cmHasSuffix(this->Reason, '\n') ? "" : "\n", + QuotedCommand(cmd), '\n')); } std::string rccStdOut; std::string rccStdErr; int retVal = 0; bool result = cmSystemTools::RunSingleCommand( - cmd, &rccStdOut, &rccStdErr, &retVal, AutogenBuildDir_.c_str(), + cmd, &rccStdOut, &rccStdErr, &retVal, this->AutogenBuildDir_.c_str(), cmSystemTools::OUTPUT_NONE, cmDuration::zero(), cmProcessOutput::Auto); if (!result || (retVal != 0)) { // rcc process failed - Log().ErrorCommand(GenT::RCC, - cmStrCat("The rcc process failed to compile\n ", - MessagePath(QrcFile_), "\ninto\n ", - MessagePath(RccFileOutput_)), - cmd, rccStdOut + rccStdErr); - cmSystemTools::RemoveFile(RccFileOutput_); + this->Log().ErrorCommand(GenT::RCC, + cmStrCat("The rcc process failed to compile\n ", + this->MessagePath(this->QrcFile_), + "\ninto\n ", + this->MessagePath(this->RccFileOutput_)), + cmd, rccStdOut + rccStdErr); + cmSystemTools::RemoveFile(this->RccFileOutput_); return false; } // rcc process success // Print rcc output if (!rccStdOut.empty()) { - Log().Info(GenT::RCC, rccStdOut); + this->Log().Info(GenT::RCC, rccStdOut); } - BuildFileChanged_ = true; + this->BuildFileChanged_ = true; return true; } @@ -448,47 +471,48 @@ bool cmQtAutoRccT::GenerateRcc() bool cmQtAutoRccT::GenerateWrapper() { // Generate a wrapper source file on demand - if (IsMultiConfig()) { + if (this->IsMultiConfig()) { // Wrapper file content std::string content = cmStrCat("// This is an autogenerated configuration wrapper file.\n", "// Changes will be overwritten.\n", "#include <", - MultiConfigOutput(), ">\n"); + this->MultiConfigOutput(), ">\n"); // Compare with existing file content bool fileDiffers = true; { std::string oldContents; - if (FileRead(oldContents, RccFilePublic_)) { + if (FileRead(oldContents, this->RccFilePublic_)) { fileDiffers = (oldContents != content); } } if (fileDiffers) { // Write new wrapper file - if (Log().Verbose()) { - Log().Info(GenT::RCC, - cmStrCat("Generating RCC wrapper file ", - MessagePath(RccFilePublic_))); + if (this->Log().Verbose()) { + this->Log().Info(GenT::RCC, + cmStrCat("Generating RCC wrapper file ", + this->MessagePath(this->RccFilePublic_))); } std::string error; - if (!FileWrite(RccFilePublic_, content, &error)) { - Log().Error(GenT::RCC, - cmStrCat("Generating RCC wrapper file ", - MessagePath(RccFilePublic_), " failed.\n", - error)); + if (!FileWrite(this->RccFilePublic_, content, &error)) { + this->Log().Error(GenT::RCC, + cmStrCat("Generating RCC wrapper file ", + this->MessagePath(this->RccFilePublic_), + " failed.\n", error)); return false; } - } else if (BuildFileChanged_) { + } else if (this->BuildFileChanged_) { // Just touch the wrapper file - if (Log().Verbose()) { - Log().Info( - GenT::RCC, - cmStrCat("Touching RCC wrapper file ", MessagePath(RccFilePublic_))); + if (this->Log().Verbose()) { + this->Log().Info(GenT::RCC, + cmStrCat("Touching RCC wrapper file ", + this->MessagePath(this->RccFilePublic_))); } - if (!cmSystemTools::Touch(RccFilePublic_, false)) { - Log().Error(GenT::RCC, - cmStrCat("Touching RCC wrapper file ", - MessagePath(RccFilePublic_), " failed.")); + if (!cmSystemTools::Touch(this->RccFilePublic_, false)) { + this->Log().Error(GenT::RCC, + cmStrCat("Touching RCC wrapper file ", + this->MessagePath(this->RccFilePublic_), + " failed.")); return false; } } diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index f5f9c67..d00bbdf 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -3,7 +3,6 @@ #include "cmRulePlaceholderExpander.h" #include <cctype> -#include <cstring> #include <utility> #include "cmOutputConverter.h" @@ -20,11 +19,6 @@ cmRulePlaceholderExpander::cmRulePlaceholderExpander( { } -cmRulePlaceholderExpander::RuleVariables::RuleVariables() -{ - memset(this, 0, sizeof(*this)); -} - std::string cmRulePlaceholderExpander::ExpandRuleVariable( cmOutputConverter* outputConverter, std::string const& variable, const RuleVariables& replaceValues) @@ -50,6 +44,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( return replaceValues.Source; } } + if (replaceValues.DynDepFile) { + if (variable == "DYNDEP_FILE") { + return replaceValues.DynDepFile; + } + } if (replaceValues.PreprocessedSource) { if (variable == "PREPROCESSED_SOURCE") { return replaceValues.PreprocessedSource; @@ -141,6 +140,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( return replaceValues.DependencyFile; } } + if (replaceValues.DependencyTarget) { + if (variable == "DEP_TARGET") { + return replaceValues.DependencyTarget; + } + } if (replaceValues.Fatbinary) { if (variable == "FATBINARY") { return replaceValues.Fatbinary; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index c8d107d..f8dc368 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -27,45 +27,46 @@ public: // ExpandRuleVariables struct RuleVariables { - RuleVariables(); - const char* CMTargetName; - const char* CMTargetType; - const char* TargetPDB; - const char* TargetCompilePDB; - const char* TargetVersionMajor; - const char* TargetVersionMinor; - const char* Language; - const char* AIXExports; - const char* Objects; - const char* Target; - const char* LinkLibraries; - const char* Source; - const char* AssemblySource; - const char* PreprocessedSource; - const char* Output; - const char* Object; - const char* ObjectDir; - const char* ObjectFileDir; - const char* Flags; - const char* ObjectsQuoted; - const char* SONameFlag; - const char* TargetSOName; - const char* TargetInstallNameDir; - const char* LinkFlags; - const char* Manifests; - const char* LanguageCompileFlags; - const char* Defines; - const char* Includes; - const char* DependencyFile; - const char* FilterPrefix; - const char* SwiftLibraryName; - const char* SwiftModule; - const char* SwiftModuleName; - const char* SwiftOutputFileMap; - const char* SwiftSources; - const char* ISPCHeader; - const char* Fatbinary; - const char* RegisterFile; + const char* CMTargetName = nullptr; + const char* CMTargetType = nullptr; + const char* TargetPDB = nullptr; + const char* TargetCompilePDB = nullptr; + const char* TargetVersionMajor = nullptr; + const char* TargetVersionMinor = nullptr; + const char* Language = nullptr; + const char* AIXExports = nullptr; + const char* Objects = nullptr; + const char* Target = nullptr; + const char* LinkLibraries = nullptr; + const char* Source = nullptr; + const char* AssemblySource = nullptr; + const char* PreprocessedSource = nullptr; + const char* DynDepFile = nullptr; + const char* Output = nullptr; + const char* Object = nullptr; + const char* ObjectDir = nullptr; + const char* ObjectFileDir = nullptr; + const char* Flags = nullptr; + const char* ObjectsQuoted = nullptr; + const char* SONameFlag = nullptr; + const char* TargetSOName = nullptr; + const char* TargetInstallNameDir = nullptr; + const char* LinkFlags = nullptr; + const char* Manifests = nullptr; + const char* LanguageCompileFlags = nullptr; + const char* Defines = nullptr; + const char* Includes = nullptr; + const char* DependencyFile = nullptr; + const char* DependencyTarget = nullptr; + const char* FilterPrefix = nullptr; + const char* SwiftLibraryName = nullptr; + const char* SwiftModule = nullptr; + const char* SwiftModuleName = nullptr; + const char* SwiftOutputFileMap = nullptr; + const char* SwiftSources = nullptr; + const char* ISPCHeader = nullptr; + const char* Fatbinary = nullptr; + const char* RegisterFile = nullptr; }; // Expand rule variables in CMake of the type found in language rules diff --git a/Source/cmScanDepFormat.cxx b/Source/cmScanDepFormat.cxx new file mode 100644 index 0000000..e046069 --- /dev/null +++ b/Source/cmScanDepFormat.cxx @@ -0,0 +1,265 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmScanDepFormat.h" + +#include <cctype> +#include <cstdio> + +#include <cm3p/json/reader.h> +#include <cm3p/json/value.h> +#include <cm3p/json/writer.h> + +#include "cmsys/FStream.hxx" + +#include "cmGeneratedFileStream.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +static bool ParseFilename(Json::Value const& val, std::string& result) +{ + if (val.isString()) { + result = val.asString(); + } else { + return false; + } + + return true; +} + +static Json::Value EncodeFilename(std::string const& path) +{ + std::string data; + data.reserve(path.size()); + + for (auto const& byte : path) { + if (std::iscntrl(byte)) { + // Control characters. + data.append("\\u"); + char buf[5]; + std::snprintf(buf, sizeof(buf), "%04x", byte); + data.append(buf); + } else if (byte == '"' || byte == '\\') { + // Special JSON characters. + data.push_back('\\'); + data.push_back(byte); + } else { + // Other data. + data.push_back(byte); + } + } + + return data; +} + +#define PARSE_BLOB(val, res) \ + do { \ + if (!ParseFilename(val, res)) { \ + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \ + arg_pp, ": invalid blob")); \ + return false; \ + } \ + } while (0) + +#define PARSE_FILENAME(val, res) \ + do { \ + if (!ParseFilename(val, res)) { \ + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", \ + arg_pp, ": invalid filename")); \ + return false; \ + } \ + \ + if (!cmSystemTools::FileIsFullPath(res)) { \ + res = cmStrCat(work_directory, '/', res); \ + } \ + } while (0) + +bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, cmSourceInfo* info) +{ + Json::Value ppio; + Json::Value const& ppi = ppio; + cmsys::ifstream ppf(arg_pp.c_str(), std::ios::in | std::ios::binary); + { + Json::Reader reader; + if (!reader.parse(ppf, ppio, false)) { + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", + arg_pp, + reader.getFormattedErrorMessages())); + return false; + } + } + + Json::Value const& version = ppi["version"]; + if (version.asUInt() != 0) { + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", + arg_pp, ": version ", version.asString())); + return false; + } + + Json::Value const& rules = ppi["rules"]; + if (rules.isArray()) { + if (rules.size() != 1) { + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", + arg_pp, ": expected 1 source entry")); + return false; + } + + for (auto const& rule : rules) { + Json::Value const& workdir = rule["work-directory"]; + if (!workdir.isString()) { + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", + arg_pp, + ": work-directory is not a string")); + return false; + } + std::string work_directory; + PARSE_BLOB(workdir, work_directory); + + Json::Value const& depends = rule["depends"]; + if (depends.isArray()) { + std::string depend_filename; + for (auto const& depend : depends) { + PARSE_FILENAME(depend, depend_filename); + info->Includes.push_back(depend_filename); + } + } + + if (rule.isMember("future-compile")) { + Json::Value const& future_compile = rule["future-compile"]; + + if (future_compile.isMember("outputs")) { + Json::Value const& outputs = future_compile["outputs"]; + if (outputs.isArray()) { + if (outputs.empty()) { + cmSystemTools::Error( + cmStrCat("-E cmake_ninja_dyndep failed to parse ", arg_pp, + ": expected at least one 1 output")); + return false; + } + + PARSE_FILENAME(outputs[0], info->PrimaryOutput); + } + } + + if (future_compile.isMember("provides")) { + Json::Value const& provides = future_compile["provides"]; + if (provides.isArray()) { + for (auto const& provide : provides) { + cmSourceReqInfo provide_info; + + Json::Value const& logical_name = provide["logical-name"]; + PARSE_BLOB(logical_name, provide_info.LogicalName); + + if (provide.isMember("compiled-module-path")) { + Json::Value const& compiled_module_path = + provide["compiled-module-path"]; + PARSE_FILENAME(compiled_module_path, + provide_info.CompiledModulePath); + } else { + provide_info.CompiledModulePath = + cmStrCat(provide_info.LogicalName, ".mod"); + } + + info->Provides.push_back(provide_info); + } + } + } + + if (future_compile.isMember("requires")) { + Json::Value const& reqs = future_compile["requires"]; + if (reqs.isArray()) { + for (auto const& require : reqs) { + cmSourceReqInfo require_info; + + Json::Value const& logical_name = require["logical-name"]; + PARSE_BLOB(logical_name, require_info.LogicalName); + + if (require.isMember("compiled-module-path")) { + Json::Value const& compiled_module_path = + require["compiled-module-path"]; + PARSE_FILENAME(compiled_module_path, + require_info.CompiledModulePath); + } + + info->Requires.push_back(require_info); + } + } + } + } + } + } + + return true; +} + +bool cmScanDepFormat_P1689_Write(std::string const& path, + std::string const& input, + cmSourceInfo const& info) +{ + Json::Value ddi(Json::objectValue); + ddi["version"] = 0; + ddi["revision"] = 0; + + Json::Value& rules = ddi["rules"] = Json::arrayValue; + + Json::Value rule(Json::objectValue); + rule["work-directory"] = + EncodeFilename(cmSystemTools::GetCurrentWorkingDirectory()); + Json::Value& inputs = rule["inputs"] = Json::arrayValue; + inputs.append(EncodeFilename(input)); + + Json::Value& rule_outputs = rule["outputs"] = Json::arrayValue; + rule_outputs.append(EncodeFilename(path)); + + Json::Value& depends = rule["depends"] = Json::arrayValue; + for (auto const& include : info.Includes) { + depends.append(EncodeFilename(include)); + } + + Json::Value& future_compile = rule["future-compile"] = Json::objectValue; + + Json::Value& outputs = future_compile["outputs"] = Json::arrayValue; + outputs.append(info.PrimaryOutput); + + Json::Value& provides = future_compile["provides"] = Json::arrayValue; + for (auto const& provide : info.Provides) { + Json::Value provide_obj(Json::objectValue); + auto const encoded = EncodeFilename(provide.LogicalName); + provide_obj["logical-name"] = encoded; + if (provide.CompiledModulePath.empty()) { + provide_obj["compiled-module-path"] = encoded; + } else { + provide_obj["compiled-module-path"] = + EncodeFilename(provide.CompiledModulePath); + } + + // TODO: Source file tracking. See below. + + provides.append(provide_obj); + } + + Json::Value& reqs = future_compile["requires"] = Json::arrayValue; + for (auto const& require : info.Requires) { + Json::Value require_obj(Json::objectValue); + auto const encoded = EncodeFilename(require.LogicalName); + require_obj["logical-name"] = encoded; + if (require.CompiledModulePath.empty()) { + require_obj["compiled-module-path"] = encoded; + } else { + require_obj["compiled-module-path"] = + EncodeFilename(require.CompiledModulePath); + } + + // TODO: Source filename inclusion. Requires collating with the provides + // filenames (as a sanity check if available on both sides). + + reqs.append(require_obj); + } + + rules.append(rule); + + cmGeneratedFileStream ddif(path); + ddif << ddi; + + return !!ddif; +} diff --git a/Source/cmScanDepFormat.h b/Source/cmScanDepFormat.h new file mode 100644 index 0000000..1ad0ecf --- /dev/null +++ b/Source/cmScanDepFormat.h @@ -0,0 +1,30 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <string> +#include <vector> + +struct cmSourceReqInfo +{ + std::string LogicalName; + std::string CompiledModulePath; +}; + +struct cmSourceInfo +{ + std::string PrimaryOutput; + + // Set of provided and required modules. + std::vector<cmSourceReqInfo> Provides; + std::vector<cmSourceReqInfo> Requires; + + // Set of files included in the translation unit. + std::vector<std::string> Includes; +}; + +bool cmScanDepFormat_P1689_Parse(std::string const& arg_pp, + cmSourceInfo* info); +bool cmScanDepFormat_P1689_Write(std::string const& path, + std::string const& input, + cmSourceInfo const& info); diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx deleted file mode 100644 index 7f97406..0000000 --- a/Source/cmServer.cxx +++ /dev/null @@ -1,570 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmServer.h" - -#include <algorithm> -#include <cassert> -#include <csignal> -#include <cstdint> -#include <iostream> -#include <mutex> -#include <utility> - -#include <cm/memory> -#include <cm/shared_mutex> - -#include <cm3p/json/reader.h> -#include <cm3p/json/writer.h> - -#include "cmsys/FStream.hxx" - -#include "cmConnection.h" -#include "cmFileMonitor.h" -#include "cmJsonObjectDictionary.h" -#include "cmServerDictionary.h" -#include "cmServerProtocol.h" -#include "cmSystemTools.h" -#include "cmake.h" - -void on_signal(uv_signal_t* signal, int signum) -{ - auto conn = static_cast<cmServerBase*>(signal->data); - conn->OnSignal(signum); -} - -static void on_walk_to_shutdown(uv_handle_t* handle, void* arg) -{ - (void)arg; - assert(uv_is_closing(handle)); - if (!uv_is_closing(handle)) { - uv_close(handle, &cmEventBasedConnection::on_close); - } -} - -class cmServer::DebugInfo -{ -public: - DebugInfo() - : StartTime(uv_hrtime()) - { - } - - bool PrintStatistics = false; - - std::string OutputFile; - uint64_t StartTime; -}; - -cmServer::cmServer(cmConnection* conn, bool supportExperimental) - : cmServerBase(conn) - , SupportExperimental(supportExperimental) -{ - // Register supported protocols: - this->RegisterProtocol(cm::make_unique<cmServerProtocol1>()); -} - -cmServer::~cmServer() -{ - Close(); -} - -void cmServer::ProcessRequest(cmConnection* connection, - const std::string& input) -{ - Json::Reader reader; - Json::Value value; - if (!reader.parse(input, value)) { - this->WriteParseError(connection, "Failed to parse JSON input."); - return; - } - - std::unique_ptr<DebugInfo> debug; - Json::Value debugValue = value["debug"]; - if (!debugValue.isNull()) { - debug = cm::make_unique<DebugInfo>(); - debug->OutputFile = debugValue["dumpToFile"].asString(); - debug->PrintStatistics = debugValue["showStats"].asBool(); - } - - const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(), - value[kCOOKIE_KEY].asString(), value); - - if (request.Type.empty()) { - cmServerResponse response(request); - response.SetError("No type given in request."); - this->WriteResponse(connection, response, nullptr); - return; - } - - cmSystemTools::SetMessageCallback( - [&request](const std::string& msg, const char* title) { - reportMessage(msg, title, request); - }); - - if (this->Protocol) { - this->Protocol->CMakeInstance()->SetProgressCallback( - [&request](const std::string& msg, float prog) { - reportProgress(msg, prog, request); - }); - this->WriteResponse(connection, this->Protocol->Process(request), - debug.get()); - } else { - this->WriteResponse(connection, this->SetProtocolVersion(request), - debug.get()); - } -} - -void cmServer::RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol) -{ - if (protocol->IsExperimental() && !this->SupportExperimental) { - protocol.reset(); - return; - } - auto version = protocol->ProtocolVersion(); - assert(version.first >= 0); - assert(version.second >= 0); - auto it = std::find_if( - this->SupportedProtocols.begin(), this->SupportedProtocols.end(), - [version](const std::unique_ptr<cmServerProtocol>& p) { - return p->ProtocolVersion() == version; - }); - if (it == this->SupportedProtocols.end()) { - this->SupportedProtocols.push_back(std::move(protocol)); - } -} - -void cmServer::PrintHello(cmConnection* connection) const -{ - Json::Value hello = Json::objectValue; - hello[kTYPE_KEY] = "hello"; - - Json::Value& protocolVersions = hello[kSUPPORTED_PROTOCOL_VERSIONS] = - Json::arrayValue; - - for (auto const& proto : this->SupportedProtocols) { - auto version = proto->ProtocolVersion(); - Json::Value tmp = Json::objectValue; - tmp[kMAJOR_KEY] = version.first; - tmp[kMINOR_KEY] = version.second; - if (proto->IsExperimental()) { - tmp[kIS_EXPERIMENTAL_KEY] = true; - } - protocolVersions.append(tmp); - } - - this->WriteJsonObject(connection, hello, nullptr); -} - -void cmServer::reportProgress(const std::string& msg, float progress, - const cmServerRequest& request) -{ - if (progress < 0.0f || progress > 1.0f) { - request.ReportMessage(msg, ""); - } else { - request.ReportProgress(0, static_cast<int>(progress * 1000), 1000, msg); - } -} - -void cmServer::reportMessage(const std::string& msg, const char* title, - const cmServerRequest& request) -{ - std::string titleString; - if (title) { - titleString = title; - } - request.ReportMessage(msg, titleString); -} - -cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request) -{ - if (request.Type != kHANDSHAKE_TYPE) { - return request.ReportError("Waiting for type \"" + kHANDSHAKE_TYPE + - "\"."); - } - - Json::Value requestedProtocolVersion = request.Data[kPROTOCOL_VERSION_KEY]; - if (requestedProtocolVersion.isNull()) { - return request.ReportError("\"" + kPROTOCOL_VERSION_KEY + - "\" is required for \"" + kHANDSHAKE_TYPE + - "\"."); - } - - if (!requestedProtocolVersion.isObject()) { - return request.ReportError("\"" + kPROTOCOL_VERSION_KEY + - "\" must be a JSON object."); - } - - Json::Value majorValue = requestedProtocolVersion[kMAJOR_KEY]; - if (!majorValue.isInt()) { - return request.ReportError("\"" + kMAJOR_KEY + - "\" must be set and an integer."); - } - - Json::Value minorValue = requestedProtocolVersion[kMINOR_KEY]; - if (!minorValue.isNull() && !minorValue.isInt()) { - return request.ReportError("\"" + kMINOR_KEY + - "\" must be unset or an integer."); - } - - const int major = majorValue.asInt(); - const int minor = minorValue.isNull() ? -1 : minorValue.asInt(); - if (major < 0) { - return request.ReportError("\"" + kMAJOR_KEY + "\" must be >= 0."); - } - if (!minorValue.isNull() && minor < 0) { - return request.ReportError("\"" + kMINOR_KEY + - "\" must be >= 0 when set."); - } - - this->Protocol = - cmServer::FindMatchingProtocol(this->SupportedProtocols, major, minor); - if (!this->Protocol) { - return request.ReportError("Protocol version not supported."); - } - - std::string errorMessage; - if (!this->Protocol->Activate(this, request, &errorMessage)) { - this->Protocol = nullptr; - return request.ReportError("Failed to activate protocol version: " + - errorMessage); - } - return request.Reply(Json::objectValue); -} - -bool cmServer::Serve(std::string* errorMessage) -{ - if (this->SupportedProtocols.empty()) { - *errorMessage = - "No protocol versions defined. Maybe you need --experimental?"; - return false; - } - assert(!this->Protocol); - - return cmServerBase::Serve(errorMessage); -} - -cmFileMonitor* cmServer::FileMonitor() const -{ - return fileMonitor.get(); -} - -void cmServer::WriteJsonObject(const Json::Value& jsonValue, - const DebugInfo* debug) const -{ - cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex); - for (auto& connection : this->Connections) { - WriteJsonObject(connection.get(), jsonValue, debug); - } -} - -void cmServer::WriteJsonObject(cmConnection* connection, - const Json::Value& jsonValue, - const DebugInfo* debug) const -{ - Json::FastWriter writer; - - auto beforeJson = uv_hrtime(); - std::string result = writer.write(jsonValue); - - if (debug) { - Json::Value copy = jsonValue; - if (debug->PrintStatistics) { - Json::Value stats = Json::objectValue; - auto endTime = uv_hrtime(); - - stats["jsonSerialization"] = double(endTime - beforeJson) / 1000000.0; - stats["totalTime"] = double(endTime - debug->StartTime) / 1000000.0; - stats["size"] = static_cast<int>(result.size()); - if (!debug->OutputFile.empty()) { - stats["dumpFile"] = debug->OutputFile; - } - - copy["zzzDebug"] = stats; - - result = writer.write(copy); // Update result to include debug info - } - - if (!debug->OutputFile.empty()) { - cmsys::ofstream myfile(debug->OutputFile.c_str()); - myfile << result; - } - } - - connection->WriteData(result); -} - -cmServerProtocol* cmServer::FindMatchingProtocol( - const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major, - int minor) -{ - cmServerProtocol* bestMatch = nullptr; - for (const auto& protocol : protocols) { - auto version = protocol->ProtocolVersion(); - if (major != version.first) { - continue; - } - if (minor == version.second) { - return protocol.get(); - } - if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) { - bestMatch = protocol.get(); - } - } - return minor < 0 ? bestMatch : nullptr; -} - -void cmServer::WriteProgress(const cmServerRequest& request, int min, - int current, int max, - const std::string& message) const -{ - assert(min <= current && current <= max); - assert(message.length() != 0); - - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = kPROGRESS_TYPE; - obj[kREPLY_TO_KEY] = request.Type; - obj[kCOOKIE_KEY] = request.Cookie; - obj[kPROGRESS_MESSAGE_KEY] = message; - obj[kPROGRESS_MINIMUM_KEY] = min; - obj[kPROGRESS_MAXIMUM_KEY] = max; - obj[kPROGRESS_CURRENT_KEY] = current; - - this->WriteJsonObject(request.Connection, obj, nullptr); -} - -void cmServer::WriteMessage(const cmServerRequest& request, - const std::string& message, - const std::string& title) const -{ - if (message.empty()) { - return; - } - - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = kMESSAGE_TYPE; - obj[kREPLY_TO_KEY] = request.Type; - obj[kCOOKIE_KEY] = request.Cookie; - obj[kMESSAGE_KEY] = message; - if (!title.empty()) { - obj[kTITLE_KEY] = title; - } - - WriteJsonObject(request.Connection, obj, nullptr); -} - -void cmServer::WriteParseError(cmConnection* connection, - const std::string& message) const -{ - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = kERROR_TYPE; - obj[kERROR_MESSAGE_KEY] = message; - obj[kREPLY_TO_KEY] = ""; - obj[kCOOKIE_KEY] = ""; - - this->WriteJsonObject(connection, obj, nullptr); -} - -void cmServer::WriteSignal(const std::string& name, - const Json::Value& data) const -{ - assert(data.isObject()); - Json::Value obj = data; - obj[kTYPE_KEY] = kSIGNAL_TYPE; - obj[kREPLY_TO_KEY] = ""; - obj[kCOOKIE_KEY] = ""; - obj[kNAME_KEY] = name; - - WriteJsonObject(obj, nullptr); -} - -void cmServer::WriteResponse(cmConnection* connection, - const cmServerResponse& response, - const DebugInfo* debug) const -{ - assert(response.IsComplete()); - - Json::Value obj = response.Data(); - obj[kCOOKIE_KEY] = response.Cookie; - obj[kTYPE_KEY] = response.IsError() ? kERROR_TYPE : kREPLY_TYPE; - obj[kREPLY_TO_KEY] = response.Type; - if (response.IsError()) { - obj[kERROR_MESSAGE_KEY] = response.ErrorMessage(); - } - - this->WriteJsonObject(connection, obj, debug); -} - -void cmServer::OnConnected(cmConnection* connection) -{ - PrintHello(connection); -} - -void cmServer::OnServeStart() -{ - cmServerBase::OnServeStart(); - fileMonitor = std::make_shared<cmFileMonitor>(GetLoop()); -} - -void cmServer::StartShutDown() -{ - if (fileMonitor) { - fileMonitor->StopMonitoring(); - fileMonitor.reset(); - } - cmServerBase::StartShutDown(); -} - -static void __start_thread(void* arg) -{ - auto server = static_cast<cmServerBase*>(arg); - std::string error; - bool success = server->Serve(&error); - if (!success || !error.empty()) { - std::cerr << "Error during serve: " << error << std::endl; - } -} - -bool cmServerBase::StartServeThread() -{ - ServeThreadRunning = true; - uv_thread_create(&ServeThread, __start_thread, this); - return true; -} - -static void __shutdownThread(uv_async_t* arg) -{ - auto server = static_cast<cmServerBase*>(arg->data); - server->StartShutDown(); -} - -bool cmServerBase::Serve(std::string* errorMessage) -{ -#ifndef NDEBUG - uv_thread_t blank_thread_t = {}; - assert(uv_thread_equal(&blank_thread_t, &ServeThreadId)); - ServeThreadId = uv_thread_self(); -#endif - - errorMessage->clear(); - - ShutdownSignal.init(Loop, __shutdownThread, this); - - SIGINTHandler.init(Loop, this); - SIGHUPHandler.init(Loop, this); - - SIGINTHandler.start(&on_signal, SIGINT); - SIGHUPHandler.start(&on_signal, SIGHUP); - - OnServeStart(); - - { - cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex); - for (auto& connection : Connections) { - if (!connection->OnServeStart(errorMessage)) { - return false; - } - } - } - - if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { - // It is important we don't ever let the event loop exit with open handles - // at best this is a memory leak, but it can also introduce race conditions - // which can hang the program. - assert(false && "Event loop stopped in unclean state."); - - *errorMessage = "Internal Error: Event loop stopped in unclean state."; - return false; - } - - return true; -} - -void cmServerBase::OnConnected(cmConnection*) -{ -} - -void cmServerBase::OnServeStart() -{ -} - -void cmServerBase::StartShutDown() -{ - ShutdownSignal.reset(); - SIGINTHandler.reset(); - SIGHUPHandler.reset(); - - { - std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); - for (auto& connection : Connections) { - connection->OnConnectionShuttingDown(); - } - Connections.clear(); - } - - uv_walk(&Loop, on_walk_to_shutdown, nullptr); -} - -bool cmServerBase::OnSignal(int signum) -{ - (void)signum; - StartShutDown(); - return true; -} - -cmServerBase::cmServerBase(cmConnection* connection) -{ - auto err = uv_loop_init(&Loop); - (void)err; - Loop.data = this; - assert(err == 0); - - AddNewConnection(connection); -} - -void cmServerBase::Close() -{ - if (Loop.data) { - if (ServeThreadRunning) { - this->ShutdownSignal.send(); - uv_thread_join(&ServeThread); - } - - uv_loop_close(&Loop); - Loop.data = nullptr; - } -} -cmServerBase::~cmServerBase() -{ - Close(); -} - -void cmServerBase::AddNewConnection(cmConnection* ownedConnection) -{ - { - std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); - Connections.emplace_back(ownedConnection); - } - ownedConnection->SetServer(this); -} - -uv_loop_t* cmServerBase::GetLoop() -{ - return &Loop; -} - -void cmServerBase::OnDisconnect(cmConnection* pConnection) -{ - auto pred = [pConnection](const std::unique_ptr<cmConnection>& m) { - return m.get() == pConnection; - }; - { - std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); - Connections.erase( - std::remove_if(Connections.begin(), Connections.end(), pred), - Connections.end()); - } - - if (Connections.empty()) { - this->ShutdownSignal.send(); - } -} diff --git a/Source/cmServer.h b/Source/cmServer.h deleted file mode 100644 index 9543329..0000000 --- a/Source/cmServer.h +++ /dev/null @@ -1,162 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <memory> -#include <string> -#include <vector> - -#include <cm/shared_mutex> - -#include <cm3p/json/value.h> -#include <cm3p/uv.h> - -#include "cmUVHandlePtr.h" - -class cmConnection; -class cmFileMonitor; -class cmServerProtocol; -class cmServerRequest; -class cmServerResponse; - -/*** - * This essentially hold and manages a libuv event queue and responds to - * messages - * on any of its connections. - */ -class cmServerBase -{ -public: - cmServerBase(cmConnection* connection); - virtual ~cmServerBase(); - - virtual void AddNewConnection(cmConnection* ownedConnection); - - /*** - * The main override responsible for tailoring behavior towards - * whatever the given server is supposed to do - * - * This should almost always be called by the given connections - * directly. - * - * @param connection The connection the request was received on - * @param request The actual request - */ - virtual void ProcessRequest(cmConnection* connection, - const std::string& request) = 0; - virtual void OnConnected(cmConnection* connection); - - /*** - * Start a dedicated thread. If this is used to start the server, it will - * join on the - * servers dtor. - */ - virtual bool StartServeThread(); - virtual bool Serve(std::string* errorMessage); - - virtual void OnServeStart(); - virtual void StartShutDown(); - - virtual bool OnSignal(int signum); - uv_loop_t* GetLoop(); - void Close(); - void OnDisconnect(cmConnection* pConnection); - -protected: - mutable cm::shared_mutex ConnectionsMutex; - std::vector<std::unique_ptr<cmConnection>> Connections; - - bool ServeThreadRunning = false; - uv_thread_t ServeThread; - cm::uv_async_ptr ShutdownSignal; -#ifndef NDEBUG -public: - // When the server starts it will mark down it's current thread ID, - // which is useful in other contexts to just assert that operations - // are performed on that same thread. - uv_thread_t ServeThreadId = {}; - -protected: -#endif - - uv_loop_t Loop; - - cm::uv_signal_ptr SIGINTHandler; - cm::uv_signal_ptr SIGHUPHandler; -}; - -class cmServer : public cmServerBase -{ -public: - class DebugInfo; - - cmServer(cmConnection* conn, bool supportExperimental); - ~cmServer() override; - - cmServer(cmServer const&) = delete; - cmServer& operator=(cmServer const&) = delete; - - bool Serve(std::string* errorMessage) override; - - cmFileMonitor* FileMonitor() const; - -private: - void RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol); - - // Callbacks from cmServerConnection: - - void ProcessRequest(cmConnection* connection, - const std::string& request) override; - std::shared_ptr<cmFileMonitor> fileMonitor; - -public: - void OnServeStart() override; - - void StartShutDown() override; - -public: - void OnConnected(cmConnection* connection) override; - -private: - static void reportProgress(const std::string& msg, float progress, - const cmServerRequest& request); - static void reportMessage(const std::string& msg, const char* title, - const cmServerRequest& request); - - // Handle requests: - cmServerResponse SetProtocolVersion(const cmServerRequest& request); - - void PrintHello(cmConnection* connection) const; - - // Write responses: - void WriteProgress(const cmServerRequest& request, int min, int current, - int max, const std::string& message) const; - void WriteMessage(const cmServerRequest& request, const std::string& message, - const std::string& title) const; - void WriteResponse(cmConnection* connection, - const cmServerResponse& response, - const DebugInfo* debug) const; - void WriteParseError(cmConnection* connection, - const std::string& message) const; - void WriteSignal(const std::string& name, const Json::Value& obj) const; - - void WriteJsonObject(Json::Value const& jsonValue, - const DebugInfo* debug) const; - - void WriteJsonObject(cmConnection* connection, Json::Value const& jsonValue, - const DebugInfo* debug) const; - - static cmServerProtocol* FindMatchingProtocol( - const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major, - int minor); - - const bool SupportExperimental; - - cmServerProtocol* Protocol = nullptr; - std::vector<std::unique_ptr<cmServerProtocol>> SupportedProtocols; - - friend class cmServerProtocol; - friend class cmServerRequest; -}; diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx deleted file mode 100644 index b4f41a0..0000000 --- a/Source/cmServerConnection.cxx +++ /dev/null @@ -1,165 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmConfigure.h" - -#include "cmServerConnection.h" - -#include <cm3p/uv.h> - -#include "cmServer.h" -#include "cmServerDictionary.h" - -#ifdef _WIN32 -# include "io.h" -#else -# include <unistd.h> -#endif -#include <cassert> -#include <utility> - -cmStdIoConnection::cmStdIoConnection( - cmConnectionBufferStrategy* bufferStrategy) - : cmEventBasedConnection(bufferStrategy) -{ -} - -cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id) -{ - switch (uv_guess_handle(file_id)) { - case UV_TTY: { - cm::uv_tty_ptr tty; - tty.init(*this->Server->GetLoop(), file_id, file_id == 0, - static_cast<cmEventBasedConnection*>(this)); - uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL); - return { std::move(tty) }; - } - case UV_FILE: - if (file_id == 0) { - return nullptr; - } - // Intentional fallthrough; stdin can _not_ be treated as a named - // pipe, however stdout can be. - CM_FALLTHROUGH; - case UV_NAMED_PIPE: { - cm::uv_pipe_ptr pipe; - pipe.init(*this->Server->GetLoop(), 0, - static_cast<cmEventBasedConnection*>(this)); - uv_pipe_open(pipe, file_id); - return { std::move(pipe) }; - } - default: - assert(false && "Unable to determine stream type"); - return nullptr; - } -} - -void cmStdIoConnection::SetServer(cmServerBase* s) -{ - cmConnection::SetServer(s); - if (!s) { - return; - } - - this->ReadStream = SetupStream(0); - this->WriteStream = SetupStream(1); -} - -void shutdown_connection(uv_prepare_t* prepare) -{ - cmStdIoConnection* connection = - static_cast<cmStdIoConnection*>(prepare->data); - - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) { - uv_close(reinterpret_cast<uv_handle_t*>(prepare), - &cmEventBasedConnection::on_close_delete<uv_prepare_t>); - } - connection->OnDisconnect(0); -} - -bool cmStdIoConnection::OnServeStart(std::string* pString) -{ - Server->OnConnected(this); - if (this->ReadStream.get()) { - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); - } else if (uv_guess_handle(0) == UV_FILE) { - char buffer[1024]; - while (auto len = read(0, buffer, sizeof(buffer))) { - ReadData(std::string(buffer, buffer + len)); - } - - // We can't start the disconnect from here, add a prepare hook to do that - // for us - auto prepare = new uv_prepare_t(); - prepare->data = this; - uv_prepare_init(Server->GetLoop(), prepare); - uv_prepare_start(prepare, shutdown_connection); - } - return cmConnection::OnServeStart(pString); -} - -bool cmStdIoConnection::OnConnectionShuttingDown() -{ - if (ReadStream.get()) { - uv_read_stop(ReadStream); - ReadStream->data = nullptr; - } - - this->ReadStream.reset(); - - cmEventBasedConnection::OnConnectionShuttingDown(); - - return true; -} - -cmServerPipeConnection::cmServerPipeConnection(const std::string& name) - : cmPipeConnection(name, new cmServerBufferStrategy) -{ -} - -cmServerStdIoConnection::cmServerStdIoConnection() - : cmStdIoConnection(new cmServerBufferStrategy) -{ -} - -cmConnectionBufferStrategy::~cmConnectionBufferStrategy() = default; - -void cmConnectionBufferStrategy::clear() -{ -} - -std::string cmServerBufferStrategy::BufferOutMessage( - const std::string& rawBuffer) const -{ - return std::string("\n") + kSTART_MAGIC + std::string("\n") + rawBuffer + - kEND_MAGIC + std::string("\n"); -} - -std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer) -{ - for (;;) { - auto needle = RawReadBuffer.find('\n'); - - if (needle == std::string::npos) { - return ""; - } - std::string line = RawReadBuffer.substr(0, needle); - const auto ls = line.size(); - if (ls > 1 && line.at(ls - 1) == '\r') { - line.erase(ls - 1, 1); - } - RawReadBuffer.erase(RawReadBuffer.begin(), - RawReadBuffer.begin() + static_cast<long>(needle) + 1); - if (line == kSTART_MAGIC) { - RequestBuffer.clear(); - continue; - } - if (line == kEND_MAGIC) { - std::string rtn; - rtn.swap(this->RequestBuffer); - return rtn; - } - - this->RequestBuffer += line; - this->RequestBuffer += "\n"; - } -} diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h deleted file mode 100644 index a70edb4..0000000 --- a/Source/cmServerConnection.h +++ /dev/null @@ -1,67 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <string> - -#include "cmConnection.h" -#include "cmPipeConnection.h" -#include "cmUVHandlePtr.h" - -class cmServerBase; - -/*** - * This connection buffer strategy accepts messages in the form of - * [== "CMake Server" ==[ -{ - ... some JSON message ... -} -]== "CMake Server" ==] - * and only passes on the core json; it discards the envelope. - */ -class cmServerBufferStrategy : public cmConnectionBufferStrategy -{ -public: - std::string BufferMessage(std::string& rawBuffer) override; - std::string BufferOutMessage(const std::string& rawBuffer) const override; - -private: - std::string RequestBuffer; -}; - -/*** - * Generic connection over std io interfaces -- tty - */ -class cmStdIoConnection : public cmEventBasedConnection -{ -public: - cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy); - - void SetServer(cmServerBase* s) override; - - bool OnConnectionShuttingDown() override; - - bool OnServeStart(std::string* pString) override; - -private: - cm::uv_stream_ptr SetupStream(int file_id); - cm::uv_stream_ptr ReadStream; -}; - -/*** - * These specific connections use the cmake server - * buffering strategy. - */ -class cmServerStdIoConnection : public cmStdIoConnection -{ -public: - cmServerStdIoConnection(); -}; - -class cmServerPipeConnection : public cmPipeConnection -{ -public: - cmServerPipeConnection(const std::string& name); -}; diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h deleted file mode 100644 index 961e4b7..0000000 --- a/Source/cmServerDictionary.h +++ /dev/null @@ -1,67 +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 <string> - -// Vocabulary: - -static const std::string kDIRTY_SIGNAL = "dirty"; -static const std::string kFILE_CHANGE_SIGNAL = "fileChange"; - -static const std::string kCACHE_TYPE = "cache"; -static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs"; -static const std::string kCODE_MODEL_TYPE = "codemodel"; -static const std::string kCOMPUTE_TYPE = "compute"; -static const std::string kCONFIGURE_TYPE = "configure"; -static const std::string kERROR_TYPE = "error"; -static const std::string kFILESYSTEM_WATCHERS_TYPE = "fileSystemWatchers"; -static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings"; -static const std::string kHANDSHAKE_TYPE = "handshake"; -static const std::string kMESSAGE_TYPE = "message"; -static const std::string kPROGRESS_TYPE = "progress"; -static const std::string kREPLY_TYPE = "reply"; -static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings"; -static const std::string kSIGNAL_TYPE = "signal"; -static const std::string kCTEST_INFO_TYPE = "ctestInfo"; - -static const std::string kBUILD_FILES_KEY = "buildFiles"; -static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments"; -static const std::string kCACHE_KEY = "cache"; -static const std::string kCAPABILITIES_KEY = "capabilities"; -static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars"; -static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory"; -static const std::string kCOOKIE_KEY = "cookie"; -static const std::string kDEBUG_OUTPUT_KEY = "debugOutput"; -static const std::string kERROR_MESSAGE_KEY = "errorMessage"; -static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; -static const std::string kGENERATOR_KEY = "generator"; -static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; -static const std::string kKEYS_KEY = "keys"; -static const std::string kMAJOR_KEY = "major"; -static const std::string kMESSAGE_KEY = "message"; -static const std::string kMINOR_KEY = "minor"; -static const std::string kPLATFORM_KEY = "platform"; -static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent"; -static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum"; -static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage"; -static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum"; -static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion"; -static const std::string kREPLY_TO_KEY = "inReplyTo"; -static const std::string kSUPPORTED_PROTOCOL_VERSIONS = - "supportedProtocolVersions"; -static const std::string kTITLE_KEY = "title"; -static const std::string kTOOLSET_KEY = "toolset"; -static const std::string kTRACE_EXPAND_KEY = "traceExpand"; -static const std::string kTRACE_KEY = "trace"; -static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized"; -static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli"; -static const std::string kWARN_UNUSED_KEY = "warnUnused"; -static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories"; -static const std::string kWATCHED_FILES_KEY = "watchedFiles"; - -static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==["; -static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]"; - -static const std::string kRENAME_PROPERTY_VALUE = "rename"; -static const std::string kCHANGE_PROPERTY_VALUE = "change"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx deleted file mode 100644 index e586fd9..0000000 --- a/Source/cmServerProtocol.cxx +++ /dev/null @@ -1,760 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmServerProtocol.h" - -#include <algorithm> -#include <cassert> -#include <functional> -#include <string> -#include <utility> -#include <vector> - -#include <cm/memory> -#include <cmext/algorithm> - -#include <cm3p/uv.h> - -#include "cmExternalMakefileProjectGenerator.h" -#include "cmFileMonitor.h" -#include "cmGlobalGenerator.h" -#include "cmJsonObjectDictionary.h" -#include "cmJsonObjects.h" -#include "cmMessageType.h" -#include "cmProperty.h" -#include "cmServer.h" -#include "cmServerDictionary.h" -#include "cmState.h" -#include "cmSystemTools.h" -#include "cmake.h" - -// Get rid of some windows macros: -#undef max - -namespace { - -std::vector<std::string> toStringList(const Json::Value& in) -{ - std::vector<std::string> result; - for (auto const& it : in) { - result.push_back(it.asString()); - } - return result; -} - -} // namespace - -cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection, - std::string t, std::string c, Json::Value d) - : Type(std::move(t)) - , Cookie(std::move(c)) - , Data(std::move(d)) - , Connection(connection) - , m_Server(server) -{ -} - -void cmServerRequest::ReportProgress(int min, int current, int max, - const std::string& message) const -{ - this->m_Server->WriteProgress(*this, min, current, max, message); -} - -void cmServerRequest::ReportMessage(const std::string& message, - const std::string& title) const -{ - m_Server->WriteMessage(*this, message, title); -} - -cmServerResponse cmServerRequest::Reply(const Json::Value& data) const -{ - cmServerResponse response(*this); - response.SetData(data); - return response; -} - -cmServerResponse cmServerRequest::ReportError(const std::string& message) const -{ - cmServerResponse response(*this); - response.SetError(message); - return response; -} - -cmServerResponse::cmServerResponse(const cmServerRequest& request) - : Type(request.Type) - , Cookie(request.Cookie) -{ -} - -void cmServerResponse::SetData(const Json::Value& data) -{ - assert(this->m_Payload == PAYLOAD_UNKNOWN); - if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) { - this->SetError("Response contains cookie or type field."); - return; - } - this->m_Payload = PAYLOAD_DATA; - this->m_Data = data; -} - -void cmServerResponse::SetError(const std::string& message) -{ - assert(this->m_Payload == PAYLOAD_UNKNOWN); - this->m_Payload = PAYLOAD_ERROR; - this->m_ErrorMessage = message; -} - -bool cmServerResponse::IsComplete() const -{ - return this->m_Payload != PAYLOAD_UNKNOWN; -} - -bool cmServerResponse::IsError() const -{ - assert(this->m_Payload != PAYLOAD_UNKNOWN); - return this->m_Payload == PAYLOAD_ERROR; -} - -std::string cmServerResponse::ErrorMessage() const -{ - if (this->m_Payload == PAYLOAD_ERROR) { - return this->m_ErrorMessage; - } - return std::string(); -} - -Json::Value cmServerResponse::Data() const -{ - assert(this->m_Payload != PAYLOAD_UNKNOWN); - return this->m_Data; -} - -bool cmServerProtocol::Activate(cmServer* server, - const cmServerRequest& request, - std::string* errorMessage) -{ - assert(server); - this->m_Server = server; - this->m_CMakeInstance = - cm::make_unique<cmake>(cmake::RoleProject, cmState::Project); - this->m_WarnUnused = false; - const bool result = this->DoActivate(request, errorMessage); - if (!result) { - this->m_CMakeInstance = nullptr; - } - return result; -} - -cmFileMonitor* cmServerProtocol::FileMonitor() const -{ - return this->m_Server ? this->m_Server->FileMonitor() : nullptr; -} - -void cmServerProtocol::SendSignal(const std::string& name, - const Json::Value& data) const -{ - if (this->m_Server) { - this->m_Server->WriteSignal(name, data); - } -} - -cmake* cmServerProtocol::CMakeInstance() const -{ - return this->m_CMakeInstance.get(); -} - -bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/, - std::string* /*errorMessage*/) -{ - return true; -} - -std::pair<int, int> cmServerProtocol1::ProtocolVersion() const -{ - return { 1, 2 }; -} - -static void setErrorMessage(std::string* errorMessage, const std::string& text) -{ - if (errorMessage) { - *errorMessage = text; - } -} - -static bool getOrTestHomeDirectory(cmState* state, std::string& value, - std::string* errorMessage) -{ - const std::string cachedValue = - *state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); - if (value.empty()) { - value = cachedValue; - return true; - } - const std::string suffix = "/CMakeLists.txt"; - const std::string cachedValueCML = cachedValue + suffix; - const std::string valueCML = value + suffix; - if (!cmSystemTools::SameFile(valueCML, cachedValueCML)) { - setErrorMessage(errorMessage, - std::string("\"CMAKE_HOME_DIRECTORY\" is set but " - "incompatible with configured " - "source directory value.")); - return false; - } - return true; -} - -static bool getOrTestValue(cmState* state, const std::string& key, - std::string& value, - const std::string& keyDescription, - std::string* errorMessage) -{ - const std::string cachedValue = state->GetSafeCacheEntryValue(key); - if (value.empty()) { - value = cachedValue; - } - if (!cachedValue.empty() && cachedValue != value) { - setErrorMessage(errorMessage, - std::string("\"") + key + - "\" is set but incompatible with configured " + - keyDescription + " value."); - return false; - } - return true; -} - -bool cmServerProtocol1::DoActivate(const cmServerRequest& request, - std::string* errorMessage) -{ - std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString(); - std::string buildDirectory = request.Data[kBUILD_DIRECTORY_KEY].asString(); - std::string generator = request.Data[kGENERATOR_KEY].asString(); - std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString(); - std::string toolset = request.Data[kTOOLSET_KEY].asString(); - std::string platform = request.Data[kPLATFORM_KEY].asString(); - - // normalize source and build directory - if (!sourceDirectory.empty()) { - sourceDirectory = cmSystemTools::CollapseFullPath(sourceDirectory); - cmSystemTools::ConvertToUnixSlashes(sourceDirectory); - } - if (!buildDirectory.empty()) { - buildDirectory = cmSystemTools::CollapseFullPath(buildDirectory); - cmSystemTools::ConvertToUnixSlashes(buildDirectory); - } - - if (buildDirectory.empty()) { - setErrorMessage(errorMessage, - std::string("\"") + kBUILD_DIRECTORY_KEY + - "\" is missing."); - return false; - } - - cmake* cm = CMakeInstance(); - if (cmSystemTools::PathExists(buildDirectory)) { - if (!cmSystemTools::FileIsDirectory(buildDirectory)) { - setErrorMessage(errorMessage, - std::string("\"") + kBUILD_DIRECTORY_KEY + - "\" exists but is not a directory."); - return false; - } - - const std::string cachePath = cmake::FindCacheFile(buildDirectory); - if (cm->LoadCache(cachePath)) { - cmState* state = cm->GetState(); - - // Check generator: - if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator", - errorMessage)) { - return false; - } - - // check extra generator: - if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator, - "extra generator", errorMessage)) { - return false; - } - - // check sourcedir: - if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) { - return false; - } - - // check toolset: - if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset", - errorMessage)) { - return false; - } - - // check platform: - if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform, - "platform", errorMessage)) { - return false; - } - } - } - - if (sourceDirectory.empty()) { - setErrorMessage(errorMessage, - std::string("\"") + kSOURCE_DIRECTORY_KEY + - "\" is unset but required."); - return false; - } - if (!cmSystemTools::FileIsDirectory(sourceDirectory)) { - setErrorMessage(errorMessage, - std::string("\"") + kSOURCE_DIRECTORY_KEY + - "\" is not a directory."); - return false; - } - if (generator.empty()) { - setErrorMessage(errorMessage, - std::string("\"") + kGENERATOR_KEY + - "\" is unset but required."); - return false; - } - - std::vector<cmake::GeneratorInfo> generators; - cm->GetRegisteredGenerators(generators); - auto baseIt = std::find_if(generators.begin(), generators.end(), - [&generator](const cmake::GeneratorInfo& info) { - return info.name == generator; - }); - if (baseIt == generators.end()) { - setErrorMessage(errorMessage, - std::string("Generator \"") + generator + - "\" not supported."); - return false; - } - auto extraIt = std::find_if( - generators.begin(), generators.end(), - [&generator, &extraGenerator](const cmake::GeneratorInfo& info) { - return info.baseName == generator && info.extraName == extraGenerator; - }); - if (extraIt == generators.end()) { - setErrorMessage(errorMessage, - std::string("The combination of generator \"" + generator + - "\" and extra generator \"" + extraGenerator + - "\" is not supported.")); - return false; - } - if (!extraIt->supportsToolset && !toolset.empty()) { - setErrorMessage(errorMessage, - std::string("Toolset was provided but is not supported by " - "the requested generator.")); - return false; - } - if (!extraIt->supportsPlatform && !platform.empty()) { - setErrorMessage(errorMessage, - std::string("Platform was provided but is not supported " - "by the requested generator.")); - return false; - } - - this->GeneratorInfo = - GeneratorInformation(generator, extraGenerator, toolset, platform, - sourceDirectory, buildDirectory); - - this->m_State = STATE_ACTIVE; - return true; -} - -void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path, - int event, int status) -{ - assert(status == 0); - static_cast<void>(status); - - if (!m_isDirty) { - m_isDirty = true; - SendSignal(kDIRTY_SIGNAL, Json::objectValue); - } - Json::Value obj = Json::objectValue; - obj[kPATH_KEY] = path; - Json::Value properties = Json::arrayValue; - if (event & UV_RENAME) { - properties.append(kRENAME_PROPERTY_VALUE); - } - if (event & UV_CHANGE) { - properties.append(kCHANGE_PROPERTY_VALUE); - } - - obj[kPROPERTIES_KEY] = properties; - SendSignal(kFILE_CHANGE_SIGNAL, obj); -} - -cmServerResponse cmServerProtocol1::Process(const cmServerRequest& request) -{ - assert(this->m_State >= STATE_ACTIVE); - - if (request.Type == kCACHE_TYPE) { - return this->ProcessCache(request); - } - if (request.Type == kCMAKE_INPUTS_TYPE) { - return this->ProcessCMakeInputs(request); - } - if (request.Type == kCODE_MODEL_TYPE) { - return this->ProcessCodeModel(request); - } - if (request.Type == kCOMPUTE_TYPE) { - return this->ProcessCompute(request); - } - if (request.Type == kCONFIGURE_TYPE) { - return this->ProcessConfigure(request); - } - if (request.Type == kFILESYSTEM_WATCHERS_TYPE) { - return this->ProcessFileSystemWatchers(request); - } - if (request.Type == kGLOBAL_SETTINGS_TYPE) { - return this->ProcessGlobalSettings(request); - } - if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) { - return this->ProcessSetGlobalSettings(request); - } - if (request.Type == kCTEST_INFO_TYPE) { - return this->ProcessCTests(request); - } - - return request.ReportError("Unknown command!"); -} - -bool cmServerProtocol1::IsExperimental() const -{ - return true; -} - -cmServerResponse cmServerProtocol1::ProcessCache( - const cmServerRequest& request) -{ - cmState* state = this->CMakeInstance()->GetState(); - - Json::Value result = Json::objectValue; - - std::vector<std::string> allKeys = state->GetCacheEntryKeys(); - - Json::Value list = Json::arrayValue; - std::vector<std::string> keys = toStringList(request.Data[kKEYS_KEY]); - if (keys.empty()) { - keys = allKeys; - } else { - for (auto const& i : keys) { - if (!cm::contains(allKeys, i)) { - return request.ReportError("Key \"" + i + "\" not found in cache."); - } - } - } - std::sort(keys.begin(), keys.end()); - for (auto const& key : keys) { - Json::Value entry = Json::objectValue; - entry[kKEY_KEY] = key; - entry[kTYPE_KEY] = - cmState::CacheEntryTypeToString(state->GetCacheEntryType(key)); - entry[kVALUE_KEY] = *state->GetCacheEntryValue(key); - - Json::Value props = Json::objectValue; - bool haveProperties = false; - for (auto const& prop : state->GetCacheEntryPropertyList(key)) { - haveProperties = true; - props[prop] = *state->GetCacheEntryProperty(key, prop); - } - if (haveProperties) { - entry[kPROPERTIES_KEY] = props; - } - - list.append(entry); - } - - result[kCACHE_KEY] = list; - return request.Reply(result); -} - -cmServerResponse cmServerProtocol1::ProcessCMakeInputs( - const cmServerRequest& request) -{ - if (this->m_State < STATE_CONFIGURED) { - return request.ReportError("This instance was not yet configured."); - } - - const cmake* cm = this->CMakeInstance(); - const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot(); - const std::string& sourceDir = cm->GetHomeDirectory(); - - Json::Value result = Json::objectValue; - result[kSOURCE_DIRECTORY_KEY] = sourceDir; - result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir; - result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm); - return request.Reply(result); -} - -cmServerResponse cmServerProtocol1::ProcessCodeModel( - const cmServerRequest& request) -{ - if (this->m_State != STATE_COMPUTED) { - return request.ReportError("No build system was generated yet."); - } - - return request.Reply(cmDumpCodeModel(this->CMakeInstance())); -} - -cmServerResponse cmServerProtocol1::ProcessCompute( - const cmServerRequest& request) -{ - if (this->m_State > STATE_CONFIGURED) { - return request.ReportError("This build system was already generated."); - } - if (this->m_State < STATE_CONFIGURED) { - return request.ReportError("This project was not configured yet."); - } - - cmake* cm = this->CMakeInstance(); - int ret = cm->Generate(); - - if (ret < 0) { - return request.ReportError("Failed to compute build system."); - } - m_State = STATE_COMPUTED; - return request.Reply(Json::Value()); -} - -cmServerResponse cmServerProtocol1::ProcessConfigure( - const cmServerRequest& request) -{ - if (this->m_State == STATE_INACTIVE) { - return request.ReportError("This instance is inactive."); - } - - FileMonitor()->StopMonitoring(); - - std::string errorMessage; - cmake* cm = this->CMakeInstance(); - this->GeneratorInfo.SetupGenerator(cm, &errorMessage); - if (!errorMessage.empty()) { - return request.ReportError(errorMessage); - } - - // Make sure the types of cacheArguments matches (if given): - std::vector<std::string> cacheArgs = { "unused" }; - bool cacheArgumentsError = false; - const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY]; - if (!passedArgs.isNull()) { - if (passedArgs.isString()) { - cacheArgs.push_back(passedArgs.asString()); - } else if (passedArgs.isArray()) { - for (auto const& arg : passedArgs) { - if (!arg.isString()) { - cacheArgumentsError = true; - break; - } - cacheArgs.push_back(arg.asString()); - } - } else { - cacheArgumentsError = true; - } - } - if (cacheArgumentsError) { - request.ReportError( - "cacheArguments must be unset, a string or an array of strings."); - } - - std::string sourceDir = cm->GetHomeDirectory(); - const std::string buildDir = cm->GetHomeOutputDirectory(); - - cmGlobalGenerator* gg = cm->GetGlobalGenerator(); - - if (buildDir.empty()) { - return request.ReportError("No build directory set via Handshake."); - } - - if (cm->LoadCache(buildDir)) { - // build directory has been set up before - cmProp cachedSourceDir = - cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY"); - if (!cachedSourceDir) { - return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache."); - } - if (sourceDir.empty()) { - sourceDir = *cachedSourceDir; - cm->SetHomeDirectory(sourceDir); - } - - cmProp cachedGenerator = - cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR"); - if (cachedGenerator) { - if (gg && gg->GetName() != *cachedGenerator) { - return request.ReportError("Configured generator does not match with " - "CMAKE_GENERATOR found in cache."); - } - } - } else { - // build directory has not been set up before - if (sourceDir.empty()) { - return request.ReportError("No sourceDirectory set via " - "setGlobalSettings and no cache found in " - "buildDirectory."); - } - } - - cmSystemTools::ResetErrorOccuredFlag(); // Reset error state - - if (cm->AddCMakePaths() != 1) { - return request.ReportError("Failed to set CMake paths."); - } - - if (!cm->SetCacheArgs(cacheArgs)) { - return request.ReportError("cacheArguments could not be set."); - } - - int ret = cm->Configure(); - cm->IssueMessage( - MessageType::DEPRECATION_WARNING, - "The 'cmake-server(7)' is deprecated. " - "Please port clients to use the 'cmake-file-api(7)' instead."); - if (ret < 0) { - return request.ReportError("Configuration failed."); - } - - std::vector<std::string> toWatchList; - cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList, - nullptr); - - FileMonitor()->MonitorPaths(toWatchList, - [this](const std::string& p, int e, int s) { - this->HandleCMakeFileChanges(p, e, s); - }); - - m_State = STATE_CONFIGURED; - m_isDirty = false; - return request.Reply(Json::Value()); -} - -cmServerResponse cmServerProtocol1::ProcessGlobalSettings( - const cmServerRequest& request) -{ - cmake* cm = this->CMakeInstance(); - Json::Value obj = Json::objectValue; - - // Capabilities information: - obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(); - - obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput(); - obj[kTRACE_KEY] = cm->GetTrace(); - obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand(); - obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized(); - obj[kWARN_UNUSED_KEY] = m_WarnUnused; - obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli(); - obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars(); - - obj[kSOURCE_DIRECTORY_KEY] = this->GeneratorInfo.SourceDirectory; - obj[kBUILD_DIRECTORY_KEY] = this->GeneratorInfo.BuildDirectory; - - // Currently used generator: - obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName; - obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName; - - return request.Reply(obj); -} - -static void setBool(const cmServerRequest& request, const std::string& key, - std::function<void(bool)> const& setter) -{ - if (request.Data[key].isNull()) { - return; - } - setter(request.Data[key].asBool()); -} - -cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings( - const cmServerRequest& request) -{ - const std::vector<std::string> boolValues = { - kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY, - kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY, - kCHECK_SYSTEM_VARS_KEY - }; - for (std::string const& i : boolValues) { - if (!request.Data[i].isNull() && !request.Data[i].isBool()) { - return request.ReportError("\"" + i + - "\" must be unset or a bool value."); - } - } - - cmake* cm = this->CMakeInstance(); - - setBool(request, kDEBUG_OUTPUT_KEY, - [cm](bool e) { cm->SetDebugOutputOn(e); }); - setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); }); - setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); }); - setBool(request, kWARN_UNINITIALIZED_KEY, - [cm](bool e) { cm->SetWarnUninitialized(e); }); - setBool(request, kWARN_UNUSED_KEY, [this](bool e) { m_WarnUnused = e; }); - setBool(request, kWARN_UNUSED_CLI_KEY, - [cm](bool e) { cm->SetWarnUnusedCli(e); }); - setBool(request, kCHECK_SYSTEM_VARS_KEY, - [cm](bool e) { cm->SetCheckSystemVars(e); }); - - return request.Reply(Json::Value()); -} - -cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers( - const cmServerRequest& request) -{ - const cmFileMonitor* const fm = FileMonitor(); - Json::Value result = Json::objectValue; - Json::Value files = Json::arrayValue; - for (auto const& f : fm->WatchedFiles()) { - files.append(f); - } - Json::Value directories = Json::arrayValue; - for (auto const& d : fm->WatchedDirectories()) { - directories.append(d); - } - result[kWATCHED_FILES_KEY] = files; - result[kWATCHED_DIRECTORIES_KEY] = directories; - - return request.Reply(result); -} - -cmServerResponse cmServerProtocol1::ProcessCTests( - const cmServerRequest& request) -{ - if (this->m_State < STATE_COMPUTED) { - return request.ReportError("This instance was not yet computed."); - } - - return request.Reply(cmDumpCTestInfo(this->CMakeInstance())); -} - -cmServerProtocol1::GeneratorInformation::GeneratorInformation( - std::string generatorName, std::string extraGeneratorName, - std::string toolset, std::string platform, std::string sourceDirectory, - std::string buildDirectory) - : GeneratorName(std::move(generatorName)) - , ExtraGeneratorName(std::move(extraGeneratorName)) - , Toolset(std::move(toolset)) - , Platform(std::move(platform)) - , SourceDirectory(std::move(sourceDirectory)) - , BuildDirectory(std::move(buildDirectory)) -{ -} - -void cmServerProtocol1::GeneratorInformation::SetupGenerator( - cmake* cm, std::string* errorMessage) -{ - const std::string fullGeneratorName = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName( - GeneratorName, ExtraGeneratorName); - - cm->SetHomeDirectory(SourceDirectory); - cm->SetHomeOutputDirectory(BuildDirectory); - - auto gg = cm->CreateGlobalGenerator(fullGeneratorName); - if (!gg) { - setErrorMessage( - errorMessage, - std::string("Could not set up the requested combination of \"") + - kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\""); - return; - } - - cm->SetGlobalGenerator(std::move(gg)); - - cm->SetGeneratorToolset(Toolset); - cm->SetGeneratorPlatform(Platform); -} diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h deleted file mode 100644 index 6009e23..0000000 --- a/Source/cmServerProtocol.h +++ /dev/null @@ -1,162 +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 "cmConfigure.h" // IWYU pragma: keep - -#include <memory> -#include <string> -#include <utility> - -#include <cm3p/json/value.h> - -#include "cmake.h" - -class cmConnection; -class cmFileMonitor; -class cmServer; -class cmServerRequest; - -class cmServerResponse -{ -public: - explicit cmServerResponse(const cmServerRequest& request); - - void SetData(const Json::Value& data); - void SetError(const std::string& message); - - bool IsComplete() const; - bool IsError() const; - std::string ErrorMessage() const; - Json::Value Data() const; - - const std::string Type; - const std::string Cookie; - -private: - enum PayLoad - { - PAYLOAD_UNKNOWN, - PAYLOAD_ERROR, - PAYLOAD_DATA - }; - PayLoad m_Payload = PAYLOAD_UNKNOWN; - std::string m_ErrorMessage; - Json::Value m_Data; -}; - -class cmServerRequest -{ -public: - cmServerResponse Reply(const Json::Value& data) const; - cmServerResponse ReportError(const std::string& message) const; - - const std::string Type; - const std::string Cookie; - const Json::Value Data; - cmConnection* Connection; - -private: - cmServerRequest(cmServer* server, cmConnection* connection, std::string t, - std::string c, Json::Value d); - - void ReportProgress(int min, int current, int max, - const std::string& message) const; - void ReportMessage(const std::string& message, - const std::string& title) const; - - cmServer* m_Server; - - friend class cmServer; -}; - -class cmServerProtocol -{ -public: - cmServerProtocol() = default; - virtual ~cmServerProtocol() = default; - - cmServerProtocol(cmServerProtocol const&) = delete; - cmServerProtocol& operator=(cmServerProtocol const&) = delete; - - virtual std::pair<int, int> ProtocolVersion() const = 0; - virtual bool IsExperimental() const = 0; - virtual cmServerResponse Process(const cmServerRequest& request) = 0; - - bool Activate(cmServer* server, const cmServerRequest& request, - std::string* errorMessage); - - cmFileMonitor* FileMonitor() const; - void SendSignal(const std::string& name, const Json::Value& data) const; - -protected: - cmake* CMakeInstance() const; - // Implement protocol specific activation tasks here. Called from Activate(). - virtual bool DoActivate(const cmServerRequest& request, - std::string* errorMessage); - bool m_WarnUnused = false; // storage for legacy option - -private: - std::unique_ptr<cmake> m_CMakeInstance; - cmServer* m_Server = nullptr; // not owned! - - friend class cmServer; -}; - -class cmServerProtocol1 : public cmServerProtocol -{ -public: - std::pair<int, int> ProtocolVersion() const override; - bool IsExperimental() const override; - cmServerResponse Process(const cmServerRequest& request) override; - -private: - bool DoActivate(const cmServerRequest& request, - std::string* errorMessage) override; - - void HandleCMakeFileChanges(const std::string& path, int event, int status); - - // Handle requests: - cmServerResponse ProcessCache(const cmServerRequest& request); - cmServerResponse ProcessCMakeInputs(const cmServerRequest& request); - cmServerResponse ProcessCodeModel(const cmServerRequest& request); - cmServerResponse ProcessCompute(const cmServerRequest& request); - cmServerResponse ProcessConfigure(const cmServerRequest& request); - cmServerResponse ProcessGlobalSettings(const cmServerRequest& request); - cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request); - cmServerResponse ProcessFileSystemWatchers(const cmServerRequest& request); - cmServerResponse ProcessCTests(const cmServerRequest& request); - - enum State - { - STATE_INACTIVE, - STATE_ACTIVE, - STATE_CONFIGURED, - STATE_COMPUTED - }; - State m_State = STATE_INACTIVE; - - bool m_isDirty = false; - - struct GeneratorInformation - { - public: - GeneratorInformation() = default; - GeneratorInformation(std::string generatorName, - std::string extraGeneratorName, std::string toolset, - std::string platform, std::string sourceDirectory, - std::string buildDirectory); - - void SetupGenerator(cmake* cm, std::string* errorMessage); - - std::string GeneratorName; - std::string ExtraGeneratorName; - std::string Toolset; - std::string Platform; - - std::string SourceDirectory; - std::string BuildDirectory; - }; - - GeneratorInformation GeneratorInfo; -}; diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index df6a38a..970564d 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -10,9 +10,12 @@ #include "cmGlobalGenerator.h" #include "cmInstalledFile.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmPolicies.h" #include "cmProperty.h" #include "cmRange.h" #include "cmSourceFile.h" +#include "cmSourceFileLocation.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -157,7 +160,7 @@ bool HandleSourceFileDirectoryScopeValidation( return true; } -bool HandleAndValidateSourceFileDirectortoryScopes( +bool HandleAndValidateSourceFileDirectoryScopes( cmExecutionStatus& status, bool source_file_directory_option_enabled, bool source_file_target_option_enabled, std::vector<std::string>& source_file_directories, @@ -216,8 +219,92 @@ void MakeSourceFilePathsAbsoluteIfNeeded( source_files_absolute_paths.push_back(absolute_file_path); } } + +bool HandleAndValidateSourceFilePropertyGENERATED( + cmSourceFile* sf, std::string const& propertyValue, PropertyOp op) +{ + auto& mf = *sf->GetLocation().GetMakefile(); + auto policyStatus = mf.GetPolicyStatus(cmPolicies::CMP0118); + + const bool policyWARN = policyStatus == cmPolicies::WARN; + const bool policyNEW = policyStatus != cmPolicies::OLD && !policyWARN; + + if (policyWARN) { + if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118), + "\nAttempt to set property 'GENERATED' with the following " + "non-boolean value (which will be interpreted as \"0\"):\n", + propertyValue, + "\nThat exact value will not be retrievable. A value of " + "\"0\" will be returned instead.\n" + "This will be an error under policy CMP0118.\n")); + } + if (cmIsOff(propertyValue)) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118), + "\nUnsetting property 'GENERATED' will not be allowed under " + "policy CMP0118!\n")); + } + if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118), + "\nAppending to property 'GENERATED' will not be allowed " + "under policy CMP0118!\n")); + } + } else if (policyNEW) { + if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) { + mf.IssueMessage( + MessageType::AUTHOR_ERROR, + cmStrCat( + "Policy CMP0118 is set to NEW and the following non-boolean value " + "given for property 'GENERATED' is therefore not allowed:\n", + propertyValue, "\nReplace it with a boolean value!\n")); + return true; + } + if (cmIsOff(propertyValue)) { + mf.IssueMessage( + MessageType::AUTHOR_ERROR, + "Unsetting the 'GENERATED' property is not allowed under CMP0118!\n"); + return true; + } + if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) { + mf.IssueMessage(MessageType::AUTHOR_ERROR, + "Policy CMP0118 is set to NEW and appending to the " + "'GENERATED' property is therefore not allowed. Only " + "setting it to \"1\" is allowed!\n"); + return true; + } + } + + // Set property. + if (!policyNEW) { + // Do it the traditional way. + switch (op) { + case PropertyOp::Append: + sf->AppendProperty("GENERATED", propertyValue, false); + break; + case PropertyOp::AppendAsString: + sf->AppendProperty("GENERATED", propertyValue, true); + break; + case PropertyOp::Remove: + sf->SetProperty("GENERATED", nullptr); + break; + case PropertyOp::Set: + sf->SetProperty("GENERATED", propertyValue.c_str()); + break; + } + } else { + sf->MarkAsGenerated(); + } + return true; } +} // END: namespace SetPropertyCommand + bool cmSetPropertyCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -324,7 +411,7 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args, std::vector<cmMakefile*> source_file_directory_makefiles; bool file_scopes_handled = - SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes( status, source_file_directory_option_enabled, source_file_target_option_enabled, source_file_directories, source_file_target_directories, source_file_directory_makefiles); @@ -367,7 +454,7 @@ bool cmSetPropertyCommand(std::vector<std::string> const& args, return true; } -namespace { +namespace /* anonymous */ { bool HandleGlobalMode(cmExecutionStatus& status, const std::set<std::string>& names, const std::string& propertyName, @@ -525,6 +612,18 @@ bool HandleSource(cmSourceFile* sf, const std::string& propertyName, const std::string& propertyValue, bool appendAsString, bool appendMode, bool remove) { + // Special validation and handling of GENERATED flag? + if (propertyName == "GENERATED") { + SetPropertyCommand::PropertyOp op = (remove) + ? SetPropertyCommand::PropertyOp::Remove + : (appendAsString) + ? SetPropertyCommand::PropertyOp::AppendAsString + : (appendMode) ? SetPropertyCommand::PropertyOp::Append + : SetPropertyCommand::PropertyOp::Set; + return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED( + sf, propertyValue, op); + } + // Set or append the property. if (appendMode) { sf->AppendProperty(propertyName, propertyValue, appendAsString); diff --git a/Source/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h index 89fdd9a..05c4873 100644 --- a/Source/cmSetPropertyCommand.h +++ b/Source/cmSetPropertyCommand.h @@ -9,6 +9,7 @@ class cmMakefile; class cmExecutionStatus; +class cmSourceFile; bool cmSetPropertyCommand(std::vector<std::string> const& args, cmExecutionStatus& status); @@ -25,7 +26,7 @@ bool HandleSourceFileDirectoryScopeValidation( std::vector<std::string>& source_file_directories, std::vector<std::string>& source_file_target_directories); -bool HandleAndValidateSourceFileDirectortoryScopes( +bool HandleAndValidateSourceFileDirectoryScopes( cmExecutionStatus& status, bool source_directories_option_encountered, bool source_target_directories_option_encountered, std::vector<std::string>& source_directories, @@ -39,4 +40,16 @@ void MakeSourceFilePathsAbsoluteIfNeeded( std::vector<std::string>& source_files_absolute_paths, std::vector<std::string>::const_iterator files_it_begin, std::vector<std::string>::const_iterator files_it_end, bool needed); + +enum class PropertyOp +{ + Remove, + Set, + Append, + AppendAsString +}; + +bool HandleAndValidateSourceFilePropertyGENERATED( + cmSourceFile* sf, std::string const& propertyValue, + PropertyOp op = PropertyOp::Set); } diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx index c1b0c28..742aa96 100644 --- a/Source/cmSetSourceFilesPropertiesCommand.cxx +++ b/Source/cmSetSourceFilesPropertiesCommand.cxx @@ -7,6 +7,7 @@ #include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -82,7 +83,7 @@ bool cmSetSourceFilesPropertiesCommand(std::vector<std::string> const& args, const auto props_begin = options_it; bool file_scopes_handled = - SetPropertyCommand::HandleAndValidateSourceFileDirectortoryScopes( + SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes( status, source_file_directory_option_enabled, source_file_target_option_enabled, source_file_directories, source_file_target_directories, source_file_directory_makefiles); @@ -167,7 +168,13 @@ static bool RunCommandForScope( if (cmSourceFile* sf = mf->GetOrCreateSource(sfname)) { // loop through the props and set them for (auto k = propertyPairs.begin(); k != propertyPairs.end(); k += 2) { - sf->SetProperty(*k, (k + 1)->c_str()); + // Special handling for GENERATED property? + if (*k == "GENERATED"_s) { + SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED( + sf, *(k + 1)); + } else { + sf->SetProperty(*k, (k + 1)->c_str()); + } } } } diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index ef44a57..9d9a7c3 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -8,6 +8,7 @@ #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPolicies.h" #include "cmProperty.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -15,9 +16,12 @@ #include "cmake.h" cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name, - cmSourceFileLocationKind kind) - : Location(mf, name, kind) + bool generated, cmSourceFileLocationKind kind) + : Location(mf, name, (!generated) ? kind : cmSourceFileLocationKind::Known) { + if (generated) { + this->MarkAsGenerated(); + } } std::string const& cmSourceFile::GetExtension() const @@ -25,6 +29,8 @@ std::string const& cmSourceFile::GetExtension() const return this->Extension; } +const std::string propTRUE = "1"; +const std::string propFALSE = "0"; const std::string cmSourceFile::propLANGUAGE = "LANGUAGE"; const std::string cmSourceFile::propLOCATION = "LOCATION"; const std::string cmSourceFile::propGENERATED = "GENERATED"; @@ -54,16 +60,14 @@ std::string const& cmSourceFile::GetOrDetermineLanguage() } // Perform computation needed to get the language if necessary. - if (this->FullPath.empty() && this->Language.empty()) { - // If a known extension is given or a known full path is given - // then trust that the current extension is sufficient to - // determine the language. This will fail only if the user - // specifies a full path to the source but leaves off the - // extension, which is kind of weird. - if (this->Location.ExtensionIsAmbiguous() && + if (this->Language.empty()) { + // If a known extension is given or a known full path is given then trust + // that the current extension is sufficient to determine the language. This + // will fail only if the user specifies a full path to the source but + // leaves off the extension, which is kind of weird. + if (this->FullPath.empty() && this->Location.ExtensionIsAmbiguous() && this->Location.DirectoryIsAmbiguous()) { - // Finalize the file location to get the extension and set the - // language. + // Finalize the file location to get the extension and set the language. this->ResolveFullPath(); } else { // Use the known extension to get the language if possible. @@ -93,10 +97,11 @@ cmSourceFileLocation const& cmSourceFile::GetLocation() const return this->Location; } -std::string const& cmSourceFile::ResolveFullPath(std::string* error) +std::string const& cmSourceFile::ResolveFullPath(std::string* error, + std::string* cmp0115Warning) { if (this->FullPath.empty()) { - if (this->FindFullPath(error)) { + if (this->FindFullPath(error, cmp0115Warning)) { this->CheckExtension(); } } @@ -108,14 +113,18 @@ std::string const& cmSourceFile::GetFullPath() const return this->FullPath; } -bool cmSourceFile::FindFullPath(std::string* error) +bool cmSourceFile::FindFullPath(std::string* error, + std::string* cmp0115Warning) { // If the file is generated compute the location without checking on disk. - if (this->GetIsGenerated()) { + // Note: We also check for a locally set GENERATED property, because + // it might have been set before policy CMP0118 was set to NEW. + if (this->GetIsGenerated(CheckScope::GlobalAndLocal)) { // The file is either already a full path or is relative to the // build directory for the target. this->Location.DirectoryUseBinary(); this->FullPath = this->Location.GetFullPath(); + this->FindFullPathFailed = false; return true; } @@ -131,9 +140,11 @@ bool cmSourceFile::FindFullPath(std::string* error) // List of extension lists std::vector<std::string> exts = makefile->GetCMakeInstance()->GetAllExtensions(); + auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115); // Tries to find the file in a given directory - auto findInDir = [this, &exts, &lPath](std::string const& dir) -> bool { + auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning, + makefile](std::string const& dir) -> bool { // Compute full path std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir); // Try full path @@ -141,13 +152,29 @@ bool cmSourceFile::FindFullPath(std::string* error) this->FullPath = fullPath; return true; } - // Try full path with extension - for (std::string const& ext : exts) { - if (!ext.empty()) { - std::string extPath = cmStrCat(fullPath, '.', ext); - if (cmSystemTools::FileExists(extPath)) { - this->FullPath = extPath; - return true; + // This has to be an if statement due to a bug in Oracle Developer Studio. + // See https://community.oracle.com/tech/developers/discussion/4476246/ + // for details. + if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) { + // Try full path with extension + for (std::string const& ext : exts) { + if (!ext.empty()) { + std::string extPath = cmStrCat(fullPath, '.', ext); + if (cmSystemTools::FileExists(extPath)) { + this->FullPath = extPath; + if (cmp0115 == cmPolicies::WARN) { + std::string warning = + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115), + "\nFile:\n ", extPath); + if (cmp0115Warning) { + *cmp0115Warning = std::move(warning); + } else { + makefile->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, warning); + } + } + return true; + } } } } @@ -168,11 +195,19 @@ bool cmSourceFile::FindFullPath(std::string* error) } // Compose error - std::string err = - cmStrCat("Cannot find source file:\n ", lPath, "\nTried extensions"); - for (std::string const& ext : exts) { - err += " ."; - err += ext; + std::string err = cmStrCat("Cannot find source file:\n ", lPath); + switch (cmp0115) { + case cmPolicies::OLD: + case cmPolicies::WARN: + err = cmStrCat(err, "\nTried extensions"); + for (auto const& ext : exts) { + err = cmStrCat(err, " .", ext); + } + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + break; } if (error != nullptr) { *error = std::move(err); @@ -246,11 +281,6 @@ void cmSourceFile::SetProperty(const std::string& prop, const char* value) } else { this->Properties.SetProperty(prop, value); } - - // Update IsGenerated flag - if (prop == propGENERATED) { - this->IsGenerated = cmIsOn(value); - } } void cmSourceFile::AppendProperty(const std::string& prop, @@ -274,14 +304,9 @@ void cmSourceFile::AppendProperty(const std::string& prop, } else { this->Properties.AppendProperty(prop, value, asString); } - - // Update IsGenerated flag - if (prop == propGENERATED) { - this->IsGenerated = this->GetPropertyAsBool(propGENERATED); - } } -const char* cmSourceFile::GetPropertyForUser(const std::string& prop) +cmProp cmSourceFile::GetPropertyForUser(const std::string& prop) { // This method is a consequence of design history and backwards // compatibility. GetProperty is (and should be) a const method. @@ -305,13 +330,27 @@ const char* cmSourceFile::GetPropertyForUser(const std::string& prop) // Similarly, LANGUAGE can be determined by the file extension // if it is requested by the user. if (prop == propLANGUAGE) { - // The c_str pointer is valid until `this->Language` is modified. - return this->GetOrDetermineLanguage().c_str(); + // The pointer is valid until `this->Language` is modified. + return &this->GetOrDetermineLanguage(); + } + + // Special handling for GENERATED property. + if (prop == propGENERATED) { + // We need to check policy CMP0118 in order to determine if we need to + // possibly consider the value of a locally set GENERATED property, too. + auto policyStatus = + this->Location.GetMakefile()->GetPolicyStatus(cmPolicies::CMP0118); + if (this->GetIsGenerated( + (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD) + ? CheckScope::GlobalAndLocal + : CheckScope::Global)) { + return &propTRUE; + } + return &propFALSE; } // Perform the normal property lookup. - cmProp p = this->GetProperty(prop); - return p ? p->c_str() : nullptr; + return this->GetProperty(prop); } cmProp cmSourceFile::GetProperty(const std::string& prop) const @@ -369,13 +408,15 @@ cmProp cmSourceFile::GetProperty(const std::string& prop) const return retVal; } -const char* cmSourceFile::GetSafeProperty(const std::string& prop) const +const std::string& cmSourceFile::GetSafeProperty(const std::string& prop) const { cmProp ret = this->GetProperty(prop); - if (!ret) { - return ""; + if (ret) { + return *ret; } - return ret->c_str(); + + static std::string const s_empty; + return s_empty; } bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const @@ -383,11 +424,29 @@ bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const return cmIsOn(this->GetProperty(prop)); } +void cmSourceFile::MarkAsGenerated() +{ + this->IsGenerated = true; + auto& mf = *this->Location.GetMakefile(); + mf.GetGlobalGenerator()->MarkAsGeneratedFile(this->ResolveFullPath()); +} + +bool cmSourceFile::GetIsGenerated(CheckScope checkScope) const +{ + if (this->IsGenerated) { + // Globally marked as generated! + return true; + } + if (checkScope == CheckScope::GlobalAndLocal) { + // Check locally stored properties. + return this->GetPropertyAsBool(propGENERATED); + } + return false; +} + void cmSourceFile::SetProperties(cmPropertyMap properties) { this->Properties = std::move(properties); - - this->IsGenerated = this->GetPropertyAsBool(propGENERATED); } cmCustomCommand* cmSourceFile::GetCustomCommand() const diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index 39ea8e3..76a5ded 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -20,18 +20,18 @@ class cmMakefile; /** \class cmSourceFile * \brief Represent a class loaded from a makefile. * - * cmSourceFile is represents a class loaded from - * a makefile. + * cmSourceFile represents a class loaded from a makefile. */ class cmSourceFile { public: /** - * Construct with the makefile storing the source and the initial - * name referencing it. + * Construct with the makefile storing the source and the initial name + * referencing it. If it shall be marked as generated, this source file's + * kind is assumed to be known, regardless of the given value. */ cmSourceFile( - cmMakefile* mf, const std::string& name, + cmMakefile* mf, const std::string& name, bool generated, cmSourceFileLocationKind kind = cmSourceFileLocationKind::Ambiguous); /** @@ -47,16 +47,36 @@ public: //! Might return a nullptr if the property is not set or invalid cmProp GetProperty(const std::string& prop) const; //! Always returns a valid pointer - const char* GetSafeProperty(const std::string& prop) const; + const std::string& GetSafeProperty(const std::string& prop) const; bool GetPropertyAsBool(const std::string& prop) const; /** Implement getting a property when called from a CMake language command like get_property or get_source_file_property. */ - const char* GetPropertyForUser(const std::string& prop); + cmProp GetPropertyForUser(const std::string& prop); - //! Checks is the GENERATED property is set and true - /// @return Equivalent to GetPropertyAsBool("GENERATED") - bool GetIsGenerated() const { return this->IsGenerated; } + /// Marks this file as generated + /** + * This stores this file's path in the global table for all generated source + * files. + */ + void MarkAsGenerated(); + enum class CheckScope + { + Global, + GlobalAndLocal + }; + /// Determines if this source file is marked as generated. + /** + * This will check if this file's path is stored in the global table of all + * generated source files. If that is not the case and checkScope is set to + * GlobalAndLocal the value of the possibly existing local GENERATED property + * is returned instead. + * @param checkScope Determines if alternatively for backwards-compatibility + * a local GENERATED property should be considered, too. + * @return true if this source file is marked as generated, otherwise false. + */ + bool GetIsGenerated( + CheckScope checkScope = CheckScope::GlobalAndLocal) const; const std::vector<BT<std::string>>& GetCompileOptions() const { @@ -77,7 +97,8 @@ public: * Resolves the full path to the file. Attempts to locate the file on disk * and finalizes its location. */ - std::string const& ResolveFullPath(std::string* error = nullptr); + std::string const& ResolveFullPath(std::string* error = nullptr, + std::string* cmp0115Warning = nullptr); /** * The resolved full path to the file. The returned file name might be empty @@ -138,7 +159,7 @@ private: bool FindFullPathFailed = false; bool IsGenerated = false; - bool FindFullPath(std::string* error); + bool FindFullPath(std::string* error, std::string* cmp0115Warning); void CheckExtension(); void CheckLanguage(std::string const& ext); @@ -154,7 +175,7 @@ private: #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$" #define CM_SOURCE_REGEX \ - "\\.(C|F|M|c|c\\+\\+|cc|cpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|" \ + "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|cu|f|f90|for|fpp|ftn|m|mm|" \ "rc|def|r|odl|idl|hpj|bat)$" #define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$" diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx index 222bafa..921eb0e 100644 --- a/Source/cmSourceFileLocation.cxx +++ b/Source/cmSourceFileLocation.cxx @@ -33,8 +33,7 @@ cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf, this->AmbiguousExtension = true; this->Directory = cmSystemTools::GetFilenamePath(name); if (cmSystemTools::FileIsFullPath(this->Directory)) { - this->Directory = cmSystemTools::CollapseFullPath( - this->Directory, mf->GetHomeOutputDirectory()); + this->Directory = cmSystemTools::CollapseFullPath(this->Directory); } this->Name = cmSystemTools::GetFilenameName(name); if (kind == cmSourceFileLocationKind::Known) { diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index 8672f61..bf6925e 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -44,6 +44,16 @@ struct StandardNeeded int value; }; +int ParseStd(std::string const& level) +{ + try { + return std::stoi(level); + } catch (std::invalid_argument&) { + // Fall through to use an invalid value. + } + return -1; +} + struct StanardLevelComputer { explicit StanardLevelComputer(std::string lang, std::vector<int> levels, @@ -113,17 +123,8 @@ struct StanardLevelComputer standardStr = "03"; } - int standardValue = -1; - int defaultValue = -1; - try { - standardValue = std::stoi(standardStr); - defaultValue = std::stoi(*defaultStd); - } catch (std::invalid_argument&) { - // fall through as we want an error - // when we can't find the bad value in the `stds` vector - } - - auto stdIt = std::find(cm::cbegin(stds), cm::cend(stds), standardValue); + auto stdIt = + std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(standardStr)); if (stdIt == cm::cend(stds)) { std::string e = cmStrCat(this->Language, "_STANDARD is set to invalid value '", @@ -134,7 +135,7 @@ struct StanardLevelComputer } auto defaultStdIt = - std::find(cm::cbegin(stds), cm::cend(stds), defaultValue); + std::find(cm::cbegin(stds), cm::cend(stds), ParseStd(*defaultStd)); if (defaultStdIt == cm::cend(stds)) { std::string e = cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT is set to invalid value '", @@ -195,7 +196,7 @@ struct StanardLevelComputer if (existingStandard) { existingLevelIter = std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), - std::stoi(*existingStandard)); + ParseStd(*existingStandard)); if (existingLevelIter == cm::cend(this->Levels)) { const std::string e = cmStrCat("The ", this->Language, "_STANDARD property on target \"", @@ -240,7 +241,7 @@ struct StanardLevelComputer } // convert defaultStandard to an integer if (std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), - std::stoi(*defaultStandard)) == cm::cend(this->Levels)) { + ParseStd(*defaultStandard)) == cm::cend(this->Levels)) { const std::string e = cmStrCat("The CMAKE_", this->Language, "_STANDARD_DEFAULT variable contains an " "invalid value: \"", @@ -257,7 +258,7 @@ struct StanardLevelComputer auto existingLevelIter = std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), - std::stoi(*existingStandard)); + ParseStd(*existingStandard)); if (existingLevelIter == cm::cend(this->Levels)) { const std::string e = cmStrCat("The ", this->Language, "_STANDARD property on target \"", @@ -311,19 +312,19 @@ std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping = std::vector<std::string>{ "90", "99", "11" } } }, { "CXX", StanardLevelComputer{ - "CXX", std::vector<int>{ 98, 11, 14, 17, 20 }, - std::vector<std::string>{ "98", "11", "14", "17", "20" } } }, + "CXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, + std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }, { "CUDA", StanardLevelComputer{ - "CUDA", std::vector<int>{ 03, 11, 14, 17, 20 }, - std::vector<std::string>{ "03", "11", "14", "17", "20" } } }, + "CUDA", std::vector<int>{ 03, 11, 14, 17, 20, 23 }, + std::vector<std::string>{ "03", "11", "14", "17", "20", "23" } } }, { "OBJC", StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 }, std::vector<std::string>{ "90", "99", "11" } } }, { "OBJCXX", StanardLevelComputer{ - "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20 }, - std::vector<std::string>{ "98", "11", "14", "17", "20" } } }, + "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20, 23 }, + std::vector<std::string>{ "98", "11", "14", "17", "20", "23" } } }, }; } diff --git a/Source/cmState.cxx b/Source/cmState.cxx index d268e62..0fd7901 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -441,6 +441,19 @@ void cmState::AddBuiltinCommand(std::string const& name, }); } +void cmState::AddFlowControlCommand(std::string const& name, Command command) +{ + this->FlowControlCommands.insert(name); + this->AddBuiltinCommand(name, std::move(command)); +} + +void cmState::AddFlowControlCommand(std::string const& name, + BuiltinCommand command) +{ + this->FlowControlCommands.insert(name); + this->AddBuiltinCommand(name, command); +} + void cmState::AddDisallowedCommand(std::string const& name, BuiltinCommand command, cmPolicies::PolicyID policy, @@ -470,7 +483,7 @@ void cmState::AddDisallowedCommand(std::string const& name, void cmState::AddUnexpectedCommand(std::string const& name, const char* error) { - this->AddBuiltinCommand( + this->AddFlowControlCommand( name, [name, error](std::vector<cmListFileArgument> const&, cmExecutionStatus& status) -> bool { @@ -485,21 +498,33 @@ void cmState::AddUnexpectedCommand(std::string const& name, const char* error) }); } -void cmState::AddScriptedCommand(std::string const& name, Command command) +bool cmState::AddScriptedCommand(std::string const& name, BT<Command> command, + cmMakefile& mf) { std::string sName = cmSystemTools::LowerCase(name); + if (this->FlowControlCommands.count(sName)) { + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Built-in flow control command \"", sName, + "\" cannot be overridden."), + command.Backtrace); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + // if the command already exists, give a new name to the old command. if (Command oldCmd = this->GetCommandByExactName(sName)) { this->ScriptedCommands["_" + sName] = oldCmd; } - this->ScriptedCommands[sName] = std::move(command); + this->ScriptedCommands[sName] = std::move(command.Value); + return true; } cmState::Command cmState::GetCommand(std::string const& name) const { - return GetCommandByExactName(cmSystemTools::LowerCase(name)); + return this->GetCommandByExactName(cmSystemTools::LowerCase(name)); } cmState::Command cmState::GetCommandByExactName(std::string const& name) const diff --git a/Source/cmState.h b/Source/cmState.h index e4c9eb5..4e41156 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -9,6 +9,7 @@ #include <set> #include <string> #include <unordered_map> +#include <unordered_set> #include <vector> #include "cmDefinitions.h" @@ -24,6 +25,7 @@ class cmCacheManager; class cmCommand; class cmGlobVerificationManager; +class cmMakefile; class cmStateSnapshot; class cmMessenger; class cmExecutionStatus; @@ -159,10 +161,13 @@ public: std::unique_ptr<cmCommand> command); void AddBuiltinCommand(std::string const& name, Command command); void AddBuiltinCommand(std::string const& name, BuiltinCommand command); + void AddFlowControlCommand(std::string const& name, Command command); + void AddFlowControlCommand(std::string const& name, BuiltinCommand command); void AddDisallowedCommand(std::string const& name, BuiltinCommand command, cmPolicies::PolicyID policy, const char* message); void AddUnexpectedCommand(std::string const& name, const char* error); - void AddScriptedCommand(std::string const& name, Command command); + bool AddScriptedCommand(std::string const& name, BT<Command> command, + cmMakefile& mf); void RemoveBuiltinCommand(std::string const& name); void RemoveUserDefinedCommands(); std::vector<std::string> GetCommandNames() const; @@ -225,6 +230,7 @@ private: std::vector<std::string> EnabledLanguages; std::unordered_map<std::string, Command> BuiltinCommands; std::unordered_map<std::string, Command> ScriptedCommands; + std::unordered_set<std::string> FlowControlCommands; cmPropertyMap GlobalProperties; std::unique_ptr<cmCacheManager> CacheManager; std::unique_ptr<cmGlobVerificationManager> GlobVerificationManager; diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index 796bb1f..7ce362a 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -148,11 +148,13 @@ bool cmStateDirectory::ContainsBoth(std::string const& local_path, cmSystemTools::IsSubDirectory(a, b)); }; - bool bothInBinary = PathEqOrSubDir(local_path, GetRelativePathTopBinary()) && - PathEqOrSubDir(remote_path, GetRelativePathTopBinary()); + bool bothInBinary = + PathEqOrSubDir(local_path, this->GetRelativePathTopBinary()) && + PathEqOrSubDir(remote_path, this->GetRelativePathTopBinary()); - bool bothInSource = PathEqOrSubDir(local_path, GetRelativePathTopSource()) && - PathEqOrSubDir(remote_path, GetRelativePathTopSource()); + bool bothInSource = + PathEqOrSubDir(local_path, this->GetRelativePathTopSource()) && + PathEqOrSubDir(remote_path, this->GetRelativePathTopSource()); return bothInBinary || bothInSource; } diff --git a/Source/cmString.cxx b/Source/cmString.cxx index 898b828..8721242 100644 --- a/Source/cmString.cxx +++ b/Source/cmString.cxx @@ -19,17 +19,17 @@ void String::internally_mutate_to_stable_string() // We assume that only one thread mutates this instance at // a time even if we point to a shared string buffer referenced // by other threads. - *this = String(data(), size()); + *this = String(this->data(), this->size()); } bool String::is_stable() const { - return str_if_stable() != nullptr; + return this->str_if_stable() != nullptr; } void String::stabilize() { - if (is_stable()) { + if (this->is_stable()) { return; } this->internally_mutate_to_stable_string(); @@ -37,16 +37,17 @@ void String::stabilize() std::string const* String::str_if_stable() const { - if (!data()) { + if (!this->data()) { // We view no string. // This is stable for the lifetime of our current value. return &empty_string_; } - if (string_ && data() == string_->data() && size() == string_->size()) { + if (this->string_ && this->data() == this->string_->data() && + this->size() == this->string_->size()) { // We view an entire string. // This is stable for the lifetime of our current value. - return string_.get(); + return this->string_.get(); } return nullptr; @@ -54,18 +55,18 @@ std::string const* String::str_if_stable() const std::string const& String::str() { - if (std::string const* s = str_if_stable()) { + if (std::string const* s = this->str_if_stable()) { return *s; } // Mutate to hold a std::string that is stable for the lifetime // of our current value. this->internally_mutate_to_stable_string(); - return *string_; + return *this->string_; } const char* String::c_str() { - const char* c = data(); + const char* c = this->data(); if (c == nullptr) { return c; } @@ -73,42 +74,42 @@ const char* String::c_str() // We always point into a null-terminated string so it is safe to // access one past the end. If it is a null byte then we can use // the pointer directly. - if (c[size()] == '\0') { + if (c[this->size()] == '\0') { return c; } // Mutate to hold a std::string so we can get a null terminator. this->internally_mutate_to_stable_string(); - c = string_->c_str(); + c = this->string_->c_str(); return c; } String& String::insert(size_type index, size_type count, char ch) { std::string s; - s.reserve(size() + count); - s.assign(data(), size()); + s.reserve(this->size() + count); + s.assign(this->data(), this->size()); s.insert(index, count, ch); return *this = std::move(s); } String& String::erase(size_type index, size_type count) { - if (index > size()) { + if (index > this->size()) { throw std::out_of_range("Index out of range in String::erase"); } - size_type const rcount = std::min(count, size() - index); + size_type const rcount = std::min(count, this->size() - index); size_type const rindex = index + rcount; std::string s; - s.reserve(size() - rcount); - s.assign(data(), index); - s.append(data() + rindex, size() - rindex); + s.reserve(this->size() - rcount); + s.assign(this->data(), index); + s.append(this->data() + rindex, this->size() - rindex); return *this = std::move(s); } String String::substr(size_type pos, size_type count) const { - if (pos > size()) { + if (pos > this->size()) { throw std::out_of_range("Index out of range in String::substr"); } return String(*this, pos, count); @@ -116,14 +117,14 @@ String String::substr(size_type pos, size_type count) const String::String(std::string&& s, Private) : string_(std::make_shared<std::string>(std::move(s))) - , view_(string_->data(), string_->size()) + , view_(this->string_->data(), this->string_->size()) { } String::size_type String::copy(char* dest, size_type count, size_type pos) const { - return view_.copy(dest, count, pos); + return this->view_.copy(dest, count, pos); } std::ostream& operator<<(std::ostream& os, String const& s) diff --git a/Source/cmString.hxx b/Source/cmString.hxx index b41b960..f1e462b 100644 --- a/Source/cmString.hxx +++ b/Source/cmString.hxx @@ -301,8 +301,8 @@ public: The other instance is left as a null string. */ String& operator=(String&& s) noexcept { - string_ = std::move(s.string_); - view_ = s.view_; + this->string_ = std::move(s.string_); + this->view_ = s.view_; s.view_ = string_view(); return *this; } @@ -340,33 +340,33 @@ public: } /** Return true if the instance is not a null string. */ - explicit operator bool() const noexcept { return data() != nullptr; } + explicit operator bool() const noexcept { return this->data() != nullptr; } /** Return a view of the string. */ - string_view view() const noexcept { return view_; } + string_view view() const noexcept { return this->view_; } operator string_view() const noexcept { return this->view(); } /** Return true if the instance is an empty stringn or null string. */ - bool empty() const noexcept { return view_.empty(); } + bool empty() const noexcept { return this->view_.empty(); } /** Return a pointer to the start of the string. */ - const char* data() const noexcept { return view_.data(); } + const char* data() const noexcept { return this->view_.data(); } /** Return the length of the string in bytes. */ - size_type size() const noexcept { return view_.size(); } - size_type length() const noexcept { return view_.length(); } + size_type size() const noexcept { return this->view_.size(); } + size_type length() const noexcept { return this->view_.length(); } /** Return the character at the given position. No bounds checking is performed. */ - char operator[](size_type pos) const noexcept { return view_[pos]; } + char operator[](size_type pos) const noexcept { return this->view_[pos]; } /** Return the character at the given position. If the position is out of bounds, throws std::out_of_range. */ - char at(size_type pos) const { return view_.at(pos); } + char at(size_type pos) const { return this->view_.at(pos); } - char front() const noexcept { return view_.front(); } + char front() const noexcept { return this->view_.front(); } - char back() const noexcept { return view_.back(); } + char back() const noexcept { return this->view_.back(); } /** Return true if this instance is stable and otherwise false. An instance is stable if it is in the 'null' state or if it is @@ -392,15 +392,18 @@ public: or str() is called. */ const char* c_str(); - const_iterator begin() const noexcept { return view_.begin(); } - const_iterator end() const noexcept { return view_.end(); } - const_iterator cbegin() const noexcept { return begin(); } - const_iterator cend() const noexcept { return end(); } + const_iterator begin() const noexcept { return this->view_.begin(); } + const_iterator end() const noexcept { return this->view_.end(); } + const_iterator cbegin() const noexcept { return this->begin(); } + const_iterator cend() const noexcept { return this->end(); } - const_reverse_iterator rbegin() const noexcept { return view_.rbegin(); } - const_reverse_iterator rend() const noexcept { return view_.rend(); } - const_reverse_iterator crbegin() const noexcept { return rbegin(); } - const_reverse_iterator crend() const noexcept { return rend(); } + const_reverse_iterator rbegin() const noexcept + { + return this->view_.rbegin(); + } + const_reverse_iterator rend() const noexcept { return this->view_.rend(); } + const_reverse_iterator crbegin() const noexcept { return this->rbegin(); } + const_reverse_iterator crend() const noexcept { return this->rend(); } /** Append to the string using any type that implements the AsStringView trait. */ @@ -410,8 +413,8 @@ public: { string_view v = AsStringView<T>::view(std::forward<T>(s)); std::string r; - r.reserve(size() + v.size()); - r.assign(data(), size()); + r.reserve(this->size() + v.size()); + r.assign(this->data(), this->size()); r.append(v.data(), v.size()); return *this = std::move(r); } @@ -428,21 +431,21 @@ public: void push_back(char ch) { std::string s; - s.reserve(size() + 1); - s.assign(data(), size()); + s.reserve(this->size() + 1); + s.assign(this->data(), this->size()); s.push_back(ch); *this = std::move(s); } - void pop_back() { *this = String(*this, 0, size() - 1); } + void pop_back() { *this = String(*this, 0, this->size() - 1); } template <typename T> typename std::enable_if<AsStringView<T>::value, String&>::type replace( size_type pos, size_type count, T&& s) { - const_iterator first = begin() + pos; + const_iterator first = this->begin() + pos; const_iterator last = first + count; - return replace(first, last, std::forward<T>(s)); + return this->replace(first, last, std::forward<T>(s)); } template <typename InputIterator> @@ -450,9 +453,9 @@ public: InputIterator first2, InputIterator last2) { std::string out; - out.append(view_.begin(), first); + out.append(this->view_.begin(), first); out.append(first2, last2); - out.append(last, view_.end()); + out.append(last, this->view_.end()); return *this = std::move(out); } @@ -462,10 +465,11 @@ public: { string_view v = AsStringView<T>::view(std::forward<T>(s)); std::string out; - out.reserve((first - view_.begin()) + v.size() + (view_.end() - last)); - out.append(view_.begin(), first); + out.reserve((first - this->view_.begin()) + v.size() + + (this->view_.end() - last)); + out.append(this->view_.begin(), first); out.append(v.data(), v.size()); - out.append(last, view_.end()); + out.append(last, this->view_.end()); return *this = std::move(out); } @@ -476,39 +480,40 @@ public: { string_view v = AsStringView<T>::view(std::forward<T>(s)); v = v.substr(pos2, count2); - return replace(pos, count, v); + return this->replace(pos, count, v); } String& replace(size_type pos, size_type count, size_type count2, char ch) { - const_iterator first = begin() + pos; + const_iterator first = this->begin() + pos; const_iterator last = first + count; - return replace(first, last, count2, ch); + return this->replace(first, last, count2, ch); } String& replace(const_iterator first, const_iterator last, size_type count2, char ch) { std::string out; - out.reserve((first - view_.begin()) + count2 + (view_.end() - last)); - out.append(view_.begin(), first); + out.reserve((first - this->view_.begin()) + count2 + + (this->view_.end() - last)); + out.append(this->view_.begin(), first); out.append(count2, ch); - out.append(last, view_.end()); + out.append(last, this->view_.end()); return *this = std::move(out); } size_type copy(char* dest, size_type count, size_type pos = 0) const; - void resize(size_type count) { resize(count, char()); } + void resize(size_type count) { this->resize(count, char()); } void resize(size_type count, char ch) { std::string s; s.reserve(count); - if (count <= size()) { - s.assign(data(), count); + if (count <= this->size()) { + s.assign(this->data(), count); } else { - s.assign(data(), size()); + s.assign(this->data(), this->size()); s.resize(count, ch); } *this = std::move(s); @@ -516,8 +521,8 @@ public: void swap(String& other) { - std::swap(string_, other.string_); - std::swap(view_, other.view_); + std::swap(this->string_, other.string_); + std::swap(this->view_, other.view_); } /** Return a substring starting at position 'pos' and @@ -528,29 +533,29 @@ public: typename std::enable_if<AsStringView<T>::value, int>::type compare( T&& s) const { - return view_.compare(AsStringView<T>::view(std::forward<T>(s))); + return this->view_.compare(AsStringView<T>::view(std::forward<T>(s))); } int compare(size_type pos1, size_type count1, string_view v) const { - return view_.compare(pos1, count1, v); + return this->view_.compare(pos1, count1, v); } int compare(size_type pos1, size_type count1, string_view v, size_type pos2, size_type count2) const { - return view_.compare(pos1, count1, v, pos2, count2); + return this->view_.compare(pos1, count1, v, pos2, count2); } int compare(size_type pos1, size_type count1, const char* s) const { - return view_.compare(pos1, count1, s); + return this->view_.compare(pos1, count1, s); } int compare(size_type pos1, size_type count1, const char* s, size_type count2) const { - return view_.compare(pos1, count1, s, count2); + return this->view_.compare(pos1, count1, s, count2); } template <typename T> @@ -558,12 +563,12 @@ public: T&& s, size_type pos = 0) const { string_view v = AsStringView<T>::view(std::forward<T>(s)); - return view_.find(v, pos); + return this->view_.find(v, pos); } size_type find(const char* s, size_type pos, size_type count) const { - return view_.find(s, pos, count); + return this->view_.find(s, pos, count); } template <typename T> @@ -571,12 +576,12 @@ public: T&& s, size_type pos = npos) const { string_view v = AsStringView<T>::view(std::forward<T>(s)); - return view_.rfind(v, pos); + return this->view_.rfind(v, pos); } size_type rfind(const char* s, size_type pos, size_type count) const { - return view_.rfind(s, pos, count); + return this->view_.rfind(s, pos, count); } template <typename T> @@ -584,12 +589,12 @@ public: find_first_of(T&& s, size_type pos = 0) const { string_view v = AsStringView<T>::view(std::forward<T>(s)); - return view_.find_first_of(v, pos); + return this->view_.find_first_of(v, pos); } size_type find_first_of(const char* s, size_type pos, size_type count) const { - return view_.find_first_of(s, pos, count); + return this->view_.find_first_of(s, pos, count); } template <typename T> @@ -597,13 +602,13 @@ public: find_first_not_of(T&& s, size_type pos = 0) const { string_view v = AsStringView<T>::view(std::forward<T>(s)); - return view_.find_first_not_of(v, pos); + return this->view_.find_first_not_of(v, pos); } size_type find_first_not_of(const char* s, size_type pos, size_type count) const { - return view_.find_first_not_of(s, pos, count); + return this->view_.find_first_not_of(s, pos, count); } template <typename T> @@ -611,12 +616,12 @@ public: find_last_of(T&& s, size_type pos = npos) const { string_view v = AsStringView<T>::view(std::forward<T>(s)); - return view_.find_last_of(v, pos); + return this->view_.find_last_of(v, pos); } size_type find_last_of(const char* s, size_type pos, size_type count) const { - return view_.find_last_of(s, pos, count); + return this->view_.find_last_of(s, pos, count); } template <typename T> @@ -624,13 +629,13 @@ public: find_last_not_of(T&& s, size_type pos = npos) const { string_view v = AsStringView<T>::view(std::forward<T>(s)); - return view_.find_last_not_of(v, pos); + return this->view_.find_last_not_of(v, pos); } size_type find_last_not_of(const char* s, size_type pos, size_type count) const { - return view_.find_last_not_of(s, pos, count); + return this->view_.find_last_not_of(s, pos, count); } private: @@ -822,7 +827,10 @@ struct StringOpPlus } #endif operator std::string() const; - std::string::size_type size() const { return l.size() + r.size(); } + std::string::size_type size() const + { + return this->l.size() + this->r.size(); + } }; template <typename T> @@ -848,7 +856,7 @@ template <typename L, typename R> StringOpPlus<L, R>::operator std::string() const { std::string s; - s.reserve(size()); + s.reserve(this->size()); s += *this; return s; } diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index e0af281..fb0b705 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -161,42 +161,42 @@ inline void MakeDigits(cm::string_view& view, char (&digits)[N], cmAlphaNum::cmAlphaNum(int val) { - MakeDigits(View_, Digits_, "%i", val); + MakeDigits(this->View_, this->Digits_, "%i", val); } cmAlphaNum::cmAlphaNum(unsigned int val) { - MakeDigits(View_, Digits_, "%u", val); + MakeDigits(this->View_, this->Digits_, "%u", val); } cmAlphaNum::cmAlphaNum(long int val) { - MakeDigits(View_, Digits_, "%li", val); + MakeDigits(this->View_, this->Digits_, "%li", val); } cmAlphaNum::cmAlphaNum(unsigned long int val) { - MakeDigits(View_, Digits_, "%lu", val); + MakeDigits(this->View_, this->Digits_, "%lu", val); } cmAlphaNum::cmAlphaNum(long long int val) { - MakeDigits(View_, Digits_, "%lli", val); + MakeDigits(this->View_, this->Digits_, "%lli", val); } cmAlphaNum::cmAlphaNum(unsigned long long int val) { - MakeDigits(View_, Digits_, "%llu", val); + MakeDigits(this->View_, this->Digits_, "%llu", val); } cmAlphaNum::cmAlphaNum(float val) { - MakeDigits(View_, Digits_, "%g", static_cast<double>(val)); + MakeDigits(this->View_, this->Digits_, "%g", static_cast<double>(val)); } cmAlphaNum::cmAlphaNum(double val) { - MakeDigits(View_, Digits_, "%g", val); + MakeDigits(this->View_, this->Digits_, "%g", val); } std::string cmCatViews(std::initializer_list<cm::string_view> views) diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 01e3d94..6b458ec 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -48,7 +48,7 @@ struct cmStrCmp { } - bool operator()(cm::string_view sv) const { return Test_ == sv; } + bool operator()(cm::string_view sv) const { return this->Test_ == sv; } private: std::string const Test_; @@ -163,9 +163,9 @@ public: { } cmAlphaNum(char ch) - : View_(Digits_, 1) + : View_(this->Digits_, 1) { - Digits_[0] = ch; + this->Digits_[0] = ch; } cmAlphaNum(int val); cmAlphaNum(unsigned int val); @@ -176,7 +176,7 @@ public: cmAlphaNum(float val); cmAlphaNum(double val); - cm::string_view View() const { return View_; } + cm::string_view View() const { return this->View_; } private: cm::string_view View_; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index b28fca9..0c8adc7 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -966,21 +966,21 @@ public: const std::string& Args::PopFront(cm::string_view error) { - if (empty()) { + if (this->empty()) { throw json_error({ error }); } - const std::string& res = *begin(); - advance(1); + const std::string& res = *this->begin(); + this->advance(1); return res; } const std::string& Args::PopBack(cm::string_view error) { - if (empty()) { + if (this->empty()) { throw json_error({ error }); } - const std::string& res = *(end() - 1); - retreat(1); + const std::string& res = *(this->end() - 1); + this->retreat(1); return res; } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 6a705f4..024356f 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1255,6 +1255,30 @@ void cmSystemTools::ConvertToOutputSlashes(std::string& path) #endif } +void cmSystemTools::ConvertToLongPath(std::string& path) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + // Try to convert path to a long path only if the path contains character '~' + if (path.find('~') == std::string::npos) { + return; + } + + std::wstring wPath = cmsys::Encoding::ToWide(path); + DWORD ret = GetLongPathNameW(wPath.c_str(), nullptr, 0); + std::vector<wchar_t> buffer(ret); + if (ret != 0) { + ret = GetLongPathNameW(wPath.c_str(), buffer.data(), + static_cast<DWORD>(buffer.size())); + } + + if (ret != 0) { + path = cmsys::Encoding::ToNarrow(buffer.data()); + } +#else + static_cast<void>(path); +#endif +} + std::string cmSystemTools::ConvertToRunCommandPath(const std::string& path) { #if defined(_WIN32) && !defined(__CYGWIN__) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 1100f05..5bbbb0c 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -287,6 +287,12 @@ public: // running cmake needs paths to be in its format static std::string ConvertToRunCommandPath(const std::string& path); + /** + * For windows computes the long path for the given path, + * For Unix, it is a noop + */ + static void ConvertToLongPath(std::string& path); + /** compute the relative path from local to remote. local must be a directory. remote can be a file or a directory. Both remote and local must be full paths. Basically, if diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index bda2b30..1fd2355 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -213,7 +213,7 @@ public: bool CheckImportedLibName(std::string const& prop, std::string const& value) const; - std::string ProcessSourceItemCMP0049(const std::string& s); + std::string ProcessSourceItemCMP0049(const std::string& s) const; }; namespace { @@ -230,34 +230,35 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, : impl(cm::make_unique<cmTargetInternals>()) { assert(mf); - impl->TargetType = type; - impl->Makefile = mf; - impl->Name = name; - impl->IsGeneratorProvided = false; - impl->HaveInstallRule = false; - impl->IsDLLPlatform = false; - impl->IsAIX = false; - impl->IsAndroid = false; - impl->IsImportedTarget = + this->impl->TargetType = type; + this->impl->Makefile = mf; + this->impl->Name = name; + this->impl->IsGeneratorProvided = false; + this->impl->HaveInstallRule = false; + this->impl->IsDLLPlatform = false; + this->impl->IsAIX = false; + this->impl->IsAndroid = false; + this->impl->IsImportedTarget = (vis == VisibilityImported || vis == VisibilityImportedGlobally); - impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally; - impl->BuildInterfaceIncludesAppended = false; - impl->PerConfig = (perConfig == PerConfig::Yes); + this->impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally; + this->impl->BuildInterfaceIncludesAppended = false; + this->impl->PerConfig = (perConfig == PerConfig::Yes); // Check whether this is a DLL platform. - impl->IsDLLPlatform = - !impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); + this->impl->IsDLLPlatform = + !this->impl->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX") + .empty(); // Check whether we are targeting AIX. { std::string const& systemName = - impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"); - impl->IsAIX = (systemName == "AIX" || systemName == "OS400"); + this->impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"); + this->impl->IsAIX = (systemName == "AIX" || systemName == "OS400"); } // Check whether we are targeting an Android platform. - impl->IsAndroid = - (impl->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android"); + this->impl->IsAndroid = (this->impl->Makefile->GetSafeDefinition( + "CMAKE_SYSTEM_NAME") == "Android"); std::string defKey; defKey.reserve(128); @@ -373,12 +374,16 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("ISPC_INSTRUCTION_SETS"); initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); + initProp("OBJC_CLANG_TIDY"); + initProp("OBJCXX_CLANG_TIDY"); initProp("Swift_LANGUAGE_VERSION"); initProp("Swift_MODULE_DIRECTORY"); initProp("VS_JUST_MY_CODE_DEBUGGING"); initProp("DISABLE_PRECOMPILE_HEADERS"); initProp("UNITY_BUILD"); + initProp("UNITY_BUILD_UNIQUE_ID"); initProp("OPTIMIZE_DEPENDENCIES"); + initProp("EXPORT_COMPILE_COMMANDS"); initPropValue("UNITY_BUILD_BATCH_SIZE", "8"); initPropValue("UNITY_BUILD_MODE", "BATCH"); initPropValue("PCH_WARN_INVALID", "ON"); @@ -433,7 +438,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, for (auto const& prop : configProps) { // Interface libraries have no output locations, so honor only // the configuration map. - if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY && + if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY && strcmp(prop, "MAP_IMPORTED_CONFIG_") != 0) { continue; } @@ -446,15 +451,15 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, // compatibility with previous CMake versions in which executables // did not support this variable. Projects may still specify the // property directly. - if (impl->TargetType != cmStateEnums::EXECUTABLE && - impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) { + if (this->impl->TargetType != cmStateEnums::EXECUTABLE && + this->impl->TargetType != cmStateEnums::INTERFACE_LIBRARY) { std::string property = cmStrCat(cmSystemTools::UpperCase(configName), "_POSTFIX"); initProp(property); } - if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || - impl->TargetType == cmStateEnums::STATIC_LIBRARY) { + if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY || + this->impl->TargetType == cmStateEnums::STATIC_LIBRARY) { std::string property = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_", cmSystemTools::UpperCase(configName)); initProp(property); @@ -463,66 +468,67 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, } // Save the backtrace of target construction. - impl->Backtrace = impl->Makefile->GetBacktrace(); + this->impl->Backtrace = this->impl->Makefile->GetBacktrace(); if (!this->IsImported()) { // Initialize the INCLUDE_DIRECTORIES property based on the current value // of the same directory property: - cm::append(impl->IncludeDirectoriesEntries, - impl->Makefile->GetIncludeDirectoriesEntries()); - cm::append(impl->IncludeDirectoriesBacktraces, - impl->Makefile->GetIncludeDirectoriesBacktraces()); + cm::append(this->impl->IncludeDirectoriesEntries, + this->impl->Makefile->GetIncludeDirectoriesEntries()); + cm::append(this->impl->IncludeDirectoriesBacktraces, + this->impl->Makefile->GetIncludeDirectoriesBacktraces()); { - auto const& sysInc = impl->Makefile->GetSystemIncludeDirectories(); - impl->SystemIncludeDirectories.insert(sysInc.begin(), sysInc.end()); + auto const& sysInc = this->impl->Makefile->GetSystemIncludeDirectories(); + this->impl->SystemIncludeDirectories.insert(sysInc.begin(), + sysInc.end()); } - cm::append(impl->CompileOptionsEntries, - impl->Makefile->GetCompileOptionsEntries()); - cm::append(impl->CompileOptionsBacktraces, - impl->Makefile->GetCompileOptionsBacktraces()); + cm::append(this->impl->CompileOptionsEntries, + this->impl->Makefile->GetCompileOptionsEntries()); + cm::append(this->impl->CompileOptionsBacktraces, + this->impl->Makefile->GetCompileOptionsBacktraces()); - cm::append(impl->LinkOptionsEntries, - impl->Makefile->GetLinkOptionsEntries()); - cm::append(impl->LinkOptionsBacktraces, - impl->Makefile->GetLinkOptionsBacktraces()); + cm::append(this->impl->LinkOptionsEntries, + this->impl->Makefile->GetLinkOptionsEntries()); + cm::append(this->impl->LinkOptionsBacktraces, + this->impl->Makefile->GetLinkOptionsBacktraces()); - cm::append(impl->LinkDirectoriesEntries, - impl->Makefile->GetLinkDirectoriesEntries()); - cm::append(impl->LinkDirectoriesBacktraces, - impl->Makefile->GetLinkDirectoriesBacktraces()); + cm::append(this->impl->LinkDirectoriesEntries, + this->impl->Makefile->GetLinkDirectoriesEntries()); + cm::append(this->impl->LinkDirectoriesBacktraces, + this->impl->Makefile->GetLinkDirectoriesBacktraces()); } - if (impl->TargetType == cmStateEnums::EXECUTABLE) { + if (this->impl->TargetType == cmStateEnums::EXECUTABLE) { initProp("ANDROID_GUI"); initProp("CROSSCOMPILING_EMULATOR"); initProp("ENABLE_EXPORTS"); } - if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || - impl->TargetType == cmStateEnums::MODULE_LIBRARY) { + if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY || + this->impl->TargetType == cmStateEnums::MODULE_LIBRARY) { this->SetProperty("POSITION_INDEPENDENT_CODE", "True"); } else if (this->CanCompileSources()) { initProp("POSITION_INDEPENDENT_CODE"); } - if (impl->TargetType == cmStateEnums::SHARED_LIBRARY || - impl->TargetType == cmStateEnums::EXECUTABLE) { + if (this->impl->TargetType == cmStateEnums::SHARED_LIBRARY || + this->impl->TargetType == cmStateEnums::EXECUTABLE) { initProp("AIX_EXPORT_ALL_SYMBOLS"); initProp("WINDOWS_EXPORT_ALL_SYMBOLS"); } // Record current policies for later use. - impl->Makefile->RecordPolicies(impl->PolicyMap); + this->impl->Makefile->RecordPolicies(this->impl->PolicyMap); - if (impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) { + if (this->impl->TargetType == cmStateEnums::INTERFACE_LIBRARY) { // This policy is checked in a few conditions. The properties relevant // to the policy are always ignored for cmStateEnums::INTERFACE_LIBRARY // targets, // so ensure that the conditions don't lead to nonsense. - impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW); + this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW); } - if (impl->TargetType <= cmStateEnums::GLOBAL_TARGET) { + if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) { initProp("DOTNET_TARGET_FRAMEWORK"); initProp("DOTNET_TARGET_FRAMEWORK_VERSION"); } @@ -555,40 +561,40 @@ cmTarget& cmTarget::operator=(cmTarget&&) noexcept = default; cmStateEnums::TargetType cmTarget::GetType() const { - return impl->TargetType; + return this->impl->TargetType; } cmMakefile* cmTarget::GetMakefile() const { - return impl->Makefile; + return this->impl->Makefile; } cmPolicies::PolicyMap const& cmTarget::GetPolicyMap() const { - return impl->PolicyMap; + return this->impl->PolicyMap; } const std::string& cmTarget::GetName() const { - return impl->Name; + return this->impl->Name; } cmPolicies::PolicyStatus cmTarget::GetPolicyStatus( cmPolicies::PolicyID policy) const { - return impl->PolicyMap.Get(policy); + return this->impl->PolicyMap.Get(policy); } cmGlobalGenerator* cmTarget::GetGlobalGenerator() const { - return impl->Makefile->GetGlobalGenerator(); + return this->impl->Makefile->GetGlobalGenerator(); } BTs<std::string> const* cmTarget::GetLanguageStandardProperty( const std::string& propertyName) const { - auto entry = impl->LanguageStandardProperties.find(propertyName); - if (entry != impl->LanguageStandardProperties.end()) { + auto entry = this->impl->LanguageStandardProperties.find(propertyName); + if (entry != this->impl->LanguageStandardProperties.end()) { return &entry->second; } @@ -600,17 +606,17 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang, const std::string& feature) { cmListFileBacktrace featureBacktrace; - for (size_t i = 0; i < impl->CompileFeaturesEntries.size(); i++) { - if (impl->CompileFeaturesEntries[i] == feature) { - if (i < impl->CompileFeaturesBacktraces.size()) { - featureBacktrace = impl->CompileFeaturesBacktraces[i]; + for (size_t i = 0; i < this->impl->CompileFeaturesEntries.size(); i++) { + if (this->impl->CompileFeaturesEntries[i] == feature) { + if (i < this->impl->CompileFeaturesBacktraces.size()) { + featureBacktrace = this->impl->CompileFeaturesBacktraces[i]; } break; } } BTs<std::string>& languageStandardProperty = - impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")]; + this->impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")]; if (languageStandardProperty.Value != value) { languageStandardProperty.Value = value; languageStandardProperty.Backtraces.clear(); @@ -620,19 +626,24 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang, void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf) { - impl->Utilities.insert(BT<std::pair<std::string, bool>>( + this->impl->Utilities.insert(BT<std::pair<std::string, bool>>( { name, cross }, mf ? mf->GetBacktrace() : cmListFileBacktrace())); } +void cmTarget::AddUtility(BT<std::pair<std::string, bool>> util) +{ + this->impl->Utilities.emplace(std::move(util)); +} + std::set<BT<std::pair<std::string, bool>>> const& cmTarget::GetUtilities() const { - return impl->Utilities; + return this->impl->Utilities; } cmListFileBacktrace const& cmTarget::GetBacktrace() const { - return impl->Backtrace; + return this->impl->Backtrace; } bool cmTarget::IsExecutableWithExports() const @@ -645,74 +656,74 @@ bool cmTarget::IsFrameworkOnApple() const { return ((this->GetType() == cmStateEnums::SHARED_LIBRARY || this->GetType() == cmStateEnums::STATIC_LIBRARY) && - impl->Makefile->IsOn("APPLE") && + this->impl->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("FRAMEWORK")); } bool cmTarget::IsAppBundleOnApple() const { return (this->GetType() == cmStateEnums::EXECUTABLE && - impl->Makefile->IsOn("APPLE") && + this->impl->Makefile->IsOn("APPLE") && this->GetPropertyAsBool("MACOSX_BUNDLE")); } bool cmTarget::IsAndroidGuiExecutable() const { - return (this->GetType() == cmStateEnums::EXECUTABLE && impl->IsAndroid && - this->GetPropertyAsBool("ANDROID_GUI")); + return (this->GetType() == cmStateEnums::EXECUTABLE && + this->impl->IsAndroid && this->GetPropertyAsBool("ANDROID_GUI")); } std::vector<cmCustomCommand> const& cmTarget::GetPreBuildCommands() const { - return impl->PreBuildCommands; + return this->impl->PreBuildCommands; } void cmTarget::AddPreBuildCommand(cmCustomCommand const& cmd) { - impl->PreBuildCommands.push_back(cmd); + this->impl->PreBuildCommands.push_back(cmd); } void cmTarget::AddPreBuildCommand(cmCustomCommand&& cmd) { - impl->PreBuildCommands.push_back(std::move(cmd)); + this->impl->PreBuildCommands.push_back(std::move(cmd)); } std::vector<cmCustomCommand> const& cmTarget::GetPreLinkCommands() const { - return impl->PreLinkCommands; + return this->impl->PreLinkCommands; } void cmTarget::AddPreLinkCommand(cmCustomCommand const& cmd) { - impl->PreLinkCommands.push_back(cmd); + this->impl->PreLinkCommands.push_back(cmd); } void cmTarget::AddPreLinkCommand(cmCustomCommand&& cmd) { - impl->PreLinkCommands.push_back(std::move(cmd)); + this->impl->PreLinkCommands.push_back(std::move(cmd)); } std::vector<cmCustomCommand> const& cmTarget::GetPostBuildCommands() const { - return impl->PostBuildCommands; + return this->impl->PostBuildCommands; } void cmTarget::AddPostBuildCommand(cmCustomCommand const& cmd) { - impl->PostBuildCommands.push_back(cmd); + this->impl->PostBuildCommands.push_back(cmd); } void cmTarget::AddPostBuildCommand(cmCustomCommand&& cmd) { - impl->PostBuildCommands.push_back(std::move(cmd)); + this->impl->PostBuildCommands.push_back(std::move(cmd)); } void cmTarget::AddTracedSources(std::vector<std::string> const& srcs) { if (!srcs.empty()) { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->SourceEntries.push_back(cmJoin(srcs, ";")); - impl->SourceBacktraces.push_back(lfbt); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->SourceEntries.push_back(cmJoin(srcs, ";")); + this->impl->SourceBacktraces.push_back(lfbt); } } @@ -723,25 +734,26 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs) for (auto filename : srcs) { if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) { if (!filename.empty()) { - filename = impl->ProcessSourceItemCMP0049(filename); + filename = this->impl->ProcessSourceItemCMP0049(filename); if (filename.empty()) { return; } } - impl->Makefile->GetOrCreateSource(filename); + this->impl->Makefile->GetOrCreateSource(filename); } srcFiles += sep; srcFiles += filename; sep = ";"; } if (!srcFiles.empty()) { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->SourceEntries.push_back(std::move(srcFiles)); - impl->SourceBacktraces.push_back(lfbt); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->SourceEntries.push_back(std::move(srcFiles)); + this->impl->SourceBacktraces.push_back(lfbt); } } -std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s) +std::string cmTargetInternals::ProcessSourceItemCMP0049( + const std::string& s) const { std::string src = s; @@ -780,7 +792,7 @@ std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s) std::string cmTarget::GetSourceCMP0049(const std::string& s) { - return impl->ProcessSourceItemCMP0049(s); + return this->impl->ProcessSourceItemCMP0049(s); } struct CreateLocation @@ -792,7 +804,7 @@ struct CreateLocation { } - cmSourceFileLocation operator()(const std::string& filename) + cmSourceFileLocation operator()(const std::string& filename) const { return cmSourceFileLocation(this->Makefile, filename); } @@ -839,26 +851,28 @@ public: cmSourceFile* cmTarget::AddSource(const std::string& src, bool before) { - cmSourceFileLocation sfl(impl->Makefile, src, + cmSourceFileLocation sfl(this->impl->Makefile, src, cmSourceFileLocationKind::Known); - if (std::find_if(impl->SourceEntries.begin(), impl->SourceEntries.end(), - TargetPropertyEntryFinder(sfl)) == - impl->SourceEntries.end()) { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->SourceEntries.insert( - before ? impl->SourceEntries.begin() : impl->SourceEntries.end(), src); - impl->SourceBacktraces.insert(before ? impl->SourceBacktraces.begin() - : impl->SourceBacktraces.end(), - lfbt); + if (std::find_if( + this->impl->SourceEntries.begin(), this->impl->SourceEntries.end(), + TargetPropertyEntryFinder(sfl)) == this->impl->SourceEntries.end()) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->SourceEntries.insert(before ? this->impl->SourceEntries.begin() + : this->impl->SourceEntries.end(), + src); + this->impl->SourceBacktraces.insert( + before ? this->impl->SourceBacktraces.begin() + : this->impl->SourceBacktraces.end(), + lfbt); } if (cmGeneratorExpression::Find(src) != std::string::npos) { return nullptr; } - return impl->Makefile->GetOrCreateSource(src, false, - cmSourceFileLocationKind::Known); + return this->impl->Makefile->GetOrCreateSource( + src, false, cmSourceFileLocationKind::Known); } -void cmTarget::ClearDependencyInformation(cmMakefile& mf) +void cmTarget::ClearDependencyInformation(cmMakefile& mf) const { std::string depname = cmStrCat(this->GetName(), "_LIB_DEPENDS"); mf.RemoveCacheDefinition(depname); @@ -873,7 +887,7 @@ std::string cmTarget::GetDebugGeneratorExpressions( // Get the list of configurations considered to be DEBUG. std::vector<std::string> debugConfigs = - impl->Makefile->GetCMakeInstance()->GetDebugConfigs(); + this->impl->Makefile->GetCMakeInstance()->GetDebugConfigs(); std::string configString = "$<CONFIG:" + debugConfigs[0] + ">"; @@ -899,13 +913,14 @@ bool cmTarget::PushTLLCommandTrace(TLLSignature signature, cmListFileContext const& lfc) { bool ret = true; - if (!impl->TLLCommands.empty()) { - if (impl->TLLCommands.back().first != signature) { + if (!this->impl->TLLCommands.empty()) { + if (this->impl->TLLCommands.back().first != signature) { ret = false; } } - if (impl->TLLCommands.empty() || impl->TLLCommands.back().second != lfc) { - impl->TLLCommands.emplace_back(signature, lfc); + if (this->impl->TLLCommands.empty() || + this->impl->TLLCommands.back().second != lfc) { + this->impl->TLLCommands.emplace_back(signature, lfc); } return ret; } @@ -915,12 +930,13 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const const char* sigString = (sig == cmTarget::KeywordTLLSignature ? "keyword" : "plain"); s << "The uses of the " << sigString << " signature are here:\n"; - cmStateDirectory cmDir = impl->Makefile->GetStateSnapshot().GetDirectory(); - for (auto const& cmd : impl->TLLCommands) { + cmStateDirectory cmDir = + this->impl->Makefile->GetStateSnapshot().GetDirectory(); + for (auto const& cmd : this->impl->TLLCommands) { if (cmd.first == sig) { cmListFileContext lfc = cmd.second; lfc.FilePath = cmDir.ConvertToRelPathIfNotContained( - impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath); + this->impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath); s << " * " << lfc << '\n'; } } @@ -928,59 +944,59 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const std::string const& cmTarget::GetInstallPath() const { - return impl->InstallPath; + return this->impl->InstallPath; } void cmTarget::SetInstallPath(std::string const& name) { - impl->InstallPath = name; + this->impl->InstallPath = name; } std::string const& cmTarget::GetRuntimeInstallPath() const { - return impl->RuntimeInstallPath; + return this->impl->RuntimeInstallPath; } void cmTarget::SetRuntimeInstallPath(std::string const& name) { - impl->RuntimeInstallPath = name; + this->impl->RuntimeInstallPath = name; } bool cmTarget::GetHaveInstallRule() const { - return impl->HaveInstallRule; + return this->impl->HaveInstallRule; } void cmTarget::SetHaveInstallRule(bool hir) { - impl->HaveInstallRule = hir; + this->impl->HaveInstallRule = hir; } void cmTarget::AddInstallGenerator(cmInstallTargetGenerator* g) { - impl->InstallGenerators.emplace_back(g); + this->impl->InstallGenerators.emplace_back(g); } std::vector<cmInstallTargetGenerator*> const& cmTarget::GetInstallGenerators() const { - return impl->InstallGenerators; + return this->impl->InstallGenerators; } bool cmTarget::GetIsGeneratorProvided() const { - return impl->IsGeneratorProvided; + return this->impl->IsGeneratorProvided; } void cmTarget::SetIsGeneratorProvided(bool igp) { - impl->IsGeneratorProvided = igp; + this->impl->IsGeneratorProvided = igp; } cmTarget::LinkLibraryVectorType const& cmTarget::GetOriginalLinkLibraries() const { - return impl->OriginalLinkLibraries; + return this->impl->OriginalLinkLibraries; } void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, @@ -1002,11 +1018,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, (tgt && (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY || tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) || - (impl->Name == lib)) { + (this->impl->Name == lib)) { return; } - impl->OriginalLinkLibraries.emplace_back(lib, llt); + this->impl->OriginalLinkLibraries.emplace_back(lib, llt); // Add the explicit dependency information for libraries. This is // simply a set of libraries separated by ";". There should always @@ -1016,11 +1032,11 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, // may be purposefully duplicated to handle recursive dependencies, // and we removing one instance will break the link line. Duplicates // will be appropriately eliminated at emit time. - if (impl->TargetType >= cmStateEnums::STATIC_LIBRARY && - impl->TargetType <= cmStateEnums::MODULE_LIBRARY && + if (this->impl->TargetType >= cmStateEnums::STATIC_LIBRARY && + this->impl->TargetType <= cmStateEnums::MODULE_LIBRARY && (this->GetPolicyStatusCMP0073() == cmPolicies::OLD || this->GetPolicyStatusCMP0073() == cmPolicies::WARN)) { - std::string targetEntry = cmStrCat(impl->Name, "_LIB_DEPENDS"); + std::string targetEntry = cmStrCat(this->impl->Name, "_LIB_DEPENDS"); std::string dependencies; cmProp old_val = mf.GetDefinition(targetEntry); if (old_val) { @@ -1047,102 +1063,102 @@ void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib, void cmTarget::AddSystemIncludeDirectories(const std::set<std::string>& incs) { - impl->SystemIncludeDirectories.insert(incs.begin(), incs.end()); + this->impl->SystemIncludeDirectories.insert(incs.begin(), incs.end()); } std::set<std::string> const& cmTarget::GetSystemIncludeDirectories() const { - return impl->SystemIncludeDirectories; + return this->impl->SystemIncludeDirectories; } cmStringRange cmTarget::GetIncludeDirectoriesEntries() const { - return cmMakeRange(impl->IncludeDirectoriesEntries); + return cmMakeRange(this->impl->IncludeDirectoriesEntries); } cmBacktraceRange cmTarget::GetIncludeDirectoriesBacktraces() const { - return cmMakeRange(impl->IncludeDirectoriesBacktraces); + return cmMakeRange(this->impl->IncludeDirectoriesBacktraces); } cmStringRange cmTarget::GetCompileOptionsEntries() const { - return cmMakeRange(impl->CompileOptionsEntries); + return cmMakeRange(this->impl->CompileOptionsEntries); } cmBacktraceRange cmTarget::GetCompileOptionsBacktraces() const { - return cmMakeRange(impl->CompileOptionsBacktraces); + return cmMakeRange(this->impl->CompileOptionsBacktraces); } cmStringRange cmTarget::GetCompileFeaturesEntries() const { - return cmMakeRange(impl->CompileFeaturesEntries); + return cmMakeRange(this->impl->CompileFeaturesEntries); } cmBacktraceRange cmTarget::GetCompileFeaturesBacktraces() const { - return cmMakeRange(impl->CompileFeaturesBacktraces); + return cmMakeRange(this->impl->CompileFeaturesBacktraces); } cmStringRange cmTarget::GetCompileDefinitionsEntries() const { - return cmMakeRange(impl->CompileDefinitionsEntries); + return cmMakeRange(this->impl->CompileDefinitionsEntries); } cmBacktraceRange cmTarget::GetCompileDefinitionsBacktraces() const { - return cmMakeRange(impl->CompileDefinitionsBacktraces); + return cmMakeRange(this->impl->CompileDefinitionsBacktraces); } cmStringRange cmTarget::GetPrecompileHeadersEntries() const { - return cmMakeRange(impl->PrecompileHeadersEntries); + return cmMakeRange(this->impl->PrecompileHeadersEntries); } cmBacktraceRange cmTarget::GetPrecompileHeadersBacktraces() const { - return cmMakeRange(impl->PrecompileHeadersBacktraces); + return cmMakeRange(this->impl->PrecompileHeadersBacktraces); } cmStringRange cmTarget::GetSourceEntries() const { - return cmMakeRange(impl->SourceEntries); + return cmMakeRange(this->impl->SourceEntries); } cmBacktraceRange cmTarget::GetSourceBacktraces() const { - return cmMakeRange(impl->SourceBacktraces); + return cmMakeRange(this->impl->SourceBacktraces); } cmStringRange cmTarget::GetLinkOptionsEntries() const { - return cmMakeRange(impl->LinkOptionsEntries); + return cmMakeRange(this->impl->LinkOptionsEntries); } cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const { - return cmMakeRange(impl->LinkOptionsBacktraces); + return cmMakeRange(this->impl->LinkOptionsBacktraces); } cmStringRange cmTarget::GetLinkDirectoriesEntries() const { - return cmMakeRange(impl->LinkDirectoriesEntries); + return cmMakeRange(this->impl->LinkDirectoriesEntries); } cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const { - return cmMakeRange(impl->LinkDirectoriesBacktraces); + return cmMakeRange(this->impl->LinkDirectoriesBacktraces); } cmStringRange cmTarget::GetLinkImplementationEntries() const { - return cmMakeRange(impl->LinkImplementationPropertyEntries); + return cmMakeRange(this->impl->LinkImplementationPropertyEntries); } cmBacktraceRange cmTarget::GetLinkImplementationBacktraces() const { - return cmMakeRange(impl->LinkImplementationPropertyBacktraces); + return cmMakeRange(this->impl->LinkImplementationPropertyBacktraces); } void cmTarget::SetProperty(const std::string& prop, const char* value) @@ -1171,154 +1187,154 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) MAKE_STATIC_PROP(TYPE); #undef MAKE_STATIC_PROP if (prop == propMANUALLY_ADDED_DEPENDENCIES) { - impl->Makefile->IssueMessage( + this->impl->Makefile->IssueMessage( MessageType::FATAL_ERROR, "MANUALLY_ADDED_DEPENDENCIES property is read-only\n"); return; } if (prop == propNAME) { - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "NAME property is read-only\n"); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "NAME property is read-only\n"); return; } if (prop == propTYPE) { - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "TYPE property is read-only\n"); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "TYPE property is read-only\n"); return; } if (prop == propEXPORT_NAME && this->IsImported()) { std::ostringstream e; e << "EXPORT_NAME property can't be set on imported targets (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (prop == propSOURCES && this->IsImported()) { std::ostringstream e; - e << "SOURCES property can't be set on imported targets (\"" << impl->Name - << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + e << "SOURCES property can't be set on imported targets (\"" + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (prop == propIMPORTED_GLOBAL && !this->IsImported()) { std::ostringstream e; e << "IMPORTED_GLOBAL property can't be set on non-imported targets (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (prop == propINCLUDE_DIRECTORIES) { - impl->IncludeDirectoriesEntries.clear(); - impl->IncludeDirectoriesBacktraces.clear(); + this->impl->IncludeDirectoriesEntries.clear(); + this->impl->IncludeDirectoriesBacktraces.clear(); if (value) { - impl->IncludeDirectoriesEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->IncludeDirectoriesBacktraces.push_back(lfbt); + this->impl->IncludeDirectoriesEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->IncludeDirectoriesBacktraces.push_back(lfbt); } } else if (prop == propCOMPILE_OPTIONS) { - impl->CompileOptionsEntries.clear(); - impl->CompileOptionsBacktraces.clear(); + this->impl->CompileOptionsEntries.clear(); + this->impl->CompileOptionsBacktraces.clear(); if (value) { - impl->CompileOptionsEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->CompileOptionsBacktraces.push_back(lfbt); + this->impl->CompileOptionsEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->CompileOptionsBacktraces.push_back(lfbt); } } else if (prop == propCOMPILE_FEATURES) { - impl->CompileFeaturesEntries.clear(); - impl->CompileFeaturesBacktraces.clear(); + this->impl->CompileFeaturesEntries.clear(); + this->impl->CompileFeaturesBacktraces.clear(); if (value) { - impl->CompileFeaturesEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->CompileFeaturesBacktraces.push_back(lfbt); + this->impl->CompileFeaturesEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->CompileFeaturesBacktraces.push_back(lfbt); } } else if (prop == propCOMPILE_DEFINITIONS) { - impl->CompileDefinitionsEntries.clear(); - impl->CompileDefinitionsBacktraces.clear(); + this->impl->CompileDefinitionsEntries.clear(); + this->impl->CompileDefinitionsBacktraces.clear(); if (value) { - impl->CompileDefinitionsEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->CompileDefinitionsBacktraces.push_back(lfbt); + this->impl->CompileDefinitionsEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->CompileDefinitionsBacktraces.push_back(lfbt); } } else if (prop == propLINK_OPTIONS) { - impl->LinkOptionsEntries.clear(); - impl->LinkOptionsBacktraces.clear(); + this->impl->LinkOptionsEntries.clear(); + this->impl->LinkOptionsBacktraces.clear(); if (value) { - impl->LinkOptionsEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->LinkOptionsBacktraces.push_back(lfbt); + this->impl->LinkOptionsEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkOptionsBacktraces.push_back(lfbt); } } else if (prop == propLINK_DIRECTORIES) { - impl->LinkDirectoriesEntries.clear(); - impl->LinkDirectoriesBacktraces.clear(); + this->impl->LinkDirectoriesEntries.clear(); + this->impl->LinkDirectoriesBacktraces.clear(); if (value) { - impl->LinkDirectoriesEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->LinkDirectoriesBacktraces.push_back(lfbt); + this->impl->LinkDirectoriesEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkDirectoriesBacktraces.push_back(lfbt); } } else if (prop == propPRECOMPILE_HEADERS) { - impl->PrecompileHeadersEntries.clear(); - impl->PrecompileHeadersBacktraces.clear(); + this->impl->PrecompileHeadersEntries.clear(); + this->impl->PrecompileHeadersBacktraces.clear(); if (value) { - impl->PrecompileHeadersEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->PrecompileHeadersBacktraces.push_back(lfbt); + this->impl->PrecompileHeadersEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->PrecompileHeadersBacktraces.push_back(lfbt); } } else if (prop == propLINK_LIBRARIES) { - impl->LinkImplementationPropertyEntries.clear(); - impl->LinkImplementationPropertyBacktraces.clear(); + this->impl->LinkImplementationPropertyEntries.clear(); + this->impl->LinkImplementationPropertyBacktraces.clear(); if (value) { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->LinkImplementationPropertyEntries.emplace_back(value); - impl->LinkImplementationPropertyBacktraces.push_back(lfbt); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkImplementationPropertyEntries.emplace_back(value); + this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt); } } else if (prop == propSOURCES) { - impl->SourceEntries.clear(); - impl->SourceBacktraces.clear(); + this->impl->SourceEntries.clear(); + this->impl->SourceBacktraces.clear(); if (value) { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->SourceEntries.emplace_back(value); - impl->SourceBacktraces.push_back(lfbt); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->SourceEntries.emplace_back(value); + this->impl->SourceBacktraces.push_back(lfbt); } } else if (prop == propIMPORTED_GLOBAL) { if (!cmIsOn(value)) { std::ostringstream e; e << "IMPORTED_GLOBAL property can't be set to FALSE on targets (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } /* no need to change anything if value does not change */ - if (!impl->ImportedGloballyVisible) { - impl->ImportedGloballyVisible = true; + if (!this->impl->ImportedGloballyVisible) { + this->impl->ImportedGloballyVisible = true; this->GetGlobalGenerator()->IndexTarget(this); } } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME") && - !impl->CheckImportedLibName(prop, value ? value : "")) { + !this->impl->CheckImportedLibName(prop, value ? value : "")) { /* error was reported by check method */ } else if (prop == propCUDA_PTX_COMPILATION && this->GetType() != cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT " "targets (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) { if (this->GetProperty("PRECOMPILE_HEADERS")) { std::ostringstream e; e << "PRECOMPILE_HEADERS property is already set on target (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } - auto reusedTarget = - impl->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget( - value); + auto reusedTarget = this->impl->Makefile->GetCMakeInstance() + ->GetGlobalGenerator() + ->FindTarget(value); if (!reusedTarget) { const std::string e( "PRECOMPILE_HEADERS_REUSE_FROM set with non existing target"); - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e); return; } @@ -1327,7 +1343,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) reusedFrom = value; } - impl->Properties.SetProperty(prop, reusedFrom.c_str()); + this->impl->Properties.SetProperty(prop, reusedFrom.c_str()); reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom); reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY", @@ -1335,18 +1351,18 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) cmProp tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME"); this->SetProperty("COMPILE_PDB_NAME", cmToCStr(tmp)); - this->AddUtility(reusedFrom, false, impl->Makefile); + this->AddUtility(reusedFrom, false, this->impl->Makefile); } else if (prop == propC_STANDARD || prop == propCXX_STANDARD || prop == propCUDA_STANDARD || prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) { if (value) { - impl->LanguageStandardProperties[prop] = - BTs<std::string>(value, impl->Makefile->GetBacktrace()); + this->impl->LanguageStandardProperties[prop] = + BTs<std::string>(value, this->impl->Makefile->GetBacktrace()); } else { - impl->LanguageStandardProperties.erase(prop); + this->impl->LanguageStandardProperties.erase(prop); } } else { - impl->Properties.SetProperty(prop, value); + this->impl->Properties.SetProperty(prop, value); } } @@ -1354,102 +1370,102 @@ void cmTarget::AppendProperty(const std::string& prop, const std::string& value, bool asString) { if (prop == "NAME") { - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - "NAME property is read-only\n"); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "NAME property is read-only\n"); return; } if (prop == "EXPORT_NAME" && this->IsImported()) { std::ostringstream e; e << "EXPORT_NAME property can't be set on imported targets (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (prop == "SOURCES" && this->IsImported()) { std::ostringstream e; - e << "SOURCES property can't be set on imported targets (\"" << impl->Name - << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + e << "SOURCES property can't be set on imported targets (\"" + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (prop == "IMPORTED_GLOBAL") { std::ostringstream e; e << "IMPORTED_GLOBAL property can't be appended, only set on imported " "targets (\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (prop == "INCLUDE_DIRECTORIES") { if (!value.empty()) { - impl->IncludeDirectoriesEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->IncludeDirectoriesBacktraces.push_back(lfbt); + this->impl->IncludeDirectoriesEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->IncludeDirectoriesBacktraces.push_back(lfbt); } } else if (prop == "COMPILE_OPTIONS") { if (!value.empty()) { - impl->CompileOptionsEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->CompileOptionsBacktraces.push_back(lfbt); + this->impl->CompileOptionsEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->CompileOptionsBacktraces.push_back(lfbt); } } else if (prop == "COMPILE_FEATURES") { if (!value.empty()) { - impl->CompileFeaturesEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->CompileFeaturesBacktraces.push_back(lfbt); + this->impl->CompileFeaturesEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->CompileFeaturesBacktraces.push_back(lfbt); } } else if (prop == "COMPILE_DEFINITIONS") { if (!value.empty()) { - impl->CompileDefinitionsEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->CompileDefinitionsBacktraces.push_back(lfbt); + this->impl->CompileDefinitionsEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->CompileDefinitionsBacktraces.push_back(lfbt); } } else if (prop == "LINK_OPTIONS") { if (!value.empty()) { - impl->LinkOptionsEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->LinkOptionsBacktraces.push_back(lfbt); + this->impl->LinkOptionsEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkOptionsBacktraces.push_back(lfbt); } } else if (prop == "LINK_DIRECTORIES") { if (!value.empty()) { - impl->LinkDirectoriesEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->LinkDirectoriesBacktraces.push_back(lfbt); + this->impl->LinkDirectoriesEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkDirectoriesBacktraces.push_back(lfbt); } } else if (prop == "PRECOMPILE_HEADERS") { if (this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) { std::ostringstream e; e << "PRECOMPILE_HEADERS_REUSE_FROM property is already set on target " "(\"" - << impl->Name << "\")\n"; - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + << this->impl->Name << "\")\n"; + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); return; } if (!value.empty()) { - impl->PrecompileHeadersEntries.emplace_back(value); - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->PrecompileHeadersBacktraces.push_back(lfbt); + this->impl->PrecompileHeadersEntries.emplace_back(value); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->PrecompileHeadersBacktraces.push_back(lfbt); } } else if (prop == "LINK_LIBRARIES") { if (!value.empty()) { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->LinkImplementationPropertyEntries.emplace_back(value); - impl->LinkImplementationPropertyBacktraces.push_back(lfbt); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkImplementationPropertyEntries.emplace_back(value); + this->impl->LinkImplementationPropertyBacktraces.push_back(lfbt); } } else if (prop == "SOURCES") { - cmListFileBacktrace lfbt = impl->Makefile->GetBacktrace(); - impl->SourceEntries.emplace_back(value); - impl->SourceBacktraces.push_back(lfbt); + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->SourceEntries.emplace_back(value); + this->impl->SourceBacktraces.push_back(lfbt); } else if (cmHasLiteralPrefix(prop, "IMPORTED_LIBNAME")) { - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - prop + " property may not be APPENDed."); + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, prop + " property may not be APPENDed."); } else if (prop == "C_STANDARD" || prop == "CXX_STANDARD" || prop == "CUDA_STANDARD" || prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") { - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, - prop + " property may not be appended."); + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, prop + " property may not be appended."); } else { - impl->Properties.AppendProperty(prop, value, asString); + this->impl->Properties.AppendProperty(prop, value, asString); } } @@ -1462,17 +1478,17 @@ void cmTarget::AppendBuildInterfaceIncludes() !this->IsExecutableWithExports()) { return; } - if (impl->BuildInterfaceIncludesAppended) { + if (this->impl->BuildInterfaceIncludesAppended) { return; } - impl->BuildInterfaceIncludesAppended = true; + this->impl->BuildInterfaceIncludesAppended = true; - if (impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) { - std::string dirs = impl->Makefile->GetCurrentBinaryDirectory(); + if (this->impl->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")) { + std::string dirs = this->impl->Makefile->GetCurrentBinaryDirectory(); if (!dirs.empty()) { dirs += ';'; } - dirs += impl->Makefile->GetCurrentSourceDirectory(); + dirs += this->impl->Makefile->GetCurrentSourceDirectory(); if (!dirs.empty()) { this->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", ("$<BUILD_INTERFACE:" + dirs + ">")); @@ -1483,67 +1499,67 @@ void cmTarget::AppendBuildInterfaceIncludes() void cmTarget::InsertInclude(std::string const& entry, cmListFileBacktrace const& bt, bool before) { - auto position = before ? impl->IncludeDirectoriesEntries.begin() - : impl->IncludeDirectoriesEntries.end(); + auto position = before ? this->impl->IncludeDirectoriesEntries.begin() + : this->impl->IncludeDirectoriesEntries.end(); - auto btPosition = before ? impl->IncludeDirectoriesBacktraces.begin() - : impl->IncludeDirectoriesBacktraces.end(); + auto btPosition = before ? this->impl->IncludeDirectoriesBacktraces.begin() + : this->impl->IncludeDirectoriesBacktraces.end(); - impl->IncludeDirectoriesEntries.insert(position, entry); - impl->IncludeDirectoriesBacktraces.insert(btPosition, bt); + this->impl->IncludeDirectoriesEntries.insert(position, entry); + this->impl->IncludeDirectoriesBacktraces.insert(btPosition, bt); } void cmTarget::InsertCompileOption(std::string const& entry, cmListFileBacktrace const& bt, bool before) { - auto position = before ? impl->CompileOptionsEntries.begin() - : impl->CompileOptionsEntries.end(); + auto position = before ? this->impl->CompileOptionsEntries.begin() + : this->impl->CompileOptionsEntries.end(); - auto btPosition = before ? impl->CompileOptionsBacktraces.begin() - : impl->CompileOptionsBacktraces.end(); + auto btPosition = before ? this->impl->CompileOptionsBacktraces.begin() + : this->impl->CompileOptionsBacktraces.end(); - impl->CompileOptionsEntries.insert(position, entry); - impl->CompileOptionsBacktraces.insert(btPosition, bt); + this->impl->CompileOptionsEntries.insert(position, entry); + this->impl->CompileOptionsBacktraces.insert(btPosition, bt); } void cmTarget::InsertCompileDefinition(std::string const& entry, cmListFileBacktrace const& bt) { - impl->CompileDefinitionsEntries.push_back(entry); - impl->CompileDefinitionsBacktraces.push_back(bt); + this->impl->CompileDefinitionsEntries.push_back(entry); + this->impl->CompileDefinitionsBacktraces.push_back(bt); } void cmTarget::InsertLinkOption(std::string const& entry, cmListFileBacktrace const& bt, bool before) { - auto position = - before ? impl->LinkOptionsEntries.begin() : impl->LinkOptionsEntries.end(); + auto position = before ? this->impl->LinkOptionsEntries.begin() + : this->impl->LinkOptionsEntries.end(); - auto btPosition = before ? impl->LinkOptionsBacktraces.begin() - : impl->LinkOptionsBacktraces.end(); + auto btPosition = before ? this->impl->LinkOptionsBacktraces.begin() + : this->impl->LinkOptionsBacktraces.end(); - impl->LinkOptionsEntries.insert(position, entry); - impl->LinkOptionsBacktraces.insert(btPosition, bt); + this->impl->LinkOptionsEntries.insert(position, entry); + this->impl->LinkOptionsBacktraces.insert(btPosition, bt); } void cmTarget::InsertLinkDirectory(std::string const& entry, cmListFileBacktrace const& bt, bool before) { - auto position = before ? impl->LinkDirectoriesEntries.begin() - : impl->LinkDirectoriesEntries.end(); + auto position = before ? this->impl->LinkDirectoriesEntries.begin() + : this->impl->LinkDirectoriesEntries.end(); - auto btPosition = before ? impl->LinkDirectoriesBacktraces.begin() - : impl->LinkDirectoriesBacktraces.end(); + auto btPosition = before ? this->impl->LinkDirectoriesBacktraces.begin() + : this->impl->LinkDirectoriesBacktraces.end(); - impl->LinkDirectoriesEntries.insert(position, entry); - impl->LinkDirectoriesBacktraces.insert(btPosition, bt); + this->impl->LinkDirectoriesEntries.insert(position, entry); + this->impl->LinkDirectoriesBacktraces.insert(btPosition, bt); } void cmTarget::InsertPrecompileHeader(std::string const& entry, cmListFileBacktrace const& bt) { - impl->PrecompileHeadersEntries.push_back(entry); - impl->PrecompileHeadersBacktraces.push_back(bt); + this->impl->PrecompileHeadersEntries.push_back(entry); + this->impl->PrecompileHeadersBacktraces.push_back(bt); } static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop, @@ -1712,19 +1728,19 @@ cmProp cmTarget::GetProperty(const std::string& prop) const if (prop == propC_STANDARD || prop == propCXX_STANDARD || prop == propCUDA_STANDARD || prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) { - auto propertyIter = impl->LanguageStandardProperties.find(prop); - if (propertyIter == impl->LanguageStandardProperties.end()) { + auto propertyIter = this->impl->LanguageStandardProperties.find(prop); + if (propertyIter == this->impl->LanguageStandardProperties.end()) { return nullptr; } return &(propertyIter->second.Value); } if (prop == propLINK_LIBRARIES) { - if (impl->LinkImplementationPropertyEntries.empty()) { + if (this->impl->LinkImplementationPropertyEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->LinkImplementationPropertyEntries, ";"); + output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";"); return &output; } // the type property returns what type the target is @@ -1732,70 +1748,71 @@ cmProp cmTarget::GetProperty(const std::string& prop) const return &cmState::GetTargetTypeName(this->GetType()); } if (prop == propINCLUDE_DIRECTORIES) { - if (impl->IncludeDirectoriesEntries.empty()) { + if (this->impl->IncludeDirectoriesEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->IncludeDirectoriesEntries, ";"); + output = cmJoin(this->impl->IncludeDirectoriesEntries, ";"); return &output; } if (prop == propCOMPILE_FEATURES) { - if (impl->CompileFeaturesEntries.empty()) { + if (this->impl->CompileFeaturesEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->CompileFeaturesEntries, ";"); + output = cmJoin(this->impl->CompileFeaturesEntries, ";"); return &output; } if (prop == propCOMPILE_OPTIONS) { - if (impl->CompileOptionsEntries.empty()) { + if (this->impl->CompileOptionsEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->CompileOptionsEntries, ";"); + output = cmJoin(this->impl->CompileOptionsEntries, ";"); return &output; } if (prop == propCOMPILE_DEFINITIONS) { - if (impl->CompileDefinitionsEntries.empty()) { + if (this->impl->CompileDefinitionsEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->CompileDefinitionsEntries, ";"); + output = cmJoin(this->impl->CompileDefinitionsEntries, ";"); return &output; } if (prop == propLINK_OPTIONS) { - if (impl->LinkOptionsEntries.empty()) { + if (this->impl->LinkOptionsEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->LinkOptionsEntries, ";"); + output = cmJoin(this->impl->LinkOptionsEntries, ";"); return &output; } if (prop == propLINK_DIRECTORIES) { - if (impl->LinkDirectoriesEntries.empty()) { + if (this->impl->LinkDirectoriesEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->LinkDirectoriesEntries, ";"); + output = cmJoin(this->impl->LinkDirectoriesEntries, ";"); return &output; } if (prop == propMANUALLY_ADDED_DEPENDENCIES) { - if (impl->Utilities.empty()) { + if (this->impl->Utilities.empty()) { return nullptr; } static std::string output; static std::vector<std::string> utilities; - utilities.resize(impl->Utilities.size()); + utilities.resize(this->impl->Utilities.size()); std::transform( - impl->Utilities.cbegin(), impl->Utilities.cend(), utilities.begin(), + this->impl->Utilities.cbegin(), this->impl->Utilities.cend(), + utilities.begin(), [](const BT<std::pair<std::string, bool>>& item) -> std::string { return item.Value.first; }); @@ -1803,12 +1820,12 @@ cmProp cmTarget::GetProperty(const std::string& prop) const return &output; } if (prop == propPRECOMPILE_HEADERS) { - if (impl->PrecompileHeadersEntries.empty()) { + if (this->impl->PrecompileHeadersEntries.empty()) { return nullptr; } static std::string output; - output = cmJoin(impl->PrecompileHeadersEntries, ";"); + output = cmJoin(this->impl->PrecompileHeadersEntries, ";"); return &output; } if (prop == propIMPORTED) { @@ -1821,24 +1838,25 @@ cmProp cmTarget::GetProperty(const std::string& prop) const return &this->GetName(); } if (prop == propBINARY_DIR) { - return &impl->Makefile->GetStateSnapshot() + return &this->impl->Makefile->GetStateSnapshot() .GetDirectory() .GetCurrentBinary(); } if (prop == propSOURCE_DIR) { - return &impl->Makefile->GetStateSnapshot() + return &this->impl->Makefile->GetStateSnapshot() .GetDirectory() .GetCurrentSource(); } } - cmProp retVal = impl->Properties.GetPropertyValue(prop); + cmProp retVal = this->impl->Properties.GetPropertyValue(prop); if (!retVal) { - const bool chain = - impl->Makefile->GetState()->IsPropertyChained(prop, cmProperty::TARGET); + const bool chain = this->impl->Makefile->GetState()->IsPropertyChained( + prop, cmProperty::TARGET); if (chain) { - return impl->Makefile->GetStateSnapshot().GetDirectory().GetProperty( - prop, chain); + return this->impl->Makefile->GetStateSnapshot() + .GetDirectory() + .GetProperty(prop, chain); } return nullptr; } @@ -1863,32 +1881,32 @@ bool cmTarget::GetPropertyAsBool(const std::string& prop) const cmPropertyMap const& cmTarget::GetProperties() const { - return impl->Properties; + return this->impl->Properties; } bool cmTarget::IsDLLPlatform() const { - return impl->IsDLLPlatform; + return this->impl->IsDLLPlatform; } bool cmTarget::IsAIX() const { - return impl->IsAIX; + return this->impl->IsAIX; } bool cmTarget::IsImported() const { - return impl->IsImportedTarget; + return this->impl->IsImportedTarget; } bool cmTarget::IsImportedGloballyVisible() const { - return impl->ImportedGloballyVisible; + return this->impl->ImportedGloballyVisible; } bool cmTarget::IsPerConfig() const { - return impl->PerConfig; + return this->impl->PerConfig; } bool cmTarget::CanCompileSources() const @@ -1943,8 +1961,8 @@ const char* cmTarget::GetSuffixVariableInternal( ? "CMAKE_SHARED_LIBRARY_SUFFIX" : "CMAKE_EXECUTABLE_SUFFIX"); case cmStateEnums::ImportLibraryArtifact: - return (impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX" - : "CMAKE_IMPORT_LIBRARY_SUFFIX"); + return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_SUFFIX" + : "CMAKE_IMPORT_LIBRARY_SUFFIX"); } break; default: @@ -1984,8 +2002,8 @@ const char* cmTarget::GetPrefixVariableInternal( ? "CMAKE_SHARED_LIBRARY_PREFIX" : ""); case cmStateEnums::ImportLibraryArtifact: - return (impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX" - : "CMAKE_IMPORT_LIBRARY_PREFIX"); + return (this->impl->IsAIX ? "CMAKE_AIX_IMPORT_FILE_PREFIX" + : "CMAKE_IMPORT_LIBRARY_PREFIX"); } break; default: @@ -2067,7 +2085,7 @@ std::string cmTarget::ImportedGetFullPath( switch (this->GetPolicyStatus(cmPolicies::CMP0111)) { case cmPolicies::WARN: - impl->Makefile->IssueMessage( + this->impl->Makefile->IssueMessage( MessageType::AUTHOR_WARNING, cmPolicies::GetPolicyWarning(cmPolicies::CMP0111) + "\n" + message()); @@ -2075,7 +2093,8 @@ std::string cmTarget::ImportedGetFullPath( case cmPolicies::OLD: break; default: - impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, message()); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + message()); } } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index d8f66bc..3066eb2 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -114,7 +114,7 @@ public: LinkLibraryVectorType const& GetOriginalLinkLibraries() const; //! Clear the dependency information recorded for this target, if any. - void ClearDependencyInformation(cmMakefile& mf); + void ClearDependencyInformation(cmMakefile& mf) const; void AddLinkLibrary(cmMakefile& mf, std::string const& lib, cmTargetLinkLibraryType llt); @@ -164,6 +164,7 @@ public: */ void AddUtility(std::string const& name, bool cross, cmMakefile* mf = nullptr); + void AddUtility(BT<std::pair<std::string, bool>> util); //! Get the utilities used by this target std::set<BT<std::pair<std::string, bool>>> const& GetUtilities() const; @@ -171,7 +172,7 @@ public: void SetProperty(const std::string& prop, const char* value); void SetProperty(const std::string& prop, const std::string& value) { - SetProperty(prop, value.c_str()); + this->SetProperty(prop, value.c_str()); } void AppendProperty(const std::string& prop, const std::string& value, bool asString = false); diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index 35635b9..3897499 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -84,8 +84,8 @@ void TargetIncludeDirectoriesImpl::HandleInterfaceContent( cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool system) { - cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend, - system); + this->cmTargetPropCommandBase::HandleInterfaceContent(tgt, content, prepend, + system); if (system) { std::string joined = this->Join(content); tgt->AppendProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", joined); @@ -101,5 +101,6 @@ bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args, args, "INCLUDE_DIRECTORIES", TargetIncludeDirectoriesImpl::ArgumentFlags( TargetIncludeDirectoriesImpl::PROCESS_BEFORE | + TargetIncludeDirectoriesImpl::PROCESS_AFTER | TargetIncludeDirectoriesImpl::PROCESS_SYSTEM)); } diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx index 0670bd9..a5066cc 100644 --- a/Source/cmTargetPrecompileHeadersCommand.cxx +++ b/Source/cmTargetPrecompileHeadersCommand.cxx @@ -57,7 +57,7 @@ private: bool prepend, bool system) override { std::string const& base = this->Makefile->GetCurrentSourceDirectory(); - cmTargetPropCommandBase::HandleInterfaceContent( + this->cmTargetPropCommandBase::HandleInterfaceContent( tgt, ConvertToAbsoluteContent(content, base), prepend, system); } diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 9e30136..e41714a 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -45,15 +45,26 @@ bool cmTargetPropCommandBase::HandleArguments( this->HandleMissingTarget(args[0]); return false; } - if ((this->Target->GetType() != cmStateEnums::EXECUTABLE) && - (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) && - (this->Target->GetType() != cmStateEnums::SHARED_LIBRARY) && - (this->Target->GetType() != cmStateEnums::MODULE_LIBRARY) && - (this->Target->GetType() != cmStateEnums::OBJECT_LIBRARY) && - (this->Target->GetType() != cmStateEnums::INTERFACE_LIBRARY) && - (this->Target->GetType() != cmStateEnums::UNKNOWN_LIBRARY)) { - this->SetError("called with non-compilable target type"); - return false; + const bool isRegularTarget = + (this->Target->GetType() == cmStateEnums::EXECUTABLE) || + (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) || + (this->Target->GetType() == cmStateEnums::SHARED_LIBRARY) || + (this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) || + (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) || + (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) || + (this->Target->GetType() == cmStateEnums::UNKNOWN_LIBRARY); + const bool isCustomTarget = this->Target->GetType() == cmStateEnums::UTILITY; + + if (prop == "SOURCES") { + if (!isRegularTarget && !isCustomTarget) { + this->SetError("called with non-compilable target type"); + return false; + } + } else { + if (!isRegularTarget) { + this->SetError("called with non-compilable target type"); + return false; + } } bool system = false; @@ -76,6 +87,13 @@ bool cmTargetPropCommandBase::HandleArguments( } prepend = true; ++argIndex; + } else if ((flags & PROCESS_AFTER) && args[argIndex] == "AFTER") { + if (args.size() < 3) { + this->SetError("called with incorrect number of arguments"); + return false; + } + prepend = false; + ++argIndex; } if ((flags & PROCESS_REUSE_FROM) && args[argIndex] == "REUSE_FROM") { @@ -131,6 +149,11 @@ bool cmTargetPropCommandBase::ProcessContentArgs( this->SetError("may only set INTERFACE properties on IMPORTED targets"); return false; } + if (this->Target->GetType() == cmStateEnums::UTILITY && + scope != "PRIVATE") { + this->SetError("may only set PRIVATE properties on custom targets"); + return false; + } } return this->PopulateTargetProperies(scope, content, prepend, system); } diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index 50ac1aa..fc24fe8 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -23,8 +23,9 @@ public: { NO_FLAGS = 0x0, PROCESS_BEFORE = 0x1, - PROCESS_SYSTEM = 0x2, - PROCESS_REUSE_FROM = 0x3 + PROCESS_AFTER = 0x2, + PROCESS_SYSTEM = 0x3, + PROCESS_REUSE_FROM = 0x4 }; bool HandleArguments(std::vector<std::string> const& args, diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index a1fbc9b..26282ef 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -25,8 +25,9 @@ protected: const std::vector<std::string>& content, bool prepend, bool system) override { - cmTargetPropCommandBase::HandleInterfaceContent( - tgt, ConvertToAbsoluteContent(tgt, content, true), prepend, system); + this->cmTargetPropCommandBase::HandleInterfaceContent( + tgt, this->ConvertToAbsoluteContent(tgt, content, true), prepend, + system); } private: @@ -43,7 +44,8 @@ private: bool /*prepend*/, bool /*system*/) override { tgt->AppendProperty( - "SOURCES", this->Join(ConvertToAbsoluteContent(tgt, content, false))); + "SOURCES", + this->Join(this->ConvertToAbsoluteContent(tgt, content, false))); return true; // Successfully handled. } diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index da4593f..7022c4e 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -147,7 +147,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, // Evaluate command line arguments std::vector<std::string> argv = - EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config); + this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config); // Expand arguments if COMMAND_EXPAND_LISTS is set if (this->Test->GetCommandExpandLists()) { diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 67f7e11..7fb69bf 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -38,7 +38,7 @@ std::string cmTimestamp::CurrentTime(const std::string& formatString, return std::string(); } - return CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); + return this->CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); } std::string cmTimestamp::FileModificationTime(const char* path, @@ -53,7 +53,7 @@ std::string cmTimestamp::FileModificationTime(const char* path, } time_t mtime = cmsys::SystemTools::ModifiedTime(real_path); - return CreateTimestampFromTimeT(mtime, formatString, utcFlag); + return this->CreateTimestampFromTimeT(mtime, formatString, utcFlag); } std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, @@ -90,7 +90,7 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, : static_cast<char>(0); if (c1 == '%' && c2 != 0) { - result += AddTimestampComponent(c2, timeStruct, timeT); + result += this->AddTimestampComponent(c2, timeStruct, timeT); ++i; } else { result += c1; diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx new file mode 100644 index 0000000..b91e1ce --- /dev/null +++ b/Source/cmTransformDepfile.cxx @@ -0,0 +1,101 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmTransformDepfile.h" + +#include <string> +#include <type_traits> +#include <utility> +#include <vector> + +#include <cm/optional> + +#include "cmsys/FStream.hxx" + +#include "cmGccDepfileReader.h" +#include "cmGccDepfileReaderTypes.h" +#include "cmSystemTools.h" + +namespace { +void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename) +{ + for (auto c : filename) { + switch (c) { + case ' ': + fout << "\\ "; + break; + case '\\': + fout << "\\\\"; + break; + default: + fout << c; + break; + } + } +} + +void WriteGccDepfile(cmsys::ofstream& fout, const cmGccDepfileContent& content) +{ + for (auto const& dep : content) { + bool first = true; + for (auto const& rule : dep.rules) { + if (!first) { + fout << " \\\n "; + } + first = false; + WriteFilenameGcc(fout, rule); + } + fout << ':'; + for (auto const& path : dep.paths) { + fout << " \\\n "; + WriteFilenameGcc(fout, path); + } + fout << '\n'; + } +} + +void WriteVsTlog(cmsys::ofstream& fout, const cmGccDepfileContent& content) +{ + for (auto const& dep : content) { + fout << '^'; + bool first = true; + for (auto const& rule : dep.rules) { + if (!first) { + fout << '|'; + } + first = false; + fout << cmSystemTools::ConvertToOutputPath(rule); + } + fout << "\r\n"; + for (auto const& path : dep.paths) { + fout << cmSystemTools::ConvertToOutputPath(path) << "\r\n"; + } + } +} +} + +bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix, + const std::string& infile, const std::string& outfile) +{ + cmGccDepfileContent content; + if (cmSystemTools::FileExists(infile)) { + auto result = cmReadGccDepfile(infile.c_str(), prefix); + if (!result) { + return false; + } + content = *std::move(result); + } + + cmsys::ofstream fout(outfile.c_str()); + if (!fout) { + return false; + } + switch (format) { + case cmDepfileFormat::GccDepfile: + WriteGccDepfile(fout, content); + break; + case cmDepfileFormat::VsTlog: + WriteVsTlog(fout, content); + break; + } + return true; +} diff --git a/Source/cmTransformDepfile.h b/Source/cmTransformDepfile.h new file mode 100644 index 0000000..792c1aa --- /dev/null +++ b/Source/cmTransformDepfile.h @@ -0,0 +1,14 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <string> + +enum class cmDepfileFormat +{ + GccDepfile, + VsTlog, +}; + +bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix, + const std::string& infile, const std::string& outfile); diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx index df2f64e..e556a11 100644 --- a/Source/cmUVHandlePtr.cxx +++ b/Source/cmUVHandlePtr.cxx @@ -80,7 +80,7 @@ struct uv_handle_deleter template <typename T> void uv_handle_ptr_base_<T>::allocate(void* data) { - reset(); + this->reset(); /* We use calloc since we know all these types are c structs @@ -88,32 +88,33 @@ void uv_handle_ptr_base_<T>::allocate(void* data) but casting from uv_handle_t to certain other types -- namely uv_timer_t -- triggers a cast_align warning on certain systems. */ - handle.reset(static_cast<T*>(calloc(1, sizeof(T))), uv_handle_deleter<T>()); - handle->data = data; + this->handle.reset(static_cast<T*>(calloc(1, sizeof(T))), + uv_handle_deleter<T>()); + this->handle->data = data; } template <typename T> void uv_handle_ptr_base_<T>::reset() { - handle.reset(); + this->handle.reset(); } template <typename T> uv_handle_ptr_base_<T>::operator uv_handle_t*() { - return reinterpret_cast<uv_handle_t*>(handle.get()); + return reinterpret_cast<uv_handle_t*>(this->handle.get()); } template <typename T> T* uv_handle_ptr_base_<T>::operator->() const noexcept { - return handle.get(); + return this->handle.get(); } template <typename T> T* uv_handle_ptr_base_<T>::get() const { - return handle.get(); + return this->handle.get(); } template <typename T> @@ -146,7 +147,7 @@ struct uv_handle_deleter<uv_async_t> void operator()(uv_async_t* handle) { - std::lock_guard<std::mutex> lock(*handleMutex); + std::lock_guard<std::mutex> lock(*this->handleMutex); handle_default_delete(handle); } }; @@ -164,8 +165,8 @@ void uv_async_ptr::send() int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data) { - allocate(data); - return uv_async_init(&loop, handle.get(), async_cb); + this->allocate(data); + return uv_async_init(&loop, this->handle.get(), async_cb); } #endif @@ -183,62 +184,62 @@ struct uv_handle_deleter<uv_signal_t> int uv_signal_ptr::init(uv_loop_t& loop, void* data) { - allocate(data); - return uv_signal_init(&loop, handle.get()); + this->allocate(data); + return uv_signal_init(&loop, this->handle.get()); } int uv_signal_ptr::start(uv_signal_cb cb, int signum) { - assert(handle); + assert(this->handle); return uv_signal_start(*this, cb, signum); } void uv_signal_ptr::stop() { - if (handle) { + if (this->handle) { uv_signal_stop(*this); } } int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data) { - allocate(data); + this->allocate(data); return uv_pipe_init(&loop, *this, ipc); } uv_pipe_ptr::operator uv_stream_t*() const { - return reinterpret_cast<uv_stream_t*>(handle.get()); + return reinterpret_cast<uv_stream_t*>(this->handle.get()); } int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options, void* data) { - allocate(data); + this->allocate(data); return uv_spawn(&loop, *this, &options); } int uv_timer_ptr::init(uv_loop_t& loop, void* data) { - allocate(data); + this->allocate(data); return uv_timer_init(&loop, *this); } int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) { - assert(handle); + assert(this->handle); return uv_timer_start(*this, cb, timeout, repeat); } #ifndef CMAKE_BOOTSTRAP uv_tty_ptr::operator uv_stream_t*() const { - return reinterpret_cast<uv_stream_t*>(handle.get()); + return reinterpret_cast<uv_stream_t*>(this->handle.get()); } int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data) { - allocate(data); + this->allocate(data); return uv_tty_init(&loop, *this, fd, readable); } #endif diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h index d9de7f3..356e227 100644 --- a/Source/cmUVHandlePtr.h +++ b/Source/cmUVHandlePtr.h @@ -128,7 +128,7 @@ public: // dtors to work. Some compilers do not like '= default' here. uv_handle_ptr_base_() {} // NOLINT(modernize-use-equals-default) uv_handle_ptr_base_(std::nullptr_t) {} - ~uv_handle_ptr_base_() { reset(); } + ~uv_handle_ptr_base_() { this->reset(); } /** * Properly close the handle if needed and sets the inner handle to nullptr diff --git a/Source/cmUuid.cxx b/Source/cmUuid.cxx index cd52b3f..2513303 100644 --- a/Source/cmUuid.cxx +++ b/Source/cmUuid.cxx @@ -82,7 +82,7 @@ bool cmUuid::StringToBinary(std::string const& input, return false; } size_t digits = kUuidGroups[i] * 2; - if (!StringToBinaryImpl(input.substr(index, digits), output)) { + if (!this->StringToBinaryImpl(input.substr(index, digits), output)) { return false; } @@ -134,12 +134,12 @@ bool cmUuid::StringToBinaryImpl(std::string const& input, for (size_t i = 0; i < input.size(); i += 2) { char c1 = 0; - if (!IntFromHexDigit(input[i], c1)) { + if (!this->IntFromHexDigit(input[i], c1)) { return false; } char c2 = 0; - if (!IntFromHexDigit(input[i + 1], c2)) { + if (!this->IntFromHexDigit(input[i + 1], c2)) { return false; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 4eb3b7f..a93a78a 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -676,7 +676,7 @@ void cmVisualStudio10TargetGenerator::Generate() cmStrCat(this->DefaultArtifactDir, "\\nasm.props"); ConvertToWindowsSlash(propsLocal); this->Makefile->ConfigureFile(propsTemplate, propsLocal, false, true, - true, true); + true); Elem(e1, "Import").Attribute("Project", propsLocal); } } @@ -1020,9 +1020,9 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) cm::string_view tagName = cm::string_view(p).substr(propNamePrefix.length()); if (!tagName.empty()) { - const std::string& value = *props.GetPropertyValue(p); - if (!value.empty()) { - e2.Element(tagName, value); + cmProp value = props.GetPropertyValue(p); + if (cmNonempty(value)) { + e2.Element(tagName, *value); } } } @@ -1897,8 +1897,15 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } // Figure out if there's any additional flags to use if (cmProp saf = sf->GetProperty("VS_SHADER_FLAGS")) { + cmGeneratorExpression ge; + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*saf); + for (const std::string& config : this->Configurations) { - toolSettings[config]["AdditionalOptions"] = *saf; + std::string evaluated = cge->Evaluate(this->LocalGenerator, config); + + if (!evaluated.empty()) { + toolSettings[config]["AdditionalOptions"] = evaluated; + } } } // Figure out if debug information should be generated @@ -2402,27 +2409,28 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( configDefines += *ccdefs; } - // Add precompile headers compile options. - std::string customAndPchOptions = options; + // We have pch state in the following situation: + // 1. We have SKIP_PRECOMPILE_HEADERS == true + // 2. We are creating the pre-compiled header + // 3. We are a different language than the linker language AND pch is + // enabled const std::string pchSource = this->GeneratorTarget->GetPchSource(config, lang); - if (!pchSource.empty() && !sf.GetProperty("SKIP_PRECOMPILE_HEADERS")) { - std::string pchOptions; - if (sf.GetFullPath() == pchSource) { - pchOptions = - this->GeneratorTarget->GetPchCreateCompileOptions(config, lang); - } else { - pchOptions = - this->GeneratorTarget->GetPchUseCompileOptions(config, lang); - } - customAndPchOptions = cmStrCat(customAndPchOptions, ';', pchOptions); - } + const bool skipPCH = + pchSource.empty() || sf.GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS"); + const bool makePCH = (sf.GetFullPath() == pchSource); + const bool useSharedPCH = + !skipPCH && (lang == this->GeneratorTarget->GetLinkerLanguage(config)); + const bool useDifferentLangPCH = + !skipPCH && (lang != this->GeneratorTarget->GetLinkerLanguage(config)); + const bool needsPCHFlags = + (makePCH || useSharedPCH || useDifferentLangPCH); // if we have flags or defines for this config then // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || - !includes.empty() || compileAs || noWinRT || - !customAndPchOptions.empty()) { + !includes.empty() || compileAs || noWinRT || !options.empty() || + needsPCHFlags) { cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); @@ -2455,15 +2463,35 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } else { clOptions.Parse(flags); } - if (!customAndPchOptions.empty()) { + + if (needsPCHFlags) { + // Add precompile headers compile options. + std::string expandedOptions; + std::string pchOptions; + if (makePCH) { + pchOptions = + this->GeneratorTarget->GetPchCreateCompileOptions(config, lang); + } else if (useSharedPCH) { + std::string pchHeader = + this->GeneratorTarget->GetPchHeader(config, lang); + clOptions.AddFlag("ForcedIncludeFiles", pchHeader); + } else if (useDifferentLangPCH) { + pchOptions = + this->GeneratorTarget->GetPchUseCompileOptions(config, lang); + } + this->LocalGenerator->AppendCompileOptions(expandedOptions, + pchOptions); + clOptions.Parse(expandedOptions); + } + + if (!options.empty()) { std::string expandedOptions; if (configDependentOptions) { this->LocalGenerator->AppendCompileOptions( expandedOptions, - genexInterpreter.Evaluate(customAndPchOptions, "COMPILE_OPTIONS")); + genexInterpreter.Evaluate(options, "COMPILE_OPTIONS")); } else { - this->LocalGenerator->AppendCompileOptions(expandedOptions, - customAndPchOptions); + this->LocalGenerator->AppendCompileOptions(expandedOptions, options); } clOptions.Parse(expandedOptions); } @@ -2786,6 +2814,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->GeneratorTarget->GetPchHeader(configName, linkLanguage); if (this->MSTools && vcxproj == this->ProjectType && pchHeader.empty()) { clOptions.AddFlag("PrecompiledHeader", "NotUsing"); + } else if (this->MSTools && vcxproj == this->ProjectType && + !pchHeader.empty()) { + clOptions.AddFlag("PrecompiledHeader", "Use"); + clOptions.AddFlag("PrecompiledHeaderFile", pchHeader); + std::string pchFile = + this->GeneratorTarget->GetPchFile(configName, linkLanguage); + clOptions.AddFlag("PrecompiledHeaderOutputFile", pchFile); } // Get preprocessor definitions for this directory. @@ -4183,8 +4218,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0) cmLocalGenerator* lg = dt->GetLocalGenerator(); std::string name = dt->GetName(); std::string path; - cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT"); - if (p) { + if (cmProp p = dt->GetProperty("EXTERNAL_MSPROJECT")) { path = *p; } else { path = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', dt->GetName(), @@ -4972,9 +5006,9 @@ void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties( if (cmHasPrefix(p, propNamePrefix)) { std::string tagName = p.substr(propNamePrefix.length()); if (!tagName.empty()) { - const std::string& val = *props.GetPropertyValue(p); - if (!val.empty()) { - tags[tagName] = val; + cmProp val = props.GetPropertyValue(p); + if (cmNonempty(val)) { + tags[tagName] = *val; } else { tags.erase(tagName); } diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx index 12aba4f..f2c091f 100644 --- a/Source/cmWorkerPool.cxx +++ b/Source/cmWorkerPool.cxx @@ -50,11 +50,14 @@ public: bool startRead(DataFunction dataFunction, EndFunction endFunction); //! libuv pipe - uv_pipe_t* uv_pipe() const { return UVPipe_.get(); } + uv_pipe_t* uv_pipe() const { return this->UVPipe_.get(); } //! uv_pipe() casted to libuv stream - uv_stream_t* uv_stream() const { return static_cast<uv_stream_t*>(UVPipe_); } + uv_stream_t* uv_stream() const + { + return static_cast<uv_stream_t*>(this->UVPipe_); + } //! uv_pipe() casted to libuv handle - uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(UVPipe_); } + uv_handle_t* uv_handle() { return static_cast<uv_handle_t*>(this->UVPipe_); } private: // -- Libuv callbacks @@ -71,37 +74,37 @@ private: void cmUVPipeBuffer::reset() { - if (UVPipe_.get() != nullptr) { - EndFunction_ = nullptr; - DataFunction_ = nullptr; - Buffer_.clear(); - Buffer_.shrink_to_fit(); - UVPipe_.reset(); + if (this->UVPipe_.get() != nullptr) { + this->EndFunction_ = nullptr; + this->DataFunction_ = nullptr; + this->Buffer_.clear(); + this->Buffer_.shrink_to_fit(); + this->UVPipe_.reset(); } } bool cmUVPipeBuffer::init(uv_loop_t* uv_loop) { - reset(); + this->reset(); if (uv_loop == nullptr) { return false; } - int ret = UVPipe_.init(*uv_loop, 0, this); + int ret = this->UVPipe_.init(*uv_loop, 0, this); return (ret == 0); } bool cmUVPipeBuffer::startRead(DataFunction dataFunction, EndFunction endFunction) { - if (UVPipe_.get() == nullptr) { + if (this->UVPipe_.get() == nullptr) { return false; } if (!dataFunction || !endFunction) { return false; } - DataFunction_ = std::move(dataFunction); - EndFunction_ = std::move(endFunction); - int ret = uv_read_start(uv_stream(), &cmUVPipeBuffer::UVAlloc, + this->DataFunction_ = std::move(dataFunction); + this->EndFunction_ = std::move(endFunction); + int ret = uv_read_start(this->uv_stream(), &cmUVPipeBuffer::UVAlloc, &cmUVPipeBuffer::UVData); return (ret == 0); } @@ -153,10 +156,10 @@ public: public: // -- Const accessors - SetupT const& Setup() const { return Setup_; } - cmWorkerPool::ProcessResultT* Result() const { return Setup_.Result; } - bool IsStarted() const { return IsStarted_; } - bool IsFinished() const { return IsFinished_; } + SetupT const& Setup() const { return this->Setup_; } + cmWorkerPool::ProcessResultT* Result() const { return this->Setup_.Result; } + bool IsStarted() const { return this->IsStarted_; } + bool IsFinished() const { return this->IsFinished_; } // -- Runtime void setup(cmWorkerPool::ProcessResultT* result, bool mergedOutput, @@ -193,109 +196,113 @@ void cmUVReadOnlyProcess::setup(cmWorkerPool::ProcessResultT* result, std::vector<std::string> const& command, std::string const& workingDirectory) { - Setup_.WorkingDirectory = workingDirectory; - Setup_.Command = command; - Setup_.Result = result; - Setup_.MergedOutput = mergedOutput; + this->Setup_.WorkingDirectory = workingDirectory; + this->Setup_.Command = command; + this->Setup_.Result = result; + this->Setup_.MergedOutput = mergedOutput; } bool cmUVReadOnlyProcess::start(uv_loop_t* uv_loop, std::function<void()> finishedCallback) { - if (IsStarted() || (Result() == nullptr)) { + if (this->IsStarted() || (this->Result() == nullptr)) { return false; } // Reset result before the start - Result()->reset(); + this->Result()->reset(); // Fill command string pointers - if (!Setup().Command.empty()) { - CommandPtr_.reserve(Setup().Command.size() + 1); - for (std::string const& arg : Setup().Command) { - CommandPtr_.push_back(arg.c_str()); + if (!this->Setup().Command.empty()) { + this->CommandPtr_.reserve(this->Setup().Command.size() + 1); + for (std::string const& arg : this->Setup().Command) { + this->CommandPtr_.push_back(arg.c_str()); } - CommandPtr_.push_back(nullptr); + this->CommandPtr_.push_back(nullptr); } else { - Result()->ErrorMessage = "Empty command"; + this->Result()->ErrorMessage = "Empty command"; } - if (!Result()->error()) { - if (!UVPipeOut_.init(uv_loop)) { - Result()->ErrorMessage = "libuv stdout pipe initialization failed"; + if (!this->Result()->error()) { + if (!this->UVPipeOut_.init(uv_loop)) { + this->Result()->ErrorMessage = "libuv stdout pipe initialization failed"; } } - if (!Result()->error()) { - if (!UVPipeErr_.init(uv_loop)) { - Result()->ErrorMessage = "libuv stderr pipe initialization failed"; + if (!this->Result()->error()) { + if (!this->UVPipeErr_.init(uv_loop)) { + this->Result()->ErrorMessage = "libuv stderr pipe initialization failed"; } } - if (!Result()->error()) { + if (!this->Result()->error()) { // -- Setup process stdio options // stdin - UVOptionsStdIO_[0].flags = UV_IGNORE; - UVOptionsStdIO_[0].data.stream = nullptr; + this->UVOptionsStdIO_[0].flags = UV_IGNORE; + this->UVOptionsStdIO_[0].data.stream = nullptr; // stdout - UVOptionsStdIO_[1].flags = + this->UVOptionsStdIO_[1].flags = static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); - UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream(); + this->UVOptionsStdIO_[1].data.stream = this->UVPipeOut_.uv_stream(); // stderr - UVOptionsStdIO_[2].flags = + this->UVOptionsStdIO_[2].flags = static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE); - UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream(); + this->UVOptionsStdIO_[2].data.stream = this->UVPipeErr_.uv_stream(); // -- Setup process options - std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0); - UVOptions_.exit_cb = &cmUVReadOnlyProcess::UVExit; - UVOptions_.file = CommandPtr_[0]; - UVOptions_.args = const_cast<char**>(CommandPtr_.data()); - UVOptions_.cwd = Setup_.WorkingDirectory.c_str(); - UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE; - UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size()); - UVOptions_.stdio = UVOptionsStdIO_.data(); + std::fill_n(reinterpret_cast<char*>(&this->UVOptions_), + sizeof(this->UVOptions_), 0); + this->UVOptions_.exit_cb = &cmUVReadOnlyProcess::UVExit; + this->UVOptions_.file = this->CommandPtr_[0]; + this->UVOptions_.args = const_cast<char**>(this->CommandPtr_.data()); + this->UVOptions_.cwd = this->Setup_.WorkingDirectory.c_str(); + this->UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE; + this->UVOptions_.stdio_count = + static_cast<int>(this->UVOptionsStdIO_.size()); + this->UVOptions_.stdio = this->UVOptionsStdIO_.data(); // -- Spawn process - int uvErrorCode = UVProcess_.spawn(*uv_loop, UVOptions_, this); + int uvErrorCode = this->UVProcess_.spawn(*uv_loop, this->UVOptions_, this); if (uvErrorCode != 0) { - Result()->ErrorMessage = "libuv process spawn failed"; + this->Result()->ErrorMessage = "libuv process spawn failed"; if (const char* uvErr = uv_strerror(uvErrorCode)) { - Result()->ErrorMessage += ": "; - Result()->ErrorMessage += uvErr; + this->Result()->ErrorMessage += ": "; + this->Result()->ErrorMessage += uvErr; } } } // -- Start reading from stdio streams - if (!Result()->error()) { - if (!UVPipeOut_.startRead( + if (!this->Result()->error()) { + if (!this->UVPipeOut_.startRead( [this](cmUVPipeBuffer::DataRange range) { this->UVPipeOutData(range); }, [this](ssize_t error) { this->UVPipeOutEnd(error); })) { - Result()->ErrorMessage = "libuv start reading from stdout pipe failed"; + this->Result()->ErrorMessage = + "libuv start reading from stdout pipe failed"; } } - if (!Result()->error()) { - if (!UVPipeErr_.startRead( + if (!this->Result()->error()) { + if (!this->UVPipeErr_.startRead( [this](cmUVPipeBuffer::DataRange range) { this->UVPipeErrData(range); }, [this](ssize_t error) { this->UVPipeErrEnd(error); })) { - Result()->ErrorMessage = "libuv start reading from stderr pipe failed"; + this->Result()->ErrorMessage = + "libuv start reading from stderr pipe failed"; } } - if (!Result()->error()) { - IsStarted_ = true; - FinishedCallback_ = std::move(finishedCallback); + if (!this->Result()->error()) { + this->IsStarted_ = true; + this->FinishedCallback_ = std::move(finishedCallback); } else { // Clear libuv handles and finish - UVProcess_.reset(); - UVPipeOut_.reset(); - UVPipeErr_.reset(); - CommandPtr_.clear(); + this->UVProcess_.reset(); + this->UVPipeOut_.reset(); + this->UVPipeErr_.reset(); + this->CommandPtr_.clear(); } - return IsStarted(); + return this->IsStarted(); } void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus, @@ -325,36 +332,36 @@ void cmUVReadOnlyProcess::UVExit(uv_process_t* handle, int64_t exitStatus, void cmUVReadOnlyProcess::UVPipeOutData(cmUVPipeBuffer::DataRange data) { - Result()->StdOut.append(data.begin(), data.end()); + this->Result()->StdOut.append(data.begin(), data.end()); } void cmUVReadOnlyProcess::UVPipeOutEnd(ssize_t error) { // Process pipe error - if ((error != 0) && !Result()->error()) { - Result()->ErrorMessage = cmStrCat( + if ((error != 0) && !this->Result()->error()) { + this->Result()->ErrorMessage = cmStrCat( "Reading from stdout pipe failed with libuv error code ", error); } // Try finish - UVTryFinish(); + this->UVTryFinish(); } void cmUVReadOnlyProcess::UVPipeErrData(cmUVPipeBuffer::DataRange data) { - std::string* str = - Setup_.MergedOutput ? &Result()->StdOut : &Result()->StdErr; + std::string* str = this->Setup_.MergedOutput ? &this->Result()->StdOut + : &this->Result()->StdErr; str->append(data.begin(), data.end()); } void cmUVReadOnlyProcess::UVPipeErrEnd(ssize_t error) { // Process pipe error - if ((error != 0) && !Result()->error()) { - Result()->ErrorMessage = cmStrCat( + if ((error != 0) && !this->Result()->error()) { + this->Result()->ErrorMessage = cmStrCat( "Reading from stderr pipe failed with libuv error code ", error); } // Try finish - UVTryFinish(); + this->UVTryFinish(); } void cmUVReadOnlyProcess::UVTryFinish() @@ -362,12 +369,13 @@ void cmUVReadOnlyProcess::UVTryFinish() // There still might be data in the pipes after the process has finished. // Therefore check if the process is finished AND all pipes are closed // before signaling the worker thread to continue. - if ((UVProcess_.get() != nullptr) || (UVPipeOut_.uv_pipe() != nullptr) || - (UVPipeErr_.uv_pipe() != nullptr)) { + if ((this->UVProcess_.get() != nullptr) || + (this->UVPipeOut_.uv_pipe() != nullptr) || + (this->UVPipeErr_.uv_pipe() != nullptr)) { return; } - IsFinished_ = true; - FinishedCallback_(); + this->IsFinished_ = true; + this->FinishedCallback_(); } /** @@ -385,7 +393,7 @@ public: /** * Set the internal thread */ - void SetThread(std::thread&& aThread) { Thread_ = std::move(aThread); } + void SetThread(std::thread&& aThread) { this->Thread_ = std::move(aThread); } /** * Run an external process @@ -414,13 +422,13 @@ private: cmWorkerPoolWorker::cmWorkerPoolWorker(uv_loop_t& uvLoop) { - Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this); + this->Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this); } cmWorkerPoolWorker::~cmWorkerPoolWorker() { - if (Thread_.joinable()) { - Thread_.join(); + if (this->Thread_.joinable()) { + this->Thread_.join(); } } @@ -433,17 +441,17 @@ bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result, } // Create process instance { - std::lock_guard<std::mutex> lock(Proc_.Mutex); - Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>(); - Proc_.ROP->setup(&result, true, command, workingDirectory); + std::lock_guard<std::mutex> lock(this->Proc_.Mutex); + this->Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>(); + this->Proc_.ROP->setup(&result, true, command, workingDirectory); } // Send asynchronous process start request to libuv loop - Proc_.Request.send(); + this->Proc_.Request.send(); // Wait until the process has been finished and destroyed { - std::unique_lock<std::mutex> ulock(Proc_.Mutex); - while (Proc_.ROP) { - Proc_.Condition.wait(ulock); + std::unique_lock<std::mutex> ulock(this->Proc_.Mutex); + while (this->Proc_.ROP) { + this->Proc_.Condition.wait(ulock); } } return !result.error(); @@ -469,12 +477,13 @@ void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle) void cmWorkerPoolWorker::UVProcessFinished() { - std::lock_guard<std::mutex> lock(Proc_.Mutex); - if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) { - Proc_.ROP.reset(); + std::lock_guard<std::mutex> lock(this->Proc_.Mutex); + if (this->Proc_.ROP && + (this->Proc_.ROP->IsFinished() || !this->Proc_.ROP->IsStarted())) { + this->Proc_.ROP.reset(); } // Notify idling thread - Proc_.Condition.notify_one(); + this->Proc_.Condition.notify_one(); } /** @@ -539,19 +548,19 @@ public: void cmWorkerPool::ProcessResultT::reset() { - ExitStatus = 0; - TermSignal = 0; - if (!StdOut.empty()) { - StdOut.clear(); - StdOut.shrink_to_fit(); + this->ExitStatus = 0; + this->TermSignal = 0; + if (!this->StdOut.empty()) { + this->StdOut.clear(); + this->StdOut.shrink_to_fit(); } - if (!StdErr.empty()) { - StdErr.clear(); - StdErr.shrink_to_fit(); + if (!this->StdErr.empty()) { + this->StdErr.clear(); + this->StdErr.shrink_to_fit(); } - if (!ErrorMessage.empty()) { - ErrorMessage.clear(); - ErrorMessage.shrink_to_fit(); + if (!this->ErrorMessage.empty()) { + this->ErrorMessage.clear(); + this->ErrorMessage.shrink_to_fit(); } } @@ -563,56 +572,58 @@ cmWorkerPoolInternal::cmWorkerPoolInternal(cmWorkerPool* pool) #ifdef CMAKE_UV_SIGNAL_HACK UVHackRAII = cm::make_unique<cmUVSignalHackRAII>(); #endif - UVLoop = cm::make_unique<uv_loop_t>(); - uv_loop_init(UVLoop.get()); + this->UVLoop = cm::make_unique<uv_loop_t>(); + uv_loop_init(this->UVLoop.get()); } cmWorkerPoolInternal::~cmWorkerPoolInternal() { - uv_loop_close(UVLoop.get()); + uv_loop_close(this->UVLoop.get()); } bool cmWorkerPoolInternal::Process() { // Reset state flags - Processing = true; - Aborting = false; + this->Processing = true; + this->Aborting = false; // Initialize libuv asynchronous request - UVRequestBegin.init(*UVLoop, &cmWorkerPoolInternal::UVSlotBegin, this); - UVRequestEnd.init(*UVLoop, &cmWorkerPoolInternal::UVSlotEnd, this); + this->UVRequestBegin.init(*this->UVLoop, &cmWorkerPoolInternal::UVSlotBegin, + this); + this->UVRequestEnd.init(*this->UVLoop, &cmWorkerPoolInternal::UVSlotEnd, + this); // Send begin request - UVRequestBegin.send(); + this->UVRequestBegin.send(); // Run libuv loop - bool success = (uv_run(UVLoop.get(), UV_RUN_DEFAULT) == 0); + bool success = (uv_run(this->UVLoop.get(), UV_RUN_DEFAULT) == 0); // Update state flags - Processing = false; - Aborting = false; + this->Processing = false; + this->Aborting = false; return success; } void cmWorkerPoolInternal::Abort() { // Clear all jobs and set abort flag - std::lock_guard<std::mutex> guard(Mutex); - if (!Aborting) { + std::lock_guard<std::mutex> guard(this->Mutex); + if (!this->Aborting) { // Register abort and clear queue - Aborting = true; - Queue.clear(); - Condition.notify_all(); + this->Aborting = true; + this->Queue.clear(); + this->Condition.notify_all(); } } inline bool cmWorkerPoolInternal::PushJob(cmWorkerPool::JobHandleT&& jobHandle) { - std::lock_guard<std::mutex> guard(Mutex); - if (Aborting) { + std::lock_guard<std::mutex> guard(this->Mutex); + if (this->Aborting) { return false; } // Append the job to the queue - Queue.emplace_back(std::move(jobHandle)); + this->Queue.emplace_back(std::move(jobHandle)); // Notify an idle worker if there's one - if (WorkersIdle != 0) { - Condition.notify_one(); + if (this->WorkersIdle != 0) { + this->Condition.notify_one(); } // Return success return true; @@ -652,79 +663,79 @@ void cmWorkerPoolInternal::UVSlotEnd(uv_async_t* handle) void cmWorkerPoolInternal::Work(unsigned int workerIndex) { cmWorkerPool::JobHandleT jobHandle; - std::unique_lock<std::mutex> uLock(Mutex); + std::unique_lock<std::mutex> uLock(this->Mutex); // Increment running workers count - ++WorkersRunning; + ++this->WorkersRunning; // Enter worker main loop while (true) { // Abort on request - if (Aborting) { + if (this->Aborting) { break; } // Wait for new jobs on the main CV - if (Queue.empty()) { - ++WorkersIdle; - Condition.wait(uLock); - --WorkersIdle; + if (this->Queue.empty()) { + ++this->WorkersIdle; + this->Condition.wait(uLock); + --this->WorkersIdle; continue; } // If there is a fence currently active or waiting, // sleep on the main CV and try again. - if (FenceProcessing) { - Condition.wait(uLock); + if (this->FenceProcessing) { + this->Condition.wait(uLock); continue; } // Pop next job from queue - jobHandle = std::move(Queue.front()); - Queue.pop_front(); + jobHandle = std::move(this->Queue.front()); + this->Queue.pop_front(); // Check for fence jobs bool raisedFence = false; if (jobHandle->IsFence()) { - FenceProcessing = true; + this->FenceProcessing = true; raisedFence = true; // Wait on the Fence CV until all pending jobs are done. - while (JobsProcessing != 0 && !Aborting) { - ConditionFence.wait(uLock); + while (this->JobsProcessing != 0 && !this->Aborting) { + this->ConditionFence.wait(uLock); } // When aborting, explicitly kick all threads alive once more. - if (Aborting) { - FenceProcessing = false; - Condition.notify_all(); + if (this->Aborting) { + this->FenceProcessing = false; + this->Condition.notify_all(); break; } } // Unlocked scope for job processing - ++JobsProcessing; + ++this->JobsProcessing; { uLock.unlock(); - jobHandle->Work(Pool, workerIndex); // Process job - jobHandle.reset(); // Destroy job + jobHandle->Work(this->Pool, workerIndex); // Process job + jobHandle.reset(); // Destroy job uLock.lock(); } - --JobsProcessing; + --this->JobsProcessing; // If this was the thread that entered fence processing // originally, notify all idling workers that the fence // is done. if (raisedFence) { - FenceProcessing = false; - Condition.notify_all(); + this->FenceProcessing = false; + this->Condition.notify_all(); } // If fence processing is still not done, notify the // the fencing worker when all active jobs are done. - if (FenceProcessing && JobsProcessing == 0) { - ConditionFence.notify_all(); + if (this->FenceProcessing && this->JobsProcessing == 0) { + this->ConditionFence.notify_all(); } } // Decrement running workers count - if (--WorkersRunning == 0) { + if (--this->WorkersRunning == 0) { // Last worker thread about to finish. Send libuv event. - UVRequestEnd.send(); + this->UVRequestEnd.send(); } } @@ -735,7 +746,7 @@ bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result, std::string const& workingDirectory) { // Get worker by index - auto* wrk = Pool_->Int_->Workers.at(WorkerIndex_).get(); + auto* wrk = this->Pool_->Int_->Workers.at(this->WorkerIndex_).get(); return wrk->RunProcess(result, command, workingDirectory); } @@ -748,29 +759,29 @@ cmWorkerPool::~cmWorkerPool() = default; void cmWorkerPool::SetThreadCount(unsigned int threadCount) { - if (!Int_->Processing) { - ThreadCount_ = (threadCount > 0) ? threadCount : 1u; + if (!this->Int_->Processing) { + this->ThreadCount_ = (threadCount > 0) ? threadCount : 1u; } } bool cmWorkerPool::Process(void* userData) { // Setup user data - UserData_ = userData; + this->UserData_ = userData; // Run libuv loop - bool success = Int_->Process(); + bool success = this->Int_->Process(); // Clear user data - UserData_ = nullptr; + this->UserData_ = nullptr; // Return return success; } bool cmWorkerPool::PushJob(JobHandleT&& jobHandle) { - return Int_->PushJob(std::move(jobHandle)); + return this->Int_->PushJob(std::move(jobHandle)); } void cmWorkerPool::Abort() { - Int_->Abort(); + this->Int_->Abort(); } diff --git a/Source/cmWorkerPool.h b/Source/cmWorkerPool.h index 0fb6707..9082d7f 100644 --- a/Source/cmWorkerPool.h +++ b/Source/cmWorkerPool.h @@ -28,7 +28,8 @@ public: void reset(); bool error() const { - return (ExitStatus != 0) || (TermSignal != 0) || !ErrorMessage.empty(); + return (this->ExitStatus != 0) || (this->TermSignal != 0) || + !this->ErrorMessage.empty(); } std::int64_t ExitStatus = 0; @@ -60,7 +61,7 @@ public: * - no jobs later in the queue will be processed before this job was * processed */ - bool IsFence() const { return Fence_; } + bool IsFence() const { return this->Fence_; } protected: /** @@ -80,13 +81,13 @@ public: * Get the worker pool. * Only valid during the JobT::Process() call! */ - cmWorkerPool* Pool() const { return Pool_; } + cmWorkerPool* Pool() const { return this->Pool_; } /** * Get the user data. * Only valid during the JobT::Process() call! */ - void* UserData() const { return Pool_->UserData(); }; + void* UserData() const { return this->Pool_->UserData(); }; /** * Get the worker index. @@ -95,7 +96,7 @@ public: * Concurrently processing jobs will never have the same WorkerIndex(). * Only valid during the JobT::Process() call! */ - unsigned int WorkerIndex() const { return WorkerIndex_; } + unsigned int WorkerIndex() const { return this->WorkerIndex_; } /** * Run an external read only process. @@ -111,8 +112,8 @@ public: //! Worker thread entry method. void Work(cmWorkerPool* pool, unsigned int workerIndex) { - Pool_ = pool; - WorkerIndex_ = workerIndex; + this->Pool_ = pool; + this->WorkerIndex_ = workerIndex; this->Process(); } @@ -150,7 +151,7 @@ public: { public: //! Does nothing - void Process() override { Pool()->Abort(); } + void Process() override { this->Pool()->Abort(); } }; public: @@ -161,7 +162,7 @@ public: /** * Number of worker threads. */ - unsigned int ThreadCount() const { return ThreadCount_; } + unsigned int ThreadCount() const { return this->ThreadCount_; } /** * Set the number of worker threads. @@ -184,7 +185,7 @@ public: * * Only valid during Process(). */ - void* UserData() const { return UserData_; } + void* UserData() const { return this->UserData_; } // -- Job processing interface @@ -212,7 +213,7 @@ public: template <class T, typename... Args> bool EmplaceJob(Args&&... args) { - return PushJob(cm::make_unique<T>(std::forward<Args>(args)...)); + return this->PushJob(cm::make_unique<T>(std::forward<Args>(args)...)); } private: diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h index c8adea9..e593621 100644 --- a/Source/cmWorkingDirectory.h +++ b/Source/cmWorkingDirectory.h @@ -26,7 +26,7 @@ public: bool SetDirectory(std::string const& newdir); void Pop(); - bool Failed() const { return ResultCode != 0; } + bool Failed() const { return this->ResultCode != 0; } /** \return 0 if the last attempt to set the working directory was * successful. If it failed, the value returned will be the @@ -34,7 +34,7 @@ public: * of the error code can be obtained by passing the result * to \c std::strerror(). */ - int GetLastResult() const { return ResultCode; } + int GetLastResult() const { return this->ResultCode; } std::string const& GetOldDirectory() const { return this->OldDir; } diff --git a/Source/cmXCodeObject.h b/Source/cmXCodeObject.h index ac5be3f..dd5e86e 100644 --- a/Source/cmXCodeObject.h +++ b/Source/cmXCodeObject.h @@ -81,6 +81,13 @@ public: void SetObject(cmXCodeObject* value) { this->Object = value; } cmXCodeObject* GetObject() { return this->Object; } void AddObject(cmXCodeObject* value) { this->List.push_back(value); } + size_t GetObjectCount() { return this->List.size(); } + void InsertObject(size_t position, cmXCodeObject* value) + { + if (position < GetObjectCount()) { + this->List.insert(this->List.begin() + position, value); + } + } void PrependObject(cmXCodeObject* value) { this->List.insert(this->List.begin(), value); diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h index a16c4c8..8a32377 100644 --- a/Source/cmXMLWriter.h +++ b/Source/cmXMLWriter.h @@ -140,9 +140,9 @@ public: cmXMLDocument(cmXMLWriter& xml) : xmlwr(xml) { - xmlwr.StartDocument(); + this->xmlwr.StartDocument(); } - ~cmXMLDocument() { xmlwr.EndDocument(); } + ~cmXMLDocument() { this->xmlwr.EndDocument(); } cmXMLDocument(const cmXMLDocument&) = delete; cmXMLDocument& operator=(const cmXMLDocument&) = delete; @@ -157,19 +157,19 @@ public: cmXMLElement(cmXMLWriter& xml, const char* tag) : xmlwr(xml) { - xmlwr.StartElement(tag); + this->xmlwr.StartElement(tag); } cmXMLElement(cmXMLElement& par, const char* tag) : xmlwr(par.xmlwr) { - xmlwr.StartElement(tag); + this->xmlwr.StartElement(tag); } cmXMLElement(cmXMLDocument& doc, const char* tag) : xmlwr(doc.xmlwr) { - xmlwr.StartElement(tag); + this->xmlwr.StartElement(tag); } - ~cmXMLElement() { xmlwr.EndElement(); } + ~cmXMLElement() { this->xmlwr.EndElement(); } cmXMLElement(const cmXMLElement&) = delete; cmXMLElement& operator=(const cmXMLElement&) = delete; @@ -177,20 +177,20 @@ public: template <typename T> cmXMLElement& Attribute(const char* name, T const& value) { - xmlwr.Attribute(name, value); + this->xmlwr.Attribute(name, value); return *this; } template <typename T> void Content(T const& content) { - xmlwr.Content(content); + this->xmlwr.Content(content); } template <typename T> void Element(std::string const& name, T const& value) { - xmlwr.Element(name, value); + this->xmlwr.Element(name, value); } - void Comment(const char* comment) { xmlwr.Comment(comment); } + void Comment(const char* comment) { this->xmlwr.Comment(comment); } private: cmXMLWriter& xmlwr; diff --git a/Source/cm_codecvt.cxx b/Source/cm_codecvt.cxx index 122e022..15f83e0 100644 --- a/Source/cm_codecvt.cxx +++ b/Source/cm_codecvt.cxx @@ -35,7 +35,7 @@ codecvt::codecvt(Encoding e) case codecvt::None: // No encoding default: - m_noconv = true; + this->m_noconv = true; } } @@ -43,7 +43,7 @@ codecvt::~codecvt() = default; bool codecvt::do_always_noconv() const throw() { - return m_noconv; + return this->m_noconv; } std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from, @@ -53,7 +53,7 @@ std::codecvt_base::result codecvt::do_out(mbstate_t& state, const char* from, { from_next = from; to_next = to; - if (m_noconv) { + if (this->m_noconv) { return std::codecvt_base::noconv; } #if defined(_WIN32) @@ -130,7 +130,7 @@ std::codecvt_base::result codecvt::do_unshift(mbstate_t& state, char* to, char*& to_next) const { to_next = to; - if (m_noconv) { + if (this->m_noconv) { return std::codecvt_base::noconv; } #if defined(_WIN32) diff --git a/Source/cmake.cxx b/Source/cmake.cxx index e655634..48848a7 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -29,6 +29,7 @@ #include "cm_sys_stat.h" #include "cmCMakePresetsFile.h" +#include "cmCommandLineArgument.h" #include "cmCommands.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" @@ -132,6 +133,13 @@ namespace { using JsonValueMapType = std::unordered_map<std::string, Json::Value>; #endif +auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool { + return true; +}; + +using CommandArgument = + cmCommandLineArgument<bool(std::string const& value, cmake* state)>; + } // namespace static bool cmakeCheckStampFile(const std::string& stampName); @@ -200,8 +208,9 @@ cmake::cmake(Role role, cmState::Mode mode) }; // The "c" extension MUST precede the "C" extension. - setupExts(this->CLikeSourceFileExtensions, - { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "m", "M", "mm" }); + setupExts( + this->CLikeSourceFileExtensions, + { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M", "mm" }); setupExts(this->HeaderFileExtensions, { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" }); setupExts(this->CudaFileExtensions, { "cu" }); @@ -263,7 +272,7 @@ Json::Value cmake::ReportCapabilitiesJson() const } obj["generators"] = generators; obj["fileApi"] = cmFileAPI::ReportCapabilities(); - obj["serverMode"] = true; + obj["serverMode"] = false; return obj; } @@ -386,152 +395,145 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) { auto findPackageMode = false; auto seenScriptOption = false; - for (unsigned int i = 1; i < args.size(); ++i) { - std::string const& arg = args[i]; - if (cmHasLiteralPrefix(arg, "-D")) { - std::string entry = arg.substr(2); - if (entry.empty()) { - ++i; - if (i < args.size()) { - entry = args[i]; - } else { - cmSystemTools::Error("-D must be followed with VAR=VALUE."); - return false; - } - } - std::string var; - std::string value; - cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED; - if (cmState::ParseCacheEntry(entry, var, value, type)) { + + auto DefineLambda = [](std::string const& entry, cmake* state) -> bool { + std::string var; + std::string value; + cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED; + if (cmState::ParseCacheEntry(entry, var, value, type)) { #ifndef CMAKE_BOOTSTRAP - this->UnprocessedPresetVariables.erase(var); + state->UnprocessedPresetVariables.erase(var); #endif - this->ProcessCacheArg(var, value, type); - } else { - cmSystemTools::Error("Parse error in command line argument: " + arg + - "\n" + "Should be: VAR:type=value\n"); - return false; - } - } else if (cmHasLiteralPrefix(arg, "-W")) { - std::string entry = arg.substr(2); - if (entry.empty()) { - ++i; - if (i < args.size()) { - entry = args[i]; - } else { - cmSystemTools::Error("-W must be followed with [no-]<name>."); - return false; - } - } + state->ProcessCacheArg(var, value, type); + } else { + cmSystemTools::Error(cmStrCat("Parse error in command line argument: ", + entry, "\n Should be: VAR:type=value\n")); + return false; + } + return true; + }; - std::string name; - bool foundNo = false; - bool foundError = false; - unsigned int nameStartPosition = 0; + auto WarningLambda = [](cm::string_view entry, cmake* state) -> bool { + bool foundNo = false; + bool foundError = false; - if (entry.find("no-", nameStartPosition) == 0) { - foundNo = true; - nameStartPosition += 3; - } + if (cmHasLiteralPrefix(entry, "no-")) { + foundNo = true; + entry.remove_prefix(3); + } - if (entry.find("error=", nameStartPosition) == 0) { - foundError = true; - nameStartPosition += 6; - } + if (cmHasLiteralPrefix(entry, "error=")) { + foundError = true; + entry.remove_prefix(6); + } - name = entry.substr(nameStartPosition); - if (name.empty()) { - cmSystemTools::Error("No warning name provided."); - return false; - } + if (entry.empty()) { + cmSystemTools::Error("No warning name provided."); + return false; + } - if (!foundNo && !foundError) { - // -W<name> - this->DiagLevels[name] = std::max(this->DiagLevels[name], DIAG_WARN); - } else if (foundNo && !foundError) { - // -Wno<name> - this->DiagLevels[name] = DIAG_IGNORE; - } else if (!foundNo && foundError) { - // -Werror=<name> - this->DiagLevels[name] = DIAG_ERROR; - } else { - // -Wno-error=<name> - this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN); - } - } else if (cmHasLiteralPrefix(arg, "-U")) { - std::string entryPattern = arg.substr(2); - if (entryPattern.empty()) { - ++i; - if (i < args.size()) { - entryPattern = args[i]; - } else { - cmSystemTools::Error("-U must be followed with VAR."); - return false; - } + std::string const name = std::string(entry); + if (!foundNo && !foundError) { + // -W<name> + state->DiagLevels[name] = std::max(state->DiagLevels[name], DIAG_WARN); + } else if (foundNo && !foundError) { + // -Wno<name> + state->DiagLevels[name] = DIAG_IGNORE; + } else if (!foundNo && foundError) { + // -Werror=<name> + state->DiagLevels[name] = DIAG_ERROR; + } else { + // -Wno-error=<name> + // This can downgrade an error to a warning, but should not enable + // or disable a warning in the first place. + auto dli = state->DiagLevels.find(name); + if (dli != state->DiagLevels.end()) { + dli->second = std::min(dli->second, DIAG_WARN); } - cmsys::RegularExpression regex( - cmsys::Glob::PatternToRegex(entryPattern, true, true)); - // go through all cache entries and collect the vars which will be - // removed - std::vector<std::string> entriesToDelete; - std::vector<std::string> cacheKeys = this->State->GetCacheEntryKeys(); - for (std::string const& ck : cacheKeys) { - cmStateEnums::CacheEntryType t = this->State->GetCacheEntryType(ck); - if (t != cmStateEnums::STATIC) { - if (regex.find(ck)) { - entriesToDelete.push_back(ck); - } + } + return true; + }; + + auto UnSetLambda = [](std::string const& entryPattern, + cmake* state) -> bool { + cmsys::RegularExpression regex( + cmsys::Glob::PatternToRegex(entryPattern, true, true)); + // go through all cache entries and collect the vars which will be + // removed + std::vector<std::string> entriesToDelete; + std::vector<std::string> cacheKeys = state->State->GetCacheEntryKeys(); + for (std::string const& ck : cacheKeys) { + cmStateEnums::CacheEntryType t = state->State->GetCacheEntryType(ck); + if (t != cmStateEnums::STATIC) { + if (regex.find(ck)) { + entriesToDelete.push_back(ck); } } + } - // now remove them from the cache - for (std::string const& currentEntry : entriesToDelete) { + // now remove them from the cache + for (std::string const& currentEntry : entriesToDelete) { #ifndef CMAKE_BOOTSTRAP - this->UnprocessedPresetVariables.erase(currentEntry); + state->UnprocessedPresetVariables.erase(currentEntry); #endif - this->State->RemoveCacheEntry(currentEntry); - } - } else if (cmHasLiteralPrefix(arg, "-C")) { - std::string path = arg.substr(2); - if (path.empty()) { - ++i; - if (i < args.size()) { - path = args[i]; - } else { - cmSystemTools::Error("-C must be followed by a file name."); - return false; - } - } - cmSystemTools::Stdout("loading initial cache file " + path + "\n"); - // Resolve script path specified on command line relative to $PWD. - path = cmSystemTools::CollapseFullPath(path); - this->ReadListFile(args, path); - } else if (cmHasLiteralPrefix(arg, "-P")) { - i++; - if (i >= args.size()) { - cmSystemTools::Error("-P must be followed by a file name."); - return false; - } - std::string path = args[i]; - if (path.empty()) { - cmSystemTools::Error("No cmake script provided."); - return false; - } - // Register fake project commands that hint misuse in script mode. - GetProjectCommandsInScriptMode(this->GetState()); - // Documented behaviour of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be - // set to $PWD for -P mode. - this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); - this->SetHomeOutputDirectory( - cmSystemTools::GetCurrentWorkingDirectory()); - this->ReadListFile(args, path); - seenScriptOption = true; - } else if (arg == "--" && seenScriptOption) { + state->State->RemoveCacheEntry(currentEntry); + } + return true; + }; + + auto ScriptLambda = [&](std::string const& path, cmake* state) -> bool { + // Register fake project commands that hint misuse in script mode. + GetProjectCommandsInScriptMode(state->GetState()); + // Documented behaviour of CMAKE{,_CURRENT}_{SOURCE,BINARY}_DIR is to be + // set to $PWD for -P mode. + state->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); + state->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); + state->ReadListFile(args, path); + seenScriptOption = true; + return true; + }; + + std::vector<CommandArgument> arguments = { + CommandArgument{ "-D", "-D must be followed with VAR=VALUE.", + CommandArgument::Values::One, DefineLambda }, + CommandArgument{ "-W", "-W must be followed with [no-]<name>.", + CommandArgument::Values::One, WarningLambda }, + CommandArgument{ "-U", "-U must be followed with VAR.", + CommandArgument::Values::One, UnSetLambda }, + CommandArgument{ "-C", "-C must be followed by a file name.", + CommandArgument::Values::One, + [&](std::string const& value, cmake* state) -> bool { + cmSystemTools::Stdout("loading initial cache file " + + value + "\n"); + // Resolve script path specified on command line + // relative to $PWD. + auto path = cmSystemTools::CollapseFullPath(value); + state->ReadListFile(args, path); + return true; + } }, + CommandArgument{ "-P", "-P must be followed by a file name.", + CommandArgument::Values::One, ScriptLambda }, + CommandArgument{ "--find-package", CommandArgument::Values::Zero, + [&](std::string const&, cmake*) -> bool { + findPackageMode = true; + return true; + } }, + }; + for (decltype(args.size()) i = 1; i < args.size(); ++i) { + std::string const& arg = args[i]; + + if (arg == "--" && seenScriptOption) { // Stop processing CMake args and avoid possible errors // when arbitrary args are given to CMake script. break; - } else if (cmHasLiteralPrefix(arg, "--find-package")) { - findPackageMode = true; + } + for (auto const& m : arguments) { + if (m.matches(arg)) { + const bool parsedCorrectly = m.parse(arg, i, args, this); + if (!parsedCorrectly) { + return false; + } + } } } @@ -730,255 +732,341 @@ void cmake::SetArgs(const std::vector<std::string>& args) bool haveToolset = false; bool havePlatform = false; bool haveBArg = false; + bool scriptMode = false; + std::string possibleUnknownArg; #if !defined(CMAKE_BOOTSTRAP) std::string profilingFormat; std::string profilingOutput; std::string presetName; bool listPresets = false; #endif - for (unsigned int i = 1; i < args.size(); ++i) { - std::string const& arg = args[i]; - if (cmHasLiteralPrefix(arg, "-H") || cmHasLiteralPrefix(arg, "-S")) { - std::string path = arg.substr(2); - if (path.empty()) { - ++i; - if (i >= args.size()) { - cmSystemTools::Error("No source directory specified for -S"); - return; - } - path = args[i]; - if (path[0] == '-') { - cmSystemTools::Error("No source directory specified for -S"); - return; - } - } - path = cmSystemTools::CollapseFullPath(path); - cmSystemTools::ConvertToUnixSlashes(path); - this->SetHomeDirectory(path); - // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 - // NOLINTNEXTLINE(bugprone-branch-clone) - } else if (cmHasLiteralPrefix(arg, "-O")) { - // There is no local generate anymore. Ignore -O option. - } else if (cmHasLiteralPrefix(arg, "-B")) { - std::string path = arg.substr(2); - if (path.empty()) { - ++i; - if (i >= args.size()) { - cmSystemTools::Error("No build directory specified for -B"); - return; - } - path = args[i]; - if (path[0] == '-') { - cmSystemTools::Error("No build directory specified for -B"); - return; - } - } + auto SourceArgLambda = [](std::string const& value, cmake* state) -> bool { + std::string path = cmSystemTools::CollapseFullPath(value); + cmSystemTools::ConvertToUnixSlashes(path); + state->SetHomeDirectory(path); + return true; + }; + + auto BuildArgLambda = [&](std::string const& value, cmake* state) -> bool { + std::string path = cmSystemTools::CollapseFullPath(value); + cmSystemTools::ConvertToUnixSlashes(path); + state->SetHomeOutputDirectory(path); + haveBArg = true; + return true; + }; - path = cmSystemTools::CollapseFullPath(path); - cmSystemTools::ConvertToUnixSlashes(path); - this->SetHomeOutputDirectory(path); - haveBArg = true; - } else if ((i < args.size() - 2) && - cmHasLiteralPrefix(arg, "--check-build-system")) { - this->CheckBuildSystemArgument = args[++i]; - this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0); - } else if ((i < args.size() - 1) && - cmHasLiteralPrefix(arg, "--check-stamp-file")) { - this->CheckStampFile = args[++i]; - } else if ((i < args.size() - 1) && - cmHasLiteralPrefix(arg, "--check-stamp-list")) { - this->CheckStampList = args[++i]; - } else if (arg == "--regenerate-during-build"_s) { - this->RegenerateDuringBuild = true; + auto PlatformLambda = [&](std::string const& value, cmake* state) -> bool { + if (havePlatform) { + cmSystemTools::Error("Multiple -A options not allowed"); + return false; } -#if defined(CMAKE_HAVE_VS_GENERATORS) - else if ((i < args.size() - 1) && - cmHasLiteralPrefix(arg, "--vs-solution-file")) { - this->VSSolutionFile = args[++i]; + state->SetGeneratorPlatform(value); + havePlatform = true; + return true; + }; + + auto ToolsetLamda = [&](std::string const& value, cmake* state) -> bool { + if (haveToolset) { + cmSystemTools::Error("Multiple -T options not allowed"); + return false; } + state->SetGeneratorToolset(value); + haveToolset = true; + return true; + }; + + std::vector<CommandArgument> arguments = { + CommandArgument{ "-S", "No source directory specified for -S", + CommandArgument::Values::One, SourceArgLambda }, + CommandArgument{ "-H", "No source directory specified for -H", + CommandArgument::Values::One, SourceArgLambda }, + CommandArgument{ "-O", CommandArgument::Values::Zero, + IgnoreAndTrueLambda }, + CommandArgument{ "-B", "No build directory specified for -B", + CommandArgument::Values::One, BuildArgLambda }, + CommandArgument{ "-P", "-P must be followed by a file name.", + CommandArgument::Values::One, + [&](std::string const&, cmake*) -> bool { + scriptMode = true; + return true; + } }, + CommandArgument{ "-D", "-D must be followed with VAR=VALUE.", + CommandArgument::Values::One, IgnoreAndTrueLambda }, + CommandArgument{ "-C", "-C must be followed by a file name.", + CommandArgument::Values::One, IgnoreAndTrueLambda }, + CommandArgument{ "-U", "-U must be followed with VAR.", + CommandArgument::Values::One, IgnoreAndTrueLambda }, + CommandArgument{ "-W", "-W must be followed with [no-]<name>.", + CommandArgument::Values::One, IgnoreAndTrueLambda }, + CommandArgument{ "-A", "No platform specified for -A", + CommandArgument::Values::One, PlatformLambda }, + CommandArgument{ "-T", "No toolset specified for -T", + CommandArgument::Values::One, ToolsetLamda }, + + CommandArgument{ "--check-build-system", CommandArgument::Values::Two, + [](std::string const& value, cmake* state) -> bool { + std::vector<std::string> values = cmExpandedList(value); + state->CheckBuildSystemArgument = values[0]; + state->ClearBuildSystem = (atoi(values[1].c_str()) > 0); + return true; + } }, + CommandArgument{ "--check-stamp-file", CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + state->CheckStampFile = value; + return true; + } }, + CommandArgument{ "--check-stamp-list", CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + state->CheckStampList = value; + return true; + } }, + CommandArgument{ "--regenerate-during-build", + CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + state->RegenerateDuringBuild = true; + return true; + } }, + + CommandArgument{ "--find-package", CommandArgument::Values::Zero, + IgnoreAndTrueLambda }, + + CommandArgument{ "--graphviz", "No file specified for --graphviz", + CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + std::string path = + cmSystemTools::CollapseFullPath(value); + cmSystemTools::ConvertToUnixSlashes(path); + state->GraphVizFile = path; + return true; + } }, + + CommandArgument{ "--debug-trycompile", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "debug trycompile on\n"; + state->DebugTryCompileOn(); + return true; + } }, + CommandArgument{ "--debug-output", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "Running with debug output on.\n"; + state->SetDebugOutputOn(true); + return true; + } }, + + CommandArgument{ "--log-level", "Invalid level specified for --log-level", + CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + const auto logLevel = StringToLogLevel(value); + if (logLevel == LogLevel::LOG_UNDEFINED) { + cmSystemTools::Error( + "Invalid level specified for --log-level"); + return false; + } + state->SetLogLevel(logLevel); + state->LogLevelWasSetViaCLI = true; + return true; + } }, + // This is supported for backward compatibility. This option only + // appeared in the 3.15.x release series and was renamed to + // --log-level in 3.16.0 + CommandArgument{ "--loglevel", "Invalid level specified for --loglevel", + CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + const auto logLevel = StringToLogLevel(value); + if (logLevel == LogLevel::LOG_UNDEFINED) { + cmSystemTools::Error( + "Invalid level specified for --loglevel"); + return false; + } + state->SetLogLevel(logLevel); + state->LogLevelWasSetViaCLI = true; + return true; + } }, + + CommandArgument{ "--log-context", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + state->SetShowLogContext(true); + return true; + } }, + CommandArgument{ + "--debug-find", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "Running with debug output on for the `find` commands.\n"; + state->SetDebugFindOutputOn(true); + return true; + } }, + CommandArgument{ "--trace-expand", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "Running with expanded trace output on.\n"; + state->SetTrace(true); + state->SetTraceExpand(true); + return true; + } }, + CommandArgument{ "--trace-format", CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + state->SetTrace(true); + const auto traceFormat = StringToTraceFormat(value); + if (traceFormat == TraceFormat::TRACE_UNDEFINED) { + cmSystemTools::Error( + "Invalid format specified for --trace-format. " + "Valid formats are human, json-v1."); + return false; + } + state->SetTraceFormat(traceFormat); + return true; + } }, + CommandArgument{ "--trace-source", CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + std::string file(value); + cmSystemTools::ConvertToUnixSlashes(file); + state->AddTraceSource(file); + state->SetTrace(true); + return true; + } }, + CommandArgument{ "--trace-redirect", CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + std::string file(value); + cmSystemTools::ConvertToUnixSlashes(file); + state->SetTraceFile(file); + state->SetTrace(true); + return true; + } }, + CommandArgument{ "--trace", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "Running with trace output on.\n"; + state->SetTrace(true); + state->SetTraceExpand(false); + return true; + } }, + CommandArgument{ "--warn-uninitialized", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "Warn about uninitialized values.\n"; + state->SetWarnUninitialized(true); + return true; + } }, + CommandArgument{ "--warn-unused-vars", CommandArgument::Values::Zero, + IgnoreAndTrueLambda }, // Option was removed. + CommandArgument{ "--no-warn-unused-cli", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout + << "Not searching for unused variables given on the " + << "command line.\n"; + state->SetWarnUnusedCli(false); + return true; + } }, + CommandArgument{ + "--check-system-vars", CommandArgument::Values::Zero, + [](std::string const&, cmake* state) -> bool { + std::cout << "Also check system files when warning about unused and " + << "uninitialized variables.\n"; + state->SetCheckSystemVars(true); + return true; + } } + }; + +#if defined(CMAKE_HAVE_VS_GENERATORS) + arguments.emplace_back("--vs-solution-file", CommandArgument::Values::One, + [](std::string const& value, cmake* state) -> bool { + state->VSSolutionFile = value; + return true; + }); #endif - else if (cmHasLiteralPrefix(arg, "-D") || cmHasLiteralPrefix(arg, "-U") || - cmHasLiteralPrefix(arg, "-C")) { - // skip for now - // in case '-[DUC] argval' var' is given, also skip the next - // in case '-[DUC]argval' is given, don't skip the next - if (arg.size() == 2) { - ++i; - } - // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 - // NOLINTNEXTLINE(bugprone-branch-clone) - } else if (cmHasLiteralPrefix(arg, "-P")) { - // skip for now - i++; - } else if (cmHasLiteralPrefix(arg, "--find-package")) { - // skip for now - i++; - } else if (cmHasLiteralPrefix(arg, "-W")) { - // skip for now - } else if (cmHasLiteralPrefix(arg, "--graphviz=")) { - std::string path = arg.substr(strlen("--graphviz=")); - path = cmSystemTools::CollapseFullPath(path); - cmSystemTools::ConvertToUnixSlashes(path); - this->GraphVizFile = path; - if (this->GraphVizFile.empty()) { - cmSystemTools::Error("No file specified for --graphviz"); - return; - } - } else if (cmHasLiteralPrefix(arg, "--debug-trycompile")) { - std::cout << "debug trycompile on\n"; - this->DebugTryCompileOn(); - } else if (cmHasLiteralPrefix(arg, "--debug-output")) { - std::cout << "Running with debug output on.\n"; - this->SetDebugOutputOn(true); - } else if (cmHasLiteralPrefix(arg, "--log-level=")) { - const auto logLevel = - StringToLogLevel(arg.substr(sizeof("--log-level=") - 1)); - if (logLevel == LogLevel::LOG_UNDEFINED) { - cmSystemTools::Error("Invalid level specified for --log-level"); - return; - } - this->SetLogLevel(logLevel); - this->LogLevelWasSetViaCLI = true; - } else if (cmHasLiteralPrefix(arg, "--loglevel=")) { - // This is supported for backward compatibility. This option only - // appeared in the 3.15.x release series and was renamed to - // --log-level in 3.16.0 - const auto logLevel = - StringToLogLevel(arg.substr(sizeof("--loglevel=") - 1)); - if (logLevel == LogLevel::LOG_UNDEFINED) { - cmSystemTools::Error("Invalid level specified for --loglevel"); - return; - } - this->SetLogLevel(logLevel); - this->LogLevelWasSetViaCLI = true; - } else if (arg == "--log-context"_s) { - this->SetShowLogContext(true); - } else if (cmHasLiteralPrefix(arg, "--debug-find")) { - std::cout << "Running with debug output on for the `find` commands.\n"; - this->SetDebugFindOutputOn(true); - } else if (cmHasLiteralPrefix(arg, "--trace-expand")) { - std::cout << "Running with expanded trace output on.\n"; - this->SetTrace(true); - this->SetTraceExpand(true); - } else if (cmHasLiteralPrefix(arg, "--trace-format=")) { - this->SetTrace(true); - const auto traceFormat = - StringToTraceFormat(arg.substr(strlen("--trace-format="))); - if (traceFormat == TraceFormat::TRACE_UNDEFINED) { - cmSystemTools::Error("Invalid format specified for --trace-format. " - "Valid formats are human, json-v1."); - return; - } - this->SetTraceFormat(traceFormat); - } else if (cmHasLiteralPrefix(arg, "--trace-source=")) { - std::string file = arg.substr(strlen("--trace-source=")); - cmSystemTools::ConvertToUnixSlashes(file); - this->AddTraceSource(file); - this->SetTrace(true); - } else if (cmHasLiteralPrefix(arg, "--trace-redirect=")) { - std::string file = arg.substr(strlen("--trace-redirect=")); - cmSystemTools::ConvertToUnixSlashes(file); - this->SetTraceFile(file); - this->SetTrace(true); - } else if (cmHasLiteralPrefix(arg, "--trace")) { - std::cout << "Running with trace output on.\n"; - this->SetTrace(true); - this->SetTraceExpand(false); - } else if (cmHasLiteralPrefix(arg, "--warn-uninitialized")) { - std::cout << "Warn about uninitialized values.\n"; - this->SetWarnUninitialized(true); - } else if (cmHasLiteralPrefix(arg, "--warn-unused-vars")) { - // Option was removed. - } else if (cmHasLiteralPrefix(arg, "--no-warn-unused-cli")) { - std::cout << "Not searching for unused variables given on the " - << "command line.\n"; - this->SetWarnUnusedCli(false); - } else if (cmHasLiteralPrefix(arg, "--check-system-vars")) { - std::cout << "Also check system files when warning about unused and " - << "uninitialized variables.\n"; - this->SetCheckSystemVars(true); - } else if (cmHasLiteralPrefix(arg, "-A")) { - std::string value = arg.substr(2); - if (value.empty()) { - ++i; - if (i >= args.size()) { - cmSystemTools::Error("No platform specified for -A"); - return; - } - value = args[i]; - } - if (havePlatform) { - cmSystemTools::Error("Multiple -A options not allowed"); - return; - } - this->SetGeneratorPlatform(value); - havePlatform = true; - } else if (cmHasLiteralPrefix(arg, "-T")) { - std::string value = arg.substr(2); - if (value.empty()) { - ++i; - if (i >= args.size()) { - cmSystemTools::Error("No toolset specified for -T"); - return; - } - value = args[i]; - } - if (haveToolset) { - cmSystemTools::Error("Multiple -T options not allowed"); - return; - } - this->SetGeneratorToolset(value); - haveToolset = true; - } else if (cmHasLiteralPrefix(arg, "-G")) { - std::string value = arg.substr(2); - if (value.empty()) { - ++i; - if (i >= args.size()) { - cmSystemTools::Error("No generator specified for -G"); - this->PrintGeneratorList(); - return; - } - value = args[i]; - } - if (!this->CreateAndSetGlobalGenerator(value, true)) { - return; - } + #if !defined(CMAKE_BOOTSTRAP) - } else if (cmHasLiteralPrefix(arg, "--profiling-format=")) { - profilingFormat = arg.substr(strlen("--profiling-format=")); - if (profilingFormat.empty()) { - cmSystemTools::Error("No format specified for --profiling-format"); - } - } else if (cmHasLiteralPrefix(arg, "--profiling-output=")) { - profilingOutput = arg.substr(strlen("--profiling-output=")); - profilingOutput = cmSystemTools::CollapseFullPath(profilingOutput); + arguments.emplace_back("--profiling-format", + "No format specified for --profiling-format", + CommandArgument::Values::One, + [&](std::string const& value, cmake*) -> bool { + profilingFormat = value; + return true; + }); + arguments.emplace_back( + "--profiling-output", "No path specified for --profiling-output", + CommandArgument::Values::One, + [&](std::string const& value, cmake*) -> bool { + profilingOutput = cmSystemTools::CollapseFullPath(value); cmSystemTools::ConvertToUnixSlashes(profilingOutput); - if (profilingOutput.empty()) { - cmSystemTools::Error("No path specified for --profiling-output"); + return true; + }); + arguments.emplace_back("--preset", "No preset specified for --preset", + CommandArgument::Values::One, + [&](std::string const& value, cmake*) -> bool { + presetName = value; + return true; + }); + arguments.emplace_back("--list-presets", CommandArgument::Values::Zero, + [&](std::string const&, cmake*) -> bool { + listPresets = true; + return true; + }); + +#endif + + bool badGeneratorName = false; + CommandArgument generatorCommand( + "-G", "No generator specified for -G", CommandArgument::Values::One, + [&](std::string const& value, cmake* state) -> bool { + bool valid = state->CreateAndSetGlobalGenerator(value, true); + badGeneratorName = !valid; + return valid; + }); + + for (decltype(args.size()) i = 1; i < args.size(); ++i) { + // iterate each argument + std::string const& arg = args[i]; + + // Generator flag has special handling for when to print help + // so it becomes the exception + if (generatorCommand.matches(arg)) { + bool parsed = generatorCommand.parse(arg, i, args, this); + if (!parsed && !badGeneratorName) { + this->PrintGeneratorList(); + return; } - } else if (cmHasLiteralPrefix(arg, "--preset=")) { - presetName = arg.substr(strlen("--preset=")); - if (presetName.empty()) { - cmSystemTools::Error("No preset specified for --preset"); + continue; + } + + bool matched = false; + bool parsedCorrectly = true; // needs to be true so we can ignore + // arguments so as -E + for (auto const& m : arguments) { + if (m.matches(arg)) { + matched = true; + parsedCorrectly = m.parse(arg, i, args, this); + break; } - } else if (cmHasLiteralPrefix(arg, "--list-presets")) { - listPresets = true; -#endif } - // no option assume it is the path to the source or an existing build - else { + + // We have an issue where arguments to a "-P" script mode + // can be provided before the "-P" argument. This means + // that we need to lazily check this argument after checking + // all args. + // Additionally it can't be the source/binary tree location + if (!parsedCorrectly) { + cmSystemTools::Error("Run 'cmake --help' for all supported options."); + exit(1); + } else if (!matched && cmHasLiteralPrefix(arg, "-")) { + possibleUnknownArg = arg; + } else if (!matched) { this->SetDirectoriesFromFile(arg); } - // Empty instance, platform and toolset if only a generator is specified - if (this->GlobalGenerator) { - this->GeneratorInstance = ""; - if (!this->GeneratorPlatformSet) { - this->GeneratorPlatform = ""; - } - if (!this->GeneratorToolsetSet) { - this->GeneratorToolset = ""; - } + } + + if (!possibleUnknownArg.empty() && !scriptMode) { + cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg)); + cmSystemTools::Error("Run 'cmake --help' for all supported options."); + exit(1); + } + + // Empty instance, platform and toolset if only a generator is specified + if (this->GlobalGenerator) { + this->GeneratorInstance = ""; + if (!this->GeneratorPlatformSet) { + this->GeneratorPlatform = ""; + } + if (!this->GeneratorToolsetSet) { + this->GeneratorToolset = ""; } } @@ -1951,7 +2039,7 @@ int cmake::ActualConfigure() } } - auto& mf = this->GlobalGenerator->GetMakefiles()[0]; + const auto& mf = this->GlobalGenerator->GetMakefiles()[0]; if (mf->IsOn("CTEST_USE_LAUNCHERS") && !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) { cmSystemTools::Error( @@ -2115,7 +2203,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) #endif // Add any cache args if (!this->SetCacheArgs(args)) { - cmSystemTools::Error("Problem processing arguments. Aborting.\n"); + cmSystemTools::Error("Run 'cmake --help' for all supported options."); return -1; } #ifndef CMAKE_BOOTSTRAP @@ -2293,12 +2381,12 @@ cmProp cmake::GetCacheDefinition(const std::string& name) const return this->State->GetInitializedCacheValue(name); } -void cmake::AddScriptingCommands() +void cmake::AddScriptingCommands() const { GetScriptingCommands(this->GetState()); } -void cmake::AddProjectCommands() +void cmake::AddProjectCommands() const { GetProjectCommands(this->GetState()); } @@ -2573,8 +2661,7 @@ int cmake::CheckBuildSystem() if (this->ClearBuildSystem) { // Get the generator used for this build system. - const char* genName = - cmToCStr(mf.GetDefinition("CMAKE_DEPENDS_GENERATOR")); + std::string genName = mf.GetSafeDefinition("CMAKE_DEPENDS_GENERATOR"); if (!cmNonempty(genName)) { genName = "Unix Makefiles"; } diff --git a/Source/cmake.h b/Source/cmake.h index 1ecf2c2..d936f28 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -411,7 +411,7 @@ public: WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; } //! Debug the try compile stuff by not deleting the files - bool GetDebugTryCompile() { return this->DebugTryCompile; } + bool GetDebugTryCompile() const { return this->DebugTryCompile; } void DebugTryCompileOn() { this->DebugTryCompile = true; } /** @@ -456,11 +456,11 @@ public: void SetShowLogContext(bool b) { this->LogContext = b; } //! Do we want debug output during the cmake run. - bool GetDebugOutput() { return this->DebugOutput; } + bool GetDebugOutput() const { return this->DebugOutput; } void SetDebugOutputOn(bool b) { this->DebugOutput = b; } //! Do we want debug output from the find commands during the cmake run. - bool GetDebugFindOutput() { return this->DebugFindOutput; } + bool GetDebugFindOutput() const { return this->DebugFindOutput; } void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; } //! Do we want trace output during the cmake run. @@ -482,11 +482,11 @@ public: void SetTraceFile(std::string const& file); void PrintTraceFormatVersion(); - bool GetWarnUninitialized() { return this->WarnUninitialized; } + bool GetWarnUninitialized() const { return this->WarnUninitialized; } void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; } - bool GetWarnUnusedCli() { return this->WarnUnusedCli; } + bool GetWarnUnusedCli() const { return this->WarnUnusedCli; } void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b; } - bool GetCheckSystemVars() { return this->CheckSystemVars; } + bool GetCheckSystemVars() const { return this->CheckSystemVars; } void SetCheckSystemVars(bool b) { this->CheckSystemVars = b; } void MarkCliAsUsed(const std::string& variable); @@ -591,8 +591,8 @@ protected: using RegisteredExtraGeneratorsVector = std::vector<cmExternalMakefileProjectGeneratorFactory*>; RegisteredExtraGeneratorsVector ExtraGenerators; - void AddScriptingCommands(); - void AddProjectCommands(); + void AddScriptingCommands() const; + void AddProjectCommands() const; void AddDefaultGenerators(); void AddDefaultExtraGenerators(); @@ -811,6 +811,7 @@ private: F(cxx_std_14) \ F(cxx_std_17) \ F(cxx_std_20) \ + F(cxx_std_23) \ FOR_EACH_CXX98_FEATURE(F) \ FOR_EACH_CXX11_FEATURE(F) \ FOR_EACH_CXX14_FEATURE(F) @@ -820,4 +821,5 @@ private: F(cuda_std_11) \ F(cuda_std_14) \ F(cuda_std_17) \ - F(cuda_std_20) + F(cuda_std_20) \ + F(cuda_std_23) diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index f7734a6..ba471b7 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -5,7 +5,6 @@ #include <algorithm> #include <cassert> -#include <cctype> #include <climits> #include <cstring> #include <iostream> @@ -19,6 +18,7 @@ #include <cm3p/uv.h> +#include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" #include "cmDocumentationEntry.h" // IWYU pragma: keep #include "cmGlobalGenerator.h" @@ -213,61 +213,114 @@ int do_cmake(int ac, char const* const* av) } #endif + bool wizard_mode = false; bool sysinfo = false; bool list_cached = false; bool list_all_cached = false; bool list_help = false; bool view_only = false; cmake::WorkingMode workingMode = cmake::NORMAL_MODE; - std::vector<std::string> args; - for (int i = 0; i < ac; ++i) { - if (strcmp(av[i], "-i") == 0) { - /* clang-format off */ - std::cerr << - "The \"cmake -i\" wizard mode is no longer supported.\n" - "Use the -D option to set cache values on the command line.\n" - "Use cmake-gui or ccmake for an interactive dialog.\n"; - /* clang-format on */ - return 1; - } - if (strcmp(av[i], "--system-information") == 0) { - sysinfo = true; - } else if (strcmp(av[i], "-N") == 0) { - view_only = true; - } else if (strcmp(av[i], "-L") == 0) { - list_cached = true; - } else if (strcmp(av[i], "-LA") == 0) { - list_all_cached = true; - } else if (strcmp(av[i], "-LH") == 0) { - list_cached = true; - list_help = true; - } else if (strcmp(av[i], "-LAH") == 0) { - list_all_cached = true; - list_help = true; - } else if (cmHasLiteralPrefix(av[i], "-P")) { - if (i == ac - 1) { - cmSystemTools::Error("No script specified for argument -P"); - return 1; + std::vector<std::string> parsedArgs; + + using CommandArgument = + cmCommandLineArgument<bool(std::string const& value)>; + std::vector<CommandArgument> arguments = { + CommandArgument{ + "-i", CommandArgument::Values::Zero, + [&wizard_mode](std::string const&) -> bool { + /* clang-format off */ + std::cerr << + "The \"cmake -i\" wizard mode is no longer supported.\n" + "Use the -D option to set cache values on the command line.\n" + "Use cmake-gui or ccmake for an interactive dialog.\n"; + /* clang-format on */ + wizard_mode = true; + return true; + } }, + CommandArgument{ "--system-information", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + sysinfo = true; + return true; + } }, + CommandArgument{ "-N", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + view_only = true; + return true; + } }, + CommandArgument{ "-LAH", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + list_all_cached = true; + list_help = true; + return true; + } }, + CommandArgument{ "-LA", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + list_all_cached = true; + return true; + } }, + CommandArgument{ "-LH", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + list_cached = true; + list_help = true; + return true; + } }, + CommandArgument{ "-L", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + list_cached = true; + return true; + } }, + CommandArgument{ "-P", "No script specified for argument -P", + CommandArgument::Values::One, + [&](std::string const& value) -> bool { + workingMode = cmake::SCRIPT_MODE; + parsedArgs.emplace_back("-P"); + parsedArgs.push_back(value); + return true; + } }, + CommandArgument{ "--find-package", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + workingMode = cmake::FIND_PACKAGE_MODE; + parsedArgs.emplace_back("--find-package"); + return true; + } }, + CommandArgument{ "--list-presets", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + workingMode = cmake::HELP_MODE; + parsedArgs.emplace_back("--list-presets"); + return true; + } }, + }; + + std::vector<std::string> inputArgs; + inputArgs.reserve(ac); + cm::append(inputArgs, av, av + ac); + + for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) { + std::string const& arg = inputArgs[i]; + bool matched = false; + for (auto const& m : arguments) { + if (m.matches(arg)) { + matched = true; + if (m.parse(arg, i, inputArgs)) { + break; + } + return 1; // failed to parse } - workingMode = cmake::SCRIPT_MODE; - args.emplace_back(av[i]); - i++; - args.emplace_back(av[i]); - } else if (cmHasLiteralPrefix(av[i], "--find-package")) { - workingMode = cmake::FIND_PACKAGE_MODE; - args.emplace_back(av[i]); - } else if (strcmp(av[i], "--list-presets") == 0) { - workingMode = cmake::HELP_MODE; - args.emplace_back(av[i]); - } else { - args.emplace_back(av[i]); } + if (!matched) { + parsedArgs.emplace_back(av[i]); + } + } + + if (wizard_mode) { + return 1; } + if (sysinfo) { cmake cm(cmake::RoleProject, cmState::Project); cm.SetHomeDirectory(""); cm.SetHomeOutputDirectory(""); - int ret = cm.GetSystemInformation(args); + int ret = cm.GetSystemInformation(parsedArgs); return ret; } cmake::Role const role = @@ -297,7 +350,7 @@ int do_cmake(int ac, char const* const* av) }); cm.SetWorkingMode(workingMode); - int res = cm.Run(args, view_only); + int res = cm.Run(parsedArgs, view_only); if (list_cached || list_all_cached) { std::cout << "-- Cache values" << std::endl; std::vector<std::string> keys = cm.GetState()->GetCacheEntryKeys(); @@ -332,16 +385,9 @@ int do_cmake(int ac, char const* const* av) } #ifndef CMAKE_BOOTSTRAP -int extract_job_number(int& index, char const* current, char const* next, - int len_of_flag) +int extract_job_number(std::string const& command, + std::string const& jobString) { - std::string command(current); - std::string jobString = command.substr(len_of_flag); - if (jobString.empty() && next && isdigit(next[0])) { - ++index; // skip parsing the job number - jobString = std::string(next); - } - int jobs = -1; unsigned long numJobs = 0; if (jobString.empty()) { @@ -356,8 +402,8 @@ int extract_job_number(int& index, char const* current, char const* next, jobs = int(numJobs); } } else { - std::cerr << "'" << command.substr(0, len_of_flag) << "' invalid number '" - << jobString << "' given.\n\n"; + std::cerr << "'" << command << "' invalid number '" << jobString + << "' given.\n\n"; } return jobs; } @@ -374,88 +420,107 @@ int do_build(int ac, char const* const* av) std::string config; std::string dir; std::vector<std::string> nativeOptions; + bool nativeOptionsPassed = false; bool cleanFirst = false; bool foundClean = false; bool foundNonClean = false; bool verbose = cmSystemTools::HasEnv("VERBOSE"); - enum Doing - { - DoingNone, - DoingDir, - DoingTarget, - DoingConfig, - DoingNative + auto jLambda = [&](std::string const& value) -> bool { + jobs = extract_job_number("-j", value); + if (jobs < 0) { + dir.clear(); + } + return true; }; - Doing doing = DoingDir; - for (int i = 2; i < ac; ++i) { - if (doing == DoingNative) { - nativeOptions.emplace_back(av[i]); - } else if (cmHasLiteralPrefix(av[i], "-j")) { - const char* nextArg = ((i + 1 < ac) ? av[i + 1] : nullptr); - jobs = extract_job_number(i, av[i], nextArg, sizeof("-j") - 1); - if (jobs < 0) { - dir.clear(); - } - doing = DoingNone; - } else if (cmHasLiteralPrefix(av[i], "--parallel")) { - const char* nextArg = ((i + 1 < ac) ? av[i + 1] : nullptr); - jobs = extract_job_number(i, av[i], nextArg, sizeof("--parallel") - 1); - if (jobs < 0) { - dir.clear(); + auto parallelLambda = [&](std::string const& value) -> bool { + jobs = extract_job_number("--parallel", value); + if (jobs < 0) { + dir.clear(); + } + return true; + }; + auto targetLambda = [&](std::string const& value) -> bool { + if (!value.empty()) { + std::vector<std::string> values = cmExpandedList(value); + for (auto const& v : values) { + targets.emplace_back(v); + if (v == "clean") { + foundClean = true; + } else { + foundNonClean = true; + } } - doing = DoingNone; - } else if ((strcmp(av[i], "--target") == 0) || - (strcmp(av[i], "-t") == 0)) { - doing = DoingTarget; - } else if (strcmp(av[i], "--config") == 0) { - doing = DoingConfig; - } else if (strcmp(av[i], "--clean-first") == 0) { - cleanFirst = true; - doing = DoingNone; - } else if ((strcmp(av[i], "--verbose") == 0) || - (strcmp(av[i], "-v") == 0)) { - verbose = true; - doing = DoingNone; - } else if (strcmp(av[i], "--use-stderr") == 0) { - /* tolerate legacy option */ - } else if (strcmp(av[i], "--") == 0) { - doing = DoingNative; - } else { - switch (doing) { - case DoingDir: - dir = cmSystemTools::CollapseFullPath(av[i]); - doing = DoingNone; - break; - case DoingTarget: - if (strlen(av[i]) == 0) { - std::cerr << "Warning: Argument number " << i - << " after --target option is empty." << std::endl; - } else { - targets.emplace_back(av[i]); - if (strcmp(av[i], "clean") == 0) { - foundClean = true; - } else { - foundNonClean = true; - } - } - if (foundClean && foundNonClean) { - std::cerr << "Error: Building 'clean' and other targets together " - "is not supported." - << std::endl; - dir.clear(); - } - break; - case DoingConfig: - config = av[i]; - doing = DoingNone; - break; - default: - std::cerr << "Unknown argument " << av[i] << std::endl; - dir.clear(); + return true; + } + return false; + }; + auto verboseLambda = [&](std::string const&) -> bool { + verbose = true; + return true; + }; + + using CommandArgument = + cmCommandLineArgument<bool(std::string const& value)>; + + std::vector<CommandArgument> arguments = { + CommandArgument{ "-j", CommandArgument::Values::ZeroOrOne, jLambda }, + CommandArgument{ "--parallel", CommandArgument::Values::ZeroOrOne, + parallelLambda }, + CommandArgument{ "-t", CommandArgument::Values::OneOrMore, targetLambda }, + CommandArgument{ "--target", CommandArgument::Values::OneOrMore, + targetLambda }, + CommandArgument{ "--config", CommandArgument::Values::One, + [&](std::string const& value) -> bool { + config = value; + return true; + } }, + CommandArgument{ "--clean-first", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + cleanFirst = true; + return true; + } }, + CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda }, + CommandArgument{ "--verbose", CommandArgument::Values::Zero, + verboseLambda }, + /* legacy option no-op*/ + CommandArgument{ "--use-stderr", CommandArgument::Values::Zero, + [](std::string const&) -> bool { return true; } }, + CommandArgument{ "--", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + nativeOptionsPassed = true; + return true; + } }, + }; + + if (ac >= 3) { + dir = cmSystemTools::CollapseFullPath(av[2]); + + std::vector<std::string> inputArgs; + inputArgs.reserve(ac - 3); + cm::append(inputArgs, av + 3, av + ac); + + decltype(inputArgs.size()) i = 0; + for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) { + + std::string const& arg = inputArgs[i]; + for (auto const& m : arguments) { + if (m.matches(arg) && m.parse(arg, i, inputArgs)) { break; + } } } + + if (nativeOptionsPassed) { + cm::append(nativeOptions, inputArgs.begin() + i, inputArgs.end()); + } + } + + if (foundClean && foundNonClean) { + std::cerr << "Error: Building 'clean' and other targets together " + "is not supported." + << std::endl; + dir.clear(); } if (jobs == cmake::NO_BUILD_PARALLEL_LEVEL) { @@ -658,60 +723,59 @@ int do_install(int ac, char const* const* av) bool strip = false; bool verbose = cmSystemTools::HasEnv("VERBOSE"); - enum Doing - { - DoingNone, - DoingDir, - DoingConfig, - DoingComponent, - DoingPrefix, - DoingDefaultDirectoryPermissions, + auto verboseLambda = [&](std::string const&) -> bool { + verbose = true; + return true; }; - Doing doing = DoingDir; + using CommandArgument = + cmCommandLineArgument<bool(std::string const& value)>; + + std::vector<CommandArgument> arguments = { + CommandArgument{ "--config", CommandArgument::Values::One, + [&](std::string const& value) -> bool { + config = value; + return true; + } }, + CommandArgument{ "--component", CommandArgument::Values::One, + [&](std::string const& value) -> bool { + component = value; + return true; + } }, + CommandArgument{ "--default-directory-permissions", + CommandArgument::Values::One, + [&](std::string const& value) -> bool { + defaultDirectoryPermissions = value; + return true; + } }, + CommandArgument{ "--prefix", CommandArgument::Values::One, + [&](std::string const& value) -> bool { + prefix = value; + return true; + } }, + CommandArgument{ "--strip", CommandArgument::Values::Zero, + [&](std::string const&) -> bool { + strip = true; + return true; + } }, + CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda }, + CommandArgument{ "--verbose", CommandArgument::Values::Zero, + verboseLambda } + }; - for (int i = 2; i < ac; ++i) { - if (strcmp(av[i], "--config") == 0) { - doing = DoingConfig; - } else if (strcmp(av[i], "--component") == 0) { - doing = DoingComponent; - } else if (strcmp(av[i], "--prefix") == 0) { - doing = DoingPrefix; - } else if (strcmp(av[i], "--strip") == 0) { - strip = true; - doing = DoingNone; - } else if ((strcmp(av[i], "--verbose") == 0) || - (strcmp(av[i], "-v") == 0)) { - verbose = true; - doing = DoingNone; - } else if (strcmp(av[i], "--default-directory-permissions") == 0) { - doing = DoingDefaultDirectoryPermissions; - } else { - switch (doing) { - case DoingDir: - dir = cmSystemTools::CollapseFullPath(av[i]); - doing = DoingNone; - break; - case DoingConfig: - config = av[i]; - doing = DoingNone; - break; - case DoingComponent: - component = av[i]; - doing = DoingNone; - break; - case DoingPrefix: - prefix = av[i]; - doing = DoingNone; - break; - case DoingDefaultDirectoryPermissions: - defaultDirectoryPermissions = av[i]; - doing = DoingNone; - break; - default: - std::cerr << "Unknown argument " << av[i] << std::endl; - dir.clear(); + if (ac >= 3) { + dir = cmSystemTools::CollapseFullPath(av[2]); + + std::vector<std::string> inputArgs; + inputArgs.reserve(ac - 3); + cm::append(inputArgs, av + 3, av + ac); + for (decltype(inputArgs.size()) i = 0; i < inputArgs.size(); ++i) { + + std::string const& arg = inputArgs[i]; + for (auto const& m : arguments) { + if (m.matches(arg) && m.parse(arg, i, inputArgs)) { break; + } } } } diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index e2ff8b7..851205e 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -20,6 +20,7 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTransformDepfile.h" #include "cmUVProcessChain.h" #include "cmUtils.hxx" #include "cmVersion.h" @@ -28,12 +29,17 @@ #if !defined(CMAKE_BOOTSTRAP) # include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback. # include "cmFileTime.h" -# include "cmServer.h" -# include "cmServerConnection.h" # include "bindexplib.h" #endif +#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES) +# include <algorithm> + +# include "cmCMakePath.h" +# include "cmProcessTools.h" +#endif + #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) && !defined(__CYGWIN__) # include "cmVisualStudioWCEPlatformParser.h" #endif @@ -59,15 +65,15 @@ #include "cmsys/Directory.hxx" #include "cmsys/FStream.hxx" #include "cmsys/Process.h" +#include "cmsys/RegularExpression.hxx" #include "cmsys/Terminal.h" -class cmConnection; - int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd); int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, std::vector<std::string>::const_iterator argEnd); +namespace { void CMakeCommandUsage(const char* program) { std::ostringstream errorStream; @@ -121,7 +127,6 @@ void CMakeCommandUsage(const char* program) "(on one volume)\n" << " rm [-rRf] <file/dir>... - remove files or directories, use -f to " "force it, r or R to remove directories and their contents recursively\n" - << " server - start cmake in server mode\n" << " sleep <number>... - sleep for given number of seconds\n" << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n" << " - create or extract a tar or zip archive\n" @@ -147,8 +152,7 @@ void CMakeCommandUsage(const char* program) cmSystemTools::Error(errorStream.str()); } -static bool cmTarFilesFrom(std::string const& file, - std::vector<std::string>& files) +bool cmTarFilesFrom(std::string const& file, std::vector<std::string>& files) { if (cmSystemTools::FileIsDirectory(file)) { std::ostringstream e; @@ -183,7 +187,7 @@ static bool cmTarFilesFrom(std::string const& file, return true; } -static void cmCatFile(const std::string& fileToAppend) +void cmCatFile(const std::string& fileToAppend) { #ifdef _WIN32 _setmode(fileno(stdout), _O_BINARY); @@ -193,7 +197,7 @@ static void cmCatFile(const std::string& fileToAppend) std::cout << source.rdbuf(); } -static bool cmRemoveDirectory(const std::string& dir, bool recursive = true) +bool cmRemoveDirectory(const std::string& dir, bool recursive = true) { if (cmSystemTools::FileIsSymlink(dir)) { if (!cmSystemTools::RemoveFile(dir)) { @@ -211,9 +215,122 @@ static bool cmRemoveDirectory(const std::string& dir, bool recursive = true) return true; } -static int HandleIWYU(const std::string& runCmd, - const std::string& /* sourceFile */, - const std::vector<std::string>& orig_cmd) +#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES) +class CLIncludeParser : public cmProcessTools::LineParser +{ +public: + CLIncludeParser(cm::string_view includePrefix, cmsys::ofstream& depFile, + std::ostream& output) + : IncludePrefix(includePrefix) + , DepFile(depFile) + , Output(output) + { + } + +private: + bool ProcessLine() override + { + if (cmHasPrefix(this->Line, this->IncludePrefix)) { + auto path = + cmTrimWhitespace(this->Line.c_str() + this->IncludePrefix.size()); + cmSystemTools::ConvertToLongPath(path); + this->DepFile << cmCMakePath(path).GenericString() << std::endl; + } else { + this->Output << this->Line << std::endl << std::flush; + } + + return true; + } + + cm::string_view IncludePrefix; + cmsys::ofstream& DepFile; + std::ostream& Output; +}; + +class CLOutputLogger : public cmProcessTools::OutputLogger +{ +public: + CLOutputLogger(std::ostream& log) + : cmProcessTools::OutputLogger(log) + { + } + + bool ProcessLine() override + { + *this->Log << std::flush; + return true; + } +}; + +int CLCompileAndDependencies(const std::vector<std::string>& args) +{ + std::string depFile; + std::string currentBinaryDir; + std::string filterPrefix; + std::vector<std::string> command; + for (auto it = args.cbegin() + 2; it != args.cend(); it++) { + if (cmHasLiteralPrefix(*it, "--dep-file=")) { + depFile = it->substr(11); + } else if (cmHasLiteralPrefix(*it, "--working-dir=")) { + currentBinaryDir = it->substr(14); + } else if (cmHasLiteralPrefix(*it, "--filter-prefix=")) { + filterPrefix = it->substr(16); + } else if (*it == "--") { + command.insert(command.begin(), ++it, args.cend()); + break; + } else { + return 1; + } + } + + std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp( + cmsysProcess_New(), cmsysProcess_Delete); + std::vector<const char*> argv(command.size() + 1); + std::transform(command.begin(), command.end(), argv.begin(), + [](std::string const& s) { return s.c_str(); }); + argv.back() = nullptr; + cmsysProcess_SetCommand(cp.get(), argv.data()); + cmsysProcess_SetWorkingDirectory(cp.get(), currentBinaryDir.c_str()); + + cmsys::ofstream fout(depFile.c_str()); + if (!fout) { + return 3; + } + + CLIncludeParser includeParser(filterPrefix, fout, std::cout); + CLOutputLogger errLogger(std::cerr); + + // Start the process. + cmProcessTools::RunProcess(cp.get(), &includeParser, &errLogger); + + int status = 0; + // handle status of process + switch (cmsysProcess_GetState(cp.get())) { + case cmsysProcess_State_Exited: + status = cmsysProcess_GetExitValue(cp.get()); + break; + case cmsysProcess_State_Exception: + status = 1; + break; + case cmsysProcess_State_Error: + status = 2; + break; + default: + break; + } + + if (status != 0) { + // remove the dependencies file because potentially invalid + fout.close(); + cmSystemTools::RemoveFile(depFile); + } + + return status; +} +#endif + +int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */, + const std::vector<std::string>& orig_cmd) { // Construct the iwyu command line by taking what was given // and adding all the arguments we give to the compiler. @@ -238,8 +355,8 @@ static int HandleIWYU(const std::string& runCmd, return 0; } -static int HandleTidy(const std::string& runCmd, const std::string& sourceFile, - const std::vector<std::string>& orig_cmd) +int HandleTidy(const std::string& runCmd, const std::string& sourceFile, + const std::vector<std::string>& orig_cmd) { // Construct the clang-tidy command line by taking what was given // and adding our compiler command line. The clang-tidy tool will @@ -268,9 +385,8 @@ static int HandleTidy(const std::string& runCmd, const std::string& sourceFile, return ret; } -static int HandleLWYU(const std::string& runCmd, - const std::string& /* sourceFile */, - const std::vector<std::string>&) +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 @@ -301,9 +417,8 @@ static int HandleLWYU(const std::string& runCmd, return 0; } -static int HandleCppLint(const std::string& runCmd, - const std::string& sourceFile, - const std::vector<std::string>&) +int HandleCppLint(const std::string& runCmd, const std::string& sourceFile, + const std::vector<std::string>&) { // Construct the cpplint command line. std::vector<std::string> cpplint_cmd = cmExpandedList(runCmd, true); @@ -329,9 +444,8 @@ static int HandleCppLint(const std::string& runCmd, return 0; } -static int HandleCppCheck(const std::string& runCmd, - const std::string& sourceFile, - const std::vector<std::string>& orig_cmd) +int HandleCppCheck(const std::string& runCmd, const std::string& sourceFile, + const std::vector<std::string>& orig_cmd) { // Construct the cpplint command line. std::vector<std::string> cppcheck_cmd = cmExpandedList(runCmd, true); @@ -394,7 +508,7 @@ struct CoCompiler bool NoOriginalCommand; }; -static const std::array<CoCompiler, 5> CoCompilers = { +const std::array<CoCompiler, 5> CoCompilers = { { // Table of options and handlers. { "--cppcheck=", HandleCppCheck, false }, { "--cpplint=", HandleCppLint, false }, @@ -408,6 +522,7 @@ struct CoCompileJob std::string Command; CoCompileHandler Handler; }; +} // called when args[0] == "__run_co_compile" int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args) @@ -589,7 +704,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } else if (args[2] == "--ignore-eol") { filesDiffer = cmsys::SystemTools::TextFilesDiffer(args[3], args[4]); } else { - ::CMakeCommandUsage(args[0].c_str()); + CMakeCommandUsage(args[0].c_str()); return 2; } @@ -624,8 +739,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } } if (outValid) { - // The def file already exists and all input files are older than the - // existing def file. + // The def file already exists and all input files are older than + // the existing def file. return 0; } } @@ -1156,6 +1271,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, cmStateSnapshot snapshot = cm.GetCurrentSnapshot(); snapshot.GetDirectory().SetCurrentBinary(startOutDir); snapshot.GetDirectory().SetCurrentSource(startDir); + snapshot.GetDirectory().SetRelativePathTopSource(homeDir.c_str()); + snapshot.GetDirectory().SetRelativePathTopBinary(homeOutDir.c_str()); cmMakefile mf(cm.GetGlobalGenerator(), snapshot); auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf); @@ -1165,12 +1282,19 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, return 1; } +#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_MAKEFILES) + // Internal CMake compiler dependencies filtering + if (args[1] == "cmake_cl_compile_depends") { + return CLCompileAndDependencies(args); + } +#endif + // Internal CMake link script support. if (args[1] == "cmake_link_script" && args.size() >= 3) { return cmcmd::ExecuteLinkScript(args); } -#if !defined(CMAKE_BOOTSTRAP) || defined(CMAKE_BOOTSTRAP_NINJA) +#if !defined(CMAKE_BOOTSTRAP) // Internal CMake ninja dependency scanning support. if (args[1] == "cmake_ninja_depends") { return cmcmd_cmake_ninja_depends(args.begin() + 2, args.end()); @@ -1359,47 +1483,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } if (args[1] == "server") { - const std::string pipePrefix = "--pipe="; - bool supportExperimental = false; - bool isDebug = false; - std::string pipe; - - for (auto const& arg : cmMakeRange(args).advance(2)) { - if (arg == "--experimental") { - supportExperimental = true; - } else if (arg == "--debug") { - pipe.clear(); - isDebug = true; - } else if (cmHasPrefix(arg, pipePrefix)) { - isDebug = false; - pipe = arg.substr(pipePrefix.size()); - if (pipe.empty()) { - cmSystemTools::Error("No pipe given after --pipe="); - return 2; - } - } else { - cmSystemTools::Error("Unknown argument for server mode"); - return 1; - } - } -#if !defined(CMAKE_BOOTSTRAP) - cmConnection* conn; - if (isDebug) { - conn = new cmServerStdIoConnection; - } else { - conn = new cmServerPipeConnection(pipe); - } - cmServer server(conn, supportExperimental); - std::string errorMessage; - if (server.Serve(&errorMessage)) { - return 0; - } - cmSystemTools::Error(errorMessage); -#else - static_cast<void>(supportExperimental); - static_cast<void>(isDebug); - cmSystemTools::Error("CMake was not built with server mode enabled"); -#endif + cmSystemTools::Error( + "CMake server mode has been removed in favor of the file-api."); return 1; } @@ -1435,9 +1520,26 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, return cmcmd::WindowsCEEnvironment("9.0", args[2]); } #endif + + // Internal depfile transformation + if (args[1] == "cmake_transform_depfile" && args.size() == 6) { + auto format = cmDepfileFormat::GccDepfile; + if (args[2] == "gccdepfile") { + format = cmDepfileFormat::GccDepfile; + } else if (args[2] == "vstlog") { + format = cmDepfileFormat::VsTlog; + } else { + return 1; + } + std::string prefix = args[3]; + if (prefix == "./") { + prefix.clear(); + } + return cmTransformDepfile(format, prefix, args[4], args[5]) ? 0 : 1; + } } - ::CMakeCommandUsage(args[0].c_str()); + CMakeCommandUsage(args[0].c_str()); return 1; } @@ -1737,7 +1839,6 @@ int cmcmd::WindowsCEEnvironment(const char* version, const std::string& name) int cmcmd::RunPreprocessor(const std::vector<std::string>& command, const std::string& intermediate_file) { - cmUVProcessChainBuilder builder; uv_fs_t fs_req; @@ -1769,7 +1870,6 @@ int cmcmd::RunPreprocessor(const std::vector<std::string>& command, return 1; } - return 0; } @@ -1787,19 +1887,56 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args) std::cerr << "Invalid cmake_llvm_rc arguments"; return 1; } + const std::string& intermediate_file = args[3]; const std::string& source_file = args[2]; std::vector<std::string> preprocess; std::vector<std::string> resource_compile; std::vector<std::string>* pArgTgt = &preprocess; + + static const cmsys::RegularExpression llvm_rc_only_single_arg("^[-/](N|Y)"); + static const cmsys::RegularExpression llvm_rc_only_double_arg( + "^[-/](C|LN|L)(.)?"); + static const cmsys::RegularExpression common_double_arg( + "^[-/](D|U|I|FO|fo|Fo)(.)?"); + bool acceptNextArg = false; + bool skipNextArg = false; for (std::string const& arg : cmMakeRange(args).advance(4)) { - // We use ++ as seperator between the preprocessing step definition and the - // rc compilation step becase we need to prepend a -- to seperate the + if (skipNextArg) { + skipNextArg = false; + continue; + } + // We use ++ as seperator between the preprocessing step definition and + // the rc compilation step becase we need to prepend a -- to seperate the // source file properly from other options when using clang-cl for // preprocessing. if (arg == "++") { pArgTgt = &resource_compile; + skipNextArg = false; + acceptNextArg = true; } else { + cmsys::RegularExpressionMatch match; + if (!acceptNextArg) { + if (common_double_arg.find(arg.c_str(), match)) { + acceptNextArg = match.match(2).empty(); + } else { + if (llvm_rc_only_single_arg.find(arg.c_str(), match)) { + if (pArgTgt == &preprocess) { + continue; + } + } else if (llvm_rc_only_double_arg.find(arg.c_str(), match)) { + if (pArgTgt == &preprocess) { + skipNextArg = match.match(2).empty(); + continue; + } + acceptNextArg = match.match(2).empty(); + } else if (pArgTgt == &resource_compile) { + continue; + } + } + } else { + acceptNextArg = false; + } if (arg.find("SOURCE_DIR") != std::string::npos) { std::string sourceDirArg = arg; cmSystemTools::ReplaceString( @@ -1819,10 +1956,15 @@ int cmcmd::RunLLVMRC(std::vector<std::string> const& args) std::cerr << "Empty resource compilation command"; return 1; } + // Since we might have skipped the last argument to llvm-rc + // we need to make sure the llvm-rc source file is present in the + // commandline + if (resource_compile.back() != intermediate_file) { + resource_compile.push_back(intermediate_file); + } auto result = RunPreprocessor(preprocess, intermediate_file); if (result != 0) { - cmSystemTools::RemoveFile(intermediate_file); return result; } @@ -1986,7 +2128,7 @@ static bool RunCommand(const char* comment, << NumberFormatter(exitFormat, retCode) << ") with the following output:\n" << output; - } else { + } else if (verbose) { // always print the output of the command, unless // it is the dumb rc command banner if (output.find("Resource Compiler Version") == std::string::npos) { @@ -2084,7 +2226,7 @@ int cmVSLink::Link() if (this->Verbose) { std::cout << "Visual Studio Incremental Link with embedded manifests\n"; } - return LinkIncremental(); + return this->LinkIncremental(); } if (this->Verbose) { if (!this->Incremental) { @@ -2093,7 +2235,7 @@ int cmVSLink::Link() std::cout << "Visual Studio Incremental Link without manifests\n"; } } - return LinkNonIncremental(); + return this->LinkNonIncremental(); } static bool mtRetIsUpdate(int mtRet) @@ -2109,8 +2251,8 @@ int cmVSLink::LinkIncremental() // http://blogs.msdn.com/zakramer/archive/2006/05/22/603558.aspx // 1. Compiler compiles the application and generates the *.obj files. - // 2. An empty manifest file is generated if this is a clean build and if - // not the previous one is reused. + // 2. An empty manifest file is generated if this is a clean build and + // if not the previous one is reused. // 3. The resource compiler (rc.exe) compiles the *.manifest file to a // *.res file. // 4. Linker generates the binary (EXE or DLL) with the /incremental diff --git a/Source/ctest.cxx b/Source/ctest.cxx index d0bc061..600df1d 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -111,6 +111,7 @@ static const char* cmDocumentationOptions[][2] = { { "--no-subproject-summary", "Disable timing summary information for " "subprojects." }, + { "--test-dir <dir>", "Specify the directory in which to look for tests." }, { "--build-and-test", "Configure, build and run a test." }, { "--build-target", "Specify a specific target to build." }, { "--build-nocmake", "Run the build without running cmake first." }, diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index 9c34a56..9607c00 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -447,6 +447,7 @@ public: Motorola, HP, Hygon, + Zhaoxin, UnknownManufacturer }; @@ -1731,7 +1732,8 @@ const char* SystemInformationImplementation::GetVendorID() case NexGen: return "NexGen Inc., Advanced Micro Devices"; case IDT: - return "IDT\\Centaur, Via Inc."; + return "IDT\\Centaur, Via Inc., Shanghai Zhaoxin Semiconductor Co., " + "Ltd."; case UMC: return "United Microelectronics Corp."; case Rise: @@ -1748,6 +1750,8 @@ const char* SystemInformationImplementation::GetVendorID() return "Hewlett-Packard"; case Hygon: return "Chengdu Haiguang IC Design Co., Ltd."; + case Zhaoxin: + return "Shanghai Zhaoxin Semiconductor Co., Ltd."; case UnknownManufacturer: default: return "Unknown Manufacturer"; @@ -2109,7 +2113,10 @@ void SystemInformationImplementation::FindManufacturer( else if (this->ChipID.Vendor == "NexGenDriven") this->ChipManufacturer = NexGen; // NexGen Inc. (now AMD) else if (this->ChipID.Vendor == "CentaurHauls") - this->ChipManufacturer = IDT; // IDT/Centaur (now VIA) + this->ChipManufacturer = IDT; // original IDT/Centaur/VIA (now Zhaoxin) + else if (this->ChipID.Vendor == " Shanghai ") + this->ChipManufacturer = + Zhaoxin; // Shanghai Zhaoxin Semiconductor Co., Ltd. else if (this->ChipID.Vendor == "RiseRiseRise") this->ChipManufacturer = Rise; // Rise else if (this->ChipID.Vendor == "GenuineTMx86") @@ -3223,7 +3230,8 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() this->ChipID.ProcessorName = "C3"; break; default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + this->ChipID.ProcessorName = + "Unknown IDT\\Centaur\\VIA\\Zhaoxin family"; return false; } break; @@ -3232,13 +3240,63 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() case 6: this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; break; + case 0xf: + this->ChipID.ProcessorName = "Zhaoxin zxc"; + break; + default: + this->ChipID.ProcessorName = + "Unknown IDT\\Centaur\\VIA\\Zhaoxin family"; + return false; + } + break; + case 7: + switch (this->ChipID.Model) { + case 0x1b: + this->ChipID.ProcessorName = "Zhaoxin kx5000"; + break; + case 0x3b: + this->ChipID.ProcessorName = "Zhaoxin kx6000"; + break; + default: + this->ChipID.ProcessorName = + "Unknown IDT\\Centaur\\VIA\\Zhaoxin family"; + return false; + } + break; + default: + this->ChipID.ProcessorName = + "Unknown IDT\\Centaur\\VIA\\Zhaoxin family"; + return false; + } + break; + + case Zhaoxin: + switch (this->ChipID.Family) { + case 6: + switch (this->ChipID.Model) { + case 0x19: + this->ChipID.ProcessorName = "Zhaoxin zxc"; + break; + default: + this->ChipID.ProcessorName = "Unknown Zhaoxin family"; + return false; + } + break; + case 7: + switch (this->ChipID.Model) { + case 0x1b: + this->ChipID.ProcessorName = "Zhaoxin kx5000"; + break; + case 0x3b: + this->ChipID.ProcessorName = "Zhaoxin kx6000"; + break; default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + this->ChipID.ProcessorName = "Unknown Zhaoxin family"; return false; } break; default: - this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; + this->ChipID.ProcessorName = "Unknown Zhaoxin family"; return false; } break; |