diff options
Diffstat (limited to 'Source')
321 files changed, 9473 insertions, 5211 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c8498a9..ddcdd7e 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -155,16 +155,20 @@ set(SRCS cmBinUtilsWindowsPELinker.h cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.cxx cmBinUtilsWindowsPEObjdumpGetRuntimeDependenciesTool.h + cmBuildOptions.h cmCacheManager.cxx cmCacheManager.h cmCLocaleEnvironmentScope.h cmCLocaleEnvironmentScope.cxx cmCMakePath.h cmCMakePath.cxx - cmCMakePresetsFile.cxx - cmCMakePresetsFile.h - cmCMakePresetsFileInternal.h - cmCMakePresetsFileReadJSON.cxx + cmCMakePresetsGraph.cxx + cmCMakePresetsGraph.h + cmCMakePresetsGraphInternal.h + cmCMakePresetsGraphReadJSON.cxx + cmCMakePresetsGraphReadJSONBuildPresets.cxx + cmCMakePresetsGraphReadJSONConfigurePresets.cxx + cmCMakePresetsGraphReadJSONTestPresets.cxx cmCommandArgumentParserHelper.cxx cmCommonTargetGenerator.cxx cmCommonTargetGenerator.h @@ -261,6 +265,8 @@ set(SRCS cmFileLockResult.h cmFilePathChecksum.cxx cmFilePathChecksum.h + cmFileSet.cxx + cmFileSet.h cmFileTime.cxx cmFileTime.h cmFileTimeCache.cxx @@ -316,6 +322,8 @@ set(SRCS cmInstallExportGenerator.cxx cmInstalledFile.h cmInstalledFile.cxx + cmInstallFileSetGenerator.h + cmInstallFileSetGenerator.cxx cmInstallFilesGenerator.h cmInstallFilesGenerator.cxx cmInstallImportedRuntimeArtifactsGenerator.h @@ -762,6 +770,7 @@ if (WIN32) cmGlobalVisualStudio9Generator.h cmVisualStudioGeneratorOptions.h cmVisualStudioGeneratorOptions.cxx + cmVsProjectType.h cmVisualStudio10TargetGenerator.h cmVisualStudio10TargetGenerator.cxx cmLocalVisualStudio10Generator.cxx @@ -1105,7 +1114,6 @@ if(APPLE) set(CPACK_SRCS ${CPACK_SRCS} CPack/cmCPackBundleGenerator.cxx CPack/cmCPackDragNDropGenerator.cxx - CPack/cmCPackOSXX11Generator.cxx CPack/cmCPackPKGGenerator.cxx CPack/cmCPackPackageMakerGenerator.cxx CPack/cmCPackProductBuildGenerator.cxx @@ -1142,13 +1150,6 @@ if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARI add_definitions(-DHAVE_FREEBSD_PKG) endif() -if(APPLE) - add_executable(OSXScriptLauncher - CPack/OSXScriptLauncher.cxx) - target_link_libraries(OSXScriptLauncher cmsys) - target_link_libraries(OSXScriptLauncher "-framework CoreFoundation") -endif() - # Build CMake executable add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE}) list(APPEND _tools cmake) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 646b63d..7cd4433 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,8 +1,8 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) -set(CMake_VERSION_MINOR 22) -set(CMake_VERSION_PATCH 2) -#set(CMake_VERSION_RC 0) +set(CMake_VERSION_MINOR 23) +set(CMake_VERSION_PATCH 0) +set(CMake_VERSION_RC 2) set(CMake_VERSION_IS_DIRTY 0) # Start with the full version number used in tags. It has no dev info. diff --git a/Source/CPack/IFW/cmCPackIFWCommon.cxx b/Source/CPack/IFW/cmCPackIFWCommon.cxx index f6b8a8a..5d995c3 100644 --- a/Source/CPack/IFW/cmCPackIFWCommon.cxx +++ b/Source/CPack/IFW/cmCPackIFWCommon.cxx @@ -29,19 +29,18 @@ cmValue cmCPackIFWCommon::GetOption(const std::string& op) const bool cmCPackIFWCommon::IsOn(const std::string& op) const { - return this->Generator ? this->Generator->cmCPackGenerator::IsOn(op) : false; + return this->Generator && this->Generator->cmCPackGenerator::IsOn(op); } bool cmCPackIFWCommon::IsSetToOff(const std::string& op) const { - return this->Generator ? this->Generator->cmCPackGenerator::IsSetToOff(op) - : false; + return this->Generator && this->Generator->cmCPackGenerator::IsSetToOff(op); } bool cmCPackIFWCommon::IsSetToEmpty(const std::string& op) const { - return this->Generator ? this->Generator->cmCPackGenerator::IsSetToEmpty(op) - : false; + return this->Generator && + this->Generator->cmCPackGenerator::IsSetToEmpty(op); } bool cmCPackIFWCommon::IsVersionLess(const char* version) const diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx index b375ba6..9ca7a69 100644 --- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx +++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx @@ -38,202 +38,266 @@ int cmCPackIFWGenerator::PackageFiles() std::string ifwTLD = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); std::string ifwTmpFile = cmStrCat(ifwTLD, "/IFWOutput.log"); - // Run repogen - if (!this->Installer.RemoteRepositories.empty()) { - std::vector<std::string> ifwCmd; - std::string ifwArg; + // Create repositories + if (!this->RunRepogen(ifwTmpFile)) { + return 0; + } + + // Create installer + if (!this->RunBinaryCreator(ifwTmpFile)) { + return 0; + } + + return 1; +} + +std::vector<std::string> cmCPackIFWGenerator::BuildRepogenCommand() +{ + std::vector<std::string> ifwCmd; + std::string ifwArg; - ifwCmd.emplace_back(this->RepoGen); + ifwCmd.emplace_back(this->RepoGen); - if (this->IsVersionLess("2.0.0")) { - ifwCmd.emplace_back("-c"); - ifwCmd.emplace_back(this->toplevel + "/config/config.xml"); + if (!this->IsVersionLess("4.2")) { + if (!this->ArchiveFormat.empty()) { + ifwCmd.emplace_back("--archive-format"); + ifwCmd.emplace_back(this->ArchiveFormat); + } + if (!this->ArchiveCompression.empty()) { + ifwCmd.emplace_back("--compression"); + ifwCmd.emplace_back(this->ArchiveCompression); } + } - ifwCmd.emplace_back("-p"); - ifwCmd.emplace_back(this->toplevel + "/packages"); + if (this->IsVersionLess("2.0.0")) { + ifwCmd.emplace_back("-c"); + ifwCmd.emplace_back(this->toplevel + "/config/config.xml"); + } - if (!this->PkgsDirsVector.empty()) { - for (std::string const& it : this->PkgsDirsVector) { - ifwCmd.emplace_back("-p"); - ifwCmd.emplace_back(it); - } + ifwCmd.emplace_back("-p"); + ifwCmd.emplace_back(this->toplevel + "/packages"); + + if (!this->PkgsDirsVector.empty()) { + for (std::string const& it : this->PkgsDirsVector) { + ifwCmd.emplace_back("-p"); + ifwCmd.emplace_back(it); } + } - if (!this->RepoDirsVector.empty()) { - if (!this->IsVersionLess("3.1")) { - for (std::string const& rd : this->RepoDirsVector) { - ifwCmd.emplace_back("--repository"); - ifwCmd.emplace_back(rd); - } - } else { - cmCPackIFWLogger(WARNING, - "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " - << "variable is set, but content will be skipped, " - << "because this feature available only since " - << "QtIFW 3.1. Please update your QtIFW instance." - << std::endl); + if (!this->RepoDirsVector.empty()) { + if (!this->IsVersionLess("3.1")) { + for (std::string const& rd : this->RepoDirsVector) { + ifwCmd.emplace_back("--repository"); + ifwCmd.emplace_back(rd); } + } else { + cmCPackIFWLogger(WARNING, + "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " + << "variable is set, but content will be skipped, " + << "because this feature available only since " + << "QtIFW 3.1. Please update your QtIFW instance." + << std::endl); } + } - if (!this->OnlineOnly && !this->DownloadedPackages.empty()) { - ifwCmd.emplace_back("-i"); - auto it = this->DownloadedPackages.begin(); - ifwArg = (*it)->Name; + if (!this->OnlineOnly && !this->DownloadedPackages.empty()) { + ifwCmd.emplace_back("-i"); + auto it = this->DownloadedPackages.begin(); + ifwArg = (*it)->Name; + ++it; + while (it != this->DownloadedPackages.end()) { + ifwArg += "," + (*it)->Name; ++it; - while (it != this->DownloadedPackages.end()) { - ifwArg += "," + (*it)->Name; - ++it; - } - ifwCmd.emplace_back(ifwArg); - } - ifwCmd.emplace_back(this->toplevel + "/repository"); - cmCPackIFWLogger(VERBOSE, - "Execute: " << cmSystemTools::PrintSingleCommand(ifwCmd) - << std::endl); - std::string output; - int retVal = 1; - cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl); - bool res = cmSystemTools::RunSingleCommand( - ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose, - cmDuration::zero()); - if (!res || retVal) { - cmGeneratedFileStream ofs(ifwTmpFile); - ofs << "# Run command: " << cmSystemTools::PrintSingleCommand(ifwCmd) - << std::endl - << "# Output:" << std::endl - << output << std::endl; - cmCPackIFWLogger( - ERROR, - "Problem running IFW command: " - << cmSystemTools::PrintSingleCommand(ifwCmd) << std::endl - << "Please check \"" << ifwTmpFile << "\" for errors" << std::endl); - return 0; } + ifwCmd.emplace_back(ifwArg); + } + ifwCmd.emplace_back(this->toplevel + "/repository"); - if (!this->Repository.RepositoryUpdate.empty() && - !this->Repository.PatchUpdatesXml()) { - cmCPackIFWLogger(WARNING, - "Problem patch IFW \"Updates\" " - << "file: \"" << this->toplevel - << "/repository/Updates.xml\"" << std::endl); - } + return ifwCmd; +} - cmCPackIFWLogger(OUTPUT, - "- repository: \"" << this->toplevel - << "/repository\" generated" - << std::endl); +int cmCPackIFWGenerator::RunRepogen(const std::string& ifwTmpFile) +{ + if (this->Installer.RemoteRepositories.empty()) { + return 1; + } + + std::vector<std::string> ifwCmd = this->BuildRepogenCommand(); + cmCPackIFWLogger(VERBOSE, + "Execute: " << cmSystemTools::PrintSingleCommand(ifwCmd) + << std::endl); + std::string output; + int retVal = 1; + cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl); + bool res = cmSystemTools::RunSingleCommand(ifwCmd, &output, &output, &retVal, + nullptr, this->GeneratorVerbose, + cmDuration::zero()); + if (!res || retVal) { + cmGeneratedFileStream ofs(ifwTmpFile); + ofs << "# Run command: " << cmSystemTools::PrintSingleCommand(ifwCmd) + << std::endl + << "# Output:" << std::endl + << output << std::endl; + cmCPackIFWLogger( + ERROR, + "Problem running IFW command: " + << cmSystemTools::PrintSingleCommand(ifwCmd) << std::endl + << "Please check \"" << ifwTmpFile << "\" for errors" << std::endl); + return 0; } - // Run binary creator - { - std::vector<std::string> ifwCmd; - std::string ifwArg; + if (!this->Repository.RepositoryUpdate.empty() && + !this->Repository.PatchUpdatesXml()) { + cmCPackIFWLogger(WARNING, + "Problem patch IFW \"Updates\" " + << "file: \"" << this->toplevel + << "/repository/Updates.xml\"" << std::endl); + } - ifwCmd.emplace_back(this->BinCreator); + cmCPackIFWLogger(OUTPUT, + "- repository: \"" << this->toplevel + << "/repository\" generated" + << std::endl); + return 1; +} - ifwCmd.emplace_back("-c"); - ifwCmd.emplace_back(this->toplevel + "/config/config.xml"); +std::vector<std::string> cmCPackIFWGenerator::BuildBinaryCreatorCommmand() +{ + std::vector<std::string> ifwCmd; + std::string ifwArg; + + ifwCmd.emplace_back(this->BinCreator); + + if (!this->IsVersionLess("4.2")) { + if (!this->ArchiveFormat.empty()) { + ifwCmd.emplace_back("--archive-format"); + ifwCmd.emplace_back(this->ArchiveFormat); + } + if (!this->ArchiveCompression.empty()) { + ifwCmd.emplace_back("--compression"); + ifwCmd.emplace_back(this->ArchiveCompression); + } + } + + if (!this->IsVersionLess("3.0")) { +#ifdef __APPLE__ + // macOS only + std::string signingIdentity = this->Installer.SigningIdentity; + if (!signingIdentity.empty()) { + ifwCmd.emplace_back("--sign"); + ifwCmd.emplace_back(signingIdentity); + } +#endif + } - if (!this->Installer.Resources.empty()) { - ifwCmd.emplace_back("-r"); - auto it = this->Installer.Resources.begin(); - std::string path = this->toplevel + "/resources/"; - ifwArg = path + *it; + ifwCmd.emplace_back("-c"); + ifwCmd.emplace_back(this->toplevel + "/config/config.xml"); + + if (!this->Installer.Resources.empty()) { + ifwCmd.emplace_back("-r"); + auto it = this->Installer.Resources.begin(); + std::string path = this->toplevel + "/resources/"; + ifwArg = path + *it; + ++it; + while (it != this->Installer.Resources.end()) { + ifwArg += "," + path + *it; ++it; - while (it != this->Installer.Resources.end()) { - ifwArg += "," + path + *it; - ++it; - } - ifwCmd.emplace_back(ifwArg); } + ifwCmd.emplace_back(ifwArg); + } - ifwCmd.emplace_back("-p"); - ifwCmd.emplace_back(this->toplevel + "/packages"); + ifwCmd.emplace_back("-p"); + ifwCmd.emplace_back(this->toplevel + "/packages"); - if (!this->PkgsDirsVector.empty()) { - for (std::string const& it : this->PkgsDirsVector) { - ifwCmd.emplace_back("-p"); - ifwCmd.emplace_back(it); - } + if (!this->PkgsDirsVector.empty()) { + for (std::string const& it : this->PkgsDirsVector) { + ifwCmd.emplace_back("-p"); + ifwCmd.emplace_back(it); } + } - if (!this->RepoDirsVector.empty()) { - if (!this->IsVersionLess("3.1")) { - for (std::string const& rd : this->RepoDirsVector) { - ifwCmd.emplace_back("--repository"); - ifwCmd.emplace_back(rd); - } - } else { - cmCPackIFWLogger(WARNING, - "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " - << "variable is set, but content will be skipped, " - << "because this feature available only since " - << "QtIFW 3.1. Please update your QtIFW instance." - << std::endl); + if (!this->RepoDirsVector.empty()) { + if (!this->IsVersionLess("3.1")) { + for (std::string const& rd : this->RepoDirsVector) { + ifwCmd.emplace_back("--repository"); + ifwCmd.emplace_back(rd); } + } else { + cmCPackIFWLogger(WARNING, + "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " + << "variable is set, but content will be skipped, " + << "because this feature available only since " + << "QtIFW 3.1. Please update your QtIFW instance." + << std::endl); } + } - if (this->OnlineOnly) { - ifwCmd.emplace_back("--online-only"); - } else if (!this->DownloadedPackages.empty() && - !this->Installer.RemoteRepositories.empty()) { - ifwCmd.emplace_back("-e"); - auto it = this->DownloadedPackages.begin(); - ifwArg = (*it)->Name; + if (this->OnlineOnly) { + ifwCmd.emplace_back("--online-only"); + } else if (!this->DownloadedPackages.empty() && + !this->Installer.RemoteRepositories.empty()) { + ifwCmd.emplace_back("-e"); + auto it = this->DownloadedPackages.begin(); + ifwArg = (*it)->Name; + ++it; + while (it != this->DownloadedPackages.end()) { + ifwArg += "," + (*it)->Name; ++it; - while (it != this->DownloadedPackages.end()) { - ifwArg += "," + (*it)->Name; - ++it; - } - ifwCmd.emplace_back(ifwArg); - } else if (!this->DependentPackages.empty()) { - ifwCmd.emplace_back("-i"); - ifwArg.clear(); - // Binary - auto bit = this->BinaryPackages.begin(); - while (bit != this->BinaryPackages.end()) { - ifwArg += (*bit)->Name + ","; - ++bit; - } - // Depend - auto it = this->DependentPackages.begin(); - ifwArg += it->second.Name; - ++it; - while (it != this->DependentPackages.end()) { - ifwArg += "," + it->second.Name; - ++it; - } - ifwCmd.emplace_back(ifwArg); } - // TODO: set correct name for multipackages - if (!this->packageFileNames.empty()) { - ifwCmd.emplace_back(this->packageFileNames[0]); - } else { - ifwCmd.emplace_back("installer" + this->OutputExtension); + ifwCmd.emplace_back(ifwArg); + } else if (!this->DependentPackages.empty()) { + ifwCmd.emplace_back("-i"); + ifwArg.clear(); + // Binary + auto bit = this->BinaryPackages.begin(); + while (bit != this->BinaryPackages.end()) { + ifwArg += (*bit)->Name + ","; + ++bit; } - cmCPackIFWLogger(VERBOSE, - "Execute: " << cmSystemTools::PrintSingleCommand(ifwCmd) - << std::endl); - std::string output; - int retVal = 1; - cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl); - bool res = cmSystemTools::RunSingleCommand( - ifwCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose, - cmDuration::zero()); - if (!res || retVal) { - cmGeneratedFileStream ofs(ifwTmpFile); - ofs << "# Run command: " << cmSystemTools::PrintSingleCommand(ifwCmd) - << std::endl - << "# Output:" << std::endl - << output << std::endl; - cmCPackIFWLogger( - ERROR, - "Problem running IFW command: " - << cmSystemTools::PrintSingleCommand(ifwCmd) << std::endl - << "Please check \"" << ifwTmpFile << "\" for errors" << std::endl); - return 0; + // Depend + auto it = this->DependentPackages.begin(); + ifwArg += it->second.Name; + ++it; + while (it != this->DependentPackages.end()) { + ifwArg += "," + it->second.Name; + ++it; } + ifwCmd.emplace_back(ifwArg); + } + // TODO: set correct name for multipackages + if (!this->packageFileNames.empty()) { + ifwCmd.emplace_back(this->packageFileNames[0]); + } else { + ifwCmd.emplace_back("installer" + this->OutputExtension); + } + + return ifwCmd; +} + +int cmCPackIFWGenerator::RunBinaryCreator(const std::string& ifwTmpFile) +{ + std::vector<std::string> ifwCmd = this->BuildBinaryCreatorCommmand(); + cmCPackIFWLogger(VERBOSE, + "Execute: " << cmSystemTools::PrintSingleCommand(ifwCmd) + << std::endl); + std::string output; + int retVal = 1; + cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl); + bool res = cmSystemTools::RunSingleCommand(ifwCmd, &output, &output, &retVal, + nullptr, this->GeneratorVerbose, + cmDuration::zero()); + if (!res || retVal) { + cmGeneratedFileStream ofs(ifwTmpFile); + ofs << "# Run command: " << cmSystemTools::PrintSingleCommand(ifwCmd) + << std::endl + << "# Output:" << std::endl + << output << std::endl; + cmCPackIFWLogger( + ERROR, + "Problem running IFW command: " + << cmSystemTools::PrintSingleCommand(ifwCmd) << std::endl + << "Please check \"" << ifwTmpFile << "\" for errors" << std::endl); + return 0; } return 1; @@ -323,6 +387,14 @@ int cmCPackIFWGenerator::InitializeInternal() cmExpandList(dirs, this->RepoDirsVector); } + // Archive format and compression level + if (cmValue af = this->GetOption("CPACK_IFW_ARCHIVE_FORMAT")) { + this->ArchiveFormat = *af; + } + if (cmValue ac = this->GetOption("CPACK_IFW_ARCHIVE_COMPRESSION")) { + this->ArchiveCompression = *ac; + } + // Installer this->Installer.Generator = this; this->Installer.ConfigureFromOptions(); diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.h b/Source/CPack/IFW/cmCPackIFWGenerator.h index 024d25d..86b4993 100644 --- a/Source/CPack/IFW/cmCPackIFWGenerator.h +++ b/Source/CPack/IFW/cmCPackIFWGenerator.h @@ -9,13 +9,15 @@ #include <string> #include <vector> -#include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" #include "cmCPackIFWCommon.h" #include "cmCPackIFWInstaller.h" #include "cmCPackIFWPackage.h" #include "cmCPackIFWRepository.h" +class cmCPackComponent; +class cmCPackComponentGroup; + /** \class cmCPackIFWGenerator * \brief A generator for Qt Installer Framework tools * @@ -30,8 +32,6 @@ public: using PackagesMap = std::map<std::string, cmCPackIFWPackage>; using RepositoriesMap = std::map<std::string, cmCPackIFWRepository>; - using ComponentsMap = std::map<std::string, cmCPackComponent>; - using ComponentGoupsMap = std::map<std::string, cmCPackComponentGroup>; using DependenceMap = std::map<std::string, cmCPackIFWPackage::DependenceStruct>; @@ -140,14 +140,22 @@ protected: std::map<cmCPackComponentGroup*, cmCPackIFWPackage*> GroupPackages; private: + std::vector<std::string> BuildRepogenCommand(); + int RunRepogen(const std::string& ifwTmpFile); + + std::vector<std::string> BuildBinaryCreatorCommmand(); + int RunBinaryCreator(const std::string& ifwTmpFile); + std::string RepoGen; std::string BinCreator; std::string FrameworkVersion; std::string ExecutableSuffix; std::string OutputExtension; + std::string ArchiveFormat; + std::string ArchiveCompression; - bool OnlineOnly; - bool ResolveDuplicateNames; + bool OnlineOnly{}; + bool ResolveDuplicateNames{}; std::vector<std::string> PkgsDirsVector; std::vector<std::string> RepoDirsVector; }; diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index 7ee6300..6fc4848 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -254,6 +254,16 @@ void cmCPackIFWInstaller::ConfigureFromOptions() } } + // DisableCommandLineInterface + if (this->GetOption("CPACK_IFW_PACKAGE_DISABLE_COMMAND_LINE_INTERFACE")) { + if (this->IsOn("CPACK_IFW_PACKAGE_DISABLE_COMMAND_LINE_INTERFACE")) { + this->DisableCommandLineInterface = "true"; + } else if (this->IsSetToOff( + "CPACK_IFW_PACKAGE_DISABLE_COMMAND_LINE_INTERFACE")) { + this->DisableCommandLineInterface = "false"; + } + } + // Space in path if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) { if (this->IsOn("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) { @@ -275,6 +285,34 @@ void cmCPackIFWInstaller::ConfigureFromOptions() this->Resources.clear(); cmExpandList(optIFW_PACKAGE_RESOURCES, this->Resources); } + + // ProductImages + if (cmValue productImages = + this->GetOption("CPACK_IFW_PACKAGE_PRODUCT_IMAGES")) { + this->ProductImages.clear(); + cmExpandList(productImages, this->ProductImages); + } + + // Run program, run program arguments, and run program description + if (cmValue program = this->GetOption("CPACK_IFW_PACKAGE_RUN_PROGRAM")) { + this->RunProgram = *program; + } + if (cmValue arguments = + this->GetOption("CPACK_IFW_PACKAGE_RUN_PROGRAM_ARGUMENTS")) { + this->RunProgramArguments.clear(); + cmExpandList(arguments, this->RunProgramArguments); + } + if (cmValue description = + this->GetOption("CPACK_IFW_PACKAGE_RUN_PROGRAM_DESCRIPTION")) { + this->RunProgramDescription = *description; + } + +#ifdef __APPLE__ + // Code signing identity for signing the generated app bundle + if (cmValue id = this->GetOption("CPACK_IFW_PACKAGE_SIGNING_IDENTITY")) { + this->SigningIdentity = *id; + } +#endif } /** \class cmCPackIFWResourcesParser @@ -362,29 +400,11 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.Element("ProductUrl", this->ProductUrl); } - // ApplicationIcon - if (!this->InstallerApplicationIcon.empty()) { - std::string name = - cmSystemTools::GetFilenameName(this->InstallerApplicationIcon); - std::string path = this->Directory + "/config/" + name; - name = cmSystemTools::GetFilenameWithoutExtension(name); - cmsys::SystemTools::CopyFileIfDifferent(this->InstallerApplicationIcon, - path); - xout.Element("InstallerApplicationIcon", name); - } - - // WindowIcon - if (!this->InstallerWindowIcon.empty()) { - std::string name = - cmSystemTools::GetFilenameName(this->InstallerWindowIcon); - std::string path = this->Directory + "/config/" + name; - cmsys::SystemTools::CopyFileIfDifferent(this->InstallerWindowIcon, path); - xout.Element("InstallerWindowIcon", name); - } - // Logo if (!this->Logo.empty()) { - std::string name = cmSystemTools::GetFilenameName(this->Logo); + std::string srcName = cmSystemTools::GetFilenameName(this->Logo); + std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName); + std::string name = "cm_logo." + suffix; std::string path = this->Directory + "/config/" + name; cmsys::SystemTools::CopyFileIfDifferent(this->Logo, path); xout.Element("Logo", name); @@ -414,42 +434,81 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.Element("Background", name); } - // WizardStyle - if (!this->WizardStyle.empty()) { - xout.Element("WizardStyle", this->WizardStyle); - } + // Attributes introduced in QtIFW 1.4.0 + if (!this->IsVersionLess("1.4")) { + // ApplicationIcon + if (!this->InstallerApplicationIcon.empty()) { + std::string srcName = + cmSystemTools::GetFilenameName(this->InstallerApplicationIcon); + std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName); + std::string name = "cm_appicon." + suffix; + std::string path = this->Directory + "/config/" + name; + cmsys::SystemTools::CopyFileIfDifferent(this->InstallerApplicationIcon, + path); + // The actual file is looked up by attaching a '.icns' (macOS), + // '.ico' (Windows). No functionality on Unix. + name = cmSystemTools::GetFilenameWithoutExtension(name); + xout.Element("InstallerApplicationIcon", name); + } - // Stylesheet - if (!this->StyleSheet.empty()) { - std::string name = cmSystemTools::GetFilenameName(this->StyleSheet); - std::string path = this->Directory + "/config/" + name; - cmsys::SystemTools::CopyFileIfDifferent(this->StyleSheet, path); - xout.Element("StyleSheet", name); + // WindowIcon + if (!this->InstallerWindowIcon.empty()) { + std::string srcName = + cmSystemTools::GetFilenameName(this->InstallerWindowIcon); + std::string suffix = cmSystemTools::GetFilenameLastExtension(srcName); + std::string name = "cm_winicon." + suffix; + std::string path = this->Directory + "/config/" + name; + cmsys::SystemTools::CopyFileIfDifferent(this->InstallerWindowIcon, path); + xout.Element("InstallerWindowIcon", name); + } } - // WizardDefaultWidth - if (!this->WizardDefaultWidth.empty()) { - xout.Element("WizardDefaultWidth", this->WizardDefaultWidth); - } + // Attributes introduced in QtIFW 2.0.0 + if (!this->IsVersionLess("2.0")) { + // WizardDefaultWidth + if (!this->WizardDefaultWidth.empty()) { + xout.Element("WizardDefaultWidth", this->WizardDefaultWidth); + } - // WizardDefaultHeight - if (!this->WizardDefaultHeight.empty()) { - xout.Element("WizardDefaultHeight", this->WizardDefaultHeight); - } + // WizardDefaultHeight + if (!this->WizardDefaultHeight.empty()) { + xout.Element("WizardDefaultHeight", this->WizardDefaultHeight); + } - // WizardShowPageList - if (!this->IsVersionLess("4.0") && !this->WizardShowPageList.empty()) { - xout.Element("WizardShowPageList", this->WizardShowPageList); - } + // Start menu directory + if (!this->StartMenuDir.empty()) { + xout.Element("StartMenuDir", this->StartMenuDir); + } - // TitleColor - if (!this->TitleColor.empty()) { - xout.Element("TitleColor", this->TitleColor); - } + // Maintenance tool + if (!this->MaintenanceToolName.empty()) { + xout.Element("MaintenanceToolName", this->MaintenanceToolName); + } - // Start menu - if (!this->IsVersionLess("2.0")) { - xout.Element("StartMenuDir", this->StartMenuDir); + // Maintenance tool ini file + if (!this->MaintenanceToolIniFile.empty()) { + xout.Element("MaintenanceToolIniFile", this->MaintenanceToolIniFile); + } + + if (!this->AllowNonAsciiCharacters.empty()) { + xout.Element("AllowNonAsciiCharacters", this->AllowNonAsciiCharacters); + } + if (!this->AllowSpaceInPath.empty()) { + xout.Element("AllowSpaceInPath", this->AllowSpaceInPath); + } + + // Control script (copy to config dir) + if (!this->ControlScript.empty()) { + std::string name = cmSystemTools::GetFilenameName(this->ControlScript); + std::string path = this->Directory + "/config/" + name; + cmsys::SystemTools::CopyFileIfDifferent(this->ControlScript, path); + xout.Element("ControlScript", name); + } + } else { + // CPack IFW default policy + xout.Comment("CPack IFW default policy for QtIFW less 2.0"); + xout.Element("AllowNonAsciiCharacters", "true"); + xout.Element("AllowSpaceInPath", "true"); } // Target dir @@ -471,41 +530,74 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.EndElement(); } - // Maintenance tool - if (!this->IsVersionLess("2.0") && !this->MaintenanceToolName.empty()) { - xout.Element("MaintenanceToolName", this->MaintenanceToolName); + // Attributes introduced in QtIFW 3.0.0 + if (!this->IsVersionLess("3.0")) { + // WizardStyle + if (!this->WizardStyle.empty()) { + xout.Element("WizardStyle", this->WizardStyle); + } + + // Stylesheet (copy to config dir) + if (!this->StyleSheet.empty()) { + std::string name = cmSystemTools::GetFilenameName(this->StyleSheet); + std::string path = this->Directory + "/config/" + name; + cmsys::SystemTools::CopyFileIfDifferent(this->StyleSheet, path); + xout.Element("StyleSheet", name); + } + + // TitleColor + if (!this->TitleColor.empty()) { + xout.Element("TitleColor", this->TitleColor); + } } - // Maintenance tool ini file - if (!this->IsVersionLess("2.0") && !this->MaintenanceToolIniFile.empty()) { - xout.Element("MaintenanceToolIniFile", this->MaintenanceToolIniFile); + // Attributes introduced in QtIFW 4.0.0 + if (!this->IsVersionLess("4.0")) { + // WizardShowPageList + if (!this->WizardShowPageList.empty()) { + xout.Element("WizardShowPageList", this->WizardShowPageList); + } + + // DisableCommandLineInterface + if (!this->DisableCommandLineInterface.empty()) { + xout.Element("DisableCommandLineInterface", + this->DisableCommandLineInterface); + } + + // RunProgram + if (!this->RunProgram.empty()) { + xout.Element("RunProgram", this->RunProgram); + } + + // RunProgramArguments + if (!this->RunProgramArguments.empty()) { + xout.StartElement("RunProgramArguments"); + for (const auto& arg : this->RunProgramArguments) { + xout.Element("Argument", arg); + } + xout.EndElement(); + } + + // RunProgramDescription + if (!this->RunProgramDescription.empty()) { + xout.Element("RunProgramDescription", this->RunProgramDescription); + } } if (!this->RemoveTargetDir.empty()) { xout.Element("RemoveTargetDir", this->RemoveTargetDir); } - // Different allows - if (this->IsVersionLess("2.0")) { - // CPack IFW default policy - xout.Comment("CPack IFW default policy for QtIFW less 2.0"); - xout.Element("AllowNonAsciiCharacters", "true"); - xout.Element("AllowSpaceInPath", "true"); - } else { - if (!this->AllowNonAsciiCharacters.empty()) { - xout.Element("AllowNonAsciiCharacters", this->AllowNonAsciiCharacters); - } - if (!this->AllowSpaceInPath.empty()) { - xout.Element("AllowSpaceInPath", this->AllowSpaceInPath); + // Product images (copy to config dir) + if (!this->IsVersionLess("4.0") && !this->ProductImages.empty()) { + xout.StartElement("ProductImages"); + for (auto const& srcImg : this->ProductImages) { + std::string name = cmSystemTools::GetFilenameName(srcImg); + std::string dstImg = this->Directory + "/config/" + name; + cmsys::SystemTools::CopyFileIfDifferent(srcImg, dstImg); + xout.Element("Image", name); } - } - - // Control script (copy to config dir) - if (!this->IsVersionLess("2.0") && !this->ControlScript.empty()) { - std::string name = cmSystemTools::GetFilenameName(this->ControlScript); - std::string path = this->Directory + "/config/" + name; - cmsys::SystemTools::CopyFileIfDifferent(this->ControlScript, path); - xout.Element("ControlScript", name); + xout.EndElement(); } // Resources (copy to resources dir) diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h index a031fc2..205835b 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.h +++ b/Source/CPack/IFW/cmCPackIFWInstaller.h @@ -109,6 +109,9 @@ public: /// uninstalling std::string RemoveTargetDir; + /// Set to true if command line interface features should be disabled + std::string DisableCommandLineInterface; + /// Set to false if the installation path cannot contain space characters std::string AllowSpaceInPath; @@ -118,6 +121,25 @@ public: /// List of resources to include in the installer binary std::vector<std::string> Resources; + /// A list of images to be shown on PerformInstallationPage. + std::vector<std::string> ProductImages; + + /// Command executed after the installer is done if the user accepts the + /// action + std::string RunProgram; + + /// Arguments passed to the program specified in <RunProgram> + std::vector<std::string> RunProgramArguments; + + /// Text shown next to the check box for running the program after the + /// installation + std::string RunProgramDescription; + +#ifdef __APPLE__ + /// Code signing identity for signing the generated app bundle + std::string SigningIdentity; +#endif + public: // Internal implementation diff --git a/Source/CPack/IFW/cmCPackIFWPackage.h b/Source/CPack/IFW/cmCPackIFWPackage.h index 0cc6f2f..350f6b2 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.h +++ b/Source/CPack/IFW/cmCPackIFWPackage.h @@ -44,7 +44,7 @@ public: struct DependenceStruct { DependenceStruct(); - DependenceStruct(const std::string& dependence); + explicit DependenceStruct(const std::string& dependence); std::string Name; CompareStruct Compare; diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx deleted file mode 100644 index b7140ab..0000000 --- a/Source/CPack/OSXScriptLauncher.cxx +++ /dev/null @@ -1,122 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include <cstddef> -#include <iostream> -#include <string> -#include <vector> - -#include <cm/memory> - -#include <CoreFoundation/CoreFoundation.h> - -#include "cmsys/FStream.hxx" -#include "cmsys/Process.h" -#include "cmsys/SystemTools.hxx" - -// For the PATH_MAX constant -#include <sys/syslimits.h> - -#define DebugError(x) \ - ofs << x << std::endl; \ - std::cout << x << std::endl - -int main(int argc, char* argv[]) -{ - // if ( cmsys::SystemTools::FileExists( - cmsys::ofstream ofs("/tmp/output.txt"); - - CFStringRef fileName; - CFBundleRef appBundle; - CFURLRef scriptFileURL; - - // get CF URL for script - if (!(appBundle = CFBundleGetMainBundle())) { - DebugError("Cannot get main bundle"); - return 1; - } - fileName = CFSTR("RuntimeScript"); - if (!(scriptFileURL = - CFBundleCopyResourceURL(appBundle, fileName, nullptr, nullptr))) { - DebugError("CFBundleCopyResourceURL failed"); - return 1; - } - - // create path string - auto path = cm::make_unique<UInt8[]>(PATH_MAX); - if (!path) { - return 1; - } - - // get the file system path of the url as a cstring - // in an encoding suitable for posix apis - if (!CFURLGetFileSystemRepresentation(scriptFileURL, true, path.get(), - PATH_MAX)) { - DebugError("CFURLGetFileSystemRepresentation failed"); - return 1; - } - - // dispose of the CF variable - CFRelease(scriptFileURL); - - std::string fullScriptPath = reinterpret_cast<char*>(path.get()); - path.reset(); - - if (!cmsys::SystemTools::FileExists(fullScriptPath)) { - return 1; - } - - std::string scriptDirectory = - cmsys::SystemTools::GetFilenamePath(fullScriptPath); - ofs << fullScriptPath << std::endl; - std::vector<const char*> args; - args.push_back(fullScriptPath.c_str()); - int cc; - for (cc = 1; cc < argc; ++cc) { - args.push_back(argv[cc]); - } - args.push_back(nullptr); - - cmsysProcess* cp = cmsysProcess_New(); - cmsysProcess_SetCommand(cp, args.data()); - cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str()); - cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1); - cmsysProcess_SetTimeout(cp, 0); - cmsysProcess_Execute(cp); - - char* data; - int length; - while (cmsysProcess_WaitForData(cp, &data, &length, nullptr)) { - // Translate NULL characters in the output into valid text. - for (int i = 0; i < length; ++i) { - if (data[i] == '\0') { - data[i] = ' '; - } - } - std::cout.write(data, length); - } - - cmsysProcess_WaitForExit(cp, nullptr); - - bool result = true; - if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) { - if (cmsysProcess_GetExitValue(cp) != 0) { - result = false; - } - } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) { - const char* exception_str = cmsysProcess_GetExceptionString(cp); - std::cerr << exception_str << std::endl; - result = false; - } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) { - const char* error_str = cmsysProcess_GetErrorString(cp); - std::cerr << error_str << std::endl; - result = false; - } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) { - const char* error_str = "Process terminated due to timeout\n"; - std::cerr << error_str << std::endl; - result = false; - } - - cmsysProcess_Delete(cp); - - return !result; -} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index d03239b..6a0095b 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -219,7 +219,9 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions); CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions); - this->LightExtensions.insert("WixUIExtension"); + if (!cmIsOn(GetOption("CPACK_WIX_SKIP_WIX_UI_EXTENSION"))) { + this->LightExtensions.insert("WixUIExtension"); + } CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions); CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions); CollectXmlNamespaces("CPACK_WIX_CUSTOM_XMLNS", this->CustomXmlNamespaces); diff --git a/Source/CPack/cmCPackComponentGroup.h b/Source/CPack/cmCPackComponentGroup.h index 58377d4..6a47b6d 100644 --- a/Source/CPack/cmCPackComponentGroup.h +++ b/Source/CPack/cmCPackComponentGroup.h @@ -35,12 +35,10 @@ class cmCPackComponent { public: cmCPackComponent() - : Group(nullptr) - , IsRequired(true) + : IsRequired(true) , IsHidden(false) , IsDisabledByDefault(false) , IsDownloaded(false) - , TotalSize(0) { } @@ -51,7 +49,7 @@ public: std::string DisplayName; /// The component group that contains this component (if any). - cmCPackComponentGroup* Group; + cmCPackComponentGroup* Group = nullptr; /// Whether this component group must always be installed. bool IsRequired : 1; @@ -103,7 +101,7 @@ public: unsigned long GetInstalledSizeInKbytes(const std::string& installDir) const; private: - mutable unsigned long TotalSize; + mutable unsigned long TotalSize = 0; }; /** \class cmCPackComponentGroup @@ -113,7 +111,8 @@ class cmCPackComponentGroup { public: cmCPackComponentGroup() - : ParentGroup(nullptr) + : IsBold(false) + , IsExpandedByDefault(false) { } @@ -136,7 +135,7 @@ public: std::vector<cmCPackComponent*> Components; /// The parent group of this component group (if any). - cmCPackComponentGroup* ParentGroup; + cmCPackComponentGroup* ParentGroup = nullptr; /// The subgroups of this group. std::vector<cmCPackComponentGroup*> Subgroups; diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx index 484db00..fabf4c5 100644 --- a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx +++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx @@ -17,9 +17,7 @@ cmCPackCygwinBinaryGenerator::cmCPackCygwinBinaryGenerator() { } -cmCPackCygwinBinaryGenerator::~cmCPackCygwinBinaryGenerator() -{ -} +cmCPackCygwinBinaryGenerator::~cmCPackCygwinBinaryGenerator() = default; int cmCPackCygwinBinaryGenerator::InitializeInternal() { @@ -43,7 +41,7 @@ int cmCPackCygwinBinaryGenerator::PackageFiles() // create an extra scope to force the stream // to create the file before the super class is called { - cmGeneratedFileStream ofs(manifestFile.c_str()); + cmGeneratedFileStream ofs(manifestFile); for (std::string const& file : files) { // remove the temp dir and replace with /usr ofs << file.substr(tempdir.size()) << "\n"; diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.h b/Source/CPack/cmCPackCygwinBinaryGenerator.h index f5f7700..ca8e0b5 100644 --- a/Source/CPack/cmCPackCygwinBinaryGenerator.h +++ b/Source/CPack/cmCPackCygwinBinaryGenerator.h @@ -19,8 +19,8 @@ public: ~cmCPackCygwinBinaryGenerator() override; protected: - virtual int InitializeInternal(); - int PackageFiles(); - virtual const char* GetOutputExtension(); + int InitializeInternal() override; + int PackageFiles() override; + const char* GetOutputExtension() override; std::string OutputExtension; }; diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.cxx b/Source/CPack/cmCPackCygwinSourceGenerator.cxx index 59df380..a5863ff 100644 --- a/Source/CPack/cmCPackCygwinSourceGenerator.cxx +++ b/Source/CPack/cmCPackCygwinSourceGenerator.cxx @@ -26,9 +26,7 @@ cmCPackCygwinSourceGenerator::cmCPackCygwinSourceGenerator() { } -cmCPackCygwinSourceGenerator::~cmCPackCygwinSourceGenerator() -{ -} +cmCPackCygwinSourceGenerator::~cmCPackCygwinSourceGenerator() = default; int cmCPackCygwinSourceGenerator::InitializeInternal() { @@ -50,7 +48,7 @@ int cmCPackCygwinSourceGenerator::PackageFiles() // Now create a tar file that contains the above .tar.bz2 file // and the CPACK_CYGWIN_PATCH_FILE and CPACK_TOPLEVEL_DIRECTORY // files - std::string compressOutFile = packageDirFileName; + const std::string& compressOutFile = packageDirFileName; // at this point compressOutFile is the full path to // _CPack_Package/.../package-2.5.0.tar.bz2 // we want to create a tar _CPack_Package/.../package-2.5.0-1-src.tar.bz2 diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.h b/Source/CPack/cmCPackCygwinSourceGenerator.h index 964a4d4..2207bde 100644 --- a/Source/CPack/cmCPackCygwinSourceGenerator.h +++ b/Source/CPack/cmCPackCygwinSourceGenerator.h @@ -19,10 +19,10 @@ public: ~cmCPackCygwinSourceGenerator() override; protected: - const char* GetPackagingInstallPrefix(); - virtual int InitializeInternal(); - int PackageFiles(); - virtual const char* GetOutputExtension(); + const char* GetPackagingInstallPrefix() override; + int InitializeInternal() override; + int PackageFiles() override; + const char* GetOutputExtension() override; std::string InstallPrefix; std::string OutputExtension; }; diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index d7aa287..8e5e637 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -203,7 +203,7 @@ bool DebGenerator::generateDataTar() const // uid/gid should be the one of the root user, and this root user has // always uid/gid equal to 0. - data_tar.SetUIDAndGID(0u, 0u); + data_tar.SetUIDAndGID(0U, 0U); data_tar.SetUNAMEAndGNAME("root", "root"); // now add all directories which have to be compressed @@ -902,7 +902,7 @@ std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix( } if (this->componentPackageMethod == ONE_PACKAGE) { - return std::string("ALL_COMPONENTS_IN_ONE"); + return { "ALL_COMPONENTS_IN_ONE" }; } // We have to find the name of the COMPONENT GROUP // the current COMPONENT belongs to. diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h index 61a6616..11561a4 100644 --- a/Source/CPack/cmCPackDebGenerator.h +++ b/Source/CPack/cmCPackDebGenerator.h @@ -29,9 +29,9 @@ public: #ifdef __APPLE__ // on MacOS enable CPackDeb iff dpkg is found std::vector<std::string> locations; - locations.push_back("/sw/bin"); // Fink - locations.push_back("/opt/local/bin"); // MacPorts - return cmSystemTools::FindProgram("dpkg", locations) != "" ? true : false; + locations.emplace_back("/sw/bin"); // Fink + locations.emplace_back("/opt/local/bin"); // MacPorts + return !cmSystemTools::FindProgram("dpkg", locations).empty(); #else // legacy behavior on other systems return true; diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index 9385a5a..0f7acfb 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -98,7 +98,9 @@ int cmCPackDragNDropGenerator::InitializeInternal() if (this->IsSet("CPACK_DMG_SLA_DIR")) { slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR"); - if (!slaDirectory.empty() && this->IsSet("CPACK_RESOURCE_FILE_LICENSE")) { + if (!slaDirectory.empty() && + this->IsOn("CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE") && + this->IsSet("CPACK_RESOURCE_FILE_LICENSE")) { std::string license_file = this->GetOption("CPACK_RESOURCE_FILE_LICENSE"); if (!license_file.empty() && @@ -278,8 +280,10 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, : "HFS+"; // Get optional arguments ... - std::string cpack_license_file = - *this->GetOption("CPACK_RESOURCE_FILE_LICENSE"); + std::string cpack_license_file; + if (this->IsOn("CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE")) { + cpack_license_file = *this->GetOption("CPACK_RESOURCE_FILE_LICENSE"); + } cmValue cpack_dmg_background_image = this->GetOption("CPACK_DMG_BACKGROUND_IMAGE"); diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h index 310b0ab..6d1267b 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.h +++ b/Source/CPack/cmCPackDragNDropGenerator.h @@ -4,12 +4,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <sstream> #include <string> #include <vector> -#include <stddef.h> - #include "cmCPackGenerator.h" class cmGeneratedFileStream; @@ -34,7 +33,7 @@ protected: bool CopyFile(std::ostringstream& source, std::ostringstream& target); bool CreateEmptyFile(std::ostringstream& target, size_t size); - bool RunCommand(std::ostringstream& command, std::string* output = 0); + bool RunCommand(std::ostringstream& command, std::string* output = nullptr); std::string GetComponentInstallDirNameSuffix( const std::string& componentName) override; diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx index 30b6b0d..b5d41fc 100644 --- a/Source/CPack/cmCPackFreeBSDGenerator.cxx +++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx @@ -21,8 +21,15 @@ #include <sys/stat.h> +// Suffix used to tell libpkg what compression to use +static const char FreeBSDPackageCompression[] = "txz"; +// Resulting package file-suffix, for < 1.17 and >= 1.17 versions of libpkg +static const char FreeBSDPackageSuffix_10[] = ".txz"; +static const char FreeBSDPackageSuffix_17[] = ".pkg"; + cmCPackFreeBSDGenerator::cmCPackFreeBSDGenerator() - : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr", ".txz") + : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr", + FreeBSDPackageSuffix_17) { } @@ -35,6 +42,56 @@ int cmCPackFreeBSDGenerator::InitializeInternal() cmCPackFreeBSDGenerator::~cmCPackFreeBSDGenerator() = default; +// This is a wrapper for struct pkg_create and pkg_create() +// +// Instantiate this class with suitable parameters, then +// check isValid() to check if it's ok. Afterwards, call +// Create() to do the actual work. This will leave a package +// in the given `output_dir`. +// +// This wrapper cleans up the struct pkg_create. +class PkgCreate +{ +public: + PkgCreate() + : d(nullptr) + { + } + PkgCreate(const std::string& output_dir, const std::string& toplevel_dir, + const std::string& manifest_name) + : d(pkg_create_new()) + , manifest(manifest_name) + + { + if (d) { + pkg_create_set_format(d, FreeBSDPackageCompression); + pkg_create_set_compression_level(d, 0); // Explicitly set default + pkg_create_set_overwrite(d, false); + pkg_create_set_rootdir(d, toplevel_dir.c_str()); + pkg_create_set_output_dir(d, output_dir.c_str()); + } + } + ~PkgCreate() + { + if (d) + pkg_create_free(d); + } + + bool isValid() const { return d; } + + bool Create() + { + if (!isValid()) + return false; + int r = pkg_create(d, manifest.c_str(), nullptr, false); + return r == 0; + } + +private: + struct pkg_create* d; + std::string manifest; +}; + // This is a wrapper, for use only in stream-based output, // that will output a string in UCL escaped fashion (in particular, // quotes and backslashes are escaped). The list of characters @@ -205,7 +262,7 @@ std::string cmCPackFreeBSDGenerator::var_lookup(const char* var_name) { cmValue pv = this->GetOption(var_name); if (!pv) { - return std::string(); + return {}; } return *pv; } @@ -271,7 +328,7 @@ void write_manifest_files(cmGeneratedFileStream& s, s << "\"files\": {\n"; for (std::string const& file : files) { s << " \"/" << cmSystemTools::RelativePath(toplevel, file) << "\": \"" - << "<sha256>" + << "<sha256>" // this gets replaced by libpkg by the actual SHA256 << "\",\n"; } s << " },\n"; @@ -281,11 +338,10 @@ int cmCPackFreeBSDGenerator::PackageFiles() { if (!this->ReadListFile("Internal/CPack/CPackFreeBSD.cmake")) { cmCPackLogger(cmCPackLog::LOG_ERROR, - "Error while execution CPackFreeBSD.cmake" << std::endl); + "Error while executing CPackFreeBSD.cmake" << std::endl); return 0; } - std::vector<std::string>::const_iterator fileIt; cmWorkingDirectory wd(toplevel); files.erase(std::remove_if(files.begin(), files.end(), ignore_file), @@ -317,20 +373,85 @@ int cmCPackFreeBSDGenerator::PackageFiles() ONE_PACKAGE_PER_COMPONENT); } + // There should be one name in the packageFileNames (already, see comment + // in cmCPackGenerator::DoPackage(), which holds what CPack guesses + // will be the package filename. libpkg does something else, though, + // so update the single filename to what we know will be right. + if (this->packageFileNames.size() == 1) { + std::string currentPackage = this->packageFileNames[0]; + auto lastSlash = currentPackage.rfind('/'); + + // If there is a pathname, preserve that; libpkg will write out + // a file with the package name and version as specified in the + // manifest, so we look those up (again). lastSlash is the slash + // itself, we need that as path separator to the calculated package name. + std::string actualPackage = + ((lastSlash != std::string::npos) + ? std::string(currentPackage, 0, lastSlash + 1) + : std::string()) + + var_lookup("CPACK_FREEBSD_PACKAGE_NAME") + '-' + + var_lookup("CPACK_FREEBSD_PACKAGE_VERSION") + FreeBSDPackageSuffix_17; + + this->packageFileNames.clear(); + this->packageFileNames.emplace_back(actualPackage); + } + + if (!pkg_initialized() && pkg_init(NULL, NULL) != EPKG_OK) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Can not initialize FreeBSD libpkg." << std::endl); + return 0; + } + std::string output_dir = cmSystemTools::CollapseFullPath("../", toplevel); - pkg_create_from_manifest(output_dir.c_str(), ::TXZ, toplevel.c_str(), - manifestname.c_str(), nullptr); + PkgCreate package(output_dir, toplevel, manifestname); + if (package.isValid()) { + if (!package.Create()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error during pkg_create()" << std::endl); + return 0; + } + } else { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error before pkg_create()" << std::endl); + return 0; + } - std::string broken_suffix = - cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), ".txz"); + // Specifically looking for packages suffixed with the TAG, either extension + std::string broken_suffix_10 = + cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_10); + std::string broken_suffix_17 = + cmStrCat('-', var_lookup("CPACK_TOPLEVEL_TAG"), FreeBSDPackageSuffix_17); for (std::string& name : packageFileNames) { cmCPackLogger(cmCPackLog::LOG_DEBUG, "Packagefile " << name << std::endl); - if (cmHasSuffix(name, broken_suffix)) { - name.replace(name.size() - broken_suffix.size(), std::string::npos, - ".txz"); + if (cmHasSuffix(name, broken_suffix_10)) { + name.replace(name.size() - broken_suffix_10.size(), std::string::npos, + FreeBSDPackageSuffix_10); + break; + } + if (cmHasSuffix(name, broken_suffix_17)) { + name.replace(name.size() - broken_suffix_17.size(), std::string::npos, + FreeBSDPackageSuffix_17); break; } } + // If the name uses a *new* style name, which doesn't exist, but there + // is an *old* style name, then use that instead. This indicates we used + // an older libpkg, which still creates .txz instead of .pkg files. + for (std::string& name : packageFileNames) { + if (cmHasSuffix(name, FreeBSDPackageSuffix_17) && + !cmSystemTools::FileExists(name)) { + const std::string badSuffix(FreeBSDPackageSuffix_17); + const std::string goodSuffix(FreeBSDPackageSuffix_10); + std::string repairedName(name); + repairedName.replace(repairedName.size() - badSuffix.size(), + std::string::npos, goodSuffix); + if (cmSystemTools::FileExists(repairedName)) { + name = repairedName; + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Repaired packagefile " << name << std::endl); + } + } + } return 1; } diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 2f700b4..7ddb103 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -186,7 +186,7 @@ int cmCPackGenerator::InstallProject() std::string bareTempInstallDirectory = this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY"); std::string tempInstallDirectoryStr = bareTempInstallDirectory; - bool setDestDir = cmIsOn(this->GetOption("CPACK_SET_DESTDIR")) | + bool setDestDir = cmIsOn(this->GetOption("CPACK_SET_DESTDIR")) || cmIsInternallyOn(this->GetOption("CPACK_SET_DESTDIR")); if (!setDestDir) { tempInstallDirectoryStr += this->GetPackagingInstallPrefix(); diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 79e344b..0b2acca 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -21,7 +21,6 @@ #ifdef __APPLE__ # include "cmCPackBundleGenerator.h" # include "cmCPackDragNDropGenerator.h" -# include "cmCPackOSXX11Generator.h" # include "cmCPackPackageMakerGenerator.h" # include "cmCPackProductBuildGenerator.h" #endif @@ -113,10 +112,6 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("PackageMaker", "Mac OSX Package Maker installer", cmCPackPackageMakerGenerator::CreateGenerator); } - if (cmCPackOSXX11Generator::CanGenerate()) { - this->RegisterGenerator("OSXX11", "Mac OSX X11 bundle", - cmCPackOSXX11Generator::CreateGenerator); - } if (cmCPackProductBuildGenerator::CanGenerate()) { this->RegisterGenerator("productbuild", "Mac OSX pkg", cmCPackProductBuildGenerator::CreateGenerator); diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h index 0846573..f3e25a6 100644 --- a/Source/CPack/cmCPackGeneratorFactory.h +++ b/Source/CPack/cmCPackGeneratorFactory.h @@ -41,5 +41,5 @@ private: using t_GeneratorCreatorsMap = std::map<std::string, CreateGeneratorCall*>; t_GeneratorCreatorsMap GeneratorCreators; DescriptionsMap GeneratorDescriptions; - cmCPackLog* Logger; + cmCPackLog* Logger{}; }; diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h index 6cec39c..2ab2f8e 100644 --- a/Source/CPack/cmCPackLog.h +++ b/Source/CPack/cmCPackLog.h @@ -4,12 +4,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstring> #include <memory> #include <ostream> #include <string> -#include <string.h> - #define cmCPack_Log(ctSelf, logType, msg) \ do { \ std::ostringstream cmCPackLog_msg; \ @@ -129,7 +128,7 @@ public: } const char* Data; - size_t Length; + std::streamsize Length; }; inline std::ostream& operator<<(std::ostream& os, const cmCPackLogWrite& c) diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index ecc5e08..217f716 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -883,7 +883,7 @@ std::string cmCPackNSISGenerator::CreateSelectionDependenciesDescription( { // Don't visit a component twice if (visited.count(component)) { - return std::string(); + return {}; } visited.insert(component); @@ -907,7 +907,7 @@ std::string cmCPackNSISGenerator::CreateDeselectionDependenciesDescription( { // Don't visit a component twice if (visited.count(component)) { - return std::string(); + return {}; } visited.insert(component); @@ -933,7 +933,7 @@ std::string cmCPackNSISGenerator::CreateComponentGroupDescription( { if (group->Components.empty() && group->Subgroups.empty()) { // Silently skip empty groups. NSIS doesn't support them. - return std::string(); + return {}; } std::string code = "SectionGroup "; diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx deleted file mode 100644 index 7bf1dc7..0000000 --- a/Source/CPack/cmCPackOSXX11Generator.cxx +++ /dev/null @@ -1,272 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCPackOSXX11Generator.h" - -#include <sstream> - -#include "cm_sys_stat.h" - -#include "cmCPackGenerator.h" -#include "cmCPackLog.h" -#include "cmDuration.h" -#include "cmGeneratedFileStream.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" -#include "cmValue.h" - -cmCPackOSXX11Generator::cmCPackOSXX11Generator() = default; - -cmCPackOSXX11Generator::~cmCPackOSXX11Generator() = default; - -int cmCPackOSXX11Generator::PackageFiles() -{ - // TODO: Use toplevel ? - // It is used! Is this an obsolete comment? - - cmValue cpackPackageExecutables = - this->GetOption("CPACK_PACKAGE_EXECUTABLES"); - if (cpackPackageExecutables) { - cmCPackLogger(cmCPackLog::LOG_DEBUG, - "The cpackPackageExecutables: " << cpackPackageExecutables - << "." << std::endl); - std::ostringstream str; - std::ostringstream deleteStr; - std::vector<std::string> cpackPackageExecutablesVector = - cmExpandedList(cpackPackageExecutables); - if (cpackPackageExecutablesVector.size() % 2 != 0) { - cmCPackLogger( - cmCPackLog::LOG_ERROR, - "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and " - "<icon name>." - << std::endl); - return 0; - } - std::vector<std::string>::iterator it; - for (it = cpackPackageExecutablesVector.begin(); - it != cpackPackageExecutablesVector.end(); ++it) { - std::string cpackExecutableName = *it; - ++it; - this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME", cpackExecutableName); - } - } - - // Disk image directories - std::string diskImageDirectory = toplevel; - std::string diskImageBackgroundImageDir = - diskImageDirectory + "/.background"; - - // App bundle directories - std::string packageDirFileName = cmStrCat( - toplevel, '/', this->GetOption("CPACK_PACKAGE_FILE_NAME"), ".app"); - std::string contentsDirectory = packageDirFileName + "/Contents"; - std::string resourcesDirectory = contentsDirectory + "/Resources"; - std::string appDirectory = contentsDirectory + "/MacOS"; - std::string scriptDirectory = resourcesDirectory + "/Scripts"; - std::string resourceFileName = - cmStrCat(this->GetOption("CPACK_PACKAGE_FILE_NAME"), ".rsrc"); - - const char* dir = resourcesDirectory.c_str(); - const char* appdir = appDirectory.c_str(); - const char* scrDir = scriptDirectory.c_str(); - const char* contDir = contentsDirectory.c_str(); - const char* rsrcFile = resourceFileName.c_str(); - cmValue iconFile = this->GetOption("CPACK_PACKAGE_ICON"); - if (iconFile) { - std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile); - if (!cmSystemTools::FileExists(iconFile)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Cannot find icon file: " - << iconFile - << ". Please check CPACK_PACKAGE_ICON setting." - << std::endl); - return 0; - } - std::string destFileName = resourcesDirectory + "/" + iconFileName; - this->ConfigureFile(iconFile, destFileName, true); - this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName); - } - - std::string applicationsLinkName = diskImageDirectory + "/Applications"; - cmSystemTools::CreateSymlink("/Applications", applicationsLinkName); - - if (!this->CopyResourcePlistFile("VolumeIcon.icns", diskImageDirectory, - ".VolumeIcon.icns", true) || - !this->CopyResourcePlistFile("DS_Store", diskImageDirectory, ".DS_Store", - true) || - !this->CopyResourcePlistFile("background.png", - diskImageBackgroundImageDir, - "background.png", true) || - !this->CopyResourcePlistFile("RuntimeScript", dir) || - !this->CopyResourcePlistFile("OSXX11.Info.plist", contDir, - "Info.plist") || - !this->CopyResourcePlistFile("OSXX11.main.scpt", scrDir, "main.scpt", - true) || - !this->CopyResourcePlistFile("OSXScriptLauncher.rsrc", dir, rsrcFile, - true) || - !this->CopyResourcePlistFile( - "OSXScriptLauncher", appdir, - this->GetOption("CPACK_PACKAGE_FILE_NAME").GetCStr(), true)) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Problem copying the resource files" << std::endl); - return 0; - } - - // Two of the files need to have execute permission, so ensure they do: - std::string runTimeScript = cmStrCat(dir, "/RuntimeScript"); - - std::string appScriptName = - cmStrCat(appdir, '/', this->GetOption("CPACK_PACKAGE_FILE_NAME")); - - mode_t mode; - if (cmsys::SystemTools::GetPermissions(runTimeScript.c_str(), mode)) { - mode |= (S_IXUSR | S_IXGRP | S_IXOTH); - cmsys::SystemTools::SetPermissions(runTimeScript.c_str(), mode); - cmCPackLogger(cmCPackLog::LOG_OUTPUT, - "Setting: " << runTimeScript << " to permission: " << mode - << std::endl); - } - - if (cmsys::SystemTools::GetPermissions(appScriptName.c_str(), mode)) { - mode |= (S_IXUSR | S_IXGRP | S_IXOTH); - cmsys::SystemTools::SetPermissions(appScriptName.c_str(), mode); - cmCPackLogger(cmCPackLog::LOG_OUTPUT, - "Setting: " << appScriptName << " to permission: " << mode - << std::endl); - } - - std::string output; - std::string tmpFile = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), - "/hdiutilOutput.log"); - std::ostringstream dmgCmd; - dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE") - << "\" create -ov -fs HFS+ -format UDZO -srcfolder \"" - << diskImageDirectory << "\" \"" << packageFileNames[0] << "\""; - cmCPackLogger(cmCPackLog::LOG_VERBOSE, - "Compress disk image using command: " << dmgCmd.str() - << std::endl); - // since we get random dashboard failures with this one - // try running it more than once - int retVal = 1; - int numTries = 10; - bool res = false; - while (numTries > 0) { - res = cmSystemTools::RunSingleCommand( - dmgCmd.str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose, - cmDuration::zero()); - if (res && !retVal) { - numTries = -1; - break; - } - cmSystemTools::Delay(500); - numTries--; - } - if (!res || retVal) { - cmGeneratedFileStream ofs(tmpFile); - ofs << "# Run command: " << dmgCmd.str() << std::endl - << "# Output:" << std::endl - << output << std::endl; - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Problem running hdiutil command: " - << dmgCmd.str() << std::endl - << "Please check " << tmpFile << " for errors" - << std::endl); - return 0; - } - - return 1; -} - -int cmCPackOSXX11Generator::InitializeInternal() -{ - cmCPackLogger(cmCPackLog::LOG_WARNING, - "The OSXX11 generator is deprecated " - "and will be removed in a future version.\n"); - cmCPackLogger(cmCPackLog::LOG_DEBUG, - "cmCPackOSXX11Generator::Initialize()" << std::endl); - std::vector<std::string> path; - std::string pkgPath = cmSystemTools::FindProgram("hdiutil", path, false); - if (pkgPath.empty()) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Cannot find hdiutil compiler" << std::endl); - return 0; - } - this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE", pkgPath); - - return this->Superclass::InitializeInternal(); -} - -/* -bool cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& name) -{ - std::string uname = cmSystemTools::UpperCase(name); - std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname; - const char* inFileName = this->GetOption(cpackVar.c_str()); - if ( !inFileName ) - { - cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: " << cpackVar.c_str() - << " not specified. It should point to " - << (name ? name : "(NULL)") - << ".rtf, " << name - << ".html, or " << name << ".txt file" << std::endl); - return false; - } - if ( !cmSystemTools::FileExists(inFileName) ) - { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find " - << (name ? name : "(NULL)") - << " resource file: " << inFileName << std::endl); - return false; - } - std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName); - if ( ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt" ) - { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Bad file extension specified: " - << ext << ". Currently only .rtfd, .rtf, .html, and .txt files allowed." - << std::endl); - return false; - } - - std::string destFileName = cmStrCat( -this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/Resources/", name, ext ); - - - cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: " - << (inFileName ? inFileName : "(NULL)") - << " to " << destFileName << std::endl); - this->ConfigureFile(inFileName, destFileName); - return true; -} -*/ - -bool cmCPackOSXX11Generator::CopyResourcePlistFile( - const std::string& name, const std::string& dir, - const char* outputFileName /* = 0 */, bool copyOnly /* = false */) -{ - std::string inFName = cmStrCat("CPack.", name, ".in"); - std::string inFileName = this->FindTemplate(inFName.c_str()); - if (inFileName.empty()) { - cmCPackLogger(cmCPackLog::LOG_ERROR, - "Cannot find input file: " << inFName << std::endl); - return false; - } - - if (!outputFileName) { - outputFileName = name.c_str(); - } - - std::string destFileName = cmStrCat(dir, '/', outputFileName); - - cmCPackLogger(cmCPackLog::LOG_VERBOSE, - "Configure file: " << inFileName << " to " << destFileName - << std::endl); - this->ConfigureFile(inFileName, destFileName, copyOnly); - return true; -} - -const char* cmCPackOSXX11Generator::GetPackagingInstallPrefix() -{ - this->InstallPrefix = - cmStrCat('/', this->GetOption("CPACK_PACKAGE_FILE_NAME"), - ".app/Contents/Resources"); - return this->InstallPrefix.c_str(); -} diff --git a/Source/CPack/cmCPackOSXX11Generator.h b/Source/CPack/cmCPackOSXX11Generator.h deleted file mode 100644 index 8fae136..0000000 --- a/Source/CPack/cmCPackOSXX11Generator.h +++ /dev/null @@ -1,39 +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 "cmCPackGenerator.h" - -/** \class cmCPackOSXX11Generator - * \brief A generator for OSX X11 modules - * - * Based on Gimp.app - */ -class cmCPackOSXX11Generator : public cmCPackGenerator -{ -public: - cmCPackTypeMacro(cmCPackOSXX11Generator, cmCPackGenerator); - - /** - * Construct generator - */ - cmCPackOSXX11Generator(); - ~cmCPackOSXX11Generator() override; - -protected: - virtual int InitializeInternal() override; - int PackageFiles() override; - const char* GetPackagingInstallPrefix() override; - const char* GetOutputExtension() override { return ".dmg"; } - - // bool CopyCreateResourceFile(const std::string& name, - // const std::string& dir); - bool CopyResourcePlistFile(const std::string& name, const std::string& dir, - const char* outputFileName = 0, - bool copyOnly = false); - std::string InstallPrefix; -}; diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx index 91adf32..d8095cc 100644 --- a/Source/CPack/cmCPackPKGGenerator.cxx +++ b/Source/CPack/cmCPackPKGGenerator.cxx @@ -162,6 +162,8 @@ void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile, CreateChoice(PostFlightComponent, xout); } + this->CreateDomains(xout); + // default background this->CreateBackground(nullptr, metapackageFile, genName, xout); // Dark Aqua @@ -210,9 +212,14 @@ void cmCPackPKGGenerator::CreateChoice(const cmCPackComponentGroup& group, void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component, cmXMLWriter& xout) { - std::string packageId = - cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"), '.', - this->GetOption("CPACK_PACKAGE_NAME"), '.', component.Name); + std::string packageId; + if (cmValue i = this->GetOption("CPACK_PRODUCTBUILD_IDENTIFIER")) { + packageId = cmStrCat(i, '.', component.Name); + } else { + packageId = + cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"), '.', + this->GetOption("CPACK_PACKAGE_NAME"), '.', component.Name); + } xout.StartElement("choice"); xout.Attribute("id", component.Name + "Choice"); @@ -268,7 +275,10 @@ void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component, xout.Attribute("id", packageId); xout.Attribute("version", this->GetOption("CPACK_PACKAGE_VERSION")); xout.Attribute("installKBytes", installedSize); - xout.Attribute("auth", "Admin"); + // The auth attribute is deprecated in favor of the domains element + if (cmIsOff(this->GetOption("CPACK_PRODUCTBUILD_DOMAINS"))) { + xout.Attribute("auth", "Admin"); + } xout.Attribute("onConclusion", "None"); if (component.IsDownloaded) { xout.Content(this->GetOption("CPACK_DOWNLOAD_SITE")); @@ -281,6 +291,36 @@ void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component, xout.EndElement(); // pkg-ref } +void cmCPackPKGGenerator::CreateDomains(cmXMLWriter& xout) +{ + std::string opt = "CPACK_PRODUCTBUILD_DOMAINS"; + if (cmIsOff(this->GetOption(opt))) { + return; + } + + xout.StartElement("domains"); + + // Product can be installed at the root of any volume by default + // unless specified + cmValue param = this->GetOption(cmStrCat(opt, "_ANYWHERE")); + xout.Attribute("enable_anywhere", + (param && cmIsOff(param)) ? "false" : "true"); + + // Product cannot be installed into the current user's home directory + // by default unless specified + param = this->GetOption(cmStrCat(opt, "_USER")); + xout.Attribute("enable_currentUserHome", + (param && cmIsOn(param)) ? "true" : "false"); + + // Product can be installed into the root directory by default + // unless specified + param = this->GetOption(cmStrCat(opt, "_ROOT")); + xout.Attribute("enable_localSystem", + (param && cmIsOff(param)) ? "false" : "true"); + + xout.EndElement(); +} + void cmCPackPKGGenerator::AddDependencyAttributes( const cmCPackComponent& component, std::set<const cmCPackComponent*>& visited, std::ostringstream& out) diff --git a/Source/CPack/cmCPackPKGGenerator.h b/Source/CPack/cmCPackPKGGenerator.h index 17cdcdf..256b334 100644 --- a/Source/CPack/cmCPackPKGGenerator.h +++ b/Source/CPack/cmCPackPKGGenerator.h @@ -43,7 +43,8 @@ protected: // which will be configured via ConfigureFile. bool CopyCreateResourceFile(const std::string& name, const std::string& dirName); - bool CopyResourcePlistFile(const std::string& name, const char* outName = 0); + bool CopyResourcePlistFile(const std::string& name, + const char* outName = nullptr); int CopyInstallScript(const std::string& resdir, const std::string& script, const std::string& name); @@ -90,6 +91,10 @@ protected: void CreateBackground(const char* themeName, const char* metapackageFile, cm::string_view genName, cmXMLWriter& xout); + /// Create the "domains" XML element to indicate where the product can + /// be installed + void CreateDomains(cmXMLWriter& xout); + // The PostFlight component when creating a metapackage cmCPackComponent PostFlightComponent; }; diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx index f55b8de..4ad616d 100644 --- a/Source/CPack/cmCPackProductBuildGenerator.cxx +++ b/Source/CPack/cmCPackProductBuildGenerator.cxx @@ -95,6 +95,10 @@ int cmCPackProductBuildGenerator::PackageFiles() if (cmValue p = this->GetOption("CPACK_PRODUCTBUILD_KEYCHAIN_PATH")) { keychainPath = p; } + std::string identifier; + if (cmValue i = this->GetOption("CPACK_PRODUCTBUILD_IDENTIFIER")) { + identifier = i; + } pkgCmd << productbuild << " --distribution \"" << packageDirFileName << "/Contents/distribution.dist\"" @@ -102,6 +106,7 @@ int cmCPackProductBuildGenerator::PackageFiles() << "\"" << " --resources \"" << resDir << "\"" << " --version \"" << version << "\"" + << (identifier.empty() ? "" : " --identifier \"" + identifier + "\"") << (identityName.empty() ? "" : " --sign \"" + identityName + "\"") << (keychainPath.empty() ? "" : " --keychain \"" + keychainPath + "\"") @@ -204,8 +209,13 @@ bool cmCPackProductBuildGenerator::GenerateComponentPackage( // The command that will be used to run ProductBuild std::ostringstream pkgCmd; - std::string pkgId = cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"), - '.', this->GetOption("CPACK_PACKAGE_NAME")); + std::string pkgId; + if (cmValue n = this->GetOption("CPACK_PRODUCTBUILD_IDENTIFIER")) { + pkgId = n; + } else { + pkgId = cmStrCat("com.", this->GetOption("CPACK_PACKAGE_VENDOR"), '.', + this->GetOption("CPACK_PACKAGE_NAME")); + } if (component) { pkgId += '.'; pkgId += component->Name; diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx index 9e50700..3d4d05e 100644 --- a/Source/CPack/cmCPackRPMGenerator.cxx +++ b/Source/CPack/cmCPackRPMGenerator.cxx @@ -329,9 +329,10 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) if (retval) { this->AddGeneratedPackageNames(); + return retval; } - return retval; + return 0; } int cmCPackRPMGenerator::PackageComponentsAllInOne( @@ -424,7 +425,7 @@ std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix( } if (this->componentPackageMethod == ONE_PACKAGE) { - return std::string("ALL_COMPONENTS_IN_ONE"); + return { "ALL_COMPONENTS_IN_ONE" }; } // We have to find the name of the COMPONENT GROUP // the current COMPONENT belongs to. diff --git a/Source/CPack/cmCPackRPMGenerator.h b/Source/CPack/cmCPackRPMGenerator.h index 0288f2f..886afb1 100644 --- a/Source/CPack/cmCPackRPMGenerator.h +++ b/Source/CPack/cmCPackRPMGenerator.h @@ -32,9 +32,9 @@ public: #ifdef __APPLE__ // on MacOS enable CPackRPM iff rpmbuild is found std::vector<std::string> locations; - locations.push_back("/sw/bin"); // Fink - locations.push_back("/opt/local/bin"); // MacPorts - return cmSystemTools::FindProgram("rpmbuild") != "" ? true : false; + locations.emplace_back("/sw/bin"); // Fink + locations.emplace_back("/opt/local/bin"); // MacPorts + return !cmSystemTools::FindProgram("rpmbuild").empty(); #else // legacy behavior on other systems return true; diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx index 1340fb5..6ad3755 100644 --- a/Source/CPack/cmCPackSTGZGenerator.cxx +++ b/Source/CPack/cmCPackSTGZGenerator.cxx @@ -107,7 +107,7 @@ int cmCPackSTGZGenerator::GenerateHeader(std::ostream* os) cmCPackLogger(cmCPackLog::LOG_DEBUG, "Number of lines: " << counter << std::endl); char buffer[1024]; - sprintf(buffer, "%d", counter); + snprintf(buffer, sizeof(buffer), "%d", counter); cmSystemTools::ReplaceString(res, headerLengthTag, buffer); // Write in file diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index 54fd358..f43642f 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -67,7 +67,7 @@ struct cpackDefinitions { using MapType = std::map<std::string, std::string>; MapType Map; - cmCPackLog* Log; + cmCPackLog* Log{}; }; int cpackDefinitionArgument(const char* argument, const char* cValue, diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index a353435..0fe4ff4 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -20,9 +20,9 @@ #include "cmSystemTools.h" #include "cmXMLParser.h" -extern "C" int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/, - const XML_Char* name, - XML_Encoding* info) +static int cmBZRXMLParserUnknownEncodingHandler(void* /*unused*/, + const XML_Char* name, + XML_Encoding* info) { static const int latin1[] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index adfc8ef..e09b4dd 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -9,6 +9,7 @@ #include "cmsys/Process.h" +#include "cmBuildOptions.h" #include "cmCTest.h" #include "cmCTestTestHandler.h" #include "cmGlobalGenerator.h" @@ -263,10 +264,13 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) if (!config) { config = "Debug"; } + + cmBuildOptions buildOptions(!this->BuildNoClean, false, + PackageResolveMode::Disable); int retVal = cm.GetGlobalGenerator()->Build( cmake::NO_BUILD_PARALLEL_LEVEL, this->SourceDir, this->BinaryDir, this->BuildProject, { tar }, output, this->BuildMakeProgram, config, - !this->BuildNoClean, false, false, remainingTime); + buildOptions, false, remainingTime); out << output; // if the build failed then return if (retVal) { diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h index b9cc35c..e022e68 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.h +++ b/Source/CTest/cmCTestBuildAndTestHandler.h @@ -4,12 +4,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <sstream> #include <string> #include <vector> -#include <stddef.h> - #include "cmCTestGenericHandler.h" #include "cmDuration.h" diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index f9c4a8e..2aba79d 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -81,6 +81,7 @@ static const char* cmCTestErrorMatches[] = { "^The project cannot be built\\.", "^\\[ERROR\\]", "^Command .* failed with exit code", + "lcc: \"([^\"]+)\", (line|строка) ([0-9]+): (error|ошибка)", nullptr }; @@ -122,6 +123,7 @@ static const char* cmCTestWarningMatches[] = { "cc-[0-9]* CC: REMARK File = .*, Line = [0-9]*", "^CMake Warning.*:", "^\\[WARNING\\]", + "lcc: \"([^\"]+)\", (line|строка) ([0-9]+): (warning|предупреждение)", nullptr }; @@ -160,6 +162,9 @@ static cmCTestBuildCompileErrorWarningRex cmCTestWarningErrorFileLine[] = { { "^([a-zA-Z./0-9_+ ~-]+)\\(([0-9]+)\\)", 1, 2 }, { "\"([a-zA-Z./0-9_+ ~-]+)\", line ([0-9]+)", 1, 2 }, { "File = ([a-zA-Z./0-9_+ ~-]+), Line = ([0-9]+)", 1, 2 }, + { "lcc: \"([^\"]+)\", (line|строка) ([0-9]+): " + "(error|ошибка|warning|предупреждение)", + 1, 3 }, { nullptr, 0, 0 } }; diff --git a/Source/CTest/cmCTestBuildHandler.h b/Source/CTest/cmCTestBuildHandler.h index 58e8d9c..e33294d 100644 --- a/Source/CTest/cmCTestBuildHandler.h +++ b/Source/CTest/cmCTestBuildHandler.h @@ -5,13 +5,12 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <chrono> +#include <cstddef> #include <deque> #include <iosfwd> #include <string> #include <vector> -#include <stddef.h> - #include "cmsys/RegularExpression.hxx" #include "cmCTestGenericHandler.h" diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 57b1dda..1b2f769 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -49,9 +49,8 @@ public: } ~cmCTestRunProcess() { - if (!(this->PipeState == -1) && - !(this->PipeState == cmsysProcess_Pipe_None) && - !(this->PipeState == cmsysProcess_Pipe_Timeout)) { + if (this->PipeState != -1 && this->PipeState != cmsysProcess_Pipe_None && + this->PipeState != cmsysProcess_Pipe_Timeout) { this->WaitForExit(); } cmsysProcess_Delete(this->Process); @@ -148,7 +147,8 @@ bool cmCTestCoverageHandler::StartCoverageLogFile( cmGeneratedFileStream& covLogFile, int logFileCount) { char covLogFilename[1024]; - sprintf(covLogFilename, "CoverageLog-%d", logFileCount); + snprintf(covLogFilename, sizeof(covLogFilename), "CoverageLog-%d", + logFileCount); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Open file: " << covLogFilename << std::endl, this->Quiet); @@ -165,7 +165,8 @@ void cmCTestCoverageHandler::EndCoverageLogFile(cmGeneratedFileStream& ostr, int logFileCount) { char covLogFilename[1024]; - sprintf(covLogFilename, "CoverageLog-%d.xml", logFileCount); + snprintf(covLogFilename, sizeof(covLogFilename), "CoverageLog-%d.xml", + logFileCount); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, "Close file: " << covLogFilename << std::endl, this->Quiet); @@ -692,7 +693,7 @@ void cmCTestCoverageHandler::PopulateCustomVectors(cmMakefile* mf) # define fnc_prefix(s, t) cmHasPrefix(s, t) #endif -bool IsFileInDir(const std::string& infile, const std::string& indir) +static bool IsFileInDir(const std::string& infile, const std::string& indir) { std::string file = cmSystemTools::CollapseFullPath(infile); std::string dir = cmSystemTools::CollapseFullPath(indir); diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index d85edcc..56f805c 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -24,7 +24,7 @@ static unsigned int cmCTestGITVersion(unsigned int epic, unsigned int major, unsigned int minor, unsigned int fix) { // 1.6.5.0 maps to 10605000 - return fix + minor * 1000 + major * 100000 + epic * 10000000; + return epic * 10000000 + major * 100000 + minor * 1000 + fix; } cmCTestGIT::cmCTestGIT(cmCTest* ct, std::ostream& log) @@ -582,16 +582,17 @@ private: time_t seconds = static_cast<time_t>(person.Time); struct tm* t = gmtime(&seconds); char dt[1024]; - sprintf(dt, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, - t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + snprintf(dt, sizeof(dt), "%04d-%02d-%02d %02d:%02d:%02d", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, + t->tm_min, t->tm_sec); std::string out = dt; // Add the time-zone field "+zone" or "-zone". char tz[32]; if (person.TimeZone >= 0) { - sprintf(tz, " +%04ld", person.TimeZone); + snprintf(tz, sizeof(tz), " +%04ld", person.TimeZone); } else { - sprintf(tz, " -%04ld", -person.TimeZone); + snprintf(tz, sizeof(tz), " -%04ld", -person.TimeZone); } out += tz; return out; diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h index b4b0ad8..4bdb9c2 100644 --- a/Source/CTest/cmCTestGenericHandler.h +++ b/Source/CTest/cmCTestGenericHandler.h @@ -4,12 +4,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <map> #include <string> #include <vector> -#include <stddef.h> - #include "cmCTest.h" #include "cmSystemTools.h" #include "cmValue.h" diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx index 15c443a..4a33869 100644 --- a/Source/CTest/cmCTestLaunch.cxx +++ b/Source/CTest/cmCTestLaunch.cxx @@ -20,9 +20,10 @@ #include "cmake.h" #ifdef _WIN32 +# include <cstdio> // for std{out,err} and fileno + # include <fcntl.h> // for _O_BINARY # include <io.h> // for _setmode -# include <stdio.h> // for std{out,err} and fileno #endif cmCTestLaunch::cmCTestLaunch(int argc, const char* const* argv) diff --git a/Source/CTest/cmCTestLaunch.h b/Source/CTest/cmCTestLaunch.h index eabb608..c5a6476 100644 --- a/Source/CTest/cmCTestLaunch.h +++ b/Source/CTest/cmCTestLaunch.h @@ -24,14 +24,14 @@ public: /** Entry point from ctest executable main(). */ static int Main(int argc, const char* const argv[]); + cmCTestLaunch(const cmCTestLaunch&) = delete; + cmCTestLaunch& operator=(const cmCTestLaunch&) = delete; + private: // Initialize the launcher from its command line. cmCTestLaunch(int argc, const char* const* argv); ~cmCTestLaunch(); - cmCTestLaunch(const cmCTestLaunch&) = delete; - cmCTestLaunch& operator=(const cmCTestLaunch&) = delete; - // Run the real command. int Run(); void RunChild(); diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx index 5334a93..149ba5d 100644 --- a/Source/CTest/cmCTestLaunchReporter.cxx +++ b/Source/CTest/cmCTestLaunchReporter.cxx @@ -13,9 +13,10 @@ #include "cmXMLWriter.h" #ifdef _WIN32 +# include <cstdio> // for std{out,err} and fileno + # include <fcntl.h> // for _O_BINARY # include <io.h> // for _setmode -# include <stdio.h> // for std{out,err} and fileno #endif cmCTestLaunchReporter::cmCTestLaunchReporter() diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h index 5de42f9..2f5ad40 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.h +++ b/Source/CTest/cmCTestMultiProcessHandler.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <map> #include <memory> #include <set> @@ -11,7 +12,6 @@ #include <vector> #include <cm3p/uv.h> -#include <stddef.h> #include "cmCTest.h" #include "cmCTestResourceAllocator.h" diff --git a/Source/CTest/cmCTestP4.h b/Source/CTest/cmCTestP4.h index d03f9cb..1889520 100644 --- a/Source/CTest/cmCTestP4.h +++ b/Source/CTest/cmCTestP4.h @@ -34,14 +34,6 @@ private: std::string Name; std::string EMail; std::string AccessTime; - - User() - : UserName() - , Name() - , EMail() - , AccessTime() - { - } }; std::map<std::string, User> Users; std::vector<std::string> P4Options; diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 9d2cef6..6cd3b09 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -229,7 +229,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) passed = this->TestResult.Status == cmCTestTestHandler::COMPLETED; char buf[1024]; - sprintf(buf, "%6.2f sec", this->TestProcess->GetTotalTime().count()); + snprintf(buf, sizeof(buf), "%6.2f sec", + this->TestProcess->GetTotalTime().count()); outputStream << buf << "\n"; bool passedOrSkipped = passed || skipped; @@ -294,9 +295,10 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) ttime -= minutes; auto seconds = std::chrono::duration_cast<std::chrono::seconds>(ttime); char buffer[100]; - sprintf(buffer, "%02d:%02d:%02d", static_cast<unsigned>(hours.count()), - static_cast<unsigned>(minutes.count()), - static_cast<unsigned>(seconds.count())); + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", + static_cast<unsigned>(hours.count()), + static_cast<unsigned>(minutes.count()), + static_cast<unsigned>(seconds.count())); *this->TestHandler->LogFile << "----------------------------------------------------------" << std::endl; diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h index 2082156..7a97fa9 100644 --- a/Source/CTest/cmCTestRunTest.h +++ b/Source/CTest/cmCTestRunTest.h @@ -4,14 +4,13 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <map> #include <memory> #include <set> #include <string> #include <vector> -#include <stddef.h> - #include "cmCTest.h" #include "cmCTestMultiProcessHandler.h" #include "cmCTestTestHandler.h" diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index f685f66..16c0a0e 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -48,8 +48,6 @@ # include <unistd.h> #endif -#define CTEST_INITIAL_CMAKE_OUTPUT_FILE_NAME "CTestInitialCMakeOutput.log" - cmCTestScriptHandler::cmCTestScriptHandler() = default; void cmCTestScriptHandler::Initialize() @@ -411,7 +409,7 @@ int cmCTestScriptHandler::ExtractVariables() char updateVar[40]; int i; for (i = 1; i < 10; ++i) { - sprintf(updateVar, "CTEST_EXTRA_UPDATES_%i", i); + snprintf(updateVar, sizeof(updateVar), "CTEST_EXTRA_UPDATES_%i", i); cmValue updateVal = this->Makefile->GetDefinition(updateVar); if (updateVal) { if (this->UpdateCmd.empty()) { diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index c4f87e9..a2dc615 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -58,6 +58,9 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() this->CTest->SetCTestConfigurationFromCMakeVariable( this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet); + this->CTest->SetCTestConfigurationFromCMakeVariable( + this->Makefile, "SubmitInactivityTimeout", + "CTEST_SUBMIT_INACTIVITY_TIMEOUT", this->Quiet); cmValue notesFilesVariable = this->Makefile->GetDefinition("CTEST_NOTES_FILES"); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index b99bb79..fae5e30 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -7,6 +7,7 @@ #include <cstdlib> #include <sstream> +#include <cm/iomanip> #include <cmext/algorithm> #include <cm3p/curl/curl.h> @@ -216,8 +217,11 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP( // if there is little to no activity for too long stop submitting ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1); - ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, - SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT); + auto submitInactivityTimeout = this->GetSubmitInactivityTimeout(); + if (submitInactivityTimeout != 0) { + ::curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, + submitInactivityTimeout); + } /* HTTP PUT please */ ::curl_easy_setopt(curl, CURLOPT_PUT, 1); @@ -499,7 +503,10 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions")); std::vector<std::string> args = cmExpandedList(curlopt); curl.SetCurlOptions(args); - curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT); + auto submitInactivityTimeout = this->GetSubmitInactivityTimeout(); + if (submitInactivityTimeout != 0) { + curl.SetTimeOutSeconds(submitInactivityTimeout); + } curl.SetHttpHeaders(this->HttpHeaders); std::string url = this->CTest->GetSubmitURL(); if (!cmHasLiteralPrefix(url, "http://") && @@ -893,6 +900,26 @@ void cmCTestSubmitHandler::SelectParts(std::set<cmCTest::Part> const& parts) } } +int cmCTestSubmitHandler::GetSubmitInactivityTimeout() +{ + int submitInactivityTimeout = SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT; + std::string const& timeoutStr = + this->CTest->GetCTestConfiguration("SubmitInactivityTimeout"); + if (!timeoutStr.empty()) { + unsigned long timeout; + if (cmStrToULong(timeoutStr, &timeout)) { + submitInactivityTimeout = static_cast<int>(timeout); + } else { + cmCTestLog(this->CTest, ERROR_MESSAGE, + "SubmitInactivityTimeout is invalid: " + << cm::quoted(timeoutStr) << "." + << " Using a default value of " + << SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT << "." << std::endl); + } + } + return submitInactivityTimeout; +} + void cmCTestSubmitHandler::SelectFiles(std::set<std::string> const& files) { this->Files.insert(files.begin(), files.end()); diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index 809c615..0c7253c 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -63,6 +63,7 @@ private: void ParseResponse(cmCTestSubmitHandlerVectorOfChar chunk); std::string GetSubmitResultsPrefix(); + int GetSubmitInactivityTimeout(); class ResponseParser; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 6e97a83..5a3a8d0 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -59,6 +59,8 @@ public: } virtual ~cmCTestCommand() = default; + cmCTestCommand(const cmCTestCommand&) = default; + cmCTestCommand& operator=(const cmCTestCommand&) = default; bool operator()(std::vector<cmListFileArgument> const& args, cmExecutionStatus& status) @@ -79,6 +81,42 @@ public: cmCTestTestHandler* TestHandler; }; +bool ReadSubdirectory(std::string fname, cmExecutionStatus& status) +{ + if (!cmSystemTools::FileExists(fname)) { + // No subdirectory? So what... + return true; + } + bool readit = false; + { + cmWorkingDirectory workdir(fname); + if (workdir.Failed()) { + status.SetError("Failed to change directory to " + fname + " : " + + std::strerror(workdir.GetLastResult())); + return false; + } + const char* testFilename; + if (cmSystemTools::FileExists("CTestTestfile.cmake")) { + // does the CTestTestfile.cmake exist ? + testFilename = "CTestTestfile.cmake"; + } else if (cmSystemTools::FileExists("DartTestfile.txt")) { + // does the DartTestfile.txt exist ? + testFilename = "DartTestfile.txt"; + } else { + // No CTestTestfile? Who cares... + return true; + } + fname += "/"; + fname += testFilename; + readit = status.GetMakefile().ReadDependentFile(fname); + } + if (!readit) { + status.SetError(cmStrCat("Could not find include file: ", fname)); + return false; + } + return true; +} + bool cmCTestSubdirCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -96,35 +134,7 @@ bool cmCTestSubdirCommand(std::vector<std::string> const& args, fname = cmStrCat(cwd, '/', arg); } - if (!cmSystemTools::FileIsDirectory(fname)) { - // No subdirectory? So what... - continue; - } - bool readit = false; - { - cmWorkingDirectory workdir(fname); - if (workdir.Failed()) { - status.SetError("Failed to change directory to " + fname + " : " + - std::strerror(workdir.GetLastResult())); - return false; - } - const char* testFilename; - if (cmSystemTools::FileExists("CTestTestfile.cmake")) { - // does the CTestTestfile.cmake exist ? - testFilename = "CTestTestfile.cmake"; - } else if (cmSystemTools::FileExists("DartTestfile.txt")) { - // does the DartTestfile.txt exist ? - testFilename = "DartTestfile.txt"; - } else { - // No CTestTestfile? Who cares... - continue; - } - fname += "/"; - fname += testFilename; - readit = status.GetMakefile().ReadDependentFile(fname); - } - if (!readit) { - status.SetError(cmStrCat("Could not load include file: ", fname)); + if (!ReadSubdirectory(std::move(fname), status)) { return false; } } @@ -142,32 +152,7 @@ bool cmCTestAddSubdirectoryCommand(std::vector<std::string> const& args, std::string fname = cmStrCat(cmSystemTools::GetCurrentWorkingDirectory(), '/', args[0]); - if (!cmSystemTools::FileExists(fname)) { - // No subdirectory? So what... - return true; - } - bool readit = false; - { - const char* testFilename; - if (cmSystemTools::FileExists("CTestTestfile.cmake")) { - // does the CTestTestfile.cmake exist ? - testFilename = "CTestTestfile.cmake"; - } else if (cmSystemTools::FileExists("DartTestfile.txt")) { - // does the DartTestfile.txt exist ? - testFilename = "DartTestfile.txt"; - } else { - // No CTestTestfile? Who cares... - return true; - } - fname += "/"; - fname += testFilename; - readit = status.GetMakefile().ReadDependentFile(fname); - } - if (!readit) { - status.SetError(cmStrCat("Could not find include file: ", fname)); - return false; - } - return true; + return ReadSubdirectory(std::move(fname), status); } class cmCTestAddTestCommand : public cmCTestCommand @@ -621,7 +606,7 @@ void cmCTestTestHandler::LogTestSummary(const std::vector<std::string>& passed, this->PrintLabelOrSubprojectSummary(false); } char realBuf[1024]; - sprintf(realBuf, "%6.2f sec", durationInSecs.count()); + snprintf(realBuf, sizeof(realBuf), "%6.2f sec", durationInSecs.count()); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "\nTotal Test time (real) = " << realBuf << "\n", this->Quiet); @@ -782,7 +767,7 @@ void cmCTestTestHandler::PrintLabelOrSubprojectSummary(bool doSubProject) label.resize(maxlen + 3, ' '); char buf[1024]; - sprintf(buf, "%6.2f sec*proc", labelTimes[i]); + snprintf(buf, sizeof(buf), "%6.2f sec*proc", labelTimes[i]); std::ostringstream labelCountStr; labelCountStr << "(" << labelCounts[i] << " test"; @@ -2181,7 +2166,7 @@ bool cmCTestTestHandler::SetTestsProperties( // Ensure we have complete triples otherwise the data is corrupt. if (triples.size() % 3 == 0) { cmState state(cmState::Unknown); - rt.Backtrace = cmListFileBacktrace(state.CreateBaseSnapshot()); + rt.Backtrace = cmListFileBacktrace(); // the first entry represents the top of the trace so we need to // reconstruct the backtrace in reverse diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 3ac05e7..135e764 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <chrono> +#include <cstddef> #include <cstdint> #include <iosfwd> #include <map> @@ -13,8 +14,6 @@ #include <utility> #include <vector> -#include <stddef.h> - #include "cmsys/RegularExpression.hxx" #include "cmCTest.h" diff --git a/Source/CTest/cmCTestVC.cxx b/Source/CTest/cmCTestVC.cxx index 423b506..d5711c5 100644 --- a/Source/CTest/cmCTestVC.cxx +++ b/Source/CTest/cmCTestVC.cxx @@ -123,9 +123,10 @@ std::string cmCTestVC::GetNightlyTime() this->CTest->GetCTestConfiguration("NightlyStartTime"), this->CTest->GetTomorrowTag()); char current_time[1024]; - sprintf(current_time, "%04d-%02d-%02d %02d:%02d:%02d", t->tm_year + 1900, - t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); - return std::string(current_time); + snprintf(current_time, sizeof(current_time), "%04d-%02d-%02d %02d:%02d:%02d", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, + t->tm_sec); + return { current_time }; } void cmCTestVC::Cleanup() diff --git a/Source/CTest/cmCTestVC.h b/Source/CTest/cmCTestVC.h index 9bd7229..7b03d10 100644 --- a/Source/CTest/cmCTestVC.h +++ b/Source/CTest/cmCTestVC.h @@ -95,15 +95,10 @@ protected: /** Represent change to one file. */ struct File { - PathStatus Status; - Revision const* Rev; - Revision const* PriorRev; - File() - : Status(PathUpdated) - , Rev(nullptr) - , PriorRev(nullptr) - { - } + PathStatus Status = PathUpdated; + Revision const* Rev = nullptr; + Revision const* PriorRev = nullptr; + File() = default; File(PathStatus status, Revision const* rev, Revision const* priorRev) : Status(status) , Rev(rev) diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 16bca01..e14a4e1 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -511,7 +511,7 @@ std::string cmProcess::GetExitExceptionString() const default: char buf[1024]; const char* fmt = "Exit code 0x%" KWIML_INT_PRIx64 "\n"; - _snprintf(buf, 1024, fmt, this->ExitValue); + snprintf(buf, sizeof(buf), fmt, this->ExitValue); exception_str.assign(buf); } #else diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h index a44aeb0..be030e4 100644 --- a/Source/CTest/cmProcess.h +++ b/Source/CTest/cmProcess.h @@ -5,14 +5,14 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <chrono> +#include <cstddef> +#include <cstdint> #include <memory> #include <string> #include <utility> #include <vector> #include <cm3p/uv.h> -#include <stddef.h> -#include <stdint.h> #include "cmDuration.h" #include "cmProcessOutput.h" @@ -52,9 +52,9 @@ public: }; State GetProcessStatus(); - int GetId() { return this->Id; } + int GetId() const { return this->Id; } void SetId(int id) { this->Id = id; } - int64_t GetExitValue() { return this->ExitValue; } + int64_t GetExitValue() const { return this->ExitValue; } cmDuration GetTotalTime() { return this->TotalTime; } enum class Exception @@ -111,15 +111,11 @@ private: class Buffer : public std::vector<char> { // Half-open index range of partial line already scanned. - size_type First; - size_type Last; + size_type First = 0; + size_type Last = 0; public: - Buffer() - : First(0) - , Last(0) - { - } + Buffer() = default; bool GetLine(std::string& line); bool GetLast(std::string& line); }; diff --git a/Source/Checks/cm_c11_thread_local.cmake b/Source/Checks/cm_c11_thread_local.cmake index 2263be3..f59688d 100644 --- a/Source/Checks/cm_c11_thread_local.cmake +++ b/Source/Checks/cm_c11_thread_local.cmake @@ -1,5 +1,5 @@ set(CMake_C11_THREAD_LOCAL_BROKEN 0) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_C11_STANDARD_COMPILE_OPTION) +if((CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "LCC") AND CMAKE_C11_STANDARD_COMPILE_OPTION) if(NOT DEFINED CMake_C11_THREAD_LOCAL_WORKS) include(${CMAKE_CURRENT_LIST_DIR}/cm_message_checks_compat.cmake) cm_message_checks_compat( diff --git a/Source/Checks/cm_cxx14_check.cmake b/Source/Checks/cm_cxx14_check.cmake index e5656bf..abf232a 100644 --- a/Source/Checks/cm_cxx14_check.cmake +++ b/Source/Checks/cm_cxx14_check.cmake @@ -1,5 +1,5 @@ set(CMake_CXX14_BROKEN 0) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|LCC|Clang|PGI|Intel") if(NOT CMAKE_CXX14_STANDARD_COMPILE_OPTION) set(CMake_CXX14_WORKS 0) endif() diff --git a/Source/Checks/cm_cxx17_check.cmake b/Source/Checks/cm_cxx17_check.cmake index dba3eaf..78a2382 100644 --- a/Source/Checks/cm_cxx17_check.cmake +++ b/Source/Checks/cm_cxx17_check.cmake @@ -1,5 +1,5 @@ set(CMake_CXX17_BROKEN 0) -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|PGI|Intel") +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|LCC|Clang|PGI|Intel") if(NOT CMAKE_CXX17_STANDARD_COMPILE_OPTION) set(CMake_CXX17_WORKS 0) endif() diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 1ba45e5..1f7776c 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -9,8 +9,6 @@ #include <string> #include <vector> -#include <unistd.h> - #include "cmsys/Encoding.hxx" #include "cmCursesColor.h" @@ -53,31 +51,18 @@ static const char* cmDocumentationOptions[][2] = { cmCursesForm* cmCursesForm::CurrentForm = nullptr; +#ifndef _WIN32 extern "C" { -void onsig(int /*unused*/) +static void onsig(int /*unused*/) { if (cmCursesForm::CurrentForm) { - endwin(); - if (initscr() == nullptr) { - static const char errmsg[] = "Error: ncurses initialization failed\n"; - auto r = write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); - static_cast<void>(r); - exit(1); - } - noecho(); /* Echo off */ - cbreak(); /* nl- or cr not needed */ - keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ - refresh(); - int x; - int y; - getmaxyx(stdscr, y, x); - cmCursesForm::CurrentForm->Render(1, 1, x, y); - cmCursesForm::CurrentForm->UpdateStatusBar(); + cmCursesForm::CurrentForm->HandleResize(); } signal(SIGWINCH, onsig); } } +#endif // _WIN32 int main(int argc, char const* const* argv) { @@ -143,7 +128,9 @@ int main(int argc, char const* const* argv) keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ cmCursesColor::InitColors(); +#ifndef _WIN32 signal(SIGWINCH, onsig); +#endif // _WIN32 int x; int y; diff --git a/Source/CursesDialog/cmCursesForm.cxx b/Source/CursesDialog/cmCursesForm.cxx index bd65c4a..ef36b45 100644 --- a/Source/CursesDialog/cmCursesForm.cxx +++ b/Source/CursesDialog/cmCursesForm.cxx @@ -2,6 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCursesForm.h" +#include <cstdlib> +#ifndef _WIN32 +# include <unistd.h> +#endif // _WIN32 + cmsys::ofstream cmCursesForm::DebugFile; bool cmCursesForm::Debug = false; @@ -43,3 +48,27 @@ void cmCursesForm::LogMessage(const char* msg) cmCursesForm::DebugFile << msg << std::endl; } + +void cmCursesForm::HandleResize() +{ + endwin(); + if (initscr() == nullptr) { + static const char errmsg[] = "Error: ncurses initialization failed\n"; +#ifdef _WIN32 + fprintf(stderr, "%s", errmsg); +#else + auto r = write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1); + static_cast<void>(r); +#endif // _WIN32 + exit(1); + } + noecho(); /* Echo off */ + cbreak(); /* nl- or cr not needed */ + keypad(stdscr, true); /* Use key symbols as KEY_DOWN */ + refresh(); + int x; + int y; + getmaxyx(stdscr, y, x); + this->Render(1, 1, x, y); + this->UpdateStatusBar(); +} diff --git a/Source/CursesDialog/cmCursesForm.h b/Source/CursesDialog/cmCursesForm.h index 93459b9..3a1eb25 100644 --- a/Source/CursesDialog/cmCursesForm.h +++ b/Source/CursesDialog/cmCursesForm.h @@ -55,6 +55,10 @@ public: static cmCursesForm* CurrentForm; + // Description: + // Handle resizing the form with curses. + void HandleResize(); + protected: static cmsys::ofstream DebugFile; static bool Debug; diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index 591c546..9b3a649 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.cxx +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -78,7 +78,8 @@ void cmCursesLongMessageForm::UpdateStatusBar() char version[cmCursesMainForm::MAX_WIDTH]; char vertmp[128]; - sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion()); + snprintf(vertmp, sizeof(vertmp), "CMake Version %s", + cmVersion::GetCMakeVersion()); size_t sideSpace = (width - strlen(vertmp)); for (size_t i = 0; i < sideSpace; i++) { version[i] = ' '; @@ -105,7 +106,7 @@ void cmCursesLongMessageForm::PrintKeys() return; } char firstLine[512]; - sprintf(firstLine, "Press [e] to exit screen"); + snprintf(firstLine, sizeof(firstLine), "Press [e] to exit screen"); char fmt_s[] = "%s"; curses_move(y - 2, 0); @@ -176,7 +177,14 @@ void cmCursesLongMessageForm::HandleInput() this->PrintKeys(); int key = getch(); - sprintf(debugMessage, "Message widget handling input, key: %d", key); +#ifdef _WIN32 + if (key == KEY_RESIZE) { + HandleResize(); + } +#endif // _WIN32 + + snprintf(debugMessage, sizeof(debugMessage), + "Message widget handling input, key: %d", key); cmCursesForm::LogMessage(debugMessage); // quit diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index b28c5b7..11b3b35 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -322,22 +322,22 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */) memset(thirdLine, ' ', 68); } else { if (this->OkToGenerate) { - sprintf(firstLine, - " [l] Show log output [c] Configure" - " [g] Generate "); + snprintf(firstLine, sizeof(firstLine), + " [l] Show log output [c] Configure" + " [g] Generate "); } else { - sprintf(firstLine, - " [l] Show log output [c] Configure" - " "); + snprintf(firstLine, sizeof(firstLine), + " [l] Show log output [c] Configure" + " "); } { const char* toggleKeyInstruction = " [t] Toggle advanced mode (currently %s)"; - sprintf(thirdLine, toggleKeyInstruction, - this->AdvancedMode ? "on" : "off"); + snprintf(thirdLine, sizeof(thirdLine), toggleKeyInstruction, + this->AdvancedMode ? "on" : "off"); } - sprintf(secondLine, - " [h] Help [q] Quit without generating"); + snprintf(secondLine, sizeof(secondLine), + " [h] Help [q] Quit without generating"); } curses_move(y - 4, 0); @@ -356,7 +356,8 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */) if (cw) { char pageLine[512] = ""; - sprintf(pageLine, "Page %d of %d", cw->GetPage(), this->NumberOfPages); + snprintf(pageLine, sizeof(pageLine), "Page %d of %d", cw->GetPage(), + this->NumberOfPages); curses_move(0, 65 - static_cast<unsigned int>(strlen(pageLine)) - 1); printw(fmt_s, pageLine); } @@ -685,6 +686,12 @@ void cmCursesMainForm::HandleInput() } int key = getch(); +#ifdef _WIN32 + if (key == KEY_RESIZE) { + HandleResize(); + } +#endif // _WIN32 + getmaxyx(stdscr, y, x); // If window too small, handle 'q' only if (x < cmCursesMainForm::MIN_WIDTH || y < cmCursesMainForm::MIN_HEIGHT) { @@ -739,7 +746,8 @@ void cmCursesMainForm::HandleInput() if ((!currentWidget || !widgetHandled) && !this->SearchMode) { // If the current widget does not want to handle input, // we handle it. - sprintf(debugMessage, "Main form handling input, key: %d", key); + snprintf(debugMessage, sizeof(debugMessage), + "Main form handling input, key: %d", key); cmCursesForm::LogMessage(debugMessage); // quit if (key == 'q') { diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index 4830d63..c0d06ce 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -85,7 +85,8 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, // <Enter> is used to change edit mode (like <Esc> in vi). while (!this->Done) { - sprintf(debugMessage, "String widget handling input, key: %d", key); + snprintf(debugMessage, sizeof(debugMessage), + "String widget handling input, key: %d", key); cmCursesForm::LogMessage(debugMessage); fm->PrintKeys(); diff --git a/Source/CursesDialog/form/CMakeLists.txt b/Source/CursesDialog/form/CMakeLists.txt index 9202bc1..68d28c8 100644 --- a/Source/CursesDialog/form/CMakeLists.txt +++ b/Source/CursesDialog/form/CMakeLists.txt @@ -5,7 +5,7 @@ project(CMAKE_FORM) # Disable warnings to avoid changing 3rd party code. if(CMAKE_C_COMPILER_ID MATCHES - "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$") + "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall") diff --git a/Source/CursesDialog/form/fty_enum.c b/Source/CursesDialog/form/fty_enum.c index 59058a9..f1059b1 100644 --- a/Source/CursesDialog/form/fty_enum.c +++ b/Source/CursesDialog/form/fty_enum.c @@ -116,7 +116,7 @@ static int Compare(const unsigned char *s, const unsigned char *buf, if (*buf=='\0') { - return (((*s)!='\0') ? NOMATCH : EXACT); + return (((*s)=='\0') ? EXACT : NOMATCH); } else { @@ -144,7 +144,7 @@ static int Compare(const unsigned char *s, const unsigned char *buf, /* If it happens that the reference buffer is at its end, the partial match is actually an exact match. */ - return ((s[-1]!='\0') ? PARTIAL : EXACT); + return ((s[-1]=='\0') ? EXACT : PARTIAL); } /*--------------------------------------------------------------------------- diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx index 194ae0c..e588853 100644 --- a/Source/LexerParser/cmGccDepfileLexer.cxx +++ b/Source/LexerParser/cmGccDepfileLexer.cxx @@ -256,6 +256,7 @@ typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; +typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; @@ -420,7 +421,7 @@ struct yy_buffer_state /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - int yy_n_chars; + yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -497,7 +498,7 @@ static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, yy_size_t len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); @@ -544,12 +545,12 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ + yyleng = (yy_size_t) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 11 -#define YY_END_OF_BUFFER 12 +#define YY_NUM_RULES 12 +#define YY_END_OF_BUFFER 13 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -557,11 +558,11 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[26] = +static const flex_int16_t yy_accept[31] = { 0, - 0, 0, 12, 10, 8, 6, 10, 9, 10, 10, - 10, 8, 0, 6, 9, 1, 7, 5, 0, 3, - 2, 0, 4, 0, 0 + 0, 0, 13, 11, 9, 6, 11, 10, 11, 11, + 11, 9, 0, 6, 10, 1, 8, 7, 0, 0, + 5, 0, 3, 2, 0, 8, 0, 4, 0, 0 } ; static const YY_CHAR yy_ec[256] = @@ -601,36 +602,40 @@ static const YY_CHAR yy_meta[11] = 1, 2, 1, 1, 2, 1, 1, 1, 1, 3 } ; -static const flex_int16_t yy_base[28] = +static const flex_int16_t yy_base[33] = { 0, - 0, 0, 29, 35, 18, 35, 22, 18, 15, 0, - 8, 12, 16, 35, 11, 35, 0, 35, 13, 35, - 35, 16, 35, 22, 35, 31, 12 + 0, 0, 36, 46, 25, 46, 31, 27, 18, 9, + 17, 15, 25, 46, 17, 46, 0, 46, 15, 27, + 46, 14, 46, 46, 27, 46, 13, 46, 33, 46, + 42, 13 } ; -static const flex_int16_t yy_def[28] = +static const flex_int16_t yy_def[33] = { 0, - 25, 1, 25, 25, 26, 25, 25, 25, 25, 27, - 25, 26, 25, 25, 25, 25, 27, 25, 25, 25, - 25, 25, 25, 25, 0, 25, 25 + 30, 1, 30, 30, 31, 30, 30, 30, 30, 30, + 30, 31, 30, 30, 30, 30, 32, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, + 30, 30 } ; -static const flex_int16_t yy_nxt[46] = +static const flex_int16_t yy_nxt[57] = { 0, 4, 5, 6, 7, 5, 8, 4, 9, 10, 11, - 18, 19, 20, 17, 21, 18, 15, 22, 18, 19, - 23, 13, 16, 15, 14, 24, 20, 13, 25, 25, - 25, 22, 12, 12, 3, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25 + 17, 18, 19, 17, 17, 26, 21, 18, 20, 21, + 22, 23, 15, 24, 13, 16, 25, 21, 22, 26, + 27, 28, 15, 14, 13, 30, 29, 23, 30, 30, + 30, 30, 25, 12, 12, 3, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30 } ; -static const flex_int16_t yy_chk[46] = +static const flex_int16_t yy_chk[57] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 11, 11, 11, 27, 11, 19, 15, 11, 13, 13, - 22, 12, 9, 8, 7, 22, 24, 5, 3, 0, - 0, 24, 26, 26, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25 + 10, 10, 10, 10, 32, 27, 22, 19, 10, 11, + 11, 11, 15, 11, 12, 9, 11, 13, 13, 20, + 20, 25, 8, 7, 5, 3, 25, 29, 0, 0, + 0, 0, 29, 31, 31, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30 } ; /* The intent behind this definition is that it'll catch @@ -669,8 +674,8 @@ struct yyguts_t size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; - int yy_n_chars; - int yyleng_r; + yy_size_t yy_n_chars; + yy_size_t yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; @@ -717,7 +722,7 @@ FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); - int yyget_leng ( yyscan_t yyscanner ); + yy_size_t yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); @@ -790,7 +795,7 @@ static int input ( yyscan_t yyscanner ); if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ - int n; \ + yy_size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ @@ -926,13 +931,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 26 ) + if ( yy_current_state >= 31 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 35 ); + while ( yy_base[yy_current_state] != 46 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -1006,34 +1011,46 @@ YY_RULE_SETUP } YY_BREAK case 7: +/* rule 7 can match eol */ YY_RULE_SETUP { - // A colon followed by space ends the rules and starts a new dependency. + // A colon ends the rules yyextra->newDependency(); + // A newline after colon terminates current rule. + yyextra->newEntry(); } YY_BREAK case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ + // A colon followed by space or line continuation ends the rules + // and starts a new dependency. + yyextra->newDependency(); + } + YY_BREAK +case 9: YY_RULE_SETUP { // Rules and dependencies are separated by blocks of whitespace. yyextra->newRuleOrDependency(); } YY_BREAK -case 9: +case 10: YY_RULE_SETUP { // Got a span of plain text. yyextra->addToCurrentPath(yytext); } YY_BREAK -case 10: +case 11: YY_RULE_SETUP { // Got an otherwise unmatched character. yyextra->addToCurrentPath(yytext); } YY_BREAK -case 11: +case 12: YY_RULE_SETUP ECHO; YY_BREAK @@ -1224,7 +1241,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { - int num_to_read = + yy_size_t num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1238,7 +1255,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( b->yy_is_our_buffer ) { - int new_size = b->yy_buf_size * 2; + yy_size_t new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -1296,7 +1313,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) @@ -1335,7 +1352,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 26 ) + if ( yy_current_state >= 31 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1364,11 +1381,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 26 ) + if ( yy_current_state >= 31 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 25); + yy_is_jam = (yy_current_state == 30); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -1389,7 +1406,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - int number_to_move = yyg->yy_n_chars + 2; + yy_size_t number_to_move = yyg->yy_n_chars + 2; char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; char *source = @@ -1441,7 +1458,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) else { /* need more input */ - int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + yy_size_t offset = yyg->yy_c_buf_p - yyg->yytext_ptr; ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) @@ -1819,12 +1836,12 @@ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, yy_size_t _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; - int i; + yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); @@ -1868,7 +1885,7 @@ static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) do \ { \ /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ + yy_size_t yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ @@ -1936,7 +1953,7 @@ FILE *yyget_out (yyscan_t yyscanner) /** Get the length of the current token. * @param yyscanner The scanner object. */ -int yyget_leng (yyscan_t yyscanner) +yy_size_t yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; diff --git a/Source/LexerParser/cmGccDepfileLexer.h b/Source/LexerParser/cmGccDepfileLexer.h index 7d34060..ab73ebc 100644 --- a/Source/LexerParser/cmGccDepfileLexer.h +++ b/Source/LexerParser/cmGccDepfileLexer.h @@ -258,6 +258,7 @@ typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; +typedef uint64_t flex_uint64_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; @@ -371,7 +372,7 @@ struct yy_buffer_state /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - int yy_n_chars; + yy_size_t yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -415,7 +416,7 @@ void yypop_buffer_state ( yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); -YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, yy_size_t len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); @@ -462,7 +463,7 @@ FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); - int yyget_leng ( yyscan_t yyscanner ); + yy_size_t yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l index aa2351e..6336b5f 100644 --- a/Source/LexerParser/cmGccDepfileLexer.in.l +++ b/Source/LexerParser/cmGccDepfileLexer.in.l @@ -48,8 +48,15 @@ NEWLINE \r?\n // A newline ends the current file name and the current rule. yyextra->newEntry(); } -:{WSPACE}+ { - // A colon followed by space ends the rules and starts a new dependency. +:{NEWLINE} { + // A colon ends the rules + yyextra->newDependency(); + // A newline after colon terminates current rule. + yyextra->newEntry(); + } +:({WSPACE}+|\\{NEWLINE}) { + // A colon followed by space or line continuation ends the rules + // and starts a new dependency. yyextra->newDependency(); } {WSPACE}+ { diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 1785571..f90b781 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -730,12 +730,12 @@ void CMakeSetupDialog::updatePreset(const QString& name) } void CMakeSetupDialog::showPresetLoadError( - const QString& dir, cmCMakePresetsFile::ReadFileResult result) + const QString& dir, cmCMakePresetsGraph::ReadFileResult result) { QMessageBox::warning( this, "Error Reading CMake Presets", QString::fromLocal8Bit("Could not read presets from %1: %2") - .arg(dir, cmCMakePresetsFile::ResultToString(result))); + .arg(dir, cmCMakePresetsGraph::ResultToString(result))); } void CMakeSetupDialog::doBinaryBrowse() diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index f0cc929..8aee70d 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -60,7 +60,7 @@ protected slots: void updatePresets(const QVector<QCMakePreset>& presets); void updatePreset(const QString& name); void showPresetLoadError(const QString& dir, - cmCMakePresetsFile::ReadFileResult result); + cmCMakePresetsGraph::ReadFileResult result); void showProgress(const QString& msg, float percent); void setEnabledState(bool); bool setupFirstConfigure(); diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index 8ab8656..ffb6157 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -32,7 +32,7 @@ QCMake::QCMake(QObject* p) qRegisterMetaType<QCMakePropertyList>(); qRegisterMetaType<QProcessEnvironment>(); qRegisterMetaType<QVector<QCMakePreset>>(); - qRegisterMetaType<cmCMakePresetsFile::ReadFileResult>(); + qRegisterMetaType<cmCMakePresetsGraph::ReadFileResult>(); cmSystemTools::DisableRunCommandOutput(); cmSystemTools::SetRunCommandHideConsole(true); @@ -69,9 +69,9 @@ QCMake::QCMake(QObject* p) connect(&this->LoadPresetsTimer, &QTimer::timeout, this, [this]() { this->loadPresets(); if (!this->PresetName.isEmpty() && - this->CMakePresetsFile.ConfigurePresets.find( + this->CMakePresetsGraph.ConfigurePresets.find( std::string(this->PresetName.toLocal8Bit())) == - this->CMakePresetsFile.ConfigurePresets.end()) { + this->CMakePresetsGraph.ConfigurePresets.end()) { this->setPreset(QString{}); } }); @@ -159,7 +159,7 @@ void QCMake::setPreset(const QString& name, bool setBinary) if (!name.isNull()) { std::string presetName(name.toLocal8Bit()); auto const& expandedPreset = - this->CMakePresetsFile.ConfigurePresets[presetName].Expanded; + this->CMakePresetsGraph.ConfigurePresets[presetName].Expanded; if (expandedPreset) { if (setBinary && !expandedPreset->BinaryDir.empty()) { QString binaryDir = @@ -427,7 +427,7 @@ QCMakePropertyList QCMake::properties() const if (!this->PresetName.isNull()) { std::string presetName(this->PresetName.toLocal8Bit()); auto const& p = - this->CMakePresetsFile.ConfigurePresets.at(presetName).Expanded; + this->CMakePresetsGraph.ConfigurePresets.at(presetName).Expanded; if (p) { for (auto const& v : p->CacheVariables) { if (!v.second) { @@ -533,17 +533,17 @@ void QCMake::setUpEnvironment() const void QCMake::loadPresets() { - auto result = this->CMakePresetsFile.ReadProjectPresets( + auto result = this->CMakePresetsGraph.ReadProjectPresets( this->SourceDirectory.toLocal8Bit().data(), true); if (result != this->LastLoadPresetsResult && - result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { emit this->presetLoadError(this->SourceDirectory, result); } this->LastLoadPresetsResult = result; QVector<QCMakePreset> presets; - for (auto const& name : this->CMakePresetsFile.ConfigurePresetOrder) { - auto const& it = this->CMakePresetsFile.ConfigurePresets[name]; + for (auto const& name : this->CMakePresetsGraph.ConfigurePresetOrder) { + auto const& it = this->CMakePresetsGraph.ConfigurePresets[name]; auto const& p = it.Unexpanded; if (p.Hidden) { continue; @@ -556,10 +556,10 @@ void QCMake::loadPresets() preset.generator = QString::fromLocal8Bit(p.Generator.data()); preset.architecture = QString::fromLocal8Bit(p.Architecture.data()); preset.setArchitecture = !p.ArchitectureStrategy || - p.ArchitectureStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set; + p.ArchitectureStrategy == cmCMakePresetsGraph::ArchToolsetStrategy::Set; preset.toolset = QString::fromLocal8Bit(p.Toolset.data()); preset.setToolset = !p.ToolsetStrategy || - p.ToolsetStrategy == cmCMakePresetsFile::ArchToolsetStrategy::Set; + p.ToolsetStrategy == cmCMakePresetsGraph::ArchToolsetStrategy::Set; preset.enabled = it.Expanded && it.Expanded->ConditionResult && std::find_if(this->AvailableGenerators.begin(), this->AvailableGenerators.end(), diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index a6751b0..8a7e4cb 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -4,7 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include "cmake.h" #ifdef _MSC_VER @@ -60,7 +60,7 @@ using QCMakePropertyList = QList<QCMakeProperty>; Q_DECLARE_METATYPE(QCMakeProperty) Q_DECLARE_METATYPE(QCMakePropertyList) Q_DECLARE_METATYPE(QProcessEnvironment) -Q_DECLARE_METATYPE(cmCMakePresetsFile::ReadFileResult) +Q_DECLARE_METATYPE(cmCMakePresetsGraph::ReadFileResult) /// Qt API for CMake library. /// Wrapper like class allows for easier integration with @@ -159,7 +159,7 @@ signals: void presetChanged(const QString& name); /// signal when there's an error reading the presets files void presetLoadError(const QString& dir, - cmCMakePresetsFile::ReadFileResult error); + cmCMakePresetsGraph::ReadFileResult error); /// signal when uninitialized warning changes void warnUninitializedModeChanged(bool value); /// signal for progress events @@ -202,9 +202,9 @@ protected: QString Platform; QString Toolset; std::vector<cmake::GeneratorInfo> AvailableGenerators; - cmCMakePresetsFile CMakePresetsFile; - cmCMakePresetsFile::ReadFileResult LastLoadPresetsResult = - cmCMakePresetsFile::ReadFileResult::READ_OK; + cmCMakePresetsGraph CMakePresetsGraph; + cmCMakePresetsGraph::ReadFileResult LastLoadPresetsResult = + cmCMakePresetsGraph::ReadFileResult::READ_OK; QString PresetName; QString CMakeExecutable; QAtomicInt InterruptFlag; diff --git a/Source/QtDialog/QCMakePreset.h b/Source/QtDialog/QCMakePreset.h index 1609fcb..7387655 100644 --- a/Source/QtDialog/QCMakePreset.h +++ b/Source/QtDialog/QCMakePreset.h @@ -5,7 +5,7 @@ #include <QString> #include <QVariant> -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" class QCMakePreset { diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index 0dc954a..017fdc0 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx @@ -320,9 +320,9 @@ private: }; #endif -bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, - std::set<std::string>& symbols, - std::set<std::string>& dataSymbols) +static bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, + std::set<std::string>& symbols, + std::set<std::string>& dataSymbols) { std::string output; // break up command line into a vector @@ -375,9 +375,9 @@ bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, return true; } -bool DumpFile(std::string const& nmPath, const char* filename, - std::set<std::string>& symbols, - std::set<std::string>& dataSymbols) +static bool DumpFile(std::string const& nmPath, const char* filename, + std::set<std::string>& symbols, + std::set<std::string>& dataSymbols) { #ifndef _WIN32 return DumpFileWithLlvmNm(nmPath, filename, symbols, dataSymbols); diff --git a/Source/bindexplib.h b/Source/bindexplib.h index bd1398f..c5d81c7 100644 --- a/Source/bindexplib.h +++ b/Source/bindexplib.h @@ -4,11 +4,10 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstdio> #include <set> #include <string> -#include <stdio.h> - class bindexplib { public: diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index a7ce3a6..831e9c7 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -4,6 +4,9 @@ #include <sstream> #include <unordered_set> +#include <utility> + +#include <cm/memory> #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" @@ -316,21 +319,26 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, } // Choose which mode of the command to use. - bool escapeOldStyle = !verbatim; + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetByproducts(byproducts); + cc->SetCommandLines(commandLines); + cc->SetComment(comment); + cc->SetWorkingDirectory(working.c_str()); + cc->SetEscapeOldStyle(!verbatim); + cc->SetUsesTerminal(uses_terminal); + cc->SetDepfile(depfile); + cc->SetJobPool(job_pool); + cc->SetCommandExpandLists(command_expand_lists); if (source.empty() && output.empty()) { // Source is empty, use the target. - std::vector<std::string> no_depends; - mf.AddCustomCommandToTarget( - target, byproducts, no_depends, commandLines, cctype, comment, - working.c_str(), mf.GetPolicyStatus(cmPolicies::CMP0116), escapeOldStyle, - uses_terminal, depfile, job_pool, command_expand_lists); + mf.AddCustomCommandToTarget(target, cctype, std::move(cc)); } else if (target.empty()) { // Target is empty, use the output. - mf.AddCustomCommandToOutput( - output, byproducts, depends, main_dependency, implicit_depends, - commandLines, comment, working.c_str(), - mf.GetPolicyStatus(cmPolicies::CMP0116), nullptr, false, escapeOldStyle, - uses_terminal, command_expand_lists, depfile, job_pool); + cc->SetOutputs(output); + cc->SetMainDependency(main_dependency); + cc->SetDepends(depends); + cc->SetImplicitDepends(implicit_depends); + mf.AddCustomCommandToOutput(std::move(cc)); } else if (!byproducts.empty()) { status.SetError("BYPRODUCTS may not be specified with SOURCE signatures"); return false; @@ -366,8 +374,7 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args, // Use the old-style mode for backward compatibility. mf.AddCustomCommandOldStyle(target, outputs, depends, source, commandLines, - comment, - mf.GetPolicyStatus(cmPolicies::CMP0116)); + comment); } return true; diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index 2b19aad..a246d06 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -4,13 +4,15 @@ #include <utility> +#include <cm/memory> + +#include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" -#include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -211,11 +213,18 @@ bool cmAddCustomTargetCommand(std::vector<std::string> const& args, } // Add the utility target to the makefile. - bool escapeOldStyle = !verbatim; - cmTarget* target = mf.AddUtilityCommand( - targetName, excludeFromAll, working_directory.c_str(), byproducts, depends, - commandLines, mf.GetPolicyStatus(cmPolicies::CMP0116), escapeOldStyle, - comment, uses_terminal, command_expand_lists, job_pool); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetWorkingDirectory(working_directory.c_str()); + cc->SetByproducts(byproducts); + cc->SetDepends(depends); + cc->SetCommandLines(commandLines); + cc->SetEscapeOldStyle(!verbatim); + cc->SetComment(comment); + cc->SetUsesTerminal(uses_terminal); + cc->SetCommandExpandLists(command_expand_lists); + cc->SetJobPool(job_pool); + cmTarget* target = + mf.AddUtilityCommand(targetName, excludeFromAll, std::move(cc)); // Add additional user-specified source files to the target. target->AddSources(sources); diff --git a/Source/cmAffinity.cxx b/Source/cmAffinity.cxx index 35443e7..591199b 100644 --- a/Source/cmAffinity.cxx +++ b/Source/cmAffinity.cxx @@ -12,7 +12,7 @@ # define CM_HAVE_CPU_AFFINITY # include <pthread.h> # include <sched.h> -// On some platforms CPU_ZERO needs memset but sched.h forgets string.h +// On some platforms CPU_ZERO needs memset but sched.h forgets cstring # include <cstring> // IWYU pragma: keep # if defined(__FreeBSD__) # include <pthread_np.h> diff --git a/Source/cmBase32.cxx b/Source/cmBase32.cxx index a9c15c2..e8e46aa 100644 --- a/Source/cmBase32.cxx +++ b/Source/cmBase32.cxx @@ -12,7 +12,7 @@ inline unsigned char Base32EncodeChar(int schar) return Base32EncodeTable[schar]; } -void Base32Encode5(const unsigned char src[5], char dst[8]) +static void Base32Encode5(const unsigned char src[5], char dst[8]) { // [0]:5 bits dst[0] = Base32EncodeChar((src[0] >> 3) & 0x1F); diff --git a/Source/cmBuildOptions.h b/Source/cmBuildOptions.h new file mode 100644 index 0000000..aa3184e --- /dev/null +++ b/Source/cmBuildOptions.h @@ -0,0 +1,44 @@ +/* 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 + +/** \brief Defines how to resolve packages **/ +enum class PackageResolveMode +{ + /** \brief Behavior is defined by preset or cache variable (e.g. + CMAKE_VS_NUGET_PACKAGE_RESTORE). This is the default. **/ + Default, + + /** \brief Ignore behavior defined by preset or cache variable and forces + packages to be resolved prior to build. **/ + Force, + + /** \brief Ignore behavior defined by preset or cache variable and forces + packages to be resolved, but skip the actual build. **/ + OnlyResolve, + + /** \brief Ignore behavior defined by preset or cache variable and don't + resolve any packages **/ + Disable +}; + +struct cmBuildOptions +{ +public: + cmBuildOptions() noexcept = default; + explicit cmBuildOptions(bool clean, bool fast, + PackageResolveMode resolveMode) noexcept + : Clean(clean) + , Fast(fast) + , ResolveMode(resolveMode) + { + } + explicit cmBuildOptions(const cmBuildOptions&) noexcept = default; + cmBuildOptions& operator=(const cmBuildOptions&) noexcept = default; + + bool Clean = false; + bool Fast = false; + PackageResolveMode ResolveMode = PackageResolveMode::Default; +}; diff --git a/Source/cmCMakePresetsFileInternal.h b/Source/cmCMakePresetsFileInternal.h deleted file mode 100644 index 3269276..0000000 --- a/Source/cmCMakePresetsFileInternal.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include <memory> - -#include "cmCMakePresetsFile.h" - -#define CHECK_OK(expr) \ - { \ - auto _result = expr; \ - if (_result != ReadFileResult::READ_OK) \ - return _result; \ - } - -namespace cmCMakePresetsFileInternal { -enum class ExpandMacroResult -{ - Ok, - Ignore, - Error, -}; - -using MacroExpander = std::function<ExpandMacroResult( - const std::string&, const std::string&, std::string&, int version)>; -} - -class cmCMakePresetsFile::Condition -{ -public: - virtual ~Condition() = default; - - virtual bool Evaluate( - const std::vector<cmCMakePresetsFileInternal::MacroExpander>& expanders, - int version, cm::optional<bool>& out) const = 0; - virtual bool IsNull() const { return false; } -}; - -namespace cmCMakePresetsFileInternal { - -class NullCondition : public cmCMakePresetsFile::Condition -{ - bool Evaluate(const std::vector<MacroExpander>& /*expanders*/, - int /*version*/, cm::optional<bool>& out) const override - { - out = true; - return true; - } - - bool IsNull() const override { return true; } -}; - -class ConstCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector<MacroExpander>& /*expanders*/, - int /*version*/, cm::optional<bool>& out) const override - { - out = this->Value; - return true; - } - - bool Value; -}; - -class EqualsCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector<MacroExpander>& expanders, int version, - cm::optional<bool>& out) const override; - - std::string Lhs; - std::string Rhs; -}; - -class InListCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector<MacroExpander>& expanders, int version, - cm::optional<bool>& out) const override; - - std::string String; - std::vector<std::string> List; -}; - -class MatchesCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector<MacroExpander>& expanders, int version, - cm::optional<bool>& out) const override; - - std::string String; - std::string Regex; -}; - -class AnyAllOfCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector<MacroExpander>& expanders, int version, - cm::optional<bool>& out) const override; - - std::vector<std::unique_ptr<Condition>> Conditions; - bool StopValue; -}; - -class NotCondition : public cmCMakePresetsFile::Condition -{ -public: - bool Evaluate(const std::vector<MacroExpander>& expanders, int version, - cm::optional<bool>& out) const override; - - std::unique_ptr<Condition> SubCondition; -}; -} diff --git a/Source/cmCMakePresetsFileReadJSON.cxx b/Source/cmCMakePresetsFileReadJSON.cxx deleted file mode 100644 index 489551d..0000000 --- a/Source/cmCMakePresetsFileReadJSON.cxx +++ /dev/null @@ -1,1032 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include <functional> -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include <cm/memory> -#include <cm/optional> -#include <cmext/string_view> - -#include <cm3p/json/reader.h> -#include <cm3p/json/value.h> - -#include "cmsys/FStream.hxx" - -#include "cmCMakePresetsFile.h" -#include "cmCMakePresetsFileInternal.h" -#include "cmJSONHelpers.h" -#include "cmVersion.h" - -namespace { -using ReadFileResult = cmCMakePresetsFile::ReadFileResult; -using CacheVariable = cmCMakePresetsFile::CacheVariable; -using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset; -using BuildPreset = cmCMakePresetsFile::BuildPreset; -using TestPreset = cmCMakePresetsFile::TestPreset; -using ArchToolsetStrategy = cmCMakePresetsFile::ArchToolsetStrategy; - -constexpr int MIN_VERSION = 1; -constexpr int MAX_VERSION = 3; - -struct CMakeVersion -{ - unsigned int Major = 0; - unsigned int Minor = 0; - unsigned int Patch = 0; -}; - -struct RootPresets -{ - CMakeVersion CMakeMinimumRequired; - std::vector<cmCMakePresetsFile::ConfigurePreset> ConfigurePresets; - std::vector<cmCMakePresetsFile::BuildPreset> BuildPresets; - std::vector<cmCMakePresetsFile::TestPreset> TestPresets; -}; - -std::unique_ptr<cmCMakePresetsFileInternal::NotCondition> InvertCondition( - std::unique_ptr<cmCMakePresetsFile::Condition> condition) -{ - auto retval = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>(); - retval->SubCondition = std::move(condition); - return retval; -} - -auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); - -auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); - -auto const ConditionStringListHelper = - cmJSONVectorHelper<std::string, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, - ConditionStringHelper); - -auto const ConstConditionHelper = - cmJSONObjectHelper<cmCMakePresetsFileInternal::ConstCondition, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_CONDITION, false) - .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) - .Bind("value"_s, &cmCMakePresetsFileInternal::ConstCondition::Value, - ConditionBoolHelper, true); - -auto const EqualsConditionHelper = - cmJSONObjectHelper<cmCMakePresetsFileInternal::EqualsCondition, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_CONDITION, false) - .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) - .Bind("lhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Lhs, - ConditionStringHelper, true) - .Bind("rhs"_s, &cmCMakePresetsFileInternal::EqualsCondition::Rhs, - ConditionStringHelper, true); - -auto const InListConditionHelper = - cmJSONObjectHelper<cmCMakePresetsFileInternal::InListCondition, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_CONDITION, false) - .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) - .Bind("string"_s, &cmCMakePresetsFileInternal::InListCondition::String, - ConditionStringHelper, true) - .Bind("list"_s, &cmCMakePresetsFileInternal::InListCondition::List, - ConditionStringListHelper, true); - -auto const MatchesConditionHelper = - cmJSONObjectHelper<cmCMakePresetsFileInternal::MatchesCondition, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_CONDITION, false) - .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) - .Bind("string"_s, &cmCMakePresetsFileInternal::MatchesCondition::String, - ConditionStringHelper, true) - .Bind("regex"_s, &cmCMakePresetsFileInternal::MatchesCondition::Regex, - ConditionStringHelper, true); - -ReadFileResult SubConditionHelper( - std::unique_ptr<cmCMakePresetsFile::Condition>& out, - const Json::Value* value); - -auto const ListConditionVectorHelper = - cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsFile::Condition>, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_CONDITION, - SubConditionHelper); -auto const AnyAllOfConditionHelper = - cmJSONObjectHelper<cmCMakePresetsFileInternal::AnyAllOfCondition, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_CONDITION, false) - .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) - .Bind("conditions"_s, - &cmCMakePresetsFileInternal::AnyAllOfCondition::Conditions, - ListConditionVectorHelper); - -auto const NotConditionHelper = - cmJSONObjectHelper<cmCMakePresetsFileInternal::NotCondition, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, false) - .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) - .Bind("condition"_s, - &cmCMakePresetsFileInternal::NotCondition::SubCondition, - SubConditionHelper); - -ReadFileResult ConditionHelper( - std::unique_ptr<cmCMakePresetsFile::Condition>& out, - const Json::Value* value) -{ - if (!value) { - out.reset(); - return ReadFileResult::READ_OK; - } - - if (value->isBool()) { - auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>(); - c->Value = value->asBool(); - out = std::move(c); - return ReadFileResult::READ_OK; - } - - if (value->isNull()) { - out = cm::make_unique<cmCMakePresetsFileInternal::NullCondition>(); - return ReadFileResult::READ_OK; - } - - if (value->isObject()) { - if (!value->isMember("type")) { - return ReadFileResult::INVALID_CONDITION; - } - - if (!(*value)["type"].isString()) { - return ReadFileResult::INVALID_CONDITION; - } - auto type = (*value)["type"].asString(); - - if (type == "const") { - auto c = cm::make_unique<cmCMakePresetsFileInternal::ConstCondition>(); - CHECK_OK(ConstConditionHelper(*c, value)); - out = std::move(c); - return ReadFileResult::READ_OK; - } - - if (type == "equals" || type == "notEquals") { - auto c = cm::make_unique<cmCMakePresetsFileInternal::EqualsCondition>(); - CHECK_OK(EqualsConditionHelper(*c, value)); - out = std::move(c); - if (type == "notEquals") { - out = InvertCondition(std::move(out)); - } - return ReadFileResult::READ_OK; - } - - if (type == "inList" || type == "notInList") { - auto c = cm::make_unique<cmCMakePresetsFileInternal::InListCondition>(); - CHECK_OK(InListConditionHelper(*c, value)); - out = std::move(c); - if (type == "notInList") { - out = InvertCondition(std::move(out)); - } - return ReadFileResult::READ_OK; - } - - if (type == "matches" || type == "notMatches") { - auto c = cm::make_unique<cmCMakePresetsFileInternal::MatchesCondition>(); - CHECK_OK(MatchesConditionHelper(*c, value)); - out = std::move(c); - if (type == "notMatches") { - out = InvertCondition(std::move(out)); - } - return ReadFileResult::READ_OK; - } - - if (type == "anyOf" || type == "allOf") { - auto c = - cm::make_unique<cmCMakePresetsFileInternal::AnyAllOfCondition>(); - c->StopValue = (type == "anyOf"); - CHECK_OK(AnyAllOfConditionHelper(*c, value)); - out = std::move(c); - return ReadFileResult::READ_OK; - } - - if (type == "not") { - auto c = cm::make_unique<cmCMakePresetsFileInternal::NotCondition>(); - CHECK_OK(NotConditionHelper(*c, value)); - out = std::move(c); - return ReadFileResult::READ_OK; - } - } - - return ReadFileResult::INVALID_CONDITION; -} - -ReadFileResult PresetConditionHelper( - std::shared_ptr<cmCMakePresetsFile::Condition>& out, - const Json::Value* value) -{ - std::unique_ptr<cmCMakePresetsFile::Condition> ptr; - auto result = ConditionHelper(ptr, value); - out = std::move(ptr); - return result; -} - -ReadFileResult SubConditionHelper( - std::unique_ptr<cmCMakePresetsFile::Condition>& out, - const Json::Value* value) -{ - std::unique_ptr<cmCMakePresetsFile::Condition> ptr; - auto result = ConditionHelper(ptr, value); - if (ptr && ptr->IsNull()) { - return ReadFileResult::INVALID_CONDITION; - } - out = std::move(ptr); - return result; -} - -cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error) -{ - return [error](std::nullptr_t& /*out*/, - const Json::Value* value) -> ReadFileResult { - if (!value) { - return ReadFileResult::READ_OK; - } - - if (!value->isObject()) { - return error; - } - - return ReadFileResult::READ_OK; - }; -} - -auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); - -auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>( - ReadFileResult::NO_VERSION, VersionIntHelper); - -auto const RootVersionHelper = - cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_ROOT) - .Bind("version"_s, VersionHelper, false); - -auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE); - -ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value) -{ - if (!value) { - out.clear(); - return ReadFileResult::READ_OK; - } - - if (value->isBool()) { - out = value->asBool() ? "TRUE" : "FALSE"; - return ReadFileResult::READ_OK; - } - - return VariableStringHelper(out, value); -} - -auto const VariableObjectHelper = - cmJSONObjectHelper<CacheVariable, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false) - .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false) - .Bind("value"_s, &CacheVariable::Value, VariableValueHelper); - -ReadFileResult VariableHelper(cm::optional<CacheVariable>& out, - const Json::Value* value) -{ - if (value->isBool()) { - out = CacheVariable{ - /*Type=*/"BOOL", - /*Value=*/value->asBool() ? "TRUE" : "FALSE", - }; - return ReadFileResult::READ_OK; - } - if (value->isString()) { - out = CacheVariable{ - /*Type=*/"", - /*Value=*/value->asString(), - }; - return ReadFileResult::READ_OK; - } - if (value->isObject()) { - out.emplace(); - return VariableObjectHelper(*out, value); - } - if (value->isNull()) { - out = cm::nullopt; - return ReadFileResult::READ_OK; - } - return ReadFileResult::INVALID_VARIABLE; -} - -auto const VariablesHelper = - cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper); - -auto const PresetStringHelper = cmJSONStringHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); - -ReadFileResult EnvironmentHelper(cm::optional<std::string>& out, - const Json::Value* value) -{ - if (!value || value->isNull()) { - out = cm::nullopt; - return ReadFileResult::READ_OK; - } - if (value->isString()) { - out = value->asString(); - return ReadFileResult::READ_OK; - } - return ReadFileResult::INVALID_PRESET; -} - -auto const EnvironmentMapHelper = - cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, - EnvironmentHelper); - -auto const PresetVectorStringHelper = - cmJSONVectorHelper<std::string, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, - PresetStringHelper); - -ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out, - const Json::Value* value) -{ - out.clear(); - if (!value) { - return ReadFileResult::READ_OK; - } - - if (value->isString()) { - out.push_back(value->asString()); - return ReadFileResult::READ_OK; - } - - return PresetVectorStringHelper(out, value); -} - -auto const PresetBoolHelper = cmJSONBoolHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); - -auto const PresetOptionalBoolHelper = - cmJSONOptionalHelper<bool, ReadFileResult>(ReadFileResult::READ_OK, - PresetBoolHelper); - -auto const PresetIntHelper = cmJSONIntHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); - -auto const PresetOptionalIntHelper = cmJSONOptionalHelper<int, ReadFileResult>( - ReadFileResult::READ_OK, PresetIntHelper); - -auto const PresetVectorIntHelper = cmJSONVectorHelper<int, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper); - -auto const PresetWarningsHelper = - cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("dev"_s, &ConfigurePreset::WarnDev, PresetOptionalBoolHelper, false) - .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated, - PresetOptionalBoolHelper, false) - .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized, - PresetOptionalBoolHelper, false) - .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli, - PresetOptionalBoolHelper, false) - .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars, - PresetOptionalBoolHelper, false); - -auto const PresetErrorsHelper = - cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("dev"_s, &ConfigurePreset::ErrorDev, PresetOptionalBoolHelper, false) - .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated, - PresetOptionalBoolHelper, false); - -auto const PresetDebugHelper = - cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("output"_s, &ConfigurePreset::DebugOutput, PresetOptionalBoolHelper, - false) - .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile, - PresetOptionalBoolHelper, false) - .Bind("find"_s, &ConfigurePreset::DebugFind, PresetOptionalBoolHelper, - false); - -ReadFileResult ArchToolsetStrategyHelper( - cm::optional<ArchToolsetStrategy>& out, const Json::Value* value) -{ - if (!value) { - out = cm::nullopt; - return ReadFileResult::READ_OK; - } - - if (!value->isString()) { - return ReadFileResult::INVALID_PRESET; - } - - if (value->asString() == "set") { - out = ArchToolsetStrategy::Set; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "external") { - out = ArchToolsetStrategy::External; - return ReadFileResult::READ_OK; - } - - return ReadFileResult::INVALID_PRESET; -} - -std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)> -ArchToolsetHelper( - std::string ConfigurePreset::*valueField, - cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField) -{ - auto const objectHelper = - cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("value", valueField, PresetStringHelper, false) - .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false); - return [valueField, strategyField, objectHelper]( - ConfigurePreset& out, const Json::Value* value) -> ReadFileResult { - if (!value) { - (out.*valueField).clear(); - out.*strategyField = cm::nullopt; - return ReadFileResult::READ_OK; - } - - if (value->isString()) { - out.*valueField = value->asString(); - out.*strategyField = cm::nullopt; - return ReadFileResult::READ_OK; - } - - if (value->isObject()) { - return objectHelper(out, value); - } - - return ReadFileResult::INVALID_PRESET; - }; -} - -auto const ArchitectureHelper = ArchToolsetHelper( - &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy); -auto const ToolsetHelper = ArchToolsetHelper( - &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy); - -auto const ConfigurePresetHelper = - cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("name"_s, &ConfigurePreset::Name, PresetStringHelper) - .Bind("inherits"_s, &ConfigurePreset::Inherits, - PresetVectorOneOrMoreStringHelper, false) - .Bind("hidden"_s, &ConfigurePreset::Hidden, PresetBoolHelper, false) - .Bind<std::nullptr_t>("vendor"_s, nullptr, - VendorHelper(ReadFileResult::INVALID_PRESET), false) - .Bind("displayName"_s, &ConfigurePreset::DisplayName, PresetStringHelper, - false) - .Bind("description"_s, &ConfigurePreset::Description, PresetStringHelper, - false) - .Bind("generator"_s, &ConfigurePreset::Generator, PresetStringHelper, - false) - .Bind("architecture"_s, ArchitectureHelper, false) - .Bind("toolset"_s, ToolsetHelper, false) - .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile, - PresetStringHelper, false) - .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, PresetStringHelper, - false) - .Bind("installDir"_s, &ConfigurePreset::InstallDir, PresetStringHelper, - false) - .Bind<std::string>("cmakeExecutable"_s, nullptr, PresetStringHelper, false) - .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables, - VariablesHelper, false) - .Bind("environment"_s, &ConfigurePreset::Environment, EnvironmentMapHelper, - false) - .Bind("warnings"_s, PresetWarningsHelper, false) - .Bind("errors"_s, PresetErrorsHelper, false) - .Bind("debug"_s, PresetDebugHelper, false) - .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator, - PresetConditionHelper, false); - -auto const BuildPresetHelper = - cmJSONObjectHelper<BuildPreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("name"_s, &BuildPreset::Name, PresetStringHelper) - .Bind("inherits"_s, &BuildPreset::Inherits, - PresetVectorOneOrMoreStringHelper, false) - .Bind("hidden"_s, &BuildPreset::Hidden, PresetBoolHelper, false) - .Bind<std::nullptr_t>("vendor"_s, nullptr, - VendorHelper(ReadFileResult::INVALID_PRESET), false) - .Bind("displayName"_s, &BuildPreset::DisplayName, PresetStringHelper, - false) - .Bind("description"_s, &BuildPreset::Description, PresetStringHelper, - false) - .Bind("environment"_s, &BuildPreset::Environment, EnvironmentMapHelper, - false) - .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset, - PresetStringHelper, false) - .Bind("inheritConfigureEnvironment"_s, - &BuildPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper, - false) - .Bind("jobs"_s, &BuildPreset::Jobs, PresetOptionalIntHelper, false) - .Bind("targets"_s, &BuildPreset::Targets, - PresetVectorOneOrMoreStringHelper, false) - .Bind("configuration"_s, &BuildPreset::Configuration, PresetStringHelper, - false) - .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, PresetOptionalBoolHelper, - false) - .Bind("verbose"_s, &BuildPreset::Verbose, PresetOptionalBoolHelper, false) - .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions, - PresetVectorStringHelper, false) - .Bind("condition"_s, &BuildPreset::ConditionEvaluator, - PresetConditionHelper, false); - -ReadFileResult TestPresetOutputVerbosityHelper( - TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value) -{ - if (!value) { - out = TestPreset::OutputOptions::VerbosityEnum::Default; - return ReadFileResult::READ_OK; - } - - if (!value->isString()) { - return ReadFileResult::INVALID_PRESET; - } - - if (value->asString() == "default") { - out = TestPreset::OutputOptions::VerbosityEnum::Default; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "verbose") { - out = TestPreset::OutputOptions::VerbosityEnum::Verbose; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "extra") { - out = TestPreset::OutputOptions::VerbosityEnum::Extra; - return ReadFileResult::READ_OK; - } - - return ReadFileResult::INVALID_PRESET; -} - -auto const TestPresetOptionalOutputVerbosityHelper = - cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum, - ReadFileResult>(ReadFileResult::READ_OK, - TestPresetOutputVerbosityHelper); - -auto const TestPresetOptionalOutputHelper = - cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress, - PresetOptionalBoolHelper, false) - .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity, - TestPresetOptionalOutputVerbosityHelper, false) - .Bind("debug"_s, &TestPreset::OutputOptions::Debug, - PresetOptionalBoolHelper, false) - .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure, - PresetOptionalBoolHelper, false) - .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet, - PresetOptionalBoolHelper, false) - .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile, - PresetStringHelper, false) - .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary, - PresetOptionalBoolHelper, false) - .Bind("subprojectSummary"_s, - &TestPreset::OutputOptions::SubprojectSummary, - PresetOptionalBoolHelper, false) - .Bind("maxPassedTestOutputSize"_s, - &TestPreset::OutputOptions::MaxPassedTestOutputSize, - PresetOptionalIntHelper, false) - .Bind("maxFailedTestOutputSize"_s, - &TestPreset::OutputOptions::MaxFailedTestOutputSize, - PresetOptionalIntHelper, false) - .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth, - PresetOptionalIntHelper, false)); - -auto const TestPresetOptionalFilterIncludeIndexObjectHelper = - cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions, - ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_PRESET) - .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start, - PresetOptionalIntHelper, false) - .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End, - PresetOptionalIntHelper, false) - .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride, - PresetOptionalIntHelper, false) - .Bind("specificTests"_s, - &TestPreset::IncludeOptions::IndexOptions::SpecificTests, - PresetVectorIntHelper, false)); - -ReadFileResult TestPresetOptionalFilterIncludeIndexHelper( - cm::optional<TestPreset::IncludeOptions::IndexOptions>& out, - const Json::Value* value) -{ - if (!value) { - out = cm::nullopt; - return ReadFileResult::READ_OK; - } - - if (value->isString()) { - out.emplace(); - out->IndexFile = value->asString(); - return ReadFileResult::READ_OK; - } - - if (value->isObject()) { - return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value); - } - - return ReadFileResult::INVALID_PRESET; -} - -auto const TestPresetOptionalFilterIncludeHelper = - cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) - .Bind("name"_s, &TestPreset::IncludeOptions::Name, PresetStringHelper, - false) - .Bind("label"_s, &TestPreset::IncludeOptions::Label, PresetStringHelper, - false) - .Bind("index"_s, &TestPreset::IncludeOptions::Index, - TestPresetOptionalFilterIncludeIndexHelper, false) - .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion, - PresetOptionalBoolHelper, false)); - -auto const TestPresetOptionalFilterExcludeFixturesHelper = - cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions, - ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_PRESET) - .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any, - PresetStringHelper, false) - .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup, - PresetStringHelper, false) - .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup, - PresetStringHelper, false)); - -auto const TestPresetOptionalFilterExcludeHelper = - cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) - .Bind("name"_s, &TestPreset::ExcludeOptions::Name, PresetStringHelper, - false) - .Bind("label"_s, &TestPreset::ExcludeOptions::Label, PresetStringHelper, - false) - .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures, - TestPresetOptionalFilterExcludeFixturesHelper, false)); - -ReadFileResult TestPresetExecutionShowOnlyHelper( - TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value) -{ - if (!value || !value->isString()) { - return ReadFileResult::INVALID_PRESET; - } - - if (value->asString() == "human") { - out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "json-v1") { - out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1; - return ReadFileResult::READ_OK; - } - - return ReadFileResult::INVALID_PRESET; -} - -auto const TestPresetOptionalExecutionShowOnlyHelper = - cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum, - ReadFileResult>(ReadFileResult::READ_OK, - TestPresetExecutionShowOnlyHelper); - -ReadFileResult TestPresetExecutionModeHelper( - TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out, - const Json::Value* value) -{ - if (!value) { - return ReadFileResult::READ_OK; - } - - if (!value->isString()) { - return ReadFileResult::INVALID_PRESET; - } - - if (value->asString() == "until-fail") { - out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "until-pass") { - out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "after-timeout") { - out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout; - return ReadFileResult::READ_OK; - } - - return ReadFileResult::INVALID_PRESET; -} - -auto const TestPresetOptionalExecutionRepeatHelper = - cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions, - ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions, - ReadFileResult>(ReadFileResult::READ_OK, - ReadFileResult::INVALID_PRESET) - .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode, - TestPresetExecutionModeHelper, true) - .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count, - PresetIntHelper, true)); - -ReadFileResult TestPresetExecutionNoTestsActionHelper( - TestPreset::ExecutionOptions::NoTestsActionEnum& out, - const Json::Value* value) -{ - if (!value) { - out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default; - return ReadFileResult::READ_OK; - } - - if (!value->isString()) { - return ReadFileResult::INVALID_PRESET; - } - - if (value->asString() == "default") { - out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "error") { - out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error; - return ReadFileResult::READ_OK; - } - - if (value->asString() == "ignore") { - out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore; - return ReadFileResult::READ_OK; - } - - return ReadFileResult::INVALID_PRESET; -} - -auto const TestPresetOptionalExecutionNoTestsActionHelper = - cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum, - ReadFileResult>(ReadFileResult::READ_OK, - TestPresetExecutionNoTestsActionHelper); - -auto const TestPresetExecutionHelper = - cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) - .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure, - PresetOptionalBoolHelper, false) - .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover, - PresetOptionalBoolHelper, false) - .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs, - PresetOptionalIntHelper, false) - .Bind("resourceSpecFile"_s, - &TestPreset::ExecutionOptions::ResourceSpecFile, - PresetStringHelper, false) - .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad, - PresetOptionalIntHelper, false) - .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly, - TestPresetOptionalExecutionShowOnlyHelper, false) - .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat, - TestPresetOptionalExecutionRepeatHelper, false) - .Bind("interactiveDebugging"_s, - &TestPreset::ExecutionOptions::InteractiveDebugging, - PresetOptionalBoolHelper, false) - .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom, - PresetOptionalBoolHelper, false) - .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout, - PresetOptionalIntHelper, false) - .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction, - TestPresetOptionalExecutionNoTestsActionHelper, false)); - -auto const TestPresetFilterHelper = - cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>( - ReadFileResult::READ_OK, - cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) - .Bind("include"_s, &TestPreset::FilterOptions::Include, - TestPresetOptionalFilterIncludeHelper, false) - .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude, - TestPresetOptionalFilterExcludeHelper, false)); - -auto const TestPresetHelper = - cmJSONObjectHelper<TestPreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) - .Bind("name"_s, &TestPreset::Name, PresetStringHelper) - .Bind("inherits"_s, &TestPreset::Inherits, - PresetVectorOneOrMoreStringHelper, false) - .Bind("hidden"_s, &TestPreset::Hidden, PresetBoolHelper, false) - .Bind<std::nullptr_t>("vendor"_s, nullptr, - VendorHelper(ReadFileResult::INVALID_PRESET), false) - .Bind("displayName"_s, &TestPreset::DisplayName, PresetStringHelper, false) - .Bind("description"_s, &TestPreset::Description, PresetStringHelper, false) - .Bind("environment"_s, &TestPreset::Environment, EnvironmentMapHelper, - false) - .Bind("configurePreset"_s, &TestPreset::ConfigurePreset, - PresetStringHelper, false) - .Bind("inheritConfigureEnvironment"_s, - &TestPreset::InheritConfigureEnvironment, PresetOptionalBoolHelper, - false) - .Bind("configuration"_s, &TestPreset::Configuration, PresetStringHelper, - false) - .Bind("overwriteConfigurationFile"_s, - &TestPreset::OverwriteConfigurationFile, PresetVectorStringHelper, - false) - .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper, - false) - .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false) - .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper, - false) - .Bind("condition"_s, &TestPreset::ConditionEvaluator, - PresetConditionHelper, false); - -auto const ConfigurePresetsHelper = - cmJSONVectorHelper<ConfigurePreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, - ConfigurePresetHelper); - -auto const BuildPresetsHelper = - cmJSONVectorHelper<BuildPreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, - BuildPresetHelper); - -auto const TestPresetsHelper = cmJSONVectorHelper<TestPreset, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, TestPresetHelper); - -auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); - -auto const CMakeVersionHelper = - cmJSONObjectHelper<CMakeVersion, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false) - .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false) - .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false) - .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false); - -auto const RootPresetsHelper = - cmJSONObjectHelper<RootPresets, ReadFileResult>( - ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false) - .Bind<int>("version"_s, nullptr, VersionHelper) - .Bind("configurePresets"_s, &RootPresets::ConfigurePresets, - ConfigurePresetsHelper, false) - .Bind("buildPresets"_s, &RootPresets::BuildPresets, BuildPresetsHelper, - false) - .Bind("testPresets"_s, &RootPresets::TestPresets, TestPresetsHelper, false) - .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired, - CMakeVersionHelper, false) - .Bind<std::nullptr_t>("vendor"_s, nullptr, - VendorHelper(ReadFileResult::INVALID_ROOT), false); -} - -cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadJSONFile( - const std::string& filename, bool user) -{ - cmsys::ifstream fin(filename.c_str()); - if (!fin) { - return ReadFileResult::FILE_NOT_FOUND; - } - // If there's a BOM, toss it. - cmsys::FStream::ReadBOM(fin); - - Json::Value root; - Json::CharReaderBuilder builder; - Json::CharReaderBuilder::strictMode(&builder.settings_); - if (!Json::parseFromStream(builder, fin, &root, nullptr)) { - return ReadFileResult::JSON_PARSE_ERROR; - } - - int v = 0; - auto result = RootVersionHelper(v, &root); - if (result != ReadFileResult::READ_OK) { - return result; - } - if (v < MIN_VERSION || v > MAX_VERSION) { - return ReadFileResult::UNRECOGNIZED_VERSION; - } - if (user) { - this->UserVersion = v; - } else { - this->Version = v; - } - - // Support for build and test presets added in version 2. - if (v < 2 && - (root.isMember("buildPresets") || root.isMember("testPresets"))) { - return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED; - } - - RootPresets presets; - if ((result = RootPresetsHelper(presets, &root)) != - ReadFileResult::READ_OK) { - return result; - } - - unsigned int currentMajor = cmVersion::GetMajorVersion(); - unsigned int currentMinor = cmVersion::GetMinorVersion(); - unsigned int currentPatch = cmVersion::GetPatchVersion(); - auto const& required = presets.CMakeMinimumRequired; - if (required.Major > currentMajor || - (required.Major == currentMajor && - (required.Minor > currentMinor || - (required.Minor == currentMinor && - (required.Patch > currentPatch))))) { - return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION; - } - - for (auto& preset : presets.ConfigurePresets) { - preset.User = user; - if (preset.Name.empty()) { - return ReadFileResult::INVALID_PRESET; - } - - PresetPair<ConfigurePreset> presetPair; - presetPair.Unexpanded = preset; - presetPair.Expanded = cm::nullopt; - if (!this->ConfigurePresets - .emplace(std::make_pair(preset.Name, presetPair)) - .second) { - return ReadFileResult::DUPLICATE_PRESETS; - } - - // Support for installDir presets added in version 3. - if (v < 3 && !preset.InstallDir.empty()) { - return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED; - } - - // Support for conditions added in version 3. - if (v < 3 && preset.ConditionEvaluator) { - return ReadFileResult::CONDITION_UNSUPPORTED; - } - - // Support for toolchainFile presets added in version 3. - if (v < 3 && !preset.ToolchainFile.empty()) { - return ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED; - } - - this->ConfigurePresetOrder.push_back(preset.Name); - } - - for (auto& preset : presets.BuildPresets) { - preset.User = user; - if (preset.Name.empty()) { - return ReadFileResult::INVALID_PRESET; - } - - PresetPair<BuildPreset> presetPair; - presetPair.Unexpanded = preset; - presetPair.Expanded = cm::nullopt; - if (!this->BuildPresets.emplace(preset.Name, presetPair).second) { - return ReadFileResult::DUPLICATE_PRESETS; - } - - // Support for conditions added in version 3. - if (v < 3 && preset.ConditionEvaluator) { - return ReadFileResult::CONDITION_UNSUPPORTED; - } - - this->BuildPresetOrder.push_back(preset.Name); - } - - for (auto& preset : presets.TestPresets) { - preset.User = user; - if (preset.Name.empty()) { - return ReadFileResult::INVALID_PRESET; - } - - PresetPair<TestPreset> presetPair; - presetPair.Unexpanded = preset; - presetPair.Expanded = cm::nullopt; - if (!this->TestPresets.emplace(preset.Name, presetPair).second) { - return ReadFileResult::DUPLICATE_PRESETS; - } - - // Support for conditions added in version 3. - if (v < 3 && preset.ConditionEvaluator) { - return ReadFileResult::CONDITION_UNSUPPORTED; - } - - this->TestPresetOrder.push_back(preset.Name); - } - - return ReadFileResult::READ_OK; -} diff --git a/Source/cmCMakePresetsFile.cxx b/Source/cmCMakePresetsGraph.cxx index 538b668..705e2b0 100644 --- a/Source/cmCMakePresetsFile.cxx +++ b/Source/cmCMakePresetsGraph.cxx @@ -1,8 +1,9 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include <algorithm> +#include <cassert> #include <cstdlib> #include <functional> #include <iostream> @@ -13,12 +14,12 @@ #include "cmsys/RegularExpression.hxx" -#include "cmCMakePresetsFileInternal.h" +#include "cmCMakePresetsGraphInternal.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #define CHECK_EXPAND(out, field, expanders, version) \ - { \ + do { \ switch (ExpandMacros(field, expanders, version)) { \ case ExpandMacroResult::Error: \ return false; \ @@ -28,7 +29,7 @@ case ExpandMacroResult::Ok: \ break; \ } \ - } + } while (false) namespace { enum class CycleStatus @@ -38,12 +39,12 @@ enum class CycleStatus Verified, }; -using ReadFileResult = cmCMakePresetsFile::ReadFileResult; -using ConfigurePreset = cmCMakePresetsFile::ConfigurePreset; -using BuildPreset = cmCMakePresetsFile::BuildPreset; -using TestPreset = cmCMakePresetsFile::TestPreset; -using ExpandMacroResult = cmCMakePresetsFileInternal::ExpandMacroResult; -using MacroExpander = cmCMakePresetsFileInternal::MacroExpander; +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; +using BuildPreset = cmCMakePresetsGraph::BuildPreset; +using TestPreset = cmCMakePresetsGraph::TestPreset; +using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult; +using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander; void InheritString(std::string& child, const std::string& parent) { @@ -77,9 +78,10 @@ void InheritVector(std::vector<T>& child, const std::vector<T>& parent) */ template <class T> ReadFileResult VisitPreset( - T& preset, std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets, + T& preset, + std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets, std::map<std::string, CycleStatus> cycleStatus, - const cmCMakePresetsFile& file) + const cmCMakePresetsGraph& graph) { switch (cycleStatus[preset.Name]) { case CycleStatus::InProgress: @@ -96,7 +98,7 @@ ReadFileResult VisitPreset( return ReadFileResult::INVALID_PRESET; } - CHECK_OK(preset.VisitPresetBeforeInherit()) + CHECK_OK(preset.VisitPresetBeforeInherit()); for (auto const& i : preset.Inherits) { auto parent = presets.find(i); @@ -105,16 +107,16 @@ ReadFileResult VisitPreset( } auto& parentPreset = parent->second.Unexpanded; - if (!preset.User && parentPreset.User) { - return ReadFileResult::USER_PRESET_INHERITANCE; + if (!preset.OriginFile->ReachableFiles.count(parentPreset.OriginFile)) { + return ReadFileResult::INHERITED_PRESET_UNREACHABLE_FROM_FILE; } - auto result = VisitPreset(parentPreset, presets, cycleStatus, file); + auto result = VisitPreset(parentPreset, presets, cycleStatus, graph); if (result != ReadFileResult::READ_OK) { return result; } - CHECK_OK(preset.VisitPresetInherit(parentPreset)) + CHECK_OK(preset.VisitPresetInherit(parentPreset)); for (auto const& v : parentPreset.Environment) { preset.Environment.insert(v); @@ -129,7 +131,7 @@ ReadFileResult VisitPreset( preset.ConditionEvaluator.reset(); } - CHECK_OK(preset.VisitPresetAfterInherit(file.GetVersion(preset))) + CHECK_OK(preset.VisitPresetAfterInherit(graph.GetVersion(preset))); cycleStatus[preset.Name] = CycleStatus::Verified; return ReadFileResult::READ_OK; @@ -137,8 +139,8 @@ ReadFileResult VisitPreset( template <class T> ReadFileResult ComputePresetInheritance( - std::map<std::string, cmCMakePresetsFile::PresetPair<T>>& presets, - const cmCMakePresetsFile& file) + std::map<std::string, cmCMakePresetsGraph::PresetPair<T>>& presets, + const cmCMakePresetsGraph& graph) { std::map<std::string, CycleStatus> cycleStatus; for (auto const& it : presets) { @@ -147,7 +149,7 @@ ReadFileResult ComputePresetInheritance( for (auto& it : presets) { auto& preset = it.second.Unexpanded; - auto result = VisitPreset<T>(preset, presets, cycleStatus, file); + auto result = VisitPreset<T>(preset, presets, cycleStatus, graph); if (result != ReadFileResult::READ_OK) { return result; } @@ -189,17 +191,17 @@ ExpandMacroResult ExpandMacro(std::string& out, const std::vector<MacroExpander>& macroExpanders, int version); -bool ExpandMacros(const cmCMakePresetsFile& file, +bool ExpandMacros(const cmCMakePresetsGraph& graph, const ConfigurePreset& preset, cm::optional<ConfigurePreset>& out, const std::vector<MacroExpander>& macroExpanders) { std::string binaryDir = preset.BinaryDir; - CHECK_EXPAND(out, binaryDir, macroExpanders, file.GetVersion(preset)) + CHECK_EXPAND(out, binaryDir, macroExpanders, graph.GetVersion(preset)); if (!binaryDir.empty()) { if (!cmSystemTools::FileIsFullPath(binaryDir)) { - binaryDir = cmStrCat(file.SourceDir, '/', binaryDir); + binaryDir = cmStrCat(graph.SourceDir, '/', binaryDir); } out->BinaryDir = cmSystemTools::CollapseFullPath(binaryDir); cmSystemTools::ConvertToUnixSlashes(out->BinaryDir); @@ -207,10 +209,10 @@ bool ExpandMacros(const cmCMakePresetsFile& file, if (!preset.InstallDir.empty()) { std::string installDir = preset.InstallDir; - CHECK_EXPAND(out, installDir, macroExpanders, file.GetVersion(preset)) + CHECK_EXPAND(out, installDir, macroExpanders, graph.GetVersion(preset)); if (!cmSystemTools::FileIsFullPath(installDir)) { - installDir = cmStrCat(file.SourceDir, '/', installDir); + installDir = cmStrCat(graph.SourceDir, '/', installDir); } out->InstallDir = cmSystemTools::CollapseFullPath(installDir); cmSystemTools::ConvertToUnixSlashes(out->InstallDir); @@ -218,89 +220,89 @@ bool ExpandMacros(const cmCMakePresetsFile& file, if (!preset.ToolchainFile.empty()) { std::string toolchain = preset.ToolchainFile; - CHECK_EXPAND(out, toolchain, macroExpanders, file.GetVersion(preset)) + CHECK_EXPAND(out, toolchain, macroExpanders, graph.GetVersion(preset)); out->ToolchainFile = toolchain; } for (auto& variable : out->CacheVariables) { if (variable.second) { CHECK_EXPAND(out, variable.second->Value, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); } } return true; } -bool ExpandMacros(const cmCMakePresetsFile& file, const BuildPreset& preset, +bool ExpandMacros(const cmCMakePresetsGraph& graph, const BuildPreset& preset, cm::optional<BuildPreset>& out, const std::vector<MacroExpander>& macroExpanders) { for (auto& target : out->Targets) { - CHECK_EXPAND(out, target, macroExpanders, file.GetVersion(preset)) + CHECK_EXPAND(out, target, macroExpanders, graph.GetVersion(preset)); } for (auto& nativeToolOption : out->NativeToolOptions) { CHECK_EXPAND(out, nativeToolOption, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); } return true; } -bool ExpandMacros(const cmCMakePresetsFile& file, const TestPreset& preset, +bool ExpandMacros(const cmCMakePresetsGraph& graph, const TestPreset& preset, cm::optional<TestPreset>& out, const std::vector<MacroExpander>& macroExpanders) { for (auto& overwrite : out->OverwriteConfigurationFile) { - CHECK_EXPAND(out, overwrite, macroExpanders, file.GetVersion(preset)); + CHECK_EXPAND(out, overwrite, macroExpanders, graph.GetVersion(preset)); } if (out->Output) { CHECK_EXPAND(out, out->Output->OutputLogFile, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); } if (out->Filter) { if (out->Filter->Include) { CHECK_EXPAND(out, out->Filter->Include->Name, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); CHECK_EXPAND(out, out->Filter->Include->Label, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); if (out->Filter->Include->Index) { CHECK_EXPAND(out, out->Filter->Include->Index->IndexFile, - macroExpanders, file.GetVersion(preset)); + macroExpanders, graph.GetVersion(preset)); } } if (out->Filter->Exclude) { CHECK_EXPAND(out, out->Filter->Exclude->Name, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); CHECK_EXPAND(out, out->Filter->Exclude->Label, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); if (out->Filter->Exclude->Fixtures) { CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Any, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Setup, - macroExpanders, file.GetVersion(preset)) + macroExpanders, graph.GetVersion(preset)); CHECK_EXPAND(out, out->Filter->Exclude->Fixtures->Cleanup, - macroExpanders, file.GetVersion(preset)) + macroExpanders, graph.GetVersion(preset)); } } } if (out->Execution) { CHECK_EXPAND(out, out->Execution->ResourceSpecFile, macroExpanders, - file.GetVersion(preset)) + graph.GetVersion(preset)); } return true; } template <class T> -bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, +bool ExpandMacros(const cmCMakePresetsGraph& graph, const T& preset, cm::optional<T>& out) { out.emplace(preset); @@ -313,20 +315,20 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, std::vector<MacroExpander> macroExpanders; MacroExpander defaultMacroExpander = - [&file, &preset](const std::string& macroNamespace, - const std::string& macroName, std::string& macroOut, - int version) -> ExpandMacroResult { + [&graph, &preset](const std::string& macroNamespace, + const std::string& macroName, std::string& macroOut, + int version) -> ExpandMacroResult { if (macroNamespace.empty()) { if (macroName == "sourceDir") { - macroOut += file.SourceDir; + macroOut += graph.SourceDir; return ExpandMacroResult::Ok; } if (macroName == "sourceParentDir") { - macroOut += cmSystemTools::GetParentDirectory(file.SourceDir); + macroOut += cmSystemTools::GetParentDirectory(graph.SourceDir); return ExpandMacroResult::Ok; } if (macroName == "sourceDirName") { - macroOut += cmSystemTools::GetFilenameName(file.SourceDir); + macroOut += cmSystemTools::GetFilenameName(graph.SourceDir); return ExpandMacroResult::Ok; } if (macroName == "presetName") { @@ -336,7 +338,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, if (macroName == "generator") { // Generator only makes sense if preset is not hidden. if (!preset.Hidden) { - macroOut += file.GetGeneratorForPreset(preset.Name); + macroOut += graph.GetGeneratorForPreset(preset.Name); } return ExpandMacroResult::Ok; } @@ -393,7 +395,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, for (auto& v : out->Environment) { if (v.second) { switch (VisitEnv(*v.second, envCycles[v.first], macroExpanders, - file.GetVersion(preset))) { + graph.GetVersion(preset))) { case ExpandMacroResult::Error: return false; case ExpandMacroResult::Ignore: @@ -408,7 +410,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, if (preset.ConditionEvaluator) { cm::optional<bool> result; if (!preset.ConditionEvaluator->Evaluate( - macroExpanders, file.GetVersion(preset), result)) { + macroExpanders, graph.GetVersion(preset), result)) { return false; } if (!result) { @@ -418,7 +420,7 @@ bool ExpandMacros(const cmCMakePresetsFile& file, const T& preset, out->ConditionResult = *result; } - return ExpandMacros(file, preset, out, macroExpanders); + return ExpandMacros(graph, preset, out, macroExpanders); } ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, @@ -541,7 +543,7 @@ ExpandMacroResult ExpandMacro(std::string& out, } } -bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate( +bool cmCMakePresetsGraphInternal::EqualsCondition::Evaluate( const std::vector<MacroExpander>& expanders, int version, cm::optional<bool>& out) const { @@ -555,7 +557,7 @@ bool cmCMakePresetsFileInternal::EqualsCondition::Evaluate( return true; } -bool cmCMakePresetsFileInternal::InListCondition::Evaluate( +bool cmCMakePresetsGraphInternal::InListCondition::Evaluate( const std::vector<MacroExpander>& expanders, int version, cm::optional<bool>& out) const { @@ -574,7 +576,7 @@ bool cmCMakePresetsFileInternal::InListCondition::Evaluate( return true; } -bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate( +bool cmCMakePresetsGraphInternal::MatchesCondition::Evaluate( const std::vector<MacroExpander>& expanders, int version, cm::optional<bool>& out) const { @@ -592,7 +594,7 @@ bool cmCMakePresetsFileInternal::MatchesCondition::Evaluate( return true; } -bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate( +bool cmCMakePresetsGraphInternal::AnyAllOfCondition::Evaluate( const std::vector<MacroExpander>& expanders, int version, cm::optional<bool>& out) const { @@ -618,7 +620,7 @@ bool cmCMakePresetsFileInternal::AnyAllOfCondition::Evaluate( return true; } -bool cmCMakePresetsFileInternal::NotCondition::Evaluate( +bool cmCMakePresetsGraphInternal::NotCondition::Evaluate( const std::vector<MacroExpander>& expanders, int version, cm::optional<bool>& out) const { @@ -633,9 +635,9 @@ bool cmCMakePresetsFileInternal::NotCondition::Evaluate( return true; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit( - const cmCMakePresetsFile::Preset& parentPreset) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ConfigurePreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& parentPreset) { auto& preset = *this; const ConfigurePreset& parent = @@ -667,8 +669,8 @@ cmCMakePresetsFile::ConfigurePreset::VisitPresetInherit( return ReadFileResult::READ_OK; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit() +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ConfigurePreset::VisitPresetBeforeInherit() { auto& preset = *this; if (preset.Environment.count("") != 0) { @@ -678,8 +680,8 @@ cmCMakePresetsFile::ConfigurePreset::VisitPresetBeforeInherit() return ReadFileResult::READ_OK; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ConfigurePreset::VisitPresetAfterInherit(int version) { auto& preset = *this; if (!preset.Hidden) { @@ -706,9 +708,9 @@ cmCMakePresetsFile::ConfigurePreset::VisitPresetAfterInherit(int version) return ReadFileResult::READ_OK; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::BuildPreset::VisitPresetInherit( - const cmCMakePresetsFile::Preset& parentPreset) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::BuildPreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& parentPreset) { auto& preset = *this; const BuildPreset& parent = static_cast<const BuildPreset&>(parentPreset); @@ -722,12 +724,15 @@ cmCMakePresetsFile::BuildPreset::VisitPresetInherit( InheritOptionalValue(preset.CleanFirst, parent.CleanFirst); InheritOptionalValue(preset.Verbose, parent.Verbose); InheritVector(preset.NativeToolOptions, parent.NativeToolOptions); + if (!preset.ResolvePackageReferences) { + preset.ResolvePackageReferences = parent.ResolvePackageReferences; + } return ReadFileResult::READ_OK; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::BuildPreset::VisitPresetAfterInherit(int /* version */) { auto& preset = *this; if (!preset.Hidden && preset.ConfigurePreset.empty()) { @@ -736,9 +741,9 @@ cmCMakePresetsFile::BuildPreset::VisitPresetAfterInherit(int /* version */) return ReadFileResult::READ_OK; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::TestPreset::VisitPresetInherit( - const cmCMakePresetsFile::Preset& parentPreset) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::TestPreset::VisitPresetInherit( + const cmCMakePresetsGraph::Preset& parentPreset) { auto& preset = *this; const TestPreset& parent = static_cast<const TestPreset&>(parentPreset); @@ -836,8 +841,8 @@ cmCMakePresetsFile::TestPreset::VisitPresetInherit( return ReadFileResult::READ_OK; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::TestPreset::VisitPresetAfterInherit(int /* version */) { auto& preset = *this; if (!preset.Hidden && preset.ConfigurePreset.empty()) { @@ -846,17 +851,17 @@ cmCMakePresetsFile::TestPreset::VisitPresetAfterInherit(int /* version */) return ReadFileResult::READ_OK; } -std::string cmCMakePresetsFile::GetFilename(const std::string& sourceDir) +std::string cmCMakePresetsGraph::GetFilename(const std::string& sourceDir) { return cmStrCat(sourceDir, "/CMakePresets.json"); } -std::string cmCMakePresetsFile::GetUserFilename(const std::string& sourceDir) +std::string cmCMakePresetsGraph::GetUserFilename(const std::string& sourceDir) { return cmStrCat(sourceDir, "/CMakeUserPresets.json"); } -cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets( +cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadProjectPresets( const std::string& sourceDir, bool allowNoFiles) { this->SourceDir = sourceDir; @@ -870,37 +875,42 @@ cmCMakePresetsFile::ReadFileResult cmCMakePresetsFile::ReadProjectPresets( return result; } -cmCMakePresetsFile::ReadFileResult -cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles) +cmCMakePresetsGraph::ReadFileResult +cmCMakePresetsGraph::ReadProjectPresetsInternal(bool allowNoFiles) { bool haveOneFile = false; + File* file; std::string filename = GetUserFilename(this->SourceDir); + std::vector<File*> inProgressFiles; if (cmSystemTools::FileExists(filename)) { - auto result = this->ReadJSONFile(filename, true); + auto result = this->ReadJSONFile(filename, RootType::User, + ReadReason::Root, inProgressFiles, file); if (result != ReadFileResult::READ_OK) { return result; } haveOneFile = true; - } - - filename = GetFilename(this->SourceDir); - if (cmSystemTools::FileExists(filename)) { - auto result = this->ReadJSONFile(filename, false); - if (result != ReadFileResult::READ_OK) { - return result; + } else { + filename = GetFilename(this->SourceDir); + if (cmSystemTools::FileExists(filename)) { + auto result = this->ReadJSONFile( + filename, RootType::Project, ReadReason::Root, inProgressFiles, file); + if (result != ReadFileResult::READ_OK) { + return result; + } + haveOneFile = true; } - haveOneFile = true; } + assert(inProgressFiles.empty()); if (!haveOneFile) { return allowNoFiles ? ReadFileResult::READ_OK : ReadFileResult::FILE_NOT_FOUND; } - CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this)) - CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this)) - CHECK_OK(ComputePresetInheritance(this->TestPresets, *this)) + CHECK_OK(ComputePresetInheritance(this->ConfigurePresets, *this)); + CHECK_OK(ComputePresetInheritance(this->BuildPresets, *this)); + CHECK_OK(ComputePresetInheritance(this->TestPresets, *this)); for (auto& it : this->ConfigurePresets) { if (!ExpandMacros(*this, it.second.Unexpanded, it.second.Expanded)) { @@ -915,6 +925,10 @@ cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles) if (configurePreset == this->ConfigurePresets.end()) { return ReadFileResult::INVALID_CONFIGURE_PRESET; } + if (!it.second.Unexpanded.OriginFile->ReachableFiles.count( + configurePreset->second.Unexpanded.OriginFile)) { + return ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE; + } if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) { it.second.Unexpanded.Environment.insert( @@ -935,6 +949,10 @@ cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles) if (configurePreset == this->ConfigurePresets.end()) { return ReadFileResult::INVALID_CONFIGURE_PRESET; } + if (!it.second.Unexpanded.OriginFile->ReachableFiles.count( + configurePreset->second.Unexpanded.OriginFile)) { + return ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE; + } if (it.second.Unexpanded.InheritConfigureEnvironment.value_or(true)) { it.second.Unexpanded.Environment.insert( @@ -951,7 +969,7 @@ cmCMakePresetsFile::ReadProjectPresetsInternal(bool allowNoFiles) return ReadFileResult::READ_OK; } -const char* cmCMakePresetsFile::ResultToString(ReadFileResult result) +const char* cmCMakePresetsGraph::ResultToString(ReadFileResult result) { switch (result) { case ReadFileResult::READ_OK: @@ -982,13 +1000,19 @@ const char* cmCMakePresetsFile::ResultToString(ReadFileResult result) return "Duplicate presets"; case ReadFileResult::CYCLIC_PRESET_INHERITANCE: return "Cyclic preset inheritance"; - case ReadFileResult::USER_PRESET_INHERITANCE: - return "Project preset inherits from user preset"; + case ReadFileResult::INHERITED_PRESET_UNREACHABLE_FROM_FILE: + return "Inherited preset is unreachable from preset's file"; + case ReadFileResult::CONFIGURE_PRESET_UNREACHABLE_FROM_FILE: + return "Configure preset is unreachable from preset's file"; case ReadFileResult::INVALID_MACRO_EXPANSION: return "Invalid macro expansion"; case ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED: return "File version must be 2 or higher for build and test preset " "support."; + case ReadFileResult::INCLUDE_UNSUPPORTED: + return "File version must be 4 or higher for include support"; + case ReadFileResult::INVALID_INCLUDE: + return "Invalid \"include\" field"; case ReadFileResult::INVALID_CONFIGURE_PRESET: return "Invalid \"configurePreset\" field"; case ReadFileResult::INSTALL_PREFIX_UNSUPPORTED: @@ -1001,12 +1025,14 @@ const char* cmCMakePresetsFile::ResultToString(ReadFileResult result) case ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED: return "File version must be 3 or higher for toolchainFile preset " "support."; + case ReadFileResult::CYCLIC_INCLUDE: + return "Cyclic include among preset files"; } return "Unknown error"; } -void cmCMakePresetsFile::ClearPresets() +void cmCMakePresetsGraph::ClearPresets() { this->ConfigurePresets.clear(); this->BuildPresets.clear(); @@ -1015,10 +1041,12 @@ void cmCMakePresetsFile::ClearPresets() this->ConfigurePresetOrder.clear(); this->BuildPresetOrder.clear(); this->TestPresetOrder.clear(); + + this->Files.clear(); } -void cmCMakePresetsFile::PrintPresets( - const std::vector<const cmCMakePresetsFile::Preset*>& presets) +void cmCMakePresetsGraph::PrintPresets( + const std::vector<const cmCMakePresetsGraph::Preset*>& presets) { if (presets.empty()) { return; @@ -1026,8 +1054,8 @@ void cmCMakePresetsFile::PrintPresets( auto longestPresetName = std::max_element(presets.begin(), presets.end(), - [](const cmCMakePresetsFile::Preset* a, - const cmCMakePresetsFile::Preset* b) { + [](const cmCMakePresetsGraph::Preset* a, + const cmCMakePresetsGraph::Preset* b) { return a->Name.length() < b->Name.length(); }); auto longestLength = (*longestPresetName)->Name.length(); @@ -1045,67 +1073,67 @@ void cmCMakePresetsFile::PrintPresets( } } -void cmCMakePresetsFile::PrintConfigurePresetList() const +void cmCMakePresetsGraph::PrintConfigurePresetList() const { PrintConfigurePresetList([](const ConfigurePreset&) { return true; }); } -void cmCMakePresetsFile::PrintConfigurePresetList( +void cmCMakePresetsGraph::PrintConfigurePresetList( const std::function<bool(const ConfigurePreset&)>& filter) const { - std::vector<const cmCMakePresetsFile::Preset*> presets; + std::vector<const cmCMakePresetsGraph::Preset*> presets; for (auto const& p : this->ConfigurePresetOrder) { auto const& preset = this->ConfigurePresets.at(p); if (!preset.Unexpanded.Hidden && preset.Expanded && preset.Expanded->ConditionResult && filter(preset.Unexpanded)) { presets.push_back( - static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded)); + static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded)); } } if (!presets.empty()) { std::cout << "Available configure presets:\n\n"; - cmCMakePresetsFile::PrintPresets(presets); + cmCMakePresetsGraph::PrintPresets(presets); } } -void cmCMakePresetsFile::PrintBuildPresetList() const +void cmCMakePresetsGraph::PrintBuildPresetList() const { - std::vector<const cmCMakePresetsFile::Preset*> presets; + std::vector<const cmCMakePresetsGraph::Preset*> presets; for (auto const& p : this->BuildPresetOrder) { auto const& preset = this->BuildPresets.at(p); if (!preset.Unexpanded.Hidden && preset.Expanded && preset.Expanded->ConditionResult) { presets.push_back( - static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded)); + static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded)); } } if (!presets.empty()) { std::cout << "Available build presets:\n\n"; - cmCMakePresetsFile::PrintPresets(presets); + cmCMakePresetsGraph::PrintPresets(presets); } } -void cmCMakePresetsFile::PrintTestPresetList() const +void cmCMakePresetsGraph::PrintTestPresetList() const { - std::vector<const cmCMakePresetsFile::Preset*> presets; + std::vector<const cmCMakePresetsGraph::Preset*> presets; for (auto const& p : this->TestPresetOrder) { auto const& preset = this->TestPresets.at(p); if (!preset.Unexpanded.Hidden && preset.Expanded && preset.Expanded->ConditionResult) { presets.push_back( - static_cast<const cmCMakePresetsFile::Preset*>(&preset.Unexpanded)); + static_cast<const cmCMakePresetsGraph::Preset*>(&preset.Unexpanded)); } } if (!presets.empty()) { std::cout << "Available test presets:\n\n"; - cmCMakePresetsFile::PrintPresets(presets); + cmCMakePresetsGraph::PrintPresets(presets); } } -void cmCMakePresetsFile::PrintAllPresets() const +void cmCMakePresetsGraph::PrintAllPresets() const { this->PrintConfigurePresetList(); std::cout << std::endl; diff --git a/Source/cmCMakePresetsFile.h b/Source/cmCMakePresetsGraph.h index 7aa9b6a..9d6c61a 100644 --- a/Source/cmCMakePresetsFile.h +++ b/Source/cmCMakePresetsGraph.h @@ -8,12 +8,15 @@ #include <map> #include <memory> #include <string> +#include <unordered_set> #include <utility> #include <vector> #include <cm/optional> -class cmCMakePresetsFile +enum class PackageResolveMode; + +class cmCMakePresetsGraph { public: enum class ReadFileResult @@ -32,14 +35,18 @@ public: INVALID_VARIABLE, DUPLICATE_PRESETS, CYCLIC_PRESET_INHERITANCE, - USER_PRESET_INHERITANCE, + INHERITED_PRESET_UNREACHABLE_FROM_FILE, + CONFIGURE_PRESET_UNREACHABLE_FROM_FILE, INVALID_MACRO_EXPANSION, BUILD_TEST_PRESETS_UNSUPPORTED, + INCLUDE_UNSUPPORTED, + INVALID_INCLUDE, INVALID_CONFIGURE_PRESET, INSTALL_PREFIX_UNSUPPORTED, INVALID_CONDITION, CONDITION_UNSUPPORTED, TOOLCHAIN_FILE_UNSUPPORTED, + CYCLIC_INCLUDE, }; enum class ArchToolsetStrategy @@ -57,25 +64,36 @@ public: class Condition; + class File + { + public: + std::string Filename; + int Version; + + std::unordered_set<File*> ReachableFiles; + }; + class Preset { public: -#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) + Preset() = default; + Preset(Preset&& /*other*/) = default; + Preset(const Preset& /*other*/) = default; + Preset& operator=(const Preset& /*other*/) = default; + virtual ~Preset() = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + Preset& operator=(Preset&& /*other*/) = default; +#else // The move assignment operators for several STL classes did not become // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. Disable the - // move assignment operator until C++17 is enabled. - // Explicitly defining a copy assignment operator prevents the compiler - // from automatically generating a move assignment operator. - Preset& operator=(const Preset& /*other*/) = default; + // assignment operator throwing an exception when it shouldn't. + Preset& operator=(Preset&& /*other*/) = delete; #endif - virtual ~Preset() = default; - std::string Name; std::vector<std::string> Inherits; bool Hidden; - bool User; + File* OriginFile; std::string DisplayName; std::string Description; @@ -99,14 +117,18 @@ public: class ConfigurePreset : public Preset { public: -#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) + ConfigurePreset() = default; + ConfigurePreset(ConfigurePreset&& /*other*/) = default; + ConfigurePreset(const ConfigurePreset& /*other*/) = default; + ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default; + ~ConfigurePreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = default; +#else // The move assignment operators for several STL classes did not become // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. Disable the - // move assignment operator until C++17 is enabled. - // Explicitly defining a copy assignment operator prevents the compiler - // from automatically generating a move assignment operator. - ConfigurePreset& operator=(const ConfigurePreset& /*other*/) = default; + // assignment operator throwing an exception when it shouldn't. + ConfigurePreset& operator=(ConfigurePreset&& /*other*/) = delete; #endif std::string Generator; @@ -140,14 +162,18 @@ public: class BuildPreset : public Preset { public: -#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) + BuildPreset() = default; + BuildPreset(BuildPreset&& /*other*/) = default; + BuildPreset(const BuildPreset& /*other*/) = default; + BuildPreset& operator=(const BuildPreset& /*other*/) = default; + ~BuildPreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + BuildPreset& operator=(BuildPreset&& /*other*/) = default; +#else // The move assignment operators for several STL classes did not become // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. Disable the - // move assignment operator until C++17 is enabled. - // Explicitly defining a copy assignment operator prevents the compiler - // from automatically generating a move assignment operator. - BuildPreset& operator=(const BuildPreset& /*other*/) = default; + // assignment operator throwing an exception when it shouldn't. + BuildPreset& operator=(BuildPreset&& /*other*/) = delete; #endif std::string ConfigurePreset; @@ -158,6 +184,7 @@ public: cm::optional<bool> CleanFirst; cm::optional<bool> Verbose; std::vector<std::string> NativeToolOptions; + cm::optional<PackageResolveMode> ResolvePackageReferences; ReadFileResult VisitPresetInherit(const Preset& parent) override; ReadFileResult VisitPresetAfterInherit(int /* version */) override; @@ -166,14 +193,18 @@ public: class TestPreset : public Preset { public: -#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) + TestPreset() = default; + TestPreset(TestPreset&& /*other*/) = default; + TestPreset(const TestPreset& /*other*/) = default; + TestPreset& operator=(const TestPreset& /*other*/) = default; + ~TestPreset() override = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + TestPreset& operator=(TestPreset&& /*other*/) = default; +#else // The move assignment operators for several STL classes did not become // noexcept until C++17, which causes some tools to warn about this move - // assignment operator throwing an exception when it shouldn't. Disable the - // move assignment operator until C++17 is enabled. - // Explicitly defining a copy assignment operator prevents the compiler - // from automatically generating a move assignment operator. - TestPreset& operator=(const TestPreset& /*other*/) = default; + // assignment operator throwing an exception when it shouldn't. + TestPreset& operator=(TestPreset&& /*other*/) = delete; #endif struct OutputOptions @@ -307,12 +338,11 @@ public: std::vector<std::string> TestPresetOrder; std::string SourceDir; - int Version; - int UserVersion; + std::vector<std::unique_ptr<File>> Files; int GetVersion(const Preset& preset) const { - return preset.User ? this->UserVersion : this->Version; + return preset.OriginFile->Version; } static std::string GetFilename(const std::string& sourceDir); @@ -349,7 +379,7 @@ public: } static void PrintPresets( - const std::vector<const cmCMakePresetsFile::Preset*>& presets); + const std::vector<const cmCMakePresetsGraph::Preset*>& presets); void PrintConfigurePresetList() const; void PrintConfigurePresetList( const std::function<bool(const ConfigurePreset&)>& filter) const; @@ -358,7 +388,22 @@ public: void PrintAllPresets() const; private: + enum class RootType + { + Project, + User, + }; + + enum class ReadReason + { + Root, + Included, + }; + ReadFileResult ReadProjectPresetsInternal(bool allowNoFiles); - ReadFileResult ReadJSONFile(const std::string& filename, bool user); + ReadFileResult ReadJSONFile(const std::string& filename, RootType rootType, + ReadReason readReason, + std::vector<File*>& inProgressFiles, + File*& file); void ClearPresets(); }; diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h new file mode 100644 index 0000000..f7c7349 --- /dev/null +++ b/Source/cmCMakePresetsGraphInternal.h @@ -0,0 +1,163 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include <memory> +#include <string> +#include <vector> + +#include <cm3p/json/value.h> + +#include "cmCMakePresetsGraph.h" +#include "cmJSONHelpers.h" + +#define CHECK_OK(expr) \ + do { \ + auto _result = expr; \ + if (_result != ReadFileResult::READ_OK) \ + return _result; \ + } while (false) + +namespace cmCMakePresetsGraphInternal { +enum class ExpandMacroResult +{ + Ok, + Ignore, + Error, +}; + +using MacroExpander = std::function<ExpandMacroResult( + const std::string&, const std::string&, std::string&, int version)>; +} + +class cmCMakePresetsGraph::Condition +{ +public: + virtual ~Condition() = default; + + virtual bool Evaluate( + const std::vector<cmCMakePresetsGraphInternal::MacroExpander>& expanders, + int version, cm::optional<bool>& out) const = 0; + virtual bool IsNull() const { return false; } +}; + +namespace cmCMakePresetsGraphInternal { + +class NullCondition : public cmCMakePresetsGraph::Condition +{ + bool Evaluate(const std::vector<MacroExpander>& /*expanders*/, + int /*version*/, cm::optional<bool>& out) const override + { + out = true; + return true; + } + + bool IsNull() const override { return true; } +}; + +class ConstCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector<MacroExpander>& /*expanders*/, + int /*version*/, cm::optional<bool>& out) const override + { + out = this->Value; + return true; + } + + bool Value; +}; + +class EqualsCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector<MacroExpander>& expanders, int version, + cm::optional<bool>& out) const override; + + std::string Lhs; + std::string Rhs; +}; + +class InListCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector<MacroExpander>& expanders, int version, + cm::optional<bool>& out) const override; + + std::string String; + std::vector<std::string> List; +}; + +class MatchesCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector<MacroExpander>& expanders, int version, + cm::optional<bool>& out) const override; + + std::string String; + std::string Regex; +}; + +class AnyAllOfCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector<MacroExpander>& expanders, int version, + cm::optional<bool>& out) const override; + + std::vector<std::unique_ptr<Condition>> Conditions; + bool StopValue; +}; + +class NotCondition : public cmCMakePresetsGraph::Condition +{ +public: + bool Evaluate(const std::vector<MacroExpander>& expanders, int version, + cm::optional<bool>& out) const override; + + std::unique_ptr<Condition> SubCondition; +}; + +cmCMakePresetsGraph::ReadFileResult PresetStringHelper( + std::string& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper( + std::vector<std::string>& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper( + cm::optional<bool>& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper( + cm::optional<int>& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper( + std::vector<int>& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult ConfigurePresetsHelper( + std::vector<cmCMakePresetsGraph::ConfigurePreset>& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult BuildPresetsHelper( + std::vector<cmCMakePresetsGraph::BuildPreset>& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult TestPresetsHelper( + std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value); + +cmJSONHelper<std::nullptr_t, cmCMakePresetsGraph::ReadFileResult> VendorHelper( + cmCMakePresetsGraph::ReadFileResult error); + +cmCMakePresetsGraph::ReadFileResult PresetConditionHelper( + std::shared_ptr<cmCMakePresetsGraph::Condition>& out, + const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult PresetVectorOneOrMoreStringHelper( + std::vector<std::string>& out, const Json::Value* value); + +cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper( + std::map<std::string, cm::optional<std::string>>& out, + const Json::Value* value); +} diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx new file mode 100644 index 0000000..85cf5be --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -0,0 +1,615 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include <algorithm> +#include <functional> +#include <map> +#include <string> +#include <unordered_set> +#include <utility> +#include <vector> + +#include <cm/memory> +#include <cm/optional> +#include <cmext/string_view> + +#include <cm3p/json/reader.h> +#include <cm3p/json/value.h> + +#include "cmsys/FStream.hxx" + +#include "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmVersion.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using CacheVariable = cmCMakePresetsGraph::CacheVariable; +using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; +using BuildPreset = cmCMakePresetsGraph::BuildPreset; +using TestPreset = cmCMakePresetsGraph::TestPreset; +using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy; + +constexpr int MIN_VERSION = 1; +constexpr int MAX_VERSION = 4; + +struct CMakeVersion +{ + unsigned int Major = 0; + unsigned int Minor = 0; + unsigned int Patch = 0; +}; + +struct RootPresets +{ + CMakeVersion CMakeMinimumRequired; + std::vector<cmCMakePresetsGraph::ConfigurePreset> ConfigurePresets; + std::vector<cmCMakePresetsGraph::BuildPreset> BuildPresets; + std::vector<cmCMakePresetsGraph::TestPreset> TestPresets; + std::vector<std::string> Include; +}; + +std::unique_ptr<cmCMakePresetsGraphInternal::NotCondition> InvertCondition( + std::unique_ptr<cmCMakePresetsGraph::Condition> condition) +{ + auto retval = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>(); + retval->SubCondition = std::move(condition); + return retval; +} + +auto const ConditionStringHelper = cmJSONStringHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); + +auto const ConditionBoolHelper = cmJSONBoolHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION); + +auto const ConditionStringListHelper = + cmJSONVectorHelper<std::string, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CONDITION, + ConditionStringHelper); + +auto const ConstConditionHelper = + cmJSONObjectHelper<cmCMakePresetsGraphInternal::ConstCondition, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) + .Bind("value"_s, &cmCMakePresetsGraphInternal::ConstCondition::Value, + ConditionBoolHelper, true); + +auto const EqualsConditionHelper = + cmJSONObjectHelper<cmCMakePresetsGraphInternal::EqualsCondition, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) + .Bind("lhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Lhs, + ConditionStringHelper, true) + .Bind("rhs"_s, &cmCMakePresetsGraphInternal::EqualsCondition::Rhs, + ConditionStringHelper, true); + +auto const InListConditionHelper = + cmJSONObjectHelper<cmCMakePresetsGraphInternal::InListCondition, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) + .Bind("string"_s, &cmCMakePresetsGraphInternal::InListCondition::String, + ConditionStringHelper, true) + .Bind("list"_s, &cmCMakePresetsGraphInternal::InListCondition::List, + ConditionStringListHelper, true); + +auto const MatchesConditionHelper = + cmJSONObjectHelper<cmCMakePresetsGraphInternal::MatchesCondition, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) + .Bind("string"_s, &cmCMakePresetsGraphInternal::MatchesCondition::String, + ConditionStringHelper, true) + .Bind("regex"_s, &cmCMakePresetsGraphInternal::MatchesCondition::Regex, + ConditionStringHelper, true); + +ReadFileResult SubConditionHelper( + std::unique_ptr<cmCMakePresetsGraph::Condition>& out, + const Json::Value* value); + +auto const ListConditionVectorHelper = + cmJSONVectorHelper<std::unique_ptr<cmCMakePresetsGraph::Condition>, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, + SubConditionHelper); +auto const AnyAllOfConditionHelper = + cmJSONObjectHelper<cmCMakePresetsGraphInternal::AnyAllOfCondition, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) + .Bind("conditions"_s, + &cmCMakePresetsGraphInternal::AnyAllOfCondition::Conditions, + ListConditionVectorHelper); + +auto const NotConditionHelper = + cmJSONObjectHelper<cmCMakePresetsGraphInternal::NotCondition, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_CONDITION, false) + .Bind<std::string>("type"_s, nullptr, ConditionStringHelper, true) + .Bind("condition"_s, + &cmCMakePresetsGraphInternal::NotCondition::SubCondition, + SubConditionHelper); + +ReadFileResult ConditionHelper( + std::unique_ptr<cmCMakePresetsGraph::Condition>& out, + const Json::Value* value) +{ + if (!value) { + out.reset(); + return ReadFileResult::READ_OK; + } + + if (value->isBool()) { + auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>(); + c->Value = value->asBool(); + out = std::move(c); + return ReadFileResult::READ_OK; + } + + if (value->isNull()) { + out = cm::make_unique<cmCMakePresetsGraphInternal::NullCondition>(); + return ReadFileResult::READ_OK; + } + + if (value->isObject()) { + if (!value->isMember("type")) { + return ReadFileResult::INVALID_CONDITION; + } + + if (!(*value)["type"].isString()) { + return ReadFileResult::INVALID_CONDITION; + } + auto type = (*value)["type"].asString(); + + if (type == "const") { + auto c = cm::make_unique<cmCMakePresetsGraphInternal::ConstCondition>(); + CHECK_OK(ConstConditionHelper(*c, value)); + out = std::move(c); + return ReadFileResult::READ_OK; + } + + if (type == "equals" || type == "notEquals") { + auto c = cm::make_unique<cmCMakePresetsGraphInternal::EqualsCondition>(); + CHECK_OK(EqualsConditionHelper(*c, value)); + out = std::move(c); + if (type == "notEquals") { + out = InvertCondition(std::move(out)); + } + return ReadFileResult::READ_OK; + } + + if (type == "inList" || type == "notInList") { + auto c = cm::make_unique<cmCMakePresetsGraphInternal::InListCondition>(); + CHECK_OK(InListConditionHelper(*c, value)); + out = std::move(c); + if (type == "notInList") { + out = InvertCondition(std::move(out)); + } + return ReadFileResult::READ_OK; + } + + if (type == "matches" || type == "notMatches") { + auto c = + cm::make_unique<cmCMakePresetsGraphInternal::MatchesCondition>(); + CHECK_OK(MatchesConditionHelper(*c, value)); + out = std::move(c); + if (type == "notMatches") { + out = InvertCondition(std::move(out)); + } + return ReadFileResult::READ_OK; + } + + if (type == "anyOf" || type == "allOf") { + auto c = + cm::make_unique<cmCMakePresetsGraphInternal::AnyAllOfCondition>(); + c->StopValue = (type == "anyOf"); + CHECK_OK(AnyAllOfConditionHelper(*c, value)); + out = std::move(c); + return ReadFileResult::READ_OK; + } + + if (type == "not") { + auto c = cm::make_unique<cmCMakePresetsGraphInternal::NotCondition>(); + CHECK_OK(NotConditionHelper(*c, value)); + out = std::move(c); + return ReadFileResult::READ_OK; + } + } + + return ReadFileResult::INVALID_CONDITION; +} + +ReadFileResult SubConditionHelper( + std::unique_ptr<cmCMakePresetsGraph::Condition>& out, + const Json::Value* value) +{ + std::unique_ptr<cmCMakePresetsGraph::Condition> ptr; + auto result = ConditionHelper(ptr, value); + if (ptr && ptr->IsNull()) { + return ReadFileResult::INVALID_CONDITION; + } + out = std::move(ptr); + return result; +} + +ReadFileResult EnvironmentHelper(cm::optional<std::string>& out, + const Json::Value* value) +{ + if (!value || value->isNull()) { + out = cm::nullopt; + return ReadFileResult::READ_OK; + } + if (value->isString()) { + out = value->asString(); + return ReadFileResult::READ_OK; + } + return ReadFileResult::INVALID_PRESET; +} + +auto const VersionIntHelper = cmJSONIntHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); + +auto const VersionHelper = cmJSONRequiredHelper<int, ReadFileResult>( + ReadFileResult::NO_VERSION, VersionIntHelper); + +auto const RootVersionHelper = + cmJSONObjectHelper<int, ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_ROOT) + .Bind("version"_s, VersionHelper, false); + +auto const CMakeVersionUIntHelper = cmJSONUIntHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_VERSION); + +auto const CMakeVersionHelper = + cmJSONObjectHelper<CMakeVersion, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_CMAKE_VERSION, false) + .Bind("major"_s, &CMakeVersion::Major, CMakeVersionUIntHelper, false) + .Bind("minor"_s, &CMakeVersion::Minor, CMakeVersionUIntHelper, false) + .Bind("patch"_s, &CMakeVersion::Patch, CMakeVersionUIntHelper, false); + +auto const IncludeHelper = cmJSONStringHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE); + +auto const IncludeVectorHelper = + cmJSONVectorHelper<std::string, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_INCLUDE, IncludeHelper); + +auto const RootPresetsHelper = + cmJSONObjectHelper<RootPresets, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_ROOT, false) + .Bind<int>("version"_s, nullptr, VersionHelper) + .Bind("configurePresets"_s, &RootPresets::ConfigurePresets, + cmCMakePresetsGraphInternal::ConfigurePresetsHelper, false) + .Bind("buildPresets"_s, &RootPresets::BuildPresets, + cmCMakePresetsGraphInternal::BuildPresetsHelper, false) + .Bind("testPresets"_s, &RootPresets::TestPresets, + cmCMakePresetsGraphInternal::TestPresetsHelper, false) + .Bind("cmakeMinimumRequired"_s, &RootPresets::CMakeMinimumRequired, + CMakeVersionHelper, false) + .Bind("include"_s, &RootPresets::Include, IncludeVectorHelper, false) + .Bind<std::nullptr_t>( + "vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper(ReadFileResult::INVALID_ROOT), + false); +} + +namespace cmCMakePresetsGraphInternal { +cmCMakePresetsGraph::ReadFileResult PresetStringHelper( + std::string& out, const Json::Value* value) +{ + static auto const helper = cmJSONStringHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); + + return helper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult PresetVectorStringHelper( + std::vector<std::string>& out, const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper<std::string, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, + cmCMakePresetsGraphInternal::PresetStringHelper); + + return helper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult PresetBoolHelper(bool& out, + const Json::Value* value) +{ + static auto const helper = cmJSONBoolHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); + + return helper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult PresetOptionalBoolHelper( + cm::optional<bool>& out, const Json::Value* value) +{ + static auto const helper = cmJSONOptionalHelper<bool, ReadFileResult>( + ReadFileResult::READ_OK, PresetBoolHelper); + + return helper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult PresetIntHelper(int& out, + const Json::Value* value) +{ + static auto const helper = cmJSONIntHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET); + + return helper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult PresetOptionalIntHelper( + cm::optional<int>& out, const Json::Value* value) +{ + static auto const helper = cmJSONOptionalHelper<int, ReadFileResult>( + ReadFileResult::READ_OK, PresetIntHelper); + + return helper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult PresetVectorIntHelper( + std::vector<int>& out, const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper<int, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, PresetIntHelper); + + return helper(out, value); +} + +cmJSONHelper<std::nullptr_t, ReadFileResult> VendorHelper(ReadFileResult error) +{ + return [error](std::nullptr_t& /*out*/, + const Json::Value* value) -> ReadFileResult { + if (!value) { + return ReadFileResult::READ_OK; + } + + if (!value->isObject()) { + return error; + } + + return ReadFileResult::READ_OK; + }; +} + +ReadFileResult PresetConditionHelper( + std::shared_ptr<cmCMakePresetsGraph::Condition>& out, + const Json::Value* value) +{ + std::unique_ptr<cmCMakePresetsGraph::Condition> ptr; + auto result = ConditionHelper(ptr, value); + out = std::move(ptr); + return result; +} + +ReadFileResult PresetVectorOneOrMoreStringHelper(std::vector<std::string>& out, + const Json::Value* value) +{ + out.clear(); + if (!value) { + return ReadFileResult::READ_OK; + } + + if (value->isString()) { + out.push_back(value->asString()); + return ReadFileResult::READ_OK; + } + + return PresetVectorStringHelper(out, value); +} + +cmCMakePresetsGraph::ReadFileResult EnvironmentMapHelper( + std::map<std::string, cm::optional<std::string>>& out, + const Json::Value* value) +{ + static auto const helper = + cmJSONMapHelper<cm::optional<std::string>, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, + EnvironmentHelper); + + return helper(out, value); +} +} + +cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( + const std::string& filename, RootType rootType, ReadReason readReason, + std::vector<File*>& inProgressFiles, File*& file) +{ + ReadFileResult result; + + for (auto const& f : this->Files) { + if (cmSystemTools::SameFile(filename, f->Filename)) { + file = f.get(); + auto fileIt = + std::find(inProgressFiles.begin(), inProgressFiles.end(), file); + if (fileIt != inProgressFiles.end()) { + return cmCMakePresetsGraph::ReadFileResult::CYCLIC_INCLUDE; + } + + return cmCMakePresetsGraph::ReadFileResult::READ_OK; + } + } + + cmsys::ifstream fin(filename.c_str()); + if (!fin) { + return ReadFileResult::FILE_NOT_FOUND; + } + // If there's a BOM, toss it. + cmsys::FStream::ReadBOM(fin); + + Json::Value root; + Json::CharReaderBuilder builder; + Json::CharReaderBuilder::strictMode(&builder.settings_); + if (!Json::parseFromStream(builder, fin, &root, nullptr)) { + return ReadFileResult::JSON_PARSE_ERROR; + } + + int v = 0; + if ((result = RootVersionHelper(v, &root)) != ReadFileResult::READ_OK) { + return result; + } + if (v < MIN_VERSION || v > MAX_VERSION) { + return ReadFileResult::UNRECOGNIZED_VERSION; + } + + // Support for build and test presets added in version 2. + if (v < 2 && + (root.isMember("buildPresets") || root.isMember("testPresets"))) { + return ReadFileResult::BUILD_TEST_PRESETS_UNSUPPORTED; + } + + // Support for include added in version 4. + if (v < 4 && root.isMember("include")) { + return ReadFileResult::INCLUDE_UNSUPPORTED; + } + + RootPresets presets; + if ((result = RootPresetsHelper(presets, &root)) != + ReadFileResult::READ_OK) { + return result; + } + + unsigned int currentMajor = cmVersion::GetMajorVersion(); + unsigned int currentMinor = cmVersion::GetMinorVersion(); + unsigned int currentPatch = cmVersion::GetPatchVersion(); + auto const& required = presets.CMakeMinimumRequired; + if (required.Major > currentMajor || + (required.Major == currentMajor && + (required.Minor > currentMinor || + (required.Minor == currentMinor && + (required.Patch > currentPatch))))) { + return ReadFileResult::UNRECOGNIZED_CMAKE_VERSION; + } + + auto filePtr = cm::make_unique<File>(); + file = filePtr.get(); + this->Files.emplace_back(std::move(filePtr)); + inProgressFiles.emplace_back(file); + file->Filename = filename; + file->Version = v; + file->ReachableFiles.insert(file); + + for (auto& preset : presets.ConfigurePresets) { + preset.OriginFile = file; + if (preset.Name.empty()) { + return ReadFileResult::INVALID_PRESET; + } + + PresetPair<ConfigurePreset> presetPair; + presetPair.Unexpanded = preset; + presetPair.Expanded = cm::nullopt; + if (!this->ConfigurePresets + .emplace(std::make_pair(preset.Name, presetPair)) + .second) { + return ReadFileResult::DUPLICATE_PRESETS; + } + + // Support for installDir presets added in version 3. + if (v < 3 && !preset.InstallDir.empty()) { + return ReadFileResult::INSTALL_PREFIX_UNSUPPORTED; + } + + // Support for conditions added in version 3. + if (v < 3 && preset.ConditionEvaluator) { + return ReadFileResult::CONDITION_UNSUPPORTED; + } + + // Support for toolchainFile presets added in version 3. + if (v < 3 && !preset.ToolchainFile.empty()) { + return ReadFileResult::TOOLCHAIN_FILE_UNSUPPORTED; + } + + this->ConfigurePresetOrder.push_back(preset.Name); + } + + for (auto& preset : presets.BuildPresets) { + preset.OriginFile = file; + if (preset.Name.empty()) { + return ReadFileResult::INVALID_PRESET; + } + + PresetPair<BuildPreset> presetPair; + presetPair.Unexpanded = preset; + presetPair.Expanded = cm::nullopt; + if (!this->BuildPresets.emplace(preset.Name, presetPair).second) { + return ReadFileResult::DUPLICATE_PRESETS; + } + + // Support for conditions added in version 3. + if (v < 3 && preset.ConditionEvaluator) { + return ReadFileResult::CONDITION_UNSUPPORTED; + } + + this->BuildPresetOrder.push_back(preset.Name); + } + + for (auto& preset : presets.TestPresets) { + preset.OriginFile = file; + if (preset.Name.empty()) { + return ReadFileResult::INVALID_PRESET; + } + + PresetPair<TestPreset> presetPair; + presetPair.Unexpanded = preset; + presetPair.Expanded = cm::nullopt; + if (!this->TestPresets.emplace(preset.Name, presetPair).second) { + return ReadFileResult::DUPLICATE_PRESETS; + } + + // Support for conditions added in version 3. + if (v < 3 && preset.ConditionEvaluator) { + return ReadFileResult::CONDITION_UNSUPPORTED; + } + + this->TestPresetOrder.push_back(preset.Name); + } + + auto const includeFile = [this, &inProgressFiles, file]( + const std::string& include, RootType rootType2, + ReadReason readReason2) -> ReadFileResult { + ReadFileResult r; + File* includedFile; + if ((r = this->ReadJSONFile(include, rootType2, readReason2, + inProgressFiles, includedFile)) != + ReadFileResult::READ_OK) { + return r; + } + + file->ReachableFiles.insert(includedFile->ReachableFiles.begin(), + includedFile->ReachableFiles.end()); + return ReadFileResult::READ_OK; + }; + + for (auto include : presets.Include) { + if (!cmSystemTools::FileIsFullPath(include)) { + auto directory = cmSystemTools::GetFilenamePath(filename); + include = cmStrCat(directory, '/', include); + } + + if ((result = includeFile(include, rootType, ReadReason::Included)) != + ReadFileResult::READ_OK) { + return result; + } + } + + if (rootType == RootType::User && readReason == ReadReason::Root) { + auto cmakePresetsFilename = GetFilename(this->SourceDir); + if (cmSystemTools::FileExists(cmakePresetsFilename)) { + if ((result = includeFile(cmakePresetsFilename, RootType::Project, + ReadReason::Root)) != + ReadFileResult::READ_OK) { + return result; + } + } + } + + inProgressFiles.pop_back(); + return ReadFileResult::READ_OK; +} diff --git a/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx new file mode 100644 index 0000000..eefe2fe --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONBuildPresets.cxx @@ -0,0 +1,108 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include <cstddef> +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <cm/optional> +#include <cmext/string_view> + +#include <cm3p/json/value.h> + +#include "cmBuildOptions.h" +#include "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using BuildPreset = cmCMakePresetsGraph::BuildPreset; + +ReadFileResult PackageResolveModeHelper(cm::optional<PackageResolveMode>& out, + const Json::Value* value) +{ + if (!value) { + out = cm::nullopt; + return ReadFileResult::READ_OK; + } + + if (!value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "on") { + out = PackageResolveMode::Force; + } else if (value->asString() == "off") { + out = PackageResolveMode::Disable; + } else if (value->asString() == "only") { + out = PackageResolveMode::OnlyResolve; + } else { + return ReadFileResult::INVALID_PRESET; + } + + return ReadFileResult::READ_OK; +} + +std::function<ReadFileResult(BuildPreset&, const Json::Value*)> const + ResolvePackageReferencesHelper = + [](BuildPreset& out, const Json::Value* value) -> ReadFileResult { + return PackageResolveModeHelper(out.ResolvePackageReferences, value); +}; + +auto const BuildPresetHelper = + cmJSONObjectHelper<BuildPreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("name"_s, &BuildPreset::Name, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("inherits"_s, &BuildPreset::Inherits, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("hidden"_s, &BuildPreset::Hidden, + cmCMakePresetsGraphInternal::PresetBoolHelper, false) + .Bind<std::nullptr_t>("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &BuildPreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &BuildPreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("environment"_s, &BuildPreset::Environment, + cmCMakePresetsGraphInternal::EnvironmentMapHelper, false) + .Bind("configurePreset"_s, &BuildPreset::ConfigurePreset, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("inheritConfigureEnvironment"_s, + &BuildPreset::InheritConfigureEnvironment, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("jobs"_s, &BuildPreset::Jobs, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("targets"_s, &BuildPreset::Targets, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("configuration"_s, &BuildPreset::Configuration, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cleanFirst"_s, &BuildPreset::CleanFirst, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("verbose"_s, &BuildPreset::Verbose, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("nativeToolOptions"_s, &BuildPreset::NativeToolOptions, + cmCMakePresetsGraphInternal::PresetVectorStringHelper, false) + .Bind("condition"_s, &BuildPreset::ConditionEvaluator, + cmCMakePresetsGraphInternal::PresetConditionHelper, false) + .Bind("resolvePackageReferences"_s, ResolvePackageReferencesHelper, false); +} + +namespace cmCMakePresetsGraphInternal { +ReadFileResult BuildPresetsHelper(std::vector<BuildPreset>& out, + const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper<BuildPreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + BuildPresetHelper); + + return helper(out, value); +} +} diff --git a/Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx b/Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx new file mode 100644 index 0000000..0f44546 --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONConfigurePresets.cxx @@ -0,0 +1,228 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include <cstddef> +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <cm/optional> +#include <cmext/string_view> + +#include <cm3p/json/value.h> + +#include "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using CacheVariable = cmCMakePresetsGraph::CacheVariable; +using ConfigurePreset = cmCMakePresetsGraph::ConfigurePreset; +using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy; + +ReadFileResult ArchToolsetStrategyHelper( + cm::optional<ArchToolsetStrategy>& out, const Json::Value* value) +{ + if (!value) { + out = cm::nullopt; + return ReadFileResult::READ_OK; + } + + if (!value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "set") { + out = ArchToolsetStrategy::Set; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "external") { + out = ArchToolsetStrategy::External; + return ReadFileResult::READ_OK; + } + + return ReadFileResult::INVALID_PRESET; +} + +std::function<ReadFileResult(ConfigurePreset&, const Json::Value*)> +ArchToolsetHelper( + std::string ConfigurePreset::*valueField, + cm::optional<ArchToolsetStrategy> ConfigurePreset::*strategyField) +{ + auto const objectHelper = + cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("value", valueField, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("strategy", strategyField, ArchToolsetStrategyHelper, false); + return [valueField, strategyField, objectHelper]( + ConfigurePreset& out, const Json::Value* value) -> ReadFileResult { + if (!value) { + (out.*valueField).clear(); + out.*strategyField = cm::nullopt; + return ReadFileResult::READ_OK; + } + + if (value->isString()) { + out.*valueField = value->asString(); + out.*strategyField = cm::nullopt; + return ReadFileResult::READ_OK; + } + + if (value->isObject()) { + return objectHelper(out, value); + } + + return ReadFileResult::INVALID_PRESET; + }; +} + +auto const ArchitectureHelper = ArchToolsetHelper( + &ConfigurePreset::Architecture, &ConfigurePreset::ArchitectureStrategy); +auto const ToolsetHelper = ArchToolsetHelper( + &ConfigurePreset::Toolset, &ConfigurePreset::ToolsetStrategy); + +auto const VariableStringHelper = cmJSONStringHelper<ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE); + +ReadFileResult VariableValueHelper(std::string& out, const Json::Value* value) +{ + if (!value) { + out.clear(); + return ReadFileResult::READ_OK; + } + + if (value->isBool()) { + out = value->asBool() ? "TRUE" : "FALSE"; + return ReadFileResult::READ_OK; + } + + return VariableStringHelper(out, value); +} + +auto const VariableObjectHelper = + cmJSONObjectHelper<CacheVariable, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_VARIABLE, false) + .Bind("type"_s, &CacheVariable::Type, VariableStringHelper, false) + .Bind("value"_s, &CacheVariable::Value, VariableValueHelper); + +ReadFileResult VariableHelper(cm::optional<CacheVariable>& out, + const Json::Value* value) +{ + if (value->isBool()) { + out = CacheVariable{ + /*Type=*/"BOOL", + /*Value=*/value->asBool() ? "TRUE" : "FALSE", + }; + return ReadFileResult::READ_OK; + } + if (value->isString()) { + out = CacheVariable{ + /*Type=*/"", + /*Value=*/value->asString(), + }; + return ReadFileResult::READ_OK; + } + if (value->isObject()) { + out.emplace(); + return VariableObjectHelper(*out, value); + } + if (value->isNull()) { + out = cm::nullopt; + return ReadFileResult::READ_OK; + } + return ReadFileResult::INVALID_VARIABLE; +} + +auto const VariablesHelper = + cmJSONMapHelper<cm::optional<CacheVariable>, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, VariableHelper); + +auto const PresetWarningsHelper = + cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("dev"_s, &ConfigurePreset::WarnDev, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("deprecated"_s, &ConfigurePreset::WarnDeprecated, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("uninitialized"_s, &ConfigurePreset::WarnUninitialized, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("unusedCli"_s, &ConfigurePreset::WarnUnusedCli, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("systemVars"_s, &ConfigurePreset::WarnSystemVars, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false); + +auto const PresetErrorsHelper = + cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("dev"_s, &ConfigurePreset::ErrorDev, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("deprecated"_s, &ConfigurePreset::ErrorDeprecated, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false); + +auto const PresetDebugHelper = + cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("output"_s, &ConfigurePreset::DebugOutput, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("tryCompile"_s, &ConfigurePreset::DebugTryCompile, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("find"_s, &ConfigurePreset::DebugFind, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false); + +auto const ConfigurePresetHelper = + cmJSONObjectHelper<ConfigurePreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("name"_s, &ConfigurePreset::Name, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("inherits"_s, &ConfigurePreset::Inherits, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("hidden"_s, &ConfigurePreset::Hidden, + cmCMakePresetsGraphInternal::PresetBoolHelper, false) + .Bind<std::nullptr_t>("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &ConfigurePreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &ConfigurePreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("generator"_s, &ConfigurePreset::Generator, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("architecture"_s, ArchitectureHelper, false) + .Bind("toolset"_s, ToolsetHelper, false) + .Bind("toolchainFile"_s, &ConfigurePreset::ToolchainFile, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("binaryDir"_s, &ConfigurePreset::BinaryDir, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("installDir"_s, &ConfigurePreset::InstallDir, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind<std::string>("cmakeExecutable"_s, nullptr, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cacheVariables"_s, &ConfigurePreset::CacheVariables, + VariablesHelper, false) + .Bind("environment"_s, &ConfigurePreset::Environment, + cmCMakePresetsGraphInternal::EnvironmentMapHelper, false) + .Bind("warnings"_s, PresetWarningsHelper, false) + .Bind("errors"_s, PresetErrorsHelper, false) + .Bind("debug"_s, PresetDebugHelper, false) + .Bind("condition"_s, &ConfigurePreset::ConditionEvaluator, + cmCMakePresetsGraphInternal::PresetConditionHelper, false); +} + +namespace cmCMakePresetsGraphInternal { +ReadFileResult ConfigurePresetsHelper(std::vector<ConfigurePreset>& out, + const Json::Value* value) +{ + static auto const helper = + cmJSONVectorHelper<ConfigurePreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + ConfigurePresetHelper); + + return helper(out, value); +} +} diff --git a/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx new file mode 100644 index 0000000..4d6474a --- /dev/null +++ b/Source/cmCMakePresetsGraphReadJSONTestPresets.cxx @@ -0,0 +1,360 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include <cstddef> +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <cm/optional> +#include <cmext/string_view> + +#include <cm3p/json/value.h> + +#include "cmCMakePresetsGraph.h" +#include "cmCMakePresetsGraphInternal.h" +#include "cmJSONHelpers.h" + +namespace { +using ReadFileResult = cmCMakePresetsGraph::ReadFileResult; +using TestPreset = cmCMakePresetsGraph::TestPreset; + +ReadFileResult TestPresetOutputVerbosityHelper( + TestPreset::OutputOptions::VerbosityEnum& out, const Json::Value* value) +{ + if (!value) { + out = TestPreset::OutputOptions::VerbosityEnum::Default; + return ReadFileResult::READ_OK; + } + + if (!value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "default") { + out = TestPreset::OutputOptions::VerbosityEnum::Default; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "verbose") { + out = TestPreset::OutputOptions::VerbosityEnum::Verbose; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "extra") { + out = TestPreset::OutputOptions::VerbosityEnum::Extra; + return ReadFileResult::READ_OK; + } + + return ReadFileResult::INVALID_PRESET; +} + +auto const TestPresetOptionalOutputVerbosityHelper = + cmJSONOptionalHelper<TestPreset::OutputOptions::VerbosityEnum, + ReadFileResult>(ReadFileResult::READ_OK, + TestPresetOutputVerbosityHelper); + +auto const TestPresetOptionalOutputHelper = + cmJSONOptionalHelper<TestPreset::OutputOptions, ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::OutputOptions, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("shortProgress"_s, &TestPreset::OutputOptions::ShortProgress, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("verbosity"_s, &TestPreset::OutputOptions::Verbosity, + TestPresetOptionalOutputVerbosityHelper, false) + .Bind("debug"_s, &TestPreset::OutputOptions::Debug, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("outputOnFailure"_s, &TestPreset::OutputOptions::OutputOnFailure, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("quiet"_s, &TestPreset::OutputOptions::Quiet, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("outputLogFile"_s, &TestPreset::OutputOptions::OutputLogFile, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("labelSummary"_s, &TestPreset::OutputOptions::LabelSummary, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("subprojectSummary"_s, + &TestPreset::OutputOptions::SubprojectSummary, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("maxPassedTestOutputSize"_s, + &TestPreset::OutputOptions::MaxPassedTestOutputSize, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("maxFailedTestOutputSize"_s, + &TestPreset::OutputOptions::MaxFailedTestOutputSize, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("maxTestNameWidth"_s, &TestPreset::OutputOptions::MaxTestNameWidth, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false)); + +auto const TestPresetOptionalFilterIncludeIndexObjectHelper = + cmJSONOptionalHelper<TestPreset::IncludeOptions::IndexOptions, + ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::IncludeOptions::IndexOptions, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_PRESET) + .Bind("start"_s, &TestPreset::IncludeOptions::IndexOptions::Start, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("end"_s, &TestPreset::IncludeOptions::IndexOptions::End, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("stride"_s, &TestPreset::IncludeOptions::IndexOptions::Stride, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("specificTests"_s, + &TestPreset::IncludeOptions::IndexOptions::SpecificTests, + cmCMakePresetsGraphInternal::PresetVectorIntHelper, false)); + +ReadFileResult TestPresetOptionalFilterIncludeIndexHelper( + cm::optional<TestPreset::IncludeOptions::IndexOptions>& out, + const Json::Value* value) +{ + if (!value) { + out = cm::nullopt; + return ReadFileResult::READ_OK; + } + + if (value->isString()) { + out.emplace(); + out->IndexFile = value->asString(); + return ReadFileResult::READ_OK; + } + + if (value->isObject()) { + return TestPresetOptionalFilterIncludeIndexObjectHelper(out, value); + } + + return ReadFileResult::INVALID_PRESET; +} + +auto const TestPresetOptionalFilterIncludeHelper = + cmJSONOptionalHelper<TestPreset::IncludeOptions, ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::IncludeOptions, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) + .Bind("name"_s, &TestPreset::IncludeOptions::Name, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("label"_s, &TestPreset::IncludeOptions::Label, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("index"_s, &TestPreset::IncludeOptions::Index, + TestPresetOptionalFilterIncludeIndexHelper, false) + .Bind("useUnion"_s, &TestPreset::IncludeOptions::UseUnion, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false)); + +auto const TestPresetOptionalFilterExcludeFixturesHelper = + cmJSONOptionalHelper<TestPreset::ExcludeOptions::FixturesOptions, + ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::ExcludeOptions::FixturesOptions, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_PRESET) + .Bind("any"_s, &TestPreset::ExcludeOptions::FixturesOptions::Any, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("setup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Setup, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("cleanup"_s, &TestPreset::ExcludeOptions::FixturesOptions::Cleanup, + cmCMakePresetsGraphInternal::PresetStringHelper, false)); + +auto const TestPresetOptionalFilterExcludeHelper = + cmJSONOptionalHelper<TestPreset::ExcludeOptions, ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::ExcludeOptions, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) + .Bind("name"_s, &TestPreset::ExcludeOptions::Name, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("label"_s, &TestPreset::ExcludeOptions::Label, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("fixtures"_s, &TestPreset::ExcludeOptions::Fixtures, + TestPresetOptionalFilterExcludeFixturesHelper, false)); + +ReadFileResult TestPresetExecutionShowOnlyHelper( + TestPreset::ExecutionOptions::ShowOnlyEnum& out, const Json::Value* value) +{ + if (!value || !value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "human") { + out = TestPreset::ExecutionOptions::ShowOnlyEnum::Human; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "json-v1") { + out = TestPreset::ExecutionOptions::ShowOnlyEnum::JsonV1; + return ReadFileResult::READ_OK; + } + + return ReadFileResult::INVALID_PRESET; +} + +auto const TestPresetOptionalExecutionShowOnlyHelper = + cmJSONOptionalHelper<TestPreset::ExecutionOptions::ShowOnlyEnum, + ReadFileResult>(ReadFileResult::READ_OK, + TestPresetExecutionShowOnlyHelper); + +ReadFileResult TestPresetExecutionModeHelper( + TestPreset::ExecutionOptions::RepeatOptions::ModeEnum& out, + const Json::Value* value) +{ + if (!value) { + return ReadFileResult::READ_OK; + } + + if (!value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "until-fail") { + out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilFail; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "until-pass") { + out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::UntilPass; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "after-timeout") { + out = TestPreset::ExecutionOptions::RepeatOptions::ModeEnum::AfterTimeout; + return ReadFileResult::READ_OK; + } + + return ReadFileResult::INVALID_PRESET; +} + +auto const TestPresetOptionalExecutionRepeatHelper = + cmJSONOptionalHelper<TestPreset::ExecutionOptions::RepeatOptions, + ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::ExecutionOptions::RepeatOptions, + ReadFileResult>(ReadFileResult::READ_OK, + ReadFileResult::INVALID_PRESET) + .Bind("mode"_s, &TestPreset::ExecutionOptions::RepeatOptions::Mode, + TestPresetExecutionModeHelper, true) + .Bind("count"_s, &TestPreset::ExecutionOptions::RepeatOptions::Count, + cmCMakePresetsGraphInternal::PresetIntHelper, true)); + +ReadFileResult TestPresetExecutionNoTestsActionHelper( + TestPreset::ExecutionOptions::NoTestsActionEnum& out, + const Json::Value* value) +{ + if (!value) { + out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default; + return ReadFileResult::READ_OK; + } + + if (!value->isString()) { + return ReadFileResult::INVALID_PRESET; + } + + if (value->asString() == "default") { + out = TestPreset::ExecutionOptions::NoTestsActionEnum::Default; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "error") { + out = TestPreset::ExecutionOptions::NoTestsActionEnum::Error; + return ReadFileResult::READ_OK; + } + + if (value->asString() == "ignore") { + out = TestPreset::ExecutionOptions::NoTestsActionEnum::Ignore; + return ReadFileResult::READ_OK; + } + + return ReadFileResult::INVALID_PRESET; +} + +auto const TestPresetOptionalExecutionNoTestsActionHelper = + cmJSONOptionalHelper<TestPreset::ExecutionOptions::NoTestsActionEnum, + ReadFileResult>(ReadFileResult::READ_OK, + TestPresetExecutionNoTestsActionHelper); + +auto const TestPresetExecutionHelper = + cmJSONOptionalHelper<TestPreset::ExecutionOptions, ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::ExecutionOptions, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) + .Bind("stopOnFailure"_s, &TestPreset::ExecutionOptions::StopOnFailure, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("enableFailover"_s, &TestPreset::ExecutionOptions::EnableFailover, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("jobs"_s, &TestPreset::ExecutionOptions::Jobs, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("resourceSpecFile"_s, + &TestPreset::ExecutionOptions::ResourceSpecFile, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("testLoad"_s, &TestPreset::ExecutionOptions::TestLoad, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("showOnly"_s, &TestPreset::ExecutionOptions::ShowOnly, + TestPresetOptionalExecutionShowOnlyHelper, false) + .Bind("repeat"_s, &TestPreset::ExecutionOptions::Repeat, + TestPresetOptionalExecutionRepeatHelper, false) + .Bind("interactiveDebugging"_s, + &TestPreset::ExecutionOptions::InteractiveDebugging, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("scheduleRandom"_s, &TestPreset::ExecutionOptions::ScheduleRandom, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("timeout"_s, &TestPreset::ExecutionOptions::Timeout, + cmCMakePresetsGraphInternal::PresetOptionalIntHelper, false) + .Bind("noTestsAction"_s, &TestPreset::ExecutionOptions::NoTestsAction, + TestPresetOptionalExecutionNoTestsActionHelper, false)); + +auto const TestPresetFilterHelper = + cmJSONOptionalHelper<TestPreset::FilterOptions, ReadFileResult>( + ReadFileResult::READ_OK, + cmJSONObjectHelper<TestPreset::FilterOptions, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET) + .Bind("include"_s, &TestPreset::FilterOptions::Include, + TestPresetOptionalFilterIncludeHelper, false) + .Bind("exclude"_s, &TestPreset::FilterOptions::Exclude, + TestPresetOptionalFilterExcludeHelper, false)); + +auto const TestPresetHelper = + cmJSONObjectHelper<TestPreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESET, false) + .Bind("name"_s, &TestPreset::Name, + cmCMakePresetsGraphInternal::PresetStringHelper) + .Bind("inherits"_s, &TestPreset::Inherits, + cmCMakePresetsGraphInternal::PresetVectorOneOrMoreStringHelper, + false) + .Bind("hidden"_s, &TestPreset::Hidden, + cmCMakePresetsGraphInternal::PresetBoolHelper, false) + .Bind<std::nullptr_t>("vendor"_s, nullptr, + cmCMakePresetsGraphInternal::VendorHelper( + ReadFileResult::INVALID_PRESET), + false) + .Bind("displayName"_s, &TestPreset::DisplayName, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("description"_s, &TestPreset::Description, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("environment"_s, &TestPreset::Environment, + cmCMakePresetsGraphInternal::EnvironmentMapHelper, false) + .Bind("configurePreset"_s, &TestPreset::ConfigurePreset, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("inheritConfigureEnvironment"_s, + &TestPreset::InheritConfigureEnvironment, + cmCMakePresetsGraphInternal::PresetOptionalBoolHelper, false) + .Bind("configuration"_s, &TestPreset::Configuration, + cmCMakePresetsGraphInternal::PresetStringHelper, false) + .Bind("overwriteConfigurationFile"_s, + &TestPreset::OverwriteConfigurationFile, + cmCMakePresetsGraphInternal::PresetVectorStringHelper, false) + .Bind("output"_s, &TestPreset::Output, TestPresetOptionalOutputHelper, + false) + .Bind("filter"_s, &TestPreset::Filter, TestPresetFilterHelper, false) + .Bind("execution"_s, &TestPreset::Execution, TestPresetExecutionHelper, + false) + .Bind("condition"_s, &TestPreset::ConditionEvaluator, + cmCMakePresetsGraphInternal::PresetConditionHelper, false); +} + +namespace cmCMakePresetsGraphInternal { +cmCMakePresetsGraph::ReadFileResult TestPresetsHelper( + std::vector<cmCMakePresetsGraph::TestPreset>& out, const Json::Value* value) +{ + static auto const helper = cmJSONVectorHelper<TestPreset, ReadFileResult>( + ReadFileResult::READ_OK, ReadFileResult::INVALID_PRESETS, + TestPresetHelper); + + return helper(out, value); +} +} diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index e460031..1b11f20 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -22,17 +22,17 @@ extern "C" { -void CCONV* cmGetClientData(void* info) +static void CCONV* cmGetClientData(void* info) { return ((cmLoadedCommandInfo*)info)->ClientData; } -void CCONV cmSetClientData(void* info, void* cd) +static void CCONV cmSetClientData(void* info, void* cd) { ((cmLoadedCommandInfo*)info)->ClientData = cd; } -void CCONV cmSetError(void* info, const char* err) +static void CCONV cmSetError(void* info, const char* err) { if (((cmLoadedCommandInfo*)info)->Error) { free(((cmLoadedCommandInfo*)info)->Error); @@ -40,30 +40,31 @@ void CCONV cmSetError(void* info, const char* err) ((cmLoadedCommandInfo*)info)->Error = strdup(err); } -unsigned int CCONV cmGetCacheMajorVersion(void* arg) +static unsigned int CCONV cmGetCacheMajorVersion(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); cmState* state = mf->GetState(); return state->GetCacheMajorVersion(); } -unsigned int CCONV cmGetCacheMinorVersion(void* arg) +static unsigned int CCONV cmGetCacheMinorVersion(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); cmState* state = mf->GetState(); return state->GetCacheMinorVersion(); } -unsigned int CCONV cmGetMajorVersion(void*) +static unsigned int CCONV cmGetMajorVersion(void*) { return cmVersion::GetMajorVersion(); } -unsigned int CCONV cmGetMinorVersion(void*) +static unsigned int CCONV cmGetMinorVersion(void*) { return cmVersion::GetMinorVersion(); } -void CCONV cmAddDefinition(void* arg, const char* name, const char* value) +static void CCONV cmAddDefinition(void* arg, const char* name, + const char* value) { if (value) { cmMakefile* mf = static_cast<cmMakefile*>(arg); @@ -72,8 +73,9 @@ void CCONV cmAddDefinition(void* arg, const char* name, const char* value) } /* Add a definition to this makefile and the global cmake cache. */ -void CCONV cmAddCacheDefinition(void* arg, const char* name, const char* value, - const char* doc, int type) +static void CCONV cmAddCacheDefinition(void* arg, const char* name, + const char* value, const char* doc, + int type) { cmMakefile* mf = static_cast<cmMakefile*>(arg); @@ -99,7 +101,7 @@ void CCONV cmAddCacheDefinition(void* arg, const char* name, const char* value, } } -const char* CCONV cmGetProjectName(void* arg) +static const char* CCONV cmGetProjectName(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); static std::string name; @@ -107,63 +109,63 @@ const char* CCONV cmGetProjectName(void* arg) return name.c_str(); } -const char* CCONV cmGetHomeDirectory(void* arg) +static const char* CCONV cmGetHomeDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetHomeDirectory().c_str(); } -const char* CCONV cmGetHomeOutputDirectory(void* arg) +static const char* CCONV cmGetHomeOutputDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetHomeOutputDirectory().c_str(); } -const char* CCONV cmGetStartDirectory(void* arg) +static const char* CCONV cmGetStartDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetCurrentSourceDirectory().c_str(); } -const char* CCONV cmGetStartOutputDirectory(void* arg) +static const char* CCONV cmGetStartOutputDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetCurrentBinaryDirectory().c_str(); } -const char* CCONV cmGetCurrentDirectory(void* arg) +static const char* CCONV cmGetCurrentDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetCurrentSourceDirectory().c_str(); } -const char* CCONV cmGetCurrentOutputDirectory(void* arg) +static const char* CCONV cmGetCurrentOutputDirectory(void* arg) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetCurrentBinaryDirectory().c_str(); } -const char* CCONV cmGetDefinition(void* arg, const char* def) +static const char* CCONV cmGetDefinition(void* arg, const char* def) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return mf->GetDefinition(def).GetCStr(); } -int CCONV cmIsOn(void* arg, const char* name) +static int CCONV cmIsOn(void* arg, const char* name) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return static_cast<int>(mf->IsOn(name)); } /** Check if a command exists. */ -int CCONV cmCommandExists(void* arg, const char* name) +static int CCONV cmCommandExists(void* arg, const char* name) { cmMakefile* mf = static_cast<cmMakefile*>(arg); return static_cast<int>(mf->GetState()->GetCommand(name) ? 1 : 0); } -void CCONV cmAddDefineFlag(void* arg, const char* definition) +static void CCONV cmAddDefineFlag(void* arg, const char* definition) { cmMakefile* mf = static_cast<cmMakefile*>(arg); mf->AddDefineFlag(definition); } -void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt, - const char* d) +static void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt, + const char* d) { cmMakefile* mf = static_cast<cmMakefile*>(arg); cmTarget* t = mf->FindLocalNonAliasTarget(tgt); @@ -176,8 +178,8 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt, t->InsertLinkDirectory(BT<std::string>(d, mf->GetBacktrace())); } -void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs, - const char** srcs, int win32) +static void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs, + const char** srcs, int win32) { cmMakefile* mf = static_cast<cmMakefile*>(arg); std::vector<std::string> srcs2; @@ -191,10 +193,11 @@ void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs, } } -void CCONV cmAddUtilityCommand(void* arg, const char* utilityName, - const char* command, const char* arguments, - int all, int numDepends, const char** depends, - int, const char**) +static void CCONV cmAddUtilityCommand(void* arg, const char* utilityName, + const char* command, + const char* arguments, int all, + int numDepends, const char** depends, + int, const char**) { // Get the makefile instance. Perform an extra variable expansion // now because the API caller expects it. @@ -220,17 +223,17 @@ void CCONV cmAddUtilityCommand(void* arg, const char* utilityName, } // Pass the call to the makefile instance. - std::vector<std::string> no_byproducts; - mf->AddUtilityCommand(utilityName, !all, nullptr, no_byproducts, depends2, - commandLines, - mf->GetPolicyStatus(cmPolicies::CMP0116)); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetDepends(depends2); + cc->SetCommandLines(commandLines); + mf->AddUtilityCommand(utilityName, !all, std::move(cc)); } -void CCONV cmAddCustomCommand(void* arg, const char* source, - const char* command, int numArgs, - const char** args, int numDepends, - const char** depends, int numOutputs, - const char** outputs, const char* target) +static void CCONV cmAddCustomCommand(void* arg, const char* source, + const char* command, int numArgs, + const char** args, int numDepends, + const char** depends, int numOutputs, + const char** outputs, const char* target) { // Get the makefile instance. Perform an extra variable expansion // now because the API caller expects it. @@ -264,15 +267,15 @@ void CCONV cmAddCustomCommand(void* arg, const char* source, // Pass the call to the makefile instance. const char* no_comment = nullptr; mf->AddCustomCommandOldStyle(target, outputs2, depends2, source, - commandLines, no_comment, - mf->GetPolicyStatus(cmPolicies::CMP0116)); + commandLines, no_comment); } -void CCONV cmAddCustomCommandToOutput(void* arg, const char* output, - const char* command, int numArgs, - const char** args, - const char* main_dependency, - int numDepends, const char** depends) +static void CCONV cmAddCustomCommandToOutput(void* arg, const char* output, + const char* command, int numArgs, + const char** args, + const char* main_dependency, + int numDepends, + const char** depends) { // Get the makefile instance. Perform an extra variable expansion // now because the API caller expects it. @@ -297,16 +300,18 @@ void CCONV cmAddCustomCommandToOutput(void* arg, const char* output, } // Pass the call to the makefile instance. - const char* no_comment = nullptr; - const char* no_working_dir = nullptr; - mf->AddCustomCommandToOutput(output, depends2, main_dependency, commandLines, - no_comment, no_working_dir, - mf->GetPolicyStatus(cmPolicies::CMP0116)); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(output); + cc->SetMainDependency(main_dependency); + cc->SetDepends(depends2); + cc->SetCommandLines(commandLines); + mf->AddCustomCommandToOutput(std::move(cc)); } -void CCONV cmAddCustomCommandToTarget(void* arg, const char* target, - const char* command, int numArgs, - const char** args, int commandType) +static void CCONV cmAddCustomCommandToTarget(void* arg, const char* target, + const char* command, int numArgs, + const char** args, + int commandType) { // Get the makefile instance. cmMakefile* mf = static_cast<cmMakefile*>(arg); @@ -338,13 +343,9 @@ void CCONV cmAddCustomCommandToTarget(void* arg, const char* target, } // Pass the call to the makefile instance. - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; - const char* no_comment = nullptr; - const char* no_working_dir = nullptr; - mf->AddCustomCommandToTarget(target, no_byproducts, no_depends, commandLines, - cctype, no_comment, no_working_dir, - mf->GetPolicyStatus(cmPolicies::CMP0116)); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetCommandLines(commandLines); + mf->AddCustomCommandToTarget(target, cctype, std::move(cc)); } static void addLinkLibrary(cmMakefile* mf, std::string const& target, @@ -376,8 +377,8 @@ static void addLinkLibrary(cmMakefile* mf, std::string const& target, t->AddLinkLibrary(*mf, lib, llt); } -void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt, - const char* value, int libtype) +static void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt, + const char* value, int libtype) { cmMakefile* mf = static_cast<cmMakefile*>(arg); @@ -394,8 +395,8 @@ void CCONV cmAddLinkLibraryForTarget(void* arg, const char* tgt, } } -void CCONV cmAddLibrary(void* arg, const char* libname, int shared, - int numSrcs, const char** srcs) +static void CCONV cmAddLibrary(void* arg, const char* libname, int shared, + int numSrcs, const char** srcs) { cmMakefile* mf = static_cast<cmMakefile*>(arg); std::vector<std::string> srcs2; @@ -409,8 +410,8 @@ void CCONV cmAddLibrary(void* arg, const char* libname, int shared, srcs2); } -char CCONV* cmExpandVariablesInString(void* arg, const char* source, - int escapeQuotes, int atOnly) +static char CCONV* cmExpandVariablesInString(void* arg, const char* source, + int escapeQuotes, int atOnly) { cmMakefile* mf = static_cast<cmMakefile*>(arg); std::string barf = source; @@ -419,8 +420,8 @@ char CCONV* cmExpandVariablesInString(void* arg, const char* source, return strdup(result.c_str()); } -int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs, - const char** args) +static int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs, + const char** args) { cmMakefile* mf = static_cast<cmMakefile*>(arg); @@ -436,10 +437,10 @@ int CCONV cmExecuteCommand(void* arg, const char* name, int numArgs, return mf->ExecuteCommand(lff, status); } -void CCONV cmExpandSourceListArguments(void* arg, int numArgs, - const char** args, int* resArgc, - char*** resArgv, - unsigned int startArgumentIndex) +static void CCONV cmExpandSourceListArguments(void* arg, int numArgs, + const char** args, int* resArgc, + char*** resArgv, + unsigned int startArgumentIndex) { (void)arg; (void)startArgumentIndex; @@ -460,7 +461,7 @@ void CCONV cmExpandSourceListArguments(void* arg, int numArgs, *resArgv = resargv; } -void CCONV cmFreeArguments(int argc, char** argv) +static void CCONV cmFreeArguments(int argc, char** argv) { int i; for (i = 0; i < argc; ++i) { @@ -469,7 +470,7 @@ void CCONV cmFreeArguments(int argc, char** argv) free(argv); } -int CCONV cmGetTotalArgumentSize(int argc, char** argv) +static int CCONV cmGetTotalArgumentSize(int argc, char** argv) { int i; int result = 0; @@ -497,19 +498,19 @@ struct cmCPluginAPISourceFile // the CPluginAPI proxy source file. using cmCPluginAPISourceFileMap = std::map<cmSourceFile*, std::unique_ptr<cmCPluginAPISourceFile>>; -cmCPluginAPISourceFileMap cmCPluginAPISourceFiles; +static cmCPluginAPISourceFileMap cmCPluginAPISourceFiles; -void* CCONV cmCreateSourceFile(void) +static void* CCONV cmCreateSourceFile() { return new cmCPluginAPISourceFile; } -void* CCONV cmCreateNewSourceFile(void*) +static void* CCONV cmCreateNewSourceFile(void*) { return new cmCPluginAPISourceFile; } -void CCONV cmDestroySourceFile(void* arg) +static void CCONV cmDestroySourceFile(void* arg) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); // Only delete if it was created by cmCreateSourceFile or @@ -519,7 +520,7 @@ void CCONV cmDestroySourceFile(void* arg) } } -void CCONV* cmGetSource(void* arg, const char* name) +static void CCONV* cmGetSource(void* arg, const char* name) { cmMakefile* mf = static_cast<cmMakefile*>(arg); if (cmSourceFile* rsf = mf->GetSource(name)) { @@ -543,7 +544,7 @@ void CCONV* cmGetSource(void* arg, const char* name) return nullptr; } -void* CCONV cmAddSource(void* arg, void* arg2) +static void* CCONV cmAddSource(void* arg, void* arg2) { cmMakefile* mf = static_cast<cmMakefile*>(arg); cmCPluginAPISourceFile* osf = static_cast<cmCPluginAPISourceFile*>(arg2); @@ -576,19 +577,19 @@ void* CCONV cmAddSource(void* arg, void* arg2) return value; } -const char* CCONV cmSourceFileGetSourceName(void* arg) +static const char* CCONV cmSourceFileGetSourceName(void* arg) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); return sf->SourceName.c_str(); } -const char* CCONV cmSourceFileGetFullPath(void* arg) +static const char* CCONV cmSourceFileGetFullPath(void* arg) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); return sf->FullPath.c_str(); } -const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop) +static const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { @@ -600,7 +601,7 @@ const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop) return sf->Properties.GetPropertyValue(prop).GetCStr(); } -int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) +static int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { @@ -609,8 +610,8 @@ int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) return cmIsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0; } -void CCONV cmSourceFileSetProperty(void* arg, const char* prop, - const char* value) +static void CCONV cmSourceFileSetProperty(void* arg, const char* prop, + const char* value) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { @@ -623,7 +624,7 @@ void CCONV cmSourceFileSetProperty(void* arg, const char* prop, } } -void CCONV cmSourceFileAddDepend(void* arg, const char* depend) +static void CCONV cmSourceFileAddDepend(void* arg, const char* depend) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { @@ -633,11 +634,11 @@ void CCONV cmSourceFileAddDepend(void* arg, const char* depend) } } -void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir, - int numSourceExtensions, - const char** sourceExtensions, - int numHeaderExtensions, - const char** headerExtensions) +static void CCONV cmSourceFileSetName(void* arg, const char* name, + const char* dir, int numSourceExtensions, + const char** sourceExtensions, + int numHeaderExtensions, + const char** headerExtensions) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (sf->RealSourceFile) { @@ -718,8 +719,9 @@ void CCONV cmSourceFileSetName(void* arg, const char* name, const char* dir, cmSystemTools::Error(e.str()); } -void CCONV cmSourceFileSetName2(void* arg, const char* name, const char* dir, - const char* ext, int headerFileOnly) +static void CCONV cmSourceFileSetName2(void* arg, const char* name, + const char* dir, const char* ext, + int headerFileOnly) { cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (sf->RealSourceFile) { @@ -743,48 +745,48 @@ void CCONV cmSourceFileSetName2(void* arg, const char* name, const char* dir, sf->SourceExtension = ext; } -char* CCONV cmGetFilenameWithoutExtension(const char* name) +static char* CCONV cmGetFilenameWithoutExtension(const char* name) { std::string sres = cmSystemTools::GetFilenameWithoutExtension(name); return strdup(sres.c_str()); } -char* CCONV cmGetFilenamePath(const char* name) +static char* CCONV cmGetFilenamePath(const char* name) { std::string sres = cmSystemTools::GetFilenamePath(name); return strdup(sres.c_str()); } -char* CCONV cmCapitalized(const char* name) +static char* CCONV cmCapitalized(const char* name) { std::string sres = cmSystemTools::Capitalized(name); return strdup(sres.c_str()); } -void CCONV cmCopyFileIfDifferent(const char* name1, const char* name2) +static void CCONV cmCopyFileIfDifferent(const char* name1, const char* name2) { cmSystemTools::CopyFileIfDifferent(name1, name2); } -void CCONV cmRemoveFile(const char* name) +static void CCONV cmRemoveFile(const char* name) { cmSystemTools::RemoveFile(name); } -void CCONV cmDisplayStatus(void* arg, const char* message) +static void CCONV cmDisplayStatus(void* arg, const char* message) { cmMakefile* mf = static_cast<cmMakefile*>(arg); mf->DisplayStatus(message, -1); } -void CCONV cmFree(void* data) +static void CCONV cmFree(void* data) { free(data); } -void CCONV DefineSourceFileProperty(void* arg, const char* name, - const char* briefDocs, - const char* longDocs, int chained) +static void CCONV DefineSourceFileProperty(void* arg, const char* name, + const char* briefDocs, + const char* longDocs, int chained) { cmMakefile* mf = static_cast<cmMakefile*>(arg); mf->GetState()->DefineProperty(name, cmProperty::SOURCE_FILE, @@ -794,7 +796,7 @@ void CCONV DefineSourceFileProperty(void* arg, const char* name, } // close the extern "C" scope -cmCAPI cmStaticCAPI = { +static cmCAPI cmStaticCAPI = { cmGetClientData, cmGetTotalArgumentSize, cmFreeArguments, diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index dfd2b6c..a1e920e 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -38,7 +38,7 @@ # include <unistd.h> // IWYU pragma: keep #endif -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include "cmCTestBuildAndTestHandler.h" #include "cmCTestBuildHandler.h" #include "cmCTestConfigureHandler.h" @@ -227,8 +227,8 @@ struct tm* cmCTest::GetNightlyTime(std::string const& str, bool tomorrowtag) char buf[1024]; // add todays year day and month to the time in str because // curl_getdate no longer assumes the day is today - sprintf(buf, "%d%02d%02d %s", lctime->tm_year + 1900, lctime->tm_mon + 1, - lctime->tm_mday, str.c_str()); + snprintf(buf, sizeof(buf), "%d%02d%02d %s", lctime->tm_year + 1900, + lctime->tm_mon + 1, lctime->tm_mday, str.c_str()); cmCTestLog(this, OUTPUT, "Determine Nightly Start Time" << std::endl << " Specified time: " << str @@ -543,9 +543,9 @@ int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) this->Impl->TomorrowTag); } char datestring[100]; - sprintf(datestring, "%04d%02d%02d-%02d%02d", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, lctime->tm_hour, - lctime->tm_min); + snprintf(datestring, sizeof(datestring), "%04d%02d%02d-%02d%02d", + lctime->tm_year + 1900, lctime->tm_mon + 1, lctime->tm_mday, + lctime->tm_hour, lctime->tm_min); tag = datestring; cmsys::ofstream ofs(tagfile.c_str()); if (ofs) { @@ -2327,12 +2327,12 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, { const auto workingDirectory = cmSystemTools::GetCurrentWorkingDirectory(); - cmCMakePresetsFile settingsFile; + cmCMakePresetsGraph settingsFile; auto result = settingsFile.ReadProjectPresets(workingDirectory); - if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { - cmSystemTools::Error(cmStrCat("Could not read presets from ", - workingDirectory, ": ", - cmCMakePresetsFile::ResultToString(result))); + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { + cmSystemTools::Error( + cmStrCat("Could not read presets from ", workingDirectory, ": ", + cmCMakePresetsGraph::ResultToString(result))); return false; } @@ -2422,15 +2422,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, if (expandedPreset->Output->Verbosity) { const auto& verbosity = *expandedPreset->Output->Verbosity; switch (verbosity) { - case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum:: + case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum:: Extra: this->Impl->ExtraVerbose = true; CM_FALLTHROUGH; - case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum:: + case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum:: Verbose: this->Impl->Verbose = true; break; - case cmCMakePresetsFile::TestPreset::OutputOptions::VerbosityEnum:: + case cmCMakePresetsGraph::TestPreset::OutputOptions::VerbosityEnum:: Default: default: // leave default settings @@ -2548,13 +2548,13 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, this->Impl->ShowOnly = true; switch (*expandedPreset->Execution->ShowOnly) { - case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::ShowOnlyEnum:: JsonV1: this->Impl->Quiet = true; this->Impl->OutputAsJson = true; this->Impl->OutputAsJsonVersion = 1; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions::ShowOnlyEnum:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::ShowOnlyEnum:: Human: // intentional fallthrough (human is the default) default: @@ -2565,15 +2565,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, if (expandedPreset->Execution->Repeat) { this->Impl->RepeatCount = expandedPreset->Execution->Repeat->Count; switch (expandedPreset->Execution->Repeat->Mode) { - case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions:: ModeEnum::UntilFail: this->Impl->RepeatMode = cmCTest::Repeat::UntilFail; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions:: ModeEnum::UntilPass: this->Impl->RepeatMode = cmCTest::Repeat::UntilPass; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions::RepeatOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions::RepeatOptions:: ModeEnum::AfterTimeout: this->Impl->RepeatMode = cmCTest::Repeat::AfterTimeout; break; @@ -2599,15 +2599,15 @@ bool cmCTest::SetArgsFromPreset(const std::string& presetName, if (expandedPreset->Execution->NoTestsAction) { switch (*expandedPreset->Execution->NoTestsAction) { - case cmCMakePresetsFile::TestPreset::ExecutionOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions:: NoTestsActionEnum::Error: this->Impl->NoTestsMode = cmCTest::NoTests::Error; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions:: NoTestsActionEnum::Ignore: this->Impl->NoTestsMode = cmCTest::NoTests::Ignore; break; - case cmCMakePresetsFile::TestPreset::ExecutionOptions:: + case cmCMakePresetsGraph::TestPreset::ExecutionOptions:: NoTestsActionEnum::Default: break; default: @@ -2967,8 +2967,9 @@ void cmCTest::SetStopTime(std::string const& time_str) tzone_offset *= 100; char buf[1024]; - sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900, - lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(), tzone_offset); + snprintf(buf, sizeof(buf), "%d%02d%02d %s %+05i", lctime->tm_year + 1900, + lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(), + tzone_offset); time_t stop_time = curl_getdate(buf, ¤t_time); if (stop_time == -1) { diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 8d5ce7e..129ef4b 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -101,7 +101,8 @@ void cmCommonTargetGenerator::AppendFortranFormatFlags( } void cmCommonTargetGenerator::AppendFortranPreprocessFlags( - std::string& flags, cmSourceFile const& source) + std::string& flags, cmSourceFile const& source, + PreprocessFlagsRequired requires_pp) { const std::string srcpp = source.GetSafeProperty("Fortran_PREPROCESS"); cmOutputConverter::FortranPreprocess preprocess = @@ -114,7 +115,9 @@ void cmCommonTargetGenerator::AppendFortranPreprocessFlags( const char* var = nullptr; switch (preprocess) { case cmOutputConverter::FortranPreprocess::Needed: - var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON"; + if (requires_pp == PreprocessFlagsRequired::YES) { + var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON"; + } break; case cmOutputConverter::FortranPreprocess::NotNeeded: var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF"; diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index baa36c9..5aba1c6 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -46,8 +46,14 @@ protected: void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); - void AppendFortranPreprocessFlags(std::string& flags, - cmSourceFile const& source); + enum class PreprocessFlagsRequired + { + YES, + NO + }; + void AppendFortranPreprocessFlags( + std::string& flags, cmSourceFile const& source, + PreprocessFlagsRequired requires_pp = PreprocessFlagsRequired::YES); virtual void AddIncludeFlags(std::string& flags, std::string const& lang, const std::string& config) = 0; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 831a81f..2ff91fe 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -722,7 +722,7 @@ void cmComputeLinkInformation::AddItem(BT<std::string> const& item, this->AddFrameworkItem(item.Value); } else if (cmSystemTools::FileIsDirectory(item.Value)) { // This is a directory. - this->DropDirectoryItem(item.Value); + this->DropDirectoryItem(item); } else { // Use the full path given to the library file. this->Depends.push_back(item.Value); @@ -1349,16 +1349,17 @@ void cmComputeLinkInformation::AddFrameworkItem(std::string const& item) } } -void cmComputeLinkInformation::DropDirectoryItem(std::string const& item) +void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item) { // A full path to a directory was found as a link item. Warn the // user. - std::ostringstream e; - e << "WARNING: Target \"" << this->Target->GetName() - << "\" requests linking to directory \"" << item << "\". " - << "Targets may link only to libraries. " - << "CMake is dropping the item."; - cmSystemTools::Message(e.str()); + this->CMakeInstance->IssueMessage( + MessageType::WARNING, + cmStrCat( + "Target \"", this->Target->GetName(), + "\" requests linking to directory \"", item.Value, + "\". Targets may link only to libraries. CMake is dropping the item."), + item.Backtrace); } void cmComputeLinkInformation::ComputeFrameworkInfo() diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 90a699e..0315540 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -187,7 +187,7 @@ private: bool CheckImplicitDirItem(std::string const& item); void AddUserItem(BT<std::string> const& item, bool pathNotKnown); void AddFrameworkItem(std::string const& item); - void DropDirectoryItem(std::string const& item); + void DropDirectoryItem(BT<std::string> const& item); bool CheckSharedLibNoSOName(std::string const& item); void AddSharedLibNoSOName(std::string const& item); void HandleBadFullItem(std::string const& item, std::string const& file); diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 971c86e..84fa897 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -699,7 +699,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, /* Use a random file name to avoid rapid creation and deletion of the same executable name (some filesystems fail on that). */ - sprintf(targetNameBuf, "cmTC_%05x", cmSystemTools::RandomSeed() & 0xFFFFF); + snprintf(targetNameBuf, sizeof(targetNameBuf), "cmTC_%05x", + cmSystemTools::RandomSeed() & 0xFFFFF); targetName = targetNameBuf; if (!targets.empty()) { diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index ec60ff7..68c65bb 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -2,32 +2,24 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCustomCommand.h" +#include <cassert> #include <utility> #include <cmext/algorithm> -cmCustomCommand::cmCustomCommand(std::vector<std::string> outputs, - std::vector<std::string> byproducts, - std::vector<std::string> depends, - cmCustomCommandLines commandLines, - cmListFileBacktrace lfbt, const char* comment, - const char* workingDirectory, - bool stdPipesUTF8) - : Outputs(std::move(outputs)) - , Byproducts(std::move(byproducts)) - , Depends(std::move(depends)) - , CommandLines(std::move(commandLines)) - , Backtrace(std::move(lfbt)) - , Comment(comment ? comment : "") - , WorkingDirectory(workingDirectory ? workingDirectory : "") - , HaveComment(comment != nullptr) - , StdPipesUTF8(stdPipesUTF8) +const std::vector<std::string>& cmCustomCommand::GetOutputs() const { + return this->Outputs; } -const std::vector<std::string>& cmCustomCommand::GetOutputs() const +void cmCustomCommand::SetOutputs(std::vector<std::string> outputs) { - return this->Outputs; + this->Outputs = std::move(outputs); +} + +void cmCustomCommand::SetOutputs(std::string output) +{ + this->Outputs = { std::move(output) }; } const std::vector<std::string>& cmCustomCommand::GetByproducts() const @@ -35,22 +27,66 @@ const std::vector<std::string>& cmCustomCommand::GetByproducts() const return this->Byproducts; } +void cmCustomCommand::SetByproducts(std::vector<std::string> byproducts) +{ + this->Byproducts = std::move(byproducts); +} + const std::vector<std::string>& cmCustomCommand::GetDepends() const { return this->Depends; } +void cmCustomCommand::SetDepends(std::vector<std::string> depends) +{ + if (this->HasMainDependency_) { + depends.insert(depends.begin(), std::move(this->Depends[0])); + } + + Depends = std::move(depends); +} + +const std::string& cmCustomCommand::GetMainDependency() const +{ + assert(this->HasMainDependency_); + return this->Depends[0]; +} + +void cmCustomCommand::SetMainDependency(std::string main_dependency) +{ + if (this->HasMainDependency_) { + assert(!main_dependency.empty()); + this->Depends[0] = std::move(main_dependency); + } else if (main_dependency.empty()) { + // Do nothing. + } else { + this->Depends.insert(this->Depends.begin(), std::move(main_dependency)); + this->HasMainDependency_ = true; + } +} + const cmCustomCommandLines& cmCustomCommand::GetCommandLines() const { return this->CommandLines; } +void cmCustomCommand::SetCommandLines(cmCustomCommandLines commandLines) +{ + this->CommandLines = std::move(commandLines); +} + const char* cmCustomCommand::GetComment() const { const char* no_comment = nullptr; return this->HaveComment ? this->Comment.c_str() : no_comment; } +void cmCustomCommand::SetComment(const char* comment) +{ + this->Comment = comment ? comment : ""; + this->HaveComment = (comment != nullptr); +} + void cmCustomCommand::AppendCommands(const cmCustomCommandLines& commandLines) { cm::append(this->CommandLines, commandLines); @@ -86,6 +122,11 @@ cmListFileBacktrace const& cmCustomCommand::GetBacktrace() const return this->Backtrace; } +void cmCustomCommand::SetBacktrace(cmListFileBacktrace lfbt) +{ + this->Backtrace = std::move(lfbt); +} + cmImplicitDependsList const& cmCustomCommand::GetImplicitDepends() const { return this->ImplicitDepends; diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 5cbd3d1..5533847 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -25,22 +25,22 @@ class cmImplicitDependsList class cmCustomCommand { public: - /** Main constructor specifies all information for the command. */ - cmCustomCommand(std::vector<std::string> outputs, - std::vector<std::string> byproducts, - std::vector<std::string> depends, - cmCustomCommandLines commandLines, cmListFileBacktrace lfbt, - const char* comment, const char* workingDirectory, - bool stdPipesUTF8); - /** Get the output file produced by the command. */ const std::vector<std::string>& GetOutputs() const; + void SetOutputs(std::vector<std::string> outputs); + void SetOutputs(std::string output); /** Get the extra files produced by the command. */ const std::vector<std::string>& GetByproducts() const; + void SetByproducts(std::vector<std::string> byproducts); /** Get the vector that holds the list of dependencies. */ const std::vector<std::string>& GetDepends() const; + void SetDepends(std::vector<std::string> depends); + + bool HasMainDependency() const { return this->HasMainDependency_; } + const std::string& GetMainDependency() const; + void SetMainDependency(std::string main_dependency); /** Get the working directory. */ std::string const& GetWorkingDirectory() const @@ -48,14 +48,25 @@ public: return this->WorkingDirectory; } + void SetWorkingDirectory(const char* workingDirectory) + { + this->WorkingDirectory = (workingDirectory ? workingDirectory : ""); + } + /** Get the list of command lines. */ const cmCustomCommandLines& GetCommandLines() const; + void SetCommandLines(cmCustomCommandLines commandLines); /** Get the comment string for the command. */ const char* GetComment() const; + void SetComment(const char* comment); /** Get a value indicating if the command uses UTF-8 output pipes. */ bool GetStdPipesUTF8() const { return this->StdPipesUTF8; } + void SetStdPipesUTF8(bool stdPipesUTF8) + { + this->StdPipesUTF8 = stdPipesUTF8; + } /** Append to the list of command lines. */ void AppendCommands(const cmCustomCommandLines& commandLines); @@ -74,6 +85,7 @@ public: /** Backtrace of the command that created this custom command. */ cmListFileBacktrace const& GetBacktrace() const; + void SetBacktrace(cmListFileBacktrace lfbt); void SetImplicitDepends(cmImplicitDependsList const&); void AppendImplicitDepends(cmImplicitDependsList const&); @@ -122,5 +134,6 @@ private: bool UsesTerminal = false; bool CommandExpandLists = false; bool StdPipesUTF8 = false; + bool HasMainDependency_ = false; cmPolicies::PolicyStatus CMP0116Status = cmPolicies::WARN; }; diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index fd0a63c..41d4442 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -346,7 +346,7 @@ std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const return this->CommandLines[c][0]; } -std::string escapeForShellOldStyle(const std::string& str) +static std::string escapeForShellOldStyle(const std::string& str) { std::string result; #if defined(_WIN32) && !defined(__CYGWIN__) diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx index 4e2d9b0..7a2f34f 100644 --- a/Source/cmDefinePropertyCommand.cxx +++ b/Source/cmDefinePropertyCommand.cxx @@ -2,9 +2,16 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmDefinePropertyCommand.h" +#include <algorithm> +#include <iterator> + +#include <cmext/string_view> + +#include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" #include "cmProperty.h" +#include "cmRange.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -44,37 +51,23 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args, // Parse remaining arguments. bool inherited = false; std::string PropertyName; - std::string BriefDocs; - std::string FullDocs; - enum Doing - { - DoingNone, - DoingProperty, - DoingBrief, - DoingFull - }; - Doing doing = DoingNone; - for (unsigned int i = 1; i < args.size(); ++i) { - if (args[i] == "PROPERTY") { - doing = DoingProperty; - } else if (args[i] == "BRIEF_DOCS") { - doing = DoingBrief; - } else if (args[i] == "FULL_DOCS") { - doing = DoingFull; - } else if (args[i] == "INHERITED") { - doing = DoingNone; - inherited = true; - } else if (doing == DoingProperty) { - doing = DoingNone; - PropertyName = args[i]; - } else if (doing == DoingBrief) { - BriefDocs += args[i]; - } else if (doing == DoingFull) { - FullDocs += args[i]; - } else { - status.SetError(cmStrCat("given invalid argument \"", args[i], "\".")); - return false; - } + std::vector<std::string> BriefDocs; + std::vector<std::string> FullDocs; + std::string initializeFromVariable; + + cmArgumentParser<void> parser; + parser.Bind("PROPERTY"_s, PropertyName); + parser.Bind("BRIEF_DOCS"_s, BriefDocs); + parser.Bind("FULL_DOCS"_s, FullDocs); + parser.Bind("INHERITED"_s, inherited); + parser.Bind("INITIALIZE_FROM_VARIABLE"_s, initializeFromVariable); + std::vector<std::string> invalidArgs; + + parser.Parse(cmMakeRange(args).advance(1), &invalidArgs); + if (!invalidArgs.empty()) { + status.SetError( + cmStrCat("given invalid argument \"", invalidArgs.front(), "\".")); + return false; } // Make sure a property name was found. @@ -83,19 +76,47 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args, return false; } - // Make sure documentation was given. - if (BriefDocs.empty()) { - status.SetError("not given a BRIEF_DOCS <brief-doc> argument."); - return false; + if (!initializeFromVariable.empty()) { + // Make sure property scope is TARGET. + if (scope != cmProperty::TARGET) { + status.SetError( + "Scope must be TARGET if INITIALIZE_FROM_VARIABLE is specified"); + return false; + } + + // Make sure the variable has the property name as a suffix. + if (!cmHasSuffix(initializeFromVariable, PropertyName)) { + status.SetError(cmStrCat("Variable name \"", initializeFromVariable, + "\" does not end with property name \"", + PropertyName, "\"")); + return false; + } + if (initializeFromVariable == PropertyName) { + status.SetError(cmStrCat( + "Variable name must have a non-empty prefix before property name \"", + PropertyName, "\"")); + return false; + } } - if (FullDocs.empty()) { - status.SetError("not given a FULL_DOCS <full-doc> argument."); + + // Make sure the variable is not reserved. + static constexpr const char* reservedPrefixes[] = { + "CMAKE_", + "_CMAKE_", + }; + if (std::any_of(std::begin(reservedPrefixes), std::end(reservedPrefixes), + [&initializeFromVariable](const char* prefix) { + return cmHasPrefix(initializeFromVariable, prefix); + })) { + status.SetError( + cmStrCat("variable name \"", initializeFromVariable, "\" is reserved")); return false; } // Actually define the property. status.GetMakefile().GetState()->DefineProperty( - PropertyName, scope, BriefDocs, FullDocs, inherited); + PropertyName, scope, cmJoin(BriefDocs, ""), cmJoin(FullDocs, ""), + inherited, initializeFromVariable); return true; } diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx index bf599ff..0cc4946 100644 --- a/Source/cmDependsCompiler.cxx +++ b/Source/cmDependsCompiler.cxx @@ -4,6 +4,7 @@ #include "cmDependsCompiler.h" #include <algorithm> +#include <iterator> #include <map> #include <memory> #include <string> @@ -111,9 +112,13 @@ bool cmDependsCompiler::CheckDependencies( // 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; + auto& rule_deps = dependencies[entry.rules[index]]; + rule_deps.insert(rule_deps.end(), depends.cbegin(), + depends.cend()); } - dependencies[entry.rules.front()] = std::move(depends); + auto& rule_deps = dependencies[entry.rules.front()]; + std::move(depends.cbegin(), depends.cend(), + std::back_inserter(rule_deps)); } } else { if (format == "msvc"_s) { diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 1678ce8..66f1733 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -26,17 +26,14 @@ template <size_t s> struct cmELFByteSwapSize { }; -void cmELFByteSwap(char* /*unused*/, cmELFByteSwapSize<1> /*unused*/) -{ -} -void cmELFByteSwap(char* data, cmELFByteSwapSize<2> /*unused*/) +static void cmELFByteSwap(char* data, cmELFByteSwapSize<2> /*unused*/) { char one_byte; one_byte = data[0]; data[0] = data[1]; data[1] = one_byte; } -void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/) +static void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/) { char one_byte; one_byte = data[0]; @@ -46,7 +43,7 @@ void cmELFByteSwap(char* data, cmELFByteSwapSize<4> /*unused*/) data[1] = data[2]; data[2] = one_byte; } -void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/) +static void cmELFByteSwap(char* data, cmELFByteSwapSize<8> /*unused*/) { char one_byte; one_byte = data[0]; diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx index 51fb219..e069b77 100644 --- a/Source/cmExecProgramCommand.cxx +++ b/Source/cmExecProgramCommand.cxx @@ -114,7 +114,7 @@ bool cmExecProgramCommand(std::vector<std::string> const& args, if (!return_variable.empty()) { char buffer[100]; - sprintf(buffer, "%d", retVal); + snprintf(buffer, sizeof(buffer), "%d", retVal); status.GetMakefile().AddDefinition(return_variable, buffer); } diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index ffcc415..3b990cc 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -318,7 +318,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, case cmsysProcess_State_Exited: { int v = cmsysProcess_GetExitValue(cp); char buf[16]; - sprintf(buf, "%d", v); + snprintf(buf, sizeof(buf), "%d", v); status.GetMakefile().AddDefinition(arguments.ResultVariable, buf); } break; case cmsysProcess_State_Exception: @@ -346,7 +346,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args, int exitCode = cmsysProcess_GetExitValueByIndex(cp, static_cast<int>(i)); char buf[16]; - sprintf(buf, "%d", exitCode); + snprintf(buf, sizeof(buf), "%d", exitCode); res.emplace_back(buf); } break; case kwsysProcess_StateByIndex_Exception: diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 3641cb2..bcd8c64 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -106,7 +106,8 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( std::string sharedLibs; std::string ldlibs; cmLinkInterfaceLibraries const* linkIFace = - target->GetLinkInterfaceLibraries(config, target, false); + target->GetLinkInterfaceLibraries( + config, target, cmGeneratorTarget::LinkInterfaceFor::Link); for (cmLinkItem const& item : linkIFace->Libraries) { cmGeneratorTarget const* gt = item.Target; std::string const& lib = item.AsStr(); diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index aa968dc..a47f1e5 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -11,12 +11,15 @@ #include <cmext/algorithm> #include "cmExportSet.h" +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -135,6 +138,8 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateCompatibleInterfaceProperties(gte, properties); this->GenerateInterfaceProperties(gte, os, properties); + + this->GenerateTargetFileSets(gte, os); } // Generate import file content for each configuration. @@ -356,3 +361,17 @@ std::string cmExportBuildFileGenerator::InstallNameDir( return install_name_dir; } + +std::string cmExportBuildFileGenerator::GetFileSetDirectories( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetDirectoryEntries(), ";")); +} + +std::string cmExportBuildFileGenerator::GetFileSetFiles( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetFileEntries(), ";")); +} diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 244f526..a7985c7 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -15,9 +15,11 @@ #include "cmStateTypes.h" class cmExportSet; +class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmLocalGenerator; +class cmTargetExport; /** \class cmExportBuildFileGenerator * \brief Generate a file exporting targets from a build tree. @@ -76,6 +78,11 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; + std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + std::pair<std::vector<std::string>, std::string> FindBuildExportInfo( cmGlobalGenerator* gg, const std::string& name); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 8b0f64e..b46b933 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportFileGenerator.h" +#include <array> #include <cassert> #include <cstring> #include <sstream> @@ -12,6 +13,7 @@ #include "cmsys/FStream.hxx" #include "cmComputeLinkInformation.h" +#include "cmFileSet.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -174,18 +176,24 @@ bool cmExportFileGenerator::PopulateInterfaceLinkLibrariesProperty( if (!target->IsLinkable()) { return false; } - cmValue input = target->GetProperty("INTERFACE_LINK_LIBRARIES"); - if (input) { - std::string prepro = - cmGeneratorExpression::Preprocess(*input, preprocessRule); - if (!prepro.empty()) { - this->ResolveTargetsInGeneratorExpressions( - prepro, target, missingTargets, ReplaceFreeTargets); - properties["INTERFACE_LINK_LIBRARIES"] = prepro; - return true; + static const std::array<std::string, 3> linkIfaceProps = { + { "INTERFACE_LINK_LIBRARIES", "INTERFACE_LINK_LIBRARIES_DIRECT", + "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE" } + }; + bool hadINTERFACE_LINK_LIBRARIES = false; + for (std::string const& linkIfaceProp : linkIfaceProps) { + if (cmValue input = target->GetProperty(linkIfaceProp)) { + std::string prepro = + cmGeneratorExpression::Preprocess(*input, preprocessRule); + if (!prepro.empty()) { + this->ResolveTargetsInGeneratorExpressions( + prepro, target, missingTargets, ReplaceFreeTargets); + properties[linkIfaceProp] = prepro; + hadINTERFACE_LINK_LIBRARIES = true; + } } } - return false; + return hadINTERFACE_LINK_LIBRARIES; } static bool isSubDirectory(std::string const& a, std::string const& b) @@ -495,8 +503,9 @@ void cmExportFileGenerator::PopulateInterfaceProperty( properties, missingTargets); } -void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop, - std::set<std::string>& ifaceProperties) +static void getPropertyContents(cmGeneratorTarget const* tgt, + const std::string& prop, + std::set<std::string>& ifaceProperties) { cmValue p = tgt->GetProperty(prop); if (!p) { @@ -506,9 +515,9 @@ void getPropertyContents(cmGeneratorTarget const* tgt, const std::string& prop, ifaceProperties.insert(content.begin(), content.end()); } -void getCompatibleInterfaceProperties(cmGeneratorTarget const* target, - std::set<std::string>& ifaceProperties, - const std::string& config) +static void getCompatibleInterfaceProperties( + cmGeneratorTarget const* target, std::set<std::string>& ifaceProperties, + const std::string& config) { if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { // object libraries have no link information, so nothing to compute @@ -925,13 +934,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.20 (this upper limit may be reviewed + // policy settings for up to CMake 3.21 (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.20)\n"; + << "cmake_policy(VERSION 2.6...3.21)\n"; /* clang-format on */ } @@ -1073,6 +1082,12 @@ void cmExportFileGenerator::GenerateImportTargetCode( os << "set_property(TARGET " << targetName << " PROPERTY DEPRECATION " << cmExportFileGeneratorEscape(target->GetDeprecation()) << ")\n"; } + + if (target->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) { + os << "set_property(TARGET " << targetName + << " PROPERTY IMPORTED_NO_SYSTEM 1)\n"; + } + os << "\n"; } @@ -1250,3 +1265,38 @@ bool cmExportFileGenerator::PopulateExportProperties( } return true; } + +void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte, + std::ostream& os, + cmTargetExport* te) +{ + auto interfaceFileSets = gte->Target->GetAllInterfaceFileSets(); + if (!interfaceFileSets.empty()) { + std::string targetName = cmStrCat(this->Namespace, gte->GetExportName()); + os << "if(NOT CMAKE_VERSION VERSION_LESS \"3.23.0\")\n" + " target_sources(" + << targetName << "\n"; + + for (auto const& name : interfaceFileSets) { + auto* fileSet = gte->Target->GetFileSet(name); + if (!fileSet) { + gte->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("File set \"", name, + "\" is listed in interface file sets of ", gte->GetName(), + " but has not been created")); + return; + } + + os << " INTERFACE" + << "\n FILE_SET " << cmOutputConverter::EscapeForCMake(name) + << "\n TYPE " + << cmOutputConverter::EscapeForCMake(fileSet->GetType()) + << "\n BASE_DIRS " + << this->GetFileSetDirectories(gte, fileSet, te) << "\n FILES " + << this->GetFileSetFiles(gte, fileSet, te) << "\n"; + } + + os << " )\nendif()\n\n"; + } +} diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 29a6a98..d50f7e8 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -15,6 +15,7 @@ #include "cmVersion.h" #include "cmVersionConfig.h" +class cmFileSet; class cmGeneratorTarget; class cmTargetExport; @@ -186,6 +187,16 @@ protected: ImportPropertyMap& properties, std::string& errorMessage); + void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, + cmTargetExport* te = nullptr); + + virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte, + cmFileSet* fileSet, + cmTargetExport* te) = 0; + virtual std::string GetFileSetFiles(cmGeneratorTarget* gte, + cmFileSet* fileSet, + cmTargetExport* te) = 0; + // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 4a3c565..f232440 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -2,19 +2,23 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExportInstallFileGenerator.h" +#include <algorithm> #include <memory> #include <sstream> #include <utility> #include "cmExportSet.h" +#include "cmFileSet.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallExportGenerator.h" +#include "cmInstallFileSetGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmOutputConverter.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -148,6 +152,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->PopulateCompatibleInterfaceProperties(gt, properties); this->GenerateInterfaceProperties(gt, os, properties); + + this->GenerateTargetFileSets(gt, os, te); } if (require3_1_0) { @@ -535,3 +541,102 @@ std::string cmExportInstallFileGenerator::InstallNameDir( return install_name_dir; } + +namespace { +bool EntryIsContextSensitive( + const std::unique_ptr<cmCompiledGeneratorExpression>& cge) +{ + return cge->GetHadContextSensitiveCondition(); +} +} + +std::string cmExportInstallFileGenerator::GetFileSetDirectories( + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) +{ + std::vector<std::string> resultVector; + + auto configs = + gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + cmGeneratorExpression ge; + auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); + + for (auto const& config : configs) { + auto dest = cmStrCat("${_IMPORT_PREFIX}/", + cmOutputConverter::EscapeForCMake( + cge->Evaluate(gte->LocalGenerator, config, gte), + cmOutputConverter::WrapQuotes::NoWrap)); + + if (cge->GetHadContextSensitiveCondition() && configs.size() != 1) { + resultVector.push_back( + cmStrCat("\"$<$<CONFIG:", config, ">:", dest, ">\"")); + } else { + resultVector.push_back(cmStrCat('"', dest, '"')); + break; + } + } + + return cmJoin(resultVector, " "); +} + +std::string cmExportInstallFileGenerator::GetFileSetFiles( + cmGeneratorTarget* gte, cmFileSet* fileSet, cmTargetExport* te) +{ + std::vector<std::string> resultVector; + + auto configs = + gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + auto fileEntries = fileSet->CompileFileEntries(); + auto directoryEntries = fileSet->CompileDirectoryEntries(); + + cmGeneratorExpression destGe; + auto destCge = + destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); + + for (auto const& config : configs) { + auto directories = fileSet->EvaluateDirectoryEntries( + directoryEntries, gte->LocalGenerator, config, gte); + + std::map<std::string, std::vector<std::string>> files; + for (auto const& entry : fileEntries) { + fileSet->EvaluateFileEntry(directories, files, entry, + gte->LocalGenerator, config, gte); + } + auto dest = cmStrCat("${_IMPORT_PREFIX}/", + cmOutputConverter::EscapeForCMake( + destCge->Evaluate(gte->LocalGenerator, config, gte), + cmOutputConverter::WrapQuotes::NoWrap), + '/'); + + bool const contextSensitive = destCge->GetHadContextSensitiveCondition() || + std::any_of(directoryEntries.begin(), directoryEntries.end(), + EntryIsContextSensitive) || + std::any_of(fileEntries.begin(), fileEntries.end(), + EntryIsContextSensitive); + + for (auto const& it : files) { + auto prefix = it.first.empty() ? "" : cmStrCat(it.first, '/'); + for (auto const& filename : it.second) { + auto relFile = + cmStrCat(prefix, cmSystemTools::GetFilenameName(filename)); + auto escapedFile = + cmStrCat(dest, + cmOutputConverter::EscapeForCMake( + relFile, cmOutputConverter::WrapQuotes::NoWrap)); + if (contextSensitive && configs.size() != 1) { + resultVector.push_back( + cmStrCat("\"$<$<CONFIG:", config, ">:", escapedFile, ">\"")); + } else { + resultVector.push_back(cmStrCat('"', escapedFile, '"')); + } + } + } + + if (!(contextSensitive && configs.size() != 1)) { + break; + } + } + + return cmJoin(resultVector, " "); +} diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 5cec2e0..9374c6b 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -14,6 +14,7 @@ #include "cmExportFileGenerator.h" #include "cmStateTypes.h" +class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmInstallExportGenerator; @@ -97,6 +98,11 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; + std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + std::string GetFileSetFiles(cmGeneratorTarget* gte, cmFileSet* fileSet, + cmTargetExport* te) override; + cmInstallExportGenerator* IEGen; // The import file generated for each configuration. diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index cbe3c4d..e98aa05 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -7,17 +7,22 @@ #include <cm/memory> +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmOutputConverter.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" #include "cmValue.h" +class cmTargetExport; + cmExportTryCompileFileGenerator::cmExportTryCompileFileGenerator( cmGlobalGenerator* gg, const std::vector<std::string>& targets, cmMakefile* mf, std::set<std::string> const& langs) @@ -102,10 +107,18 @@ void cmExportTryCompileFileGenerator::PopulateProperties( const cmGeneratorTarget* target, ImportPropertyMap& properties, std::set<cmGeneratorTarget const*>& emitted) { + // Look through all non-special properties. std::vector<std::string> props = target->GetPropertyKeys(); + // Include special properties that might be relevant here. + props.emplace_back("INTERFACE_LINK_LIBRARIES"); + props.emplace_back("INTERFACE_LINK_LIBRARIES_DIRECT"); + props.emplace_back("INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"); for (std::string const& p : props) { - - properties[p] = *target->GetProperty(p); + cmValue v = target->GetProperty(p); + if (!v) { + continue; + } + properties[p] = *v; if (cmHasLiteralPrefix(p, "IMPORTED_LINK_INTERFACE_LIBRARIES") || cmHasLiteralPrefix(p, "IMPORTED_LINK_DEPENDENT_LIBRARIES") || @@ -137,3 +150,17 @@ std::string cmExportTryCompileFileGenerator::InstallNameDir( return install_name_dir; } + +std::string cmExportTryCompileFileGenerator::GetFileSetDirectories( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetDirectoryEntries(), ";")); +} + +std::string cmExportTryCompileFileGenerator::GetFileSetFiles( + cmGeneratorTarget* /*gte*/, cmFileSet* fileSet, cmTargetExport* /*te*/) +{ + return cmOutputConverter::EscapeForCMake( + cmJoin(fileSet->GetFileEntries(), ";")); +} diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 127b8df..8a1fd7e 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -11,9 +11,11 @@ #include "cmExportFileGenerator.h" +class cmFileSet; class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; +class cmTargetExport; class cmExportTryCompileFileGenerator : public cmExportFileGenerator { @@ -48,6 +50,13 @@ protected: std::string InstallNameDir(cmGeneratorTarget const* target, const std::string& config) override; + std::string GetFileSetDirectories(cmGeneratorTarget* target, + cmFileSet* fileSet, + cmTargetExport* te) override; + + std::string GetFileSetFiles(cmGeneratorTarget* target, cmFileSet* fileSet, + cmTargetExport* te) override; + private: std::string FindTargets(const std::string& prop, const cmGeneratorTarget* tgt, diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index e2c54d7..988c5c3 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -677,6 +677,12 @@ std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) } else { compiler = "pgi"; // does not exist as default in CodeBlocks 16.01 } + } else if (compilerId == "LCC") { + if (pureFortran) { + compiler = "lfortran"; + } else { + compiler = "lcc"; + } } else if (compilerId == "GNU") { if (pureFortran) { compiler = "gfortran"; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index fa93b04..19e87d5 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -435,8 +435,7 @@ std::string cmExtraSublimeTextGenerator::ComputeIncludes( lg->GetIncludeDirectories(includes, target, language, config); std::string includesString = - lg->GetIncludeFlags(includes, target, language, config, false, - cmLocalGenerator::IncludePathStyle::Absolute); + lg->GetIncludeFlags(includes, target, language, config, false); return includesString; } diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx index 77d5795..80c069f 100644 --- a/Source/cmFLTKWrapUICommand.cxx +++ b/Source/cmFLTKWrapUICommand.cxx @@ -3,14 +3,17 @@ #include "cmFLTKWrapUICommand.h" #include <cstddef> +#include <utility> +#include <cm/memory> + +#include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" -#include "cmPolicies.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" @@ -95,15 +98,17 @@ bool cmFLTKWrapUICommand(std::vector<std::string> const& args, }); // Add command for generating the .h and .cxx files - std::string no_main_dependency; - const char* no_comment = nullptr; - const char* no_working_dir = nullptr; - mf.AddCustomCommandToOutput(cxxres, depends, no_main_dependency, - commandLines, no_comment, no_working_dir, - mf.GetPolicyStatus(cmPolicies::CMP0116)); - mf.AddCustomCommandToOutput(hname, depends, no_main_dependency, - commandLines, no_comment, no_working_dir, - mf.GetPolicyStatus(cmPolicies::CMP0116)); + + auto hcc = cm::make_unique<cmCustomCommand>(); + hcc->SetDepends(depends); + hcc->SetCommandLines(commandLines); + auto ccc = cm::make_unique<cmCustomCommand>(*hcc); + + hcc->SetOutputs(cxxres); + mf.AddCustomCommandToOutput(std::move(hcc)); + + ccc->SetOutputs(hname); + mf.AddCustomCommandToOutput(std::move(ccc)); cmSourceFile* sf = mf.GetSource(cxxres); sf->AddDepend(hname); diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index d529f52..c1df992 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -686,7 +686,8 @@ std::string cmFileAPI::NoSupportedVersion( // The "codemodel" object kind. -static unsigned int const CodeModelV2Minor = 3; +// Update Help/manual/cmake-file-api.7.rst when updating this constant. +static unsigned int const CodeModelV2Minor = 4; void cmFileAPI::BuildClientRequestCodeModel( ClientRequest& r, std::vector<RequestVersion> const& versions) diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 147181e..40e1d2e 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -23,11 +23,13 @@ #include "cmCryptoHash.h" #include "cmExportSet.h" #include "cmFileAPI.h" +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallDirectoryGenerator.h" #include "cmInstallExportGenerator.h" +#include "cmInstallFileSetGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" #include "cmInstallGetRuntimeDependenciesGenerator.h" @@ -1043,6 +1045,53 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen) installer["runtimeDependencySetType"] = "library"; break; } + } else if (auto* installFileSet = + dynamic_cast<cmInstallFileSetGenerator*>(gen)) { + installer["type"] = "fileSet"; + installer["destination"] = installFileSet->GetDestination(this->Config); + + auto* fileSet = installFileSet->GetFileSet(); + auto* target = installFileSet->GetTarget(); + + auto dirCges = fileSet->CompileDirectoryEntries(); + auto dirs = fileSet->EvaluateDirectoryEntries( + dirCges, target->GetLocalGenerator(), this->Config, target); + + auto entryCges = fileSet->CompileFileEntries(); + std::map<std::string, std::vector<std::string>> entries; + for (auto const& entryCge : entryCges) { + fileSet->EvaluateFileEntry(dirs, entries, entryCge, + target->GetLocalGenerator(), this->Config, + target); + } + + Json::Value files = Json::arrayValue; + for (auto const& it : entries) { + auto dir = it.first; + if (!dir.empty()) { + dir += '/'; + } + for (auto const& file : it.second) { + files.append(this->DumpInstallerPath( + this->TopSource, file, + cmStrCat(dir, cmSystemTools::GetFilenameName(file)))); + } + } + installer["paths"] = std::move(files); + installer["fileSetName"] = fileSet->GetName(); + installer["fileSetType"] = fileSet->GetType(); + installer["fileSetDirectories"] = Json::arrayValue; + for (auto const& dir : dirs) { + installer["fileSetDirectories"].append( + RelativeIfUnder(this->TopSource, dir)); + } + installer["fileSetTarget"] = Json::objectValue; + installer["fileSetTarget"]["id"] = TargetId(target, this->TopBuild); + installer["fileSetTarget"]["index"] = this->TargetIndexMap[target]; + + if (installFileSet->GetOptional()) { + installer["isOptional"] = true; + } } // Add fields common to all install generators. diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx index b3540c9..fe2972f 100644 --- a/Source/cmFileAPIToolchains.cxx +++ b/Source/cmFileAPIToolchains.cxx @@ -30,10 +30,6 @@ class Toolchains cmFileAPI& FileAPI; unsigned long Version; - static const std::vector<ToolchainVariable> CompilerVariables; - static const std::vector<ToolchainVariable> CompilerImplicitVariables; - static const ToolchainVariable SourceFileExtensionsVariable; - Json::Value DumpToolchains(); Json::Value DumpToolchain(std::string const& lang); Json::Value DumpToolchainVariables( @@ -48,24 +44,6 @@ public: Json::Value Dump(); }; -const std::vector<ToolchainVariable> Toolchains::CompilerVariables{ - { "path", "COMPILER", false }, - { "id", "COMPILER_ID", false }, - { "version", "COMPILER_VERSION", false }, - { "target", "COMPILER_TARGET", false }, -}; - -const std::vector<ToolchainVariable> Toolchains::CompilerImplicitVariables{ - { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true }, - { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true }, - { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true }, - { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true }, -}; - -const ToolchainVariable Toolchains::SourceFileExtensionsVariable{ - "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true -}; - Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned long version) : FileAPI(fileAPI) , Version(version) @@ -94,6 +72,25 @@ Json::Value Toolchains::DumpToolchains() Json::Value Toolchains::DumpToolchain(std::string const& lang) { + static const std::vector<ToolchainVariable> CompilerVariables{ + { "path", "COMPILER", false }, + { "id", "COMPILER_ID", false }, + { "version", "COMPILER_VERSION", false }, + { "target", "COMPILER_TARGET", false }, + }; + + static const std::vector<ToolchainVariable> CompilerImplicitVariables{ + { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true }, + { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true }, + { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", + true }, + { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true }, + }; + + static const ToolchainVariable SourceFileExtensionsVariable{ + "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true + }; + const auto& mf = this->FileAPI.GetCMakeInstance()->GetGlobalGenerator()->GetMakefiles()[0]; Json::Value toolchain = Json::objectValue; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index c3ae228..da2f15f 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -197,15 +197,15 @@ bool HandleReadCommand(std::vector<std::string> const& args, } // is there a limit? - long sizeLimit = -1; + std::string::size_type sizeLimit = std::string::npos; if (!arguments.Limit.empty()) { - sizeLimit = atoi(arguments.Limit.c_str()); + std::istringstream(arguments.Limit) >> sizeLimit; } // is there an offset? - long offset = 0; + cmsys::ifstream::off_type offset = 0; if (!arguments.Offset.empty()) { - offset = atoi(arguments.Offset.c_str()); + std::istringstream(arguments.Offset) >> offset; } file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6 @@ -215,28 +215,21 @@ bool HandleReadCommand(std::vector<std::string> const& args, if (arguments.Hex) { // Convert part of the file into hex code char c; - while ((sizeLimit != 0) && (file.get(c))) { + while ((sizeLimit > 0) && (file.get(c))) { char hex[4]; - sprintf(hex, "%.2x", c & 0xff); + snprintf(hex, sizeof(hex), "%.2x", c & 0xff); output += hex; - if (sizeLimit > 0) { - sizeLimit--; - } + sizeLimit--; } } else { std::string line; bool has_newline = false; while ( - sizeLimit != 0 && + sizeLimit > 0 && cmSystemTools::GetLineFromStream(file, line, &has_newline, sizeLimit)) { - if (sizeLimit > 0) { - sizeLimit = sizeLimit - static_cast<long>(line.size()); - if (has_newline) { - sizeLimit--; - } - if (sizeLimit < 0) { - sizeLimit = 0; - } + sizeLimit = sizeLimit - line.size(); + if (has_newline && sizeLimit > 0) { + sizeLimit--; } output += line; if (has_newline) { @@ -1632,8 +1625,9 @@ size_t cmFileCommandCurlDebugCallback(CURL*, curl_infotype type, char* chPtr, case CURLINFO_SSL_DATA_IN: case CURLINFO_SSL_DATA_OUT: { char buf[128]; - int n = sprintf(buf, "[%" KWIML_INT_PRIu64 " bytes data]\n", - static_cast<KWIML_INT_uint64_t>(size)); + int n = + snprintf(buf, sizeof(buf), "[%" KWIML_INT_PRIu64 " bytes data]\n", + static_cast<KWIML_INT_uint64_t>(size)); if (n > 0) { cm::append(vec, buf, buf + n); } diff --git a/Source/cmFileLockResult.cxx b/Source/cmFileLockResult.cxx index 9d5a6c6..70b8cdb 100644 --- a/Source/cmFileLockResult.cxx +++ b/Source/cmFileLockResult.cxx @@ -5,7 +5,6 @@ #include <cerrno> #include <cstring> -#define WINMSG_BUF_LEN (1024) cmFileLockResult cmFileLockResult::MakeOk() { return { OK, 0 }; @@ -54,6 +53,7 @@ std::string cmFileLockResult::GetOutputMessage() const case SYSTEM: #if defined(_WIN32) { +# define WINMSG_BUF_LEN (1024) char winmsg[WINMSG_BUF_LEN]; DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; if (FormatMessageA(flags, NULL, this->ErrorValue, diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx new file mode 100644 index 0000000..08d56ba --- /dev/null +++ b/Source/cmFileSet.cxx @@ -0,0 +1,151 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFileSet.h" + +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#include "cmGeneratorExpression.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmake.h" + +cmFileSet::cmFileSet(std::string name, std::string type) + : Name(std::move(name)) + , Type(std::move(type)) +{ +} + +void cmFileSet::ClearDirectoryEntries() +{ + this->DirectoryEntries.clear(); +} + +void cmFileSet::AddDirectoryEntry(BT<std::string> directories) +{ + this->DirectoryEntries.push_back(std::move(directories)); +} + +void cmFileSet::ClearFileEntries() +{ + this->FileEntries.clear(); +} + +void cmFileSet::AddFileEntry(BT<std::string> files) +{ + this->FileEntries.push_back(std::move(files)); +} + +std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> +cmFileSet::CompileFileEntries() const +{ + std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result; + + for (auto const& entry : this->FileEntries) { + for (auto const& ex : cmExpandedList(entry.Value)) { + cmGeneratorExpression ge(entry.Backtrace); + auto cge = ge.Parse(ex); + result.push_back(std::move(cge)); + } + } + + return result; +} + +std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> +cmFileSet::CompileDirectoryEntries() const +{ + std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result; + + for (auto const& entry : this->DirectoryEntries) { + for (auto const& ex : cmExpandedList(entry.Value)) { + cmGeneratorExpression ge(entry.Backtrace); + auto cge = ge.Parse(ex); + result.push_back(std::move(cge)); + } + } + + return result; +} + +std::vector<std::string> cmFileSet::EvaluateDirectoryEntries( + const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges, + cmLocalGenerator* lg, const std::string& config, + const cmGeneratorTarget* target, + cmGeneratorExpressionDAGChecker* dagChecker) const +{ + std::vector<std::string> result; + for (auto const& cge : cges) { + auto entry = cge->Evaluate(lg, config, target, dagChecker); + auto dirs = cmExpandedList(entry); + for (std::string dir : dirs) { + if (!cmSystemTools::FileIsFullPath(dir)) { + dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir); + } + auto collapsedDir = cmSystemTools::CollapseFullPath(dir); + for (auto const& priorDir : result) { + auto collapsedPriorDir = cmSystemTools::CollapseFullPath(priorDir); + if (!cmSystemTools::SameFile(collapsedDir, collapsedPriorDir) && + (cmSystemTools::IsSubDirectory(collapsedDir, collapsedPriorDir) || + cmSystemTools::IsSubDirectory(collapsedPriorDir, collapsedDir))) { + lg->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Base directories in file set cannot be subdirectories of each " + "other:\n ", + priorDir, "\n ", dir), + cge->GetBacktrace()); + return {}; + } + } + result.push_back(dir); + } + } + return result; +} + +void cmFileSet::EvaluateFileEntry( + const std::vector<std::string>& dirs, + std::map<std::string, std::vector<std::string>>& filesPerDir, + const std::unique_ptr<cmCompiledGeneratorExpression>& cge, + cmLocalGenerator* lg, const std::string& config, + const cmGeneratorTarget* target, + cmGeneratorExpressionDAGChecker* dagChecker) const +{ + auto files = cge->Evaluate(lg, config, target, dagChecker); + for (std::string file : cmExpandedList(files)) { + if (!cmSystemTools::FileIsFullPath(file)) { + file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file); + } + auto collapsedFile = cmSystemTools::CollapseFullPath(file); + bool found = false; + std::string relDir; + for (auto const& dir : dirs) { + auto collapsedDir = cmSystemTools::CollapseFullPath(dir); + if (cmSystemTools::IsSubDirectory(collapsedFile, collapsedDir)) { + found = true; + relDir = cmSystemTools::GetParentDirectory( + cmSystemTools::RelativePath(collapsedDir, collapsedFile)); + break; + } + } + if (!found) { + std::ostringstream e; + e << "File:\n " << file + << "\nmust be in one of the file set's base directories:"; + for (auto const& dir : dirs) { + e << "\n " << dir; + } + lg->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(), + cge->GetBacktrace()); + return; + } + + filesPerDir[relDir].push_back(file); + } +} diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h new file mode 100644 index 0000000..5ee4a98 --- /dev/null +++ b/Source/cmFileSet.h @@ -0,0 +1,64 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "cmListFileCache.h" + +class cmCompiledGeneratorExpression; +struct cmGeneratorExpressionDAGChecker; +class cmGeneratorTarget; +class cmLocalGenerator; + +class cmFileSet +{ +public: + cmFileSet(std::string name, std::string type); + + const std::string& GetName() const { return this->Name; } + const std::string& GetType() const { return this->Type; } + + void ClearDirectoryEntries(); + void AddDirectoryEntry(BT<std::string> directories); + const std::vector<BT<std::string>>& GetDirectoryEntries() const + { + return this->DirectoryEntries; + } + + void ClearFileEntries(); + void AddFileEntry(BT<std::string> files); + const std::vector<BT<std::string>>& GetFileEntries() const + { + return this->FileEntries; + } + + std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> + CompileFileEntries() const; + + std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> + CompileDirectoryEntries() const; + + std::vector<std::string> EvaluateDirectoryEntries( + const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>>& cges, + cmLocalGenerator* lg, const std::string& config, + const cmGeneratorTarget* target, + cmGeneratorExpressionDAGChecker* dagChecker = nullptr) const; + + void EvaluateFileEntry( + const std::vector<std::string>& dirs, + std::map<std::string, std::vector<std::string>>& filesPerDir, + const std::unique_ptr<cmCompiledGeneratorExpression>& cge, + cmLocalGenerator* lg, const std::string& config, + const cmGeneratorTarget* target, + cmGeneratorExpressionDAGChecker* dagChecker = nullptr) const; + +private: + std::string Name; + std::string Type; + std::vector<BT<std::string>> DirectoryEntries; + std::vector<BT<std::string>> FileEntries; +}; diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h index 4419880..ccc9633 100644 --- a/Source/cmFileTime.h +++ b/Source/cmFileTime.h @@ -24,6 +24,8 @@ public: #endif cmFileTime() = default; ~cmFileTime() = default; + cmFileTime(const cmFileTime&) = default; + cmFileTime& operator=(const cmFileTime&) = default; /** * @brief Loads the file time of fileName from the file system diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index a123e44..efc4e3a 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -168,7 +168,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) } this->ExpandPaths(); - this->ComputeFinalPaths(); + this->ComputeFinalPaths(IgnorePaths::Yes); return true; } diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index bdc9207..7106e4b 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -73,10 +73,17 @@ void cmFindCommon::DebugMessage(std::string const& msg) const bool cmFindCommon::ComputeIfDebugModeWanted() { - return this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") || + return this->Makefile->GetDebugFindPkgMode() || + this->Makefile->IsOn("CMAKE_FIND_DEBUG_MODE") || this->Makefile->GetCMakeInstance()->GetDebugFindOutput(); } +bool cmFindCommon::ComputeIfDebugModeWanted(std::string const& var) +{ + return this->ComputeIfDebugModeWanted() || + this->Makefile->GetCMakeInstance()->GetDebugFindOutput(var); +} + void cmFindCommon::InitializeSearchPathGroups() { std::vector<PathLabel>* labels; @@ -240,21 +247,29 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) std::vector<std::string> unrootedPaths = paths; paths.clear(); + auto isSameDirectoryOrSubDirectory = [](std::string const& l, + std::string const& r) { + return (cmSystemTools::GetRealPath(l) == cmSystemTools::GetRealPath(r)) || + cmSystemTools::IsSubDirectory(l, r); + }; + for (std::string const& r : roots) { for (std::string const& up : unrootedPaths) { // Place the unrooted path under the current root if it is not // already inside. Skip the unrooted path if it is relative to // a user home directory or is empty. std::string rootedDir; - if (cmSystemTools::IsSubDirectory(up, r) || - (stagePrefix && cmSystemTools::IsSubDirectory(up, *stagePrefix))) { + if (isSameDirectoryOrSubDirectory(up, r) || + (stagePrefix && isSameDirectoryOrSubDirectory(up, *stagePrefix))) { rootedDir = up; } else if (!up.empty() && up[0] != '~') { - // Start with the new root. - rootedDir = cmStrCat(r, '/'); - - // Append the original path with its old root removed. - rootedDir += cmSystemTools::SplitPathRootComponent(up); + auto const* split = cmSystemTools::SplitPathRootComponent(up); + if (split && *split) { + // Start with the new root. + rootedDir = cmStrCat(r, '/', split); + } else { + rootedDir = r; + } } // Store the new path. @@ -271,14 +286,15 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore) { - // null-terminated list of paths. - static const char* paths[] = { "CMAKE_SYSTEM_IGNORE_PATH", - "CMAKE_IGNORE_PATH", nullptr }; + static constexpr const char* paths[] = { + "CMAKE_SYSTEM_IGNORE_PATH", + "CMAKE_IGNORE_PATH", + }; // Construct the list of path roots with no trailing slashes. - for (const char** pathName = paths; *pathName; ++pathName) { + for (const char* pathName : paths) { // Get the list of paths to ignore from the variable. - this->Makefile->GetDefExpandList(*pathName, ignore); + this->Makefile->GetDefExpandList(pathName, ignore); } for (std::string& i : ignore) { @@ -293,6 +309,31 @@ void cmFindCommon::GetIgnoredPaths(std::set<std::string>& ignore) ignore.insert(ignoreVec.begin(), ignoreVec.end()); } +void cmFindCommon::GetIgnoredPrefixPaths(std::vector<std::string>& ignore) +{ + static constexpr const char* paths[] = { + "CMAKE_SYSTEM_IGNORE_PREFIX_PATH", + "CMAKE_IGNORE_PREFIX_PATH", + }; + + // Construct the list of path roots with no trailing slashes. + for (const char* pathName : paths) { + // Get the list of paths to ignore from the variable. + this->Makefile->GetDefExpandList(pathName, ignore); + } + + for (std::string& i : ignore) { + cmSystemTools::ConvertToUnixSlashes(i); + } +} + +void cmFindCommon::GetIgnoredPrefixPaths(std::set<std::string>& ignore) +{ + std::vector<std::string> ignoreVec; + this->GetIgnoredPrefixPaths(ignoreVec); + ignore.insert(ignoreVec.begin(), ignoreVec.end()); +} + bool cmFindCommon::CheckCommonArgument(std::string const& arg) { if (arg == "NO_DEFAULT_PATH") { @@ -347,23 +388,28 @@ void cmFindCommon::AddPathSuffix(std::string const& arg) this->SearchPathSuffixes.push_back(std::move(suffix)); } -void AddTrailingSlash(std::string& s) +static void AddTrailingSlash(std::string& s) { if (!s.empty() && s.back() != '/') { s += '/'; } } -void cmFindCommon::ComputeFinalPaths() +void cmFindCommon::ComputeFinalPaths(IgnorePaths ignorePaths) { // Filter out ignored paths from the prefix list - std::set<std::string> ignored; - this->GetIgnoredPaths(ignored); + std::set<std::string> ignoredPaths; + std::set<std::string> ignoredPrefixes; + if (ignorePaths == IgnorePaths::Yes) { + this->GetIgnoredPaths(ignoredPaths); + this->GetIgnoredPrefixPaths(ignoredPrefixes); + } // Combine the separate path types, filtering out ignores this->SearchPaths.clear(); std::vector<PathLabel>& allLabels = this->PathGroupLabelMap[PathGroup::All]; for (PathLabel const& l : allLabels) { - this->LabeledPaths[l].ExtractWithout(ignored, this->SearchPaths); + this->LabeledPaths[l].ExtractWithout(ignoredPaths, ignoredPrefixes, + this->SearchPaths); } // Expand list of paths inside all search roots. diff --git a/Source/cmFindCommon.h b/Source/cmFindCommon.h index f84242e..5d9b3e1 100644 --- a/Source/cmFindCommon.h +++ b/Source/cmFindCommon.h @@ -82,12 +82,21 @@ protected: /** Place a set of search paths under the search roots. */ void RerootPaths(std::vector<std::string>& paths); - /** Get ignored paths from CMAKE_[SYSTEM_]IGNORE_path variables. */ + /** Get ignored paths from CMAKE_[SYSTEM_]IGNORE_PATH variables. */ void GetIgnoredPaths(std::vector<std::string>& ignore); void GetIgnoredPaths(std::set<std::string>& ignore); + /** Get ignored paths from CMAKE_[SYSTEM_]IGNORE_PREFIX_PATH variables. */ + void GetIgnoredPrefixPaths(std::vector<std::string>& ignore); + void GetIgnoredPrefixPaths(std::set<std::string>& ignore); + /** Compute final search path list (reroot + trailing slash). */ - void ComputeFinalPaths(); + enum class IgnorePaths + { + No, + Yes, + }; + void ComputeFinalPaths(IgnorePaths ignorePaths); /** Compute the current default root path mode. */ void SelectDefaultRootPathMode(); @@ -99,8 +108,9 @@ protected: void SelectDefaultSearchModes(); /** The `InitialPass` functions of the child classes should set - this->DebugMode to the result of this. */ + this->DebugMode to the result of these. */ bool ComputeIfDebugModeWanted(); + bool ComputeIfDebugModeWanted(std::string const& var); // Path arguments prior to path manipulation routines std::vector<std::string> UserHintsArgs; @@ -129,7 +139,7 @@ protected: std::map<PathLabel, cmSearchPath> LabeledPaths; std::vector<std::string> SearchPaths; - std::set<std::string> SearchPathsEmitted; + std::set<cmSearchPath::PathWithPrefix> SearchPathsEmitted; bool SearchFrameworkFirst; bool SearchFrameworkOnly; diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index ff04bab..1c4039b 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -32,13 +32,14 @@ cmFindLibraryCommand::cmFindLibraryCommand(cmExecutionStatus& status) // cmFindLibraryCommand bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn) { - this->DebugMode = this->ComputeIfDebugModeWanted(); this->CMakePathName = "LIBRARY"; if (!this->ParseArguments(argsIn)) { return false; } + this->DebugMode = this->ComputeIfDebugModeWanted(this->VariableName); + if (this->AlreadyDefined) { this->NormalizeFindResult(); return true; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 335ebbe..f55d838 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -144,9 +144,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) this->RequiredCMakeVersion = CMake_VERSION_ENCODE(v[0], v[1], v[2]); } - this->DebugMode = this->ComputeIfDebugModeWanted(); - this->DebugBuffer.clear(); - // Lookup target architecture, if any. if (cmValue arch = this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) { @@ -236,6 +233,10 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) // Always search directly in a generated path. this->SearchPathSuffixes.emplace_back(); + // Process debug mode + cmMakefile::DebugFindPkgRAII debugFindPkgRAII(this->Makefile, this->Name); + this->DebugMode = this->ComputeIfDebugModeWanted(); + // Parse the arguments. enum Doing { @@ -607,15 +608,14 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) loadedPackage = true; } } - - if (this->DebugMode) { - this->DebugMessage(this->DebugBuffer); - this->DebugBuffer.clear(); - } } this->AppendSuccessInformation(); + if (!this->DebugBuffer.empty()) { + this->DebugMessage(this->DebugBuffer); + } + return loadedPackage; } @@ -657,6 +657,16 @@ bool cmFindPackageCommand::FindPackageUsingConfigMode() this->IgnoredPaths.clear(); this->IgnoredPaths.insert(ignored.begin(), ignored.end()); + // get igonored prefix paths from vars and reroot them. + std::vector<std::string> ignoredPrefixes; + this->GetIgnoredPrefixPaths(ignoredPrefixes); + this->RerootPaths(ignoredPrefixes); + + // Construct a set of ignored prefix paths + this->IgnoredPrefixPaths.clear(); + this->IgnoredPrefixPaths.insert(ignoredPrefixes.begin(), + ignoredPrefixes.end()); + // Find and load the package. return this->HandlePackageMode(HandlePackageModeType::Config); } @@ -671,7 +681,7 @@ void cmFindPackageCommand::SetVersionVariables( addDefinition(prefix, version); char buf[64]; - sprintf(buf, "%u", major); + snprintf(buf, sizeof(buf), "%u", major); addDefinition(prefix + "_MAJOR", buf); sprintf(buf, "%u", minor); addDefinition(prefix + "_MINOR", buf); @@ -776,22 +786,21 @@ void cmFindPackageCommand::RestoreFindDefinitions() bool cmFindPackageCommand::FindModule(bool& found) { - std::string module = cmStrCat("Find", this->Name, ".cmake"); + std::string moduleFileName = cmStrCat("Find", this->Name, ".cmake"); bool system = false; - std::string debugBuffer = - cmStrCat("find_package considered the following paths for ", this->Name, - ".cmake\n"); + std::string debugBuffer = cmStrCat( + "find_package considered the following paths for ", moduleFileName, ":\n"); std::string mfile = this->Makefile->GetModulesFile( - module, system, this->DebugMode, debugBuffer); + moduleFileName, system, this->DebugMode, debugBuffer); if (this->DebugMode) { if (mfile.empty()) { - debugBuffer = cmStrCat(debugBuffer, "The file was not found."); + debugBuffer = cmStrCat(debugBuffer, "The file was not found.\n"); } else { debugBuffer = cmStrCat(debugBuffer, "The file was found at\n ", mfile, "\n"); } - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } if (!mfile.empty()) { @@ -935,11 +944,6 @@ bool cmFindPackageCommand::HandlePackageMode( result = false; } - if (this->DebugMode) { - this->DebugMessage(this->DebugBuffer); - this->DebugBuffer.clear(); - } - // package not found if (result && !found) { // warn if package required or neither quiet nor in config mode @@ -1105,7 +1109,8 @@ bool cmFindPackageCommand::FindConfig() if (this->DebugMode) { this->DebugBuffer = cmStrCat(this->DebugBuffer, "find_package considered the following " - "locations for the Config module:\n"); + "locations for ", + this->Name, "'s Config module:\n"); } // Search for frameworks. @@ -1297,11 +1302,11 @@ inline std::size_t collectPathsForDebug(std::string& buffer, { const auto& paths = searchPath.GetPaths(); if (paths.empty()) { - buffer += " none"; + buffer += " none\n"; return 0; } for (std::size_t i = startIndex; i < paths.size(); i++) { - buffer += " " + paths[i] + "\n"; + buffer += " " + paths[i].Path + "\n"; } return paths.size(); } @@ -1338,7 +1343,7 @@ void cmFindPackageCommand::ComputePrefixes() } this->FillPrefixesUserGuess(); - this->ComputeFinalPaths(); + this->ComputeFinalPaths(IgnorePaths::No); } void cmFindPackageCommand::FillPrefixesPackageRoot() @@ -1357,7 +1362,7 @@ void cmFindPackageCommand::FillPrefixesPackageRoot() std::string debugBuffer = "<PackageName>_ROOT CMake variable " "[CMAKE_FIND_USE_PACKAGE_ROOT_PATH].\n"; collectPathsForDebug(debugBuffer, paths); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1380,7 +1385,7 @@ void cmFindPackageCommand::FillPrefixesCMakeEnvironment() paths.AddEnvPath("CMAKE_PREFIX_PATH"); if (this->DebugMode) { debugBuffer = cmStrCat(debugBuffer, - "\nCMAKE_PREFIX_PATH env variable " + "CMAKE_PREFIX_PATH env variable " "[CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n"); debugOffset = collectPathsForDebug(debugBuffer, paths, debugOffset); } @@ -1390,10 +1395,10 @@ void cmFindPackageCommand::FillPrefixesCMakeEnvironment() if (this->DebugMode) { debugBuffer = cmStrCat(debugBuffer, - "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env " + "CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env " "variables [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].\n"); collectPathsForDebug(debugBuffer, paths, debugOffset); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1414,10 +1419,10 @@ void cmFindPackageCommand::FillPrefixesCMakeVariable() if (this->DebugMode) { debugBuffer = cmStrCat(debugBuffer, - "\nCMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables " + "CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables " "[CMAKE_FIND_USE_CMAKE_PATH].\n"); collectPathsForDebug(debugBuffer, paths, debugOffset); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1442,7 +1447,7 @@ void cmFindPackageCommand::FillPrefixesSystemEnvironment() std::string debugBuffer = "Standard system environment variables " "[CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].\n"; collectPathsForDebug(debugBuffer, paths); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1472,7 +1477,7 @@ void cmFindPackageCommand::FillPrefixesUserRegistry() "CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].\n"; collectPathsForDebug(debugBuffer, this->LabeledPaths[PathLabel::UserRegistry]); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1492,7 +1497,7 @@ void cmFindPackageCommand::FillPrefixesSystemRegistry() "[CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].\n"; collectPathsForDebug(debugBuffer, this->LabeledPaths[PathLabel::SystemRegistry]); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1671,7 +1676,7 @@ void cmFindPackageCommand::FillPrefixesCMakeSystemVariable() std::string debugBuffer = "CMake variables defined in the Platform file " "[CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].\n"; collectPathsForDebug(debugBuffer, paths); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1686,7 +1691,7 @@ void cmFindPackageCommand::FillPrefixesUserGuess() std::string debugBuffer = "Paths specified by the find_package PATHS option.\n"; collectPathsForDebug(debugBuffer, paths); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -1701,7 +1706,7 @@ void cmFindPackageCommand::FillPrefixesUserHints() std::string debugBuffer = "Paths specified by the find_package HINTS option.\n"; collectPathsForDebug(debugBuffer, paths); - this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer, "\n"); + this->DebugBuffer = cmStrCat(this->DebugBuffer, debugBuffer); } } @@ -2278,6 +2283,16 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) return false; } + // Skip this if it's in ignored paths. + std::string prefixWithoutSlash = prefix_in; + if (prefixWithoutSlash != "/" && prefixWithoutSlash.back() == '/') { + prefixWithoutSlash.erase(prefixWithoutSlash.length() - 1); + } + if (this->IgnoredPaths.count(prefixWithoutSlash) || + this->IgnoredPrefixPaths.count(prefixWithoutSlash)) { + return false; + } + // PREFIX/ (useful on windows or in build trees) if (this->SearchDirectory(prefix_in)) { return true; diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index edf32d4..f921bb0 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -203,6 +203,7 @@ private: std::vector<std::string> Names; std::vector<std::string> Configs; std::set<std::string> IgnoredPaths; + std::set<std::string> IgnoredPrefixPaths; std::string DebugBuffer; /*! the selected sortOrder (None by default)*/ diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx index 3d21167..27074ff 100644 --- a/Source/cmFindPathCommand.cxx +++ b/Source/cmFindPathCommand.cxx @@ -29,13 +29,14 @@ cmFindPathCommand::cmFindPathCommand(cmExecutionStatus& status) // cmFindPathCommand bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn) { - this->DebugMode = this->ComputeIfDebugModeWanted(); this->CMakePathName = "INCLUDE"; if (!this->ParseArguments(argsIn)) { return false; } + this->DebugMode = this->ComputeIfDebugModeWanted(this->VariableName); + if (this->AlreadyDefined) { this->NormalizeFindResult(); return true; @@ -64,7 +65,8 @@ std::string cmFindPathCommand::FindHeader() } std::string cmFindPathCommand::FindHeaderInFramework( - std::string const& file, std::string const& dir) const + std::string const& file, std::string const& dir, + cmFindBaseDebugState& debug) const { std::string fileName = file; std::string frameWorkName; @@ -87,11 +89,13 @@ std::string cmFindPathCommand::FindHeaderInFramework( std::string fpath = cmStrCat(dir, frameWorkName, ".framework"); std::string intPath = cmStrCat(fpath, "/Headers/", fileName); if (cmSystemTools::FileExists(intPath)) { + debug.FoundAt(intPath); if (this->IncludeFileInPath) { return intPath; } return fpath; } + debug.FailedAt(intPath); } } // if it is not found yet or not a framework header, then do a glob search @@ -102,12 +106,15 @@ std::string cmFindPathCommand::FindHeaderInFramework( std::vector<std::string> files = globIt.GetFiles(); if (!files.empty()) { std::string fheader = cmSystemTools::CollapseFullPath(files[0]); + debug.FoundAt(fheader); if (this->IncludeFileInPath) { return fheader; } fheader.resize(fheader.size() - file.size()); return fheader; } + + // No frameworks matched the glob, so nothing more to add to debug.FailedAt() return ""; } @@ -134,8 +141,7 @@ std::string cmFindPathCommand::FindFrameworkHeader(cmFindBaseDebugState& debug) { for (std::string const& n : this->Names) { for (std::string const& sp : this->SearchPaths) { - std::string fwPath = this->FindHeaderInFramework(n, sp); - fwPath.empty() ? debug.FailedAt(fwPath) : debug.FoundAt(fwPath); + std::string fwPath = this->FindHeaderInFramework(n, sp, debug); if (!fwPath.empty()) { return fwPath; } diff --git a/Source/cmFindPathCommand.h b/Source/cmFindPathCommand.h index c7281f1..a7746f6 100644 --- a/Source/cmFindPathCommand.h +++ b/Source/cmFindPathCommand.h @@ -30,7 +30,8 @@ public: private: std::string FindHeaderInFramework(std::string const& file, - std::string const& dir) const; + std::string const& dir, + cmFindBaseDebugState& debug) const; std::string FindHeader(); std::string FindNormalHeader(cmFindBaseDebugState& debug); std::string FindFrameworkHeader(cmFindBaseDebugState& debug); diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 1c87625..780b256 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -104,6 +104,26 @@ struct cmFindProgramHelper } bool FileIsExecutable(std::string const& file) const { +#ifdef _WIN32 + if (!this->FileIsExecutableCMP0109(file)) { + return false; + } + // Pretend the Windows "python" app installer alias does not exist. + if (cmSystemTools::LowerCase(file).find("/windowsapps/python") != + std::string::npos) { + std::string dest; + if (cmSystemTools::ReadSymlink(file, dest) && + cmHasLiteralSuffix(dest, "\\AppInstallerPythonRedirector.exe")) { + return false; + } + } + return true; +#else + return this->FileIsExecutableCMP0109(file); +#endif + } + bool FileIsExecutableCMP0109(std::string const& file) const + { switch (this->PolicyCMP0109) { case cmPolicies::OLD: return cmSystemTools::FileExists(file, true); @@ -157,13 +177,14 @@ cmFindProgramCommand::cmFindProgramCommand(cmExecutionStatus& status) // cmFindProgramCommand bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn) { - this->DebugMode = this->ComputeIfDebugModeWanted(); + this->CMakePathName = "PROGRAM"; // call cmFindBase::ParseArguments if (!this->ParseArguments(argsIn)) { return false; } + this->DebugMode = this->ComputeIfDebugModeWanted(this->VariableName); if (this->AlreadyDefined) { this->NormalizeFindResult(); diff --git a/Source/cmFunctionBlocker.cxx b/Source/cmFunctionBlocker.cxx index d4666d7..40e692d 100644 --- a/Source/cmFunctionBlocker.cxx +++ b/Source/cmFunctionBlocker.cxx @@ -27,7 +27,7 @@ bool cmFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, if (!this->ArgumentsMatch(lff, mf)) { cmListFileContext const& lfc = this->GetStartingContext(); cmListFileContext closingContext = - cmListFileContext::FromCommandContext(lff, lfc.FilePath); + cmListFileContext::FromListFileFunction(lff, lfc.FilePath); std::ostringstream e; /* clang-format off */ e << "A logical block opening on the line\n" diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx index afa8e9b..34c8824 100644 --- a/Source/cmGccDepfileLexerHelper.cxx +++ b/Source/cmGccDepfileLexerHelper.cxx @@ -113,6 +113,24 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) void cmGccDepfileLexerHelper::sanitizeContent() { for (auto it = this->Content.begin(); it != this->Content.end();) { + // Remove empty paths and normalize windows paths + for (auto pit = it->paths.begin(); pit != it->paths.end();) { + if (pit->empty()) { + pit = it->paths.erase(pit); + } else { +#if defined(_WIN32) + // Unescape the colon following the drive letter. + // Some versions of GNU compilers can escape this character. + // c\:\path must be transformed to c:\path + if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' && + std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' && + (*pit)[2] == ':') { + pit->erase(1, 1); + } +#endif + ++pit; + } + } // Remove empty rules for (auto rit = it->rules.begin(); rit != it->rules.end();) { if (rit->empty()) { @@ -121,28 +139,10 @@ void cmGccDepfileLexerHelper::sanitizeContent() ++rit; } } - // Remove the entry if rules are empty - if (it->rules.empty()) { + // Remove the entry if rules are empty or do not have any paths + if (it->rules.empty() || it->paths.empty()) { it = this->Content.erase(it); } else { - // Remove empty paths and normalize windows paths - for (auto pit = it->paths.begin(); pit != it->paths.end();) { - if (pit->empty()) { - pit = it->paths.erase(pit); - } else { -#if defined(_WIN32) - // Unescape the colon following the drive letter. - // Some versions of GNU compilers can escape this character. - // c\:\path must be transformed to c:\path - if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' && - std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' && - (*pit)[2] == ':') { - pit->erase(1, 1); - } -#endif - ++pit; - } - } ++it; } } diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index 06778b1..c86001a 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -136,7 +136,8 @@ void cmGeneratedFileStreamBase::Open(std::string const& name) this->TempName += this->TempExt; } else { char buf[64]; - sprintf(buf, "tmp%05x", cmSystemTools::RandomSeed() & 0xFFFFF); + snprintf(buf, sizeof(buf), "tmp%05x", + cmSystemTools::RandomSeed() & 0xFFFFF); this->TempName += buf; } diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index a1fce55..d4b02a5 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -188,11 +188,13 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( return top->Target == tgt && prop == "LINK_LIBRARIES"_s; } - return prop == "LINK_LIBRARIES"_s || prop == "LINK_INTERFACE_LIBRARIES"_s || + return prop == "LINK_LIBRARIES"_s || prop == "INTERFACE_LINK_LIBRARIES"_s || + prop == "INTERFACE_LINK_LIBRARIES_DIRECT"_s || + prop == "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"_s || + prop == "LINK_INTERFACE_LIBRARIES"_s || prop == "IMPORTED_LINK_INTERFACE_LIBRARIES"_s || cmHasLiteralPrefix(prop, "LINK_INTERFACE_LIBRARIES_") || - cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_") || - prop == "INTERFACE_LINK_LIBRARIES"_s; + cmHasLiteralPrefix(prop, "IMPORTED_LINK_INTERFACE_LIBRARIES_"); } cmGeneratorExpressionDAGChecker const* cmGeneratorExpressionDAGChecker::Top() diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index c357ee1..396e9c9 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -814,7 +814,8 @@ struct PlatformIdNode : public cmGeneratorExpressionNode } return "0"; } -} platformIdNode; +}; +static struct PlatformIdNode platformIdNode; template <cmSystemTools::CompareOp Op> struct VersionNode : public cmGeneratorExpressionNode @@ -1261,7 +1262,7 @@ static const struct DeviceLinkNode : public cmGeneratorExpressionNode } } deviceLinkNode; -std::string getLinkedTargetsContent( +static std::string getLinkedTargetsContent( cmGeneratorTarget const* target, std::string const& prop, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagChecker) @@ -1830,8 +1831,8 @@ static const char* targetPolicyWhitelist[] = { #undef TARGET_POLICY_STRING }; -cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt, - const char* policy) +static cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt, + const char* policy) { #define RETURN_POLICY(POLICY) \ if (strcmp(policy, #POLICY) == 0) { \ @@ -1846,7 +1847,7 @@ cmPolicies::PolicyStatus statusForTarget(cmGeneratorTarget const* tgt, return cmPolicies::WARN; } -cmPolicies::PolicyID policyForString(const char* policy_id) +static cmPolicies::PolicyID policyForString(const char* policy_id) { #define RETURN_POLICY_ID(POLICY_ID) \ if (strcmp(policy_id, #POLICY_ID) == 0) { \ diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 8033ef5..63cf2ec 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -25,6 +25,7 @@ #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" +#include "cmFileSet.h" #include "cmFileTimes.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" @@ -41,6 +42,7 @@ #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmSourceFileLocationKind.h" +#include "cmSourceGroup.h" #include "cmStandardLevelResolver.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -50,17 +52,21 @@ #include "cmTargetPropertyComputer.h" #include "cmake.h" -class cmMessenger; - namespace { +using LinkInterfaceFor = cmGeneratorTarget::LinkInterfaceFor; + const cmsys::RegularExpression FrameworkRegularExpression( "^(.*/)?([^/]*)\\.framework/(.*)$"); +const std::string kINTERFACE_LINK_LIBRARIES = "INTERFACE_LINK_LIBRARIES"; +const std::string kINTERFACE_LINK_LIBRARIES_DIRECT = + "INTERFACE_LINK_LIBRARIES_DIRECT"; +const std::string kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE = + "INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE"; } template <> cmValue cmTargetPropertyComputer::GetSources<cmGeneratorTarget>( - cmGeneratorTarget const* tgt, cmMessenger* /* messenger */, - cmListFileBacktrace const& /* context */) + cmGeneratorTarget const* tgt, cmMakefile const& /* mf */) { return tgt->GetSourcesProperty(); } @@ -173,9 +179,73 @@ private: BT<std::string> PropertyValue; }; -std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry> -CreateTargetPropertyEntry(const BT<std::string>& propertyValue, - bool evaluateForBuildsystem = false) +class TargetPropertyEntryFileSet + : public cmGeneratorTarget::TargetPropertyEntry +{ +public: + TargetPropertyEntryFileSet( + std::vector<std::string> dirs, bool contextSensitiveDirs, + std::unique_ptr<cmCompiledGeneratorExpression> entryCge, + const cmFileSet* fileSet, cmLinkImplItem const& item = NoLinkImplItem) + : cmGeneratorTarget::TargetPropertyEntry(item) + , BaseDirs(std::move(dirs)) + , ContextSensitiveDirs(contextSensitiveDirs) + , EntryCge(std::move(entryCge)) + , FileSet(fileSet) + { + } + + const std::string& Evaluate(cmLocalGenerator* lg, const std::string& config, + cmGeneratorTarget const* headTarget, + cmGeneratorExpressionDAGChecker* dagChecker, + std::string const& /*lang*/) const override + { + std::map<std::string, std::vector<std::string>> filesPerDir; + this->FileSet->EvaluateFileEntry(this->BaseDirs, filesPerDir, + this->EntryCge, lg, config, headTarget, + dagChecker); + + std::vector<std::string> files; + for (auto const& it : filesPerDir) { + files.insert(files.end(), it.second.begin(), it.second.end()); + } + + static std::string filesStr; + filesStr = cmJoin(files, ";"); + return filesStr; + } + + cmListFileBacktrace GetBacktrace() const override + { + return this->EntryCge->GetBacktrace(); + } + + std::string const& GetInput() const override + { + return this->EntryCge->GetInput(); + } + + bool GetHadContextSensitiveCondition() const override + { + return this->ContextSensitiveDirs || + this->EntryCge->GetHadContextSensitiveCondition(); + } + +private: + const std::vector<std::string> BaseDirs; + const bool ContextSensitiveDirs; + const std::unique_ptr<cmCompiledGeneratorExpression> EntryCge; + const cmFileSet* FileSet; +}; + +std::unique_ptr< + cmGeneratorTarget:: + TargetPropertyEntry> static CreateTargetPropertyEntry(const BT<std:: + string>& + propertyValue, + bool + evaluateForBuildsystem = + false) { if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) { cmGeneratorExpression ge(propertyValue.Backtrace); @@ -190,7 +260,7 @@ CreateTargetPropertyEntry(const BT<std::string>& propertyValue, cm::make_unique<TargetPropertyEntryString>(propertyValue)); } -void CreatePropertyGeneratorExpressions( +static void CreatePropertyGeneratorExpressions( cmBTStringRange entries, std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items, bool evaluateForBuildsystem = false) @@ -373,8 +443,8 @@ std::string cmGeneratorTarget::GetExportName() const cmValue cmGeneratorTarget::GetProperty(const std::string& prop) const { - if (cmValue result = cmTargetPropertyComputer::GetProperty( - this, prop, this->Makefile->GetMessenger(), this->GetBacktrace())) { + if (cmValue result = + cmTargetPropertyComputer::GetProperty(this, prop, *this->Makefile)) { return result; } if (cmSystemTools::GetFatalErrorOccured()) { @@ -684,6 +754,12 @@ void cmGeneratorTarget::ClearSourcesCache() this->LinkImplMap.clear(); } +void cmGeneratorTarget::ClearLinkInterfaceCache() +{ + this->LinkInterfaceMap.clear(); + this->LinkInterfaceUsageRequirementsOnlyMap.clear(); +} + void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before) { this->SourceEntries.insert( @@ -747,6 +823,9 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, if (!depTgt->IsImported() || excludeImported) { return; } + if (depTgt->GetPropertyAsBool("IMPORTED_NO_SYSTEM")) { + return; + } if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, @@ -1255,7 +1334,7 @@ bool cmGeneratorTarget::GetPropertyAsBool(const std::string& prop) const bool cmGeneratorTarget::MaybeHaveInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, - bool usage_requirements_only) const + LinkInterfaceFor interfaceFor) const { std::string const key = prop + '@' + context->Config; auto i = this->MaybeInterfacePropertyExists.find(key); @@ -1273,7 +1352,7 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( context->HeadTarget ? context->HeadTarget : this; if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries(context->Config, headTarget, - usage_requirements_only)) { + interfaceFor)) { if (iface->HadHeadSensitiveCondition) { // With a different head target we may get to a library with // this interface property. @@ -1283,8 +1362,8 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( // head target, so we can follow them. for (cmLinkItem const& lib : iface->Libraries) { if (lib.Target && - lib.Target->MaybeHaveInterfaceProperty( - prop, context, usage_requirements_only)) { + lib.Target->MaybeHaveInterfaceProperty(prop, context, + interfaceFor)) { maybeInterfaceProp = true; break; } @@ -1299,13 +1378,12 @@ bool cmGeneratorTarget::MaybeHaveInterfaceProperty( std::string cmGeneratorTarget::EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagCheckerParent, - bool usage_requirements_only) const + LinkInterfaceFor interfaceFor) const { std::string result; // If the property does not appear transitively at all, we are done. - if (!this->MaybeHaveInterfaceProperty(prop, context, - usage_requirements_only)) { + if (!this->MaybeHaveInterfaceProperty(prop, context, interfaceFor)) { return result; } @@ -1337,7 +1415,7 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( } if (cmLinkInterfaceLibraries const* iface = this->GetLinkInterfaceLibraries( - context->Config, headTarget, usage_requirements_only)) { + context->Config, headTarget, interfaceFor)) { context->HadContextSensitiveCondition = context->HadContextSensitiveCondition || iface->HadContextSensitiveCondition; @@ -1355,7 +1433,7 @@ std::string cmGeneratorTarget::EvaluateInterfaceProperty( context->Language); std::string libResult = cmGeneratorExpression::StripEmptyListElements( lib.Target->EvaluateInterfaceProperty(prop, &libContext, &dagChecker, - usage_requirements_only)); + interfaceFor)); if (!libResult.empty()) { if (result.empty()) { result = std::move(libResult); @@ -1409,8 +1487,8 @@ std::string AddLangSpecificInterfaceIncludeDirectories( } std::string directories; - if (const auto* interface = - target->GetLinkInterfaceLibraries(config, root, true)) { + if (const auto* interface = target->GetLinkInterfaceLibraries( + config, root, LinkInterfaceFor::Usage)) { for (const cmLinkItem& library : interface->Libraries) { if (const cmGeneratorTarget* dependency = library.Target) { if (cm::contains(dependency->GetAllConfigCompileLanguages(), lang)) { @@ -1481,7 +1559,7 @@ void addInterfaceEntry(cmGeneratorTarget const* headTarget, std::string const& lang, cmGeneratorExpressionDAGChecker* dagChecker, EvaluatedTargetPropertyEntries& entries, - bool usage_requirements_only, + LinkInterfaceFor interfaceFor, std::vector<cmLinkImplItem> const& libraries) { for (cmLinkImplItem const& lib : libraries) { @@ -1494,7 +1572,7 @@ void addInterfaceEntry(cmGeneratorTarget const* headTarget, headTarget->GetLocalGenerator(), config, false, headTarget, headTarget, true, lib.Backtrace, lang); cmExpandList(lib.Target->EvaluateInterfaceProperty( - prop, &context, dagChecker, usage_requirements_only), + prop, &context, dagChecker, interfaceFor), ee.Values); ee.ContextDependent = context.HadContextSensitiveCondition; entries.Entries.emplace_back(std::move(ee)); @@ -1521,13 +1599,13 @@ enum class IncludeRuntimeInterface Yes, No }; -void AddInterfaceEntries(cmGeneratorTarget const* headTarget, - std::string const& config, std::string const& prop, - std::string const& lang, - cmGeneratorExpressionDAGChecker* dagChecker, - EvaluatedTargetPropertyEntries& entries, - IncludeRuntimeInterface searchRuntime, - bool usage_requirements_only = true) +void AddInterfaceEntries( + cmGeneratorTarget const* headTarget, std::string const& config, + std::string const& prop, std::string const& lang, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries, + IncludeRuntimeInterface searchRuntime, + LinkInterfaceFor interfaceFor = LinkInterfaceFor::Usage) { if (searchRuntime == IncludeRuntimeInterface::Yes) { if (cmLinkImplementation const* impl = @@ -1538,10 +1616,10 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, auto runtimeLibIt = impl->LanguageRuntimeLibraries.find(lang); if (runtimeLibIt != impl->LanguageRuntimeLibraries.end()) { addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, - usage_requirements_only, runtimeLibIt->second); + interfaceFor, runtimeLibIt->second); } addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, - usage_requirements_only, impl->Libraries); + interfaceFor, impl->Libraries); } } else { if (cmLinkImplementationLibraries const* impl = @@ -1549,7 +1627,7 @@ void AddInterfaceEntries(cmGeneratorTarget const* headTarget, entries.HadContextSensitiveCondition = impl->HadContextSensitiveCondition; addInterfaceEntry(headTarget, config, prop, lang, dagChecker, entries, - usage_requirements_only, impl->Libraries); + interfaceFor, impl->Libraries); } } } @@ -1586,6 +1664,80 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget, } } +void addFileSetEntry(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + cmFileSet const* fileSet, + EvaluatedTargetPropertyEntries& entries) +{ + auto dirCges = fileSet->CompileDirectoryEntries(); + auto dirs = fileSet->EvaluateDirectoryEntries( + dirCges, headTarget->GetLocalGenerator(), config, headTarget, dagChecker); + bool contextSensitiveDirs = false; + for (auto const& dirCge : dirCges) { + if (dirCge->GetHadContextSensitiveCondition()) { + contextSensitiveDirs = true; + break; + } + } + cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance(); + for (auto& entryCge : fileSet->CompileFileEntries()) { + TargetPropertyEntryFileSet tpe(dirs, contextSensitiveDirs, + std::move(entryCge), fileSet); + entries.Entries.emplace_back( + EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, tpe)); + for (auto const& file : entries.Entries.back().Values) { + auto* sf = headTarget->Makefile->GetOrCreateSource(file); + if (fileSet->GetType() == "HEADERS"_s) { + sf->SetProperty("HEADER_FILE_ONLY", "TRUE"); + } + +#ifndef CMAKE_BOOTSTRAP + std::string e; + std::string w; + auto path = sf->ResolveFullPath(&e, &w); + if (!w.empty()) { + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, + headTarget->GetBacktrace()); + } + if (path.empty()) { + if (!e.empty()) { + cm->IssueMessage(MessageType::FATAL_ERROR, e, + headTarget->GetBacktrace()); + } + return; + } + bool found = false; + for (auto const& sg : headTarget->Makefile->GetSourceGroups()) { + if (sg.MatchesFiles(path)) { + found = true; + break; + } + } + if (!found) { + if (fileSet->GetType() == "HEADERS"_s) { + headTarget->Makefile->GetOrCreateSourceGroup("Header Files") + ->AddGroupFile(path); + } + } +#endif + } + } +} + +void AddFileSetEntries(cmGeneratorTarget const* headTarget, + std::string const& config, + cmGeneratorExpressionDAGChecker* dagChecker, + EvaluatedTargetPropertyEntries& entries) +{ + for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) { + for (auto const& name : cmExpandedList(entry.Value)) { + auto const* headerSet = headTarget->Target->GetFileSet(name); + addFileSetEntry(headTarget, config, dagChecker, headerSet, entries); + } + } +} + bool processSources(cmGeneratorTarget const* tgt, EvaluatedTargetPropertyEntries& entries, std::vector<BT<std::string>>& srcs, @@ -1708,7 +1860,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( EvaluatedTargetPropertyEntries linkInterfaceSourcesEntries; AddInterfaceEntries(this, config, "INTERFACE_SOURCES", std::string(), &dagChecker, linkInterfaceSourcesEntries, - IncludeRuntimeInterface::No, true); + IncludeRuntimeInterface::No, LinkInterfaceFor::Usage); std::vector<std::string>::size_type numFilesBefore = files.size(); bool contextDependentInterfaceSources = processSources( this, linkInterfaceSourcesEntries, files, uniqueSrcs, debugSources); @@ -1723,10 +1875,18 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( uniqueSrcs, debugSources); } + // Collect this target's file sets. + std::vector<std::string>::size_type numFilesBefore3 = files.size(); + EvaluatedTargetPropertyEntries fileSetEntries; + AddFileSetEntries(this, config, &dagChecker, fileSetEntries); + bool contextDependentFileSets = + processSources(this, fileSetEntries, files, uniqueSrcs, debugSources); + // Determine if sources are context-dependent or not. if (!contextDependentDirectSources && !(contextDependentInterfaceSources && numFilesBefore < files.size()) && - !(contextDependentObjects && numFilesBefore2 < files.size())) { + !(contextDependentObjects && numFilesBefore2 < files.size()) && + !(contextDependentFileSets && numFilesBefore3 < files.size())) { this->SourcesAreContextDependent = Tribool::False; } else { this->SourcesAreContextDependent = Tribool::True; @@ -2538,7 +2698,6 @@ public: : Config(std::move(config)) , Languages(languages) , HeadTarget(head) - , Target(target) , SecondPass(secondPass) { this->Visited.insert(target); @@ -2547,36 +2706,6 @@ public: void Visit(cmLinkItem const& item) { if (!item.Target) { - if (item.AsStr().find("::") != std::string::npos) { - bool noMessage = false; - MessageType messageType = MessageType::FATAL_ERROR; - std::ostringstream e; - switch (this->Target->GetLocalGenerator()->GetPolicyStatus( - cmPolicies::CMP0028)) { - case cmPolicies::WARN: { - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0028) << "\n"; - messageType = MessageType::AUTHOR_WARNING; - } break; - case cmPolicies::OLD: - noMessage = true; - break; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Issue the fatal message. - break; - } - - if (!noMessage) { - e << "Target \"" << this->Target->GetName() - << "\" links to target \"" << item.AsStr() - << "\" but the target was not found. Perhaps a find_package() " - "call is missing for an IMPORTED target, or an ALIAS target is " - "missing?"; - this->Target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage( - messageType, e.str(), this->Target->GetBacktrace()); - } - } return; } if (!this->Visited.insert(item.Target).second) { @@ -2609,7 +2738,6 @@ private: std::string Config; std::unordered_set<std::string>& Languages; cmGeneratorTarget const* HeadTarget; - const cmGeneratorTarget* Target; std::set<cmGeneratorTarget const*> Visited; bool SecondPass; bool HadLinkLanguageSensitiveCondition = false; @@ -2923,16 +3051,17 @@ void cmGeneratorTarget::GetAutoUicOptions(std::vector<std::string>& result, result); } -void processILibs(const std::string& config, - cmGeneratorTarget const* headTarget, cmLinkItem const& item, - cmGlobalGenerator* gg, - std::vector<cmGeneratorTarget const*>& tgts, - std::set<cmGeneratorTarget const*>& emitted) +static void processILibs(const std::string& config, + cmGeneratorTarget const* headTarget, + cmLinkItem const& item, cmGlobalGenerator* gg, + std::vector<cmGeneratorTarget const*>& tgts, + std::set<cmGeneratorTarget const*>& emitted) { if (item.Target && emitted.insert(item.Target).second) { tgts.push_back(item.Target); if (cmLinkInterfaceLibraries const* iface = - item.Target->GetLinkInterfaceLibraries(config, headTarget, true)) { + item.Target->GetLinkInterfaceLibraries(config, headTarget, + LinkInterfaceFor::Usage)) { for (cmLinkItem const& lib : iface->Libraries) { processILibs(config, headTarget, lib, gg, tgts, emitted); } @@ -3286,7 +3415,7 @@ void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags, void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const { - const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES"); + std::string property = this->GetSafeProperty("CUDA_ARCHITECTURES"); if (property.empty()) { switch (this->GetPolicyStatusCMP0104()) { @@ -3314,6 +3443,28 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const return; } + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + + // Check for special modes: `all`, `all-major`. + if (property == "all" || property == "all-major") { + if (compiler == "NVIDIA" && + cmSystemTools::VersionCompare( + cmSystemTools::OP_GREATER_EQUAL, + this->Makefile->GetDefinition("CMAKE_CUDA_COMPILER_VERSION"), + "11.5")) { + flags = cmStrCat(flags, " -arch=", property); + return; + } + if (property == "all") { + property = + *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL"); + } else if (property == "all-major") { + property = + *this->Makefile->GetDefinition("CMAKE_CUDA_ARCHITECTURES_ALL_MAJOR"); + } + } + struct CudaArchitecture { std::string name; @@ -3355,9 +3506,6 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const } } - std::string const& compiler = - this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); - if (compiler == "NVIDIA") { for (CudaArchitecture& architecture : architectures) { flags += @@ -3514,7 +3662,7 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt, cmLinkImplItem const& item = entry.LinkImplItem; std::string const& targetName = item.AsStr(); bool const fromImported = item.Target && item.Target->IsImported(); - bool const checkCMP0027 = item.FromGenex; + bool const checkCMP0027 = item.CheckCMP0027; std::string usedIncludes; for (std::string& entryInclude : entry.Values) { @@ -4416,7 +4564,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( AddInterfaceEntries(this, config, "INTERFACE_LINK_OPTIONS", language, &dagChecker, entries, IncludeRuntimeInterface::Yes, - this->GetPolicyStatusCMP0099() != cmPolicies::NEW); + this->GetPolicyStatusCMP0099() == cmPolicies::NEW + ? LinkInterfaceFor::Link + : LinkInterfaceFor::Usage); processOptions(this, entries, result, uniqueOptions, debugOptions, "link options", OptionsParse::Shell, this->IsDeviceLink()); @@ -4682,7 +4832,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES", language, &dagChecker, entries, IncludeRuntimeInterface::Yes, - this->GetPolicyStatusCMP0099() != cmPolicies::NEW); + this->GetPolicyStatusCMP0099() == cmPolicies::NEW + ? LinkInterfaceFor::Link + : LinkInterfaceFor::Usage); processLinkDirectories(this, entries, result, uniqueDirectories, debugDirectories); @@ -4721,7 +4873,9 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( } AddInterfaceEntries(this, config, "INTERFACE_LINK_DEPENDS", language, &dagChecker, entries, IncludeRuntimeInterface::Yes, - this->GetPolicyStatusCMP0099() != cmPolicies::NEW); + this->GetPolicyStatusCMP0099() == cmPolicies::NEW + ? LinkInterfaceFor::Link + : LinkInterfaceFor::Usage); processOptions(this, entries, result, uniqueOptions, false, "link depends", OptionsParse::None); @@ -5692,7 +5846,7 @@ std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/) return "(unset)"; } -std::string compatibilityType(CompatibleType t) +static std::string compatibilityType(CompatibleType t) { switch (t) { case BoolType: @@ -5708,7 +5862,7 @@ std::string compatibilityType(CompatibleType t) return ""; } -std::string compatibilityAgree(CompatibleType t, bool dominant) +static std::string compatibilityAgree(CompatibleType t, bool dominant) { switch (t) { case BoolType: @@ -5798,23 +5952,23 @@ std::pair<bool, bool> consistentProperty(bool lhs, bool rhs, return { lhs == rhs, lhs }; } -std::pair<bool, const char*> consistentStringProperty(const char* lhs, - const char* rhs) +static std::pair<bool, const char*> consistentStringProperty(const char* lhs, + const char* rhs) { const bool b = strcmp(lhs, rhs) == 0; return { b, b ? lhs : nullptr }; } -std::pair<bool, std::string> consistentStringProperty(const std::string& lhs, - const std::string& rhs) +static std::pair<bool, std::string> consistentStringProperty( + const std::string& lhs, const std::string& rhs) { const bool b = lhs == rhs; return { b, b ? lhs : valueAsString(nullptr) }; } -std::pair<bool, const char*> consistentNumberProperty(const char* lhs, - const char* rhs, - CompatibleType t) +static std::pair<bool, const char*> consistentNumberProperty(const char* lhs, + const char* rhs, + CompatibleType t) { char* pEnd; @@ -5865,9 +6019,9 @@ std::pair<bool, const char*> consistentProperty(const char* lhs, return { false, nullptr }; } -std::pair<bool, std::string> consistentProperty(const std::string& lhs, - const std::string& rhs, - CompatibleType t) +static std::pair<bool, std::string> consistentProperty(const std::string& lhs, + const std::string& rhs, + CompatibleType t) { const std::string null_ptr = valueAsString(nullptr); @@ -6108,6 +6262,139 @@ cmComputeLinkInformation* cmGeneratorTarget::GetLinkInformation( return i->second.get(); } +void cmGeneratorTarget::CheckLinkLibraries() const +{ + bool linkLibrariesOnlyTargets = + this->GetPropertyAsBool("LINK_LIBRARIES_ONLY_TARGETS"); + + // Evaluate the link interface of this target if needed for extra checks. + if (linkLibrariesOnlyTargets) { + std::vector<std::string> const& configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (std::string const& config : configs) { + this->GetLinkInterfaceLibraries(config, this, LinkInterfaceFor::Link); + } + } + + // Check link the implementation for each generated configuration. + for (auto const& hmp : this->LinkImplMap) { + HeadToLinkImplementationMap const& hm = hmp.second; + // There could be several entries used when computing the pre-CMP0022 + // default link interface. Check only the entry for our own link impl. + auto const hmi = hm.find(this); + if (hmi == hm.end() || !hmi->second.LibrariesDone) { + continue; + } + for (cmLinkImplItem const& item : hmi->second.Libraries) { + if (!this->VerifyLinkItemColons(LinkItemRole::Implementation, item)) { + return; + } + if (linkLibrariesOnlyTargets && + !this->VerifyLinkItemIsTarget(LinkItemRole::Implementation, item)) { + return; + } + } + } + + // Check link the interface for each generated combination of + // configuration and consuming head target. We should not need to + // consider LinkInterfaceUsageRequirementsOnlyMap because its entries + // should be a subset of LinkInterfaceMap (with LINK_ONLY left out). + for (auto const& hmp : this->LinkInterfaceMap) { + for (auto const& hmi : hmp.second) { + if (!hmi.second.LibrariesDone) { + continue; + } + for (cmLinkItem const& item : hmi.second.Libraries) { + if (!this->VerifyLinkItemColons(LinkItemRole::Interface, item)) { + return; + } + if (linkLibrariesOnlyTargets && + !this->VerifyLinkItemIsTarget(LinkItemRole::Interface, item)) { + return; + } + } + } + } +} + +namespace { +cm::string_view missingTargetPossibleReasons = + "Possible reasons include:\n" + " * There is a typo in the target name.\n" + " * A find_package call is missing for an IMPORTED target.\n" + " * An ALIAS target is missing.\n"_s; +} + +bool cmGeneratorTarget::VerifyLinkItemColons(LinkItemRole role, + cmLinkItem const& item) const +{ + if (item.Target || item.AsStr().find("::") == std::string::npos) { + return true; + } + MessageType messageType = MessageType::FATAL_ERROR; + std::string e; + switch (this->GetLocalGenerator()->GetPolicyStatus(cmPolicies::CMP0028)) { + case cmPolicies::WARN: { + e = cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0028), "\n"); + messageType = MessageType::AUTHOR_WARNING; + } break; + case cmPolicies::OLD: + return true; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Issue the fatal message. + break; + } + + if (role == LinkItemRole::Implementation) { + e = cmStrCat(e, "Target \"", this->GetName(), "\" links to"); + } else { + e = cmStrCat(e, "The link interface of target \"", this->GetName(), + "\" contains"); + } + e = + cmStrCat(e, ":\n ", item.AsStr(), "\n", "but the target was not found. ", + missingTargetPossibleReasons); + cmListFileBacktrace backtrace = item.Backtrace; + if (backtrace.Empty()) { + backtrace = this->GetBacktrace(); + } + this->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(messageType, e, + backtrace); + return false; +} + +bool cmGeneratorTarget::VerifyLinkItemIsTarget(LinkItemRole role, + cmLinkItem const& item) const +{ + if (item.Target) { + return true; + } + std::string const& str = item.AsStr(); + if (!str.empty() && + (str[0] == '-' || str[0] == '$' || str[0] == '`' || + str.find_first_of("/\\") != std::string::npos)) { + return true; + } + + std::string e = cmStrCat("Target \"", this->GetName(), + "\" has LINK_LIBRARIES_ONLY_TARGETS enabled, but ", + role == LinkItemRole::Implementation + ? "it links to" + : "its link interface contains", + ":\n ", item.AsStr(), "\nwhich is not a target. ", + missingTargetPossibleReasons); + cmListFileBacktrace backtrace = item.Backtrace; + if (backtrace.Empty()) { + backtrace = this->GetBacktrace(); + } + this->LocalGenerator->GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, e, backtrace); + return false; +} + void cmGeneratorTarget::GetTargetVersion(int& major, int& minor) const { int patch; @@ -6368,7 +6655,7 @@ bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n, cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( std::string const& n, cmListFileBacktrace const& bt, - LookupLinkItemScope* scope) const + LookupLinkItemScope* scope, LookupSelf lookupSelf) const { cm::optional<cmLinkItem> maybeItem; if (this->IsLinkLookupScope(n, scope->LG)) { @@ -6376,62 +6663,80 @@ cm::optional<cmLinkItem> cmGeneratorTarget::LookupLinkItem( } std::string name = this->CheckCMP0004(n); - if (name == this->GetName() || name.empty()) { + if (name.empty() || + (lookupSelf == LookupSelf::No && name == this->GetName())) { return maybeItem; } maybeItem = this->ResolveLinkItem(BT<std::string>(name, bt), scope->LG); return maybeItem; } -void cmGeneratorTarget::ExpandLinkItems(std::string const& prop, - std::string const& value, - std::string const& config, - cmGeneratorTarget const* headTarget, - bool usage_requirements_only, - cmLinkInterface& iface) const +void cmGeneratorTarget::ExpandLinkItems( + std::string const& prop, cmBTStringRange entries, std::string const& config, + cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor, + LinkInterfaceField field, cmLinkInterface& iface) const { + if (entries.empty()) { + return; + } // Keep this logic in sync with ComputeLinkImplementationLibraries. - cmGeneratorExpression ge; cmGeneratorExpressionDAGChecker dagChecker(this, prop, nullptr, nullptr); // The $<LINK_ONLY> expression may be in a link interface to specify // private link dependencies that are otherwise excluded from usage // requirements. - if (usage_requirements_only) { + if (interfaceFor == LinkInterfaceFor::Usage) { dagChecker.SetTransitivePropertiesOnly(); } - std::vector<std::string> libs; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(value); - cge->SetEvaluateForBuildsystem(true); - cmExpandList(cge->Evaluate(this->LocalGenerator, config, headTarget, - &dagChecker, this, headTarget->LinkerLanguage), - libs); cmMakefile const* mf = this->LocalGenerator->GetMakefile(); LookupLinkItemScope scope{ this->LocalGenerator }; - for (std::string const& lib : libs) { - if (cm::optional<cmLinkItem> maybeItem = - this->LookupLinkItem(lib, cge->GetBacktrace(), &scope)) { - cmLinkItem item = std::move(*maybeItem); - - if (!item.Target) { - // Report explicitly linked object files separately. - std::string const& maybeObj = item.AsStr(); - if (cmSystemTools::FileIsFullPath(maybeObj)) { - cmSourceFile const* sf = - mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); - if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { - iface.Objects.emplace_back(std::move(item)); - continue; + for (BT<std::string> const& entry : entries) { + cmGeneratorExpression ge(entry.Backtrace); + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value); + cge->SetEvaluateForBuildsystem(true); + std::vector<std::string> libs = cmExpandedList( + cge->Evaluate(this->LocalGenerator, config, headTarget, &dagChecker, + this, headTarget->LinkerLanguage)); + for (std::string const& lib : libs) { + if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( + lib, cge->GetBacktrace(), &scope, + field == LinkInterfaceField::Libraries ? LookupSelf::No + : LookupSelf::Yes)) { + cmLinkItem item = std::move(*maybeItem); + + if (field == LinkInterfaceField::HeadInclude) { + iface.HeadInclude.emplace_back(std::move(item)); + continue; + } + if (field == LinkInterfaceField::HeadExclude) { + iface.HeadExclude.emplace_back(std::move(item)); + continue; + } + if (!item.Target) { + // Report explicitly linked object files separately. + std::string const& maybeObj = item.AsStr(); + if (cmSystemTools::FileIsFullPath(maybeObj)) { + cmSourceFile const* sf = + mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); + if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { + iface.Objects.emplace_back(std::move(item)); + continue; + } } } - } - iface.Libraries.emplace_back(std::move(item)); + iface.Libraries.emplace_back(std::move(item)); + } + } + if (cge->GetHadHeadSensitiveCondition()) { + iface.HadHeadSensitiveCondition = true; + } + if (cge->GetHadContextSensitiveCondition()) { + iface.HadContextSensitiveCondition = true; + } + if (cge->GetHadLinkLanguageSensitiveCondition()) { + iface.HadLinkLanguageSensitiveCondition = true; } } - iface.HadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); - iface.HadContextSensitiveCondition = cge->GetHadContextSensitiveCondition(); - iface.HadLinkLanguageSensitiveCondition = - cge->GetHadLinkLanguageSensitiveCondition(); } cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( @@ -6446,7 +6751,8 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( { // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, false, secondPass); + return this->GetImportLinkInterface(config, head, LinkInterfaceFor::Link, + secondPass); } // Link interfaces are not supported for executables that do not @@ -6459,20 +6765,20 @@ cmLinkInterface const* cmGeneratorTarget::GetLinkInterface( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = this->GetHeadToLinkInterfaceMap(config); - if (secondPass) { - hm.erase(head); - } - // If the link interface does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + head = hm.begin()->first; } cmOptionalLinkInterface& iface = hm[head]; + if (secondPass) { + iface = cmOptionalLinkInterface(); + } if (!iface.LibrariesDone) { iface.LibrariesDone = true; - this->ComputeLinkInterfaceLibraries(config, iface, head, false); + this->ComputeLinkInterfaceLibraries(config, iface, head, + LinkInterfaceFor::Link); } if (!iface.AllDone) { iface.AllDone = true; @@ -6566,11 +6872,11 @@ void cmGeneratorTarget::ComputeLinkInterface( const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries( const std::string& config, cmGeneratorTarget const* head, - bool usage_requirements_only) const + LinkInterfaceFor interfaceFor) const { // Imported targets have their own link interface. if (this->IsImported()) { - return this->GetImportLinkInterface(config, head, usage_requirements_only); + return this->GetImportLinkInterface(config, head, interfaceFor); } // Link interfaces are not supported for executables that do not @@ -6582,21 +6888,20 @@ const cmLinkInterfaceLibraries* cmGeneratorTarget::GetLinkInterfaceLibraries( // Lookup any existing link interface for this configuration. cmHeadToLinkInterfaceMap& hm = - (usage_requirements_only + (interfaceFor == LinkInterfaceFor::Usage ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); // If the link interface does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + head = hm.begin()->first; } cmOptionalLinkInterface& iface = hm[head]; if (!iface.LibrariesDone) { iface.LibrariesDone = true; - this->ComputeLinkInterfaceLibraries(config, iface, head, - usage_requirements_only); + this->ComputeLinkInterfaceLibraries(config, iface, head, interfaceFor); } return iface.Exists ? &iface : nullptr; @@ -6857,7 +7162,7 @@ bool cmGeneratorTarget::GetRPATH(const std::string& config, void cmGeneratorTarget::ComputeLinkInterfaceLibraries( const std::string& config, cmOptionalLinkInterface& iface, - cmGeneratorTarget const* headTarget, bool usage_requirements_only) const + cmGeneratorTarget const* headTarget, LinkInterfaceFor interfaceFor) const { // Construct the property name suffix for this configuration. std::string suffix = "_"; @@ -6869,59 +7174,66 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // An explicit list of interface libraries may be set for shared // libraries and executables that export symbols. - cmValue explicitLibraries = nullptr; - std::string linkIfaceProp; + bool haveExplicitLibraries = false; + cmValue explicitLibrariesCMP0022OLD; + std::string linkIfacePropCMP0022OLD; bool const cmp0022NEW = (this->GetPolicyStatusCMP0022() != cmPolicies::OLD && this->GetPolicyStatusCMP0022() != cmPolicies::WARN); if (cmp0022NEW) { // CMP0022 NEW behavior is to use INTERFACE_LINK_LIBRARIES. - linkIfaceProp = "INTERFACE_LINK_LIBRARIES"; - explicitLibraries = this->GetProperty(linkIfaceProp); - } else if (this->GetType() == cmStateEnums::SHARED_LIBRARY || - this->IsExecutableWithExports()) { + haveExplicitLibraries = !this->Target->GetLinkInterfaceEntries().empty() || + !this->Target->GetLinkInterfaceDirectEntries().empty() || + !this->Target->GetLinkInterfaceDirectExcludeEntries().empty(); + } else { // CMP0022 OLD behavior is to use LINK_INTERFACE_LIBRARIES if set on a // shared lib or executable. - - // Lookup the per-configuration property. - linkIfaceProp = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix); - explicitLibraries = this->GetProperty(linkIfaceProp); - - // If not set, try the generic property. - if (!explicitLibraries) { - linkIfaceProp = "LINK_INTERFACE_LIBRARIES"; - explicitLibraries = this->GetProperty(linkIfaceProp); + if (this->GetType() == cmStateEnums::SHARED_LIBRARY || + this->IsExecutableWithExports()) { + // Lookup the per-configuration property. + linkIfacePropCMP0022OLD = cmStrCat("LINK_INTERFACE_LIBRARIES", suffix); + explicitLibrariesCMP0022OLD = this->GetProperty(linkIfacePropCMP0022OLD); + + // If not set, try the generic property. + if (!explicitLibrariesCMP0022OLD) { + linkIfacePropCMP0022OLD = "LINK_INTERFACE_LIBRARIES"; + explicitLibrariesCMP0022OLD = + this->GetProperty(linkIfacePropCMP0022OLD); + } } - } - if (explicitLibraries && - this->GetPolicyStatusCMP0022() == cmPolicies::WARN && - !this->PolicyWarnedCMP0022) { - // Compare the explicitly set old link interface properties to the - // preferred new link interface property one and warn if different. - cmValue newExplicitLibraries = - this->GetProperty("INTERFACE_LINK_LIBRARIES"); - if (newExplicitLibraries && - (*newExplicitLibraries != *explicitLibraries)) { - std::ostringstream w; - /* clang-format off */ - w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" - "Target \"" << this->GetName() << "\" has an " - "INTERFACE_LINK_LIBRARIES property which differs from its " << - linkIfaceProp << " properties." - "\n" - "INTERFACE_LINK_LIBRARIES:\n" - " " << *newExplicitLibraries << "\n" << - linkIfaceProp << ":\n" - " " << *explicitLibraries << "\n"; - /* clang-format on */ - this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); - this->PolicyWarnedCMP0022 = true; + if (explicitLibrariesCMP0022OLD && + this->GetPolicyStatusCMP0022() == cmPolicies::WARN && + !this->PolicyWarnedCMP0022) { + // Compare the explicitly set old link interface properties to the + // preferred new link interface property one and warn if different. + cmValue newExplicitLibraries = + this->GetProperty("INTERFACE_LINK_LIBRARIES"); + if (newExplicitLibraries && + (*newExplicitLibraries != *explicitLibrariesCMP0022OLD)) { + std::ostringstream w; + /* clang-format off */ + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0022) << "\n" + "Target \"" << this->GetName() << "\" has an " + "INTERFACE_LINK_LIBRARIES property which differs from its " << + linkIfacePropCMP0022OLD << " properties." + "\n" + "INTERFACE_LINK_LIBRARIES:\n" + " " << *newExplicitLibraries << "\n" << + linkIfacePropCMP0022OLD << ":\n" + " " << *explicitLibrariesCMP0022OLD << "\n"; + /* clang-format on */ + this->LocalGenerator->IssueMessage(MessageType::AUTHOR_WARNING, + w.str()); + this->PolicyWarnedCMP0022 = true; + } } + + haveExplicitLibraries = static_cast<bool>(explicitLibrariesCMP0022OLD); } // There is no implicit link interface for executables or modules // so if none was explicitly set then there is no link interface. - if (!explicitLibraries && + if (!haveExplicitLibraries && (this->GetType() == cmStateEnums::EXECUTABLE || (this->GetType() == cmStateEnums::MODULE_LIBRARY))) { return; @@ -6931,12 +7243,29 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( // If CMP0022 is NEW then the plain tll signature sets the // INTERFACE_LINK_LIBRARIES property. Even if the project // clears it, the link interface is still explicit. - iface.Explicit = cmp0022NEW || explicitLibraries; + iface.Explicit = cmp0022NEW || explicitLibrariesCMP0022OLD; - if (explicitLibraries) { - // The interface libraries have been explicitly set. - this->ExpandLinkItems(linkIfaceProp, *explicitLibraries, config, - headTarget, usage_requirements_only, iface); + if (cmp0022NEW) { + // The interface libraries are specified by INTERFACE_LINK_LIBRARIES. + // Use its special representation directly to get backtraces. + this->ExpandLinkItems( + kINTERFACE_LINK_LIBRARIES, this->Target->GetLinkInterfaceEntries(), + config, headTarget, interfaceFor, LinkInterfaceField::Libraries, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT, + this->Target->GetLinkInterfaceDirectEntries(), + config, headTarget, interfaceFor, + LinkInterfaceField::HeadInclude, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, + this->Target->GetLinkInterfaceDirectExcludeEntries(), + config, headTarget, interfaceFor, + LinkInterfaceField::HeadExclude, iface); + } else if (explicitLibrariesCMP0022OLD) { + // The interface libraries have been explicitly set in pre-CMP0022 style. + std::vector<BT<std::string>> entries; + entries.emplace_back(*explicitLibrariesCMP0022OLD); + this->ExpandLinkItems(linkIfacePropCMP0022OLD, cmMakeRange(entries), + config, headTarget, interfaceFor, + LinkInterfaceField::Libraries, iface); } // If the link interface is explicit, do not fall back to the link impl. @@ -6950,15 +7279,14 @@ void cmGeneratorTarget::ComputeLinkInterfaceLibraries( iface.Libraries.insert(iface.Libraries.end(), impl->Libraries.begin(), impl->Libraries.end()); if (this->GetPolicyStatusCMP0022() == cmPolicies::WARN && - !this->PolicyWarnedCMP0022 && !usage_requirements_only) { + !this->PolicyWarnedCMP0022 && interfaceFor == LinkInterfaceFor::Link) { // Compare the link implementation fallback link interface to the // preferred new link interface property and warn if different. cmLinkInterface ifaceNew; - static const std::string newProp = "INTERFACE_LINK_LIBRARIES"; - if (cmValue newExplicitLibraries = this->GetProperty(newProp)) { - this->ExpandLinkItems(newProp, *newExplicitLibraries, config, - headTarget, usage_requirements_only, ifaceNew); - } + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES, + this->Target->GetLinkInterfaceEntries(), config, + headTarget, interfaceFor, + LinkInterfaceField::Libraries, ifaceNew); if (ifaceNew.Libraries != iface.Libraries) { std::string oldLibraries = cmJoin(impl->Libraries, ";"); std::string newLibraries = cmJoin(ifaceNew.Libraries, ";"); @@ -7071,7 +7399,7 @@ void cmGeneratorTarget::ComputeLinkImplementationRuntimeLibraries( const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( const std::string& config, cmGeneratorTarget const* headTarget, - bool usage_requirements_only, bool secondPass) const + LinkInterfaceFor interfaceFor, bool secondPass) const { cmGeneratorTarget::ImportInfo const* info = this->GetImportInfo(config); if (!info) { @@ -7079,32 +7407,41 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( } cmHeadToLinkInterfaceMap& hm = - (usage_requirements_only + (interfaceFor == LinkInterfaceFor::Usage ? this->GetHeadToLinkInterfaceUsageRequirementsMap(config) : this->GetHeadToLinkInterfaceMap(config)); - if (secondPass) { - hm.erase(headTarget); - } - // If the link interface does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + headTarget = hm.begin()->first; } cmOptionalLinkInterface& iface = hm[headTarget]; + if (secondPass) { + iface = cmOptionalLinkInterface(); + } if (!iface.AllDone) { iface.AllDone = true; + iface.LibrariesDone = true; iface.Multiplicity = info->Multiplicity; cmExpandList(info->Languages, iface.Languages); - this->ExpandLinkItems(info->LibrariesProp, info->Libraries, config, - headTarget, usage_requirements_only, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT, + cmMakeRange(info->LibrariesHeadInclude), config, + headTarget, interfaceFor, + LinkInterfaceField::HeadInclude, iface); + this->ExpandLinkItems(kINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, + cmMakeRange(info->LibrariesHeadExclude), config, + headTarget, interfaceFor, + LinkInterfaceField::HeadExclude, iface); + this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries), + config, headTarget, interfaceFor, + LinkInterfaceField::Libraries, iface); std::vector<std::string> deps = cmExpandedList(info->SharedDeps); LookupLinkItemScope scope{ this->LocalGenerator }; for (std::string const& dep : deps) { - if (cm::optional<cmLinkItem> maybeItem = - this->LookupLinkItem(dep, cmListFileBacktrace(), &scope)) { + if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( + dep, cmListFileBacktrace(), &scope, LookupSelf::No)) { iface.SharedDeps.emplace_back(std::move(*maybeItem)); } } @@ -7170,24 +7507,35 @@ void cmGeneratorTarget::ComputeImportInfo(std::string const& desired_config, // Get the link interface. { - std::string linkProp = "INTERFACE_LINK_LIBRARIES"; - cmValue propertyLibs = this->GetProperty(linkProp); - - if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { - if (!propertyLibs) { - linkProp = cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix); - propertyLibs = this->GetProperty(linkProp); + // Use the INTERFACE_LINK_LIBRARIES special representation directly + // to get backtraces. + cmBTStringRange entries = this->Target->GetLinkInterfaceEntries(); + if (!entries.empty()) { + info.LibrariesProp = "INTERFACE_LINK_LIBRARIES"; + for (BT<std::string> const& entry : entries) { + info.Libraries.emplace_back(entry); } - + } else if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { + std::string linkProp = + cmStrCat("IMPORTED_LINK_INTERFACE_LIBRARIES", suffix); + cmValue propertyLibs = this->GetProperty(linkProp); if (!propertyLibs) { linkProp = "IMPORTED_LINK_INTERFACE_LIBRARIES"; propertyLibs = this->GetProperty(linkProp); } + if (propertyLibs) { + info.LibrariesProp = linkProp; + info.Libraries.emplace_back(*propertyLibs); + } } - if (propertyLibs) { - info.LibrariesProp = linkProp; - info.Libraries = *propertyLibs; - } + } + for (BT<std::string> const& entry : + this->Target->GetLinkInterfaceDirectEntries()) { + info.LibrariesHeadInclude.emplace_back(entry); + } + for (BT<std::string> const& entry : + this->Target->GetLinkInterfaceDirectExcludeEntries()) { + info.LibrariesHeadExclude.emplace_back(entry); } if (this->GetType() == cmStateEnums::INTERFACE_LIBRARY) { if (loc) { @@ -7549,6 +7897,11 @@ bool cmGeneratorTarget::IsCSharpOnly() const return languages.size() == 1 && languages.count("CSharp") > 0; } +bool cmGeneratorTarget::IsDotNetSdkTarget() const +{ + return !this->GetProperty("DOTNET_SDK").IsEmpty(); +} + void cmGeneratorTarget::ComputeLinkImplementationLanguages( const std::string& config, cmOptionalLinkImplementation& impl) const { @@ -7598,9 +7951,9 @@ cmGeneratorTarget::GetLinkImplementationLibrariesInternal( this->LinkImplMap[cmSystemTools::UpperCase(config)]; // If the link implementation does not depend on the head target - // then return the one we computed first. + // then re-use the one from the head we computed first. if (!hm.empty() && !hm.begin()->second.HadHeadSensitiveCondition) { - return &hm.begin()->second; + head = hm.begin()->first; } cmOptionalLinkImplementation& impl = hm[head]; @@ -7617,6 +7970,112 @@ bool cmGeneratorTarget::IsNullImpliedByLinkLibraries( return cm::contains(this->LinkImplicitNullProperties, p); } +namespace { +class TransitiveLinkImpl +{ + cmGeneratorTarget const* Self; + std::string const& Config; + cmLinkImplementation& Impl; + + std::set<cmLinkItem> Emitted; + std::set<cmLinkItem> Excluded; + std::unordered_set<cmGeneratorTarget const*> Followed; + + void Follow(cmGeneratorTarget const* target); + +public: + TransitiveLinkImpl(cmGeneratorTarget const* self, std::string const& config, + cmLinkImplementation& impl) + : Self(self) + , Config(config) + , Impl(impl) + { + } + + void Compute(); +}; + +void TransitiveLinkImpl::Follow(cmGeneratorTarget const* target) +{ + if (!target || !this->Followed.insert(target).second || + target->GetPolicyStatusCMP0022() == cmPolicies::OLD || + target->GetPolicyStatusCMP0022() == cmPolicies::WARN) { + return; + } + + // Get this target's usage requirements. + cmLinkInterfaceLibraries const* iface = target->GetLinkInterfaceLibraries( + this->Config, this->Self, LinkInterfaceFor::Usage); + if (!iface) { + return; + } + if (iface->HadContextSensitiveCondition) { + this->Impl.HadContextSensitiveCondition = true; + } + + // Process 'INTERFACE_LINK_LIBRARIES_DIRECT' usage requirements. + for (cmLinkItem const& item : iface->HeadInclude) { + // Inject direct dependencies from the item's usage requirements + // before the item itself. + this->Follow(item.Target); + + // Add the item itself, but at most once. + if (this->Emitted.insert(item).second) { + this->Impl.Libraries.emplace_back(item, /* checkCMP0027= */ false); + } + } + + // Follow transitive dependencies. + for (cmLinkItem const& item : iface->Libraries) { + this->Follow(item.Target); + } + + // Record exclusions from 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE' + // usage requirements. + for (cmLinkItem const& item : iface->HeadExclude) { + this->Excluded.insert(item); + } +} + +void TransitiveLinkImpl::Compute() +{ + // Save the original items and start with an empty list. + std::vector<cmLinkImplItem> original = std::move(this->Impl.Libraries); + + // Avoid injecting any original items as usage requirements. + // This gives LINK_LIBRARIES final control over the order + // if it explicitly lists everything. + this->Emitted.insert(original.cbegin(), original.cend()); + + // Process each original item. + for (cmLinkImplItem& item : original) { + // Inject direct dependencies listed in 'INTERFACE_LINK_LIBRARIES_DIRECT' + // usage requirements before the item itself. + this->Follow(item.Target); + + // Add the item itself. + this->Impl.Libraries.emplace_back(std::move(item)); + } + + // Remove items listed in 'INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE' + // usage requirements found through any dependency above. + this->Impl.Libraries.erase( + std::remove_if(this->Impl.Libraries.begin(), this->Impl.Libraries.end(), + [this](cmLinkImplItem const& item) { + return this->Excluded.find(item) != this->Excluded.end(); + }), + this->Impl.Libraries.end()); +} + +void ComputeLinkImplTransitive(cmGeneratorTarget const* self, + std::string const& config, + cmLinkImplementation& impl) +{ + TransitiveLinkImpl transitiveLinkImpl(self, config, impl); + transitiveLinkImpl.Compute(); +} +} + void cmGeneratorTarget::ComputeLinkImplementationLibraries( const std::string& config, cmOptionalLinkImplementation& impl, cmGeneratorTarget const* head) const @@ -7637,7 +8096,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( std::string const& evaluated = cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, this->LinkerLanguage); - bool const fromGenex = evaluated != entry.Value; + bool const checkCMP0027 = evaluated != entry.Value; cmExpandList(evaluated, llibs); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; @@ -7711,7 +8170,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } } - impl.Libraries.emplace_back(std::move(item), fromGenex); + impl.Libraries.emplace_back(std::move(item), checkCMP0027); } std::set<std::string> const& seenProps = cge->GetSeenTargetProperties(); @@ -7723,6 +8182,11 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cge->GetMaxLanguageStandard(this, this->MaxLanguageStandards); } + // Update the list of direct link dependencies from usage requirements. + if (head == this) { + ComputeLinkImplTransitive(this, config, impl); + } + // Get the list of configurations considered to be DEBUG. std::vector<std::string> debugConfigs = this->Makefile->GetCMakeInstance()->GetDebugConfigs(); @@ -7804,6 +8268,26 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem(BT<std::string> const& name, return cmLinkItem(resolved.Target, false, bt); } +bool cmGeneratorTarget::HasPackageReferences() const +{ + return this->IsInBuildSystem() && + !this->GetProperty("VS_PACKAGE_REFERENCES")->empty(); +} + +std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const +{ + std::vector<std::string> packageReferences; + + if (this->IsInBuildSystem()) { + if (cmValue vsPackageReferences = + this->GetProperty("VS_PACKAGE_REFERENCES")) { + cmExpandList(*vsPackageReferences, packageReferences); + } + } + + return packageReferences; +} + std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const { if (OutputInfo const* info = this->GetOutputInfo(config)) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 9906963..45639c0 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -16,6 +16,7 @@ #include <cm/optional> +#include "cmAlgorithms.h" #include "cmLinkItem.h" #include "cmListFileCache.h" #include "cmPolicies.h" @@ -83,6 +84,10 @@ public: cmComputeLinkInformation* GetLinkInformation( const std::string& config) const; + // Perform validation checks on memoized link structures. + // Call this after generation is complete. + void CheckLinkLibraries() const; + cmStateEnums::TargetType GetType() const; const std::string& GetName() const; std::string GetExportName() const; @@ -237,14 +242,20 @@ public: cmOptionalLinkInterface& iface, const cmGeneratorTarget* head) const; + enum class LinkInterfaceFor + { + Usage, // Interface for usage requirements excludes $<LINK_ONLY>. + Link, // Interface for linking includes $<LINK_ONLY>. + }; + cmLinkInterfaceLibraries const* GetLinkInterfaceLibraries( const std::string& config, const cmGeneratorTarget* headTarget, - bool usage_requirements_only) const; + LinkInterfaceFor interfaceFor) const; void ComputeLinkInterfaceLibraries(const std::string& config, cmOptionalLinkInterface& iface, const cmGeneratorTarget* head, - bool usage_requirements_only) const; + LinkInterfaceFor interfaceFor) const; /** Get the library name for an imported interface library. */ std::string GetImportedLibName(std::string const& config) const; @@ -413,6 +424,9 @@ public: cmLinkItem ResolveLinkItem(BT<std::string> const& name, cmLocalGenerator const* lg) const; + bool HasPackageReferences() const; + std::vector<std::string> GetPackageReferences() const; + // Compute the set of languages compiled by the target. This is // computed every time it is called because the languages can change // when source file properties are changed and we do not have enough @@ -425,6 +439,8 @@ public: bool IsCSharpOnly() const; + bool IsDotNetSdkTarget() const; + void GetObjectLibrariesCMP0026( std::vector<cmGeneratorTarget*>& objlibs) const; @@ -651,6 +667,9 @@ public: */ void ClearSourcesCache(); + // Do not use. This is only for a specific call site with a FIXME comment. + void ClearLinkInterfaceCache(); + void AddSource(const std::string& src, bool before = false); void AddTracedSources(std::vector<std::string> const& srcs); @@ -781,7 +800,7 @@ public: std::string EvaluateInterfaceProperty( std::string const& prop, cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagCheckerParent, - bool usage_requirements_only = true) const; + LinkInterfaceFor interfaceFor = LinkInterfaceFor::Usage) const; bool HaveInstallTreeRPATH(const std::string& config) const; @@ -966,6 +985,14 @@ private: cmLinkImplementation const* GetLinkImplementation(const std::string& config, bool secondPass) const; + enum class LinkItemRole + { + Implementation, + Interface, + }; + bool VerifyLinkItemIsTarget(LinkItemRole role, cmLinkItem const& item) const; + bool VerifyLinkItemColons(LinkItemRole role, cmLinkItem const& item) const; + // Cache import information from properties for each configuration. struct ImportInfo { @@ -977,8 +1004,10 @@ private: std::string ImportLibrary; std::string LibName; std::string Languages; - std::string Libraries; std::string LibrariesProp; + std::vector<BT<std::string>> Libraries; + std::vector<BT<std::string>> LibrariesHeadInclude; + std::vector<BT<std::string>> LibrariesHeadExclude; std::string SharedDeps; }; @@ -994,7 +1023,7 @@ private: cmLinkInterface const* GetImportLinkInterface(const std::string& config, const cmGeneratorTarget* head, - bool usage_requirements_only, + LinkInterfaceFor interfaceFor, bool secondPass = false) const; using KindedSourcesMapType = std::map<std::string, KindedSources>; @@ -1008,7 +1037,7 @@ private: mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists; bool MaybeHaveInterfaceProperty(std::string const& prop, cmGeneratorExpressionContext* context, - bool usage_requirements_only) const; + LinkInterfaceFor interfaceFor) const; using TargetPropertyEntryVector = std::vector<std::unique_ptr<TargetPropertyEntry>>; @@ -1039,19 +1068,31 @@ private: bool IsLinkLookupScope(std::string const& n, cmLocalGenerator const*& lg) const; - void ExpandLinkItems(std::string const& prop, std::string const& value, + enum class LinkInterfaceField + { + Libraries, + HeadExclude, + HeadInclude, + }; + void ExpandLinkItems(std::string const& prop, cmBTStringRange entries, std::string const& config, const cmGeneratorTarget* headTarget, - bool usage_requirements_only, + LinkInterfaceFor interfaceFor, LinkInterfaceField field, cmLinkInterface& iface) const; struct LookupLinkItemScope { cmLocalGenerator const* LG; }; + enum class LookupSelf + { + No, + Yes, + }; cm::optional<cmLinkItem> LookupLinkItem(std::string const& n, cmListFileBacktrace const& bt, - LookupLinkItemScope* scope) const; + LookupLinkItemScope* scope, + LookupSelf lookupSelf) const; std::vector<BT<std::string>> GetSourceFilePaths( std::string const& config) const; diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 162860a..4a25311 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -7,7 +7,6 @@ #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" #include "cmInstalledFile.h" -#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" @@ -23,8 +22,6 @@ #include "cmValue.h" #include "cmake.h" -class cmMessenger; - namespace { enum OutType { @@ -187,7 +184,8 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, status.GetMakefile().GetState()->GetPropertyDefinition(propertyName, scope)) { output = def->GetShortDescription(); - } else { + } + if (output.empty()) { output = "NOTFOUND"; } status.GetMakefile().AddDefinition(variable, output); @@ -198,7 +196,8 @@ bool cmGetPropertyCommand(std::vector<std::string> const& args, status.GetMakefile().GetState()->GetPropertyDefinition(propertyName, scope)) { output = def->GetFullDescription(); - } else { + } + if (output.empty()) { output = "NOTFOUND"; } status.GetMakefile().AddDefinition(variable, output); @@ -365,9 +364,8 @@ bool HandleTargetMode(cmExecutionStatus& status, const std::string& name, } return StoreResult(infoType, status.GetMakefile(), variable, nullptr); } - cmListFileBacktrace bt = status.GetMakefile().GetBacktrace(); - cmMessenger* messenger = status.GetMakefile().GetMessenger(); - cmValue prop = target->GetComputedProperty(propertyName, messenger, bt); + cmValue prop = + target->GetComputedProperty(propertyName, status.GetMakefile()); if (!prop) { prop = target->GetProperty(propertyName); } diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx index 12c8221..e1ae9b2 100644 --- a/Source/cmGetTargetPropertyCommand.cxx +++ b/Source/cmGetTargetPropertyCommand.cxx @@ -6,15 +6,12 @@ #include "cmExecutionStatus.h" #include "cmGlobalGenerator.h" -#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" #include "cmTarget.h" #include "cmValue.h" -class cmMessenger; - bool cmGetTargetPropertyCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -43,9 +40,7 @@ bool cmGetTargetPropertyCommand(std::vector<std::string> const& args, } } else if (!args[2].empty()) { cmValue prop_cstr = nullptr; - cmListFileBacktrace bt = mf.GetBacktrace(); - cmMessenger* messenger = mf.GetMessenger(); - prop_cstr = tgt->GetComputedProperty(args[2], messenger, bt); + prop_cstr = tgt->GetComputedProperty(args[2], mf); if (!prop_cstr) { prop_cstr = tgt->GetProperty(args[2]); } diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx index 9ac5cd5..89c5b01 100644 --- a/Source/cmGlobVerificationManager.cxx +++ b/Source/cmGlobVerificationManager.cxx @@ -8,11 +8,14 @@ #include "cmGeneratedFileStream.h" #include "cmListFileCache.h" +#include "cmMessageType.h" +#include "cmMessenger.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmVersion.h" -bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path) +bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path, + cmMessenger* messenger) { if (this->Cache.empty()) { return true; @@ -52,7 +55,7 @@ bool cmGlobVerificationManager::SaveVerificationScript(const std::string& path) for (auto const& bt : v.Backtraces) { verifyScriptFile << "# " << std::get<0>(bt); - std::get<1>(bt).PrintTitle(verifyScriptFile); + messenger->PrintBacktraceTitle(verifyScriptFile, std::get<1>(bt)); verifyScriptFile << "\n"; } @@ -145,7 +148,7 @@ void cmGlobVerificationManager::AddCacheEntry( const bool recurse, const bool listDirectories, const bool followSymlinks, const std::string& relative, const std::string& expression, const std::vector<std::string>& files, const std::string& variable, - const cmListFileBacktrace& backtrace) + const cmListFileBacktrace& backtrace, cmMessenger* messenger) { CacheEntryKey key = CacheEntryKey(recurse, listDirectories, followSymlinks, relative, expression); @@ -157,17 +160,17 @@ void cmGlobVerificationManager::AddCacheEntry( } else if (value.Initialized && value.Files != files) { std::ostringstream message; message << std::boolalpha; - message << "The glob expression\n"; + message << "The glob expression\n "; key.PrintGlobCommand(message, variable); - backtrace.PrintTitle(message); - message << "\nwas already present in the glob cache but the directory\n" + message << "\nwas already present in the glob cache but the directory " "contents have changed during the configuration run.\n"; message << "Matching glob expressions:"; for (auto const& bt : value.Backtraces) { message << "\n " << std::get<0>(bt); - std::get<1>(bt).PrintTitle(message); + messenger->PrintBacktraceTitle(message, std::get<1>(bt)); } - cmSystemTools::Error(message.str()); + messenger->IssueMessage(MessageType::FATAL_ERROR, message.str(), + backtrace); } else { value.Backtraces.emplace_back(variable, backtrace); } diff --git a/Source/cmGlobVerificationManager.h b/Source/cmGlobVerificationManager.h index b618fb0..52d71aa 100644 --- a/Source/cmGlobVerificationManager.h +++ b/Source/cmGlobVerificationManager.h @@ -12,6 +12,8 @@ #include "cmListFileCache.h" +class cmMessenger; + /** \class cmGlobVerificationManager * \brief Class for expressing build-time dependencies on glob expressions. * @@ -23,7 +25,7 @@ class cmGlobVerificationManager protected: //! Save verification script for given makefile. //! Saves to output <path>/<CMakeFilesDirectory>/VerifyGlobs.cmake - bool SaveVerificationScript(const std::string& path); + bool SaveVerificationScript(const std::string& path, cmMessenger* messenger); //! Add an entry into the glob cache void AddCacheEntry(bool recurse, bool listDirectories, bool followSymlinks, @@ -31,7 +33,7 @@ protected: const std::string& expression, const std::vector<std::string>& files, const std::string& variable, - const cmListFileBacktrace& bt); + const cmListFileBacktrace& bt, cmMessenger* messenger); //! Clear the glob cache for state reset. void Reset(); diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index b7bac9c..776ee40 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -2,14 +2,16 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalBorlandMakefileGenerator.h" +#include <ostream> #include <utility> #include <cm/memory> #include "cmDocumentationEntry.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmMessageType.h" #include "cmState.h" #include "cmake.h" @@ -69,12 +71,13 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalBorlandMakefileGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int /*jobs*/, bool verbose, + const std::string& config, int /*jobs*/, bool verbose, + const cmBuildOptions& buildOptions, std::vector<std::string> const& makeOptions) { return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( - makeProgram, projectName, projectDir, targetNames, config, fast, - cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions); + makeProgram, projectName, projectDir, targetNames, config, + cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, makeOptions); } void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice( diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index 5a4e8c2..a280b81 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -4,8 +4,16 @@ #include <iosfwd> #include <memory> +#include <string> +#include <vector> -#include "cmGlobalNMakeMakefileGenerator.h" +#include "cmGlobalGeneratorFactory.h" +#include "cmGlobalUnixMakefileGenerator3.h" + +class cmLocalGenerator; +class cmMakefile; +class cmake; +struct cmDocumentationEntry; /** \class cmGlobalBorlandMakefileGenerator * \brief Write a Borland makefiles. @@ -51,7 +59,8 @@ protected: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 97ad7ab..156ecce 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -38,7 +38,6 @@ #include "cmInstallGenerator.h" #include "cmInstallRuntimeDependencySet.h" #include "cmLinkLineComputer.h" -#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMSVC60LinkLineComputer.h" #include "cmMakefile.h" @@ -329,6 +328,18 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const return failed; } +void cmGlobalGenerator::CheckTargetLinkLibraries() const +{ + for (const auto& generator : this->LocalGenerators) { + for (const auto& gt : generator->GetGeneratorTargets()) { + gt->CheckLinkLibraries(); + } + for (const auto& gt : generator->GetOwnedImportedGeneratorTargets()) { + gt->CheckLinkLibraries(); + } + } +} + bool cmGlobalGenerator::CheckTargetsForType() const { if (!this->GetLanguageEnabled("Swift")) { @@ -337,6 +348,12 @@ bool cmGlobalGenerator::CheckTargetsForType() const bool failed = false; for (const auto& generator : this->LocalGenerators) { for (const auto& target : generator->GetGeneratorTargets()) { + std::string systemName = + target->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"); + if (systemName.find("Windows") == std::string::npos) { + continue; + } + if (target->GetType() == cmStateEnums::EXECUTABLE) { std::vector<std::string> const& configs = target->Makefile->GetGeneratorConfigs( @@ -1028,6 +1045,54 @@ void cmGlobalGenerator::CheckCompilerIdCompatibility( break; } } + + if (compilerId == "LCC") { + switch (mf->GetPolicyStatus(cmPolicies::CMP0129)) { + case cmPolicies::WARN: + if (!this->CMakeInstance->GetIsInTryCompile() && + mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0129")) { + std::ostringstream w; + /* clang-format off */ + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0129) << "\n" + "Converting " << lang << + R"( compiler id "LCC" to "GNU" for compatibility.)" + ; + /* clang-format on */ + mf->IssueMessage(MessageType::AUTHOR_WARNING, w.str()); + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + // OLD behavior is to convert LCC to GNU. + mf->AddDefinition(compilerIdVar, "GNU"); + if (lang == "C") { + mf->AddDefinition("CMAKE_COMPILER_IS_GNUCC", "1"); + } else if (lang == "CXX") { + mf->AddDefinition("CMAKE_COMPILER_IS_GNUCXX", "1"); + } else if (lang == "Fortran") { + mf->AddDefinition("CMAKE_COMPILER_IS_GNUG77", "1"); + } + { + // Fix compiler versions. + std::string version = "CMAKE_" + lang + "_COMPILER_VERSION"; + std::string emulated = "CMAKE_" + lang + "_SIMULATE_VERSION"; + std::string emulatedId = "CMAKE_" + lang + "_SIMULATE_ID"; + std::string const& actual = mf->GetRequiredDefinition(emulated); + mf->AddDefinition(version, actual); + mf->RemoveDefinition(emulatedId); + mf->RemoveDefinition(emulated); + } + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + mf->IssueMessage( + MessageType::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0129)); + CM_FALLTHROUGH; + case cmPolicies::NEW: + // NEW behavior is to keep LCC. + break; + } + } } std::string cmGlobalGenerator::GetLanguageOutputExtension( @@ -1264,7 +1329,7 @@ void cmGlobalGenerator::Configure() // update the cache entry for the number of local generators, this is used // for progress char num[100]; - sprintf(num, "%d", static_cast<int>(this->Makefiles.size())); + snprintf(num, sizeof(num), "%d", static_cast<int>(this->Makefiles.size())); this->GetCMakeInstance()->AddCacheEntry("CMAKE_NUMBER_OF_MAKEFILES", num, "number of local generators", cmStateEnums::INTERNAL); @@ -1553,6 +1618,9 @@ void cmGlobalGenerator::Generate() this->ExtraGenerator->Generate(); } + // Perform validation checks on memoized link structures. + this->CheckTargetLinkLibraries(); + if (!this->CMP0042WarnTargets.empty()) { std::ostringstream w; w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0042) << "\n"; @@ -1926,16 +1994,19 @@ int cmGlobalGenerator::TryCompile(int jobs, const std::string& srcdir, } std::string config = mf->GetSafeDefinition("CMAKE_TRY_COMPILE_CONFIGURATION"); + cmBuildOptions defaultBuildOptions(false, fast, PackageResolveMode::Disable); + return this->Build(jobs, srcdir, bindir, projectName, newTarget, output, "", - config, false, fast, false, this->TryCompileTimeout); + config, defaultBuildOptions, false, + this->TryCompileTimeout); } std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalGenerator::GenerateBuildCommand( const std::string& /*unused*/, const std::string& /*unused*/, const std::string& /*unused*/, std::vector<std::string> const& /*unused*/, - const std::string& /*unused*/, bool /*unused*/, int /*unused*/, - bool /*unused*/, std::vector<std::string> const& /*unused*/) + const std::string& /*unused*/, int /*unused*/, bool /*unused*/, + const cmBuildOptions& /*unused*/, std::vector<std::string> const& /*unused*/) { GeneratedMakeCommand makeCommand; makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented"); @@ -1953,7 +2024,7 @@ int cmGlobalGenerator::Build( int jobs, const std::string& /*unused*/, const std::string& bindir, const std::string& projectName, const std::vector<std::string>& targets, std::string& output, const std::string& makeCommandCSTR, - const std::string& config, bool clean, bool fast, bool verbose, + const std::string& config, const cmBuildOptions& buildOptions, bool verbose, cmDuration timeout, cmSystemTools::OutputOption outputflag, std::vector<std::string> const& nativeOptions) { @@ -1985,9 +2056,9 @@ int cmGlobalGenerator::Build( std::string outputBuffer; std::string* outputPtr = &outputBuffer; - std::vector<GeneratedMakeCommand> makeCommand = - this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, targets, - realConfig, fast, jobs, verbose, nativeOptions); + std::vector<GeneratedMakeCommand> makeCommand = this->GenerateBuildCommand( + makeCommandCSTR, projectName, bindir, targets, realConfig, jobs, verbose, + buildOptions, nativeOptions); // Workaround to convince some commands to produce output. if (outputflag == cmSystemTools::OUTPUT_PASSTHROUGH && @@ -1996,10 +2067,11 @@ int cmGlobalGenerator::Build( } // should we do a clean first? - if (clean) { + if (buildOptions.Clean) { std::vector<GeneratedMakeCommand> cleanCommand = this->GenerateBuildCommand(makeCommandCSTR, projectName, bindir, - { "clean" }, realConfig, fast, jobs, verbose); + { "clean" }, realConfig, jobs, verbose, + buildOptions); output += "\nRun Clean Command:"; output += cleanCommand.front().Printable(); output += "\n"; @@ -2824,13 +2896,11 @@ void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, cmTarget& target = tb.first; target.SetProperty("EXCLUDE_FROM_ALL", "TRUE"); - std::vector<std::string> no_outputs; - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; // Store the custom command in the target. - cmCustomCommand cc(no_outputs, no_byproducts, no_depends, gti.CommandLines, - cmListFileBacktrace(), nullptr, gti.WorkingDir.c_str(), - gti.StdPipesUTF8); + cmCustomCommand cc; + cc.SetCommandLines(gti.CommandLines); + cc.SetWorkingDirectory(gti.WorkingDir.c_str()); + cc.SetStdPipesUTF8(gti.StdPipesUTF8); cc.SetUsesTerminal(gti.UsesTerminal); target.AddPostBuildCommand(std::move(cc)); if (!gti.Message.empty()) { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 96696aa..a43d4a6 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -20,6 +20,7 @@ #include "cm_codecvt.hxx" +#include "cmBuildOptions.h" #include "cmCustomCommandLines.h" #include "cmDuration.h" #include "cmExportSet.h" @@ -229,8 +230,8 @@ public: int jobs, const std::string& srcdir, const std::string& bindir, const std::string& projectName, std::vector<std::string> const& targetNames, std::string& output, - const std::string& makeProgram, const std::string& config, bool clean, - bool fast, bool verbose, cmDuration timeout, + const std::string& makeProgram, const std::string& config, + const cmBuildOptions& buildOptions, bool verbose, cmDuration timeout, cmSystemTools::OutputOption outputflag = cmSystemTools::OUTPUT_NONE, std::vector<std::string> const& nativeOptions = std::vector<std::string>()); @@ -248,7 +249,8 @@ public: virtual std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()); virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const; @@ -684,6 +686,7 @@ private: virtual void ForceLinkerLanguages(); + void CheckTargetLinkLibraries() const; bool CheckTargetsForMissingSources() const; bool CheckTargetsForType() const; bool CheckTargetsForPchCompilePdb() const; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index b1c0488..5e51dd2 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalGhsMultiGenerator.h" -#include <algorithm> #include <map> #include <ostream> #include <utility> @@ -18,6 +17,7 @@ #include "cmLocalGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmState.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -29,10 +29,8 @@ const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj"; #ifdef __linux__ const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild"; -const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "/usr/ghs"; #elif defined(_WIN32) const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe"; -const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs"; #endif cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm) @@ -70,31 +68,21 @@ void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory( bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, bool build, cmMakefile* mf) { + /* In build mode nothing to be done. + * Toolset already determined and build tool absolute path is cached. + */ if (build) { return true; } - std::string tsp; /* toolset path */ + /* Determine the absolute directory for the toolset */ + std::string tsp; this->GetToolset(mf, tsp, ts); /* no toolset was found */ if (tsp.empty()) { return false; } - if (ts.empty()) { - std::string message; - message = cmStrCat( - "Green Hills MULTI: -T <toolset> not specified; defaulting to \"", tsp, - '"'); - cmSystemTools::Message(message); - - /* store the full toolset for later use - * -- already done if -T<toolset> was specified - */ - mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp, - "Location of generator toolset.", - cmStateEnums::INTERNAL); - } /* set the build tool to use */ std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") + @@ -102,13 +90,13 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, cmValue prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM"); /* check if the toolset changed from last generate */ - if (prevTool && (gbuild != *prevTool)) { - std::string message = + if (cmNonempty(prevTool) && !cmSystemTools::ComparePath(gbuild, prevTool)) { + std::string const& e = cmStrCat("toolset build tool: ", gbuild, - "\nDoes not match the previously used build tool: ", *prevTool, + "\nDoes not match the previously used build tool: ", prevTool, "\nEither remove the CMakeCache.txt file and CMakeFiles " "directory or choose a different binary directory."); - cmSystemTools::Error(message); + mf->IssueMessage(MessageType::FATAL_ERROR, e); return false; } @@ -124,58 +112,20 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p, cmMakefile* mf) { - std::string arch; - if (p.empty()) { - cmSystemTools::Message( - "Green Hills MULTI: -A <arch> not specified; defaulting to \"arm\""); - arch = "arm"; - - /* store the platform name for later use - * -- already done if -A<arch> was specified - */ - mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch, - "Name of generator platform.", - cmStateEnums::INTERNAL); - } else { - arch = p; - } - - /* check if OS location has been updated by platform scripts */ - std::string platform = mf->GetSafeDefinition("GHS_TARGET_PLATFORM"); - std::string osdir = mf->GetSafeDefinition("GHS_OS_DIR"); - if (cmIsOff(osdir) && platform.find("integrity") != std::string::npos) { - if (!this->CMakeInstance->GetIsInTryCompile()) { - /* required OS location is not found */ - std::string m = cmStrCat( - "Green Hills MULTI: GHS_OS_DIR not specified; No OS found in \"", - mf->GetSafeDefinition("GHS_OS_ROOT"), '"'); - cmSystemTools::Message(m); + /* set primary target */ + cmValue t = mf->GetDefinition("GHS_PRIMARY_TARGET"); + if (cmIsOff(t)) { + /* Use the value from `-A` or use `arm` */ + std::string arch = "arm"; + if (!cmIsOff(p)) { + arch = p; } - osdir = "GHS_OS_DIR-NOT-SPECIFIED"; - } else if (!this->CMakeInstance->GetIsInTryCompile() && - cmIsOff(this->OsDir) && !cmIsOff(osdir)) { - /* OS location was updated by auto-selection */ - std::string m = cmStrCat( - "Green Hills MULTI: GHS_OS_DIR not specified; found \"", osdir, '"'); - cmSystemTools::Message(m); - } - this->OsDir = osdir; - - // Determine GHS_BSP_NAME - std::string bspName = mf->GetSafeDefinition("GHS_BSP_NAME"); - - if (cmIsOff(bspName) && platform.find("integrity") != std::string::npos) { - bspName = "sim" + arch; - /* write back the calculate name for next time */ - mf->AddCacheDefinition("GHS_BSP_NAME", bspName, - "Name of GHS target platform.", - cmStateEnums::STRING, true); - std::string m = cmStrCat( - "Green Hills MULTI: GHS_BSP_NAME not specified; defaulting to \"", - bspName, '"'); - cmSystemTools::Message(m); - } + cmValue platform = mf->GetDefinition("GHS_TARGET_PLATFORM"); + std::string tgt = cmStrCat(arch, '_', platform, ".tgt"); + /* update the primary target name*/ + mf->AddDefinition("GHS_PRIMARY_TARGET", tgt); + } return true; } @@ -186,20 +136,6 @@ void cmGlobalGhsMultiGenerator::EnableLanguage( mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files - const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM")->c_str(); - if (!tgtPlatform) { - cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not " - "specified; defaulting to \"integrity\""); - tgtPlatform = "integrity"; - } - - /* store the platform name for later use */ - mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform, - "Name of GHS target platform.", cmStateEnums::STRING); - - /* store original OS location */ - this->OsDir = mf->GetSafeDefinition("GHS_OS_DIR"); - this->cmGlobalGenerator::EnableLanguage(l, mf, optional); } @@ -212,43 +148,59 @@ bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/) return true; } -void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd, +void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsp, const std::string& ts) { - cmValue ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT"); + /* Determine tsp - full path of the toolset from ts (toolset hint via -T) */ - if (cmNonempty(ghsRoot)) { - tsd = *ghsRoot; - } else { - tsd = DEFAULT_TOOLSET_ROOT; - } + std::string root = mf->GetSafeDefinition("GHS_TOOLSET_ROOT"); + // Check if `-T` was set by user if (ts.empty()) { + // Enter toolset search mode std::vector<std::string> output; - // Use latest? version - if (tsd.back() != '/') { - tsd += "/"; + // Make sure root exists... + if (!cmSystemTools::PathExists(root)) { + std::string msg = + "GHS_TOOLSET_ROOT directory \"" + root + "\" does not exist."; + mf->IssueMessage(MessageType::FATAL_ERROR, msg); + tsp = ""; + return; + } + + // Add a directory separator + if (root.back() != '/') { + root += "/"; } - cmSystemTools::Glob(tsd, "comp_[^;]+", output); + + // Get all compiler directories in toolset root + cmSystemTools::Glob(root, "comp_[^;]+", output); if (output.empty()) { + // No compiler directories found std::string msg = - "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + tsd + "\"."; - cmSystemTools::Error(msg); - tsd = ""; + "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + root + "\"."; + mf->IssueMessage(MessageType::FATAL_ERROR, msg); + tsp = ""; } else { - tsd += output.back(); + // Use latest? version + tsp = root + output.back(); } + } else { + // Toolset was provided by user std::string tryPath; - tryPath = cmSystemTools::CollapseFullPath(ts, tsd); + + // NOTE: CollapseFullPath() will determine if user toolset was full path or + // or relative path. + tryPath = cmSystemTools::CollapseFullPath(ts, root); if (!cmSystemTools::FileExists(tryPath)) { - std::string msg = "GHS toolset \"" + tryPath + "\" not found."; - cmSystemTools::Error(msg); - tsd = ""; + std::string msg = "GHS toolset \"" + tryPath + "\" does not exist."; + mf->IssueMessage(MessageType::FATAL_ERROR, msg); + tsp = ""; } else { - tsd = tryPath; + tsp = tryPath; } } } @@ -333,25 +285,25 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout, fout << "# Top Level Project File\n"; // Specify BSP option if supplied by user - cmValue bspName = - this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME"); + // -- not all platforms require this entry in the project file + cmValue bspName = root->GetMakefile()->GetDefinition("GHS_BSP_NAME"); if (!cmIsOff(bspName)) { fout << " -bsp " << *bspName << '\n'; } // Specify OS DIR if supplied by user // -- not all platforms require this entry in the project file - if (!cmIsOff(this->OsDir)) { + cmValue osDir = root->GetMakefile()->GetDefinition("GHS_OS_DIR"); + if (!cmIsOff(osDir)) { cmValue osDirOption = - this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION"); - std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/'); + root->GetMakefile()->GetDefinition("GHS_OS_DIR_OPTION"); fout << " "; if (cmIsOff(osDirOption)) { fout << ""; } else { fout << *osDirOption; } - fout << "\"" << this->OsDir << "\"\n"; + fout << "\"" << osDir << "\"\n"; } } @@ -558,7 +510,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalGhsMultiGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/, + const std::string& /*config*/, int jobs, bool /*verbose*/, + const cmBuildOptions& /*buildOptions*/, std::vector<std::string> const& makeOptions) { GeneratedMakeCommand makeCommand = {}; @@ -616,8 +569,7 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout, cmLocalGenerator* root) { fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n'; - cmValue ghsGpjMacros = - this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS"); + cmValue ghsGpjMacros = root->GetMakefile()->GetDefinition("GHS_GPJ_MACROS"); if (ghsGpjMacros) { std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros); for (std::string const& arg : expandedList) { @@ -629,20 +581,8 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout, void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( cmLocalGenerator* root, std::ostream& fout) { - /* set primary target */ - std::string tgt; - cmValue t = - this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET"); - if (cmNonempty(t)) { - tgt = *t; - this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET"); - } else { - cmValue a = - this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM"); - cmValue p = - this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM"); - tgt = cmStrCat((a ? *a : ""), '_', (p ? *p : ""), ".tgt"); - } + /* put primary target and customization files into project file */ + cmValue const tgt = root->GetMakefile()->GetDefinition("GHS_PRIMARY_TARGET"); /* clang-format off */ fout << "primaryTarget=" << tgt << "\n" @@ -653,7 +593,7 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( /* clang-format on */ cmValue const customization = - this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION"); + root->GetMakefile()->GetDefinition("GHS_CUSTOMIZATION"); if (cmNonempty(customization)) { fout << "customization=" << cmGlobalGhsMultiGenerator::TrimQuotes(*customization) << '\n'; diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index bd08301..26ea3c7 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "cmBuildOptions.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmTargetDepend.h" @@ -87,7 +88,8 @@ protected: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; @@ -112,9 +114,7 @@ private: static std::string TrimQuotes(std::string str); - std::string OsDir; static const char* DEFAULT_BUILD_PROGRAM; - static const char* DEFAULT_TOOLSET_ROOT; bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build); diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index 40deebb..1a625cc 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -2,8 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalJOMMakefileGenerator.h" +#include <ostream> + +#include <cmext/algorithm> + #include "cmDocumentationEntry.h" -#include "cmLocalUnixMakefileGenerator3.h" +#include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" #include "cmake.h" @@ -59,7 +63,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalJOMMakefileGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions, std::vector<std::string> const& makeOptions) { std::vector<std::string> jomMakeOptions; @@ -77,6 +82,6 @@ cmGlobalJOMMakefileGenerator::GenerateBuildCommand( } return cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( - makeProgram, projectName, projectDir, targetNames, config, fast, jobs, - verbose, jomMakeOptions); + makeProgram, projectName, projectDir, targetNames, config, jobs, verbose, + buildOptions, jomMakeOptions); } diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h index 58860dd..332d1cf 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -4,8 +4,16 @@ #include <iosfwd> #include <memory> +#include <string> +#include <vector> +#include "cmGlobalGeneratorFactory.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmValue.h" + +class cmMakefile; +class cmake; +struct cmDocumentationEntry; /** \class cmGlobalJOMMakefileGenerator * \brief Write a JOM makefiles. @@ -44,7 +52,8 @@ protected: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx index ae9d5a7..c8520b8 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.cxx +++ b/Source/cmGlobalMSYSMakefileGenerator.cxx @@ -5,10 +5,10 @@ #include "cmsys/FStream.hxx" #include "cmDocumentationEntry.h" -#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" -#include "cmMessageType.h" #include "cmState.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmake.h" cmGlobalMSYSMakefileGenerator::cmGlobalMSYSMakefileGenerator(cmake* cm) diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h index 1a47b4f..586487f 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.h +++ b/Source/cmGlobalMSYSMakefileGenerator.h @@ -3,9 +3,16 @@ #pragma once #include <memory> +#include <string> +#include <vector> +#include "cmGlobalGeneratorFactory.h" #include "cmGlobalUnixMakefileGenerator3.h" +class cmMakefile; +class cmake; +struct cmDocumentationEntry; + /** \class cmGlobalMSYSMakefileGenerator * \brief Write a NMake makefiles. * diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx index d9fc505..54d048d 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.cxx +++ b/Source/cmGlobalMinGWMakefileGenerator.cxx @@ -3,9 +3,9 @@ #include "cmGlobalMinGWMakefileGenerator.h" #include "cmDocumentationEntry.h" -#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmState.h" +#include "cmSystemTools.h" #include "cmake.h" cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator(cmake* cm) diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h index ffc9ebe..1574faf 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.h +++ b/Source/cmGlobalMinGWMakefileGenerator.h @@ -3,9 +3,16 @@ #pragma once #include <memory> +#include <string> +#include <vector> +#include "cmGlobalGeneratorFactory.h" #include "cmGlobalUnixMakefileGenerator3.h" +class cmMakefile; +class cmake; +struct cmDocumentationEntry; + /** \class cmGlobalMinGWMakefileGenerator * \brief Write a NMake makefiles. * diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index a038f87..55748cf 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -2,13 +2,20 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalNMakeMakefileGenerator.h" +#include <ostream> + +#include <cmext/algorithm> + #include "cmsys/RegularExpression.hxx" #include "cmDocumentationEntry.h" #include "cmDuration.h" -#include "cmLocalUnixMakefileGenerator3.h" +#include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmState.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmake.h" cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator(cmake* cm) @@ -99,7 +106,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalNMakeMakefileGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int /*jobs*/, bool verbose, + const std::string& config, int /*jobs*/, bool verbose, + const cmBuildOptions& buildOptions, std::vector<std::string> const& makeOptions) { std::vector<std::string> nmakeMakeOptions; @@ -110,8 +118,8 @@ cmGlobalNMakeMakefileGenerator::GenerateBuildCommand( cm::append(nmakeMakeOptions, makeOptions); return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( - makeProgram, projectName, projectDir, targetNames, config, fast, - cmake::NO_BUILD_PARALLEL_LEVEL, verbose, nmakeMakeOptions); + makeProgram, projectName, projectDir, targetNames, config, + cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, nmakeMakeOptions); } void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os, diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h index 4f202b5..b3574eb 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -4,8 +4,18 @@ #include <iosfwd> #include <memory> +#include <string> +#include <vector> +#include "cm_codecvt.hxx" + +#include "cmGlobalGeneratorFactory.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmValue.h" + +class cmMakefile; +class cmake; +struct cmDocumentationEntry; /** \class cmGlobalNMakeMakefileGenerator * \brief Write a NMake makefiles. @@ -48,7 +58,8 @@ protected: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 7122b9f..4245037 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -156,7 +156,7 @@ std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name) encoded += i; } else { char buf[16]; - sprintf(buf, ".%02x", static_cast<unsigned int>(i)); + snprintf(buf, sizeof(buf), ".%02x", static_cast<unsigned int>(i)); encoded += buf; } } @@ -166,14 +166,18 @@ std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name) std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string& lit) { std::string result = lit; - cmSystemTools::ReplaceString(result, "$", "$$"); - cmSystemTools::ReplaceString(result, "\n", "$\n"); + EncodeLiteralInplace(result); + return result; +} + +void cmGlobalNinjaGenerator::EncodeLiteralInplace(std::string& lit) +{ + cmSystemTools::ReplaceString(lit, "$", "$$"); + cmSystemTools::ReplaceString(lit, "\n", "$\n"); if (this->IsMultiConfig()) { - cmSystemTools::ReplaceString(result, - cmStrCat('$', this->GetCMakeCFGIntDir()), + cmSystemTools::ReplaceString(lit, cmStrCat('$', this->GetCMakeCFGIntDir()), this->GetCMakeCFGIntDir()); } - return result; } std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path) @@ -185,7 +189,7 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string& path) else std::replace(result.begin(), result.end(), '/', '\\'); #endif - result = this->EncodeLiteral(result); + this->EncodeLiteralInplace(result); cmSystemTools::ReplaceString(result, " ", "$ "); cmSystemTools::ReplaceString(result, ":", "$:"); return result; @@ -955,7 +959,7 @@ cmGlobalNinjaGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& /*projectName*/, const std::string& /*projectDir*/, std::vector<std::string> const& targetNames, const std::string& config, - bool /*fast*/, int jobs, bool verbose, + int jobs, bool verbose, const cmBuildOptions& /*buildOptions*/, std::vector<std::string> const& makeOptions) { GeneratedMakeCommand makeCommand; @@ -1021,6 +1025,19 @@ bool cmGlobalNinjaGenerator::OpenBuildFileStreams() return false; } + // New buffer size 8 MiB + constexpr auto buildFileStreamBufferSize = 8 * 1024 * 1024; + + // Ensure the buffer is allocated + if (!this->BuildFileStreamBuffer) { + this->BuildFileStreamBuffer = + cm::make_unique<char[]>(buildFileStreamBufferSize); + } + + // Enlarge the internal buffer of the `BuildFileStream` + this->BuildFileStream->rdbuf()->pubsetbuf(this->BuildFileStreamBuffer.get(), + buildFileStreamBufferSize); + // Write a comment about this file. *this->BuildFileStream << "# This file contains all the build statements describing the\n" diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 84fc06c..aa2df4d 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -18,6 +18,7 @@ #include "cm_codecvt.hxx" +#include "cmBuildOptions.h" #include "cmGeneratedFileStream.h" #include "cmGlobalCommonGenerator.h" #include "cmGlobalGeneratorFactory.h" @@ -77,6 +78,7 @@ public: static std::string EncodeRuleName(std::string const& name); std::string EncodeLiteral(const std::string& lit); + void EncodeLiteralInplace(std::string& lit); std::string EncodePath(const std::string& path); std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer( @@ -199,7 +201,8 @@ public: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; @@ -526,6 +529,7 @@ private: /// The file containing the build statement. (the relationship of the /// compilation DAG). std::unique_ptr<cmGeneratedFileStream> BuildFileStream; + std::unique_ptr<char[]> BuildFileStreamBuffer; /// The file containing the rule statements. (The action attached to each /// edge of the compilation DAG). std::unique_ptr<cmGeneratedFileStream> RulesFileStream; diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 0556540..ab9ca50 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -518,7 +518,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( const std::string& makeProgram, const std::string& /*projectName*/, const std::string& /*projectDir*/, std::vector<std::string> const& targetNames, const std::string& /*config*/, - bool fast, int jobs, bool verbose, + int jobs, bool verbose, const cmBuildOptions& buildOptions, std::vector<std::string> const& makeOptions) { GeneratedMakeCommand makeCommand; @@ -548,7 +548,7 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( makeCommand.Add(makeOptions.begin(), makeOptions.end()); for (auto tname : targetNames) { if (!tname.empty()) { - if (fast) { + if (buildOptions.Fast) { tname += "/fast"; } cmSystemTools::ConvertToOutputSlashes(tname); diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 94ee476..5157826 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -12,6 +12,7 @@ #include <string> #include <vector> +#include "cmBuildOptions.h" #include "cmGeneratorTarget.h" #include "cmGlobalCommonGenerator.h" #include "cmGlobalGeneratorFactory.h" @@ -163,7 +164,8 @@ public: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index 6cab492..db54b86 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -3,24 +3,35 @@ #include "cmGlobalVisualStudio10Generator.h" #include <algorithm> +#include <cstring> +#include <map> +#include <sstream> #include <utility> #include <cm/memory> #include <cm3p/json/reader.h> +#include <cm3p/json/value.h> #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmDocumentationEntry.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalGeneratorFactory.h" +#include "cmGlobalVisualStudio71Generator.h" +#include "cmGlobalVisualStudio7Generator.h" +#include "cmGlobalVisualStudioGenerator.h" +#include "cmIDEFlagTable.h" +#include "cmLocalGenerator.h" #include "cmLocalVisualStudio10Generator.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmVersion.h" #include "cmVisualStudioSlnData.h" #include "cmVisualStudioSlnParser.h" @@ -159,7 +170,7 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( this->DefaultNasmFlagTableName = "v10"; this->DefaultRCFlagTableName = "v10"; - this->Version = VS10; + this->Version = VSVersion::VS10; this->PlatformToolsetNeedsDebugEnum = false; } @@ -266,8 +277,8 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset( } this->SupportsUnityBuilds = - this->Version >= cmGlobalVisualStudioGenerator::VS16 || - (this->Version == cmGlobalVisualStudioGenerator::VS15 && + this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 || + (this->Version == cmGlobalVisualStudioGenerator::VSVersion::VS15 && cmSystemTools::PathExists(this->VCTargetsPath + "/Microsoft.Cpp.Unity.targets")); @@ -580,7 +591,7 @@ bool cmGlobalVisualStudio10Generator::InitializeWindowsCE(cmMakefile* mf) this->DefaultPlatformToolset = this->SelectWindowsCEToolset(); - if (this->GetVersion() == cmGlobalVisualStudioGenerator::VS12) { + if (this->GetVersion() == cmGlobalVisualStudioGenerator::VSVersion::VS12) { // VS 12 .NET CF defaults to .NET framework 3.9 for Windows CE. this->DefaultTargetFrameworkVersion = "v3.9"; this->DefaultTargetFrameworkIdentifier = "WindowsEmbeddedCompact"; @@ -713,6 +724,10 @@ void cmGlobalVisualStudio10Generator::Generate() /* clang-format on */ lg->IssueMessage(MessageType::WARNING, e.str()); } + if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue( + "CMAKE_VS_NUGET_PACKAGE_RESTORE")) { + this->CMakeInstance->MarkCliAsUsed("CMAKE_VS_NUGET_PACKAGE_RESTORE"); + } } void cmGlobalVisualStudio10Generator::EnableLanguage( @@ -1088,7 +1103,8 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalVisualStudio10Generator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions, std::vector<std::string> const& makeOptions) { std::vector<GeneratedMakeCommand> makeCommands; @@ -1118,7 +1134,7 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( slnFile += ".sln"; cmVisualStudioSlnParser parser; if (parser.ParseFile(slnFile, slnData, - cmVisualStudioSlnParser::DataGroupProjects)) { + cmVisualStudioSlnParser::DataGroupAll)) { std::vector<cmSlnProjectEntry> slnProjects = slnData.GetProjects(); for (cmSlnProjectEntry const& project : slnProjects) { if (useDevEnv) { @@ -1134,8 +1150,8 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( if (useDevEnv) { // Use devenv to build solutions containing Intel Fortran projects. return cmGlobalVisualStudio7Generator::GenerateBuildCommand( - makeProgram, projectName, projectDir, targetNames, config, fast, jobs, - verbose, makeOptions); + makeProgram, projectName, projectDir, targetNames, config, jobs, verbose, + buildOptions, makeOptions); } std::vector<std::string> realTargetNames = targetNames; @@ -1154,37 +1170,108 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( GeneratedMakeCommand makeCommand; makeCommand.RequiresOutputForward = requiresOutputForward; makeCommand.Add(makeProgramSelected); + cm::optional<cmSlnProjectEntry> proj = cm::nullopt; if (tname == "clean") { - makeCommand.Add(std::string(projectName) + ".sln"); + makeCommand.Add(cmStrCat(projectName, ".sln")); makeCommand.Add("/t:Clean"); } else { std::string targetProject = cmStrCat(tname, ".vcxproj"); + proj = slnData.GetProjectByName(tname); if (targetProject.find('/') == std::string::npos) { // it might be in a subdir - if (cmSlnProjectEntry const* proj = slnData.GetProjectByName(tname)) { + if (proj) { targetProject = proj->GetRelativePath(); cmSystemTools::ConvertToUnixSlashes(targetProject); } } - makeCommand.Add(std::move(targetProject)); + makeCommand.Add(targetProject); + + // Check if we do need a restore at all (i.e. if there are package + // references and restore has not been disabled by a command line option. + PackageResolveMode restoreMode = buildOptions.ResolveMode; + bool requiresRestore = true; + + if (restoreMode == PackageResolveMode::Disable) { + requiresRestore = false; + } else if (cmValue cached = + this->CMakeInstance->GetState()->GetCacheEntryValue( + tname + "_REQUIRES_VS_PACKAGE_RESTORE")) { + requiresRestore = cached.IsOn(); + } else { + // There are no package references defined. + requiresRestore = false; + } + + // If a restore is required, evaluate the restore mode. + if (requiresRestore) { + if (restoreMode == PackageResolveMode::OnlyResolve) { + // Only invoke the restore target on the project. + makeCommand.Add("/t:Restore"); + } else { + // Invoke restore target, unless it has been explicitly disabled. + bool restorePackages = true; + + if (this->Version < VSVersion::VS15) { + // Package restore is only supported starting from Visual Studio + // 2017. Package restore must be executed manually using NuGet + // shell for older versions. + this->CMakeInstance->IssueMessage( + MessageType::WARNING, + "Restoring package references is only supported for Visual " + "Studio 2017 and later. You have to manually restore the " + "packages using NuGet before building the project."); + restorePackages = false; + } else if (restoreMode == PackageResolveMode::Default) { + // Decide if a restore is performed, based on a cache variable. + if (cmValue cached = + this->CMakeInstance->GetState()->GetCacheEntryValue( + "CMAKE_VS_NUGET_PACKAGE_RESTORE")) + restorePackages = cached.IsOn(); + } + + if (restorePackages) { + if (this->IsMsBuildRestoreSupported()) { + makeCommand.Add("/restore"); + } else { + GeneratedMakeCommand restoreCommand; + restoreCommand.Add(makeProgramSelected); + restoreCommand.Add(targetProject); + restoreCommand.Add("/t:Restore"); + makeCommands.emplace_back(restoreCommand); + } + } + } + } } - std::string configArg = "/p:Configuration="; - if (!config.empty()) { - configArg += config; - } else { - configArg += "Debug"; + + std::string plainConfig = config; + if (config.empty()) { + plainConfig = "Debug"; + } + + std::string platform = GetPlatformName(); + if (proj) { + std::string extension = + cmSystemTools::GetFilenameLastExtension(proj->GetRelativePath()); + extension = cmSystemTools::LowerCase(extension); + if (extension.compare(".csproj") == 0) { + // Use correct platform name + platform = + slnData.GetConfigurationTarget(tname, plainConfig, platform); + } } - makeCommand.Add(configArg); - makeCommand.Add(std::string("/p:Platform=") + this->GetPlatformName()); - makeCommand.Add(std::string("/p:VisualStudioVersion=") + - this->GetIDEVersion()); + + makeCommand.Add(cmStrCat("/p:Configuration=", plainConfig)); + makeCommand.Add(cmStrCat("/p:Platform=", platform)); + makeCommand.Add( + cmStrCat("/p:VisualStudioVersion=", this->GetIDEVersion())); if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) { if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) { makeCommand.Add("/m"); } else { - makeCommand.Add(std::string("/m:") + std::to_string(jobs)); + makeCommand.Add(cmStrCat("/m:", std::to_string(jobs))); } // Having msbuild.exe and cl.exe using multiple jobs is discouraged makeCommand.Add("/p:CL_MPCount=1"); @@ -1192,7 +1279,7 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( // Respect the verbosity: 'n' normal will show build commands // 'm' minimal only the build step's title - makeCommand.Add(std::string("/v:") + ((verbose) ? "n" : "m")); + makeCommand.Add(cmStrCat("/v:", ((verbose) ? "n" : "m"))); makeCommand.Add(makeOptions.begin(), makeOptions.end()); makeCommands.emplace_back(std::move(makeCommand)); } @@ -1273,23 +1360,23 @@ std::string cmGlobalVisualStudio10Generator::Encoding() const char* cmGlobalVisualStudio10Generator::GetToolsVersion() const { switch (this->Version) { - case cmGlobalVisualStudioGenerator::VS9: - case cmGlobalVisualStudioGenerator::VS10: - case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: return "4.0"; // in Visual Studio 2013 they detached the MSBuild tools version // from the .Net Framework version and instead made it have it's own // version number - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: return "12.0"; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: return "14.0"; - case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: return "15.0"; - case cmGlobalVisualStudioGenerator::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: return "16.0"; - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: return "17.0"; } return ""; @@ -1548,6 +1635,18 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetNasmFlagTable() const return LoadFlagTable(std::string(), this->DefaultNasmFlagTableName, "NASM"); } +bool cmGlobalVisualStudio10Generator::IsMsBuildRestoreSupported() const +{ + if (this->Version >= VSVersion::VS16) { + return true; + } + + static std::string const vsVer15_7_5 = "15.7.27703.2042"; + cm::optional<std::string> vsVer = this->GetVSInstanceVersion(); + return (vsVer && + cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_7_5)); +} + std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const { std::string const& toolset = this->GetPlatformToolsetString(); diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 6e62390..4977a84 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -2,14 +2,25 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <cstddef> #include <memory> #include <set> +#include <string> +#include <vector> #include <cm/optional> #include <cm/string_view> #include "cmGlobalVisualStudio8Generator.h" +class cmGeneratorTarget; +class cmGlobalGeneratorFactory; +class cmLocalGenerator; +class cmMakefile; +class cmSourceFile; +class cmake; +struct cmIDEFlagTable; + /** \class cmGlobalVisualStudio10Generator * \brief Write a Unix makefiles. * @@ -32,7 +43,8 @@ public: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; @@ -161,6 +173,8 @@ public: cmIDEFlagTable const* GetMasmFlagTable() const; cmIDEFlagTable const* GetNasmFlagTable() const; + bool IsMsBuildRestoreSupported() const; + protected: cmGlobalVisualStudio10Generator(cmake* cm, const std::string& name, std::string const& platformInGeneratorName); diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx index a5ffcf0..10dc258 100644 --- a/Source/cmGlobalVisualStudio11Generator.cxx +++ b/Source/cmGlobalVisualStudio11Generator.cxx @@ -2,12 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio11Generator.h" +#include <cstring> +#include <sstream> #include <utility> +#include <vector> -#include "cmAlgorithms.h" #include "cmDocumentationEntry.h" -#include "cmLocalVisualStudio10Generator.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalGeneratorFactory.h" +#include "cmGlobalVisualStudioGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" static const char vs11generatorName[] = "Visual Studio 11 2012"; @@ -141,7 +148,7 @@ cmGlobalVisualStudio11Generator::cmGlobalVisualStudio11Generator( this->DefaultLinkFlagTableName = "v11"; this->DefaultMasmFlagTableName = "v11"; this->DefaultRCFlagTableName = "v11"; - this->Version = VS11; + this->Version = VSVersion::VS11; } bool cmGlobalVisualStudio11Generator::MatchesGeneratorName( diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h index b11905e..2f8a7f6 100644 --- a/Source/cmGlobalVisualStudio11Generator.h +++ b/Source/cmGlobalVisualStudio11Generator.h @@ -4,13 +4,14 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <iosfwd> #include <memory> #include <set> #include <string> +#include <cm/optional> + #include "cmGlobalVisualStudio10Generator.h" -#include "cmStateTypes.h" +#include "cmTransformDepfile.h" class cmGlobalGeneratorFactory; class cmMakefile; diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx index 8bdf356..12ffa5b 100644 --- a/Source/cmGlobalVisualStudio12Generator.cxx +++ b/Source/cmGlobalVisualStudio12Generator.cxx @@ -2,10 +2,18 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio12Generator.h" -#include "cmAlgorithms.h" +#include <cstring> +#include <sstream> +#include <vector> + #include "cmDocumentationEntry.h" -#include "cmLocalVisualStudio10Generator.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalGeneratorFactory.h" +#include "cmGlobalVisualStudioGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" static const char vs12generatorName[] = "Visual Studio 12 2013"; @@ -114,7 +122,7 @@ cmGlobalVisualStudio12Generator::cmGlobalVisualStudio12Generator( this->DefaultLinkFlagTableName = "v12"; this->DefaultMasmFlagTableName = "v12"; this->DefaultRCFlagTableName = "v12"; - this->Version = VS12; + this->Version = VSVersion::VS12; } bool cmGlobalVisualStudio12Generator::MatchesGeneratorName( diff --git a/Source/cmGlobalVisualStudio12Generator.h b/Source/cmGlobalVisualStudio12Generator.h index c220d40..a84756e 100644 --- a/Source/cmGlobalVisualStudio12Generator.h +++ b/Source/cmGlobalVisualStudio12Generator.h @@ -4,7 +4,6 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <iosfwd> #include <memory> #include <string> diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index ff1642f..9f94cca 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -2,11 +2,20 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio14Generator.h" +#include <cstring> +#include <sstream> + #include <cm/vector> #include "cmDocumentationEntry.h" -#include "cmLocalVisualStudio10Generator.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalGeneratorFactory.h" +#include "cmGlobalVisualStudioGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmValue.h" static const char vs14generatorName[] = "Visual Studio 14 2015"; @@ -116,7 +125,7 @@ cmGlobalVisualStudio14Generator::cmGlobalVisualStudio14Generator( this->DefaultLinkFlagTableName = "v140"; this->DefaultMasmFlagTableName = "v14"; this->DefaultRCFlagTableName = "v14"; - this->Version = VS14; + this->Version = VSVersion::VS14; } bool cmGlobalVisualStudio14Generator::MatchesGeneratorName( diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h index 7804b83..7fb9b4b 100644 --- a/Source/cmGlobalVisualStudio14Generator.h +++ b/Source/cmGlobalVisualStudio14Generator.h @@ -4,7 +4,6 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <iosfwd> #include <memory> #include <string> diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 50975ff..ce943a2 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -2,11 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio71Generator.h" -#include "cmDocumentationEntry.h" +#include <map> +#include <sstream> + #include "cmGeneratorTarget.h" -#include "cmLocalVisualStudio7Generator.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalVisualStudioGenerator.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" -#include "cmMessageType.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +class cmake; cmGlobalVisualStudio71Generator::cmGlobalVisualStudio71Generator( cmake* cm, const std::string& platformName) diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index cb3b8c1..0e7ddd0 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -2,7 +2,20 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <iosfwd> +#include <set> +#include <string> +#include <utility> +#include <vector> + #include "cmGlobalVisualStudio7Generator.h" +#include "cmValue.h" + +class cmGeneratorTarget; +class cmLocalGenerator; +class cmake; +template <typename T> +class BT; /** \class cmGlobalVisualStudio71Generator * \brief Write a Unix makefiles. diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 6876e61..134937e 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -2,6 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio7Generator.h" +#include <algorithm> +#include <cstdio> +#include <ostream> #include <utility> #include <vector> @@ -10,19 +13,22 @@ #include <windows.h> -#include <assert.h> - -#include "cmsys/Encoding.hxx" - #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" #include "cmLocalVisualStudio7Generator.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmState.h" +#include "cmStateTypes.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTargetDepend.h" #include "cmUuid.h" +#include "cmVisualStudioGeneratorOptions.h" #include "cmake.h" static cmVS7FlagTable cmVS7ExtraFlagTable[] = { @@ -206,7 +212,7 @@ cmGlobalVisualStudio7Generator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& /*projectDir*/, std::vector<std::string> const& targetNames, const std::string& config, - bool /*fast*/, int /*jobs*/, bool /*verbose*/, + int /*jobs*/, bool /*verbose*/, const cmBuildOptions& /*buildOptions*/, std::vector<std::string> const& makeOptions) { // Select the caller- or user-preferred make program, else devenv. @@ -298,7 +304,8 @@ void cmGlobalVisualStudio7Generator::Generate() GetSLNFile(this->LocalGenerators[0].get())); } - if (this->Version == VS10 && !this->CMakeInstance->GetIsInTryCompile()) { + if (this->Version == VSVersion::VS10 && + !this->CMakeInstance->GetIsInTryCompile()) { std::string cmakeWarnVS10; if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue( "CMAKE_WARN_VS10")) { @@ -367,8 +374,16 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( this->IsPartOfDefaultBuild(configs, projectTargets, target); cmValue vcprojName = target->GetProperty("GENERATOR_FILE_NAME"); if (vcprojName) { + std::string mapping; + + // On VS 19 and above, always map .NET SDK projects to "Any CPU". + if (target->IsDotNetSdkTarget() && + this->GetVersion() >= VSVersion::VS16 && + !this->IsReservedTarget(target->GetName())) { + mapping = "Any CPU"; + } this->WriteProjectConfigurations(fout, *vcprojName, *target, configs, - configsPartOfDefaultBuild); + configsPartOfDefaultBuild, mapping); } } } diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 8e762cf..33f1063 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -2,14 +2,26 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <iosfwd> +#include <map> #include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include <cm3p/json/value.h> -#include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" #include "cmValue.h" -class cmTarget; +class cmGeneratorTarget; struct cmIDEFlagTable; +class cmLocalGenerator; +class cmMakefile; +class cmake; +template <typename T> +class BT; /** \class cmGlobalVisualStudio7Generator * \brief Write a Unix makefiles. @@ -57,7 +69,8 @@ public: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 1e45813..dbd2de9 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -2,22 +2,41 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio8Generator.h" +#include <algorithm> +#include <functional> +#include <ostream> +#include <utility> + #include <cm/memory> +#include <cmext/algorithm> #include <cmext/memory> #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" -#include "cmDocumentationEntry.h" +#include "cmCustomCommandTypes.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalVisualStudio7Generator.h" +#include "cmGlobalVisualStudioGenerator.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmLocalVisualStudio7Generator.h" #include "cmMakefile.h" -#include "cmMessageType.h" +#include "cmPolicies.h" #include "cmSourceFile.h" -#include "cmVisualStudioWCEPlatformParser.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTargetDepend.h" +#include "cmValue.h" +#include "cmVisualStudioGeneratorOptions.h" #include "cmake.h" +struct cmIDEFlagTable; + cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator( cmake* cm, const std::string& name, std::string const& platformInGeneratorName) @@ -147,13 +166,10 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() auto& lg = cm::static_reference_cast<cmLocalVisualStudio7Generator>(generators[0]); - const char* no_working_directory = nullptr; - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; - cmCustomCommandLines no_commands; - cmTarget* tgt = lg.AddUtilityCommand( - CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, no_working_directory, - no_byproducts, no_depends, no_commands, cmPolicies::NEW); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetCMP0116Status(cmPolicies::NEW); + cmTarget* tgt = lg.AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, + std::move(cc)); auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg); auto gt = ptr.get(); @@ -203,11 +219,15 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() std::vector<std::string> byproducts; byproducts.push_back(cm->GetGlobVerifyStamp()); - lg.AddCustomCommandToTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, byproducts, - no_depends, verifyCommandLines, + cc = cm::make_unique<cmCustomCommand>(); + cc->SetByproducts(byproducts); + cc->SetCommandLines(verifyCommandLines); + cc->SetComment("Checking File Globs"); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetStdPipesUTF8(stdPipesUTF8); + lg.AddCustomCommandToTarget(CMAKE_CHECK_BUILD_SYSTEM_TARGET, cmCustomCommandType::PRE_BUILD, - "Checking File Globs", no_working_directory, - cmPolicies::NEW, stdPipesUTF8); + std::move(cc)); // Ensure ZERO_CHECK always runs in Visual Studio using MSBuild, // otherwise the prebuild command will not be run. @@ -234,13 +254,16 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // file as the main dependency because it would get // overwritten by the CreateVCProjBuildRule. // (this could be avoided with per-target source files) - std::string no_main_dependency; - cmImplicitDependsList no_implicit_depends; - if (cmSourceFile* file = lg.AddCustomCommandToOutput( - stamps, no_byproducts, listFiles, no_main_dependency, - no_implicit_depends, commandLines, "Checking Build System", - no_working_directory, cmPolicies::NEW, true, false, false, false, "", - "", stdPipesUTF8)) { + cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(stamps); + cc->SetDepends(listFiles); + cc->SetCommandLines(commandLines); + cc->SetComment("Checking Build System"); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetStdPipesUTF8(stdPipesUTF8); + if (cmSourceFile* file = + lg.AddCustomCommandToOutput(std::move(cc), true)) { gt->AddSource(file->ResolveFullPath()); } else { cmSystemTools::Error("Error adding rule for " + stamps[0]); diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index b6ecdf0..fe57c54 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -2,10 +2,20 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <iosfwd> +#include <set> +#include <string> +#include <vector> + #include <cm/optional> #include "cmGlobalVisualStudio71Generator.h" +class cmGeneratorTarget; +class cmMakefile; +class cmake; +struct cmIDEFlagTable; + /** \class cmGlobalVisualStudio8Generator * \brief Write a Unix makefiles. * diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx index 2339a80..e03e665 100644 --- a/Source/cmGlobalVisualStudio9Generator.cxx +++ b/Source/cmGlobalVisualStudio9Generator.cxx @@ -2,14 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudio9Generator.h" +#include <cstring> #include <utility> +#include <vector> #include "cmDocumentationEntry.h" -#include "cmLocalVisualStudio7Generator.h" -#include "cmMakefile.h" -#include "cmMessageType.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalGeneratorFactory.h" +#include "cmGlobalVisualStudioGenerator.h" +#include "cmSystemTools.h" #include "cmVisualStudioWCEPlatformParser.h" +class cmake; + static const char vs9generatorName[] = "Visual Studio 9 2008"; class cmGlobalVisualStudio9Generator::Factory : public cmGlobalGeneratorFactory @@ -119,7 +124,7 @@ cmGlobalVisualStudio9Generator::cmGlobalVisualStudio9Generator( std::string const& platformInGeneratorName) : cmGlobalVisualStudio8Generator(cm, name, platformInGeneratorName) { - this->Version = VS9; + this->Version = VSVersion::VS9; std::string vc9Express; this->ExpressEdition = cmSystemTools::ReadRegistryValue( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\9.0\\Setup\\VC;" diff --git a/Source/cmGlobalVisualStudio9Generator.h b/Source/cmGlobalVisualStudio9Generator.h index 6f4d159..1c93d49 100644 --- a/Source/cmGlobalVisualStudio9Generator.h +++ b/Source/cmGlobalVisualStudio9Generator.h @@ -3,9 +3,13 @@ #pragma once #include <memory> +#include <string> #include "cmGlobalVisualStudio8Generator.h" +class cmGlobalGeneratorFactory; +class cmake; + /** \class cmGlobalVisualStudio9Generator * \brief Write a Unix makefiles. * diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index f9bd67e..141b5eb 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -3,8 +3,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudioGenerator.h" +#include <cassert> #include <future> #include <iostream> +#include <sstream> +#include <system_error> +#include <utility> #include <cm/iterator> #include <cm/memory> @@ -14,17 +18,20 @@ #include <objbase.h> #include <shellapi.h> -#include "cmsys/Encoding.hxx" - #include "cmCallVisualStudioMacro.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" -#include "cmLocalVisualStudioGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmPolicies.h" #include "cmSourceFile.h" #include "cmState.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" @@ -90,21 +97,21 @@ std::string const& cmGlobalVisualStudioGenerator::GetPlatformName() const const char* cmGlobalVisualStudioGenerator::GetIDEVersion() const { switch (this->Version) { - case cmGlobalVisualStudioGenerator::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: return "9.0"; - case cmGlobalVisualStudioGenerator::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: return "10.0"; - case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: return "11.0"; - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: return "12.0"; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: return "14.0"; - case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: return "15.0"; - case cmGlobalVisualStudioGenerator::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: return "16.0"; - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: return "17.0"; } return ""; @@ -117,11 +124,11 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << '\n'; switch (this->Version) { - case cmGlobalVisualStudioGenerator::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: fout << "Microsoft Visual Studio Solution File, Format Version 10.00\n"; fout << "# Visual Studio 2008\n"; break; - case cmGlobalVisualStudioGenerator::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: fout << "Microsoft Visual Studio Solution File, Format Version 11.00\n"; if (this->ExpressEdition) { fout << "# Visual C++ Express 2010\n"; @@ -129,7 +136,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << "# Visual Studio 2010\n"; } break; - case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; if (this->ExpressEdition) { fout << "# Visual Studio Express 2012 for Windows Desktop\n"; @@ -137,7 +144,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << "# Visual Studio 2012\n"; } break; - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; if (this->ExpressEdition) { fout << "# Visual Studio Express 2013 for Windows Desktop\n"; @@ -145,7 +152,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << "# Visual Studio 2013\n"; } break; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: // Visual Studio 14 writes .sln format 12.00 fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; if (this->ExpressEdition) { @@ -154,7 +161,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << "# Visual Studio 14\n"; } break; - case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: // Visual Studio 15 writes .sln format 12.00 fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; if (this->ExpressEdition) { @@ -163,7 +170,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << "# Visual Studio 15\n"; } break; - case cmGlobalVisualStudioGenerator::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: // Visual Studio 16 writes .sln format 12.00 fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; if (this->ExpressEdition) { @@ -172,7 +179,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout) fout << "# Visual Studio Version 16\n"; } break; - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: // Visual Studio 17 writes .sln format 12.00 fout << "Microsoft Visual Studio Solution File, Format Version 12.00\n"; if (this->ExpressEdition) { @@ -199,19 +206,18 @@ void cmGlobalVisualStudioGenerator::AddExtraIDETargets() { // Add a special target that depends on ALL projects for easy build // of one configuration only. - const char* no_working_dir = nullptr; - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; - cmCustomCommandLines no_commands; for (auto const& it : this->ProjectMap) { std::vector<cmLocalGenerator*> const& gen = it.second; // add the ALL_BUILD to the first local generator of each project if (!gen.empty()) { // Use no actual command lines so that the target itself is not // considered always out of date. - cmTarget* allBuild = gen[0]->AddUtilityCommand( - "ALL_BUILD", true, no_working_dir, no_byproducts, no_depends, - no_commands, cmPolicies::NEW, false, "Build all projects"); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetComment("Build all projects"); + cmTarget* allBuild = + gen[0]->AddUtilityCommand("ALL_BUILD", true, std::move(cc)); gen[0]->AddGeneratorTarget( cm::make_unique<cmGeneratorTarget>(allBuild, gen[0])); @@ -942,9 +948,13 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( cmCustomCommandLines commandLines = cmMakeSingleCommandLine( { cmakeCommand, "-E", "__create_def", mdi->DefFile, objs_file }); - cmCustomCommand command(outputs, empty, empty, commandLines, - gt->Target->GetMakefile()->GetBacktrace(), - "Auto build dll exports", ".", true); + cmCustomCommand command; + command.SetOutputs(outputs); + command.SetCommandLines(commandLines); + command.SetComment("Auto build dll exports"); + command.SetBacktrace(gt->Target->GetMakefile()->GetBacktrace()); + command.SetWorkingDirectory("."); + command.SetStdPipesUTF8(true); commands.push_back(std::move(command)); } diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 23c8a02..cb1b14b 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -10,8 +10,11 @@ #include <string> #include <vector> +#include "cm_codecvt.hxx" + #include "cmGlobalGenerator.h" #include "cmTargetDepend.h" +#include "cmValue.h" class cmCustomCommand; class cmGeneratorTarget; @@ -29,7 +32,7 @@ class cmGlobalVisualStudioGenerator : public cmGlobalGenerator { public: /** Known versions of Visual Studio. */ - enum VSVersion + enum class VSVersion : uint16_t { VS9 = 90, VS10 = 100, diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index b5a6b9f..bc38335 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -2,16 +2,26 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalVisualStudioVersionedGenerator.h" +#include <cstring> +#include <set> +#include <sstream> +#include <utility> +#include <vector> + #include <cmext/string_view> #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" +#include "cmsys/RegularExpression.hxx" -#include "cmAlgorithms.h" #include "cmDocumentationEntry.h" -#include "cmLocalVisualStudio10Generator.h" +#include "cmGlobalGenerator.h" +#include "cmGlobalGeneratorFactory.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmStateTypes.h" #include "cmStringAlgorithms.h" +#include "cmSystemTools.h" #include "cmVSSetupHelper.h" #include "cmake.h" @@ -65,21 +75,21 @@ static unsigned int VSVersionToMajor( cmGlobalVisualStudioGenerator::VSVersion v) { switch (v) { - case cmGlobalVisualStudioGenerator::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: return 9; - case cmGlobalVisualStudioGenerator::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: return 10; - case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: return 11; - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: return 12; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: return 14; - case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: return 15; - case cmGlobalVisualStudioGenerator::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: return 16; - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: return 17; } return 0; @@ -89,40 +99,64 @@ static const char* VSVersionToToolset( cmGlobalVisualStudioGenerator::VSVersion v) { switch (v) { - case cmGlobalVisualStudioGenerator::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: return "v90"; - case cmGlobalVisualStudioGenerator::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: return "v100"; - case cmGlobalVisualStudioGenerator::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: return "v110"; - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: return "v120"; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: return "v140"; - case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: return "v141"; - case cmGlobalVisualStudioGenerator::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: return "v142"; - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: return "v143"; } return ""; } +static std::string VSVersionToMajorString( + cmGlobalVisualStudioGenerator::VSVersion v) +{ + switch (v) { + case cmGlobalVisualStudioGenerator::VSVersion::VS9: + return "9"; + case cmGlobalVisualStudioGenerator::VSVersion::VS10: + return "10"; + case cmGlobalVisualStudioGenerator::VSVersion::VS11: + return "11"; + case cmGlobalVisualStudioGenerator::VSVersion::VS12: + return "12"; + case cmGlobalVisualStudioGenerator::VSVersion::VS14: + return "14"; + case cmGlobalVisualStudioGenerator::VSVersion::VS15: + return "15"; + case cmGlobalVisualStudioGenerator::VSVersion::VS16: + return "16"; + case cmGlobalVisualStudioGenerator::VSVersion::VS17: + return "17"; + } + return ""; +} + static const char* VSVersionToAndroidToolset( cmGlobalVisualStudioGenerator::VSVersion v) { switch (v) { - case cmGlobalVisualStudioGenerator::VS9: - case cmGlobalVisualStudioGenerator::VS10: - case cmGlobalVisualStudioGenerator::VS11: - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: return ""; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: return "Clang_3_8"; - case cmGlobalVisualStudioGenerator::VS15: - case cmGlobalVisualStudioGenerator::VS16: - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: return "Clang_5_0"; } return ""; @@ -160,7 +194,7 @@ public: if (!*p) { return std::unique_ptr<cmGlobalGenerator>( new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS15, cm, genName, "")); + cmGlobalVisualStudioGenerator::VSVersion::VS15, cm, genName, "")); } if (!allowArch || *p++ != ' ') { return std::unique_ptr<cmGlobalGenerator>(); @@ -168,12 +202,12 @@ public: if (strcmp(p, "Win64") == 0) { return std::unique_ptr<cmGlobalGenerator>( new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS15, cm, genName, "x64")); + cmGlobalVisualStudioGenerator::VSVersion::VS15, cm, genName, "x64")); } if (strcmp(p, "ARM") == 0) { return std::unique_ptr<cmGlobalGenerator>( new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS15, cm, genName, "ARM")); + cmGlobalVisualStudioGenerator::VSVersion::VS15, cm, genName, "ARM")); } return std::unique_ptr<cmGlobalGenerator>(); } @@ -269,7 +303,7 @@ public: if (!*p) { return std::unique_ptr<cmGlobalGenerator>( new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS16, cm, genName, "")); + cmGlobalVisualStudioGenerator::VSVersion::VS16, cm, genName, "")); } return std::unique_ptr<cmGlobalGenerator>(); } @@ -334,7 +368,7 @@ public: if (!*p) { return std::unique_ptr<cmGlobalGenerator>( new cmGlobalVisualStudioVersionedGenerator( - cmGlobalVisualStudioGenerator::VS17, cm, genName, "")); + cmGlobalVisualStudioGenerator::VSVersion::VS17, cm, genName, "")); } return std::unique_ptr<cmGlobalGenerator>(); } @@ -397,11 +431,11 @@ cmGlobalVisualStudioVersionedGenerator::cmGlobalVisualStudioVersionedGenerator( this->DefaultCLFlagTableName = VSVersionToToolset(this->Version); this->DefaultCSharpFlagTableName = VSVersionToToolset(this->Version); this->DefaultLinkFlagTableName = VSVersionToToolset(this->Version); - if (this->Version >= cmGlobalVisualStudioGenerator::VS16) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16) { this->DefaultPlatformName = VSHostPlatformName(); this->DefaultPlatformToolsetHostArchitecture = VSHostArchitecture(); } - if (this->Version >= cmGlobalVisualStudioGenerator::VS17) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS17) { // FIXME: Search for an existing framework? Under '%ProgramFiles(x86)%', // see 'Reference Assemblies\Microsoft\Framework\.NETFramework'. // Use a version installed by VS 2022 without a separate component. @@ -414,23 +448,23 @@ bool cmGlobalVisualStudioVersionedGenerator::MatchesGeneratorName( { std::string genName; switch (this->Version) { - case cmGlobalVisualStudioGenerator::VS9: - case cmGlobalVisualStudioGenerator::VS10: - case cmGlobalVisualStudioGenerator::VS11: - case cmGlobalVisualStudioGenerator::VS12: - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: break; - case cmGlobalVisualStudioGenerator::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: if (cmVS15GenName(name, genName)) { return genName == this->GetName(); } break; - case cmGlobalVisualStudioGenerator::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: if (cmVS16GenName(name, genName)) { return genName == this->GetName(); } break; - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: if (cmVS17GenName(name, genName)) { return genName == this->GetName(); } @@ -447,15 +481,25 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( return true; } - if (!i.empty()) { - if (!this->vsSetupAPIHelper.SetVSInstance(i)) { + if (!this->ParseGeneratorInstance(i, mf)) { + return false; + } + + if (!this->GeneratorInstanceVersion.empty()) { + std::string const majorStr = VSVersionToMajorString(this->Version); + cmsys::RegularExpression versionRegex( + cmStrCat("^", majorStr, "\\.[0-9]+\\.[0-9]+\\.[0-9]+$")); + if (!versionRegex.find(this->GeneratorInstanceVersion)) { std::ostringstream e; /* clang-format off */ e << "Generator\n" " " << this->GetName() << "\n" - "could not find specified instance of Visual Studio:\n" - " " << i; + "given instance specification\n" + " " << i << "\n" + "but the version field is not 4 integer components" + " starting in " << majorStr << "." + ; /* clang-format on */ mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); return false; @@ -463,7 +507,29 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( } std::string vsInstance; - if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) { + if (!i.empty()) { + vsInstance = i; + if (!this->vsSetupAPIHelper.SetVSInstance( + this->GeneratorInstance, this->GeneratorInstanceVersion)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "could not find specified instance of Visual Studio:\n" + " " << i; + /* clang-format on */ + if (!this->GeneratorInstance.empty() && + this->GeneratorInstanceVersion.empty() && + cmSystemTools::FileIsDirectory(this->GeneratorInstance)) { + e << "\n" + "The directory exists, but the instance is not known to the " + "Visual Studio Installer, and no 'version=' field was given."; + } + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + } else if (!this->vsSetupAPIHelper.GetVSInstanceInfo(vsInstance)) { std::ostringstream e; /* clang-format off */ e << @@ -491,6 +557,88 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( return true; } +bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance( + std::string const& is, cmMakefile* mf) +{ + this->GeneratorInstance.clear(); + this->GeneratorInstanceVersion.clear(); + + std::vector<std::string> const fields = cmTokenize(is, ","); + std::vector<std::string>::const_iterator fi = fields.begin(); + if (fi == fields.end()) { + return true; + } + + // The first field may be the VS instance. + if (fi->find('=') == fi->npos) { + this->GeneratorInstance = *fi; + ++fi; + } + + std::set<std::string> handled; + + // The rest of the fields must be key=value pairs. + for (; fi != fields.end(); ++fi) { + std::string::size_type pos = fi->find('='); + if (pos == fi->npos) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "given instance specification\n" + " " << is << "\n" + "that contains a field after the first ',' with no '='." + ; + /* clang-format on */ + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + std::string const key = fi->substr(0, pos); + std::string const value = fi->substr(pos + 1); + if (!handled.insert(key).second) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "given instance specification\n" + " " << is << "\n" + "that contains duplicate field key '" << key << "'." + ; + /* clang-format on */ + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + if (!this->ProcessGeneratorInstanceField(key, value)) { + std::ostringstream e; + /* clang-format off */ + e << + "Generator\n" + " " << this->GetName() << "\n" + "given instance specification\n" + " " << is << "\n" + "that contains invalid field '" << *fi << "'." + ; + /* clang-format on */ + mf->IssueMessage(MessageType::FATAL_ERROR, e.str()); + return false; + } + } + + return true; +} + +bool cmGlobalVisualStudioVersionedGenerator::ProcessGeneratorInstanceField( + std::string const& key, std::string const& value) +{ + if (key == "version") { + this->GeneratorInstanceVersion = value; + return true; + } + return false; +} + bool cmGlobalVisualStudioVersionedGenerator::GetVSInstance( std::string& dir) const { @@ -543,16 +691,16 @@ cmGlobalVisualStudioVersionedGenerator::GetAndroidApplicationTypeRevision() const { switch (this->Version) { - case cmGlobalVisualStudioGenerator::VS9: - case cmGlobalVisualStudioGenerator::VS10: - case cmGlobalVisualStudioGenerator::VS11: - case cmGlobalVisualStudioGenerator::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS9: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: return ""; - case cmGlobalVisualStudioGenerator::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: return "2.0"; - case cmGlobalVisualStudioGenerator::VS15: - case cmGlobalVisualStudioGenerator::VS16: - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: return "3.0"; } return ""; @@ -658,7 +806,7 @@ bool cmGlobalVisualStudioVersionedGenerator::InitializeWindows(cmMakefile* mf) // the target Windows version. if (this->IsWin81SDKInstalled()) { // VS 2019 does not default to 8.1 so specify it explicitly when needed. - if (this->Version >= cmGlobalVisualStudioGenerator::VS16 && + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS16 && !cmSystemTools::VersionCompareGreater(this->SystemVersion, "8.1")) { this->SetWindowsTargetPlatformVersion("8.1", mf); return true; @@ -746,7 +894,7 @@ std::string cmGlobalVisualStudioVersionedGenerator::FindMSBuildCommand() // Ask Visual Studio Installer tool. std::string vs; if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) { - if (this->Version >= cmGlobalVisualStudioGenerator::VS17) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS17) { msbuild = vs + "/MSBuild/Current/Bin/amd64/MSBuild.exe"; if (cmSystemTools::FileExists(msbuild)) { return msbuild; diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 2aed65b..2e573ec 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -4,16 +4,18 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <iosfwd> #include <memory> #include <string> #include <cm/optional> +#include "cmGlobalVisualStudio10Generator.h" #include "cmGlobalVisualStudio14Generator.h" +#include "cmGlobalVisualStudioGenerator.h" #include "cmVSSetupHelper.h" class cmGlobalGeneratorFactory; +class cmMakefile; class cmake; /** \class cmGlobalVisualStudioVersionedGenerator */ @@ -65,6 +67,9 @@ protected: std::string GetWindows10SDKMaxVersionDefault(cmMakefile*) const override; + virtual bool ProcessGeneratorInstanceField(std::string const& key, + std::string const& value); + std::string FindMSBuildCommand() override; std::string FindDevEnvCommand() override; @@ -76,5 +81,10 @@ private: class Factory17; friend class Factory17; mutable cmVSSetupAPIHelper vsSetupAPIHelper; + + bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf); + + std::string GeneratorInstance; + std::string GeneratorInstanceVersion; cm::optional<std::string> LastGeneratorInstanceString; }; diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index 3e2d92d..fb2a8b6 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -65,12 +65,13 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand> cmGlobalWatcomWMakeGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int /*jobs*/, bool verbose, + const std::string& config, int /*jobs*/, bool verbose, + const cmBuildOptions& buildOptions, std::vector<std::string> const& makeOptions) { return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( - makeProgram, projectName, projectDir, targetNames, config, fast, - cmake::NO_BUILD_PARALLEL_LEVEL, verbose, makeOptions); + makeProgram, projectName, projectDir, targetNames, config, + cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, makeOptions); } void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os, diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h index da39d3f..eb93934 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "cmBuildOptions.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalUnixMakefileGenerator3.h" @@ -57,7 +58,8 @@ protected: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index f34ef62..203addd 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -6,6 +6,7 @@ #include <cassert> #include <cstdio> #include <cstring> +#include <functional> #include <iomanip> #include <sstream> #include <unordered_set> @@ -17,36 +18,42 @@ #include "cmsys/RegularExpression.hxx" -#include "cmCMakePath.h" #include "cmComputeLinkInformation.h" #include "cmCryptoHash.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmCustomCommandLines.h" +#include "cmCustomCommandTypes.h" #include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGeneratorFactory.h" +#include "cmLinkItem.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalXCodeGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmOutputConverter.h" +#include "cmPolicies.h" #include "cmSourceFile.h" +#include "cmSourceFileLocation.h" +#include "cmSourceFileLocationKind.h" #include "cmSourceGroup.h" #include "cmState.h" +#include "cmStateSnapshot.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" +#include "cmTargetDepend.h" #include "cmXCode21Object.h" #include "cmXCodeObject.h" #include "cmXCodeScheme.h" +#include "cmXMLWriter.h" #include "cmake.h" -struct cmLinkImplementation; - #if !defined(CMAKE_BOOTSTRAP) && defined(__APPLE__) # include <CoreFoundation/CoreFoundation.h> # if !TARGET_OS_IPHONE @@ -471,7 +478,7 @@ cmGlobalXCodeGenerator::GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& /*projectDir*/, std::vector<std::string> const& targetNames, const std::string& config, - bool /*fast*/, int jobs, bool /*verbose*/, + int jobs, bool /*verbose*/, const cmBuildOptions& /*buildOptions*/, std::vector<std::string> const& makeOptions) { GeneratedMakeCommand makeCommand; @@ -601,15 +608,13 @@ std::string cmGlobalXCodeGenerator::PostBuildMakeTarget( void cmGlobalXCodeGenerator::AddExtraTargets( cmLocalGenerator* root, std::vector<cmLocalGenerator*>& gens) { - const char* no_working_directory = nullptr; - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; - // Add ALL_BUILD - cmTarget* allbuild = root->AddUtilityCommand( - "ALL_BUILD", true, no_working_directory, no_byproducts, no_depends, - cmMakeSingleCommandLine({ "echo", "Build all projects" }), - cmPolicies::NEW); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetCommandLines( + cmMakeSingleCommandLine({ "echo", "Build all projects" })); + cc->SetCMP0116Status(cmPolicies::NEW); + cmTarget* allbuild = + root->AddUtilityCommand("ALL_BUILD", true, std::move(cc)); root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(allbuild, root)); @@ -635,10 +640,11 @@ void cmGlobalXCodeGenerator::AddExtraTargets( std::string file = this->ConvertToRelativeForMake(this->CurrentReRunCMakeMakefile); cmSystemTools::ReplaceString(file, "\\ ", " "); - cmTarget* check = root->AddUtilityCommand( - CMAKE_CHECK_BUILD_SYSTEM_TARGET, true, no_working_directory, - no_byproducts, no_depends, - cmMakeSingleCommandLine({ "make", "-f", file }), cmPolicies::NEW); + cc = cm::make_unique<cmCustomCommand>(); + cc->SetCommandLines(cmMakeSingleCommandLine({ "make", "-f", file })); + cc->SetCMP0116Status(cmPolicies::NEW); + cmTarget* check = root->AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, + true, std::move(cc)); root->AddGeneratorTarget(cm::make_unique<cmGeneratorTarget>(check, root)); } @@ -664,11 +670,13 @@ void cmGlobalXCodeGenerator::AddExtraTargets( target->GetType() == cmStateEnums::OBJECT_LIBRARY) { legacyDependHelperCommandLines.front().back() = // fill placeholder this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)"); + cc = cm::make_unique<cmCustomCommand>(); + cc->SetCommandLines(legacyDependHelperCommandLines); + cc->SetComment("Depend check for xcode"); + cc->SetWorkingDirectory(legacyDependHelperDir.c_str()); + cc->SetCMP0116Status(cmPolicies::NEW); gen->AddCustomCommandToTarget( - target->GetName(), no_byproducts, no_depends, - legacyDependHelperCommandLines, cmCustomCommandType::POST_BUILD, - "Depend check for xcode", legacyDependHelperDir.c_str(), - cmPolicies::NEW, true, false, "", "", false, + target->GetName(), cmCustomCommandType::POST_BUILD, std::move(cc), cmObjectLibraryCommands::Accept); } @@ -833,8 +841,8 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateFlatClone(cmXCodeObject* orig) return obj; } -std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target, - const std::string& fullpath) +static std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target, + const std::string& fullpath) { std::string key(target->GetName()); key += "-"; @@ -1716,15 +1724,16 @@ void cmGlobalXCodeGenerator::CreateCustomCommands( cmStrCat("$<TARGET_SONAME_FILE:", gtgt->GetName(), '>'); std::string str_link_file = cmStrCat("$<TARGET_LINKER_FILE:", gtgt->GetName(), '>'); - bool stdPipesUTF8 = true; cmCustomCommandLines cmd = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "cmake_symlink_library", str_file, str_so_file, str_link_file }); - cmCustomCommand command( - std::vector<std::string>(), std::vector<std::string>(), - std::vector<std::string>(), cmd, this->CurrentMakefile->GetBacktrace(), - "Creating symlinks", "", stdPipesUTF8); + cmCustomCommand command; + command.SetCommandLines(cmd); + command.SetComment("Creating symlinks"); + command.SetWorkingDirectory(""); + command.SetBacktrace(this->CurrentMakefile->GetBacktrace()); + command.SetStdPipesUTF8(true); postbuild.push_back(std::move(command)); } @@ -2674,7 +2683,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, if (emitted.insert(frameworkDir).second) { std::string incpath = this->XCodeEscapePath(frameworkDir); if (emitSystemIncludes && - gtgt->IsSystemIncludeDirectory(frameworkDir, configName, + gtgt->IsSystemIncludeDirectory(include, configName, langForPreprocessor)) { sysfdirs.Add(incpath); } else { @@ -3910,6 +3919,14 @@ void cmGlobalXCodeGenerator::AddEmbeddedFrameworks(cmXCodeObject* target) NoActionOnCopyByDefault); } +void cmGlobalXCodeGenerator::AddEmbeddedPlugIns(cmXCodeObject* target) +{ + static const auto dstSubfolderSpec = "13"; + + this->AddEmbeddedObjects(target, "Embed PlugIns", "XCODE_EMBED_PLUGINS", + dstSubfolderSpec, NoActionOnCopyByDefault); +} + void cmGlobalXCodeGenerator::AddEmbeddedAppExtensions(cmXCodeObject* target) { static const auto dstSubfolderSpec = "13"; @@ -4298,6 +4315,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( for (auto t : targets) { this->AddDependAndLinkInformation(t); this->AddEmbeddedFrameworks(t); + this->AddEmbeddedPlugIns(t); this->AddEmbeddedAppExtensions(t); // Inherit project-wide values for any target-specific search paths. this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS"); diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 4d7ee90..ff6ffe8 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -11,10 +11,12 @@ #include <string> #include <vector> +#include <cm/optional> #include <cm/string_view> #include "cmGlobalGenerator.h" #include "cmTransformDepfile.h" +#include "cmValue.h" #include "cmXCodeObject.h" class cmCustomCommand; @@ -78,7 +80,8 @@ public: std::vector<GeneratedMakeCommand> GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, std::vector<std::string> const& targetNames, - const std::string& config, bool fast, int jobs, bool verbose, + const std::string& config, int jobs, bool verbose, + const cmBuildOptions& buildOptions = cmBuildOptions(), std::vector<std::string> const& makeOptions = std::vector<std::string>()) override; @@ -216,6 +219,7 @@ private: const std::string& dstSubfolderSpec, int actionsOnByDefault); void AddEmbeddedFrameworks(cmXCodeObject* target); + void AddEmbeddedPlugIns(cmXCodeObject* target); void AddEmbeddedAppExtensions(cmXCodeObject* target); void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target, cmXCodeObject* buildSettings, diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index b53319f..c09aa46 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -2,15 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmIDEOptions.h" +#include <algorithm> +#include <cstring> #include <iterator> +#include <utility> #include <cmext/algorithm> -#include <string.h> - #include "cmsys/String.h" -#include "cmAlgorithms.h" #include "cmIDEFlagTable.h" #include "cmStringAlgorithms.h" diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 92e3bb5..8ce7ed1 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -6,11 +6,13 @@ #include <cassert> #include <cstddef> #include <iterator> +#include <map> #include <set> #include <sstream> #include <utility> #include <cm/memory> +#include <cm/string_view> #include <cmext/string_view> #include "cmsys/Glob.hxx" @@ -18,11 +20,13 @@ #include "cmArgumentParser.h" #include "cmExecutionStatus.h" #include "cmExportSet.h" +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" #include "cmInstallCommandArguments.h" #include "cmInstallDirectoryGenerator.h" #include "cmInstallExportGenerator.h" +#include "cmInstallFileSetGenerator.h" #include "cmInstallFilesGenerator.h" #include "cmInstallGenerator.h" #include "cmInstallGetRuntimeDependenciesGenerator.h" @@ -89,6 +93,9 @@ public: bool MakeFilesFullPath(const char* modeName, const std::vector<std::string>& relFiles, std::vector<std::string>& absFiles); + bool MakeFilesFullPath(const char* modeName, const std::string& basePath, + const std::vector<std::string>& relFiles, + std::vector<std::string>& absFiles); bool CheckCMP0006(bool& failure) const; std::string GetDestination(const cmInstallCommandArguments* args, @@ -177,6 +184,19 @@ std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator( args.GetDestination()); } +std::unique_ptr<cmInstallFileSetGenerator> CreateInstallFileSetGenerator( + Helper& helper, cmTarget& target, cmFileSet* fileSet, + const std::string& destination, const cmInstallCommandArguments& args) +{ + cmInstallGenerator::MessageLevel message = + cmInstallGenerator::SelectMessageLevel(helper.Makefile); + return cm::make_unique<cmInstallFileSetGenerator>( + target.GetName(), fileSet, destination, args.GetPermissions(), + args.GetConfigurations(), args.GetComponent(), message, + args.GetExcludeFromAll(), args.GetOptional(), + helper.Makefile->GetBacktrace()); +} + void AddInstallRuntimeDependenciesGenerator( Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet, const cmInstallCommandArguments& runtimeArgs, @@ -390,6 +410,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, std::vector<std::string> PrivateHeader; std::vector<std::string> PublicHeader; std::vector<std::string> Resource; + std::vector<std::vector<std::string>> FileSets; }; static auto const argHelper = @@ -403,7 +424,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args, .Bind("INCLUDES"_s, &ArgVectors::Includes) .Bind("PRIVATE_HEADER"_s, &ArgVectors::PrivateHeader) .Bind("PUBLIC_HEADER"_s, &ArgVectors::PublicHeader) - .Bind("RESOURCE"_s, &ArgVectors::Resource); + .Bind("RESOURCE"_s, &ArgVectors::Resource) + .Bind("FILE_SET"_s, &ArgVectors::FileSets); std::vector<std::string> genericArgVector; ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector); @@ -442,6 +464,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args, cmInstallCommandArguments publicHeaderArgs(helper.DefaultComponentName); cmInstallCommandArguments resourceArgs(helper.DefaultComponentName); cmInstallCommandIncludesArgument includesArgs; + std::vector<cmInstallCommandFileSetArguments> fileSetArgs( + argVectors.FileSets.size(), { helper.DefaultComponentName }); // now parse the args for specific parts of the target (e.g. LIBRARY, // RUNTIME, ARCHIVE etc. @@ -455,6 +479,15 @@ bool HandleTargetsMode(std::vector<std::string> const& args, publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs); resourceArgs.Parse(argVectors.Resource, &unknownArgs); includesArgs.Parse(&argVectors.Includes, &unknownArgs); + for (std::size_t i = 0; i < argVectors.FileSets.size(); i++) { + // We have to create a separate object for the parsing because + // cmArgumentParser<void>::Bind() binds to a specific address, but the + // objects in the vector can move around. So we parse in an object with a + // fixed address and then copy the data into the vector. + cmInstallCommandFileSetArguments fileSetArg(helper.DefaultComponentName); + fileSetArg.Parse(argVectors.FileSets[i], &unknownArgs); + fileSetArgs[i] = std::move(fileSetArg); + } if (!unknownArgs.empty()) { // Unknown argument. @@ -473,6 +506,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, privateHeaderArgs.SetGenericArguments(&genericArgs); publicHeaderArgs.SetGenericArguments(&genericArgs); resourceArgs.SetGenericArguments(&genericArgs); + for (auto& fileSetArg : fileSetArgs) { + fileSetArg.SetGenericArguments(&genericArgs); + } success = success && archiveArgs.Finalize(); success = success && libraryArgs.Finalize(); @@ -483,6 +519,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, success = success && privateHeaderArgs.Finalize(); success = success && publicHeaderArgs.Finalize(); success = success && resourceArgs.Finalize(); + for (auto& fileSetArg : fileSetArgs) { + success = success && fileSetArg.Finalize(); + } if (!success) { return false; @@ -493,7 +532,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, if (archiveArgs.GetNamelinkOnly() || runtimeArgs.GetNamelinkOnly() || objectArgs.GetNamelinkOnly() || frameworkArgs.GetNamelinkOnly() || bundleArgs.GetNamelinkOnly() || privateHeaderArgs.GetNamelinkOnly() || - publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly()) { + publicHeaderArgs.GetNamelinkOnly() || resourceArgs.GetNamelinkOnly() || + std::any_of(fileSetArgs.begin(), fileSetArgs.end(), + [](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return fileSetArg.GetNamelinkOnly(); })) { status.SetError( "TARGETS given NAMELINK_ONLY option not in LIBRARY group. " "The NAMELINK_ONLY option may be specified only following LIBRARY."); @@ -502,7 +544,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, if (archiveArgs.GetNamelinkSkip() || runtimeArgs.GetNamelinkSkip() || objectArgs.GetNamelinkSkip() || frameworkArgs.GetNamelinkSkip() || bundleArgs.GetNamelinkSkip() || privateHeaderArgs.GetNamelinkSkip() || - publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip()) { + publicHeaderArgs.GetNamelinkSkip() || resourceArgs.GetNamelinkSkip() || + std::any_of(fileSetArgs.begin(), fileSetArgs.end(), + [](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return fileSetArg.GetNamelinkSkip(); })) { status.SetError( "TARGETS given NAMELINK_SKIP option not in LIBRARY group. " "The NAMELINK_SKIP option may be specified only following LIBRARY."); @@ -515,7 +560,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, bundleArgs.HasNamelinkComponent() || privateHeaderArgs.HasNamelinkComponent() || publicHeaderArgs.HasNamelinkComponent() || - resourceArgs.HasNamelinkComponent()) { + resourceArgs.HasNamelinkComponent() || + std::any_of(fileSetArgs.begin(), fileSetArgs.end(), + [](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return fileSetArg.HasNamelinkComponent(); })) { status.SetError( "TARGETS given NAMELINK_COMPONENT option not in LIBRARY group. " "The NAMELINK_COMPONENT option may be specified only following " @@ -531,12 +579,21 @@ bool HandleTargetsMode(std::vector<std::string> const& args, !libraryArgs.GetType().empty() || !runtimeArgs.GetType().empty() || !objectArgs.GetType().empty() || !frameworkArgs.GetType().empty() || !bundleArgs.GetType().empty() || !privateHeaderArgs.GetType().empty() || - !publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty()) { + !publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty() || + std::any_of(fileSetArgs.begin(), fileSetArgs.end(), + [](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return !fileSetArg.GetType().empty(); })) { status.SetError( "TARGETS given TYPE option. The TYPE option may only be specified in " " install(FILES) and install(DIRECTORIES)."); return false; } + if (std::any_of(fileSetArgs.begin(), fileSetArgs.end(), + [](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return fileSetArg.GetFileSet().empty(); })) { + status.SetError("TARGETS given FILE_SET option without file set name."); + return false; + } cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr; if (withRuntimeDependencies) { @@ -647,6 +704,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, bool installsPrivateHeader = false; bool installsPublicHeader = false; bool installsResource = false; + std::vector<bool> installsFileSet(fileSetArgs.size(), false); // Generate install script code to install the given targets. for (cmTarget* ti : targets) { @@ -662,6 +720,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, std::unique_ptr<cmInstallFilesGenerator> privateHeaderGenerator; std::unique_ptr<cmInstallFilesGenerator> publicHeaderGenerator; std::unique_ptr<cmInstallFilesGenerator> resourceGenerator; + std::vector<std::unique_ptr<cmInstallFileSetGenerator>> fileSetGenerators; // Avoid selecting default destinations for PUBLIC_HEADER and // PRIVATE_HEADER if any artifacts are specified. @@ -670,9 +729,24 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // Track whether this is a namelink-only rule. bool namelinkOnly = false; - auto addTargetExport = [&]() { + auto addTargetExport = [&]() -> bool { // Add this install rule to an export if one was specified. if (!exports.empty()) { + auto interfaceFileSets = target.GetAllInterfaceFileSets(); + if (std::any_of( + interfaceFileSets.begin(), interfaceFileSets.end(), + [=](const std::string& name) -> bool { + return !std::any_of( + fileSetArgs.begin(), fileSetArgs.end(), + [=](const cmInstallCommandFileSetArguments& fileSetArg) + -> bool { return fileSetArg.GetFileSet() == name; }); + })) { + status.SetError(cmStrCat( + "TARGETS target ", target.GetName(), + " is exported but not all of its file sets are installed")); + return false; + } + auto te = cm::make_unique<cmTargetExport>(); te->TargetName = target.GetName(); te->ArchiveGenerator = archiveGenerator.get(); @@ -682,6 +756,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, te->LibraryGenerator = libraryGenerator.get(); te->RuntimeGenerator = runtimeGenerator.get(); te->ObjectsGenerator = objectGenerator.get(); + for (auto const& gen : fileSetGenerators) { + te->FileSetGenerators[gen->GetFileSet()] = gen.get(); + } target.AddInstallIncludeDirectories( *te, cmMakeRange(includesArgs.GetIncludeDirs())); te->NamelinkOnly = namelinkOnly; @@ -689,6 +766,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, ->GetExportSets()[exports] .AddTargetExport(std::move(te)); } + return true; }; switch (target.GetType()) { @@ -700,7 +778,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // When in namelink only mode skip all libraries on Windows. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; - addTargetExport(); + if (!addTargetExport()) { + return false; + } continue; } @@ -736,7 +816,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // When in namelink only mode skip frameworks. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; - addTargetExport(); + if (!addTargetExport()) { + return false; + } continue; } @@ -785,7 +867,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, // When in namelink only mode skip frameworks. if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; - addTargetExport(); + if (!addTargetExport()) { + return false; + } continue; } @@ -942,9 +1026,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, helper.GetIncludeDestination(&privateHeaderArgs)); } else { std::ostringstream e; - e << "INSTALL TARGETS - target " << target.GetName() << " has " + e << "Target " << target.GetName() << " has " << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION."; - cmSystemTools::Message(e.str(), "Warning"); + helper.Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str()); } } @@ -964,9 +1048,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, helper.GetIncludeDestination(&publicHeaderArgs)); } else { std::ostringstream e; - e << "INSTALL TARGETS - target " << target.GetName() << " has " + e << "Target " << target.GetName() << " has " << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION."; - cmSystemTools::Message(e.str(), "Warning"); + helper.Makefile->IssueMessage(MessageType::AUTHOR_WARNING, e.str()); } } @@ -983,16 +1067,48 @@ bool HandleTargetsMode(std::vector<std::string> const& args, resourceGenerator = CreateInstallFilesGenerator( helper.Makefile, absFiles, resourceArgs, false); } else if (!target.IsAppBundleOnApple()) { - cmSystemTools::Message( - cmStrCat("INSTALL TARGETS - target ", target.GetName(), - " has RESOURCE files but no RESOURCE DESTINATION."), - "Warning"); + helper.Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat("Target ", target.GetName(), + " has RESOURCE files but no RESOURCE DESTINATION.")); + } + } + } + + if (!namelinkOnly) { + for (std::size_t i = 0; i < fileSetArgs.size(); i++) { + if (auto* fileSet = target.GetFileSet(fileSetArgs[i].GetFileSet())) { + auto interfaceFileSetEntries = cmExpandedList(target.GetSafeProperty( + cmTarget::GetInterfaceFileSetsPropertyName(fileSet->GetType()))); + if (std::find(interfaceFileSetEntries.begin(), + interfaceFileSetEntries.end(), + fileSetArgs[i].GetFileSet()) != + interfaceFileSetEntries.end()) { + std::string destination; + if (fileSet->GetType() == "HEADERS"_s) { + destination = helper.GetIncludeDestination(&fileSetArgs[i]); + } else { + destination = fileSetArgs[i].GetDestination(); + if (destination.empty()) { + status.SetError(cmStrCat( + "TARGETS given no FILE_SET DESTINATION for target \"", + target.GetName(), "\" file set \"", fileSet->GetName(), + "\".")); + return false; + } + } + fileSetGenerators.push_back(CreateInstallFileSetGenerator( + helper, target, fileSet, destination, fileSetArgs[i])); + installsFileSet[i] = true; + } } } } // Add this install rule to an export if one was specified. - addTargetExport(); + if (!addTargetExport()) { + return false; + } // Keep track of whether we're installing anything in each category installsArchive = installsArchive || archiveGenerator; @@ -1016,6 +1132,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args, helper.Makefile->AddInstallGenerator(std::move(privateHeaderGenerator)); helper.Makefile->AddInstallGenerator(std::move(publicHeaderGenerator)); helper.Makefile->AddInstallGenerator(std::move(resourceGenerator)); + for (auto& gen : fileSetGenerators) { + helper.Makefile->AddInstallGenerator(std::move(gen)); + } } if (withRuntimeDependencies && !runtimeDependencySet->Empty()) { @@ -1067,6 +1186,12 @@ bool HandleTargetsMode(std::vector<std::string> const& args, helper.Makefile->GetGlobalGenerator()->AddInstallComponent( resourceArgs.GetComponent()); } + for (std::size_t i = 0; i < fileSetArgs.size(); i++) { + if (installsFileSet[i]) { + helper.Makefile->GetGlobalGenerator()->AddInstallComponent( + fileSetArgs[i].GetComponent()); + } + } return true; } @@ -2063,12 +2188,20 @@ bool Helper::MakeFilesFullPath(const char* modeName, const std::vector<std::string>& relFiles, std::vector<std::string>& absFiles) { + return this->MakeFilesFullPath( + modeName, this->Makefile->GetCurrentSourceDirectory(), relFiles, absFiles); +} + +bool Helper::MakeFilesFullPath(const char* modeName, + const std::string& basePath, + const std::vector<std::string>& relFiles, + std::vector<std::string>& absFiles) +{ for (std::string const& relFile : relFiles) { std::string file = relFile; std::string::size_type gpos = cmGeneratorExpression::Find(file); if (gpos != 0 && !cmSystemTools::FileIsFullPath(file)) { - file = - cmStrCat(this->Makefile->GetCurrentSourceDirectory(), '/', relFile); + file = cmStrCat(basePath, '/', relFile); } // Make sure the file is not a directory. diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index cc3df2a..7309316 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -152,6 +152,11 @@ const std::string& cmInstallCommandArguments::GetType() const return this->Type; } +const std::string& cmInstallCommandArguments::GetDefaultComponent() const +{ + return this->DefaultComponentName; +} + const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations() const { @@ -220,3 +225,17 @@ void cmInstallCommandIncludesArgument::Parse( this->IncludeDirs.push_back(std::move(dir)); } } + +cmInstallCommandFileSetArguments::cmInstallCommandFileSetArguments( + std::string defaultComponent) + : cmInstallCommandArguments(std::move(defaultComponent)) +{ + this->Bind("FILE_SET"_s, this->FileSet); +} + +void cmInstallCommandFileSetArguments::Parse( + std::vector<std::string> args, std::vector<std::string>* unconsumedArgs) +{ + args.insert(args.begin(), "FILE_SET"); + this->cmInstallCommandArguments::Parse(args, unconsumedArgs); +} diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index f318a1a..79bd945 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -34,6 +34,8 @@ public: bool HasNamelinkComponent() const; const std::string& GetType() const; + const std::string& GetDefaultComponent() const; + static bool CheckPermissions(const std::string& onePerm, std::string& perm); private: @@ -71,3 +73,17 @@ public: private: std::vector<std::string> IncludeDirs; }; + +class cmInstallCommandFileSetArguments : public cmInstallCommandArguments +{ +public: + cmInstallCommandFileSetArguments(std::string defaultComponent); + + void Parse(std::vector<std::string> args, + std::vector<std::string>* unconsumedArgs); + + const std::string& GetFileSet() const { return this->FileSet; } + +private: + std::string FileSet; +}; diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index d932fd9..820f24a 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -85,7 +85,9 @@ void cmInstallExportGenerator::ComputeTempDir() } if (useMD5) { // Replace the destination path with a hash to keep it short. +#ifndef CMAKE_BOOTSTRAP this->TempDir += cmSystemTools::ComputeStringMD5(this->Destination); +#endif } else { std::string dest = this->Destination; // Avoid unix full paths. diff --git a/Source/cmInstallFileSetGenerator.cxx b/Source/cmInstallFileSetGenerator.cxx new file mode 100644 index 0000000..7121ea3 --- /dev/null +++ b/Source/cmInstallFileSetGenerator.cxx @@ -0,0 +1,88 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmInstallFileSetGenerator.h" + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "cmFileSet.h" +#include "cmGeneratorExpression.h" +#include "cmGlobalGenerator.h" +#include "cmInstallType.h" +#include "cmLocalGenerator.h" +#include "cmStringAlgorithms.h" + +cmInstallFileSetGenerator::cmInstallFileSetGenerator( + std::string targetName, cmFileSet* fileSet, std::string const& dest, + std::string file_permissions, std::vector<std::string> const& configurations, + std::string const& component, MessageLevel message, bool exclude_from_all, + bool optional, cmListFileBacktrace backtrace) + : cmInstallGenerator(dest, configurations, component, message, + exclude_from_all, false, std::move(backtrace)) + , TargetName(std::move(targetName)) + , FileSet(fileSet) + , FilePermissions(std::move(file_permissions)) + , Optional(optional) +{ + this->ActionsPerConfig = true; +} + +cmInstallFileSetGenerator::~cmInstallFileSetGenerator() = default; + +bool cmInstallFileSetGenerator::Compute(cmLocalGenerator* lg) +{ + this->LocalGenerator = lg; + + // Lookup this target in the current directory. + this->Target = lg->FindLocalNonAliasGeneratorTarget(this->TargetName); + if (!this->Target) { + // If no local target has been found, find it in the global scope. + this->Target = + lg->GetGlobalGenerator()->FindGeneratorTarget(this->TargetName); + } + + return true; +} + +std::string cmInstallFileSetGenerator::GetDestination( + std::string const& config) const +{ + return cmGeneratorExpression::Evaluate(this->Destination, + this->LocalGenerator, config); +} + +void cmInstallFileSetGenerator::GenerateScriptForConfig( + std::ostream& os, const std::string& config, Indent indent) +{ + for (auto const& dirEntry : this->CalculateFilesPerDir(config)) { + std::string destSub; + if (!dirEntry.first.empty()) { + destSub = cmStrCat('/', dirEntry.first); + } + this->AddInstallRule(os, cmStrCat(this->GetDestination(config), destSub), + cmInstallType_FILES, dirEntry.second, + this->GetOptional(), this->FilePermissions.c_str(), + nullptr, nullptr, nullptr, indent); + } +} + +std::map<std::string, std::vector<std::string>> +cmInstallFileSetGenerator::CalculateFilesPerDir( + const std::string& config) const +{ + std::map<std::string, std::vector<std::string>> result; + + auto dirCges = this->FileSet->CompileDirectoryEntries(); + auto dirs = this->FileSet->EvaluateDirectoryEntries( + dirCges, this->LocalGenerator, config, this->Target); + + auto fileCges = this->FileSet->CompileFileEntries(); + for (auto const& fileCge : fileCges) { + this->FileSet->EvaluateFileEntry( + dirs, result, fileCge, this->LocalGenerator, config, this->Target); + } + + return result; +} diff --git a/Source/cmInstallFileSetGenerator.h b/Source/cmInstallFileSetGenerator.h new file mode 100644 index 0000000..8d067d9 --- /dev/null +++ b/Source/cmInstallFileSetGenerator.h @@ -0,0 +1,52 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <iosfwd> +#include <map> +#include <string> +#include <vector> + +#include "cmInstallGenerator.h" +#include "cmListFileCache.h" +#include "cmScriptGenerator.h" + +class cmGeneratorTarget; +class cmFileSet; +class cmLocalGenerator; + +class cmInstallFileSetGenerator : public cmInstallGenerator +{ +public: + cmInstallFileSetGenerator(std::string targetName, cmFileSet* fileSet, + std::string const& dest, + std::string file_permissions, + std::vector<std::string> const& configurations, + std::string const& component, MessageLevel message, + bool exclude_from_all, bool optional, + cmListFileBacktrace backtrace); + ~cmInstallFileSetGenerator() override; + + bool Compute(cmLocalGenerator* lg) override; + + std::string GetDestination(std::string const& config) const; + std::string GetDestination() const { return this->Destination; } + bool GetOptional() const { return this->Optional; } + cmFileSet* GetFileSet() const { return this->FileSet; } + cmGeneratorTarget* GetTarget() const { return this->Target; } + +protected: + void GenerateScriptForConfig(std::ostream& os, const std::string& config, + Indent indent) override; + +private: + std::string TargetName; + cmLocalGenerator* LocalGenerator; + cmFileSet* const FileSet; + std::string const FilePermissions; + bool const Optional; + cmGeneratorTarget* Target; + + std::map<std::string, std::vector<std::string>> CalculateFilesPerDir( + const std::string& config) const; +}; diff --git a/Source/cmLinkItem.cxx b/Source/cmLinkItem.cxx index 62e7ef4..2dc40ff 100644 --- a/Source/cmLinkItem.cxx +++ b/Source/cmLinkItem.cxx @@ -68,8 +68,8 @@ cmLinkImplItem::cmLinkImplItem() { } -cmLinkImplItem::cmLinkImplItem(cmLinkItem item, bool fromGenex) +cmLinkImplItem::cmLinkImplItem(cmLinkItem item, bool checkCMP0027) : cmLinkItem(std::move(item)) - , FromGenex(fromGenex) + , CheckCMP0027(checkCMP0027) { } diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 0863edd..262728b 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -40,8 +40,8 @@ class cmLinkImplItem : public cmLinkItem { public: cmLinkImplItem(); - cmLinkImplItem(cmLinkItem item, bool fromGenex); - bool FromGenex = false; + cmLinkImplItem(cmLinkItem item, bool checkCMP0027); + bool CheckCMP0027 = false; }; /** The link implementation specifies the direct library @@ -70,6 +70,12 @@ struct cmLinkInterfaceLibraries // Object files listed in the interface. std::vector<cmLinkItem> Objects; + // Items to be included as if directly linked by the head target. + std::vector<cmLinkItem> HeadInclude; + + // Items to be excluded from direct linking by the head target. + std::vector<cmLinkItem> HeadExclude; + // Whether the list depends on a genex referencing the head target. bool HadHeadSensitiveCondition = false; diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx index 7ad8690..d87d183 100644 --- a/Source/cmLinkItemGraphVisitor.cxx +++ b/Source/cmLinkItemGraphVisitor.cxx @@ -107,8 +107,8 @@ void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target, } } - const auto* interfaceLibraries = - target.GetLinkInterfaceLibraries(config, &target, true); + const auto* interfaceLibraries = target.GetLinkInterfaceLibraries( + config, &target, cmGeneratorTarget::LinkInterfaceFor::Usage); if (interfaceLibraries != nullptr) { for (auto const& lib : interfaceLibraries->Libraries) { auto const& name = lib.AsStr(); diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index 7d42fc8..56345df 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -155,7 +155,7 @@ bool HandleLengthCommand(std::vector<std::string> const& args, GetList(varArgsExpanded, listName, status.GetMakefile()); size_t length = varArgsExpanded.size(); char buffer[1024]; - sprintf(buffer, "%d", static_cast<int>(length)); + snprintf(buffer, sizeof(buffer), "%d", static_cast<int>(length)); status.GetMakefile().AddDefinition(variableName, buffer); return true; @@ -678,6 +678,14 @@ public: this->Start = this->NormalizeIndex(this->Start, count); this->Stop = this->NormalizeIndex(this->Stop, count); + // Does stepping move us further from the end? + if (this->Start > this->Stop) { + throw transform_error( + cmStrCat("sub-command TRANSFORM, selector FOR " + "expects <start> to be no greater than <stop> (", + this->Start, " > ", this->Stop, ")")); + } + // compute indexes auto size = (this->Stop - this->Start + 1) / this->Step; if ((this->Stop - this->Start + 1) % this->Step != 0) { @@ -1026,9 +1034,10 @@ bool HandleTransformCommand(std::vector<std::string> const& args, } } - if (step < 0) { + if (step <= 0) { status.SetError("sub-command TRANSFORM, selector FOR expects " - "non negative numeric value for <step>."); + "positive numeric value for <step>."); + return false; } command.Selector = diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 2e444f2..3da266d 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -14,7 +14,6 @@ #include "cmListFileLexer.h" #include "cmMessageType.h" #include "cmMessenger.h" -#include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -370,68 +369,68 @@ cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const if (name == "if") { stack.push_back({ NestingStateEnum::If, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }); } else if (name == "elseif") { if (!TopIs(stack, NestingStateEnum::If)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.back() = { NestingStateEnum::If, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }; } else if (name == "else") { if (!TopIs(stack, NestingStateEnum::If)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.back() = { NestingStateEnum::Else, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }; } else if (name == "endif") { if (!TopIs(stack, NestingStateEnum::If) && !TopIs(stack, NestingStateEnum::Else)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.pop_back(); } else if (name == "while") { stack.push_back({ NestingStateEnum::While, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }); } else if (name == "endwhile") { if (!TopIs(stack, NestingStateEnum::While)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.pop_back(); } else if (name == "foreach") { stack.push_back({ NestingStateEnum::Foreach, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }); } else if (name == "endforeach") { if (!TopIs(stack, NestingStateEnum::Foreach)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.pop_back(); } else if (name == "function") { stack.push_back({ NestingStateEnum::Function, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }); } else if (name == "endfunction") { if (!TopIs(stack, NestingStateEnum::Function)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.pop_back(); } else if (name == "macro") { stack.push_back({ NestingStateEnum::Macro, - cmListFileContext::FromCommandContext(func, this->FileName), + cmListFileContext::FromListFileFunction(func, this->FileName), }); } else if (name == "endmacro") { if (!TopIs(stack, NestingStateEnum::Macro)) { - return cmListFileContext::FromCommandContext(func, this->FileName); + return cmListFileContext::FromListFileFunction(func, this->FileName); } stack.pop_back(); } @@ -444,45 +443,19 @@ cm::optional<cmListFileContext> cmListFileParser::CheckNesting() const return cm::nullopt; } -// We hold either the bottom scope of a directory or a call/file context. -// Discriminate these cases via the parent pointer. +// We hold a call/file context. struct cmListFileBacktrace::Entry { - Entry(cmStateSnapshot bottom) - : Bottom(bottom) - { - } - Entry(std::shared_ptr<Entry const> parent, cmListFileContext lfc) : Context(std::move(lfc)) , Parent(std::move(parent)) { } - ~Entry() - { - if (this->Parent) { - this->Context.~cmListFileContext(); - } else { - this->Bottom.~cmStateSnapshot(); - } - } - - bool IsBottom() const { return !this->Parent; } - - union - { - cmStateSnapshot Bottom; - cmListFileContext Context; - }; + cmListFileContext Context; std::shared_ptr<Entry const> Parent; }; -cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& snapshot) - : TopEntry(std::make_shared<Entry const>(snapshot.GetCallStackBottom())) -{ -} - /* NOLINTNEXTLINE(performance-unnecessary-value-param) */ cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> parent, cmListFileContext const& lfc) @@ -495,18 +468,6 @@ cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> top) { } -cmStateSnapshot cmListFileBacktrace::GetBottom() const -{ - cmStateSnapshot bottom; - if (Entry const* cur = this->TopEntry.get()) { - while (Entry const* parent = cur->Parent.get()) { - cur = parent; - } - bottom = cur->Bottom; - } - return bottom; -} - cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const { // We are entering a file-level scope but have not yet reached @@ -521,86 +482,24 @@ cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const cmListFileBacktrace cmListFileBacktrace::Push( cmListFileContext const& lfc) const { - assert(this->TopEntry); - assert(!this->TopEntry->IsBottom() || this->TopEntry->Bottom.IsValid()); return cmListFileBacktrace(this->TopEntry, lfc); } cmListFileBacktrace cmListFileBacktrace::Pop() const { assert(this->TopEntry); - assert(!this->TopEntry->IsBottom()); return cmListFileBacktrace(this->TopEntry->Parent); } cmListFileContext const& cmListFileBacktrace::Top() const { assert(this->TopEntry); - assert(!this->TopEntry->IsBottom()); return this->TopEntry->Context; } -void cmListFileBacktrace::PrintTitle(std::ostream& out) const -{ - // The title exists only if we have a call on top of the bottom. - if (!this->TopEntry || this->TopEntry->IsBottom()) { - return; - } - cmListFileContext lfc = this->TopEntry->Context; - cmStateSnapshot bottom = this->GetBottom(); - if (bottom.GetState()->GetProjectKind() == cmState::ProjectKind::Normal) { - lfc.FilePath = cmSystemTools::RelativeIfUnder( - bottom.GetState()->GetSourceDirectory(), lfc.FilePath); - } - out << (lfc.Line ? " at " : " in ") << lfc; -} - -void cmListFileBacktrace::PrintCallStack(std::ostream& out) const -{ - // The call stack exists only if we have at least two calls on top - // of the bottom. - if (!this->TopEntry || this->TopEntry->IsBottom() || - this->TopEntry->Parent->IsBottom()) { - return; - } - - bool first = true; - cmStateSnapshot bottom = this->GetBottom(); - for (Entry const* cur = this->TopEntry->Parent.get(); !cur->IsBottom(); - cur = cur->Parent.get()) { - if (cur->Context.Name.empty() && - cur->Context.Line != cmListFileContext::DeferPlaceholderLine) { - // Skip this whole-file scope. When we get here we already will - // have printed a more-specific context within the file. - continue; - } - if (first) { - first = false; - out << "Call Stack (most recent call first):\n"; - } - cmListFileContext lfc = cur->Context; - if (bottom.GetState()->GetProjectKind() == cmState::ProjectKind::Normal) { - lfc.FilePath = cmSystemTools::RelativeIfUnder( - bottom.GetState()->GetSourceDirectory(), lfc.FilePath); - } - out << " " << lfc << "\n"; - } -} - -size_t cmListFileBacktrace::Depth() const -{ - size_t depth = 0; - if (Entry const* cur = this->TopEntry.get()) { - for (; !cur->IsBottom(); cur = cur->Parent.get()) { - ++depth; - } - } - return depth; -} - bool cmListFileBacktrace::Empty() const { - return !this->TopEntry || this->TopEntry->IsBottom(); + return !this->TopEntry; } std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 98cb4a7..5d45027 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -4,7 +4,6 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <cstddef> #include <iosfwd> #include <memory> #include <string> @@ -13,7 +12,6 @@ #include <cm/optional> -#include "cmStateSnapshot.h" #include "cmSystemTools.h" /** \class cmListFileCache @@ -25,28 +23,6 @@ class cmMessenger; -struct cmCommandContext -{ - struct cmCommandName - { - std::string Original; - std::string Lower; - cmCommandName() = default; - cmCommandName(std::string name) - : Original(std::move(name)) - , Lower(cmSystemTools::LowerCase(this->Original)) - { - } - } Name; - long Line = 0; - cmCommandContext() = default; - cmCommandContext(std::string name, long line) - : Name(std::move(name)) - , Line(line) - { - } -}; - struct cmListFileArgument { enum Delimiter @@ -72,49 +48,6 @@ struct cmListFileArgument long Line = 0; }; -class cmListFileContext -{ -public: - std::string Name; - std::string FilePath; - long Line = 0; - static long const DeferPlaceholderLine = -1; - cm::optional<std::string> DeferId; - - cmListFileContext() = default; - cmListFileContext(std::string name, std::string filePath, long line) - : Name(std::move(name)) - , FilePath(std::move(filePath)) - , Line(line) - { - } - -#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 = {}) - { - cmListFileContext lfc; - lfc.FilePath = fileName; - lfc.Line = lfcc.Line; - lfc.Name = lfcc.Name.Original; - lfc.DeferId = std::move(deferId); - return lfc; - } -}; - -std::ostream& operator<<(std::ostream&, cmListFileContext const&); -bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs); -bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs); -bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs); - class cmListFileFunction { public: @@ -127,12 +60,12 @@ public: std::string const& OriginalName() const noexcept { - return this->Impl->Name.Original; + return this->Impl->OriginalName; } std::string const& LowerCaseName() const noexcept { - return this->Impl->Name.Lower; + return this->Impl->LowerCaseName; } long Line() const noexcept { return this->Impl->Line; } @@ -142,45 +75,86 @@ public: return this->Impl->Arguments; } - operator cmCommandContext const&() const noexcept { return *this->Impl; } - private: - struct Implementation : public cmCommandContext + struct Implementation { Implementation(std::string name, long line, std::vector<cmListFileArgument> args) - : cmCommandContext{ std::move(name), line } + : OriginalName{ std::move(name) } + , LowerCaseName{ cmSystemTools::LowerCase(this->OriginalName) } + , Line{ line } , Arguments{ std::move(args) } { } + + std::string OriginalName; + std::string LowerCaseName; + long Line = 0; std::vector<cmListFileArgument> Arguments; }; std::shared_ptr<Implementation const> Impl; }; +class cmListFileContext +{ +public: + std::string Name; + std::string FilePath; + long Line = 0; + static long const DeferPlaceholderLine = -1; + cm::optional<std::string> DeferId; + + cmListFileContext() = default; + cmListFileContext(cmListFileContext&& /*other*/) = default; + cmListFileContext(const cmListFileContext& /*other*/) = default; + cmListFileContext& operator=(const cmListFileContext& /*other*/) = default; +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + cmListFileContext& operator=(cmListFileContext&& /*other*/) = default; +#else + // The move assignment operators for several STL classes did not become + // noexcept until C++17, which causes some tools to warn about this move + // assignment operator throwing an exception when it shouldn't. + cmListFileContext& operator=(cmListFileContext&& /*other*/) = delete; +#endif + + cmListFileContext(std::string name, std::string filePath, long line) + : Name(std::move(name)) + , FilePath(std::move(filePath)) + , Line(line) + { + } + + static cmListFileContext FromListFileFunction( + cmListFileFunction const& lff, std::string const& fileName, + cm::optional<std::string> deferId = {}) + { + cmListFileContext lfc; + lfc.FilePath = fileName; + lfc.Line = lff.Line(); + lfc.Name = lff.OriginalName(); + lfc.DeferId = std::move(deferId); + return lfc; + } +}; + +std::ostream& operator<<(std::ostream&, cmListFileContext const&); +bool operator<(const cmListFileContext& lhs, const cmListFileContext& rhs); +bool operator==(cmListFileContext const& lhs, cmListFileContext const& rhs); +bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs); + // Represent a backtrace (call stack). Provide value semantics // but use efficient reference-counting underneath to avoid copies. class cmListFileBacktrace { public: - // Default-constructed backtrace may not be used until after - // set via assignment from a backtrace constructed with a - // valid snapshot. + // Default-constructed backtrace is empty. cmListFileBacktrace() = default; - // Construct an empty backtrace whose bottom sits in the directory - // indicated by the given valid snapshot. - cmListFileBacktrace(cmStateSnapshot const& snapshot); - - cmStateSnapshot GetBottom() const; - // Get a backtrace with the given file scope added to the top. - // May not be called until after construction with a valid snapshot. cmListFileBacktrace Push(std::string const& file) const; // Get a backtrace with the given call context added to the top. - // May not be called until after construction with a valid snapshot. cmListFileBacktrace Push(cmListFileContext const& lfc) const; // Get a backtrace with the top level removed. @@ -191,15 +165,6 @@ public: // This may be called only if Empty() would return false. cmListFileContext const& Top() const; - // Print the top of the backtrace. - void PrintTitle(std::ostream& out) const; - - // Print the call stack below the top of the backtrace. - void PrintCallStack(std::ostream& out) const; - - // Get the number of 'frames' in this backtrace - size_t Depth() const; - // Return true if this backtrace is empty. bool Empty() const; diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 2456db9..2080b40 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -44,6 +44,7 @@ namespace { const char* LastName = nullptr; +extern "C" void TrapsForSignals(int sig); extern "C" void TrapsForSignals(int sig) { fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n", diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index fc5e6e5..2adb232 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -37,6 +37,7 @@ #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" #include "cmMakefile.h" +#include "cmRange.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" @@ -834,16 +835,14 @@ cmValue cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target, } std::string cmLocalGenerator::ConvertToIncludeReference( - std::string const& path, IncludePathStyle pathStyle, OutputFormat format) + std::string const& path, OutputFormat format) { - static_cast<void>(pathStyle); return this->ConvertToOutputForExisting(path, format); } std::string cmLocalGenerator::GetIncludeFlags( std::vector<std::string> const& includeDirs, cmGeneratorTarget* target, - std::string const& lang, std::string const& config, bool forResponseFile, - IncludePathStyle pathStyle) + std::string const& lang, std::string const& config, bool forResponseFile) { if (lang.empty()) { return ""; @@ -922,8 +921,7 @@ std::string cmLocalGenerator::GetIncludeFlags( } flagUsed = true; } - std::string includePath = - this->ConvertToIncludeReference(i, pathStyle, shellFormat); + std::string includePath = this->ConvertToIncludeReference(i, shellFormat); if (quotePaths && !includePath.empty() && includePath.front() != '\"') { includeFlags << "\""; } @@ -1056,14 +1054,8 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } cmTarget* cmLocalGenerator::AddCustomCommandToTarget( - const std::string& target, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmCustomCommandType type, - const char* comment, const char* workingDir, - cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle, bool uses_terminal, - const std::string& depfile, const std::string& job_pool, - bool command_expand_lists, cmObjectLibraryCommands objLibCommands, - bool stdPipesUTF8) + const std::string& target, cmCustomCommandType type, + std::unique_ptr<cmCustomCommand> cc, cmObjectLibraryCommands objLibCommands) { cmTarget* t = this->Makefile->GetCustomCommandTarget( target, objLibCommands, this->DirectoryBacktrace); @@ -1071,74 +1063,43 @@ cmTarget* cmLocalGenerator::AddCustomCommandToTarget( return nullptr; } - detail::AddCustomCommandToTarget( - *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts, - depends, commandLines, type, comment, workingDir, escapeOldStyle, - uses_terminal, depfile, job_pool, command_expand_lists, stdPipesUTF8, - cmp0116); + cc->SetBacktrace(this->DirectoryBacktrace); - return t; -} + detail::AddCustomCommandToTarget(*this, cmCommandOrigin::Generator, t, type, + std::move(cc)); -cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( - const std::string& output, const std::vector<std::string>& depends, - const std::string& main_dependency, const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, - cmPolicies::PolicyStatus cmp0116, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool, bool stdPipesUTF8) -{ - std::vector<std::string> no_byproducts; - cmImplicitDependsList no_implicit_depends; - return this->AddCustomCommandToOutput( - { output }, no_byproducts, depends, main_dependency, no_implicit_depends, - commandLines, comment, workingDir, cmp0116, replace, escapeOldStyle, - uses_terminal, command_expand_lists, depfile, job_pool, stdPipesUTF8); + return t; } cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput( - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, cmPolicies::PolicyStatus cmp0116, bool replace, - bool escapeOldStyle, bool uses_terminal, bool command_expand_lists, - const std::string& depfile, const std::string& job_pool, bool stdPipesUTF8) + std::unique_ptr<cmCustomCommand> cc, bool replace) { // Make sure there is at least one output. - if (outputs.empty()) { + if (cc->GetOutputs().empty()) { cmSystemTools::Error("Attempt to add a custom rule with no output!"); return nullptr; } - return detail::AddCustomCommandToOutput( - *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs, - byproducts, depends, main_dependency, implicit_depends, commandLines, - comment, workingDir, replace, escapeOldStyle, uses_terminal, - command_expand_lists, depfile, job_pool, stdPipesUTF8, cmp0116); + cc->SetBacktrace(this->DirectoryBacktrace); + return detail::AddCustomCommandToOutput(*this, cmCommandOrigin::Generator, + std::move(cc), replace); } cmTarget* cmLocalGenerator::AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, const char* workingDir, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116, - bool escapeOldStyle, const char* comment, bool uses_terminal, - bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8) + const std::string& utilityName, bool excludeFromAll, + std::unique_ptr<cmCustomCommand> cc) { cmTarget* target = this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll); target->SetIsGeneratorProvided(true); - if (commandLines.empty() && depends.empty()) { + if (cc->GetCommandLines().empty() && cc->GetDepends().empty()) { return target; } - detail::AddUtilityCommand( - *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target, - workingDir, byproducts, depends, commandLines, escapeOldStyle, comment, - uses_terminal, command_expand_lists, job_pool, stdPipesUTF8, cmp0116); + cc->SetBacktrace(this->DirectoryBacktrace); + detail::AddUtilityCommand(*this, cmCommandOrigin::Generator, target, + std::move(cc)); return target; } @@ -1410,25 +1371,23 @@ std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags( } void cmLocalGenerator::GetDeviceLinkFlags( - cmLinkLineComputer* linkLineComputer, const std::string& config, + cmLinkLineComputer& linkLineComputer, const std::string& config, std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target) { cmGeneratorTarget::DeviceLinkSetter setter(*target); cmComputeLinkInformation* pcli = target->GetLinkInformation(config); - const std::string linkLanguage = - linkLineComputer->GetLinkerLanguage(target, config); if (pcli) { // Compute the required device link libraries when // resolving gpu lang device symbols - this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs, frameworkPath, + this->OutputLinkLibraries(pcli, &linkLineComputer, linkLibs, frameworkPath, linkPath); } std::vector<std::string> linkOpts; - target->GetLinkOptions(linkOpts, config, linkLanguage); + target->GetLinkOptions(linkOpts, config, "CUDA"); // LINK_OPTIONS are escaped. this->AppendCompileOptions(linkFlags, linkOpts); } @@ -2656,10 +2615,15 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) true); } else if (reuseTarget->GetType() == cmStateEnums::OBJECT_LIBRARY) { + // FIXME: This can propagate more than one level, unlike + // the rest of the object files in an object library. + // Find another way to do this. target->Target->AppendProperty( "INTERFACE_LINK_LIBRARIES", cmStrCat("$<$<CONFIG:", config, ">:$<LINK_ONLY:", pchSourceObj, ">>")); + // We updated the link interface, so ensure it is recomputed. + target->ClearLinkInterfaceCache(); } } } else { @@ -2751,8 +2715,6 @@ void cmLocalGenerator::CopyPchCompilePdb( file << "endforeach()\n"; } - bool stdPipesUTF8 = true; - auto configGenex = [&](cm::string_view expr) -> std::string { if (this->GetGlobalGenerator()->IsMultiConfig()) { return cmStrCat("$<$<CONFIG:", config, ">:", expr, ">"); @@ -2765,29 +2727,26 @@ void cmLocalGenerator::CopyPchCompilePdb( configGenex(cmStrCat("-DPDB_PREFIX=", pdb_prefix)), configGenex("-P"), configGenex(copy_script) }); - const std::string no_main_dependency; - const std::vector<std::string> no_deps; const char* no_message = ""; - const char* no_current_dir = nullptr; - const cmPolicies::PolicyStatus cmp0116_new = cmPolicies::NEW; - std::vector<std::string> no_byproducts; std::vector<std::string> outputs; outputs.push_back(configGenex( cmStrCat(target_compile_pdb_dir, pdb_prefix, ReuseFrom, ".pdb"))); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetCommandLines(commandLines); + cc->SetComment(no_message); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetStdPipesUTF8(true); + if (this->GetGlobalGenerator()->IsVisualStudio()) { + cc->SetByproducts(outputs); this->AddCustomCommandToTarget( - target->GetName(), outputs, no_deps, commandLines, - cmCustomCommandType::PRE_BUILD, no_message, no_current_dir, cmp0116_new, - true, false, "", "", false, cmObjectLibraryCommands::Accept, - stdPipesUTF8); + target->GetName(), cmCustomCommandType::PRE_BUILD, std::move(cc), + cmObjectLibraryCommands::Accept); } else { - cmImplicitDependsList no_implicit_depends; - cmSourceFile* copy_rule = this->AddCustomCommandToOutput( - outputs, no_byproducts, no_deps, no_main_dependency, no_implicit_depends, - commandLines, no_message, no_current_dir, cmp0116_new, false, true, - false, false, "", "", stdPipesUTF8); + cc->SetOutputs(outputs); + cmSourceFile* copy_rule = this->AddCustomCommandToOutput(std::move(cc)); if (copy_rule) { target->AddSource(copy_rule->ResolveFullPath()); @@ -2808,10 +2767,47 @@ inline void RegisterUnitySources(cmGeneratorTarget* target, cmSourceFile* sf, } } -void cmLocalGenerator::IncludeFileInUnitySources( - cmGeneratedFileStream& unity_file, std::string const& sf_full_path, - cmValue beforeInclude, cmValue afterInclude, cmValue uniqueIdName) const +cmLocalGenerator::UnitySource cmLocalGenerator::WriteUnitySource( + cmGeneratorTarget* target, std::vector<std::string> const& configs, + cmRange<std::vector<UnityBatchedSource>::const_iterator> sources, + cmValue beforeInclude, cmValue afterInclude, std::string filename) const +{ + cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); + cmGeneratedFileStream file( + filename, false, target->GetGlobalGenerator()->GetMakefileEncoding()); + file.SetCopyIfDifferent(true); + file << "/* generated by CMake */\n\n"; + + bool perConfig = false; + for (UnityBatchedSource const& ubs : sources) { + cm::optional<std::string> cond; + if (ubs.Configs.size() != configs.size()) { + perConfig = true; + cond = std::string(); + cm::string_view sep; + for (size_t ci : ubs.Configs) { + cond = cmStrCat(*cond, sep, "defined(CMAKE_UNITY_CONFIG_", + cmSystemTools::UpperCase(configs[ci]), ")"); + sep = " || "_s; + } + } + RegisterUnitySources(target, ubs.Source, filename); + WriteUnitySourceInclude(file, cond, ubs.Source->ResolveFullPath(), + beforeInclude, afterInclude, uniqueIdName); + } + + return UnitySource(std::move(filename), perConfig); +} + +void cmLocalGenerator::WriteUnitySourceInclude( + std::ostream& unity_file, cm::optional<std::string> const& cond, + std::string const& sf_full_path, cmValue beforeInclude, cmValue afterInclude, + cmValue uniqueIdName) const { + if (cond) { + unity_file << "#if " << *cond << "\n"; + } + if (cmNonempty(uniqueIdName)) { std::string pathToHash; auto PathEqOrSubDir = [](std::string const& a, std::string const& b) { @@ -2831,7 +2827,10 @@ void cmLocalGenerator::IncludeFileInUnitySources( unity_file << "/* " << pathToHash << " */\n" << "#undef " << *uniqueIdName << "\n" << "#define " << *uniqueIdName << " unity_" - << cmSystemTools::ComputeStringMD5(pathToHash) << "\n"; +#ifndef CMAKE_BOOTSTRAP + << cmSystemTools::ComputeStringMD5(pathToHash) << "\n" +#endif + ; } if (beforeInclude) { @@ -2843,21 +2842,25 @@ void cmLocalGenerator::IncludeFileInUnitySources( if (afterInclude) { unity_file << *afterInclude << "\n"; } + if (cond) { + unity_file << "#endif\n"; + } unity_file << "\n"; } -std::vector<std::string> cmLocalGenerator::AddUnityFilesModeAuto( +std::vector<cmLocalGenerator::UnitySource> +cmLocalGenerator::AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, - std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base, size_t batchSize) + std::vector<std::string> const& configs, + std::vector<UnityBatchedSource> const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base, size_t batchSize) { if (batchSize == 0) { batchSize = filtered_sources.size(); } - cmValue uniqueIdName = target->GetProperty("UNITY_BUILD_UNIQUE_ID"); - - std::vector<std::string> unity_files; + std::vector<UnitySource> unity_files; for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0; itemsLeft > 0; itemsLeft -= chunk, ++batch) { @@ -2865,74 +2868,48 @@ std::vector<std::string> cmLocalGenerator::AddUnityFilesModeAuto( std::string filename = cmStrCat(filename_base, "unity_", batch, (lang == "C") ? "_c.c" : "_cxx.cxx"); - - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - size_t begin = batch * batchSize; - size_t end = begin + chunk; - - cmGeneratedFileStream file( - filename_tmp, false, - target->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (; begin != end; ++begin) { - cmSourceFile* sf = filtered_sources[begin]; - RegisterUnitySources(target, sf, filename); - IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); - } - } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); - unity_files.emplace_back(std::move(filename)); + auto const begin = filtered_sources.begin() + batch * batchSize; + auto const end = begin + chunk; + unity_files.emplace_back(this->WriteUnitySource( + target, configs, cmMakeRange(begin, end), beforeInclude, afterInclude, + std::move(filename))); } return unity_files; } -std::vector<std::string> cmLocalGenerator::AddUnityFilesModeGroup( +std::vector<cmLocalGenerator::UnitySource> +cmLocalGenerator::AddUnityFilesModeGroup( cmGeneratorTarget* target, std::string const& lang, - std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base) + std::vector<std::string> const& configs, + std::vector<UnityBatchedSource> const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base) { - std::vector<std::string> unity_files; + std::vector<UnitySource> unity_files; // sources organized by group name. Drop any source // without a group - std::unordered_map<std::string, std::vector<cmSourceFile*>> explicit_mapping; - for (cmSourceFile* sf : filtered_sources) { - if (cmValue value = sf->GetProperty("UNITY_GROUP")) { + std::unordered_map<std::string, std::vector<UnityBatchedSource>> + explicit_mapping; + for (UnityBatchedSource const& ubs : filtered_sources) { + if (cmValue value = ubs.Source->GetProperty("UNITY_GROUP")) { auto i = explicit_mapping.find(*value); if (i == explicit_mapping.end()) { - std::vector<cmSourceFile*> sources{ sf }; - explicit_mapping.emplace(*value, sources); + std::vector<UnityBatchedSource> sources{ ubs }; + explicit_mapping.emplace(*value, std::move(sources)); } else { - i->second.emplace_back(sf); + i->second.emplace_back(ubs); } } } - cmValue 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, (lang == "C") ? "_c.c" : "_cxx.cxx"); - - const std::string filename_tmp = cmStrCat(filename, ".tmp"); - { - cmGeneratedFileStream file( - filename_tmp, false, - target->GetGlobalGenerator()->GetMakefileEncoding()); - file << "/* generated by CMake */\n\n"; - - for (cmSourceFile* sf : item.second) { - RegisterUnitySources(target, sf, filename); - IncludeFileInUnitySources(file, sf->ResolveFullPath(), beforeInclude, - afterInclude, uniqueIdName); - } - } - cmSystemTools::MoveFileIfDifferent(filename_tmp, filename); - unity_files.emplace_back(std::move(filename)); + unity_files.emplace_back(this->WriteUnitySource( + target, configs, cmMakeRange(item.second), beforeInclude, afterInclude, + std::move(filename))); } return unity_files; @@ -2944,20 +2921,33 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) return; } - // FIXME: Handle all configurations in multi-config generators. - std::string config; - if (!this->GetGlobalGenerator()->IsMultiConfig()) { - config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + std::vector<UnityBatchedSource> unitySources; + + std::vector<std::string> configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + std::map<cmSourceFile const*, size_t> index; + + for (size_t ci = 0; ci < configs.size(); ++ci) { + // FIXME: Refactor collection of sources to not evaluate object libraries. + std::vector<cmSourceFile*> sources; + target->GetSourceFiles(sources, configs[ci]); + for (cmSourceFile* sf : sources) { + auto mi = index.find(sf); + if (mi == index.end()) { + unitySources.emplace_back(sf); + std::map<cmSourceFile const*, size_t>::value_type entry( + sf, unitySources.size() - 1); + mi = index.insert(entry).first; + } + unitySources[mi->second].Configs.emplace_back(ci); + } } std::string filename_base = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", target->GetName(), ".dir/Unity/"); - // FIXME: Refactor collection of sources to not evaluate object libraries. - std::vector<cmSourceFile*> sources; - target->GetSourceFiles(sources, config); - cmValue batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE"); const size_t unityBatchSize = batchSizeString ? static_cast<size_t>(std::atoi(batchSizeString->c_str())) @@ -2969,9 +2959,11 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE"); for (std::string lang : { "C", "CXX" }) { - std::vector<cmSourceFile*> filtered_sources; - std::copy_if(sources.begin(), sources.end(), - std::back_inserter(filtered_sources), [&](cmSourceFile* sf) { + std::vector<UnityBatchedSource> filtered_sources; + std::copy_if(unitySources.begin(), unitySources.end(), + std::back_inserter(filtered_sources), + [&](UnityBatchedSource const& ubs) -> bool { + cmSourceFile* sf = ubs.Source; return sf->GetLanguage() == lang && !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") && !sf->GetPropertyAsBool("HEADER_FILE_ONLY") && @@ -2981,15 +2973,15 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) !sf->GetProperty("INCLUDE_DIRECTORIES"); }); - std::vector<std::string> unity_files; + std::vector<UnitySource> unity_files; if (!unityMode || *unityMode == "BATCH") { - unity_files = - AddUnityFilesModeAuto(target, lang, filtered_sources, beforeInclude, - afterInclude, filename_base, unityBatchSize); + unity_files = AddUnityFilesModeAuto( + target, lang, configs, filtered_sources, beforeInclude, afterInclude, + filename_base, unityBatchSize); } else if (unityMode && *unityMode == "GROUP") { unity_files = - AddUnityFilesModeGroup(target, lang, filtered_sources, beforeInclude, - afterInclude, filename_base); + AddUnityFilesModeGroup(target, lang, configs, filtered_sources, + beforeInclude, afterInclude, filename_base); } else { // unity mode is set to an unsupported value std::string e("Invalid UNITY_BUILD_MODE value of " + *unityMode + @@ -2998,11 +2990,15 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) this->IssueMessage(MessageType::FATAL_ERROR, e); } - for (auto const& file : unity_files) { - auto* unity = this->GetMakefile()->GetOrCreateSource(file); - target->AddSource(file, true); + for (UnitySource const& file : unity_files) { + auto* unity = this->GetMakefile()->GetOrCreateSource(file.Path); + target->AddSource(file.Path, true); unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON"); - unity->SetProperty("UNITY_SOURCE_FILE", file); + unity->SetProperty("UNITY_SOURCE_FILE", file.Path); + if (file.PerConfig) { + unity->SetProperty("COMPILE_DEFINITIONS", + "CMAKE_UNITY_CONFIG_$<UPPER_CASE:$<CONFIG>>"); + } } } } @@ -3439,21 +3435,27 @@ void cmLocalGenerator::GenerateTargetInstallRules( static bool cmLocalGeneratorShortenObjectName(std::string& objName, std::string::size_type max_len) { + // Check if the path can be shortened using an md5 sum replacement for + // a portion of the path. + std::string::size_type md5Len = 32; + std::string::size_type numExtraChars = objName.size() - max_len + md5Len; + std::string::size_type pos = objName.find('/', numExtraChars); + if (pos == std::string::npos) { + pos = objName.rfind('/', numExtraChars); + if (pos == std::string::npos || pos <= md5Len) { + return false; + } + } + // Replace the beginning of the path portion of the object name with // its own md5 sum. - std::string::size_type pos = - objName.find('/', objName.size() - max_len + 32); - if (pos != std::string::npos) { - cmCryptoHash md5(cmCryptoHash::AlgoMD5); - std::string md5name = cmStrCat(md5.HashString(objName.substr(0, pos)), - cm::string_view(objName).substr(pos)); - objName = md5name; + cmCryptoHash md5(cmCryptoHash::AlgoMD5); + std::string md5name = cmStrCat(md5.HashString(objName.substr(0, pos)), + cm::string_view(objName).substr(pos)); + objName = md5name; - // The object name is now short enough. - return true; - } - // The object name could not be shortened enough. - return false; + // The object name is now shorter, check if it is short enough. + return pos >= numExtraChars; } bool cmLocalGeneratorCheckObjectName(std::string& objName, @@ -3505,7 +3507,7 @@ std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName( bool done; int cc = 0; char rpstr[100]; - sprintf(rpstr, "_p_"); + snprintf(rpstr, sizeof(rpstr), "_p_"); cmSystemTools::ReplaceString(ssin, "+", rpstr); std::string sssin = sin; do { @@ -3521,7 +3523,7 @@ std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName( } sssin = ssin; cmSystemTools::ReplaceString(ssin, "_p_", rpstr); - sprintf(rpstr, "_p%d_", cc++); + snprintf(rpstr, sizeof(rpstr), "_p%d_", cc++); } while (!done); } @@ -4015,23 +4017,20 @@ std::string ComputeCustomCommandRuleFileName(cmLocalGenerator& lg, h.HashString(output).substr(0, 16)); } -cmSourceFile* AddCustomCommand( - cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116) +cmSourceFile* AddCustomCommand(cmLocalGenerator& lg, cmCommandOrigin origin, + std::unique_ptr<cmCustomCommand> cc, + bool replace) { cmMakefile* mf = lg.GetMakefile(); + const auto& lfbt = cc->GetBacktrace(); + const auto& outputs = cc->GetOutputs(); + const auto& byproducts = cc->GetByproducts(); + const auto& commandLines = cc->GetCommandLines(); // Choose a source file on which to store the custom command. cmSourceFile* file = nullptr; - if (!commandLines.empty() && !main_dependency.empty()) { + if (!commandLines.empty() && cc->HasMainDependency()) { + const auto& main_dependency = cc->GetMainDependency(); // The main dependency was specified. Use it unless a different // custom command already used it. file = mf->GetSource(main_dependency); @@ -4081,29 +4080,14 @@ cmSourceFile* AddCustomCommand( // Attach the custom command to the file. if (file) { - // Construct a complete list of dependencies. - std::vector<std::string> depends2(depends); - if (!main_dependency.empty()) { - depends2.push_back(main_dependency); - } - - std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>( - outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir, - stdPipesUTF8); - cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); - cc->SetImplicitDepends(implicit_depends); - cc->SetUsesTerminal(uses_terminal); - cc->SetCommandExpandLists(command_expand_lists); - cc->SetDepfile(depfile); - cc->SetJobPool(job_pool); - cc->SetCMP0116Status(cmp0116); - file->SetCustomCommand(std::move(cc)); lg.AddSourceOutputs(file, outputs, cmLocalGenerator::OutputRole::Primary, lfbt, origin); lg.AddSourceOutputs(file, byproducts, cmLocalGenerator::OutputRole::Byproduct, lfbt, origin); + + file->SetCustomCommand(std::move(cc)); } return file; } @@ -4132,63 +4116,38 @@ bool AnyTargetCommandOutputMatches( } namespace detail { -void AddCustomCommandToTarget(cmLocalGenerator& lg, - const cmListFileBacktrace& lfbt, - cmCommandOrigin origin, cmTarget* target, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, - cmCustomCommandType type, const char* comment, - const char* workingDir, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile, - const std::string& job_pool, - bool command_expand_lists, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116) +void AddCustomCommandToTarget(cmLocalGenerator& lg, cmCommandOrigin origin, + cmTarget* target, cmCustomCommandType type, + std::unique_ptr<cmCustomCommand> cc) { // 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, - comment, workingDir, stdPipesUTF8); - cc.SetEscapeOldStyle(escapeOldStyle); - cc.SetEscapeAllowMakeVars(true); - cc.SetUsesTerminal(uses_terminal); - cc.SetCommandExpandLists(command_expand_lists); - cc.SetDepfile(depfile); - cc.SetJobPool(job_pool); - cc.SetCMP0116Status(cmp0116); - cc.SetTarget(target->GetName()); + cc->SetEscapeAllowMakeVars(true); + cc->SetTarget(target->GetName()); + + lg.AddTargetByproducts(target, cc->GetByproducts(), cc->GetBacktrace(), + origin); + switch (type) { case cmCustomCommandType::PRE_BUILD: - target->AddPreBuildCommand(std::move(cc)); + target->AddPreBuildCommand(std::move(*cc)); break; case cmCustomCommandType::PRE_LINK: - target->AddPreLinkCommand(std::move(cc)); + target->AddPreLinkCommand(std::move(*cc)); break; case cmCustomCommandType::POST_BUILD: - target->AddPostBuildCommand(std::move(cc)); + target->AddPostBuildCommand(std::move(*cc)); break; } - lg.AddTargetByproducts(target, byproducts, lfbt, origin); + cc.reset(); } -cmSourceFile* AddCustomCommandToOutput( - cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116) +cmSourceFile* AddCustomCommandToOutput(cmLocalGenerator& lg, + cmCommandOrigin origin, + std::unique_ptr<cmCustomCommand> cc, + bool replace) { - 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, cmp0116); + return AddCustomCommand(lg, origin, std::move(cc), replace); } void AppendCustomCommandToOutput(cmLocalGenerator& lg, @@ -4231,33 +4190,25 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, lfbt); } -void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - cmCommandOrigin origin, cmTarget* target, - const char* workingDir, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, - bool escapeOldStyle, const char* comment, - bool uses_terminal, bool command_expand_lists, - const std::string& job_pool, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116) +void AddUtilityCommand(cmLocalGenerator& lg, cmCommandOrigin origin, + cmTarget* target, std::unique_ptr<cmCustomCommand> cc) { + // They might be moved away + auto byproducts = cc->GetByproducts(); + auto lfbt = cc->GetBacktrace(); + // Use an empty comment to avoid generation of default comment. - if (!comment) { - comment = ""; + if (!cc->GetComment()) { + cc->SetComment(""); } // Create the generated symbolic output name of the utility target. std::string output = lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt); + cc->SetOutputs(output); - std::string no_main_dependency; - cmImplicitDependsList no_implicit_depends; - cmSourceFile* rule = AddCustomCommand( - 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, cmp0116); + cmSourceFile* rule = AddCustomCommand(lg, origin, std::move(cc), + /*replace=*/false); if (rule) { lg.AddTargetByproducts(target, byproducts, lfbt, origin); } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 3614c84..115a54a 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -11,8 +11,11 @@ #include <set> #include <string> #include <unordered_map> +#include <utility> #include <vector> +#include <cm/optional> + #include <cm3p/kwiml/int.h> #include "cmCustomCommandTypes.h" @@ -28,7 +31,6 @@ class cmComputeLinkInformation; class cmCustomCommand; class cmCustomCommandGenerator; class cmCustomCommandLines; -class cmGeneratedFileStream; class cmGeneratorTarget; class cmGlobalGenerator; class cmImplicitDependsList; @@ -40,6 +42,9 @@ class cmState; class cmTarget; class cmake; +template <typename Iter> +class cmRange; + /** Flag if byproducts shall also be considered. */ enum class cmSourceOutputKind { @@ -174,18 +179,12 @@ public: bool AppendLWYUFlags(std::string& flags, const cmGeneratorTarget* target, const std::string& lang); - enum class IncludePathStyle - { - Default, - Absolute, - }; - //! Get the include flags for the current makefile and language - std::string GetIncludeFlags( - std::vector<std::string> const& includes, cmGeneratorTarget* target, - std::string const& lang, std::string const& config, - bool forResponseFile = false, - IncludePathStyle pathStyle = IncludePathStyle::Default); + std::string GetIncludeFlags(std::vector<std::string> const& includes, + cmGeneratorTarget* target, + std::string const& lang, + std::string const& config, + bool forResponseFile = false); using GeneratorTargetVector = std::vector<std::unique_ptr<cmGeneratorTarget>>; @@ -194,6 +193,11 @@ public: return this->GeneratorTargets; } + const GeneratorTargetVector& GetOwnedImportedGeneratorTargets() const + { + return this->OwnedImportedGeneratorTargets; + } + void AddGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt); void AddImportedGeneratorTarget(cmGeneratorTarget* gt); void AddOwnedImportedGeneratorTarget(std::unique_ptr<cmGeneratorTarget> gt); @@ -324,53 +328,23 @@ public: * Add a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a target. */ cmTarget* AddCustomCommandToTarget( - const std::string& target, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmCustomCommandType type, - const char* comment, const char* workingDir, - cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle = true, - bool uses_terminal = false, const std::string& depfile = "", - const std::string& job_pool = "", bool command_expand_lists = false, - cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject, - bool stdPipesUTF8 = false); + const std::string& target, cmCustomCommandType type, + std::unique_ptr<cmCustomCommand> cc, + cmObjectLibraryCommands objLibCommands = cmObjectLibraryCommands::Reject); /** * Add a custom command to a source file. */ - cmSourceFile* AddCustomCommandToOutput( - const std::string& output, const std::vector<std::string>& depends, - const std::string& main_dependency, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, cmPolicies::PolicyStatus cmp0116, - bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false, bool command_expand_lists = false, - const std::string& depfile = "", const std::string& job_pool = "", - bool stdPipesUTF8 = false); - cmSourceFile* AddCustomCommandToOutput( - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, cmPolicies::PolicyStatus cmp0116, - bool replace = false, bool escapeOldStyle = true, - bool uses_terminal = false, bool command_expand_lists = false, - const std::string& depfile = "", const std::string& job_pool = "", - bool stdPipesUTF8 = false); + cmSourceFile* AddCustomCommandToOutput(std::unique_ptr<cmCustomCommand> cc, + bool replace = false); /** * Add a utility to the build. A utility target is a command that is run * every time the target is built. */ - cmTarget* AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, - const char* workingDir, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116, - bool escapeOldStyle = true, const char* comment = nullptr, - bool uses_terminal = false, bool command_expand_lists = false, - const std::string& job_pool = "", bool stdPipesUTF8 = false); + cmTarget* AddUtilityCommand(const std::string& utilityName, + bool excludeFromAll, + std::unique_ptr<cmCustomCommand> cc); virtual std::string CreateUtilityOutput( std::string const& targetName, std::vector<std::string> const& byproducts, @@ -496,7 +470,7 @@ public: /** Fill out these strings for the given target. Libraries to link, * flags, and linkflags. */ - void GetDeviceLinkFlags(cmLinkLineComputer* linkLineComputer, + void GetDeviceLinkFlags(cmLinkLineComputer& linkLineComputer, const std::string& config, std::string& linkLibs, std::string& linkFlags, std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target); @@ -550,12 +524,11 @@ public: cmValue GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop); protected: - // The default implementation ignores the IncludePathStyle and always - // uses absolute paths. A generator may override this to use relative - // paths in some cases. + // The default implementation converts to a Windows shortpath to + // help older toolchains handle spaces and such. A generator may + // override this to avoid that conversion. virtual std::string ConvertToIncludeReference( - std::string const& path, IncludePathStyle pathStyle, - cmOutputConverter::OutputFormat format); + std::string const& path, cmOutputConverter::OutputFormat format); //! put all the libraries for a target on into the given stream void OutputLinkLibraries(cmComputeLinkInformation* pcli, @@ -657,18 +630,48 @@ private: const std::string& ReuseFrom, cmGeneratorTarget* reuseTarget, std::vector<std::string> const& extensions); - void IncludeFileInUnitySources(cmGeneratedFileStream& unity_file, - std::string const& sf_full_path, - cmValue beforeInclude, cmValue afterInclude, - cmValue uniqueIdName) const; - std::vector<std::string> AddUnityFilesModeAuto( + + struct UnityBatchedSource + { + cmSourceFile* Source = nullptr; + std::vector<size_t> Configs; + UnityBatchedSource(cmSourceFile* sf) + : Source(sf) + { + } + }; + struct UnitySource + { + std::string Path; + bool PerConfig = false; + UnitySource(std::string path, bool perConfig) + : Path(std::move(path)) + , PerConfig(perConfig) + { + } + }; + + UnitySource WriteUnitySource( + cmGeneratorTarget* target, std::vector<std::string> const& configs, + cmRange<std::vector<UnityBatchedSource>::const_iterator> sources, + cmValue beforeInclude, cmValue afterInclude, std::string filename) const; + void WriteUnitySourceInclude(std::ostream& unity_file, + cm::optional<std::string> const& cond, + std::string const& sf_full_path, + cmValue beforeInclude, cmValue afterInclude, + cmValue uniqueIdName) const; + std::vector<UnitySource> AddUnityFilesModeAuto( cmGeneratorTarget* target, std::string const& lang, - std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base, size_t batchSize); - std::vector<std::string> AddUnityFilesModeGroup( + std::vector<std::string> const& configs, + std::vector<UnityBatchedSource> const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base, size_t batchSize); + std::vector<UnitySource> AddUnityFilesModeGroup( cmGeneratorTarget* target, std::string const& lang, - std::vector<cmSourceFile*> const& filtered_sources, cmValue beforeInclude, - cmValue afterInclude, std::string const& filename_base); + std::vector<std::string> const& configs, + std::vector<UnityBatchedSource> const& filtered_sources, + cmValue beforeInclude, cmValue afterInclude, + std::string const& filename_base); }; #if !defined(CMAKE_BOOTSTRAP) @@ -678,30 +681,14 @@ bool cmLocalGeneratorCheckObjectName(std::string& objName, #endif namespace detail { -void AddCustomCommandToTarget(cmLocalGenerator& lg, - const cmListFileBacktrace& lfbt, - cmCommandOrigin origin, cmTarget* target, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, - cmCustomCommandType type, const char* comment, - const char* workingDir, bool escapeOldStyle, - bool uses_terminal, const std::string& depfile, - const std::string& job_pool, - bool command_expand_lists, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116); - -cmSourceFile* AddCustomCommandToOutput( - cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116); +void AddCustomCommandToTarget(cmLocalGenerator& lg, cmCommandOrigin origin, + cmTarget* target, cmCustomCommandType type, + std::unique_ptr<cmCustomCommand> cc); + +cmSourceFile* AddCustomCommandToOutput(cmLocalGenerator& lg, + cmCommandOrigin origin, + std::unique_ptr<cmCustomCommand> cc, + bool replace); void AppendCustomCommandToOutput(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, @@ -710,16 +697,8 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines); -void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - cmCommandOrigin origin, cmTarget* target, - const char* workingDir, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, - bool escapeOldStyle, const char* comment, - bool uses_terminal, bool command_expand_lists, - const std::string& job_pool, bool stdPipesUTF8, - cmPolicies::PolicyStatus cmp0116); +void AddUtilityCommand(cmLocalGenerator& lg, cmCommandOrigin origin, + cmTarget* target, std::unique_ptr<cmCustomCommand> cc); std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target); std::vector<std::string> ComputeISPCExtraObjects( diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 8556fe6..106f76b 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -205,11 +205,8 @@ cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator() // Virtual protected methods. std::string cmLocalNinjaGenerator::ConvertToIncludeReference( - std::string const& path, IncludePathStyle pathStyle, - cmOutputConverter::OutputFormat format) + std::string const& path, cmOutputConverter::OutputFormat format) { - // FIXME: Remove IncludePathStyle infrastructure. It is no longer used. - static_cast<void>(pathStyle); return this->ConvertToOutputFormat(path, format); } diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index 6404037..3118bb4 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -12,7 +12,6 @@ #include "cmListFileCache.h" #include "cmLocalCommonGenerator.h" -#include "cmLocalGenerator.h" #include "cmNinjaTypes.h" #include "cmOutputConverter.h" @@ -93,8 +92,7 @@ public: protected: std::string ConvertToIncludeReference( - std::string const& path, IncludePathStyle pathStyle, - cmOutputConverter::OutputFormat format) override; + std::string const& path, cmOutputConverter::OutputFormat format) override; private: cmGeneratedFileStream& GetImplFileStream(const std::string& config) const; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 7e39b91..0f8cdca 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1274,12 +1274,12 @@ std::string cmLocalUnixMakefileGenerator3::CreateMakeVariable( cmSystemTools::ReplaceString(ret, "-", "__"); cmSystemTools::ReplaceString(ret, "+", "___"); int ni = 0; - char buffer[5]; + char buffer[12]; // make sure the _ version is not already used, if // it is used then add number to the end of the variable while (this->ShortMakeVariableMap.count(ret) && ni < 1000) { ++ni; - sprintf(buffer, "%04d", ni); + snprintf(buffer, sizeof(buffer), "%04d", ni); ret = unmodified + buffer; } this->ShortMakeVariableMap[ret] = "1"; @@ -1302,13 +1302,13 @@ std::string cmLocalUnixMakefileGenerator3::CreateMakeVariable( if (static_cast<int>(str1.size()) + static_cast<int>(str2.size()) > size) { str1 = str1.substr(0, size - str2.size()); } - char buffer[5]; + char buffer[12]; int ni = 0; - sprintf(buffer, "%04d", ni); + snprintf(buffer, sizeof(buffer), "%04d", ni); ret = str1 + str2 + buffer; while (this->ShortMakeVariableMap.count(ret) && ni < 1000) { ++ni; - sprintf(buffer, "%04d", ni); + snprintf(buffer, sizeof(buffer), "%04d", ni); ret = str1 + str2 + buffer; } if (ni == 1000) { diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index 3ed49a0..4c0d2eea 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -2,18 +2,19 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalVisualStudio10Generator.h" -#include <cmext/algorithm> - #include <cm3p/expat.h> -#include "cmAlgorithms.h" -#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmGlobalVisualStudio10Generator.h" -#include "cmMakefile.h" +#include "cmGlobalVisualStudioGenerator.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmVisualStudio10TargetGenerator.h" #include "cmXMLParser.h" #include "cmake.h" +class cmGeneratorTarget; + class cmVS10XMLParser : public cmXMLParser { public: diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h index 45ee082..75fe262 100644 --- a/Source/cmLocalVisualStudio10Generator.h +++ b/Source/cmLocalVisualStudio10Generator.h @@ -8,6 +8,7 @@ #include "cmLocalVisualStudio7Generator.h" +class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 96dda53..ed7e888 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -2,26 +2,45 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalVisualStudio7Generator.h" +#include <algorithm> +#include <cassert> +#include <cstring> +#include <functional> +#include <sstream> +#include <utility> + #include <cm/memory> #include <cmext/algorithm> #include <windows.h> #include <cm3p/expat.h> -#include <ctype.h> // for isspace + +#include "cmsys/FStream.hxx" #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" +#include "cmCustomCommandLines.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmGlobalVisualStudio7Generator.h" +#include "cmGlobalVisualStudioGenerator.h" +#include "cmListFileCache.h" #include "cmMakefile.h" -#include "cmMessageType.h" +#include "cmOutputConverter.h" +#include "cmPolicies.h" #include "cmSourceFile.h" +#include "cmSourceGroup.h" +#include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTargetDepend.h" +#include "cmValue.h" +#include "cmVsProjectType.h" #include "cmXMLParser.h" #include "cmake.h" @@ -109,19 +128,21 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() const auto& tgts = this->GetGeneratorTargets(); for (auto& l : tgts) { if (l->GetType() == cmStateEnums::GLOBAL_TARGET) { - std::vector<std::string> no_depends; cmCustomCommandLines force_commands = cmMakeSingleCommandLine({ "cd", "." }); - std::string no_main_dependency; std::string force = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", l->GetName(), "_force"); if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) { sf->SetProperty("SYMBOLIC", "1"); } - if (cmSourceFile* file = this->AddCustomCommandToOutput( - force, no_depends, no_main_dependency, force_commands, " ", - nullptr, cmPolicies::NEW, true)) { + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(force); + cc->SetCommandLines(force_commands); + cc->SetComment(" "); + cc->SetCMP0116Status(cmPolicies::NEW); + if (cmSourceFile* file = + this->AddCustomCommandToOutput(std::move(cc), true)) { l->AddSource(file->ResolveFullPath()); } } @@ -177,8 +198,8 @@ void cmLocalVisualStudio7Generator::GenerateTarget(cmGeneratorTarget* target) // Intel Fortran for VS10 uses VS9 format ".vfproj" files. cmGlobalVisualStudioGenerator::VSVersion realVersion = gg->GetVersion(); if (this->FortranProject && - gg->GetVersion() >= cmGlobalVisualStudioGenerator::VS10) { - gg->SetVersion(cmGlobalVisualStudioGenerator::VS9); + gg->GetVersion() >= cmGlobalVisualStudioGenerator::VSVersion::VS10) { + gg->SetVersion(cmGlobalVisualStudioGenerator::VSVersion::VS9); } // add to the list of projects @@ -239,16 +260,20 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() std::string argB = cmStrCat("-B", this->GetBinaryDirectory()); std::string stampName = cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/generate.stamp"); - bool stdPipesUTF8 = true; cmCustomCommandLines commandLines = cmMakeSingleCommandLine({ cmSystemTools::GetCMakeCommand(), argS, argB, "--check-stamp-file", stampName }); std::string comment = cmStrCat("Building Custom Rule ", makefileIn); - const char* no_working_directory = nullptr; - this->AddCustomCommandToOutput(stampName, listFiles, makefileIn, - commandLines, comment.c_str(), - no_working_directory, cmPolicies::NEW, true, - false, false, false, "", "", stdPipesUTF8); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(stampName); + cc->SetMainDependency(makefileIn); + cc->SetDepends(listFiles); + cc->SetCommandLines(commandLines); + cc->SetComment(comment.c_str()); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetStdPipesUTF8(true); + this->AddCustomCommandToOutput(std::move(cc), true); if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) { // Finalize the source file path now since we're adding this after // the generator validated all project-named sources. @@ -546,7 +571,17 @@ public: this->First = true; this->Stream << "\t\t\t<Tool\n\t\t\t\tName=\"" << tool << "\""; } - void Finish() { this->Stream << (this->First ? "" : "\"") << "/>\n"; } + void Finish() + { + // If any commands were generated, finish constructing them. + if (!this->First) { + std::string finishScript = + this->LG->FinishConstructScript(VsProjectType::vcxproj); + this->Stream << this->LG->EscapeForXML(finishScript) << "\""; + } + + this->Stream << "/>\n"; + } void Write(std::vector<cmCustomCommand> const& ccs) { for (cmCustomCommand const& command : ccs) { @@ -1071,7 +1106,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n"; } if (this->WindowsCEProject) { - if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS9) { + if (this->GetVersion() < + cmGlobalVisualStudioGenerator::VSVersion::VS9) { fout << "\t\t\t\tSubSystem=\"9\"\n"; } else { fout << "\t\t\t\tSubSystem=\"8\"\n"; @@ -1148,7 +1184,8 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( fout << "\t\t\t\tGenerateDebugInformation=\"true\"\n"; } if (this->WindowsCEProject) { - if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS9) { + if (this->GetVersion() < + cmGlobalVisualStudioGenerator::VSVersion::VS9) { fout << "\t\t\t\tSubSystem=\"9\"\n"; } else { fout << "\t\t\t\tSubSystem=\"8\"\n"; @@ -1784,6 +1821,7 @@ void cmLocalVisualStudio7Generator::WriteCustomRule( if (this->FortranProject) { cmSystemTools::ReplaceString(script, "$(Configuration)", config); } + script += this->FinishConstructScript(VsProjectType::vcxproj); /* clang-format off */ fout << "\t\t\t\t\t<Tool\n" << "\t\t\t\t\tName=\"" << customTool << "\"\n" @@ -1990,7 +2028,8 @@ void cmLocalVisualStudio7Generator::WriteProjectStart( << "<VisualStudioProject\n" << "\tProjectType=\"Visual C++\"\n"; /* clang-format on */ - fout << "\tVersion=\"" << (gg->GetVersion() / 10) << ".00\"\n"; + fout << "\tVersion=\"" << (static_cast<uint16_t>(gg->GetVersion()) / 10) + << ".00\"\n"; cmValue p = target->GetProperty("PROJECT_LABEL"); const std::string projLabel = p ? *p : libName; p = target->GetProperty("VS_KEYWORD"); diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 6e06c09..d95ebc2 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -5,7 +5,9 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <map> #include <memory> +#include <set> #include <string> #include <vector> diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 03213ef..93f01ed 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -2,15 +2,21 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalVisualStudioGenerator.h" +#include <utility> + #include "windows.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" +#include "cmCustomCommandLines.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmOutputConverter.h" #include "cmSourceFile.h" +#include "cmStateTypes.h" #include "cmSystemTools.h" +#include "cmValue.h" cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator( cmGlobalGenerator* gg, cmMakefile* mf) @@ -99,15 +105,11 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target, } // Add a pre-build event to create the directory. - std::vector<std::string> no_output; - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; - bool stdPipesUTF8 = true; cmCustomCommandLines commands = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir }); - pcc.reset(new cmCustomCommand(no_output, no_byproducts, no_depends, commands, - cmListFileBacktrace(), nullptr, nullptr, - stdPipesUTF8)); + pcc.reset(new cmCustomCommand()); + pcc->SetCommandLines(commands); + pcc->SetStdPipesUTF8(true); pcc->SetEscapeOldStyle(false); pcc->SetEscapeAllowMakeVars(true); return pcc; @@ -241,3 +243,20 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( return script; } + +std::string cmLocalVisualStudioGenerator::FinishConstructScript( + VsProjectType projectType, const std::string& newline) +{ + bool useLocal = this->CustomCommandUseLocal(); + + // Store the script in a string. + std::string script; + + if (useLocal && projectType == VsProjectType::csproj) { + // This label is not provided by MSBuild for C# projects. + script += newline; + script += this->GetReportErrorLabel(); + } + + return script; +} diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h index 91fb6b0..cf4f4d9 100644 --- a/Source/cmLocalVisualStudioGenerator.h +++ b/Source/cmLocalVisualStudioGenerator.h @@ -10,6 +10,7 @@ #include "cmGlobalVisualStudioGenerator.h" #include "cmLocalGenerator.h" +#include "cmVsProjectType.h" class cmCustomCommand; class cmCustomCommandGenerator; @@ -30,9 +31,10 @@ public: cmLocalVisualStudioGenerator(cmGlobalGenerator* gg, cmMakefile* mf); virtual ~cmLocalVisualStudioGenerator(); - /** Construct a script from the given list of command lines. */ std::string ConstructScript(cmCustomCommandGenerator const& ccg, const std::string& newline = "\n"); + std::string FinishConstructScript(VsProjectType projectType, + const std::string& newline = "\n"); /** Label to which to jump in a batch file after a failed step in a sequence of custom commands. */ diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index 3b4e3a8..dd064a1 100644 --- a/Source/cmLocalXCodeGenerator.cxx +++ b/Source/cmLocalXCodeGenerator.cxx @@ -2,14 +2,18 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmLocalXCodeGenerator.h" +#include <memory> +#include <ostream> +#include <utility> + #include "cmGeneratorTarget.h" #include "cmGlobalXCodeGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" -class cmGeneratorTarget; class cmGlobalGenerator; -class cmMakefile; cmLocalXCodeGenerator::cmLocalXCodeGenerator(cmGlobalGenerator* gg, cmMakefile* mf) diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h index 5f72f6d..ff6b356 100644 --- a/Source/cmLocalXCodeGenerator.h +++ b/Source/cmLocalXCodeGenerator.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <iosfwd> #include <map> #include <string> diff --git a/Source/cmMachO.cxx b/Source/cmMachO.cxx index 53112e0..4fcaedf 100644 --- a/Source/cmMachO.cxx +++ b/Source/cmMachO.cxx @@ -56,7 +56,7 @@ bool peek(cmsys::ifstream& fin, T& v) template <typename T> bool read(cmsys::ifstream& fin, T& v) { - return !!fin.read(reinterpret_cast<char*>(&v), sizeof(T)); + return static_cast<bool>(fin.read(reinterpret_cast<char*>(&v), sizeof(T))); } // read from the file and fill multiple data structures where @@ -68,7 +68,8 @@ bool read(cmsys::ifstream& fin, std::vector<T>& v) if (v.empty()) { return true; } - return !!fin.read(reinterpret_cast<char*>(&v[0]), sizeof(T) * v.size()); + return static_cast<bool>( + fin.read(reinterpret_cast<char*>(&v[0]), sizeof(T) * v.size())); } } @@ -340,7 +341,8 @@ bool cmMachO::GetInstallName(std::string& install_name) if (lc_cmd == LC_ID_DYLIB || lc_cmd == LC_LOAD_WEAK_DYLIB || lc_cmd == LC_LOAD_DYLIB) { if (sizeof(dylib_command) < cmd.LoadCommand.size()) { - uint32_t namelen = cmd.LoadCommand.size() - sizeof(dylib_command); + uint32_t namelen = static_cast<uint32_t>(cmd.LoadCommand.size() - + sizeof(dylib_command)); install_name.assign(&cmd.LoadCommand[sizeof(dylib_command)], namelen); return true; } diff --git a/Source/cmMachO.h b/Source/cmMachO.h index faa024b..ec7d54c 100644 --- a/Source/cmMachO.h +++ b/Source/cmMachO.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> #include <string> #if !defined(CMake_USE_MACH_PARSER) diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 8c4b2a7..154df63 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -77,7 +77,7 @@ bool cmMacroHelperCommand::operator()( argVs.reserve(expandedArgs.size()); char argvName[60]; for (unsigned int j = 0; j < expandedArgs.size(); ++j) { - sprintf(argvName, "${ARGV%u}", j); + snprintf(argvName, sizeof(argvName), "${ARGV%u}", j); argVs.emplace_back(argvName); } // Invoke all the functions that were collected in the block. diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 88f3cc7..94d3be6 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -79,7 +79,6 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, cmStateSnapshot const& snapshot) : GlobalGenerator(globalGenerator) , StateSnapshot(snapshot) - , Backtrace(snapshot) { this->IsSourceFileTryCompile = false; @@ -134,8 +133,8 @@ cmDirectoryId cmMakefile::GetDirectoryId() const // If we ever need to expose this to CMake language code we should // add a read-only property in cmMakefile::GetProperty. char buf[32]; - sprintf(buf, "(%p)", - static_cast<void const*>(this)); // cast avoids format warning + snprintf(buf, sizeof(buf), "(%p)", + static_cast<void const*>(this)); // cast avoids format warning return std::string(buf); } @@ -340,7 +339,7 @@ public: cm::optional<std::string> deferId, cmExecutionStatus& status) : Makefile(mf) { - cmListFileContext const& lfc = cmListFileContext::FromCommandContext( + cmListFileContext const& lfc = cmListFileContext::FromListFileFunction( lff, this->Makefile->StateSnapshot.GetExecutionListFile(), std::move(deferId)); this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc); @@ -891,12 +890,23 @@ struct file_not_persistent }; } -void cmMakefile::AddGeneratorAction(GeneratorAction action) +void cmMakefile::AddGeneratorAction(GeneratorAction&& action) { assert(!this->GeneratorActionsInvoked); this->GeneratorActions.emplace_back(std::move(action), this->Backtrace); } +void cmMakefile::GeneratorAction::operator()(cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt) +{ + if (cc) { + CCAction(lg, lfbt, std::move(cc)); + } else { + assert(Action); + Action(lg, lfbt); + } +} + void cmMakefile::DoGenerate(cmLocalGenerator& lg) { // do all the variable expansions here @@ -904,7 +914,7 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg) // give all the commands a chance to do something // after the file has been parsed before generation - for (const BT<GeneratorAction>& action : this->GeneratorActions) { + for (auto& action : this->GeneratorActions) { action.Value(lg, action.Backtrace); } this->GeneratorActionsInvoked = true; @@ -956,19 +966,6 @@ private: cmListFileBacktrace& Backtrace; cmListFileBacktrace Previous; }; - -cm::optional<std::string> MakeOptionalString(const char* str) -{ - if (str) { - return str; - } - return cm::nullopt; -} - -const char* GetCStrOrNull(const cm::optional<std::string>& str) -{ - return str ? str->c_str() : nullptr; -} } bool cmMakefile::ValidateCustomCommand( @@ -1056,14 +1053,12 @@ cmTarget* cmMakefile::GetCustomCommandTarget( } cmTarget* cmMakefile::AddCustomCommandToTarget( - const std::string& target, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmCustomCommandType type, - const char* comment, const char* workingDir, - cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle, bool uses_terminal, - const std::string& depfile, const std::string& job_pool, - bool command_expand_lists, bool stdPipesUTF8) + const std::string& target, cmCustomCommandType type, + std::unique_ptr<cmCustomCommand> cc) { + const auto& byproducts = cc->GetByproducts(); + const auto& commandLines = cc->GetCommandLines(); + cmTarget* t = this->GetCustomCommandTarget( target, cmObjectLibraryCommands::Reject, this->Backtrace); @@ -1075,53 +1070,30 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( // Always create the byproduct sources and mark them generated. this->CreateGeneratedOutputs(byproducts); - // Strings could be moved into the callback function with C++14. - cm::optional<std::string> commentStr = MakeOptionalString(comment); - cm::optional<std::string> workingStr = MakeOptionalString(workingDir); + cc->SetCMP0116Status(this->GetPolicyStatus(cmPolicies::CMP0116)); // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + std::move(cc), + [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + std::unique_ptr<cmCustomCommand> tcc) { BacktraceGuard guard(this->Backtrace, lfbt); - detail::AddCustomCommandToTarget( - lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends, - commandLines, type, GetCStrOrNull(commentStr), - GetCStrOrNull(workingStr), escapeOldStyle, uses_terminal, depfile, - job_pool, command_expand_lists, stdPipesUTF8, cmp0116); + tcc->SetBacktrace(lfbt); + detail::AddCustomCommandToTarget(lg, cmCommandOrigin::Project, t, type, + std::move(tcc)); }); return t; } void cmMakefile::AddCustomCommandToOutput( - const std::string& output, const std::vector<std::string>& depends, - const std::string& main_dependency, const cmCustomCommandLines& commandLines, - const char* comment, const char* workingDir, - cmPolicies::PolicyStatus cmp0116, const CommandSourceCallback& callback, - bool replace, bool escapeOldStyle, bool uses_terminal, - bool command_expand_lists, const std::string& depfile, - const std::string& job_pool, bool stdPipesUTF8) -{ - std::vector<std::string> no_byproducts; - cmImplicitDependsList no_implicit_depends; - this->AddCustomCommandToOutput( - { output }, no_byproducts, depends, main_dependency, no_implicit_depends, - commandLines, comment, workingDir, cmp0116, callback, replace, - escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool, - stdPipesUTF8); -} - -void cmMakefile::AddCustomCommandToOutput( - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, cmPolicies::PolicyStatus cmp0116, - const CommandSourceCallback& callback, bool replace, bool escapeOldStyle, - bool uses_terminal, bool command_expand_lists, const std::string& depfile, - const std::string& job_pool, bool stdPipesUTF8) + std::unique_ptr<cmCustomCommand> cc, const CommandSourceCallback& callback, + bool replace) { + const auto& outputs = cc->GetOutputs(); + const auto& byproducts = cc->GetByproducts(); + const auto& commandLines = cc->GetCommandLines(); + // Make sure there is at least one output. if (outputs.empty()) { cmSystemTools::Error("Attempt to add a custom rule with no output!"); @@ -1137,20 +1109,17 @@ void cmMakefile::AddCustomCommandToOutput( this->CreateGeneratedOutputs(outputs); this->CreateGeneratedOutputs(byproducts); - // Strings could be moved into the callback function with C++14. - cm::optional<std::string> commentStr = MakeOptionalString(comment); - cm::optional<std::string> workingStr = MakeOptionalString(workingDir); + cc->SetCMP0116Status(this->GetPolicyStatus(cmPolicies::CMP0116)); // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + std::move(cc), + [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + std::unique_ptr<cmCustomCommand> tcc) { BacktraceGuard guard(this->Backtrace, lfbt); + tcc->SetBacktrace(lfbt); cmSourceFile* sf = detail::AddCustomCommandToOutput( - lg, lfbt, cmCommandOrigin::Project, outputs, byproducts, depends, - main_dependency, implicit_depends, commandLines, - GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace, - escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool, - stdPipesUTF8, cmp0116); + lg, cmCommandOrigin::Project, std::move(tcc), replace); if (callback && sf) { callback(sf); } @@ -1160,19 +1129,21 @@ void cmMakefile::AddCustomCommandToOutput( void cmMakefile::AddCustomCommandOldStyle( const std::string& target, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, const std::string& source, - const cmCustomCommandLines& commandLines, const char* comment, - cmPolicies::PolicyStatus cmp0116) + const cmCustomCommandLines& commandLines, const char* comment) { + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetDepends(depends); + cc->SetCommandLines(commandLines); + cc->SetComment(comment); + // Translate the old-style signature to one of the new-style // signatures. if (source == target) { // In the old-style signature if the source and target were the // same then it added a post-build rule to the target. Preserve // this behavior. - std::vector<std::string> no_byproducts; - this->AddCustomCommandToTarget( - target, no_byproducts, depends, commandLines, - cmCustomCommandType::POST_BUILD, comment, nullptr, cmp0116); + this->AddCustomCommandToTarget(target, cmCustomCommandType::POST_BUILD, + std::move(cc)); return; } @@ -1204,20 +1175,19 @@ void cmMakefile::AddCustomCommandOldStyle( if (sourceFiles.find(source)) { // The source looks like a real file. Use it as the main dependency. for (std::string const& output : outputs) { - this->AddCustomCommandToOutput(output, depends, source, commandLines, - comment, nullptr, cmp0116, - addRuleFileToTarget); + auto cc1 = cm::make_unique<cmCustomCommand>(*cc); + cc1->SetOutputs(output); + cc1->SetMainDependency(source); + this->AddCustomCommandToOutput(std::move(cc1), addRuleFileToTarget); } } else { - std::string no_main_dependency; - std::vector<std::string> depends2 = depends; - depends2.push_back(source); + cc->AppendDepends({ source }); // The source may not be a real file. Do not use a main dependency. for (std::string const& output : outputs) { - this->AddCustomCommandToOutput(output, depends2, no_main_dependency, - commandLines, comment, nullptr, cmp0116, - addRuleFileToTarget); + auto cc1 = cm::make_unique<cmCustomCommand>(*cc); + cc1->SetOutputs(output); + this->AddCustomCommandToOutput(std::move(cc1), addRuleFileToTarget); } } } @@ -1239,14 +1209,13 @@ void cmMakefile::AppendCustomCommandToOutput( } } -cmTarget* cmMakefile::AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, const char* workingDir, - const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116, - bool escapeOldStyle, const char* comment, bool uses_terminal, - bool command_expand_lists, const std::string& job_pool, bool stdPipesUTF8) +cmTarget* cmMakefile::AddUtilityCommand(const std::string& utilityName, + bool excludeFromAll, + std::unique_ptr<cmCustomCommand> cc) { + const auto& depends = cc->GetDepends(); + const auto& byproducts = cc->GetByproducts(); + const auto& commandLines = cc->GetCommandLines(); cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll); // Validate custom commands. @@ -1258,19 +1227,17 @@ cmTarget* cmMakefile::AddUtilityCommand( // Always create the byproduct sources and mark them generated. this->CreateGeneratedOutputs(byproducts); - // Strings could be moved into the callback function with C++14. - cm::optional<std::string> commentStr = MakeOptionalString(comment); - cm::optional<std::string> workingStr = MakeOptionalString(workingDir); + cc->SetCMP0116Status(this->GetPolicyStatus(cmPolicies::CMP0116)); // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + std::move(cc), + [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + std::unique_ptr<cmCustomCommand> tcc) { BacktraceGuard guard(this->Backtrace, lfbt); - detail::AddUtilityCommand( - lg, lfbt, cmCommandOrigin::Project, target, GetCStrOrNull(workingStr), - byproducts, depends, commandLines, escapeOldStyle, - GetCStrOrNull(commentStr), uses_terminal, command_expand_lists, - job_pool, stdPipesUTF8, cmp0116); + tcc->SetBacktrace(lfbt); + detail::AddUtilityCommand(lg, cmCommandOrigin::Project, target, + std::move(tcc)); }); return target; @@ -4428,11 +4395,12 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, } // Deprecate old policies. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0088 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0094 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. - id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083))) { + id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 || + id == cmPolicies::CMP0091))) { this->IssueMessage(MessageType::DEPRECATION_WARNING, cmPolicies::GetPolicyDeprecatedWarning(id)); } @@ -4551,3 +4519,22 @@ cmMakefile::MacroPushPop::~MacroPushPop() { this->Makefile->PopMacroScope(this->ReportError); } + +cmMakefile::DebugFindPkgRAII::DebugFindPkgRAII(cmMakefile* mf, + std::string const& pkg) + : Makefile(mf) + , OldValue(this->Makefile->DebugFindPkg) +{ + this->Makefile->DebugFindPkg = + this->Makefile->GetCMakeInstance()->GetDebugFindPkgOutput(pkg); +} + +cmMakefile::DebugFindPkgRAII::~DebugFindPkgRAII() +{ + this->Makefile->DebugFindPkg = this->OldValue; +} + +bool cmMakefile::GetDebugFindPkgMode() const +{ + return this->DebugFindPkg; +} diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 671cdab..f425697 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -24,6 +24,7 @@ #include "cm_sys_stat.h" #include "cmAlgorithms.h" +#include "cmCustomCommand.h" #include "cmCustomCommandTypes.h" #include "cmListFileCache.h" #include "cmMessageType.h" @@ -50,7 +51,6 @@ class cmExportBuildFileGenerator; class cmFunctionBlocker; class cmGeneratorExpressionEvaluationFile; class cmGlobalGenerator; -class cmImplicitDependsList; class cmInstallGenerator; class cmLocalGenerator; class cmMessenger; @@ -140,13 +140,47 @@ public: bool EnforceUniqueName(std::string const& name, std::string& msg, bool isCustom = false) const; - using GeneratorAction = - std::function<void(cmLocalGenerator&, const cmListFileBacktrace&)>; + class GeneratorAction + { + using ActionT = + std::function<void(cmLocalGenerator&, const cmListFileBacktrace&)>; + using CCActionT = + std::function<void(cmLocalGenerator&, const cmListFileBacktrace&, + std::unique_ptr<cmCustomCommand> cc)>; + + public: + GeneratorAction(ActionT&& action) + : Action(std::move(action)) + { + } + + GeneratorAction(std::unique_ptr<cmCustomCommand> tcc, CCActionT&& action) + : CCAction(std::move(action)) + , cc(std::move(tcc)) + { + } + + void operator()(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt); + + private: + ActionT Action; + + // FIXME: Use std::variant + CCActionT CCAction; + std::unique_ptr<cmCustomCommand> cc; + }; /** * Register an action that is executed during Generate */ - void AddGeneratorAction(GeneratorAction action); + void AddGeneratorAction(GeneratorAction&& action); + + /// Helper to insert the constructor GeneratorAction(args...) + template <class... Args> + void AddGeneratorAction(Args&&... args) + { + AddGeneratorAction(GeneratorAction(std::move(args)...)); + } /** * Perform generate actions, Library dependency analysis etc before output of @@ -165,15 +199,9 @@ public: * Dispatch adding a custom PRE_BUILD, PRE_LINK, or POST_BUILD command to a * target. */ - cmTarget* AddCustomCommandToTarget( - const std::string& target, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmCustomCommandType type, - const char* comment, const char* workingDir, - cmPolicies::PolicyStatus cmp0116, bool escapeOldStyle = true, - bool uses_terminal = false, const std::string& depfile = "", - const std::string& job_pool = "", bool command_expand_lists = false, - bool stdPipesUTF8 = false); + cmTarget* AddCustomCommandToTarget(const std::string& target, + cmCustomCommandType type, + std::unique_ptr<cmCustomCommand> cc); /** * Called for each file with custom command. @@ -184,33 +212,14 @@ public: * Dispatch adding a custom command to a source file. */ void AddCustomCommandToOutput( - const std::string& output, const std::vector<std::string>& depends, - const std::string& main_dependency, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, cmPolicies::PolicyStatus cmp0116, - const CommandSourceCallback& callback = nullptr, bool replace = false, - bool escapeOldStyle = true, bool uses_terminal = false, - bool command_expand_lists = false, const std::string& depfile = "", - const std::string& job_pool = "", bool stdPipesUTF8 = false); - void AddCustomCommandToOutput( - 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, - const cmCustomCommandLines& commandLines, const char* comment, - const char* workingDir, cmPolicies::PolicyStatus cmp0116, - const CommandSourceCallback& callback = nullptr, bool replace = false, - bool escapeOldStyle = true, bool uses_terminal = false, - bool command_expand_lists = false, const std::string& depfile = "", - const std::string& job_pool = "", bool stdPipesUTF8 = false); + std::unique_ptr<cmCustomCommand> cc, + const CommandSourceCallback& callback = nullptr, bool replace = false); void AddCustomCommandOldStyle(const std::string& target, const std::vector<std::string>& outputs, const std::vector<std::string>& depends, const std::string& source, const cmCustomCommandLines& commandLines, - const char* comment, - cmPolicies::PolicyStatus cmp0116); + const char* comment); void AppendCustomCommandToOutput( const std::string& output, const std::vector<std::string>& depends, const cmImplicitDependsList& implicit_depends, @@ -252,14 +261,9 @@ public: * Dispatch adding a utility to the build. A utility target is a command * that is run every time the target is built. */ - cmTarget* AddUtilityCommand( - const std::string& utilityName, bool excludeFromAll, - const char* workingDir, const std::vector<std::string>& byproducts, - const std::vector<std::string>& depends, - const cmCustomCommandLines& commandLines, cmPolicies::PolicyStatus cmp0116, - bool escapeOldStyle = true, const char* comment = nullptr, - bool uses_terminal = false, bool command_expand_lists = false, - const std::string& job_pool = "", bool stdPipesUTF8 = false); + cmTarget* AddUtilityCommand(const std::string& utilityName, + bool excludeFromAll, + std::unique_ptr<cmCustomCommand> cc); /** * Add a subdirectory to the build. @@ -927,6 +931,18 @@ public: // searches std::deque<std::vector<std::string>> FindPackageRootPathStack; + class DebugFindPkgRAII + { + cmMakefile* Makefile; + bool OldValue; + + public: + DebugFindPkgRAII(cmMakefile* mf, std::string const& pkg); + ~DebugFindPkgRAII(); + }; + + bool GetDebugFindPkgMode() const; + void MaybeWarnCMP0074(std::string const& pkg); void MaybeWarnUninitialized(std::string const& variable, const char* sourceFilename) const; @@ -1100,6 +1116,8 @@ private: std::vector<BT<GeneratorAction>> GeneratorActions; bool GeneratorActionsInvoked = false; + bool DebugFindPkg = false; + bool CheckSystemVars; bool CheckCMP0000; std::set<std::string> WarnedCMP0074; diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 575fb05..e41ed8c 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -170,9 +170,6 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( // Expand the rule variables. { - bool useWatcomQuote = - this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); - // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); @@ -181,7 +178,6 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( this->LocalGenerator, this->LocalGenerator->GetStateSnapshot().GetDirectory())); linkLineComputer->SetForResponse(useResponseFileForLibs); - linkLineComputer->SetUseWatcomQuote(useWatcomQuote); linkLineComputer->SetRelink(relink); // Collect up flags to link in needed libraries. @@ -193,7 +189,7 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( // rule. std::string buildObjs; this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects, - buildObjs, depends, useWatcomQuote); + buildObjs, depends, false); std::string const& aixExports = this->GetAIXExports(this->GetConfigName()); @@ -204,11 +200,9 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir), cmOutputConverter::SHELL); - cmOutputConverter::OutputFormat output = (useWatcomQuote) - ? cmOutputConverter::WATCOMQUOTE - : cmOutputConverter::SHELL; std::string target = this->LocalGenerator->ConvertToOutputFormat( - this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput), output); + this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput), + cmOutputConverter::SHELL); std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(this->GetConfigName()); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index ace73a7..66031db 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -308,9 +308,6 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( // Expand the rule variables. std::vector<std::string> real_link_commands; { - bool useWatcomQuote = - this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); - // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); @@ -321,7 +318,6 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( this->LocalGenerator, this->LocalGenerator->GetStateSnapshot().GetDirectory())); linkLineComputer->SetForResponse(useResponseFileForLibs); - linkLineComputer->SetUseWatcomQuote(useWatcomQuote); linkLineComputer->SetRelink(relink); this->CreateLinkLibs(linkLineComputer.get(), linkLibs, @@ -332,11 +328,7 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( std::string buildObjs; this->CreateObjectLists(useLinkScript, false, // useArchiveRules useResponseFileForObjects, buildObjs, depends, - useWatcomQuote); - - cmOutputConverter::OutputFormat output = (useWatcomQuote) - ? cmOutputConverter::WATCOMQUOTE - : cmOutputConverter::SHELL; + false); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); objectDir = this->LocalGenerator->ConvertToOutputFormat( @@ -344,7 +336,8 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( cmOutputConverter::SHELL); std::string target = this->LocalGenerator->ConvertToOutputFormat( - this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput), output); + this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput), + cmOutputConverter::SHELL); std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(this->GetConfigName()); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5f138ba..1c92c7f 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -899,28 +899,31 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Construct the compile rules. { - std::vector<std::string> compileCommands; + std::string cudaCompileMode; if (lang == "CUDA") { - std::string cmdVar; if (this->GeneratorTarget->GetPropertyAsBool( "CUDA_SEPARABLE_COMPILATION")) { - cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION"; - } else if (this->GeneratorTarget->GetPropertyAsBool( - "CUDA_PTX_COMPILATION")) { - cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION"; + const std::string& rdcFlag = + this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); + cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, " "); + } + if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { + const std::string& ptxFlag = + this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_PTX_FLAG"); + cudaCompileMode = cmStrCat(cudaCompileMode, ptxFlag); } else { - cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION"; + const std::string& wholeFlag = + this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); + cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); } - const std::string& compileRule = - this->Makefile->GetRequiredDefinition(cmdVar); - cmExpandList(compileRule, compileCommands); - } else { - const std::string cmdVar = "CMAKE_" + lang + "_COMPILE_OBJECT"; - const std::string& compileRule = - this->Makefile->GetRequiredDefinition(cmdVar); - cmExpandList(compileRule, compileCommands); + vars.CudaCompileMode = cudaCompileMode.c_str(); } + std::vector<std::string> compileCommands; + const std::string& compileRule = this->Makefile->GetRequiredDefinition( + "CMAKE_" + lang + "_COMPILE_OBJECT"); + cmExpandList(compileRule, compileCommands); + if (this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS") && lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; @@ -1529,9 +1532,9 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( return; } + cmLocalUnixMakefileGenerator3* localGen{ this->LocalGenerator }; std::vector<std::string> architectures = cmExpandedList(architecturesStr); - std::string const& relPath = - this->LocalGenerator->GetHomeRelativeOutputPath(); + std::string const& relPath = localGen->GetHomeRelativeOutputPath(); // Ensure there are no duplicates. const std::vector<std::string> linkDeps = [&]() -> std::vector<std::string> { @@ -1551,12 +1554,12 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( const std::string objectDir = this->GeneratorTarget->ObjectDirectory; const std::string relObjectDir = - this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir); + localGen->MaybeRelativeToCurBinDir(objectDir); // Construct a list of files associated with this executable that // may need to be cleaned. std::vector<std::string> cleanFiles; - cleanFiles.push_back(this->LocalGenerator->MaybeRelativeToCurBinDir(output)); + cleanFiles.push_back(localGen->MaybeRelativeToCurBinDir(output)); std::string profiles; std::vector<std::string> fatbinaryDepends; @@ -1593,8 +1596,8 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( " -arch=sm_", architecture, registerFileCmd, " -o=$@ ", cmJoin(linkDeps, " ")); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, cubin, - linkDeps, { command }, false); + localGen->WriteMakeRule(*this->BuildFileStream, nullptr, cubin, linkDeps, + { command }, false); } // Combine all architectures into a single fatbinary. @@ -1608,9 +1611,8 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( const std::string fatbinaryOutputRel = cmStrCat(relPath, relObjectDir, "cmake_cuda_fatbin.h"); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, - fatbinaryOutputRel, fatbinaryDepends, - { fatbinaryCommand }, false); + localGen->WriteMakeRule(*this->BuildFileStream, nullptr, fatbinaryOutputRel, + fatbinaryDepends, { fatbinaryCommand }, false); // Compile the stub that registers the kernels and contains the // fatbinaries. @@ -1624,18 +1626,21 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( vars.Fatbinary = fatbinaryOutput.c_str(); vars.RegisterFile = registerFile.c_str(); + std::string linkFlags; + this->GetDeviceLinkFlags(linkFlags, "CUDA"); + vars.LinkFlags = linkFlags.c_str(); + std::string flags = this->GetFlags("CUDA", this->GetConfigName()); vars.Flags = flags.c_str(); std::string compileCmd = this->GetLinkRule("CMAKE_CUDA_DEVICE_LINK_COMPILE"); std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); - rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, - compileCmd, vars); + localGen->CreateRulePlaceholderExpander()); + rulePlaceholderExpander->ExpandRuleVariables(localGen, compileCmd, vars); commands.emplace_back(compileCmd); - this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, output, - { fatbinaryOutputRel }, commands, false); + localGen->WriteMakeRule(*this->BuildFileStream, nullptr, output, + { fatbinaryOutputRel }, commands, false); // Clean all the possible executable names and symlinks. this->CleanFiles.insert(cleanFiles.begin(), cleanFiles.end()); @@ -2186,7 +2191,7 @@ void cmMakefileTargetGenerator::CreateObjectLists( for (unsigned int i = 0; i < object_strings.size(); ++i) { // Number the response files. char rsp[32]; - sprintf(rsp, "objects%u.rsp", i + 1); + snprintf(rsp, sizeof(rsp), "objects%u.rsp", i + 1); // Create this response file. std::string objects_rsp = diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx index 56221bf..df9ebcf 100644 --- a/Source/cmMathCommand.cxx +++ b/Source/cmMathCommand.cxx @@ -107,7 +107,7 @@ bool HandleExprCommand(std::vector<std::string> const& args, fmt = "%" KWIML_INT_PRId64; break; } - sprintf(buffer, fmt, helper.GetResult()); + snprintf(buffer, sizeof(buffer), fmt, helper.GetResult()); std::string const& w = helper.GetWarning(); if (!w.empty()) { diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx index 1cb638a..6dd192e 100644 --- a/Source/cmMessenger.cxx +++ b/Source/cmMessenger.cxx @@ -12,6 +12,7 @@ #endif #include <sstream> +#include <utility> #include "cmsys/Terminal.h" @@ -102,7 +103,7 @@ static int getMessageColor(MessageType t) } } -void printMessageText(std::ostream& msg, std::string const& text) +static void printMessageText(std::ostream& msg, std::string const& text) { msg << ":\n"; cmDocumentationFormatter formatter; @@ -110,7 +111,7 @@ void printMessageText(std::ostream& msg, std::string const& text) formatter.PrintFormatted(msg, text.c_str()); } -void displayMessage(MessageType t, std::ostringstream& msg) +static void displayMessage(MessageType t, std::ostringstream& msg) { // Add a note about warning suppression. if (t == MessageType::AUTHOR_WARNING) { @@ -151,23 +152,55 @@ void displayMessage(MessageType t, std::ostringstream& msg) } } +namespace { +void PrintCallStack(std::ostream& out, cmListFileBacktrace bt, + cm::optional<std::string> const& topSource) +{ + // The call stack exists only if we have at least two calls on top + // of the bottom. + if (bt.Empty()) { + return; + } + bt = bt.Pop(); + if (bt.Empty()) { + return; + } + + bool first = true; + for (; !bt.Empty(); bt = bt.Pop()) { + cmListFileContext lfc = bt.Top(); + if (lfc.Name.empty() && + lfc.Line != cmListFileContext::DeferPlaceholderLine) { + // Skip this whole-file scope. When we get here we already will + // have printed a more-specific context within the file. + continue; + } + if (first) { + first = false; + out << "Call Stack (most recent call first):\n"; + } + if (topSource) { + lfc.FilePath = cmSystemTools::RelativeIfUnder(*topSource, lfc.FilePath); + } + out << " " << lfc << "\n"; + } +} +} + void cmMessenger::IssueMessage(MessageType t, const std::string& text, const cmListFileBacktrace& backtrace) const { bool force = false; - if (!force) { - // override the message type, if needed, for warnings and errors - MessageType override = this->ConvertMessageType(t); - if (override != t) { - t = override; - force = true; - } + // override the message type, if needed, for warnings and errors + MessageType override = this->ConvertMessageType(t); + if (override != t) { + t = override; + force = true; } - if (!force && !this->IsMessageTypeVisible(t)) { - return; + if (force || this->IsMessageTypeVisible(t)) { + this->DisplayMessage(t, text, backtrace); } - this->DisplayMessage(t, text, backtrace); } void cmMessenger::DisplayMessage(MessageType t, const std::string& text, @@ -179,12 +212,32 @@ void cmMessenger::DisplayMessage(MessageType t, const std::string& text, } // Add the immediate context. - backtrace.PrintTitle(msg); + this->PrintBacktraceTitle(msg, backtrace); printMessageText(msg, text); // Add the rest of the context. - backtrace.PrintCallStack(msg); + PrintCallStack(msg, backtrace, this->TopSource); displayMessage(t, msg); } + +void cmMessenger::PrintBacktraceTitle(std::ostream& out, + cmListFileBacktrace const& bt) const +{ + // The title exists only if we have a call on top of the bottom. + if (bt.Empty()) { + return; + } + cmListFileContext lfc = bt.Top(); + if (this->TopSource) { + lfc.FilePath = + cmSystemTools::RelativeIfUnder(*this->TopSource, lfc.FilePath); + } + out << (lfc.Line ? " at " : " in ") << lfc; +} + +void cmMessenger::SetTopSource(cm::optional<std::string> topSource) +{ + this->TopSource = std::move(topSource); +} diff --git a/Source/cmMessenger.h b/Source/cmMessenger.h index b6f5712..451add0 100644 --- a/Source/cmMessenger.h +++ b/Source/cmMessenger.h @@ -4,8 +4,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <iosfwd> #include <string> +#include <cm/optional> + #include "cmListFileCache.h" #include "cmMessageType.h" @@ -19,6 +22,8 @@ public: void DisplayMessage(MessageType t, std::string const& text, cmListFileBacktrace const& backtrace) const; + void SetTopSource(cm::optional<std::string> topSource); + void SetSuppressDevWarnings(bool suppress) { this->SuppressDevWarnings = suppress; @@ -47,10 +52,16 @@ public: return this->DeprecatedWarningsAsErrors; } + // Print the top of a backtrace. + void PrintBacktraceTitle(std::ostream& out, + cmListFileBacktrace const& bt) const; + private: bool IsMessageTypeVisible(MessageType t) const; MessageType ConvertMessageType(MessageType t) const; + cm::optional<std::string> TopSource; + bool SuppressDevWarnings = false; bool SuppressDeprecatedWarnings = false; bool DevWarningsAsErrors = false; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 517d529..1c5bac8 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -326,6 +326,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules( vars.Object = "$out"; vars.Fatbinary = "$FATBIN"; vars.RegisterFile = "$REGISTER"; + vars.LinkFlags = "$LINK_FLAGS"; std::string flags = this->GetFlags("CUDA", config); vars.Flags = flags.c_str(); @@ -744,9 +745,10 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements( return deps; }(); + cmGlobalNinjaGenerator* globalGen{ this->GetGlobalGenerator() }; const std::string objectDir = cmStrCat(this->GeneratorTarget->GetSupportDirectory(), - this->GetGlobalGenerator()->ConfigDirectory(config)); + globalGen->ConfigDirectory(config)); const std::string ninjaOutputDir = this->ConvertToNinjaPath(objectDir); cmNinjaBuild fatbinary(this->LanguageLinkerCudaFatbinaryRule(config)); @@ -777,26 +779,37 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements( cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin); fatbinary.ExplicitDeps.emplace_back(cubin); - this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), dlink); + globalGen->WriteBuild(this->GetCommonFileStream(), dlink); } // Combine all architectures into a single fatbinary. fatbinary.Outputs = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") }; - this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), - fatbinary); + globalGen->WriteBuild(this->GetCommonFileStream(), fatbinary); // Compile the stub that registers the kernels and contains the fatbinaries. + cmLocalNinjaGenerator* localGen{ this->GetLocalGenerator() }; cmNinjaBuild dcompile(this->LanguageLinkerCudaDeviceCompileRule(config)); dcompile.Outputs = { output }; dcompile.ExplicitDeps = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") }; - dcompile.Variables["FATBIN"] = - this->GetLocalGenerator()->ConvertToOutputFormat( - cmStrCat(objectDir, "/cmake_cuda_fatbin.h"), cmOutputConverter::SHELL); - dcompile.Variables["REGISTER"] = - this->GetLocalGenerator()->ConvertToOutputFormat( - cmStrCat(objectDir, "/cmake_cuda_register.h"), cmOutputConverter::SHELL); - this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), - dcompile); + dcompile.Variables["FATBIN"] = localGen->ConvertToOutputFormat( + cmStrCat(objectDir, "/cmake_cuda_fatbin.h"), cmOutputConverter::SHELL); + dcompile.Variables["REGISTER"] = localGen->ConvertToOutputFormat( + cmStrCat(objectDir, "/cmake_cuda_register.h"), cmOutputConverter::SHELL); + + cmNinjaLinkLineDeviceComputer linkLineComputer( + localGen, localGen->GetStateSnapshot().GetDirectory(), globalGen); + linkLineComputer.SetUseNinjaMulti(globalGen->IsMultiConfig()); + + // Link libraries and paths are only used during the final executable/library + // link. + std::string frameworkPath; + std::string linkPath; + std::string linkLibs; + localGen->GetDeviceLinkFlags(linkLineComputer, config, linkLibs, + dcompile.Variables["LINK_FLAGS"], frameworkPath, + linkPath, this->GetGeneratorTarget()); + + globalGen->WriteBuild(this->GetCommonFileStream(), dcompile); } void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement( @@ -850,24 +863,19 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement( std::string createRule = genTarget->GetCreateRuleVariable(this->TargetLinkLanguage(config), config); - const bool useWatcomQuote = - this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE"); cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator(); vars["TARGET_FILE"] = localGen.ConvertToOutputFormat(output, cmOutputConverter::SHELL); - std::unique_ptr<cmLinkLineComputer> linkLineComputer( - new cmNinjaLinkLineDeviceComputer( - this->GetLocalGenerator(), - this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(), - globalGen)); - linkLineComputer->SetUseWatcomQuote(useWatcomQuote); - linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig()); + cmNinjaLinkLineDeviceComputer linkLineComputer( + this->GetLocalGenerator(), + this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(), globalGen); + linkLineComputer.SetUseNinjaMulti(globalGen->IsMultiConfig()); - localGen.GetDeviceLinkFlags(linkLineComputer.get(), config, - vars["LINK_LIBRARIES"], vars["LINK_FLAGS"], - frameworkPath, linkPath, genTarget); + localGen.GetDeviceLinkFlags(linkLineComputer, config, vars["LINK_LIBRARIES"], + vars["LINK_FLAGS"], frameworkPath, linkPath, + genTarget); this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 57657b1..dd7d244 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -216,7 +216,8 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( // Add Fortran format flags. if (language == "Fortran") { this->AppendFortranFormatFlags(flags, *source); - this->AppendFortranPreprocessFlags(flags, *source); + this->AppendFortranPreprocessFlags(flags, *source, + PreprocessFlagsRequired::NO); } // Add source file specific flags. @@ -263,10 +264,7 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, language, config); // Add include directory flags. std::string includeFlags = this->LocalGenerator->GetIncludeFlags( - includes, this->GeneratorTarget, language, config, false, - // full include paths for RC needed by cmcldeps - language == "RC" ? cmLocalGenerator::IncludePathStyle::Absolute - : cmLocalGenerator::IncludePathStyle::Default); + includes, this->GeneratorTarget, language, config, false); if (this->GetGlobalGenerator()->IsGCCOnWindows()) { std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/'); } @@ -325,8 +323,7 @@ std::string cmNinjaTargetGenerator::ComputeIncludes( } std::string includesString = this->LocalGenerator->GetIncludeFlags( - includes, this->GeneratorTarget, language, config, false, - cmLocalGenerator::IncludePathStyle::Absolute); + includes, this->GeneratorTarget, language, config, false); this->LocalGenerator->AppendFlags(includesString, this->GetIncludes(language, config)); @@ -605,6 +602,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, vars.TargetCompilePDB = "$TARGET_COMPILE_PDB"; vars.ObjectDir = "$OBJECT_DIR"; vars.ObjectFileDir = "$OBJECT_FILE_DIR"; + vars.CudaCompileMode = "$CUDA_COMPILE_MODE"; vars.ISPCHeader = "$ISPC_HEADER_FILE"; cmMakefile* mf = this->GetMakefile(); @@ -815,27 +813,32 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, vars.Flags = flags.c_str(); vars.DependencyFile = rule.DepFile.c_str(); - // Rule for compiling object file. - std::vector<std::string> compileCmds; + std::string cudaCompileMode; if (lang == "CUDA") { - std::string cmdVar; if (this->GeneratorTarget->GetPropertyAsBool( "CUDA_SEPARABLE_COMPILATION")) { - cmdVar = "CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION"; - } else if (this->GeneratorTarget->GetPropertyAsBool( - "CUDA_PTX_COMPILATION")) { - cmdVar = "CMAKE_CUDA_COMPILE_PTX_COMPILATION"; + const std::string& rdcFlag = + this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); + cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, " "); + } + if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { + const std::string& ptxFlag = + this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_PTX_FLAG"); + cudaCompileMode = cmStrCat(cudaCompileMode, ptxFlag); } else { - cmdVar = "CMAKE_CUDA_COMPILE_WHOLE_COMPILATION"; + const std::string& wholeFlag = + this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); + cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); } - const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar); - cmExpandList(compileCmd, compileCmds); - } else { - const std::string cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT"); - const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar); - cmExpandList(compileCmd, compileCmds); + vars.CudaCompileMode = cudaCompileMode.c_str(); } + // Rule for compiling object file. + std::vector<std::string> compileCmds; + const std::string cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT"); + const std::string& compileCmd = mf->GetRequiredDefinition(cmdVar); + cmExpandList(compileCmd, compileCmds); + // See if we need to use a compiler launcher like ccache or distcc std::string compilerLauncher; if (!compileCmds.empty() && @@ -1407,8 +1410,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( cmSystemTools::GetParentDirectory(source->GetFullPath())); std::string sourceDirectoryFlag = this->LocalGenerator->GetIncludeFlags( - sourceDirectory, this->GeneratorTarget, language, config, false, - cmLocalGenerator::IncludePathStyle::Default); + sourceDirectory, this->GeneratorTarget, language, config, false); vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]); } diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 2b785e1..b143170 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -8,6 +8,11 @@ #include <set> #include <vector> +#ifdef _WIN32 +# include <unordered_map> +# include <utility> +#endif + #include "cmState.h" #include "cmStateDirectory.h" #include "cmStringAlgorithms.h" @@ -117,17 +122,34 @@ std::string cmOutputConverter::MaybeRelativeToCurBinDir( std::string cmOutputConverter::ConvertToOutputForExisting( const std::string& remote, OutputFormat format) const { +#ifdef _WIN32 + // Cache the Short Paths since we only convert the same few paths anyway and + // calling `GetShortPathNameW` is really expensive. + static std::unordered_map<std::string, std::string> shortPathCache{}; + // If this is a windows shell, the result has a space, and the path // already exists, we can use a short-path to reference it without a // space. if (this->GetState()->UseWindowsShell() && remote.find_first_of(" #") != std::string::npos && cmSystemTools::FileExists(remote)) { - std::string tmp; - if (cmSystemTools::GetShortPath(remote, tmp)) { - return this->ConvertToOutputFormat(tmp, format); - } + + std::string shortPath = [&]() { + auto cachedShortPathIt = shortPathCache.find(remote); + + if (cachedShortPathIt != shortPathCache.end()) { + return cachedShortPathIt->second; + } + + std::string tmp{}; + cmSystemTools::GetShortPath(remote, tmp); + shortPathCache[remote] = tmp; + return tmp; + }(); + + return this->ConvertToOutputFormat(shortPath, format); } +#endif // Otherwise, perform standard conversion. return this->ConvertToOutputFormat(remote, format); @@ -143,7 +165,7 @@ std::string cmOutputConverter::ConvertToOutputFormat(cm::string_view source, result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE, output == NINJAMULTI); } else if (output == RESPONSE) { - result = this->EscapeForShell(result, false, false, false); + result = this->EscapeForShell(result, false, false, false, false, true); } return result; } @@ -175,9 +197,11 @@ static bool cmOutputConverterIsShellOperator(cm::string_view str) return (shellOperators.count(str) != 0); } -std::string cmOutputConverter::EscapeForShell( - cm::string_view str, bool makeVars, bool forEcho, bool useWatcomQuote, - bool unescapeNinjaConfiguration) const +std::string cmOutputConverter::EscapeForShell(cm::string_view str, + bool makeVars, bool forEcho, + bool useWatcomQuote, + bool unescapeNinjaConfiguration, + bool forResponse) const { // Do not escape shell operators. if (cmOutputConverterIsShellOperator(str)) { @@ -203,6 +227,9 @@ std::string cmOutputConverter::EscapeForShell( if (useWatcomQuote) { flags |= Shell_Flag_WatcomQuote; } + if (forResponse) { + flags |= Shell_Flag_IsResponse; + } if (this->GetState()->UseWatcomWMake()) { flags |= Shell_Flag_WatcomWMake; } @@ -219,10 +246,11 @@ std::string cmOutputConverter::EscapeForShell( return Shell_GetArgument(str, flags); } -std::string cmOutputConverter::EscapeForCMake(cm::string_view str) +std::string cmOutputConverter::EscapeForCMake(cm::string_view str, + WrapQuotes wrapQuotes) { // Always double-quote the argument to take care of most escapes. - std::string result = "\""; + std::string result = (wrapQuotes == WrapQuotes::Wrap) ? "\"" : ""; for (const char c : str) { if (c == '"') { // Escape the double quote to avoid ending the argument. @@ -238,7 +266,9 @@ std::string cmOutputConverter::EscapeForCMake(cm::string_view str) result += c; } } - result += "\""; + if (wrapQuotes == WrapQuotes::Wrap) { + result += "\""; + } return result; } @@ -357,6 +387,13 @@ bool cmOutputConverter::Shell_CharNeedsQuotes(char c, int flags) return true; } + /* Quote hyphens in response files */ + if (flags & Shell_Flag_IsResponse) { + if (c == '-') { + return true; + } + } + if (flags & Shell_Flag_IsUnix) { /* On UNIX several special characters need quotes to preserve them. */ if (Shell_CharNeedsQuotesOnUnix(c)) { diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 865df71..335442d 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -88,13 +88,22 @@ public: Shell_Flag_IsUnix = (1 << 8), Shell_Flag_UnescapeNinjaConfiguration = (1 << 9), + + Shell_Flag_IsResponse = (1 << 10) }; std::string EscapeForShell(cm::string_view str, bool makeVars = false, bool forEcho = false, bool useWatcomQuote = false, - bool unescapeNinjaConfiguration = false) const; + bool unescapeNinjaConfiguration = false, + bool forResponse = false) const; - static std::string EscapeForCMake(cm::string_view str); + enum class WrapQuotes + { + Wrap, + NoWrap, + }; + static std::string EscapeForCMake(cm::string_view str, + WrapQuotes wrapQuotes = WrapQuotes::Wrap); /** Compute an escaped version of the given argument for use in a windows shell. */ diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 23000fa..e31de1c 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -103,7 +103,7 @@ static bool isPolicyNewerThan(cmPolicies::PolicyID id, unsigned int majorV, return false; } -const char* idToShortDescription(cmPolicies::PolicyID id) +static const char* idToShortDescription(cmPolicies::PolicyID id) { switch (id) { #define POLICY_CASE(ID, SHORT_DESCRIPTION) \ diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index ce04117..99e2eb6 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -385,7 +385,10 @@ class cmMakefile; 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0128, \ "Selection of language standard and extension flags improved.", 3, \ - 22, 0, cmPolicies::WARN) + 22, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0129, \ + "Compiler id for MCST LCC compilers is now LCC, not GNU.", 3, 23, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 20fcdbe..04d99c9 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -235,14 +235,15 @@ bool cmProjectCommand(std::vector<std::string> const& args, std::array<std::string, MAX_VERSION_COMPONENTS> version_components; if (cmp0096 == cmPolicies::OLD || cmp0096 == cmPolicies::WARN) { - char vb[MAX_VERSION_COMPONENTS] - [std::numeric_limits<unsigned>::digits10 + 2]; + constexpr size_t maxIntLength = + std::numeric_limits<unsigned>::digits10 + 2; + char vb[MAX_VERSION_COMPONENTS][maxIntLength]; unsigned v[MAX_VERSION_COMPONENTS] = { 0, 0, 0, 0 }; const int vc = std::sscanf(version.c_str(), "%u.%u.%u.%u", &v[0], &v[1], &v[2], &v[3]); for (auto i = 0u; i < MAX_VERSION_COMPONENTS; ++i) { if (int(i) < vc) { - std::sprintf(vb[i], "%u", v[i]); + std::snprintf(vb[i], maxIntLength, "%u", v[i]); version_string += &"."[std::size_t(i == 0)]; version_string += vb[i]; version_components[i] = vb[i]; diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx index 1796bb8..22723b9 100644 --- a/Source/cmPropertyDefinition.cxx +++ b/Source/cmPropertyDefinition.cxx @@ -6,31 +6,34 @@ cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription, std::string fullDescription, - bool chained) + bool chained, + std::string initializeFromVariable) : ShortDescription(std::move(shortDescription)) , FullDescription(std::move(fullDescription)) , Chained(chained) + , InitializeFromVariable(std::move(initializeFromVariable)) { } void cmPropertyDefinitionMap::DefineProperty( const std::string& name, cmProperty::ScopeType scope, const std::string& ShortDescription, const std::string& FullDescription, - bool chain) + bool chain, const std::string& initializeFromVariable) { - auto it = this->Map_.find(key_type(name, scope)); + auto it = this->Map_.find(KeyType(name, scope)); if (it == this->Map_.end()) { // try_emplace() since C++17 - this->Map_.emplace( - std::piecewise_construct, std::forward_as_tuple(name, scope), - std::forward_as_tuple(ShortDescription, FullDescription, chain)); + this->Map_.emplace(std::piecewise_construct, + std::forward_as_tuple(name, scope), + std::forward_as_tuple(ShortDescription, FullDescription, + chain, initializeFromVariable)); } } cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition( const std::string& name, cmProperty::ScopeType scope) const { - auto it = this->Map_.find(key_type(name, scope)); + auto it = this->Map_.find(KeyType(name, scope)); if (it != this->Map_.end()) { return &it->second; } diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h index fca936e..9dd2cfe 100644 --- a/Source/cmPropertyDefinition.h +++ b/Source/cmPropertyDefinition.h @@ -22,7 +22,8 @@ class cmPropertyDefinition public: /// Constructor cmPropertyDefinition(std::string shortDescription, - std::string fullDescription, bool chained); + std::string fullDescription, bool chained, + std::string initializeFromVariable); /// Is the property chained? bool IsChained() const { return this->Chained; } @@ -39,10 +40,17 @@ public: return this->FullDescription; } + /// Get the variable the property is initialized from + const std::string& GetInitializeFromVariable() const + { + return this->InitializeFromVariable; + } + private: std::string ShortDescription; std::string FullDescription; bool Chained; + std::string InitializeFromVariable; }; /** \class cmPropertyDefinitionMap @@ -54,13 +62,19 @@ public: // define the property void DefineProperty(const std::string& name, cmProperty::ScopeType scope, const std::string& ShortDescription, - const std::string& FullDescription, bool chain); + const std::string& FullDescription, bool chain, + const std::string& initializeFromVariable); // get the property definition if present, otherwise nullptr cmPropertyDefinition const* GetPropertyDefinition( const std::string& name, cmProperty::ScopeType scope) const; + using KeyType = std::pair<std::string, cmProperty::ScopeType>; + const std::map<KeyType, cmPropertyDefinition>& GetMap() const + { + return this->Map_; + } + private: - using key_type = std::pair<std::string, cmProperty::ScopeType>; - std::map<key_type, cmPropertyDefinition> Map_; + std::map<KeyType, cmPropertyDefinition> Map_; }; diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx index ca0b259..58cf514 100644 --- a/Source/cmQTWrapCPPCommand.cxx +++ b/Source/cmQTWrapCPPCommand.cxx @@ -2,10 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQTWrapCPPCommand.h" +#include <utility> + +#include <cm/memory> + +#include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" -#include "cmPolicies.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" @@ -71,11 +75,12 @@ bool cmQTWrapCPPCommand(std::vector<std::string> const& args, depends.push_back(moc_exe); depends.push_back(hname); - std::string no_main_dependency; - const char* no_working_dir = nullptr; - mf.AddCustomCommandToOutput( - newName, depends, no_main_dependency, commandLines, "Qt Wrapped File", - no_working_dir, mf.GetPolicyStatus(cmPolicies::CMP0116)); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(newName); + cc->SetDepends(depends); + cc->SetCommandLines(commandLines); + cc->SetComment("Qt Wrapped File"); + mf.AddCustomCommandToOutput(std::move(cc)); } } diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx index f98f0b3..8b2a42c 100644 --- a/Source/cmQTWrapUICommand.cxx +++ b/Source/cmQTWrapUICommand.cxx @@ -2,10 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQTWrapUICommand.h" +#include <utility> + +#include <cm/memory> + +#include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" -#include "cmPolicies.h" #include "cmRange.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" @@ -84,23 +88,26 @@ bool cmQTWrapUICommand(std::vector<std::string> const& args, std::vector<std::string> depends; depends.push_back(uiName); - std::string no_main_dependency; - const char* no_comment = nullptr; - const char* no_working_dir = nullptr; - mf.AddCustomCommandToOutput(hName, depends, no_main_dependency, - hCommandLines, no_comment, no_working_dir, - mf.GetPolicyStatus(cmPolicies::CMP0116)); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(hName); + cc->SetDepends(depends); + cc->SetCommandLines(hCommandLines); + mf.AddCustomCommandToOutput(std::move(cc)); depends.push_back(hName); - mf.AddCustomCommandToOutput(cxxName, depends, no_main_dependency, - cxxCommandLines, no_comment, no_working_dir, - mf.GetPolicyStatus(cmPolicies::CMP0116)); + cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(cxxName); + cc->SetDepends(depends); + cc->SetCommandLines(cxxCommandLines); + mf.AddCustomCommandToOutput(std::move(cc)); depends.clear(); depends.push_back(hName); - mf.AddCustomCommandToOutput(mocName, depends, no_main_dependency, - mocCommandLines, no_comment, no_working_dir, - mf.GetPolicyStatus(cmPolicies::CMP0116)); + cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(mocName); + cc->SetDepends(depends); + cc->SetCommandLines(mocCommandLines); + mf.AddCustomCommandToOutput(std::move(cc)); } } diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index 9584e5c..0a394b5 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -22,10 +22,10 @@ /// @brief Merges newOpts into baseOpts /// @arg valueOpts list of options that accept a value -void MergeOptions(std::vector<std::string>& baseOpts, - std::vector<std::string> const& newOpts, - std::initializer_list<cm::string_view> valueOpts, - bool isQt5OrLater) +static void MergeOptions(std::vector<std::string>& baseOpts, + std::vector<std::string> const& newOpts, + std::initializer_list<cm::string_view> valueOpts, + bool isQt5OrLater) { if (newOpts.empty()) { return; diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index f9e889a..b7ea7d6 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -7,7 +7,7 @@ #include <cm/memory> -#include "cmCustomCommandLines.h" +#include "cmCustomCommand.h" #include "cmDuration.h" #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" @@ -171,13 +171,12 @@ void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget( cmMakefile* makefile = localGen->GetMakefile(); // Create utility target - std::vector<std::string> no_byproducts; - std::vector<std::string> no_depends; - cmCustomCommandLines no_commands; - const cmPolicies::PolicyStatus cmp0116_new = cmPolicies::NEW; - cmTarget* target = localGen->AddUtilityCommand( - name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts, - no_depends, no_commands, cmp0116_new, false, comment.c_str()); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetWorkingDirectory(makefile->GetHomeOutputDirectory().c_str()); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetComment(comment.c_str()); + cmTarget* target = localGen->AddUtilityCommand(name, true, std::move(cc)); localGen->AddGeneratorTarget( cm::make_unique<cmGeneratorTarget>(target, localGen)); diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index c49cafe..a01e6ae 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -636,12 +636,12 @@ bool cmQtAutoGenInitializer::InitMoc() auto getDefs = [this](std::string const& cfg) -> std::set<std::string> { std::set<std::string> defines; this->LocalGen->GetTargetDefines(this->GenTarget, cfg, "CXX", defines); -#ifdef _WIN32 - if (this->Moc.PredefsCmd.empty()) { + if (this->Moc.PredefsCmd.empty() && + this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == + "Windows") { // Add WIN32 definition if we don't have a moc_predefs.h defines.insert("WIN32"); } -#endif return defines; }; @@ -1230,15 +1230,15 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Add a rule file to cause the target to build if a dependency has // changed, which will trigger the pre-build command to run autogen - std::string no_main_dependency; - cmCustomCommandLines no_command_lines; - this->LocalGen->AddCustomCommandToOutput( - timestampFileGenex, uicDependencies, no_main_dependency, - no_command_lines, /*comment=*/"", this->Dir.Work.c_str(), - /*cmp0116=*/cmPolicies::NEW, /*replace=*/false, - /*escapeOldStyle=*/false, /*uses_terminal=*/false, - /*command_expand_lists=*/false, /*depfile=*/"", /*job_pool=*/"", - stdPipesUTF8); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(timestampFileGenex); + cc->SetDepends(uicDependencies); + cc->SetComment(""); + cc->SetWorkingDirectory(this->Dir.Work.c_str()); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetStdPipesUTF8(stdPipesUTF8); + this->LocalGen->AddCustomCommandToOutput(std::move(cc)); } // Add the pre-build command directly to bypass the OBJECT_LIBRARY @@ -1246,11 +1246,13 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. // // 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, autogenByproducts, no_deps, commandLines, - this->Makefile->GetBacktrace(), autogenComment.c_str(), - this->Dir.Work.c_str(), stdPipesUTF8); + cmCustomCommand cc; + cc.SetByproducts(autogenByproducts); + cc.SetCommandLines(commandLines); + cc.SetComment(autogenComment.c_str()); + cc.SetBacktrace(this->Makefile->GetBacktrace()); + cc.SetWorkingDirectory(this->Dir.Work.c_str()); + cc.SetStdPipesUTF8(stdPipesUTF8); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); this->GenTarget->Target->AddPreBuildCommand(std::move(cc)); @@ -1321,11 +1323,15 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() dependencies.push_back(depname); } + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetWorkingDirectory(this->Dir.Work.c_str()); + cc->SetByproducts(timestampTargetProvides); + cc->SetDepends(dependencies); + cc->SetCommandLines(timestampTargetCommandLines); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand( - timestampTargetName, true, this->Dir.Work.c_str(), - /*byproducts=*/timestampTargetProvides, - /*depends=*/dependencies, timestampTargetCommandLines, cmPolicies::NEW, - false, nullptr); + timestampTargetName, true, std::move(cc)); this->LocalGen->AddGeneratorTarget( cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen)); @@ -1354,16 +1360,18 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile })); this->AddGeneratedSource(outputFile, this->Moc); - const std::string no_main_dependency; - this->LocalGen->AddCustomCommandToOutput( - { outputFile }, timestampByproducts, dependencies, no_main_dependency, - /*implicit_depends=*/{}, commandLines, autogenComment.c_str(), - this->Dir.Work.c_str(), - /*cmp0116=*/cmPolicies::NEW, /*replace=*/false, - /*escapeOldStyle=*/false, - /*uses_terminal=*/false, - /*command_expand_lists=*/false, this->AutogenTarget.DepFile, "", - stdPipesUTF8); + cc = cm::make_unique<cmCustomCommand>(); + cc->SetOutputs(outputFile); + cc->SetByproducts(timestampByproducts); + cc->SetDepends(dependencies); + cc->SetCommandLines(commandLines); + cc->SetComment(autogenComment.c_str()); + cc->SetWorkingDirectory(this->Dir.Work.c_str()); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetDepfile(this->AutogenTarget.DepFile); + cc->SetStdPipesUTF8(stdPipesUTF8); + this->LocalGen->AddCustomCommandToOutput(std::move(cc)); // Alter variables for the autogen target which now merely wraps the // custom command @@ -1374,11 +1382,16 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } // Create autogen target + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetWorkingDirectory(this->Dir.Work.c_str()); + cc->SetByproducts(autogenByproducts); + cc->SetDepends(dependencies); + cc->SetCommandLines(commandLines); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetEscapeOldStyle(false); + cc->SetComment(autogenComment.c_str()); cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand( - this->AutogenTarget.Name, true, this->Dir.Work.c_str(), - /*byproducts=*/autogenByproducts, - /*depends=*/dependencies, commandLines, cmPolicies::NEW, false, - autogenComment.c_str()); + this->AutogenTarget.Name, true, std::move(cc)); // Create autogen generator target this->LocalGen->AddGeneratorTarget( cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen)); @@ -1435,7 +1448,6 @@ bool cmQtAutoGenInitializer::InitRccTargets() ccDepends.push_back(qrc.QrcFile); ccDepends.push_back(qrc.InfoFile); - bool stdPipesUTF8 = true; cmCustomCommandLines commandLines; if (this->MultiConfig) { // Build for all configurations @@ -1453,6 +1465,13 @@ bool cmQtAutoGenInitializer::InitRccTargets() cmStrCat("Automatic RCC for ", FileProjectRelativePath(this->Makefile, qrc.QrcFile)); + auto cc = cm::make_unique<cmCustomCommand>(); + cc->SetWorkingDirectory(this->Dir.Work.c_str()); + cc->SetCommandLines(commandLines); + cc->SetCMP0116Status(cmPolicies::NEW); + cc->SetComment(ccComment.c_str()); + cc->SetStdPipesUTF8(true); + if (qrc.Generated || this->Rcc.GlobalTarget) { // Create custom rcc target std::string ccName; @@ -1462,10 +1481,11 @@ bool cmQtAutoGenInitializer::InitRccTargets() ccName += cmStrCat('_', qrc.QrcPathChecksum); } - cmTarget* autoRccTarget = this->LocalGen->AddUtilityCommand( - ccName, true, this->Dir.Work.c_str(), ccOutput, ccDepends, - commandLines, cmPolicies::NEW, false, ccComment.c_str(), false, - false, "", stdPipesUTF8); + cc->SetByproducts(ccOutput); + cc->SetDepends(ccDepends); + cc->SetEscapeOldStyle(false); + cmTarget* autoRccTarget = + this->LocalGen->AddUtilityCommand(ccName, true, std::move(cc)); // Create autogen generator target this->LocalGen->AddGeneratorTarget( @@ -1500,13 +1520,10 @@ bool cmQtAutoGenInitializer::InitRccTargets() if (!this->Rcc.ExecutableTargetName.empty()) { ccDepends.push_back(this->Rcc.ExecutableTargetName); } - std::string no_main_dependency; - cmImplicitDependsList no_implicit_depends; - this->LocalGen->AddCustomCommandToOutput( - ccOutput, ccByproducts, ccDepends, no_main_dependency, - no_implicit_depends, commandLines, ccComment.c_str(), - this->Dir.Work.c_str(), cmPolicies::NEW, false, true, false, false, - "", "", stdPipesUTF8); + cc->SetOutputs(ccOutput); + cc->SetByproducts(ccByproducts); + cc->SetDepends(ccDepends); + this->LocalGen->AddCustomCommandToOutput(std::move(cc)); } // Reconfigure when .qrc file changes this->Makefile->AddCMakeDependFile(qrc.QrcFile); diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index 7480aeb..4cee09d 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -85,6 +85,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( return replaceValues.ObjectsQuoted; } } + if (replaceValues.CudaCompileMode) { + if (variable == "CUDA_COMPILE_MODE") { + return replaceValues.CudaCompileMode; + } + } if (replaceValues.AIXExports) { if (variable == "AIX_EXPORTS") { return replaceValues.AIXExports; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index c22e0fa..852954f 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -65,6 +65,7 @@ public: const char* SwiftOutputFileMap = nullptr; const char* SwiftSources = nullptr; const char* ISPCHeader = nullptr; + const char* CudaCompileMode = nullptr; const char* Fatbinary = nullptr; const char* RegisterFile = nullptr; const char* Launcher = nullptr; diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index 1bb459c..bfee64c 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -19,23 +19,25 @@ cmSearchPath::cmSearchPath(cmFindCommon* findCmd) cmSearchPath::~cmSearchPath() = default; -void cmSearchPath::ExtractWithout(const std::set<std::string>& ignore, +void cmSearchPath::ExtractWithout(const std::set<std::string>& ignorePaths, + const std::set<std::string>& ignorePrefixes, std::vector<std::string>& outPaths, bool clear) const { if (clear) { outPaths.clear(); } - for (std::string const& path : this->Paths) { - if (ignore.count(path) == 0) { - outPaths.push_back(path); + for (auto const& path : this->Paths) { + if (ignorePaths.count(path.Path) == 0 && + ignorePrefixes.count(path.Prefix) == 0) { + outPaths.push_back(path.Path); } } } void cmSearchPath::AddPath(const std::string& path) { - this->AddPathInternal(path); + this->AddPathInternal(path, ""); } void cmSearchPath::AddUserPath(const std::string& path) @@ -69,7 +71,7 @@ void cmSearchPath::AddUserPath(const std::string& path) // Process them all from the current directory for (std::string const& p : outPaths) { this->AddPathInternal( - p, this->FC->Makefile->GetCurrentSourceDirectory().c_str()); + p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str()); } } @@ -83,7 +85,7 @@ void cmSearchPath::AddCMakePath(const std::string& variable) for (std::string const& p : expanded) { this->AddPathInternal( - p, this->FC->Makefile->GetCurrentSourceDirectory().c_str()); + p, "", this->FC->Makefile->GetCurrentSourceDirectory().c_str()); } } } @@ -93,7 +95,7 @@ void cmSearchPath::AddEnvPath(const std::string& variable) std::vector<std::string> expanded; cmSystemTools::GetPath(expanded, variable.c_str()); for (std::string const& p : expanded) { - this->AddPathInternal(p); + this->AddPathInternal(p, ""); } } @@ -132,24 +134,25 @@ void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin) void cmSearchPath::AddSuffixes(const std::vector<std::string>& suffixes) { - std::vector<std::string> inPaths; + std::vector<PathWithPrefix> inPaths; inPaths.swap(this->Paths); this->Paths.reserve(inPaths.size() * (suffixes.size() + 1)); - for (std::string& inPath : inPaths) { - cmSystemTools::ConvertToUnixSlashes(inPath); + for (PathWithPrefix& inPath : inPaths) { + cmSystemTools::ConvertToUnixSlashes(inPath.Path); + cmSystemTools::ConvertToUnixSlashes(inPath.Prefix); // if *i is only / then do not add a // // this will get incorrectly considered a network // path on windows and cause huge delays. - std::string p = inPath; + std::string p = inPath.Path; if (!p.empty() && p.back() != '/') { p += "/"; } // Combine with all the suffixes for (std::string const& suffix : suffixes) { - this->Paths.push_back(p + suffix); + this->Paths.push_back(PathWithPrefix{ p + suffix, inPath.Prefix }); } // And now the original w/o any suffix @@ -178,6 +181,10 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths, if (!subdir.empty() && !dir.empty() && dir.back() != '/') { dir += "/"; } + std::string prefix = dir; + if (!prefix.empty() && prefix != "/") { + prefix.erase(prefix.size() - 1); + } if (subdir == "include" || subdir == "lib") { cmValue arch = this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE"); @@ -185,37 +192,47 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths, if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") && this->FC->Makefile->IsDefinitionSet( "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) { - this->AddPathInternal(cmStrCat('/', *arch, dir, subdir), base); + this->AddPathInternal(cmStrCat('/', *arch, dir, subdir), + cmStrCat('/', *arch, prefix), base); } else { - this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), base); + this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix, + base); } } } std::string add = dir + subdir; if (add != "/") { - this->AddPathInternal(add, base); + this->AddPathInternal(add, prefix, base); } if (subdir == "bin") { - this->AddPathInternal(dir + "sbin", base); + this->AddPathInternal(dir + "sbin", prefix, base); } if (!subdir.empty() && path != "/") { - this->AddPathInternal(path, base); + this->AddPathInternal(path, prefix, base); } } } -void cmSearchPath::AddPathInternal(const std::string& path, const char* base) +void cmSearchPath::AddPathInternal(const std::string& path, + const std::string& prefix, const char* base) { assert(this->FC != nullptr); - std::string collapsed = cmSystemTools::CollapseFullPath(path, base); + std::string collapsedPath = cmSystemTools::CollapseFullPath(path, base); - if (collapsed.empty()) { + if (collapsedPath.empty()) { return; } + std::string collapsedPrefix; + if (!prefix.empty()) { + collapsedPrefix = cmSystemTools::CollapseFullPath(prefix, base); + } + // Insert the path if has not already been emitted. - if (this->FC->SearchPathsEmitted.insert(collapsed).second) { - this->Paths.push_back(std::move(collapsed)); + PathWithPrefix pathWithPrefix{ std::move(collapsedPath), + std::move(collapsedPrefix) }; + if (this->FC->SearchPathsEmitted.insert(pathWithPrefix).second) { + this->Paths.emplace_back(std::move(pathWithPrefix)); } } diff --git a/Source/cmSearchPath.h b/Source/cmSearchPath.h index c15cb97..4c0cabb 100644 --- a/Source/cmSearchPath.h +++ b/Source/cmSearchPath.h @@ -26,10 +26,25 @@ public: cmSearchPath(cmFindCommon* findCmd = nullptr); ~cmSearchPath(); - const std::vector<std::string>& GetPaths() const { return this->Paths; } + cmSearchPath(const cmSearchPath&) = default; + cmSearchPath& operator=(const cmSearchPath&) = default; + + struct PathWithPrefix + { + std::string Path; + std::string Prefix; + + bool operator<(const PathWithPrefix& other) const + { + return this->Path < other.Path || + (this->Path == other.Path && this->Prefix < other.Prefix); + } + }; + const std::vector<PathWithPrefix>& GetPaths() const { return this->Paths; } std::size_t size() const { return this->Paths.size(); } - void ExtractWithout(const std::set<std::string>& ignore, + void ExtractWithout(const std::set<std::string>& ignorePaths, + const std::set<std::string>& ignorePrefixes, std::vector<std::string>& outPaths, bool clear = false) const; @@ -44,8 +59,9 @@ public: const char* base = nullptr); protected: - void AddPathInternal(const std::string& path, const char* base = nullptr); + void AddPathInternal(const std::string& path, const std::string& prefix, + const char* base = nullptr); cmFindCommon* FC; - std::vector<std::string> Paths; + std::vector<PathWithPrefix> Paths; }; diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index acc2ed2..785f356 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -152,8 +152,12 @@ struct StandardLevelComputer "dialect \"" << this->Language << *standardProp << "\" " << (ext ? "(with compiler extensions)" : "") - << ", but CMake " - "does not know the compile flags to use to enable it."; + << ". But the current compiler \"" + << makefile->GetSafeDefinition("CMAKE_" + this->Language + + "_COMPILER_ID") + << "\" does not support this, or " + "CMake does not know the flags to enable it."; + makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); } return option_flag; diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h index 417f14d..2722528 100644 --- a/Source/cmStandardLexer.h +++ b/Source/cmStandardLexer.h @@ -50,6 +50,10 @@ # endif #endif +#if defined(__LCC__) +# pragma diag_suppress 1873 /* comparison between signed and unsigned */ +#endif + #if defined(__NVCOMPILER) # pragma diag_suppress 111 /* statement is unreachable */ # pragma diag_suppress 550 /* variable set but never used */ diff --git a/Source/cmState.cxx b/Source/cmState.cxx index e79949d..f1144e1 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -228,22 +228,22 @@ std::string const& cmState::GetGlobVerifyStamp() const return this->GlobVerificationManager->GetVerifyStamp(); } -bool cmState::SaveVerificationScript(const std::string& path) +bool cmState::SaveVerificationScript(const std::string& path, + cmMessenger* messenger) { - return this->GlobVerificationManager->SaveVerificationScript(path); + return this->GlobVerificationManager->SaveVerificationScript(path, + messenger); } -void cmState::AddGlobCacheEntry(bool recurse, bool listDirectories, - bool followSymlinks, - const std::string& relative, - const std::string& expression, - const std::vector<std::string>& files, - const std::string& variable, - cmListFileBacktrace const& backtrace) +void cmState::AddGlobCacheEntry( + bool recurse, bool listDirectories, bool followSymlinks, + const std::string& relative, const std::string& expression, + const std::vector<std::string>& files, const std::string& variable, + cmListFileBacktrace const& backtrace, cmMessenger* messenger) { this->GlobVerificationManager->AddCacheEntry( recurse, listDirectories, followSymlinks, relative, expression, files, - variable, backtrace); + variable, backtrace, messenger); } void cmState::RemoveCacheEntry(std::string const& key) @@ -327,10 +327,12 @@ cmStateSnapshot cmState::Reset() void cmState::DefineProperty(const std::string& name, cmProperty::ScopeType scope, const std::string& ShortDescription, - const std::string& FullDescription, bool chained) + const std::string& FullDescription, bool chained, + const std::string& initializeFromVariable) { this->PropertyDefinitions.DefineProperty(name, scope, ShortDescription, - FullDescription, chained); + FullDescription, chained, + initializeFromVariable); } cmPropertyDefinition const* cmState::GetPropertyDefinition( diff --git a/Source/cmState.h b/Source/cmState.h index a1666ca..4f2b7df 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -133,12 +133,18 @@ public: // Define a property void DefineProperty(const std::string& name, cmProperty::ScopeType scope, const std::string& ShortDescription, - const std::string& FullDescription, bool chain = false); + const std::string& FullDescription, bool chain = false, + const std::string& initializeFromVariable = ""); // get property definition cmPropertyDefinition const* GetPropertyDefinition( const std::string& name, cmProperty::ScopeType scope) const; + const cmPropertyDefinitionMap& GetPropertyDefinitions() const + { + return this->PropertyDefinitions; + } + bool IsPropertyChained(const std::string& name, cmProperty::ScopeType scope) const; @@ -238,13 +244,14 @@ private: bool DoWriteGlobVerifyTarget() const; std::string const& GetGlobVerifyScript() const; std::string const& GetGlobVerifyStamp() const; - bool SaveVerificationScript(const std::string& path); + bool SaveVerificationScript(const std::string& path, cmMessenger* messenger); void AddGlobCacheEntry(bool recurse, bool listDirectories, bool followSymlinks, const std::string& relative, const std::string& expression, const std::vector<std::string>& files, const std::string& variable, - cmListFileBacktrace const& bt); + cmListFileBacktrace const& bt, + cmMessenger* messenger); cmPropertyDefinitionMap PropertyDefinitions; std::vector<std::string> EnabledLanguages; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index f44fcf7..e5935b8 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -526,7 +526,7 @@ bool HandleLengthCommand(std::vector<std::string> const& args, size_t length = stringValue.size(); char buffer[1024]; - sprintf(buffer, "%d", static_cast<int>(length)); + snprintf(buffer, sizeof(buffer), "%d", static_cast<int>(length)); status.GetMakefile().AddDefinition(variableName, buffer); return true; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 1934393..effb837 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -540,7 +540,7 @@ size_t cmSystemTools::CalculateCommandLineLengthLimit() #if defined(_SC_ARG_MAX) // ARG_MAX is the maximum size of the command and environment // that can be passed to the exec functions on UNIX. - // The value in limits.h does not need to be present and may + // The value in climits does not need to be present and may // depend upon runtime memory constraints, hence sysconf() // should be used to query it. long szArgMax = sysconf(_SC_ARG_MAX); @@ -1158,39 +1158,26 @@ void cmSystemTools::MoveFileIfDifferent(const std::string& source, RemoveFile(source); } +#ifndef CMAKE_BOOTSTRAP std::string cmSystemTools::ComputeFileHash(const std::string& source, cmCryptoHash::Algo algo) { -#if !defined(CMAKE_BOOTSTRAP) cmCryptoHash hash(algo); return hash.HashFile(source); -#else - (void)source; - cmSystemTools::Message("hashsum not supported in bootstrapping mode", - "Error"); - return std::string(); -#endif } std::string cmSystemTools::ComputeStringMD5(const std::string& input) { -#if !defined(CMAKE_BOOTSTRAP) cmCryptoHash md5(cmCryptoHash::AlgoMD5); return md5.HashString(input); -#else - (void)input; - cmSystemTools::Message("md5sum not supported in bootstrapping mode", - "Error"); - return ""; -#endif } +# ifdef _WIN32 std::string cmSystemTools::ComputeCertificateThumbprint( const std::string& source) { std::string thumbprint; -#if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) CRYPT_INTEGER_BLOB cryptBlob; HCERTSTORE certStore = NULL; PCCERT_CONTEXT certContext = NULL; @@ -1247,14 +1234,11 @@ std::string cmSystemTools::ComputeCertificateThumbprint( } CloseHandle(certFile); } -#else - (void)source; - cmSystemTools::Message("ComputeCertificateThumbprint is not implemented", - "Error"); -#endif return thumbprint; } +# endif +#endif void cmSystemTools::Glob(const std::string& directory, const std::string& regexp, @@ -1693,7 +1677,8 @@ void list_item_verbose(FILE* out, struct archive_entry* entry) /* Use uname if it's present, else uid. */ p = archive_entry_uname(entry); if ((p == nullptr) || (*p == '\0')) { - sprintf(tmp, "%lu ", static_cast<unsigned long>(archive_entry_uid(entry))); + snprintf(tmp, sizeof(tmp), "%lu ", + static_cast<unsigned long>(archive_entry_uid(entry))); p = tmp; } w = strlen(p); @@ -1707,7 +1692,8 @@ void list_item_verbose(FILE* out, struct archive_entry* entry) fprintf(out, "%s", p); w = strlen(p); } else { - sprintf(tmp, "%lu", static_cast<unsigned long>(archive_entry_gid(entry))); + snprintf(tmp, sizeof(tmp), "%lu", + static_cast<unsigned long>(archive_entry_gid(entry))); w = strlen(tmp); fprintf(out, "%s", tmp); } @@ -1721,15 +1707,15 @@ void list_item_verbose(FILE* out, struct archive_entry* entry) archive_entry_filetype(entry) == AE_IFBLK) { unsigned long rdevmajor = archive_entry_rdevmajor(entry); unsigned long rdevminor = archive_entry_rdevminor(entry); - sprintf(tmp, "%lu,%lu", rdevmajor, rdevminor); + snprintf(tmp, sizeof(tmp), "%lu,%lu", rdevmajor, rdevminor); } else { /* * Note the use of platform-dependent macros to format * the filesize here. We need the format string and the * corresponding type for the cast. */ - sprintf(tmp, BSDTAR_FILESIZE_PRINTF, - static_cast<BSDTAR_FILESIZE_TYPE>(archive_entry_size(entry))); + snprintf(tmp, sizeof(tmp), BSDTAR_FILESIZE_PRINTF, + static_cast<BSDTAR_FILESIZE_TYPE>(archive_entry_size(entry))); } if (w + strlen(tmp) >= gs_width) { gs_width = w + strlen(tmp) + 1; @@ -2496,8 +2482,8 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath, return false; } -std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have, - cm::string_view const& want) +static std::string::size_type cmSystemToolsFindRPath( + cm::string_view const& have, cm::string_view const& want) { std::string::size_type pos = 0; while (pos < have.size()) { @@ -2694,11 +2680,11 @@ std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback( } } -cm::optional<bool> ChangeRPathELF(std::string const& file, - std::string const& oldRPath, - std::string const& newRPath, - bool removeEnvironmentRPath, - std::string* emsg, bool* changed) +static cm::optional<bool> ChangeRPathELF(std::string const& file, + std::string const& oldRPath, + std::string const& newRPath, + bool removeEnvironmentRPath, + std::string* emsg, bool* changed) { auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath]( cm::optional<std::string>& outRPath, @@ -3306,7 +3292,7 @@ std::string cmSystemTools::EncodeURL(std::string const& in, bool escapeSlashes) case ' ': case '=': case '%': - sprintf(hexCh, "%%%02X", static_cast<int>(c)); + snprintf(hexCh, sizeof(hexCh), "%%%02X", static_cast<int>(c)); break; case '/': if (escapeSlashes) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 715724c..19dabe8 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -179,6 +179,7 @@ public: static void MoveFileIfDifferent(const std::string& source, const std::string& destination); +#ifndef CMAKE_BOOTSTRAP //! Compute the hash of a file static std::string ComputeFileHash(const std::string& source, cmCryptoHash::Algo algo); @@ -186,8 +187,11 @@ public: /** Compute the md5sum of a string. */ static std::string ComputeStringMD5(const std::string& input); +# ifdef _WIN32 //! Get the SHA thumbprint for a certificate file static std::string ComputeCertificateThumbprint(const std::string& source); +# endif +#endif /** * Run a single executable command diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 45e23d3..6059055 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -14,19 +14,21 @@ #include <cm/memory> #include <cmext/algorithm> +#include <cmext/string_view> #include "cmsys/RegularExpression.hxx" #include "cmAlgorithms.h" #include "cmCustomCommand.h" +#include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" -#include "cmMessenger.h" #include "cmProperty.h" +#include "cmPropertyDefinition.h" #include "cmPropertyMap.h" #include "cmRange.h" #include "cmSourceFile.h" @@ -80,9 +82,8 @@ const std::string& cmTargetPropertyComputer::ComputeLocation<cmTarget>( } template <> -cmValue cmTargetPropertyComputer::GetSources<cmTarget>( - cmTarget const* tgt, cmMessenger* messenger, - cmListFileBacktrace const& context) +cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt, + cmMakefile const& mf) { cmBTStringRange entries = tgt->GetSourceEntries(); if (entries.empty()) { @@ -109,7 +110,7 @@ cmValue cmTargetPropertyComputer::GetSources<cmTarget>( bool noMessage = true; std::ostringstream e; MessageType messageType = MessageType::AUTHOR_WARNING; - switch (context.GetBottom().GetPolicy(cmPolicies::CMP0051)) { + switch (mf.GetPolicyStatus(cmPolicies::CMP0051)) { case cmPolicies::WARN: e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0051) << "\n"; noMessage = false; @@ -130,7 +131,7 @@ cmValue cmTargetPropertyComputer::GetSources<cmTarget>( "time. Code reading that property needs to be adapted to " "ignore the generator expression using the string(GENEX_STRIP) " "command."; - messenger->IssueMessage(messageType, e.str(), context); + mf.IssueMessage(messageType, e.str()); } if (addContent) { ss << sep; @@ -201,8 +202,14 @@ public: std::vector<BT<std::string>> LinkOptionsEntries; std::vector<BT<std::string>> LinkDirectoriesEntries; std::vector<BT<std::string>> LinkImplementationPropertyEntries; + std::vector<BT<std::string>> LinkInterfacePropertyEntries; + std::vector<BT<std::string>> LinkInterfaceDirectPropertyEntries; + std::vector<BT<std::string>> LinkInterfaceDirectExcludePropertyEntries; + std::vector<BT<std::string>> HeaderSetsEntries; + std::vector<BT<std::string>> InterfaceHeaderSetsEntries; std::vector<std::pair<cmTarget::TLLSignature, cmListFileContext>> TLLCommands; + std::map<std::string, cmFileSet> FileSets; cmListFileBacktrace Backtrace; bool CheckImportedLibName(std::string const& prop, @@ -396,6 +403,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("XCODE_SCHEME_ADDRESS_SANITIZER"); initProp("XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN"); initProp("XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING"); + initProp("XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE"); initProp("XCODE_SCHEME_THREAD_SANITIZER"); initProp("XCODE_SCHEME_THREAD_SANITIZER_STOP"); initProp("XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER"); @@ -467,6 +475,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp(property); } } + if (!this->IsImported()) { + initProp("LINK_LIBRARIES_ONLY_TARGETS"); + } } // Save the backtrace of target construction. @@ -522,6 +533,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->impl->PolicyMap.Set(cmPolicies::CMP0022, cmPolicies::NEW); } + if (!this->IsImported()) { + initProp("DOTNET_SDK"); + } + if (this->impl->TargetType <= cmStateEnums::GLOBAL_TARGET) { initProp("DOTNET_TARGET_FRAMEWORK"); initProp("DOTNET_TARGET_FRAMEWORK_VERSION"); @@ -546,6 +561,16 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, } } } + + for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) { + if (prop.first.second == cmProperty::TARGET && + !prop.second.GetInitializeFromVariable().empty()) { + if (auto value = + mf->GetDefinition(prop.second.GetInitializeFromVariable())) { + this->SetProperty(prop.first.first, value); + } + } + } } cmTarget::cmTarget(cmTarget&&) noexcept = default; @@ -1114,6 +1139,31 @@ cmBTStringRange cmTarget::GetLinkImplementationEntries() const return cmMakeRange(this->impl->LinkImplementationPropertyEntries); } +cmBTStringRange cmTarget::GetLinkInterfaceEntries() const +{ + return cmMakeRange(this->impl->LinkInterfacePropertyEntries); +} + +cmBTStringRange cmTarget::GetLinkInterfaceDirectEntries() const +{ + return cmMakeRange(this->impl->LinkInterfaceDirectPropertyEntries); +} + +cmBTStringRange cmTarget::GetLinkInterfaceDirectExcludeEntries() const +{ + return cmMakeRange(this->impl->LinkInterfaceDirectExcludePropertyEntries); +} + +cmBTStringRange cmTarget::GetHeaderSetsEntries() const +{ + return cmMakeRange(this->impl->HeaderSetsEntries); +} + +cmBTStringRange cmTarget::GetInterfaceHeaderSetsEntries() const +{ + return cmMakeRange(this->impl->InterfaceHeaderSetsEntries); +} + namespace { #define MAKE_PROP(PROP) const std::string prop##PROP = #PROP MAKE_PROP(C_STANDARD); @@ -1143,6 +1193,13 @@ MAKE_PROP(BINARY_DIR); MAKE_PROP(SOURCE_DIR); MAKE_PROP(FALSE); MAKE_PROP(TRUE); +MAKE_PROP(HEADER_DIRS); +MAKE_PROP(HEADER_SET); +MAKE_PROP(HEADER_SETS); +MAKE_PROP(INTERFACE_HEADER_SETS); +MAKE_PROP(INTERFACE_LINK_LIBRARIES); +MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT); +MAKE_PROP(INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE); #undef MAKE_PROP } @@ -1162,6 +1219,21 @@ std::string ConvertToString<cmValue>(cmValue value) { return std::string(*value); } + +template <typename ValueType> +bool StringIsEmpty(ValueType value); + +template <> +bool StringIsEmpty<const char*>(const char* value) +{ + return cmValue::IsEmpty(value); +} + +template <> +bool StringIsEmpty<cmValue>(cmValue value) +{ + return value.IsEmpty(); +} } template <typename ValueType> @@ -1253,6 +1325,25 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt); } + } else if (prop == propINTERFACE_LINK_LIBRARIES) { + this->impl->LinkInterfacePropertyEntries.clear(); + if (value) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt); + } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) { + this->impl->LinkInterfaceDirectPropertyEntries.clear(); + if (value) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt); + } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) { + this->impl->LinkInterfaceDirectExcludePropertyEntries.clear(); + if (value) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value, + lfbt); + } } else if (prop == propSOURCES) { this->impl->SourceEntries.clear(); if (value) { @@ -1325,6 +1416,104 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) } else { this->impl->LanguageStandardProperties.erase(prop); } + } else if (prop == propHEADER_DIRS) { + auto* fileSet = this->GetFileSet("HEADERS"); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "The default header set has not yet been created."); + return; + } + fileSet->ClearDirectoryEntries(); + if (!StringIsEmpty(value)) { + fileSet->AddDirectoryEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } + } else if (prop == propHEADER_SET) { + auto* fileSet = this->GetFileSet("HEADERS"); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "The default header set has not yet been created."); + return; + } + fileSet->ClearFileEntries(); + if (!StringIsEmpty(value)) { + fileSet->AddFileEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } + } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) { + auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_")); + if (fileSetName.empty()) { + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "Header set name cannot be empty."); + return; + } + auto* fileSet = this->GetFileSet(fileSetName); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", fileSetName, + "\" has not yet been created.")); + return; + } + fileSet->ClearDirectoryEntries(); + if (!StringIsEmpty(value)) { + fileSet->AddDirectoryEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } + } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) { + auto fileSetName = prop.substr(cmStrLen("HEADER_SET_")); + if (fileSetName.empty()) { + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "Header set name cannot be empty."); + return; + } + auto* fileSet = this->GetFileSet(fileSetName); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", fileSetName, + "\" has not yet been created.")); + return; + } + fileSet->ClearFileEntries(); + if (!StringIsEmpty(value)) { + fileSet->AddFileEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } + } else if (prop == propHEADER_SETS) { + if (value) { + for (auto const& name : cmExpandedList(value)) { + if (!this->GetFileSet(name)) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", name, "\" has not yet been created.")); + return; + } + } + } + this->impl->HeaderSetsEntries.clear(); + if (!StringIsEmpty(value)) { + this->impl->HeaderSetsEntries.emplace_back( + value, this->impl->Makefile->GetBacktrace()); + } + } else if (prop == propINTERFACE_HEADER_SETS) { + if (value) { + for (auto const& name : cmExpandedList(value)) { + if (!this->GetFileSet(name)) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", name, "\" has not yet been created.")); + return; + } + } + } + this->impl->InterfaceHeaderSetsEntries.clear(); + if (!StringIsEmpty(value)) { + this->impl->InterfaceHeaderSetsEntries.emplace_back( + value, this->impl->Makefile->GetBacktrace()); + } } else { this->impl->Properties.SetProperty(prop, value); } @@ -1408,6 +1597,22 @@ void cmTarget::AppendProperty(const std::string& prop, cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); this->impl->LinkImplementationPropertyEntries.emplace_back(value, lfbt); } + } else if (prop == propINTERFACE_LINK_LIBRARIES) { + if (!value.empty()) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfacePropertyEntries.emplace_back(value, lfbt); + } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) { + if (!value.empty()) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectPropertyEntries.emplace_back(value, lfbt); + } + } else if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) { + if (!value.empty()) { + cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); + this->impl->LinkInterfaceDirectExcludePropertyEntries.emplace_back(value, + lfbt); + } } else if (prop == "SOURCES") { cmListFileBacktrace lfbt = this->impl->Makefile->GetBacktrace(); this->impl->SourceEntries.emplace_back(value, lfbt); @@ -1419,6 +1624,82 @@ void cmTarget::AppendProperty(const std::string& prop, prop == "OBJC_STANDARD" || prop == "OBJCXX_STANDARD") { this->impl->Makefile->IssueMessage( MessageType::FATAL_ERROR, prop + " property may not be appended."); + } else if (prop == "HEADER_DIRS") { + auto* fileSet = this->GetFileSet("HEADERS"); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "The default header set has not yet been created."); + return; + } + fileSet->AddDirectoryEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } else if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) { + auto fileSetName = prop.substr(cmStrLen("HEADER_DIRS_")); + if (fileSetName.empty()) { + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "Header set name cannot be empty."); + return; + } + auto* fileSet = this->GetFileSet(fileSetName); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", fileSetName, + "\" has not yet been created.")); + return; + } + fileSet->AddDirectoryEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } else if (prop == "HEADER_SET") { + auto* fileSet = this->GetFileSet("HEADERS"); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + "The default header set has not yet been created."); + return; + } + fileSet->AddFileEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } else if (cmHasLiteralPrefix(prop, "HEADER_SET_")) { + auto fileSetName = prop.substr(cmStrLen("HEADER_SET_")); + if (fileSetName.empty()) { + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, + "Header set name cannot be empty."); + return; + } + auto* fileSet = this->GetFileSet(fileSetName); + if (!fileSet) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", fileSetName, + "\" has not yet been created.")); + return; + } + fileSet->AddFileEntry( + BT<std::string>(value, this->impl->Makefile->GetBacktrace())); + } else if (prop == "HEADER_SETS") { + for (auto const& name : cmExpandedList(value)) { + if (!this->GetFileSet(name)) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", name, "\" has not yet been created.")); + return; + } + } + this->impl->HeaderSetsEntries.emplace_back( + value, this->impl->Makefile->GetBacktrace()); + } else if (prop == "INTERFACE_HEADER_SETS") { + for (auto const& name : cmExpandedList(value)) { + if (!this->GetFileSet(name)) { + this->impl->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Header set \"", name, "\" has not yet been created.")); + return; + } + } + this->impl->InterfaceHeaderSetsEntries.emplace_back( + value, this->impl->Makefile->GetBacktrace()); } else { this->impl->Properties.AppendProperty(prop, value, asString); } @@ -1608,10 +1889,9 @@ void cmTarget::CheckProperty(const std::string& prop, } cmValue cmTarget::GetComputedProperty(const std::string& prop, - cmMessenger* messenger, - cmListFileBacktrace const& context) const + cmMakefile& mf) const { - return cmTargetPropertyComputer::GetProperty(this, prop, messenger, context); + return cmTargetPropertyComputer::GetProperty(this, prop, mf); } cmValue cmTarget::GetProperty(const std::string& prop) const @@ -1637,7 +1917,14 @@ cmValue cmTarget::GetProperty(const std::string& prop) const propNAME, propBINARY_DIR, propSOURCE_DIR, - propSOURCES + propSOURCES, + propHEADER_DIRS, + propHEADER_SET, + propHEADER_SETS, + propINTERFACE_HEADER_SETS, + propINTERFACE_LINK_LIBRARIES, + propINTERFACE_LINK_LIBRARIES_DIRECT, + propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE, }; if (specialProps.count(prop)) { if (prop == propC_STANDARD || prop == propCXX_STANDARD || @@ -1658,6 +1945,34 @@ cmValue cmTarget::GetProperty(const std::string& prop) const output = cmJoin(this->impl->LinkImplementationPropertyEntries, ";"); return cmValue(output); } + if (prop == propINTERFACE_LINK_LIBRARIES) { + if (this->impl->LinkInterfacePropertyEntries.empty()) { + return nullptr; + } + + static std::string output; + output = cmJoin(this->impl->LinkInterfacePropertyEntries, ";"); + return cmValue(output); + } + if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT) { + if (this->impl->LinkInterfaceDirectPropertyEntries.empty()) { + return nullptr; + } + + static std::string output; + output = cmJoin(this->impl->LinkInterfaceDirectPropertyEntries, ";"); + return cmValue(output); + } + if (prop == propINTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE) { + if (this->impl->LinkInterfaceDirectExcludePropertyEntries.empty()) { + return nullptr; + } + + static std::string output; + output = + cmJoin(this->impl->LinkInterfaceDirectExcludePropertyEntries, ";"); + return cmValue(output); + } // the type property returns what type the target is if (prop == propTYPE) { return cmValue(cmState::GetTargetTypeName(this->GetType())); @@ -1763,6 +2078,60 @@ cmValue cmTarget::GetProperty(const std::string& prop) const .GetDirectory() .GetCurrentSource()); } + if (prop == propHEADER_DIRS) { + auto const* fileSet = this->GetFileSet("HEADERS"); + if (!fileSet) { + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s); + return cmValue(output); + } + if (prop == propHEADER_SET) { + auto const* fileSet = this->GetFileSet("HEADERS"); + if (!fileSet) { + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetFileEntries(), ";"_s); + return cmValue(output); + } + if (prop == propHEADER_SETS) { + static std::string output; + output = cmJoin(this->impl->HeaderSetsEntries, ";"_s); + return cmValue(output); + } + if (prop == propINTERFACE_HEADER_SETS) { + static std::string output; + output = cmJoin(this->impl->InterfaceHeaderSetsEntries, ";"_s); + return cmValue(output); + } + } + if (cmHasLiteralPrefix(prop, "HEADER_DIRS_")) { + std::string fileSetName = prop.substr(cmStrLen("HEADER_DIRS_")); + if (fileSetName.empty()) { + return nullptr; + } + auto const* fileSet = this->GetFileSet(fileSetName); + if (!fileSet) { + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetDirectoryEntries(), ";"_s); + return cmValue(output); + } + if (cmHasLiteralPrefix(prop, "HEADER_SET_")) { + std::string fileSetName = prop.substr(cmStrLen("HEADER_SET_")); + if (fileSetName.empty()) { + return nullptr; + } + auto const* fileSet = this->GetFileSet(fileSetName); + if (!fileSet) { + return nullptr; + } + static std::string output; + output = cmJoin(fileSet->GetFileEntries(), ";"_s); + return cmValue(output); } cmValue retVal = this->impl->Properties.GetPropertyValue(prop); @@ -2019,6 +2388,59 @@ std::string cmTarget::ImportedGetFullPath( return result; } +const cmFileSet* cmTarget::GetFileSet(const std::string& name) const +{ + auto it = this->impl->FileSets.find(name); + return it == this->impl->FileSets.end() ? nullptr : &it->second; +} + +cmFileSet* cmTarget::GetFileSet(const std::string& name) +{ + auto it = this->impl->FileSets.find(name); + return it == this->impl->FileSets.end() ? nullptr : &it->second; +} + +std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet( + const std::string& name, const std::string& type) +{ + auto result = + this->impl->FileSets.emplace(std::make_pair(name, cmFileSet(name, type))); + return std::make_pair(&result.first->second, result.second); +} + +std::string cmTarget::GetFileSetsPropertyName(const std::string& type) +{ + if (type == "HEADERS") { + return "HEADER_SETS"; + } + return ""; +} + +std::string cmTarget::GetInterfaceFileSetsPropertyName(const std::string& type) +{ + if (type == "HEADERS") { + return "INTERFACE_HEADER_SETS"; + } + return ""; +} + +std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const +{ + std::vector<std::string> result; + auto inserter = std::back_inserter(result); + + auto appendEntries = [=](const std::vector<BT<std::string>>& entries) { + for (auto const& entry : entries) { + auto expanded = cmExpandedList(entry.Value); + std::copy(expanded.begin(), expanded.end(), inserter); + } + }; + + appendEntries(this->impl->InterfaceHeaderSetsEntries); + + return result; +} + bool cmTargetInternals::CheckImportedLibName(std::string const& prop, std::string const& value) const { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 95aa4d3..0cdd2fc 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -12,7 +12,6 @@ #include <vector> #include "cmAlgorithms.h" -#include "cmListFileCache.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" @@ -20,15 +19,22 @@ #include "cmValue.h" class cmCustomCommand; +class cmFileSet; class cmGlobalGenerator; class cmInstallTargetGenerator; +class cmListFileBacktrace; +class cmListFileContext; class cmMakefile; -class cmMessenger; class cmPropertyMap; class cmSourceFile; class cmTargetExport; class cmTargetInternals; +template <typename T> +class BT; +template <typename T> +class BTs; + /** \class cmTarget * \brief Represent a library or executable target loaded from a makefile. * @@ -184,8 +190,7 @@ public: std::string const& GetSafeProperty(std::string const& prop) const; bool GetPropertyAsBool(const std::string& prop) const; void CheckProperty(const std::string& prop, cmMakefile* context) const; - cmValue GetComputedProperty(const std::string& prop, cmMessenger* messenger, - cmListFileBacktrace const& context) const; + cmValue GetComputedProperty(const std::string& prop, cmMakefile& mf) const; //! Get all properties cmPropertyMap const& GetProperties() const; @@ -263,6 +268,14 @@ public: cmBTStringRange GetLinkImplementationEntries() const; + cmBTStringRange GetLinkInterfaceEntries() const; + cmBTStringRange GetLinkInterfaceDirectEntries() const; + cmBTStringRange GetLinkInterfaceDirectExcludeEntries() const; + + cmBTStringRange GetHeaderSetsEntries() const; + + cmBTStringRange GetInterfaceHeaderSetsEntries() const; + std::string ImportedGetFullPath(const std::string& config, cmStateEnums::ArtifactType artifact) const; @@ -271,6 +284,16 @@ public: bool operator()(cmTarget const* t1, cmTarget const* t2) const; }; + const cmFileSet* GetFileSet(const std::string& name) const; + cmFileSet* GetFileSet(const std::string& name); + std::pair<cmFileSet*, bool> GetOrCreateFileSet(const std::string& name, + const std::string& type); + + std::vector<std::string> GetAllInterfaceFileSets() const; + + static std::string GetFileSetsPropertyName(const std::string& type); + static std::string GetInterfaceFileSetsPropertyName(const std::string& type); + private: template <typename ValueType> void StoreProperty(const std::string& prop, ValueType value); diff --git a/Source/cmTargetDepend.h b/Source/cmTargetDepend.h index 36702bd..9027409 100644 --- a/Source/cmTargetDepend.h +++ b/Source/cmTargetDepend.h @@ -6,6 +6,8 @@ #include <set> +#include "cmListFileCache.h" + class cmGeneratorTarget; /** One edge in the global target dependency graph. diff --git a/Source/cmTargetExport.h b/Source/cmTargetExport.h index 19fc931..885ac74 100644 --- a/Source/cmTargetExport.h +++ b/Source/cmTargetExport.h @@ -6,7 +6,9 @@ #include <string> +class cmFileSet; class cmGeneratorTarget; +class cmInstallFileSetGenerator; class cmInstallFilesGenerator; class cmInstallTargetGenerator; @@ -29,6 +31,7 @@ public: cmInstallTargetGenerator* FrameworkGenerator; cmInstallTargetGenerator* BundleGenerator; cmInstallFilesGenerator* HeaderGenerator; + std::map<cmFileSet*, cmInstallFileSetGenerator*> FileSetGenerators; ///@} bool NamelinkOnly = false; diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index e15c941..94fcdd9 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -2,11 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmTargetLinkLibrariesCommand.h" +#include <cassert> #include <memory> #include <sstream> #include <unordered_set> #include <utility> +#include <cm/optional> + #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" #include "cmGlobalGenerator.h" @@ -178,123 +181,156 @@ bool cmTargetLinkLibrariesCommand(std::vector<std::string> const& args, // specification if the keyword is encountered as the first argument. ProcessingState currentProcessingState = ProcessingLinkLibraries; + // Accumulate consectuive non-keyword arguments into one entry in + // order to handle unquoted generator expressions containing ';'. + cm::optional<std::string> currentEntry; + auto processCurrentEntry = [&]() -> bool { + if (currentEntry) { + assert(!haveLLT); + if (!tll.HandleLibrary(currentProcessingState, *currentEntry, + GENERAL_LibraryType)) { + return false; + } + currentEntry = cm::nullopt; + } + return true; + }; + auto extendCurrentEntry = [¤tEntry](std::string const& arg) { + if (currentEntry) { + currentEntry = cmStrCat(*currentEntry, ';', arg); + } else { + currentEntry = arg; + } + }; + + // Keep this list in sync with the keyword dispatch below. + static std::unordered_set<std::string> const keywords{ + "LINK_INTERFACE_LIBRARIES", + "INTERFACE", + "LINK_PUBLIC", + "PUBLIC", + "LINK_PRIVATE", + "PRIVATE", + "debug", + "optimized", + "general", + }; + // Add libraries, note that there is an optional prefix // of debug and optimized that can be used. for (unsigned int i = 1; i < args.size(); ++i) { - if (args[i] == "LINK_INTERFACE_LIBRARIES") { - currentProcessingState = ProcessingPlainLinkInterface; - if (i != 1) { - mf.IssueMessage( - MessageType::FATAL_ERROR, - "The LINK_INTERFACE_LIBRARIES option must appear as the second " - "argument, just after the target name."); - return true; - } - } else if (args[i] == "INTERFACE") { - if (i != 1 && - currentProcessingState != ProcessingKeywordPrivateInterface && - currentProcessingState != ProcessingKeywordPublicInterface && - currentProcessingState != ProcessingKeywordLinkInterface) { - mf.IssueMessage( - MessageType::FATAL_ERROR, - "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " - "argument, just after the target name."); - return true; - } - currentProcessingState = ProcessingKeywordLinkInterface; - } else if (args[i] == "LINK_PUBLIC") { - if (i != 1 && - currentProcessingState != ProcessingPlainPrivateInterface && - currentProcessingState != ProcessingPlainPublicInterface) { - mf.IssueMessage( - MessageType::FATAL_ERROR, - "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second " - "argument, just after the target name."); - return true; - } - currentProcessingState = ProcessingPlainPublicInterface; - } else if (args[i] == "PUBLIC") { - if (i != 1 && - currentProcessingState != ProcessingKeywordPrivateInterface && - currentProcessingState != ProcessingKeywordPublicInterface && - currentProcessingState != ProcessingKeywordLinkInterface) { - mf.IssueMessage( - MessageType::FATAL_ERROR, - "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " - "argument, just after the target name."); - return true; - } - currentProcessingState = ProcessingKeywordPublicInterface; - } else if (args[i] == "LINK_PRIVATE") { - if (i != 1 && currentProcessingState != ProcessingPlainPublicInterface && - currentProcessingState != ProcessingPlainPrivateInterface) { - mf.IssueMessage( - MessageType::FATAL_ERROR, - "The LINK_PUBLIC or LINK_PRIVATE option must appear as the second " - "argument, just after the target name."); - return true; - } - currentProcessingState = ProcessingPlainPrivateInterface; - } else if (args[i] == "PRIVATE") { - if (i != 1 && - currentProcessingState != ProcessingKeywordPrivateInterface && - currentProcessingState != ProcessingKeywordPublicInterface && - currentProcessingState != ProcessingKeywordLinkInterface) { - mf.IssueMessage( - MessageType::FATAL_ERROR, - "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " - "argument, just after the target name."); - return true; - } - currentProcessingState = ProcessingKeywordPrivateInterface; - } else if (args[i] == "debug") { - if (haveLLT) { - LinkLibraryTypeSpecifierWarning(mf, llt, DEBUG_LibraryType); - } - llt = DEBUG_LibraryType; - haveLLT = true; - } else if (args[i] == "optimized") { - if (haveLLT) { - LinkLibraryTypeSpecifierWarning(mf, llt, OPTIMIZED_LibraryType); + if (keywords.count(args[i])) { + // A keyword argument terminates any preceding accumulated entry. + if (!processCurrentEntry()) { + return false; } - llt = OPTIMIZED_LibraryType; - haveLLT = true; - } else if (args[i] == "general") { - if (haveLLT) { - LinkLibraryTypeSpecifierWarning(mf, llt, GENERAL_LibraryType); + + // Process this keyword argument. + if (args[i] == "LINK_INTERFACE_LIBRARIES") { + currentProcessingState = ProcessingPlainLinkInterface; + if (i != 1) { + mf.IssueMessage( + MessageType::FATAL_ERROR, + "The LINK_INTERFACE_LIBRARIES option must appear as the " + "second argument, just after the target name."); + return true; + } + } else if (args[i] == "INTERFACE") { + if (i != 1 && + currentProcessingState != ProcessingKeywordPrivateInterface && + currentProcessingState != ProcessingKeywordPublicInterface && + currentProcessingState != ProcessingKeywordLinkInterface) { + mf.IssueMessage(MessageType::FATAL_ERROR, + "The INTERFACE, PUBLIC or PRIVATE option must " + "appear as the second argument, just after the " + "target name."); + return true; + } + currentProcessingState = ProcessingKeywordLinkInterface; + } else if (args[i] == "LINK_PUBLIC") { + if (i != 1 && + currentProcessingState != ProcessingPlainPrivateInterface && + currentProcessingState != ProcessingPlainPublicInterface) { + mf.IssueMessage( + MessageType::FATAL_ERROR, + "The LINK_PUBLIC or LINK_PRIVATE option must appear as the " + "second argument, just after the target name."); + return true; + } + currentProcessingState = ProcessingPlainPublicInterface; + } else if (args[i] == "PUBLIC") { + if (i != 1 && + currentProcessingState != ProcessingKeywordPrivateInterface && + currentProcessingState != ProcessingKeywordPublicInterface && + currentProcessingState != ProcessingKeywordLinkInterface) { + mf.IssueMessage(MessageType::FATAL_ERROR, + "The INTERFACE, PUBLIC or PRIVATE option must " + "appear as the second argument, just after the " + "target name."); + return true; + } + currentProcessingState = ProcessingKeywordPublicInterface; + } else if (args[i] == "LINK_PRIVATE") { + if (i != 1 && + currentProcessingState != ProcessingPlainPublicInterface && + currentProcessingState != ProcessingPlainPrivateInterface) { + mf.IssueMessage( + MessageType::FATAL_ERROR, + "The LINK_PUBLIC or LINK_PRIVATE option must appear as the " + "second argument, just after the target name."); + return true; + } + currentProcessingState = ProcessingPlainPrivateInterface; + } else if (args[i] == "PRIVATE") { + if (i != 1 && + currentProcessingState != ProcessingKeywordPrivateInterface && + currentProcessingState != ProcessingKeywordPublicInterface && + currentProcessingState != ProcessingKeywordLinkInterface) { + mf.IssueMessage(MessageType::FATAL_ERROR, + "The INTERFACE, PUBLIC or PRIVATE option must " + "appear as the second argument, just after the " + "target name."); + return true; + } + currentProcessingState = ProcessingKeywordPrivateInterface; + } else if (args[i] == "debug") { + if (haveLLT) { + LinkLibraryTypeSpecifierWarning(mf, llt, DEBUG_LibraryType); + } + llt = DEBUG_LibraryType; + haveLLT = true; + } else if (args[i] == "optimized") { + if (haveLLT) { + LinkLibraryTypeSpecifierWarning(mf, llt, OPTIMIZED_LibraryType); + } + llt = OPTIMIZED_LibraryType; + haveLLT = true; + } else if (args[i] == "general") { + if (haveLLT) { + LinkLibraryTypeSpecifierWarning(mf, llt, GENERAL_LibraryType); + } + llt = GENERAL_LibraryType; + haveLLT = true; } - llt = GENERAL_LibraryType; - haveLLT = true; } else if (haveLLT) { // The link type was specified by the previous argument. haveLLT = false; + assert(!currentEntry); if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) { return false; } - } else { - // Lookup old-style cache entry if type is unspecified. So if you - // do a target_link_libraries(foo optimized bar) it will stay optimized - // and not use the lookup. As there may be the case where someone has - // specified that a library is both debug and optimized. (this check is - // only there for backwards compatibility when mixing projects built - // with old versions of CMake and new) llt = GENERAL_LibraryType; - std::string linkType = cmStrCat(args[0], "_LINK_TYPE"); - cmValue linkTypeString = mf.GetDefinition(linkType); - if (linkTypeString) { - if (*linkTypeString == "debug") { - llt = DEBUG_LibraryType; - } - if (*linkTypeString == "optimized") { - llt = OPTIMIZED_LibraryType; - } - } - if (!tll.HandleLibrary(currentProcessingState, args[i], llt)) { - return false; - } + } else { + // Accumulate this argument in the current entry. + extendCurrentEntry(args[i]); } } + // Process the last accumulated entry, if any. + if (!processCurrentEntry()) { + return false; + } + // Make sure the last argument was not a library type specifier. if (haveLLT) { mf.IssueMessage(MessageType::FATAL_ERROR, diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 3bd1ea3..391b954 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -155,10 +155,10 @@ bool cmTargetPropCommandBase::ProcessContentArgs( return false; } } - return this->PopulateTargetProperies(scope, content, prepend, system); + return this->PopulateTargetProperties(scope, content, prepend, system); } -bool cmTargetPropCommandBase::PopulateTargetProperies( +bool cmTargetPropCommandBase::PopulateTargetProperties( const std::string& scope, const std::vector<std::string>& content, bool prepend, bool system) { diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index fc24fe8..6bf7c3c 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -40,6 +40,9 @@ protected: virtual void HandleInterfaceContent(cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool system); + virtual bool PopulateTargetProperties( + const std::string& scope, const std::vector<std::string>& content, + bool prepend, bool system); private: virtual void HandleMissingTarget(const std::string& name) = 0; @@ -52,9 +55,6 @@ private: bool ProcessContentArgs(std::vector<std::string> const& args, unsigned int& argIndex, bool prepend, bool system); - bool PopulateTargetProperies(const std::string& scope, - const std::vector<std::string>& content, - bool prepend, bool system); cmExecutionStatus& Status; }; diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index 9b94142..134b4b6 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -5,19 +5,17 @@ #include <sstream> +#include "cmMakefile.h" #include "cmMessageType.h" -#include "cmMessenger.h" #include "cmPolicies.h" -#include "cmStateSnapshot.h" bool cmTargetPropertyComputer::HandleLocationPropertyPolicy( - std::string const& tgtName, cmMessenger* messenger, - cmListFileBacktrace const& context) + std::string const& tgtName, cmMakefile const& mf) { std::ostringstream e; const char* modal = nullptr; MessageType messageType = MessageType::AUTHOR_WARNING; - switch (context.GetBottom().GetPolicy(cmPolicies::CMP0026)) { + switch (mf.GetPolicyStatus(cmPolicies::CMP0026)) { case cmPolicies::WARN: e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0026) << "\n"; modal = "should"; @@ -38,7 +36,7 @@ bool cmTargetPropertyComputer::HandleLocationPropertyPolicy( << "\". Use the target name directly with " "add_custom_command, or use the generator expression $<TARGET_FILE>, " "as appropriate.\n"; - messenger->IssueMessage(messageType, e.str(), context); + mf.IssueMessage(messageType, e.str()); } return messageType != MessageType::FATAL_ERROR; diff --git a/Source/cmTargetPropertyComputer.h b/Source/cmTargetPropertyComputer.h index e61a1fc..82c6355 100644 --- a/Source/cmTargetPropertyComputer.h +++ b/Source/cmTargetPropertyComputer.h @@ -6,38 +6,35 @@ #include <string> -#include "cmListFileCache.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" -class cmMessenger; +class cmMakefile; class cmTargetPropertyComputer { public: template <typename Target> static cmValue GetProperty(Target const* tgt, const std::string& prop, - cmMessenger* messenger, - cmListFileBacktrace const& context) + cmMakefile const& mf) { - if (cmValue loc = GetLocation(tgt, prop, messenger, context)) { + if (cmValue loc = GetLocation(tgt, prop, mf)) { return loc; } if (cmSystemTools::GetFatalErrorOccured()) { return nullptr; } if (prop == "SOURCES") { - return GetSources(tgt, messenger, context); + return GetSources(tgt, mf); } return nullptr; } private: static bool HandleLocationPropertyPolicy(std::string const& tgtName, - cmMessenger* messenger, - cmListFileBacktrace const& context); + cmMakefile const& mf); template <typename Target> static const std::string& ComputeLocationForBuild(Target const* tgt); @@ -47,8 +44,7 @@ private: template <typename Target> static cmValue GetLocation(Target const* tgt, std::string const& prop, - cmMessenger* messenger, - cmListFileBacktrace const& context) + cmMakefile const& mf) { // Watch for special "computed" properties that are dependent on @@ -61,8 +57,7 @@ private: static const std::string propLOCATION = "LOCATION"; if (prop == propLOCATION) { if (!tgt->IsImported() && - !HandleLocationPropertyPolicy(tgt->GetName(), messenger, - context)) { + !HandleLocationPropertyPolicy(tgt->GetName(), mf)) { return nullptr; } return cmValue(ComputeLocationForBuild(tgt)); @@ -71,8 +66,7 @@ private: // Support "LOCATION_<CONFIG>". if (cmHasLiteralPrefix(prop, "LOCATION_")) { if (!tgt->IsImported() && - !HandleLocationPropertyPolicy(tgt->GetName(), messenger, - context)) { + !HandleLocationPropertyPolicy(tgt->GetName(), mf)) { return nullptr; } std::string configName = prop.substr(9); @@ -85,8 +79,7 @@ private: std::string configName(prop.c_str(), prop.size() - 9); if (configName != "IMPORTED") { if (!tgt->IsImported() && - !HandleLocationPropertyPolicy(tgt->GetName(), messenger, - context)) { + !HandleLocationPropertyPolicy(tgt->GetName(), mf)) { return nullptr; } return cmValue(ComputeLocation(tgt, configName)); @@ -97,6 +90,5 @@ private: } template <typename Target> - static cmValue GetSources(Target const* tgt, cmMessenger* messenger, - cmListFileBacktrace const& context); + static cmValue GetSources(Target const* tgt, cmMakefile const& mf); }; diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index 26282ef..b425acb 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -2,12 +2,21 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmTargetSourcesCommand.h" +#include <algorithm> #include <sstream> +#include <utility> +#include <cm/string_view> +#include <cmext/string_view> + +#include "cmArgumentParser.h" +#include "cmFileSet.h" #include "cmGeneratorExpression.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" @@ -15,6 +24,20 @@ namespace { +struct FileSetArgs +{ + std::string Type; + std::string FileSet; + std::vector<std::string> BaseDirs; + std::vector<std::string> Files; +}; + +auto const FileSetArgsParser = cmArgumentParser<FileSetArgs>() + .Bind("TYPE"_s, &FileSetArgs::Type) + .Bind("FILE_SET"_s, &FileSetArgs::FileSet) + .Bind("BASE_DIRS"_s, &FileSetArgs::BaseDirs) + .Bind("FILES"_s, &FileSetArgs::Files); + class TargetSourcesImpl : public cmTargetPropCommandBase { public: @@ -26,8 +49,10 @@ protected: bool prepend, bool system) override { this->cmTargetPropCommandBase::HandleInterfaceContent( - tgt, this->ConvertToAbsoluteContent(tgt, content, true), prepend, - system); + tgt, + this->ConvertToAbsoluteContent(tgt, content, IsInterface::Yes, + CheckCMP0076::Yes), + prepend, system); } private: @@ -43,29 +68,55 @@ private: const std::vector<std::string>& content, bool /*prepend*/, bool /*system*/) override { - tgt->AppendProperty( - "SOURCES", - this->Join(this->ConvertToAbsoluteContent(tgt, content, false))); + tgt->AppendProperty("SOURCES", + this->Join(this->ConvertToAbsoluteContent( + tgt, content, IsInterface::No, CheckCMP0076::Yes))); return true; // Successfully handled. } + bool PopulateTargetProperties(const std::string& scope, + const std::vector<std::string>& content, + bool prepend, bool system) override + { + if (!content.empty() && content.front() == "FILE_SET"_s) { + return this->HandleFileSetMode(scope, content, prepend, system); + } + return this->cmTargetPropCommandBase::PopulateTargetProperties( + scope, content, prepend, system); + } + std::string Join(const std::vector<std::string>& content) override { return cmJoin(content, ";"); } + enum class IsInterface + { + Yes, + No, + }; + enum class CheckCMP0076 + { + Yes, + No, + }; std::vector<std::string> ConvertToAbsoluteContent( cmTarget* tgt, const std::vector<std::string>& content, - bool isInterfaceContent); + IsInterface isInterfaceContent, CheckCMP0076 checkCmp0076); + + bool HandleFileSetMode(const std::string& scope, + const std::vector<std::string>& content, bool prepend, + bool system); }; std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent( cmTarget* tgt, const std::vector<std::string>& content, - bool isInterfaceContent) + IsInterface isInterfaceContent, CheckCMP0076 checkCmp0076) { // Skip conversion in case old behavior has been explicitly requested - if (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076) == - cmPolicies::OLD) { + if (checkCmp0076 == CheckCMP0076::Yes && + this->Makefile->GetPolicyStatus(cmPolicies::CMP0076) == + cmPolicies::OLD) { return content; } @@ -76,7 +127,7 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent( std::string absoluteSrc; if (cmSystemTools::FileIsFullPath(src) || cmGeneratorExpression::Find(src) == 0 || - (!isInterfaceContent && + (isInterfaceContent == IsInterface::No && (this->Makefile->GetCurrentSourceDirectory() == tgt->GetMakefile()->GetCurrentSourceDirectory()))) { absoluteSrc = src; @@ -95,28 +146,33 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent( bool issueMessage = true; bool useAbsoluteContent = false; std::ostringstream e; - switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076)) { - case cmPolicies::WARN: - e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0076) << "\n"; - break; - case cmPolicies::OLD: - issueMessage = false; - break; - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::REQUIRED_IF_USED: - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0076)); - break; - case cmPolicies::NEW: { - issueMessage = false; - useAbsoluteContent = true; - break; + if (checkCmp0076 == CheckCMP0076::Yes) { + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0076)) { + case cmPolicies::WARN: + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0076) << "\n"; + break; + case cmPolicies::OLD: + issueMessage = false; + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0076)); + break; + case cmPolicies::NEW: { + issueMessage = false; + useAbsoluteContent = true; + break; + } } + } else { + issueMessage = false; + useAbsoluteContent = true; } if (issueMessage) { - if (isInterfaceContent) { + if (isInterfaceContent == IsInterface::Yes) { e << "An interface source of target \"" << tgt->GetName() << "\" has a relative path."; } else { @@ -129,6 +185,138 @@ std::vector<std::string> TargetSourcesImpl::ConvertToAbsoluteContent( return useAbsoluteContent ? absoluteContent : content; } +bool TargetSourcesImpl::HandleFileSetMode( + const std::string& scope, const std::vector<std::string>& content, + bool /*prepend*/, bool /*system*/) +{ + std::vector<std::string> unparsed; + auto args = FileSetArgsParser.Parse(content, &unparsed); + + if (!unparsed.empty()) { + this->SetError( + cmStrCat("Unrecognized keyword: \"", unparsed.front(), "\"")); + return false; + } + + if (args.FileSet.empty()) { + this->SetError("FILE_SET must not be empty"); + return false; + } + + if (this->Target->GetType() == cmStateEnums::UTILITY) { + this->SetError("FILE_SETs may not be added to custom targets"); + return false; + } + + bool const isDefault = args.Type == args.FileSet || + (args.Type.empty() && args.FileSet[0] >= 'A' && args.FileSet[0] <= 'Z'); + std::string type = isDefault ? args.FileSet : args.Type; + + auto fileSet = this->Target->GetOrCreateFileSet(args.FileSet, type); + if (fileSet.second) { + if (!isDefault) { + if (args.FileSet[0] >= 'A' && args.FileSet[0] <= 'Z') { + this->SetError( + "Non-default file set name must not start with a capital letter"); + return false; + } + } + if (type.empty()) { + this->SetError("Must specify a TYPE when creating file set"); + return false; + } + if (type != "HEADERS"_s) { + this->SetError("File set TYPE may only be \"HEADERS\""); + return false; + } + + if (args.BaseDirs.empty()) { + args.BaseDirs.emplace_back(this->Makefile->GetCurrentSourceDirectory()); + } + + if (scope == "PRIVATE"_s || scope == "PUBLIC"_s) { + this->Target->AppendProperty(cmTarget::GetFileSetsPropertyName(type), + args.FileSet); + } + if (scope == "INTERFACE"_s || scope == "PUBLIC"_s) { + this->Target->AppendProperty( + cmTarget::GetInterfaceFileSetsPropertyName(type), args.FileSet); + } + } else { + type = fileSet.first->GetType(); + if (!args.Type.empty() && args.Type != type) { + this->SetError(cmStrCat( + "Type \"", args.Type, "\" for file set \"", fileSet.first->GetName(), + "\" does not match original type \"", type, "\"")); + return false; + } + + std::string existingScope = "PRIVATE"; + + auto const fileSetsProperty = cmTarget::GetFileSetsPropertyName(type); + auto const interfaceFileSetsProperty = + cmTarget::GetInterfaceFileSetsPropertyName(type); + std::vector<std::string> fileSets; + std::vector<std::string> interfaceFileSets; + cmExpandList(this->Target->GetSafeProperty(fileSetsProperty), fileSets); + cmExpandList(this->Target->GetSafeProperty(interfaceFileSetsProperty), + interfaceFileSets); + + if (std::find(interfaceFileSets.begin(), interfaceFileSets.end(), + args.FileSet) != interfaceFileSets.end()) { + existingScope = "INTERFACE"; + } + if (std::find(fileSets.begin(), fileSets.end(), args.FileSet) != + fileSets.end()) { + if (existingScope == "INTERFACE"_s) { + existingScope = "PUBLIC"; + } + } else if (existingScope != "INTERFACE"_s) { + this->SetError(cmStrCat("File set \"", args.FileSet, "\" is not in ", + fileSetsProperty, " or ", + interfaceFileSetsProperty)); + return false; + } + + if (scope != existingScope) { + this->SetError( + cmStrCat("Scope ", scope, " for file set \"", args.FileSet, + "\" does not match original scope ", existingScope)); + return false; + } + } + + auto files = this->Join(this->ConvertToAbsoluteContent( + this->Target, args.Files, IsInterface::Yes, CheckCMP0076::No)); + if (!files.empty()) { + fileSet.first->AddFileEntry( + BT<std::string>(files, this->Makefile->GetBacktrace())); + } + + auto baseDirectories = this->Join(this->ConvertToAbsoluteContent( + this->Target, args.BaseDirs, IsInterface::Yes, CheckCMP0076::No)); + if (!baseDirectories.empty()) { + fileSet.first->AddDirectoryEntry( + BT<std::string>(baseDirectories, this->Makefile->GetBacktrace())); + if (type == "HEADERS"_s) { + for (auto const& dir : cmExpandedList(baseDirectories)) { + auto interfaceDirectoriesGenex = + cmStrCat("$<BUILD_INTERFACE:", dir, ">"); + if (scope == "PRIVATE"_s || scope == "PUBLIC"_s) { + this->Target->AppendProperty("INCLUDE_DIRECTORIES", + interfaceDirectoriesGenex); + } + if (scope == "INTERFACE"_s || scope == "PUBLIC"_s) { + this->Target->AppendProperty("INTERFACE_INCLUDE_DIRECTORIES", + interfaceDirectoriesGenex); + } + } + } + } + + return true; +} + } // namespace bool cmTargetSourcesCommand(std::vector<std::string> const& args, diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 3826577..e2b6c20 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -17,18 +17,27 @@ #include <cstdlib> #include <cstring> #include <sstream> +#include <utility> #ifdef __MINGW32__ # include <libloaderapi.h> #endif +#include <cm3p/uv.h> + #include "cmStringAlgorithms.h" #include "cmSystemTools.h" std::string cmTimestamp::CurrentTime(const std::string& formatString, bool utcFlag) const { - time_t currentTimeT = time(nullptr); + // get current time with microsecond resolution + uv_timeval64_t timeval; + uv_gettimeofday(&timeval); + auto currentTimeT = static_cast<time_t>(timeval.tv_sec); + auto microseconds = static_cast<uint32_t>(timeval.tv_usec); + + // check for override via SOURCE_DATE_EPOCH for reproducible builds std::string source_date_epoch; cmSystemTools::GetEnv("SOURCE_DATE_EPOCH", source_date_epoch); if (!source_date_epoch.empty()) { @@ -38,12 +47,15 @@ std::string cmTimestamp::CurrentTime(const std::string& formatString, cmSystemTools::Error("Cannot parse SOURCE_DATE_EPOCH as integer"); exit(27); } + // SOURCE_DATE_EPOCH has only a resolution in the seconds range + microseconds = 0; } if (currentTimeT == time_t(-1)) { return std::string(); } - return this->CreateTimestampFromTimeT(currentTimeT, formatString, utcFlag); + return this->CreateTimestampFromTimeT(currentTimeT, microseconds, + formatString, utcFlag); } std::string cmTimestamp::FileModificationTime(const char* path, @@ -57,11 +69,32 @@ std::string cmTimestamp::FileModificationTime(const char* path, return std::string(); } - time_t mtime = cmsys::SystemTools::ModifiedTime(real_path); - return this->CreateTimestampFromTimeT(mtime, formatString, utcFlag); + // use libuv's implementation of stat(2) to get the file information + time_t mtime = 0; + uint32_t microseconds = 0; + uv_fs_t req; + if (uv_fs_stat(nullptr, &req, real_path.c_str(), nullptr) == 0) { + mtime = static_cast<time_t>(req.statbuf.st_mtim.tv_sec); + // tv_nsec has nanosecond resolution, but we truncate it to microsecond + // resolution in order to be consistent with cmTimestamp::CurrentTime() + microseconds = static_cast<uint32_t>(req.statbuf.st_mtim.tv_nsec / 1000); + } + uv_fs_req_cleanup(&req); + + return this->CreateTimestampFromTimeT(mtime, microseconds, formatString, + utcFlag); +} + +std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, + std::string formatString, + bool utcFlag) const +{ + return this->CreateTimestampFromTimeT(timeT, 0, std::move(formatString), + utcFlag); } std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, + const uint32_t microseconds, std::string formatString, bool utcFlag) const { @@ -95,7 +128,8 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, : static_cast<char>(0); if (c1 == '%' && c2 != 0) { - result += this->AddTimestampComponent(c2, timeStruct, timeT); + result += + this->AddTimestampComponent(c2, timeStruct, timeT, microseconds); ++i; } else { result += c1; @@ -144,9 +178,9 @@ time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const #endif } -std::string cmTimestamp::AddTimestampComponent(char flag, - struct tm& timeStruct, - const time_t timeT) const +std::string cmTimestamp::AddTimestampComponent( + char flag, struct tm& timeStruct, const time_t timeT, + const uint32_t microseconds) const { std::string formatString = cmStrCat('%', flag); @@ -180,13 +214,19 @@ std::string cmTimestamp::AddTimestampComponent(char flag, const time_t unixEpoch = this->CreateUtcTimeTFromTm(tmUnixEpoch); if (unixEpoch == -1) { cmSystemTools::Error( - "Error generating UNIX epoch in " - "STRING(TIMESTAMP ...). Please, file a bug report against CMake"); + "Error generating UNIX epoch in string(TIMESTAMP ...) or " + "file(TIMESTAMP ...). Please, file a bug report against CMake"); return std::string(); } return std::to_string(static_cast<long int>(difftime(timeT, unixEpoch))); } + case 'f': // microseconds + { + // clip number to 6 digits and pad with leading zeros + std::string microsecs = std::to_string(microseconds % 1000000); + return std::string(6 - microsecs.length(), '0') + microsecs; + } default: { return formatString; } diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h index 0e2c200..ada5006 100644 --- a/Source/cmTimestamp.h +++ b/Source/cmTimestamp.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstdint> #include <ctime> #include <string> @@ -23,9 +24,14 @@ public: std::string CreateTimestampFromTimeT(time_t timeT, std::string formatString, bool utcFlag) const; + std::string CreateTimestampFromTimeT(time_t timeT, uint32_t microseconds, + std::string formatString, + bool utcFlag) const; + private: time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const; std::string AddTimestampComponent(char flag, struct tm& timeStruct, - time_t timeT) const; + time_t timeT, + uint32_t microseconds = 0) const; }; diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx index 4032596..81a6507 100644 --- a/Source/cmTransformDepfile.cxx +++ b/Source/cmTransformDepfile.cxx @@ -4,7 +4,6 @@ #include <algorithm> #include <functional> -#include <memory> #include <string> #include <type_traits> #include <utility> @@ -95,14 +94,16 @@ void WriteMSBuildAdditionalInputs(cmsys::ofstream& fout, // Write the format expected by MSBuild CustomBuild AdditionalInputs. const char* sep = ""; - for (std::string path : content.front().paths) { - if (!cmSystemTools::FileIsFullPath(path)) { - path = - cmSystemTools::CollapseFullPath(path, lg.GetCurrentBinaryDirectory()); + for (const auto& c : content) { + for (std::string path : c.paths) { + if (!cmSystemTools::FileIsFullPath(path)) { + path = cmSystemTools::CollapseFullPath(path, + lg.GetCurrentBinaryDirectory()); + } + std::replace(path.begin(), path.end(), '/', '\\'); + fout << sep << path; + sep = ";"; } - std::replace(path.begin(), path.end(), '/', '\\'); - fout << sep << path; - sep = ";"; } fout << "\n"; } diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index cc9e158..cd468b9 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -211,7 +211,7 @@ void cmTryRunCommand::RunExecutable(const std::string& runArgs, char retChar[16]; const char* retStr; if (worked) { - sprintf(retChar, "%i", retVal); + snprintf(retChar, sizeof(retChar), "%i", retVal); retStr = retChar; } else { retStr = "FAILED_TO_RUN"; diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 969a2c2..cbd241b 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVSSetupHelper.h" +#include <utility> + #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" @@ -46,17 +48,36 @@ const CLSID CLSID_SetupConfiguration = { /* clang-format on */ #endif +namespace { const WCHAR* Win10SDKComponent = L"Microsoft.VisualStudio.Component.Windows10SDK"; const WCHAR* Win81SDKComponent = L"Microsoft.VisualStudio.Component.Windows81SDK"; const WCHAR* ComponentType = L"Component"; +bool LoadVSInstanceVCToolsetVersion(VSInstanceInfo& vsInstanceInfo) +{ + std::string const vcRoot = vsInstanceInfo.GetInstallLocation(); + std::string vcToolsVersionFile = + vcRoot + "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt"; + std::string vcToolsVersion; + cmsys::ifstream fin(vcToolsVersionFile.c_str()); + if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) { + return false; + } + vcToolsVersion = cmTrimWhitespace(vcToolsVersion); + std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion; + if (!cmSystemTools::FileIsDirectory(vcToolsDir)) { + return false; + } + vsInstanceInfo.VCToolsetVersion = vcToolsVersion; + return true; +} +} + std::string VSInstanceInfo::GetInstallLocation() const { - std::string loc = cmsys::Encoding::ToNarrow(this->VSInstallLocation); - cmSystemTools::ConvertToUnixSlashes(loc); - return loc; + return this->VSInstallLocation; } cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version) @@ -83,10 +104,12 @@ cmVSSetupAPIHelper::~cmVSSetupAPIHelper() CoUninitialize(); } -bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation) +bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation, + std::string const& vsInstallVersion) { this->SpecifiedVSInstallLocation = vsInstallLocation; cmSystemTools::ConvertToUnixSlashes(this->SpecifiedVSInstallLocation); + this->SpecifiedVSInstallVersion = vsInstallVersion; chosenInstanceInfo = VSInstanceInfo(); return this->EnumerateAndChooseVSInstance(); } @@ -152,29 +175,17 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( if (pInstance == NULL) return false; - SmartBSTR bstrId; - if (SUCCEEDED(pInstance->GetInstanceId(&bstrId))) { - vsInstanceInfo.InstanceId = std::wstring(bstrId); - } else { - return false; - } - InstanceState state; if (FAILED(pInstance->GetState(&state))) { return false; } - ULONGLONG ullVersion = 0; SmartBSTR bstrVersion; if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) { return false; } else { - vsInstanceInfo.Version = std::wstring(bstrVersion); - if (FAILED(setupHelper->ParseVersion(bstrVersion, &ullVersion))) { - vsInstanceInfo.ullVersion = 0; - } else { - vsInstanceInfo.ullVersion = ullVersion; - } + vsInstanceInfo.Version = + cmsys::Encoding::ToNarrow(std::wstring(bstrVersion)); } // Reboot may have been required before the installation path was created. @@ -183,26 +194,15 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( if (FAILED(pInstance->GetInstallationPath(&bstrInstallationPath))) { return false; } else { - vsInstanceInfo.VSInstallLocation = std::wstring(bstrInstallationPath); + vsInstanceInfo.VSInstallLocation = + cmsys::Encoding::ToNarrow(std::wstring(bstrInstallationPath)); + cmSystemTools::ConvertToUnixSlashes(vsInstanceInfo.VSInstallLocation); } } // Check if a compiler is installed with this instance. - { - std::string const vcRoot = vsInstanceInfo.GetInstallLocation(); - std::string vcToolsVersionFile = - vcRoot + "/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt"; - std::string vcToolsVersion; - cmsys::ifstream fin(vcToolsVersionFile.c_str()); - if (!fin || !cmSystemTools::GetLineFromStream(fin, vcToolsVersion)) { - return false; - } - vcToolsVersion = cmTrimWhitespace(vcToolsVersion); - std::string const vcToolsDir = vcRoot + "/VC/Tools/MSVC/" + vcToolsVersion; - if (!cmSystemTools::FileIsDirectory(vcToolsDir)) { - return false; - } - vsInstanceInfo.VCToolsetVersion = vcToolsVersion; + if (!LoadVSInstanceVCToolsetVersion(vsInstanceInfo)) { + return false; } // Reboot may have been required before the product package was registered @@ -264,7 +264,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceVersion(std::string& vsInstanceVersion) bool isInstalled = this->EnumerateAndChooseVSInstance(); if (isInstalled) { - vsInstanceVersion = cmsys::Encoding::ToNarrow(chosenInstanceInfo.Version); + vsInstanceVersion = chosenInstanceInfo.Version; } return isInstalled; @@ -298,7 +298,7 @@ bool cmVSSetupAPIHelper::IsEWDKEnabled() bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() { bool isVSInstanceExists = false; - if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + if (chosenInstanceInfo.VSInstallLocation.compare("") != 0) { return true; } @@ -311,12 +311,11 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() if (envVSVersion.empty() || envVsInstallDir.empty()) return false; - chosenInstanceInfo.VSInstallLocation = - std::wstring(envVsInstallDir.begin(), envVsInstallDir.end()); - chosenInstanceInfo.Version = - std::wstring(envVSVersion.begin(), envVSVersion.end()); - chosenInstanceInfo.VCToolsetVersion = envVSVersion; - chosenInstanceInfo.ullVersion = std::stoi(envVSVersion); + chosenInstanceInfo.VSInstallLocation = envVsInstallDir; + chosenInstanceInfo.Version = envVSVersion; + if (!LoadVSInstanceVCToolsetVersion(chosenInstanceInfo)) { + return false; + } chosenInstanceInfo.IsWin10SDKInstalled = true; chosenInstanceInfo.IsWin81SDKInstalled = !envWindowsSdkDir81.empty(); return true; @@ -343,7 +342,9 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() return false; } - std::wstring const wantVersion = std::to_wstring(this->Version) + L'.'; + std::string const wantVersion = std::to_string(this->Version) + '.'; + + bool specifiedLocationNotSpecifiedVersion = false; SmartCOMPtr<ISetupInstance> instance; while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { @@ -371,6 +372,16 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() std::string currentVSLocation = instanceInfo.GetInstallLocation(); if (cmSystemTools::ComparePath(currentVSLocation, this->SpecifiedVSInstallLocation)) { + if (this->SpecifiedVSInstallVersion.empty() || + instanceInfo.Version == this->SpecifiedVSInstallVersion) { + chosenInstanceInfo = instanceInfo; + return true; + } + specifiedLocationNotSpecifiedVersion = true; + } + } else if (!this->SpecifiedVSInstallVersion.empty()) { + // We are looking for a specific version. + if (instanceInfo.Version == this->SpecifiedVSInstallVersion) { chosenInstanceInfo = instanceInfo; return true; } @@ -392,6 +403,13 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() } } + if (!this->SpecifiedVSInstallLocation.empty() && + !specifiedLocationNotSpecifiedVersion) { + // The VS Installer does not know about the specified location. + // Check for one directly on disk. + return this->LoadSpecifiedVSInstanceFromDisk(); + } + if (vecVSInstances.size() > 0) { isVSInstanceExists = true; int index = ChooseVSInstance(vecVSInstances); @@ -454,6 +472,32 @@ int cmVSSetupAPIHelper::ChooseVSInstance( return chosenIndex; } +bool cmVSSetupAPIHelper::LoadSpecifiedVSInstanceFromDisk() +{ + if (!cmSystemTools::FileIsDirectory(this->SpecifiedVSInstallLocation)) { + return false; + } + VSInstanceInfo vsInstanceInfo; + vsInstanceInfo.VSInstallLocation = this->SpecifiedVSInstallLocation; + // FIXME: Is there a better way to get SDK information? + vsInstanceInfo.IsWin10SDKInstalled = true; + vsInstanceInfo.IsWin81SDKInstalled = false; + + if (!this->SpecifiedVSInstallVersion.empty()) { + // Assume the version specified by the user is correct. + vsInstanceInfo.Version = this->SpecifiedVSInstallVersion; + } else { + return false; + } + + if (!LoadVSInstanceVCToolsetVersion(vsInstanceInfo)) { + return false; + } + + chosenInstanceInfo = std::move(vsInstanceInfo); + return true; +} + bool cmVSSetupAPIHelper::Initialize() { if (initializationFailure) diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index 61a3ac7..44c883b 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -84,11 +84,9 @@ private: struct VSInstanceInfo { - std::wstring InstanceId; - std::wstring VSInstallLocation; - std::wstring Version; + std::string VSInstallLocation; + std::string Version; std::string VCToolsetVersion; - ULONGLONG ullVersion = 0; // A.B.C.D = (A<<48)|(B<<32)|(C<<16)|D bool IsWin10SDKInstalled = false; bool IsWin81SDKInstalled = false; @@ -101,7 +99,8 @@ public: cmVSSetupAPIHelper(unsigned int version); ~cmVSSetupAPIHelper(); - bool SetVSInstance(std::string const& vsInstallLocation); + bool SetVSInstance(std::string const& vsInstallLocation, + std::string const& vsInstallVersion); bool IsVSInstalled(); bool GetVSInstanceInfo(std::string& vsInstallLocation); @@ -118,6 +117,7 @@ private: bool& bWin10SDK, bool& bWin81SDK); int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances); bool EnumerateAndChooseVSInstance(); + bool LoadSpecifiedVSInstanceFromDisk(); unsigned int Version; @@ -134,4 +134,5 @@ private: bool IsEWDKEnabled(); std::string SpecifiedVSInstallLocation; + std::string SpecifiedVSInstallVersion; }; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index a871e4c..8ffb664 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2,8 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVisualStudio10TargetGenerator.h" +#include <algorithm> +#include <cstdio> +#include <cstring> #include <iterator> #include <set> +#include <sstream> #include <cm/memory> #include <cm/optional> @@ -13,22 +17,41 @@ #include "windows.h" +#include "cmsys/FStream.hxx" +#include "cmsys/RegularExpression.hxx" + #include "cmComputeLinkInformation.h" #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmGlobalVisualStudio10Generator.h" -#include "cmGlobalVisualStudioVersionedGenerator.h" +#include "cmGlobalVisualStudio7Generator.h" +#include "cmGlobalVisualStudioGenerator.h" #include "cmLinkLineDeviceComputer.h" +#include "cmListFileCache.h" +#include "cmLocalGenerator.h" #include "cmLocalVisualStudio10Generator.h" +#include "cmLocalVisualStudio7Generator.h" +#include "cmLocalVisualStudioGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmPropertyMap.h" #include "cmSourceFile.h" +#include "cmSourceFileLocation.h" +#include "cmSourceFileLocationKind.h" +#include "cmSourceGroup.h" +#include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmValue.h" #include "cmVisualStudioGeneratorOptions.h" +struct cmIDEFlagTable; + static void ConvertToWindowsSlash(std::string& s); static std::string cmVS10EscapeXML(std::string arg) @@ -212,14 +235,27 @@ static bool cmVS10IsTargetsFile(std::string const& path) return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0; } -static std::string computeProjectFileExtension(cmGeneratorTarget const* t) +static VsProjectType computeProjectType(cmGeneratorTarget const* t) { - std::string res; - res = ".vcxproj"; if (t->IsCSharpOnly()) { - res = ".csproj"; + return VsProjectType::csproj; + } + return VsProjectType::vcxproj; +} + +static std::string computeProjectFileExtension(VsProjectType projectType) +{ + switch (projectType) { + case VsProjectType::csproj: + return ".csproj"; + default: + return ".vcxproj"; } - return res; +} + +static std::string computeProjectFileExtension(cmGeneratorTarget const* t) +{ + return computeProjectFileExtension(computeProjectType(t)); } cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( @@ -267,7 +303,8 @@ std::string cmVisualStudio10TargetGenerator::CalcCondition( oss << config << "|" << this->Platform; oss << "'"; // handle special case for 32 bit C# targets - if (this->ProjectType == csproj && this->Platform == "Win32") { + if (this->ProjectType == VsProjectType::csproj && + this->Platform == "Win32") { oss << " Or "; oss << "'$(Configuration)|$(Platform)'=='"; oss << config << "|x86"; @@ -315,21 +352,18 @@ std::ostream& cmVisualStudio10TargetGenerator::Elem::WriteString( void cmVisualStudio10TargetGenerator::Generate() { + this->ProjectType = computeProjectType(this->GeneratorTarget); + this->Managed = this->ProjectType == VsProjectType::csproj; const std::string ProjectFileExtension = - computeProjectFileExtension(this->GeneratorTarget); - if (ProjectFileExtension == ".vcxproj") { - this->ProjectType = vcxproj; - this->Managed = false; - } else if (ProjectFileExtension == ".csproj") { - if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { - std::string message = "The C# target \"" + - this->GeneratorTarget->GetName() + - "\" is of type STATIC_LIBRARY. This is discouraged (and may be " - "disabled in future). Make it a SHARED library instead."; - this->Makefile->IssueMessage(MessageType::DEPRECATION_WARNING, message); - } - this->ProjectType = csproj; - this->Managed = true; + computeProjectFileExtension(this->ProjectType); + + if (this->ProjectType == VsProjectType::csproj && + this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { + std::string message = "The C# target \"" + + this->GeneratorTarget->GetName() + + "\" is of type STATIC_LIBRARY. This is discouraged (and may be " + "disabled in future). Make it a SHARED library instead."; + this->Makefile->IssueMessage(MessageType::DEPRECATION_WARNING, message); } if (this->Android && @@ -381,6 +415,30 @@ void cmVisualStudio10TargetGenerator::Generate() // Write the encoding header into the file char magic[] = { char(0xEF), char(0xBB), char(0xBF) }; BuildFileStream.write(magic, 3); + + if (this->ProjectType == VsProjectType::csproj && + this->GeneratorTarget->IsDotNetSdkTarget() && + this->GlobalGenerator->GetVersion() >= + cmGlobalVisualStudioGenerator::VSVersion::VS16) { + this->WriteSdkStyleProjectFile(BuildFileStream); + } else { + this->WriteClassicMsBuildProjectFile(BuildFileStream); + } + + if (BuildFileStream.Close()) { + this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile); + } + + // The groups are stored in a separate file for VS 10 + this->WriteGroups(); + + // Update cache with project-specific entries. + this->UpdateCache(); +} + +void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( + cmGeneratedFileStream& BuildFileStream) +{ BuildFileStream << "<?xml version=\"1.0\" encoding=\"" << this->GlobalGenerator->Encoding() << "\"?>"; { @@ -388,7 +446,7 @@ void cmVisualStudio10TargetGenerator::Generate() e0.Attribute("DefaultTargets", "Build"); const char* toolsVersion = this->GlobalGenerator->GetToolsVersion(); if (this->GlobalGenerator->GetVersion() == - cmGlobalVisualStudioGenerator::VS12 && + cmGlobalVisualStudioGenerator::VSVersion::VS12 && this->GlobalGenerator->TargetsWindowsCE()) { toolsVersion = "4.0"; } @@ -423,14 +481,27 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Element("PreferredToolArchitecture", hostArch); } - if (this->ProjectType != csproj) { + // ALL_BUILD and ZERO_CHECK projects transitively include + // Microsoft.Common.CurrentVersion.targets which triggers Target + // ResolveNugetPackageAssets when SDK-style targets are in the project. + // However, these projects have no nuget packages to reference and the + // build fails. + // Setting ResolveNugetPackages to false skips this target and the build + // succeeds. + cm::string_view targetName{ this->GeneratorTarget->GetName() }; + if (targetName == "ALL_BUILD" || + targetName == CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + Elem e1(e0, "PropertyGroup"); + e1.Element("ResolveNugetPackages", "false"); + } + + if (this->ProjectType != VsProjectType::csproj) { this->WriteProjectConfigurations(e0); } { Elem e1(e0, "PropertyGroup"); - e1.Attribute("Label", "Globals"); - e1.Element("ProjectGuid", "{" + this->GUID + "}"); + this->WriteCommonPropertyGroupGlobals(e1); if ((this->MSTools || this->Android) && this->GeneratorTarget->IsInBuildSystem()) { @@ -438,16 +509,6 @@ void cmVisualStudio10TargetGenerator::Generate() this->VerifyNecessaryFiles(); } - cmValue vsProjectTypes = - this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES"); - if (vsProjectTypes) { - const char* tagName = "ProjectTypes"; - if (this->ProjectType == csproj) { - tagName = "ProjectTypeGuids"; - } - e1.Element(tagName, *vsProjectTypes); - } - cmValue vsProjectName = this->GeneratorTarget->GetProperty("VS_SCC_PROJECTNAME"); cmValue vsLocalPath = @@ -471,24 +532,6 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Element("WinMDAssembly", "true"); } - cmValue vsGlobalKeyword = - this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD"); - if (!vsGlobalKeyword) { - if (this->GlobalGenerator->TargetsAndroid()) { - e1.Element("Keyword", "Android"); - } else { - e1.Element("Keyword", "Win32Proj"); - } - } else { - e1.Element("Keyword", *vsGlobalKeyword); - } - - cmValue vsGlobalRootNamespace = - this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"); - if (vsGlobalRootNamespace) { - e1.Element("RootNamespace", *vsGlobalRootNamespace); - } - e1.Element("Platform", this->Platform); cmValue projLabel = this->GeneratorTarget->GetProperty("PROJECT_LABEL"); e1.Element("ProjectName", projLabel ? projLabel : this->Name); @@ -507,16 +550,16 @@ void cmVisualStudio10TargetGenerator::Generate() } else if (cmValue tfVer = this->GeneratorTarget->GetProperty( "DOTNET_TARGET_FRAMEWORK_VERSION")) { targetFrameworkVersion = *tfVer; - } else if (this->ProjectType == csproj) { + } else if (this->ProjectType == VsProjectType::csproj) { targetFrameworkVersion = this->GlobalGenerator->GetTargetFrameworkVersion(); } - if (this->ProjectType == vcxproj && + if (this->ProjectType == VsProjectType::vcxproj && this->GlobalGenerator->TargetsWindowsCE()) { e1.Element("EnableRedirectPlatform", "true"); e1.Element("RedirectPlatformValue", this->Platform); } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { if (this->GlobalGenerator->TargetsWindowsCE()) { // FIXME: These target VS_TARGET_FRAMEWORK* target properties // are undocumented settings only ever supported for WinCE. @@ -569,7 +612,7 @@ void cmVisualStudio10TargetGenerator::Generate() // project using an older toolset version is opened in a newer version of // the IDE (respected by VS 2013 and above). if (this->GlobalGenerator->GetVersion() >= - cmGlobalVisualStudioGenerator::VS12) { + cmGlobalVisualStudioGenerator::VSVersion::VS12) { e1.Element("VCProjectUpgraderObjectName", "NoUpgrade"); } @@ -578,27 +621,9 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Element("VCTargetsPath", vcTargetsPath); } - std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); - for (std::string const& keyIt : keys) { - static const cm::string_view prefix = "VS_GLOBAL_"; - if (!cmHasPrefix(keyIt, prefix)) - continue; - cm::string_view globalKey = - cm::string_view(keyIt).substr(prefix.length()); - // Skip invalid or separately-handled properties. - if (globalKey.empty() || globalKey == "PROJECT_TYPES" || - globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") { - continue; - } - cmValue value = this->GeneratorTarget->GetProperty(keyIt); - if (!value) - continue; - e1.Element(globalKey, *value); - } - if (this->Managed) { if (this->LocalGenerator->GetVersion() >= - cmGlobalVisualStudioGenerator::VS17) { + cmGlobalVisualStudioGenerator::VSVersion::VS17) { e1.Element("ManagedAssembly", "true"); } std::string outputType; @@ -643,7 +668,7 @@ void cmVisualStudio10TargetGenerator::Generate() } switch (this->ProjectType) { - case vcxproj: { + case VsProjectType::vcxproj: { std::string const& props = this->GlobalGenerator->GetPlatformToolsetVersionProps(); if (!props.empty()) { @@ -651,7 +676,7 @@ void cmVisualStudio10TargetGenerator::Generate() } Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS); } break; - case csproj: + case VsProjectType::csproj: Elem(e0, "Import") .Attribute("Project", VS10_CSharp_DEFAULT_PROPS) .Attribute("Condition", "Exists('" VS10_CSharp_DEFAULT_PROPS "')"); @@ -660,7 +685,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteProjectConfigurationValues(e0); - if (this->ProjectType == vcxproj) { + if (this->ProjectType == VsProjectType::vcxproj) { Elem(e0, "Import").Attribute("Project", VS10_CXX_PROPS); } { @@ -706,10 +731,10 @@ void cmVisualStudio10TargetGenerator::Generate() e1.Attribute("Label", "PropertySheets"); std::string props; switch (this->ProjectType) { - case vcxproj: + case VsProjectType::vcxproj: props = VS10_CXX_USER_PROPS; break; - case csproj: + case VsProjectType::csproj: props = VS10_CSharp_USER_PROPS; break; } @@ -744,10 +769,10 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteProjectReferences(e0); this->WriteSDKReferences(e0); switch (this->ProjectType) { - case vcxproj: + case VsProjectType::vcxproj: Elem(e0, "Import").Attribute("Project", VS10_CXX_TARGETS); break; - case csproj: + case VsProjectType::csproj: if (this->GlobalGenerator->TargetsWindowsCE()) { Elem(e0, "Import").Attribute("Project", VS10_CSharp_NETCF_TARGETS); } else { @@ -788,12 +813,13 @@ void cmVisualStudio10TargetGenerator::Generate() Elem(e1, "Import").Attribute("Project", nasmTargets); } } - if (this->ProjectType == vcxproj && this->HaveCustomCommandDepfile) { + if (this->ProjectType == VsProjectType::vcxproj && + this->HaveCustomCommandDepfile) { std::string depfileTargets = GetCMakeFilePath("Templates/MSBuild/CustomBuildDepFile.targets"); Elem(e0, "Import").Attribute("Project", depfileTargets); } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { for (std::string const& c : this->Configurations) { Elem e1(e0, "PropertyGroup"); e1.Attribute("Condition", "'$(Configuration)' == '" + c + "'"); @@ -814,22 +840,184 @@ void cmVisualStudio10TargetGenerator::Generate() } } } +} - if (BuildFileStream.Close()) { - this->GlobalGenerator->FileReplacedDuringGenerate(PathToProjectFile); +void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile( + cmGeneratedFileStream& BuildFileStream) +{ + if (this->ProjectType != VsProjectType::csproj || + !this->GeneratorTarget->IsDotNetSdkTarget()) { + std::string message = "The target \"" + this->GeneratorTarget->GetName() + + "\" is not eligible for .Net SDK style project."; + this->Makefile->IssueMessage(MessageType::INTERNAL_ERROR, message); + return; } - // The groups are stored in a separate file for VS 10 - this->WriteGroups(); + if (this->HasCustomCommands()) { + std::string message = "The target \"" + this->GeneratorTarget->GetName() + + "\" does not currently support add_custom_command as the Visual Studio " + "generators have not yet learned how to generate custom commands in " + ".Net SDK-style projects."; + this->Makefile->IssueMessage(MessageType::FATAL_ERROR, message); + return; + } + + Elem e0(BuildFileStream, "Project"); + e0.Attribute("Sdk", *this->GeneratorTarget->GetProperty("DOTNET_SDK")); + + { + Elem e1(e0, "PropertyGroup"); + this->WriteCommonPropertyGroupGlobals(e1); + + e1.Element("EnableDefaultItems", "false"); + // Disable the project upgrade prompt that is displayed the first time a + // project using an older toolset version is opened in a newer version + // of the IDE. + e1.Element("VCProjectUpgraderObjectName", "NoUpgrade"); + e1.Element("ManagedAssembly", "true"); + + cmValue targetFramework = + this->GeneratorTarget->GetProperty("DOTNET_TARGET_FRAMEWORK"); + if (targetFramework) { + if (targetFramework->find(';') != std::string::npos) { + e1.Element("TargetFrameworks", *targetFramework); + } else { + e1.Element("TargetFramework", *targetFramework); + } + } else { + e1.Element("TargetFramework", "net5.0"); + } + + std::string outputType; + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::OBJECT_LIBRARY: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Target \"", this->GeneratorTarget->GetName(), + "\" is of a type not supported for managed binaries.")); + return; + case cmStateEnums::SHARED_LIBRARY: + outputType = "Library"; + break; + case cmStateEnums::EXECUTABLE: { + auto const win32 = + this->GeneratorTarget->GetSafeProperty("WIN32_EXECUTABLE"); + if (win32.find("$<") != std::string::npos) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Target \"", this->GeneratorTarget->GetName(), + "\" has a generator expression in its WIN32_EXECUTABLE " + "property. This is not supported on managed " + "executables.")); + return; + } + outputType = "Exe"; + } break; + case cmStateEnums::UTILITY: + case cmStateEnums::INTERFACE_LIBRARY: + case cmStateEnums::GLOBAL_TARGET: + outputType = "Utility"; + break; + case cmStateEnums::UNKNOWN_LIBRARY: + break; + } + e1.Element("OutputType", outputType); + } + + for (const std::string& config : this->Configurations) { + Elem e1(e0, "PropertyGroup"); + e1.Attribute("Condition", "'$(Configuration)' == '" + config + "'"); + e1.SetHasElements(); + this->WriteEvents(e1, config); + + std::string outDir = this->GeneratorTarget->GetDirectory(config) + "/"; + ConvertToWindowsSlash(outDir); + e1.Element("OutputPath", outDir); + } + + this->WriteDotNetDocumentationFile(e0); + this->WriteAllSources(e0); + this->WriteDotNetReferences(e0); + this->WritePackageReferences(e0); + this->WriteProjectReferences(e0); } -void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0) +void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1) { - std::vector<std::string> packageReferences; - if (cmValue vsPackageReferences = - this->GeneratorTarget->GetProperty("VS_PACKAGE_REFERENCES")) { - cmExpandList(*vsPackageReferences, packageReferences); + e1.Attribute("Label", "Globals"); + e1.Element("ProjectGuid", "{" + this->GUID + "}"); + + cmValue vsProjectTypes = + this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES"); + if (vsProjectTypes) { + const char* tagName = "ProjectTypes"; + if (this->ProjectType == VsProjectType::csproj) { + tagName = "ProjectTypeGuids"; + } + e1.Element(tagName, *vsProjectTypes); } + + cmValue vsGlobalKeyword = + this->GeneratorTarget->GetProperty("VS_GLOBAL_KEYWORD"); + if (!vsGlobalKeyword) { + if (this->GlobalGenerator->TargetsAndroid()) { + e1.Element("Keyword", "Android"); + } else { + e1.Element("Keyword", "Win32Proj"); + } + } else { + e1.Element("Keyword", *vsGlobalKeyword); + } + + cmValue vsGlobalRootNamespace = + this->GeneratorTarget->GetProperty("VS_GLOBAL_ROOTNAMESPACE"); + if (vsGlobalRootNamespace) { + e1.Element("RootNamespace", *vsGlobalRootNamespace); + } + + std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); + for (std::string const& keyIt : keys) { + static const cm::string_view prefix = "VS_GLOBAL_"; + if (!cmHasPrefix(keyIt, prefix)) + continue; + cm::string_view globalKey = cm::string_view(keyIt).substr(prefix.length()); + // Skip invalid or separately-handled properties. + if (globalKey.empty() || globalKey == "PROJECT_TYPES" || + globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") { + continue; + } + cmValue value = this->GeneratorTarget->GetProperty(keyIt); + if (!value) + continue; + e1.Element(globalKey, *value); + } +} + +bool cmVisualStudio10TargetGenerator::HasCustomCommands() const +{ + if (!this->GeneratorTarget->GetPreBuildCommands().empty() || + !this->GeneratorTarget->GetPreLinkCommands().empty() || + !this->GeneratorTarget->GetPostBuildCommands().empty()) { + return true; + } + + for (cmGeneratorTarget::AllConfigSource const& si : + this->GeneratorTarget->GetAllConfigSources()) { + if (si.Source->GetCustomCommand()) { + return true; + } + } + + return false; +} + +void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0) +{ + std::vector<std::string> packageReferences = + this->GeneratorTarget->GetPackageReferences(); + if (!packageReferences.empty()) { Elem e1(e0, "ItemGroup"); for (std::string const& ri : packageReferences) { @@ -959,7 +1147,8 @@ void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0) std::string const& documentationFile = this->GeneratorTarget->GetSafeProperty("VS_DOTNET_DOCUMENTATION_FILE"); - if (this->ProjectType == csproj && !documentationFile.empty()) { + if (this->ProjectType == VsProjectType::csproj && + !documentationFile.empty()) { Elem e1(e0, "PropertyGroup"); Elem e2(e1, "DocumentationFile"); e2.Content(documentationFile); @@ -976,7 +1165,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) std::string obj = oi->GetFullPath(); ConvertToWindowsSlash(obj); bool useRelativePath = false; - if (this->ProjectType == csproj && this->InSourceBuild) { + if (this->ProjectType == VsProjectType::csproj && this->InSourceBuild) { // If we do an in-source build and the resource file is in a // subdirectory // of the .csproj file, we have to use relative pathnames, otherwise @@ -990,7 +1179,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) Elem e2(e1, "EmbeddedResource"); e2.Attribute("Include", obj); - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h"; e2.Element("DependentUpon", hFileName); @@ -1161,7 +1350,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues(Elem& e0) e1.Attribute("Condition", this->CalcCondition(c)); e1.Attribute("Label", "Configuration"); - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { std::string configType; if (cmValue vsConfigurationType = this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) { @@ -1292,6 +1481,10 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( if (this->IPOEnabledConfigurations.count(config) > 0) { e1.Element("WholeProgramOptimization", "true"); } + if (this->ASanEnabledConfigurations.find(config) != + this->ASanEnabledConfigurations.end()) { + e1.Element("EnableAsan", "true"); + } { auto s = this->SpectreMitigation.find(config); if (s != this->SpectreMitigation.end()) { @@ -1470,7 +1663,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( std::unique_ptr<Elem> spe1; std::unique_ptr<Elem> spe2; - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild"); this->WriteSource(*spe2, source); @@ -1494,7 +1687,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( std::stringstream additional_inputs; { const char* sep = ""; - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { // csproj files do not attach the command to a specific file // so the primary input must be listed explicitly. additional_inputs << source->GetFullPath(); @@ -1524,7 +1717,7 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } } } - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { additional_inputs << sep << "%(AdditionalInputs)"; } } @@ -1545,7 +1738,8 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( } } } - if (this->ProjectType == csproj) { + script += lg->FinishConstructScript(this->ProjectType); + if (this->ProjectType == VsProjectType::csproj) { std::string name = "CustomCommand_" + c + "_" + cmSystemTools::ComputeStringMD5(sourcePath); this->WriteCustomRuleCSharp(e0, c, name, script, additional_inputs.str(), @@ -1569,13 +1763,13 @@ void cmVisualStudio10TargetGenerator::WriteCustomRuleCpp( e2.WritePlatformConfigTag("AdditionalInputs", cond, additional_inputs); e2.WritePlatformConfigTag("Outputs", cond, outputs); if (this->LocalGenerator->GetVersion() > - cmGlobalVisualStudioGenerator::VS10) { + cmGlobalVisualStudioGenerator::VSVersion::VS10) { // VS >= 11 let us turn off linking of custom command outputs. e2.WritePlatformConfigTag("LinkObjects", cond, "false"); } if (symbolic && this->LocalGenerator->GetVersion() >= - cmGlobalVisualStudioGenerator::VS16) { + cmGlobalVisualStudioGenerator::VSVersion::VS16) { // VS >= 16.4 warn if outputs are not created, but one of our // outputs is marked SYMBOLIC and not expected to be created. e2.WritePlatformConfigTag("VerifyInputsAndOutputsExist", cond, "false"); @@ -1636,7 +1830,7 @@ static void ConvertToWindowsSlash(std::string& s) void cmVisualStudio10TargetGenerator::WriteGroups() { - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } @@ -1901,7 +2095,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource( std::string includeInVsix; std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); - if (this->ProjectType == csproj && !this->InSourceBuild) { + if (this->ProjectType == VsProjectType::csproj && !this->InSourceBuild) { toolHasSettings = true; } if (ext == "hlsl") { @@ -2138,7 +2332,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, bool forceRelative = sf->GetLanguage() == "CUDA"; std::string sourceFile = this->ConvertPath(sf->GetFullPath(), forceRelative); if (this->LocalGenerator->GetVersion() == - cmGlobalVisualStudioGenerator::VS10 && + cmGlobalVisualStudioGenerator::VSVersion::VS10 && cmSystemTools::FileIsFullPath(sourceFile)) { // Normal path conversion resulted in a full path. VS 10 (but not 11) // refuses to show the property page in the IDE for a source file with a @@ -2162,7 +2356,7 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, ConvertToWindowsSlash(sourceFile); e2.Attribute("Include", sourceFile); - if (this->ProjectType == csproj && !this->InSourceBuild) { + if (this->ProjectType == VsProjectType::csproj && !this->InSourceBuild) { // For out of source projects we have to provide a link (if not specified // via property) for every source file (besides .cs files) otherwise they // will not be visible in VS at all. @@ -2236,7 +2430,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) case cmGeneratorTarget::SourceKindExternalObject: tool = "Object"; if (this->LocalGenerator->GetVersion() < - cmGlobalVisualStudioGenerator::VS11) { + cmGlobalVisualStudioGenerator::VSVersion::VS11) { // For VS == 10 we cannot use LinkObjects to avoid linking custom // command outputs. If an object file is generated in this target, // then vs10 will use it in the build, and we have to list it as @@ -2348,12 +2542,13 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) // Visual Studio versions prior to 2017 15.8 do not know about unity // builds, thus we exclude the files already part of unity sources. if (!si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")) { - exclude_configs = si.Configs; + exclude_configs = all_configs; } } } - if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) { + if (si.Kind == cmGeneratorTarget::SourceKindObjectSource || + si.Kind == cmGeneratorTarget::SourceKindUnityBatched) { this->OutputSourceSpecificFlags(e2, si.Source); } if (si.Source->GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS")) { @@ -2464,6 +2659,22 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( e2.Element("ObjectFileName", "$(IntDir)/" + objectName); } } + + if (lang == "ASM_NASM") { + if (cmValue objectDeps = sf.GetProperty("OBJECT_DEPENDS")) { + std::string dependencies; + std::vector<std::string> depends = cmExpandedList(*objectDeps); + const char* sep = ""; + for (std::string& d : depends) { + ConvertToWindowsSlash(d); + dependencies += sep; + dependencies += d; + sep = ";"; + } + e2.Element("AdditionalDependencies", dependencies); + } + } + for (std::string const& config : this->Configurations) { std::string configUpper = cmSystemTools::UpperCase(config); std::string configDefines = defines; @@ -2536,11 +2747,15 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( if (needsPCHFlags) { // Add precompile headers compile options. - std::string expandedOptions; - std::string pchOptions; if (makePCH) { - pchOptions = - this->GeneratorTarget->GetPchCreateCompileOptions(config, lang); + clOptions.AddFlag("PrecompiledHeader", "Create"); + std::string pchHeader = + this->GeneratorTarget->GetPchHeader(config, lang); + clOptions.AddFlag("PrecompiledHeaderFile", pchHeader); + std::string pchFile = + this->GeneratorTarget->GetPchFile(config, lang); + clOptions.AddFlag("PrecompiledHeaderOutputFile", pchFile); + clOptions.AddFlag("ForcedIncludeFiles", pchHeader); } else if (useNoPCH) { clOptions.AddFlag("PrecompiledHeader", "NotUsing"); } else if (useSharedPCH) { @@ -2548,12 +2763,15 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( this->GeneratorTarget->GetPchHeader(config, lang); clOptions.AddFlag("ForcedIncludeFiles", pchHeader); } else if (useDifferentLangPCH) { - pchOptions = - this->GeneratorTarget->GetPchUseCompileOptions(config, lang); + clOptions.AddFlag("PrecompiledHeader", "Use"); + std::string pchHeader = + this->GeneratorTarget->GetPchHeader(config, lang); + clOptions.AddFlag("PrecompiledHeaderFile", pchHeader); + std::string pchFile = + this->GeneratorTarget->GetPchFile(config, lang); + clOptions.AddFlag("PrecompiledHeaderOutputFile", pchFile); + clOptions.AddFlag("ForcedIncludeFiles", pchHeader); } - this->LocalGenerator->AppendCompileOptions(expandedOptions, - pchOptions); - clOptions.Parse(expandedOptions); } if (!options.empty()) { @@ -2603,7 +2821,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( e2.Element("DependentUpon", fileName.substr(0, fileName.find_last_of("."))); } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { std::string f = source->GetFullPath(); using CsPropMap = std::map<std::string, std::string>; CsPropMap sourceFileTags; @@ -2634,7 +2852,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( if (ttype > cmStateEnums::GLOBAL_TARGET) { return; } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } @@ -2643,40 +2861,6 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( for (std::string const& config : this->Configurations) { const std::string cond = this->CalcCondition(config); - if (ttype <= cmStateEnums::UTILITY) { - if (cmValue workingDir = this->GeneratorTarget->GetProperty( - "VS_DEBUGGER_WORKING_DIRECTORY")) { - std::string genWorkingDir = cmGeneratorExpression::Evaluate( - *workingDir, this->LocalGenerator, config); - e1.WritePlatformConfigTag("LocalDebuggerWorkingDirectory", cond, - genWorkingDir); - } - - if (cmValue environment = - this->GeneratorTarget->GetProperty("VS_DEBUGGER_ENVIRONMENT")) { - std::string genEnvironment = cmGeneratorExpression::Evaluate( - *environment, this->LocalGenerator, config); - e1.WritePlatformConfigTag("LocalDebuggerEnvironment", cond, - genEnvironment); - } - - if (cmValue debuggerCommand = - this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) { - std::string genDebuggerCommand = cmGeneratorExpression::Evaluate( - *debuggerCommand, this->LocalGenerator, config); - e1.WritePlatformConfigTag("LocalDebuggerCommand", cond, - genDebuggerCommand); - } - - if (cmValue commandArguments = this->GeneratorTarget->GetProperty( - "VS_DEBUGGER_COMMAND_ARGUMENTS")) { - std::string genCommandArguments = cmGeneratorExpression::Evaluate( - *commandArguments, this->LocalGenerator, config); - e1.WritePlatformConfigTag("LocalDebuggerCommandArguments", cond, - genCommandArguments); - } - } - if (ttype >= cmStateEnums::UTILITY) { e1.WritePlatformConfigTag( "IntDir", cond, "$(Platform)\\$(Configuration)\\$(ProjectName)\\"); @@ -2753,6 +2937,40 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( this->OutputLinkIncremental(e1, config); } + + if (ttype <= cmStateEnums::UTILITY) { + if (cmValue workingDir = this->GeneratorTarget->GetProperty( + "VS_DEBUGGER_WORKING_DIRECTORY")) { + std::string genWorkingDir = cmGeneratorExpression::Evaluate( + *workingDir, this->LocalGenerator, config); + e1.WritePlatformConfigTag("LocalDebuggerWorkingDirectory", cond, + genWorkingDir); + } + + if (cmValue environment = + this->GeneratorTarget->GetProperty("VS_DEBUGGER_ENVIRONMENT")) { + std::string genEnvironment = cmGeneratorExpression::Evaluate( + *environment, this->LocalGenerator, config); + e1.WritePlatformConfigTag("LocalDebuggerEnvironment", cond, + genEnvironment); + } + + if (cmValue debuggerCommand = + this->GeneratorTarget->GetProperty("VS_DEBUGGER_COMMAND")) { + std::string genDebuggerCommand = cmGeneratorExpression::Evaluate( + *debuggerCommand, this->LocalGenerator, config); + e1.WritePlatformConfigTag("LocalDebuggerCommand", cond, + genDebuggerCommand); + } + + if (cmValue commandArguments = this->GeneratorTarget->GetProperty( + "VS_DEBUGGER_COMMAND_ARGUMENTS")) { + std::string genCommandArguments = cmGeneratorExpression::Evaluate( + *commandArguments, this->LocalGenerator, config); + e1.WritePlatformConfigTag("LocalDebuggerCommandArguments", cond, + genCommandArguments); + } + } } } @@ -2762,7 +2980,7 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( if (!this->MSTools) { return; } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } // static libraries and things greater than modules do not need @@ -2830,11 +3048,11 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; std::unique_ptr<Options> pOptions; switch (this->ProjectType) { - case vcxproj: + case VsProjectType::vcxproj: pOptions = cm::make_unique<Options>( this->LocalGenerator, Options::Compiler, gg->GetClFlagTable()); break; - case csproj: + case VsProjectType::csproj: pOptions = cm::make_unique<Options>(this->LocalGenerator, Options::CSharpCompiler, gg->GetCSharpFlagTable()); @@ -2854,7 +3072,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // Choose a language whose flags to use for ClCompile. static const char* clLangs[] = { "CXX", "C", "Fortran" }; std::string langForClCompile; - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { langForClCompile = "CSharp"; } else if (cm::contains(clLangs, linkLanguage)) { langForClCompile = linkLanguage; @@ -2881,12 +3099,18 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->IPOEnabledConfigurations.insert(configName); } + // Check if ASan is enabled. + if (flags.find("/fsanitize=address") != std::string::npos) { + this->ASanEnabledConfigurations.insert(configName); + } + // Precompile Headers std::string pchHeader = this->GeneratorTarget->GetPchHeader(configName, linkLanguage); - if (this->MSTools && vcxproj == this->ProjectType && pchHeader.empty()) { + if (this->MSTools && VsProjectType::vcxproj == this->ProjectType && + pchHeader.empty()) { clOptions.AddFlag("PrecompiledHeader", "NotUsing"); - } else if (this->MSTools && vcxproj == this->ProjectType && + } else if (this->MSTools && VsProjectType::vcxproj == this->ProjectType && !pchHeader.empty()) { clOptions.AddFlag("PrecompiledHeader", "Use"); clOptions.AddFlag("PrecompiledHeaderFile", pchHeader); @@ -2898,10 +3122,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); if (this->MSTools) { - if (this->ProjectType == vcxproj) { + if (this->ProjectType == VsProjectType::vcxproj) { clOptions.FixExceptionHandlingDefault(); if (this->GlobalGenerator->GetVersion() >= - cmGlobalVisualStudioGenerator::VS15) { + cmGlobalVisualStudioGenerator::VSVersion::VS15) { // Toolsets that come with VS 2017 may now enable UseFullPaths // by default and there is no negative /FC option that projects // can use to switch it back. Older toolsets disable this by @@ -2916,7 +3140,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( // check for managed C++ assembly compiler flag. This overrides any // /clr* compiler flags which may be defined in the flags variable(s). - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { // Warn if /clr was added manually. This should not be done // anymore, because cmGeneratorTarget may not be aware that the // target uses C++/CLI. @@ -2945,13 +3169,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.Parse(defineFlags); std::vector<std::string> targetDefines; switch (this->ProjectType) { - case vcxproj: + case VsProjectType::vcxproj: if (!langForClCompile.empty()) { this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, langForClCompile); } break; - case csproj: + case VsProjectType::csproj: this->GeneratorTarget->GetCompileDefinitions(targetDefines, configName, "CSharp"); cm::erase_if(targetDefines, [](std::string const& def) { @@ -2961,7 +3185,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } clOptions.AddDefines(targetDefines); - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { clOptions.AppendFlag("DefineConstants", targetDefines); } @@ -3024,7 +3248,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } } - if (this->ProjectType != csproj && clOptions.IsManaged()) { + if (this->ProjectType != VsProjectType::csproj && clOptions.IsManaged()) { this->Managed = true; std::string managedType = clOptions.GetFlag("CompileAsManaged"); if (managedType == "Safe" || managedType == "Pure") { @@ -3037,7 +3261,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.AddFlag("ExceptionHandling", "Async"); clOptions.AddFlag("BasicRuntimeChecks", "Default"); } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { // /nowin32manifest overrides /win32manifest: parameter if (clOptions.HasFlag("NoWin32Manifest")) { clOptions.RemoveFlag("ApplicationManifest"); @@ -3063,7 +3287,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( Elem& e1, std::string const& configName) { Options& clOptions = *(this->ClOptions[configName]); - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } Elem e2(e1, "ClCompile"); @@ -3201,6 +3425,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( this->LocalGenerator, Options::CudaCompiler, gg->GetCudaFlagTable()); Options& cudaOptions = *pOptions; + auto cudaVersion = this->GlobalGenerator->GetPlatformToolsetCudaString(); + // Get compile flags for CUDA in this directory. std::string flags; this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, "CUDA", @@ -3226,16 +3452,30 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( // the default to not have any extension cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).obj"); - bool notPtx = true; if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) { cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true"); - } else if (this->GeneratorTarget->GetPropertyAsBool( - "CUDA_PTX_COMPILATION")) { + } + bool notPtx = true; + if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { cudaOptions.AddFlag("NvccCompilation", "ptx"); // We drop the %(Extension) component as CMake expects all PTX files // to not have the source file extension at all cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).ptx"); notPtx = false; + + if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, + cudaVersion, "9.0") && + cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, cudaVersion, + "11.5")) { + // The DriverApi flag before 11.5 ( verified back to 9.0 ) which controls + // PTX compilation doesn't propagate user defines causing + // target_compile_definitions to behave differently for VS + + // PTX compared to other generators so we patch the rules + // to normalize behavior + cudaOptions.AddFlag("DriverApiCommandLineTemplate", + "%(BaseCommandLineTemplate) [CompileOut] [FastMath] " + "[Defines] \"%(FullPath)\""); + } } if (notPtx && @@ -4014,7 +4254,7 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( this->GeneratorTarget->GetType() > cmStateEnums::MODULE_LIBRARY) { return; } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } @@ -4050,7 +4290,7 @@ void cmVisualStudio10TargetGenerator::AddLibraries( if (!location.empty()) { ConvertToWindowsSlash(location); switch (this->ProjectType) { - case csproj: + case VsProjectType::csproj: // If the target we want to "link" to is an imported managed // target and this is a C# project, we add a hint reference. This // reference is written to project file in @@ -4058,7 +4298,7 @@ void cmVisualStudio10TargetGenerator::AddLibraries( this->DotNetHintReferences[config].push_back( DotNetHintReference(l.Target->GetName(), location)); break; - case vcxproj: + case VsProjectType::vcxproj: // Add path of assembly to list of using-directories, so the // managed assembly can be used by '#using <assembly.dll>' in // code. @@ -4118,7 +4358,7 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( if (!this->MSTools) { return; } - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } if (this->GeneratorTarget->GetType() > cmStateEnums::UTILITY) { @@ -4159,7 +4399,7 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0) { - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { return; } for (const std::string& c : this->Configurations) { @@ -4178,7 +4418,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0) // output midl flags <Midl></Midl> this->WriteMidlOptions(e1, c); // write events - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { this->WriteEvents(e1, c); } // output link flags <Link></Link> @@ -4243,8 +4483,11 @@ void cmVisualStudio10TargetGenerator::WriteEvent( stdPipesUTF8 = stdPipesUTF8 || cc.GetStdPipesUTF8(); } } + if (!script.empty()) { + script += lg->FinishConstructScript(this->ProjectType); + } comment = cmVS10EscapeComment(comment); - if (this->ProjectType != csproj) { + if (this->ProjectType != VsProjectType::csproj) { Elem e2(e1, name); if (stdPipesUTF8) { this->WriteStdOutEncodingUtf8(e2); @@ -5066,7 +5309,7 @@ bool cmVisualStudio10TargetGenerator::ForceOld(const std::string& source) const void cmVisualStudio10TargetGenerator::GetCSharpSourceProperties( cmSourceFile const* sf, std::map<std::string, std::string>& tags) { - if (this->ProjectType == csproj) { + if (this->ProjectType == VsProjectType::csproj) { const cmPropertyMap& props = sf->GetProperties(); for (const std::string& p : props.GetKeys()) { static const cm::string_view propNamePrefix = "VS_CSHARP_"; @@ -5152,3 +5395,32 @@ void cmVisualStudio10TargetGenerator::WriteStdOutEncodingUtf8(Elem& e1) e1.Element("StdOutEncoding", "UTF-8"); } } + +void cmVisualStudio10TargetGenerator::UpdateCache() +{ + std::vector<std::string> packageReferences; + + if (this->GeneratorTarget->HasPackageReferences()) { + // Store a cache entry that later determines, if a package restore is + // required. + this->GeneratorTarget->Makefile->AddCacheDefinition( + this->GeneratorTarget->GetName() + "_REQUIRES_VS_PACKAGE_RESTORE", "ON", + "Value Computed by CMake", cmStateEnums::STATIC); + } else { + // If there are any dependencies that require package restore, inherit the + // cache variable. + cmGlobalGenerator::TargetDependSet const& unordered = + this->GlobalGenerator->GetTargetDirectDepends(this->GeneratorTarget); + using OrderedTargetDependSet = + cmGlobalVisualStudioGenerator::OrderedTargetDependSet; + OrderedTargetDependSet depends(unordered, CMAKE_CHECK_BUILD_SYSTEM_TARGET); + + for (cmGeneratorTarget const* dt : depends) { + if (dt->HasPackageReferences()) { + this->GeneratorTarget->Makefile->AddCacheDefinition( + this->GeneratorTarget->GetName() + "_REQUIRES_VS_PACKAGE_RESTORE", + "ON", "Value Computed by CMake", cmStateEnums::STATIC); + } + } + } +} diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index a5ce5e5..8d777a3 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -4,15 +4,17 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include <iosfwd> +#include <cstddef> #include <map> #include <memory> #include <set> #include <string> #include <unordered_map> +#include <utility> #include <vector> #include "cmGeneratorTarget.h" +#include "cmVsProjectType.h" class cmComputeLinkInformation; class cmCustomCommand; @@ -196,6 +198,7 @@ private: std::string GetCSharpSourceLink(cmSourceFile const* source); void WriteStdOutEncodingUtf8(Elem& e1); + void UpdateCache(); private: friend class cmVS10GeneratorOptions; @@ -209,11 +212,8 @@ private: OptionsMap NasmOptions; OptionsMap LinkOptions; std::string LangForClCompile; - enum VsProjectType - { - vcxproj, - csproj - } ProjectType; + + VsProjectType ProjectType; bool InSourceBuild; std::vector<std::string> Configurations; std::vector<TargetsFileAndConfigs> TargetsFileAndConfigsVec; @@ -230,6 +230,7 @@ private: unsigned int NsightTegraVersion[4]; bool TargetCompileAsWinRT; std::set<std::string> IPOEnabledConfigurations; + std::set<std::string> ASanEnabledConfigurations; std::map<std::string, std::string> SpectreMitigation; cmGlobalVisualStudio10Generator* const GlobalGenerator; cmLocalVisualStudio10Generator* const LocalGenerator; @@ -259,6 +260,15 @@ private: void ClassifyAllConfigSources(); void ClassifyAllConfigSource(cmGeneratorTarget::AllConfigSource const& acs); + // .Net SDK-stype project variable and helper functions + void WriteClassicMsBuildProjectFile(cmGeneratedFileStream& BuildFileStream); + void WriteSdkStyleProjectFile(cmGeneratedFileStream& BuildFileStream); + + void WriteCommonPropertyGroupGlobals( + cmVisualStudio10TargetGenerator::Elem& e1); + + bool HasCustomCommands() const; + std::unordered_map<std::string, ConfigToSettings> ParsedToolTargetSettings; bool PropertyIsSameInAllConfigs(const ConfigToSettings& toolSettings, const std::string& propName); diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 058ffb4..9045a4d 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -1,12 +1,18 @@ #include "cmVisualStudioGeneratorOptions.h" +#include <algorithm> +#include <map> +#include <sstream> +#include <utility> +#include <vector> + #include <cm/iterator> #include "cmAlgorithms.h" -#include "cmGeneratorExpression.h" -#include "cmGeneratorTarget.h" #include "cmLocalVisualStudioGenerator.h" #include "cmOutputConverter.h" +#include "cmRange.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" static void cmVS10EscapeForMSBuild(std::string& ret) @@ -69,13 +75,13 @@ void cmVisualStudioGeneratorOptions::FixExceptionHandlingDefault() // the flag to disable exception handling. When the user does // remove the flag we need to override the IDE default of on. switch (this->Version) { - case cmGlobalVisualStudioGenerator::VS10: - case cmGlobalVisualStudioGenerator::VS11: - case cmGlobalVisualStudioGenerator::VS12: - case cmGlobalVisualStudioGenerator::VS14: - case cmGlobalVisualStudioGenerator::VS15: - case cmGlobalVisualStudioGenerator::VS16: - case cmGlobalVisualStudioGenerator::VS17: + case cmGlobalVisualStudioGenerator::VSVersion::VS10: + case cmGlobalVisualStudioGenerator::VSVersion::VS11: + case cmGlobalVisualStudioGenerator::VSVersion::VS12: + case cmGlobalVisualStudioGenerator::VSVersion::VS14: + case cmGlobalVisualStudioGenerator::VSVersion::VS15: + case cmGlobalVisualStudioGenerator::VSVersion::VS16: + case cmGlobalVisualStudioGenerator::VSVersion::VS17: // by default VS puts <ExceptionHandling></ExceptionHandling> empty // for a project, to make our projects look the same put a new line // and space over for the closing </ExceptionHandling> as the default @@ -102,7 +108,8 @@ void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose) if (verbose && this->FlagMap.find("SuppressStartupBanner") == this->FlagMap.end()) { this->FlagMap["SuppressStartupBanner"] = - this->Version < cmGlobalVisualStudioGenerator::VS10 ? "FALSE" : ""; + this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS10 ? "FALSE" + : ""; } } @@ -175,6 +182,10 @@ void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() // First entries for the -arch=<arch> [-code=<code>,...] pair. if (!arch.empty()) { std::string arch_name = arch[0]; + if (arch_name == "all" || arch_name == "all-major") { + AppendFlagString("AdditionalOptions", "-arch=" + arch_name); + return; + } std::vector<std::string> codes; if (!code.empty()) { codes = cmTokenize(code[0], ","); @@ -419,7 +430,7 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( } std::ostringstream oss; - if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS10) { oss << "%(" << tag << ")"; } std::vector<std::string>::const_iterator de = @@ -427,13 +438,13 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) { // Escape the definition for the compiler. std::string define; - if (this->Version < cmGlobalVisualStudioGenerator::VS10) { + if (this->Version < cmGlobalVisualStudioGenerator::VSVersion::VS10) { define = this->LocalGenerator->EscapeForShell(di, true); } else { define = di; } // Escape this flag for the MSBuild. - if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS10) { cmVS10EscapeForMSBuild(define); if (lang == "RC") { cmSystemTools::ReplaceString(define, "\"", "\\\""); @@ -475,7 +486,7 @@ void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( } // Escape this include for the MSBuild. - if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS10) { cmVS10EscapeForMSBuild(include); } oss << sep << include; @@ -487,7 +498,7 @@ void cmVisualStudioGeneratorOptions::OutputAdditionalIncludeDirectories( } } - if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS10) { oss << sep << "%(" << tag << ")"; } @@ -501,7 +512,7 @@ void cmVisualStudioGeneratorOptions::OutputFlagMap(std::ostream& fout, std::ostringstream oss; const char* sep = ""; for (std::string i : m.second) { - if (this->Version >= cmGlobalVisualStudioGenerator::VS10) { + if (this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS10) { cmVS10EscapeForMSBuild(i); } oss << sep << i; diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index b123019..ed4ee1d 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -12,7 +12,6 @@ #include "cmIDEOptions.h" class cmLocalVisualStudioGenerator; -class cmGeneratorTarget; using cmVS7FlagTable = cmIDEFlagTable; diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx index 48112dd..2a6dfc4 100644 --- a/Source/cmVisualStudioSlnData.cxx +++ b/Source/cmVisualStudioSlnData.cxx @@ -2,24 +2,42 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVisualStudioSlnData.h" -const cmSlnProjectEntry* cmSlnData::GetProjectByGUID( +#include <cstddef> +#include <utility> + +#include "cmSystemTools.h" + +void cmSlnProjectEntry::AddProjectConfiguration( + const std::string& solutionConfiguration, + const std::string& projectConfiguration) +{ + projectConfigurationMap[solutionConfiguration] = projectConfiguration; +} + +std::string cmSlnProjectEntry::GetProjectConfiguration( + const std::string& solutionConfiguration) +{ + return projectConfigurationMap[solutionConfiguration]; +} + +const cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByGUID( const std::string& projectGUID) const { ProjectStorage::const_iterator it(ProjectsByGUID.find(projectGUID)); if (it != ProjectsByGUID.end()) - return &it->second; + return it->second; else - return NULL; + return cm::nullopt; } -const cmSlnProjectEntry* cmSlnData::GetProjectByName( +const cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByName( const std::string& projectName) const { ProjectStringIndex::const_iterator it(ProjectNameIndex.find(projectName)); if (it != ProjectNameIndex.end()) - return &it->second->second; + return it->second->second; else - return NULL; + return cm::nullopt; } std::vector<cmSlnProjectEntry> cmSlnData::GetProjects() const @@ -47,3 +65,24 @@ cmSlnProjectEntry* cmSlnData::AddProject( ProjectNameIndex[projectName] = it; return &it->second; } + +std::string cmSlnData::GetConfigurationTarget( + const std::string& projectName, const std::string& solutionConfiguration, + const std::string& platformName) +{ + std::string solutionTarget = solutionConfiguration + "|" + platformName; + cm::optional<cmSlnProjectEntry> project = GetProjectByName(projectName); + if (!project) + return platformName; + + std::string projectTarget = project->GetProjectConfiguration(solutionTarget); + if (projectTarget.empty()) + return platformName; + + std::vector<std::string> targetElements = + cmSystemTools::SplitString(projectTarget, '|'); + if (targetElements.size() != 2) + return platformName; + + return targetElements[1]; +} diff --git a/Source/cmVisualStudioSlnData.h b/Source/cmVisualStudioSlnData.h index b217bd8..100dd9b 100644 --- a/Source/cmVisualStudioSlnData.h +++ b/Source/cmVisualStudioSlnData.h @@ -8,6 +8,8 @@ #include <string> #include <vector> +#include <cm/optional> + class cmSlnProjectEntry { public: @@ -24,17 +26,40 @@ public: std::string GetName() const { return Name; } std::string GetRelativePath() const { return RelativePath; } + void AddProjectConfiguration(const std::string& solutionConfiguration, + const std::string& projectConfiguration); + + std::string GetProjectConfiguration( + const std::string& solutionConfiguration); + private: std::string Guid, Name, RelativePath; + std::map<std::string, std::string> projectConfigurationMap; }; class cmSlnData { public: - const cmSlnProjectEntry* GetProjectByGUID( + std::string GetVisualStudioVersion() const { return visualStudioVersion; } + void SetVisualStudioVersion(const std::string& version) + { + visualStudioVersion = version; + } + + std::string GetMinimumVisualStudioVersion() const + { + return minimumVisualStudioVersion; + } + + void SetMinimumVisualStudioVersion(const std::string& version) + { + minimumVisualStudioVersion = version; + } + + const cm::optional<cmSlnProjectEntry> GetProjectByGUID( const std::string& projectGUID) const; - const cmSlnProjectEntry* GetProjectByName( + const cm::optional<cmSlnProjectEntry> GetProjectByName( const std::string& projectName) const; std::vector<cmSlnProjectEntry> GetProjects() const; @@ -43,9 +68,20 @@ public: const std::string& projectName, const std::string& projectRelativePath); + void AddConfiguration(const std::string& configuration) + { + solutionConfigurations.push_back(configuration); + } + + std::string GetConfigurationTarget(const std::string& projectName, + const std::string& solutionConfiguration, + const std::string& platformName); + private: + std::string visualStudioVersion, minimumVisualStudioVersion; using ProjectStorage = std::map<std::string, cmSlnProjectEntry>; ProjectStorage ProjectsByGUID; using ProjectStringIndex = std::map<std::string, ProjectStorage::iterator>; ProjectStringIndex ProjectNameIndex; + std::vector<std::string> solutionConfigurations; }; diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx index d7822b1..feab895 100644 --- a/Source/cmVisualStudioSlnParser.cxx +++ b/Source/cmVisualStudioSlnParser.cxx @@ -3,7 +3,10 @@ #include "cmVisualStudioSlnParser.h" #include <cassert> +#include <memory> #include <stack> +#include <utility> +#include <vector> #include "cmsys/FStream.hxx" @@ -217,9 +220,14 @@ bool cmVisualStudioSlnParser::State::Process( this->Stack.push(FileStateProject); } else this->IgnoreUntilTag("EndProject"); - } else if (line.GetTag().compare("Global") == 0) + } else if (line.GetTag().compare("Global") == 0) { + this->Stack.push(FileStateGlobal); - else { + } else if (line.GetTag().compare("VisualStudioVersion") == 0) { + output.SetVisualStudioVersion(line.GetValue(0)); + } else if (line.GetTag().compare("MinimumVisualStudioVersion") == 0) { + output.SetMinimumVisualStudioVersion(line.GetValue(0)); + } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } @@ -287,10 +295,9 @@ bool cmVisualStudioSlnParser::State::Process( case FileStateSolutionConfigurations: if (line.GetTag().compare("EndGlobalSection") == 0) this->Stack.pop(); - else if (line.IsKeyValuePair()) - // implement configuration storing here, once needed - ; - else { + else if (line.IsKeyValuePair()) { + output.AddConfiguration(line.GetValue(0)); + } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } @@ -298,10 +305,30 @@ bool cmVisualStudioSlnParser::State::Process( case FileStateProjectConfigurations: if (line.GetTag().compare("EndGlobalSection") == 0) this->Stack.pop(); - else if (line.IsKeyValuePair()) - // implement configuration storing here, once needed - ; - else { + else if (line.IsKeyValuePair()) { + std::vector<std::string> tagElements = + cmSystemTools::SplitString(line.GetTag(), '.'); + if (tagElements.size() != 3 && tagElements.size() != 4) { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + + std::string guid = tagElements[0]; + std::string solutionConfiguration = tagElements[1]; + std::string activeBuild = tagElements[2]; + cm::optional<cmSlnProjectEntry> projectEntry = + output.GetProjectByGUID(guid); + + if (!projectEntry) { + result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); + return false; + } + + if (activeBuild.compare("ActiveCfg") == 0) { + projectEntry->AddProjectConfiguration(solutionConfiguration, + line.GetValue(0)); + } + } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } @@ -452,8 +479,7 @@ bool cmVisualStudioSlnParser::GetParseHadBOM() const bool cmVisualStudioSlnParser::IsDataGroupSetSupported( DataGroupSet dataGroups) const { - return (dataGroups & DataGroupProjects) == dataGroups; - // only supporting DataGroupProjects for now + return (dataGroups & DataGroupProjects) != 0; } bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, cmSlnData& output, diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h index 1c33759..60be598 100644 --- a/Source/cmVisualStudioSlnParser.h +++ b/Source/cmVisualStudioSlnParser.h @@ -5,13 +5,12 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <bitset> +#include <cstddef> #include <iosfwd> #include <string> #include <cm/string_view> -#include <stddef.h> - class cmSlnData; class cmVisualStudioSlnParser diff --git a/Source/cmVisualStudioWCEPlatformParser.cxx b/Source/cmVisualStudioWCEPlatformParser.cxx index 3b113aa..2f71cf5 100644 --- a/Source/cmVisualStudioWCEPlatformParser.cxx +++ b/Source/cmVisualStudioWCEPlatformParser.cxx @@ -2,8 +2,12 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmVisualStudioWCEPlatformParser.h" +#include <algorithm> +#include <cstring> +#include <utility> + #include "cmGlobalVisualStudioGenerator.h" -#include "cmXMLParser.h" +#include "cmSystemTools.h" int cmVisualStudioWCEPlatformParser::ParseVersion(const char* version) { diff --git a/Source/cmVisualStudioWCEPlatformParser.h b/Source/cmVisualStudioWCEPlatformParser.h index eb4e978..2fff91c 100644 --- a/Source/cmVisualStudioWCEPlatformParser.h +++ b/Source/cmVisualStudioWCEPlatformParser.h @@ -4,12 +4,11 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <cstddef> #include <map> #include <string> #include <vector> -#include <stddef.h> - #include "cmXMLParser.h" // This class is used to parse XML with configuration diff --git a/Source/cmVsProjectType.h b/Source/cmVsProjectType.h new file mode 100644 index 0000000..8899267 --- /dev/null +++ b/Source/cmVsProjectType.h @@ -0,0 +1,11 @@ +/* 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 + +enum class VsProjectType +{ + vcxproj, + csproj +}; diff --git a/Source/cmXCOFF.cxx b/Source/cmXCOFF.cxx index 890636e..a6d278d 100644 --- a/Source/cmXCOFF.cxx +++ b/Source/cmXCOFF.cxx @@ -61,20 +61,20 @@ namespace { struct XCOFF32 { - typedef struct filehdr filehdr; - typedef struct aouthdr aouthdr; - typedef struct scnhdr scnhdr; - typedef struct ldhdr ldhdr; + using filehdr = struct filehdr; + using aouthdr = struct aouthdr; + using scnhdr = struct scnhdr; + using ldhdr = struct ldhdr; static const std::size_t aouthdr_size = _AOUTHSZ_EXEC; }; const unsigned char xcoff32_magic[] = { 0x01, 0xDF }; struct XCOFF64 { - typedef struct filehdr_64 filehdr; - typedef struct aouthdr_64 aouthdr; - typedef struct scnhdr_64 scnhdr; - typedef struct ldhdr_64 ldhdr; + using filehdr = struct filehdr_64; + using aouthdr = struct aouthdr_64; + using scnhdr = struct scnhdr_64; + using ldhdr = struct ldhdr_64; static const std::size_t aouthdr_size = _AOUTHSZ_EXEC_64; }; const unsigned char xcoff64_magic[] = { 0x01, 0xF7 }; @@ -326,8 +326,8 @@ cmXCOFF::cmXCOFF(const char* fname, Mode mode) cmXCOFF::~cmXCOFF() = default; -cmXCOFF::cmXCOFF(cmXCOFF&&) = default; -cmXCOFF& cmXCOFF::operator=(cmXCOFF&&) = default; +cmXCOFF::cmXCOFF(cmXCOFF&&) noexcept = default; +cmXCOFF& cmXCOFF::operator=(cmXCOFF&&) noexcept = default; bool cmXCOFF::Valid() const { diff --git a/Source/cmXCOFF.h b/Source/cmXCOFF.h index 16cda9d..f6d9d94 100644 --- a/Source/cmXCOFF.h +++ b/Source/cmXCOFF.h @@ -35,9 +35,9 @@ public: /** Destruct. */ ~cmXCOFF(); - cmXCOFF(cmXCOFF&&); + cmXCOFF(cmXCOFF&&) noexcept; cmXCOFF(cmXCOFF const&) = delete; - cmXCOFF& operator=(cmXCOFF&&); + cmXCOFF& operator=(cmXCOFF&&) noexcept; cmXCOFF& operator=(cmXCOFF const&) = delete; /** Get the error message if any. */ diff --git a/Source/cmXCode21Object.h b/Source/cmXCode21Object.h index f3fc438..0c7f22b 100644 --- a/Source/cmXCode21Object.h +++ b/Source/cmXCode21Object.h @@ -6,6 +6,7 @@ #include <iosfwd> #include <memory> +#include <string> #include <vector> #include "cmXCodeObject.h" diff --git a/Source/cmXCodeObject.cxx b/Source/cmXCodeObject.cxx index d5c5275..c817980 100644 --- a/Source/cmXCodeObject.cxx +++ b/Source/cmXCodeObject.cxx @@ -6,8 +6,6 @@ #include <CoreFoundation/CoreFoundation.h> -#include "cmSystemTools.h" - const char* cmXCodeObject::PBXTypeNames[] = { /* clang-format needs this comment to break after the opening brace */ "PBXGroup", diff --git a/Source/cmXCodeObject.h b/Source/cmXCodeObject.h index dd5e86e..389fb62 100644 --- a/Source/cmXCodeObject.h +++ b/Source/cmXCodeObject.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <algorithm> +#include <cstddef> #include <iosfwd> #include <map> #include <string> diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx index e2c0f2d..adc500a 100644 --- a/Source/cmXCodeScheme.cxx +++ b/Source/cmXCodeScheme.cxx @@ -3,16 +3,24 @@ #include "cmXCodeScheme.h" #include <iomanip> -#include <iostream> #include <sstream> #include <utility> #include <cmext/algorithm> +#include "cmsys/String.h" + #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" -#include "cmXMLSafe.h" +#include "cmStateTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmValue.h" +#include "cmXCodeObject.h" +#include "cmXMLWriter.h" + +class cmLocalGenerator; cmXCodeScheme::cmXCodeScheme(cmLocalGenerator* lg, cmXCodeObject* xcObj, TestObjects tests, @@ -148,6 +156,16 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, true); xout.Attribute("debugServiceExtension", "internal"); xout.Attribute("allowLocationSimulation", "YES"); + if (cmValue gpuFrameCaptureMode = this->Target->GetTarget()->GetProperty( + "XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE")) { + std::string value = *gpuFrameCaptureMode; + if (cmsysString_strcasecmp(value.c_str(), "Metal") == 0) { + value = "1"; + } else if (cmsysString_strcasecmp(value.c_str(), "Disabled") == 0) { + value = "3"; + } + xout.Attribute("enableGPUFrameCaptureMode", value); + } // Diagnostics tab begin diff --git a/Source/cmXCodeScheme.h b/Source/cmXCodeScheme.h index 11f043e..07fdedb 100644 --- a/Source/cmXCodeScheme.h +++ b/Source/cmXCodeScheme.h @@ -4,12 +4,13 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <iosfwd> +#include <string> #include <vector> -#include "cmGlobalXCodeGenerator.h" -#include "cmSystemTools.h" -#include "cmXCodeObject.h" -#include "cmXMLWriter.h" +class cmLocalGenerator; +class cmXCodeObject; +class cmXMLWriter; /** \class cmXCodeScheme * \brief Write shared schemes for native targets in Xcode project. diff --git a/Source/cmXMLParser.h b/Source/cmXMLParser.h index 7e805d7..176252d 100644 --- a/Source/cmXMLParser.h +++ b/Source/cmXMLParser.h @@ -21,6 +21,7 @@ class cmXMLParser { public: cmXMLParser(); + cmXMLParser(const cmXMLParser& /*other*/) = default; virtual ~cmXMLParser(); //! Parse given XML string diff --git a/Source/cmXMLSafe.cxx b/Source/cmXMLSafe.cxx index d31a239..4014635 100644 --- a/Source/cmXMLSafe.cxx +++ b/Source/cmXMLSafe.cxx @@ -73,7 +73,7 @@ std::ostream& operator<<(std::ostream& os, cmXMLSafe const& self) } else { // Use a human-readable hex value for this invalid character. char buf[16]; - sprintf(buf, "%X", ch); + snprintf(buf, sizeof(buf), "%X", ch); os << "[NON-XML-CHAR-0x" << buf << "]"; } @@ -82,7 +82,7 @@ std::ostream& operator<<(std::ostream& os, cmXMLSafe const& self) ch = static_cast<unsigned char>(*first++); // Use a human-readable hex value for this invalid byte. char buf[16]; - sprintf(buf, "%X", ch); + snprintf(buf, sizeof(buf), "%X", ch); os << "[NON-UTF-8-BYTE-0x" << buf << "]"; } } diff --git a/Source/cm_codecvt.cxx b/Source/cm_codecvt.cxx index 216d3f0..8115306 100644 --- a/Source/cm_codecvt.cxx +++ b/Source/cm_codecvt.cxx @@ -3,17 +3,14 @@ #include "cm_codecvt.hxx" #if defined(_WIN32) -# include <windows.h> +# include <cassert> +# include <cstring> -# include <assert.h> -# include <string.h> +# include <windows.h> # undef max # include "cmsys/Encoding.hxx" -#endif -#if defined(_WIN32) -/* Number of leading ones before a zero in the byte (see cm_utf8.c). */ -extern "C" unsigned char const cm_utf8_ones[256]; +# include "cm_utf8.h" #endif codecvt::codecvt(Encoding e) @@ -42,7 +39,7 @@ codecvt::codecvt(Encoding e) codecvt::~codecvt() = default; -bool codecvt::do_always_noconv() const throw() +bool codecvt::do_always_noconv() const noexcept { return this->m_noconv; } @@ -234,12 +231,12 @@ void codecvt::BufferPartial(mbstate_t& state, int size, } #endif -int codecvt::do_max_length() const throw() +int codecvt::do_max_length() const noexcept { return 4; } -int codecvt::do_encoding() const throw() +int codecvt::do_encoding() const noexcept { return 0; } diff --git a/Source/cm_codecvt.hxx b/Source/cm_codecvt.hxx index b73204f..9af083f 100644 --- a/Source/cm_codecvt.hxx +++ b/Source/cm_codecvt.hxx @@ -24,14 +24,14 @@ public: protected: ~codecvt() override; - bool do_always_noconv() const throw() override; + bool do_always_noconv() const noexcept override; result do_out(mbstate_t& state, const char* from, const char* from_end, const char*& from_next, char* to, char* to_end, char*& to_next) const override; result do_unshift(mbstate_t& state, char* to, char*, char*& to_next) const override; - int do_max_length() const throw() override; - int do_encoding() const throw() override; + int do_max_length() const noexcept override; + int do_encoding() const noexcept override; private: // The mbstate_t argument to do_out and do_unshift is responsible diff --git a/Source/cm_utf8.c b/Source/cm_utf8.c index 62e7e8c..b046aef 100644 --- a/Source/cm_utf8.c +++ b/Source/cm_utf8.c @@ -42,6 +42,11 @@ static unsigned int const cm_utf8_min[7] = { const char* cm_utf8_decode_character(const char* first, const char* last, unsigned int* pc) { + /* We need at least one byte. */ + if (first == last) { + return 0; + } + /* Count leading ones in the first byte. */ unsigned char c = (unsigned char)*first++; unsigned char const ones = cm_utf8_ones[c]; diff --git a/Source/cm_utf8.h b/Source/cm_utf8.h index fa9ed3a..67f3d3f 100644 --- a/Source/cm_utf8.h +++ b/Source/cm_utf8.h @@ -6,6 +6,8 @@ extern "C" { #endif +extern unsigned char const cm_utf8_ones[256]; + /** Decode one UTF-8 character from the input byte range. On success, stores the unicode character number in *pc and returns the first position not extracted. On failure, returns 0. */ diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fda7900..f9e2d6e 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -28,8 +28,9 @@ #include "cm_sys_stat.h" +#include "cmBuildOptions.h" #include "cmCMakePath.h" -#include "cmCMakePresetsFile.h" +#include "cmCMakePresetsGraph.h" #include "cmCommandLineArgument.h" #include "cmCommands.h" #include "cmDocumentation.h" @@ -205,7 +206,7 @@ cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) exts.ordered.reserve(extList.size()); for (cm::string_view ext : extList) { exts.ordered.emplace_back(ext); - }; + } // Fill unordered set exts.unordered.insert(exts.ordered.begin(), exts.ordered.end()); }; @@ -543,6 +544,10 @@ bool cmake::SetCacheArgs(const std::vector<std::string>& args) "-C", "-C must be followed by a file name.", CommandArgument::Values::One, CommandArgument::RequiresSeparator::No, [&](std::string const& value, cmake* state) -> bool { + if (value.empty()) { + cmSystemTools::Error("No file name specified for -C"); + return false; + } cmSystemTools::Stdout("loading initial cache file " + value + "\n"); // Resolve script path specified on command line // relative to $PWD. @@ -790,6 +795,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) bool haveBArg = false; bool scriptMode = false; std::string possibleUnknownArg; + std::string extraProvidedPath; #if !defined(CMAKE_BOOTSTRAP) std::string profilingFormat; std::string profilingOutput; @@ -798,14 +804,30 @@ void cmake::SetArgs(const std::vector<std::string>& args) ListPresets listPresets = ListPresets::None; #endif + auto EmptyStringArgLambda = [](std::string const&, cmake* state) -> bool { + state->IssueMessage( + MessageType::WARNING, + "Ignoring empty string (\"\") provided on the command line."); + return true; + }; + auto SourceArgLambda = [](std::string const& value, cmake* state) -> bool { + if (value.empty()) { + cmSystemTools::Error("No source directory specified for -S"); + return false; + } std::string path = cmSystemTools::CollapseFullPath(value); cmSystemTools::ConvertToUnixSlashes(path); - state->SetHomeDirectory(path); + + state->SetHomeDirectoryViaCommandLine(path, HomeDirArgStyle::Dash_S); return true; }; auto BuildArgLambda = [&](std::string const& value, cmake* state) -> bool { + if (value.empty()) { + cmSystemTools::Error("No build directory specified for -B"); + return false; + } std::string path = cmSystemTools::CollapseFullPath(value); cmSystemTools::ConvertToUnixSlashes(path); state->SetHomeOutputDirectory(path); @@ -834,6 +856,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) }; std::vector<CommandArgument> arguments = { + CommandArgument{ "", CommandArgument::Values::Zero, EmptyStringArgLambda }, CommandArgument{ "-S", "No source directory specified for -S", CommandArgument::Values::One, CommandArgument::RequiresSeparator::No, SourceArgLambda }, @@ -968,7 +991,34 @@ void cmake::SetArgs(const std::vector<std::string>& args) "--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); + state->SetDebugFindOutput(true); + return true; + } }, + CommandArgument{ + "--debug-find-pkg", "Provide a package argument for --debug-find-pkg", + CommandArgument::Values::One, CommandArgument::RequiresSeparator::Yes, + [](std::string const& value, cmake* state) -> bool { + std::vector<std::string> find_pkgs(cmTokenize(value, ",")); + std::cout << "Running with debug output on for the 'find' commands " + "for package(s)"; + for (auto const& v : find_pkgs) { + std::cout << " " << v; + state->SetDebugFindOutputPkgs(v); + } + std::cout << ".\n"; + return true; + } }, + CommandArgument{ + "--debug-find-var", CommandArgument::Values::One, + CommandArgument::RequiresSeparator::Yes, + [](std::string const& value, cmake* state) -> bool { + std::vector<std::string> find_vars(cmTokenize(value, ",")); + std::cout << "Running with debug output on for the variable(s)"; + for (auto const& v : find_vars) { + std::cout << " " << v; + state->SetDebugFindOutputVars(v); + } + std::cout << ".\n"; return true; } }, CommandArgument{ "--trace-expand", CommandArgument::Values::Zero, @@ -1141,10 +1191,18 @@ void cmake::SetArgs(const std::vector<std::string>& args) } else if (!matched && cmHasLiteralPrefix(arg, "-")) { possibleUnknownArg = arg; } else if (!matched) { - this->SetDirectoriesFromFile(arg); + bool parsedDirectory = this->SetDirectoriesFromFile(arg); + if (!parsedDirectory) { + extraProvidedPath = arg; + } } } + if (!extraProvidedPath.empty() && !scriptMode) { + this->IssueMessage(MessageType::WARNING, + cmStrCat("Ignoring extra path from command line:\n \"", + extraProvidedPath, "\"")); + } if (!possibleUnknownArg.empty() && !scriptMode) { cmSystemTools::Error(cmStrCat("Unknown argument ", possibleUnknownArg)); cmSystemTools::Error("Run 'cmake --help' for all supported options."); @@ -1212,43 +1270,43 @@ void cmake::SetArgs(const std::vector<std::string>& args) #if !defined(CMAKE_BOOTSTRAP) if (listPresets != ListPresets::None || !presetName.empty()) { - cmCMakePresetsFile settingsFile; - auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory()); - if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + cmCMakePresetsGraph presetsGraph; + auto result = presetsGraph.ReadProjectPresets(this->GetHomeDirectory()); + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { cmSystemTools::Error( cmStrCat("Could not read presets from ", this->GetHomeDirectory(), - ": ", cmCMakePresetsFile::ResultToString(result))); + ": ", cmCMakePresetsGraph::ResultToString(result))); return; } if (listPresets != ListPresets::None) { if (listPresets == ListPresets::Configure) { - this->PrintPresetList(settingsFile); + this->PrintPresetList(presetsGraph); } else if (listPresets == ListPresets::Build) { - settingsFile.PrintBuildPresetList(); + presetsGraph.PrintBuildPresetList(); } else if (listPresets == ListPresets::Test) { - settingsFile.PrintTestPresetList(); + presetsGraph.PrintTestPresetList(); } else if (listPresets == ListPresets::All) { - settingsFile.PrintAllPresets(); + presetsGraph.PrintAllPresets(); } this->SetWorkingMode(WorkingMode::HELP_MODE); return; } - auto preset = settingsFile.ConfigurePresets.find(presetName); - if (preset == settingsFile.ConfigurePresets.end()) { + auto preset = presetsGraph.ConfigurePresets.find(presetName); + if (preset == presetsGraph.ConfigurePresets.end()) { cmSystemTools::Error(cmStrCat("No such preset in ", this->GetHomeDirectory(), ": \"", presetName, '"')); - this->PrintPresetList(settingsFile); + this->PrintPresetList(presetsGraph); return; } if (preset->second.Unexpanded.Hidden) { cmSystemTools::Error(cmStrCat("Cannot use hidden preset in ", this->GetHomeDirectory(), ": \"", presetName, '"')); - this->PrintPresetList(settingsFile); + this->PrintPresetList(presetsGraph); return; } auto const& expandedPreset = preset->second.Expanded; @@ -1292,14 +1350,14 @@ void cmake::SetArgs(const std::vector<std::string>& args) if (!expandedPreset->ArchitectureStrategy || expandedPreset->ArchitectureStrategy == - cmCMakePresetsFile::ArchToolsetStrategy::Set) { + cmCMakePresetsGraph::ArchToolsetStrategy::Set) { if (!this->GeneratorPlatformSet) { this->SetGeneratorPlatform(expandedPreset->Architecture); } } if (!expandedPreset->ToolsetStrategy || expandedPreset->ToolsetStrategy == - cmCMakePresetsFile::ArchToolsetStrategy::Set) { + cmCMakePresetsGraph::ArchToolsetStrategy::Set) { if (!this->GeneratorToolsetSet) { this->SetGeneratorToolset(expandedPreset->Toolset); } @@ -1325,7 +1383,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) this->DebugTryCompileOn(); } if (expandedPreset->DebugFind == true) { - this->SetDebugFindOutputOn(true); + this->SetDebugFindOutput(true); } } #endif @@ -1423,26 +1481,31 @@ void cmake::PrintTraceFormatVersion() } } -void cmake::SetDirectoriesFromFile(const std::string& arg) +bool cmake::SetDirectoriesFromFile(const std::string& arg) { // Check if the argument refers to a CMakeCache.txt or // CMakeLists.txt file. std::string listPath; std::string cachePath; - bool argIsFile = false; + bool is_source_dir = false; + bool is_empty_directory = false; if (cmSystemTools::FileIsDirectory(arg)) { std::string path = cmSystemTools::CollapseFullPath(arg); cmSystemTools::ConvertToUnixSlashes(path); std::string cacheFile = cmStrCat(path, "/CMakeCache.txt"); std::string listFile = cmStrCat(path, "/CMakeLists.txt"); + + is_empty_directory = true; if (cmSystemTools::FileExists(cacheFile)) { cachePath = path; + is_empty_directory = false; } if (cmSystemTools::FileExists(listFile)) { listPath = path; + is_empty_directory = false; + is_source_dir = true; } } else if (cmSystemTools::FileExists(arg)) { - argIsFile = true; std::string fullPath = cmSystemTools::CollapseFullPath(arg); std::string name = cmSystemTools::GetFilenameName(fullPath); name = cmSystemTools::LowerCase(name); @@ -1458,7 +1521,6 @@ void cmake::SetDirectoriesFromFile(const std::string& arg) std::string name = cmSystemTools::GetFilenameName(fullPath); name = cmSystemTools::LowerCase(name); if (name == "cmakecache.txt"_s || name == "cmakelists.txt"_s) { - argIsFile = true; listPath = cmSystemTools::GetFilenamePath(fullPath); } else { listPath = fullPath; @@ -1473,42 +1535,60 @@ void cmake::SetDirectoriesFromFile(const std::string& arg) if (existingValue) { this->SetHomeOutputDirectory(cachePath); this->SetHomeDirectory(*existingValue); - return; + return true; } } } + bool no_source_tree = this->GetHomeDirectory().empty(); + bool no_build_tree = this->GetHomeOutputDirectory().empty(); + + // When invoked with a path that points to an existing CMakeCache + // This function is called multiple times with the same path + const bool passed_same_path = (listPath == this->GetHomeDirectory()) || + (listPath == this->GetHomeOutputDirectory()); + bool used_provided_path = + (passed_same_path || is_source_dir || no_build_tree); + // If there is a CMakeLists.txt file, use it as the source tree. if (!listPath.empty()) { - this->SetHomeDirectory(listPath); - - if (argIsFile) { - // Source CMakeLists.txt file given. It was probably dropped - // onto the executable in a GUI. Default to an in-source build. - this->SetHomeOutputDirectory(listPath); - } else { - // Source directory given on command line. Use current working - // directory as build tree if -B hasn't been given already - if (this->GetHomeOutputDirectory().empty()) { + // When invoked with a path that points to an existing CMakeCache + // This function is called multiple times with the same path + if (is_source_dir) { + this->SetHomeDirectoryViaCommandLine(listPath, HomeDirArgStyle::Plain); + if (no_build_tree) { std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); this->SetHomeOutputDirectory(cwd); } + } else if (no_source_tree && no_build_tree) { + this->SetHomeDirectory(listPath); + + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + } else if (no_build_tree) { + this->SetHomeOutputDirectory(listPath); + } + } else { + if (no_source_tree) { + // We didn't find a CMakeLists.txt and it wasn't specified + // with -S. Assume it is the path to the source tree + std::string full = cmSystemTools::CollapseFullPath(arg); + this->SetHomeDirectory(full); + } + if (no_build_tree && !no_source_tree && is_empty_directory) { + // passed `-S <path> <build_dir> when build_dir is an empty directory + std::string full = cmSystemTools::CollapseFullPath(arg); + this->SetHomeOutputDirectory(full); + } else if (no_build_tree) { + // We didn't find a CMakeCache.txt and it wasn't specified + // with -B. Assume the current working directory as the build tree. + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + used_provided_path = false; } - return; } - if (this->GetHomeDirectory().empty()) { - // We didn't find a CMakeLists.txt and it wasn't specified - // with -S. Assume it is the path to the source tree - std::string full = cmSystemTools::CollapseFullPath(arg); - this->SetHomeDirectory(full); - } - if (this->GetHomeOutputDirectory().empty()) { - // We didn't find a CMakeCache.txt and it wasn't specified - // with -B. Assume the current working directory as the build tree. - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - this->SetHomeOutputDirectory(cwd); - } + return used_provided_path; } // at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the @@ -1680,12 +1760,12 @@ bool cmake::CreateAndSetGlobalGenerator(const std::string& name, } #ifndef CMAKE_BOOTSTRAP -void cmake::PrintPresetList(const cmCMakePresetsFile& file) const +void cmake::PrintPresetList(const cmCMakePresetsGraph& graph) const { std::vector<GeneratorInfo> generators; this->GetRegisteredGenerators(generators, false); auto filter = - [&generators](const cmCMakePresetsFile::ConfigurePreset& preset) -> bool { + [&generators](const cmCMakePresetsGraph::ConfigurePreset& preset) -> bool { if (preset.Generator.empty()) { return true; } @@ -1696,16 +1776,46 @@ void cmake::PrintPresetList(const cmCMakePresetsFile& file) const return it != generators.end(); }; - file.PrintConfigurePresetList(filter); + graph.PrintConfigurePresetList(filter); } #endif +void cmake::SetHomeDirectoryViaCommandLine(std::string const& path, + HomeDirArgStyle argStyle) +{ + bool fromDashS = argStyle == HomeDirArgStyle::Dash_S; + static bool homeDirectorySetExplicitly = false; + if (path.empty()) { + return; + } + + auto prev_path = this->GetHomeDirectory(); + if (prev_path != path && !prev_path.empty()) { + const bool ignore_prev_path = + (fromDashS || (!fromDashS && !homeDirectorySetExplicitly)); + const std::string& ignored_path = (ignore_prev_path) ? prev_path : path; + this->IssueMessage(MessageType::WARNING, + cmStrCat("Ignoring extra path from command line:\n \"", + ignored_path, "\"")); + } + if (fromDashS || !homeDirectorySetExplicitly) { + this->SetHomeDirectory(path); + } + homeDirectorySetExplicitly = fromDashS; +} + void cmake::SetHomeDirectory(const std::string& dir) { this->State->SetSourceDirectory(dir); if (this->CurrentSnapshot.IsValid()) { this->CurrentSnapshot.SetDefinition("CMAKE_SOURCE_DIR", dir); } + + if (this->State->GetProjectKind() == cmState::ProjectKind::Normal) { + this->Messenger->SetTopSource(this->GetHomeDirectory()); + } else { + this->Messenger->SetTopSource(cm::nullopt); + } } std::string const& cmake::GetHomeDirectory() const @@ -2155,7 +2265,8 @@ int cmake::ActualConfigure() "CMakeLists.txt ?"); } - this->State->SaveVerificationScript(this->GetHomeOutputDirectory()); + this->State->SaveVerificationScript(this->GetHomeOutputDirectory(), + this->Messenger.get()); this->SaveCache(this->GetHomeOutputDirectory()); if (cmSystemTools::GetErrorOccuredFlag()) { return -1; @@ -2452,7 +2563,7 @@ void cmake::AddGlobCacheEntry(bool recurse, bool listDirectories, { this->State->AddGlobCacheEntry(recurse, listDirectories, followSymlinks, relative, expression, files, variable, - backtrace); + backtrace, this->Messenger.get()); } std::vector<std::string> cmake::GetAllExtensions() const @@ -3185,8 +3296,8 @@ std::vector<std::string> cmake::GetDebugConfigs() int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets, std::string config, std::vector<std::string> nativeOptions, - bool clean, bool verbose, const std::string& presetName, - bool listPresets) + cmBuildOptions& buildOptions, bool verbose, + const std::string& presetName, bool listPresets) { this->SetHomeDirectory(""); this->SetHomeOutputDirectory(""); @@ -3196,12 +3307,12 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets, this->SetHomeDirectory(cmSystemTools::GetCurrentWorkingDirectory()); this->SetHomeOutputDirectory(cmSystemTools::GetCurrentWorkingDirectory()); - cmCMakePresetsFile settingsFile; + cmCMakePresetsGraph settingsFile; auto result = settingsFile.ReadProjectPresets(this->GetHomeDirectory()); - if (result != cmCMakePresetsFile::ReadFileResult::READ_OK) { + if (result != cmCMakePresetsGraph::ReadFileResult::READ_OK) { cmSystemTools::Error( cmStrCat("Could not read presets from ", this->GetHomeDirectory(), - ": ", cmCMakePresetsFile::ResultToString(result))); + ": ", cmCMakePresetsGraph::ResultToString(result))); return 1; } @@ -3292,8 +3403,13 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets, config = expandedPreset->Configuration; } - if (!clean && expandedPreset->CleanFirst) { - clean = *expandedPreset->CleanFirst; + if (!buildOptions.Clean && expandedPreset->CleanFirst) { + buildOptions.Clean = *expandedPreset->CleanFirst; + } + + if (buildOptions.ResolveMode == PackageResolveMode::Default && + expandedPreset->ResolvePackageReferences) { + buildOptions.ResolveMode = *expandedPreset->ResolvePackageReferences; } if (!verbose && expandedPreset->Verbose) { @@ -3432,7 +3548,7 @@ int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets, this->GlobalGenerator->PrintBuildCommandAdvice(std::cerr, jobs); return this->GlobalGenerator->Build( - jobs, "", dir, projName, targets, output, "", config, clean, false, + jobs, "", dir, projName, targets, output, "", config, buildOptions, verbose, cmDuration::zero(), cmSystemTools::OUTPUT_PASSTHROUGH, nativeOptions); } @@ -3612,6 +3728,26 @@ void cmake::SetDeprecatedWarningsAsErrors(bool b) cmStateEnums::INTERNAL); } +void cmake::SetDebugFindOutputPkgs(std::string const& args) +{ + this->DebugFindPkgs.emplace(args); +} + +void cmake::SetDebugFindOutputVars(std::string const& args) +{ + this->DebugFindVars.emplace(args); +} + +bool cmake::GetDebugFindOutput(std::string const& var) const +{ + return this->DebugFindVars.count(var); +} + +bool cmake::GetDebugFindPkgOutput(std::string const& pkg) const +{ + return this->DebugFindPkgs.count(pkg); +} + #if !defined(CMAKE_BOOTSTRAP) cmMakefileProfilingData& cmake::GetProfilingOutput() { diff --git a/Source/cmake.h b/Source/cmake.h index 3f2b2ed..9c795c5 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -31,7 +31,7 @@ # include <cm3p/json/value.h> -# include "cmCMakePresetsFile.h" +# include "cmCMakePresetsGraph.h" #endif class cmExternalMakefileProjectGeneratorFactory; @@ -45,6 +45,7 @@ class cmMakefileProfilingData; #endif class cmMessenger; class cmVariableWatch; +struct cmBuildOptions; struct cmDocumentationEntry; /** \brief Represents a cmake invocation. @@ -182,6 +183,29 @@ public: #endif std::string ReportCapabilities() const; + enum class HomeDirArgStyle + { + Plain, + Dash_S, + }; + + /** + * Set the home directory from `-S` or from a known location + * that contains a CMakeLists.txt. Will generate warnings + * when overriding an existing source directory. + * + * | args | src dir| warning | + * | ----------------- | ------ | -------------- | + * | `dirA dirA` | dirA | N/A | + * | `-S dirA -S dirA` | dirA | N/A | + * | `-S dirA -S dirB` | dirB | Ignoring dirA | + * | `-S dirA dirB` | dirA | Ignoring dirB | + * | `dirA -S dirB` | dirB | Ignoring dirA | + * | `dirA dirB` | dirB | Ignoring dirA | + */ + void SetHomeDirectoryViaCommandLine(std::string const& path, + HomeDirArgStyle argStyle); + //@{ /** * Set/Get the home directory (or output directory) in the project. The @@ -248,7 +272,7 @@ public: #ifndef CMAKE_BOOTSTRAP //! Print list of configure presets - void PrintPresetList(const cmCMakePresetsFile& file) const; + void PrintPresetList(const cmCMakePresetsGraph& graph) const; #endif //! Return the global generator assigned to this instance of cmake @@ -486,7 +510,11 @@ public: //! Do we want debug output from the find commands during the cmake run. bool GetDebugFindOutput() const { return this->DebugFindOutput; } - void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; } + bool GetDebugFindOutput(std::string const& var) const; + bool GetDebugFindPkgOutput(std::string const& pkg) const; + void SetDebugFindOutput(bool b) { this->DebugFindOutput = b; } + void SetDebugFindOutputPkgs(std::string const& args); + void SetDebugFindOutputVars(std::string const& args); //! Do we want trace output during the cmake run. bool GetTrace() const { return this->Trace; } @@ -583,8 +611,8 @@ public: //! run the --build option int Build(int jobs, std::string dir, std::vector<std::string> targets, std::string config, std::vector<std::string> nativeOptions, - bool clean, bool verbose, const std::string& presetName, - bool listPresets); + cmBuildOptions& buildOptions, bool verbose, + const std::string& presetName, bool listPresets); //! run the --open option bool Open(const std::string& dir, bool dryRun); @@ -644,7 +672,7 @@ protected: */ int CheckBuildSystem(); - void SetDirectoriesFromFile(const std::string& arg); + bool SetDirectoriesFromFile(const std::string& arg); //! Make sure all commands are what they say they are and there is no /// macros. @@ -687,7 +715,7 @@ private: std::string GraphVizFile; InstalledFilesMap InstalledFiles; #ifndef CMAKE_BOOTSTRAP - std::map<std::string, cm::optional<cmCMakePresetsFile::CacheVariable>> + std::map<std::string, cm::optional<cmCMakePresetsGraph::CacheVariable>> UnprocessedPresetVariables; std::map<std::string, cm::optional<std::string>> UnprocessedPresetEnvironment; @@ -704,6 +732,9 @@ private: std::vector<std::string> TraceOnlyThisSources; + std::set<std::string> DebugFindPkgs; + std::set<std::string> DebugFindVars; + LogLevel MessageLogLevel = LogLevel::LOG_STATUS; bool LogLevelWasSetViaCLI = false; bool LogContext = false; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 6090ec4..0554c3e 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -5,6 +5,7 @@ #include <algorithm> #include <cassert> +#include <cctype> #include <climits> #include <cstdio> #include <cstring> @@ -19,6 +20,7 @@ #include <cm3p/uv.h> +#include "cmBuildOptions.h" #include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" #include "cmDocumentationEntry.h" // IWYU pragma: keep @@ -90,6 +92,10 @@ const char* cmDocumentationOptions[][2] = { "useful on one try_compile at a time." }, { "--debug-output", "Put cmake in a debug mode." }, { "--debug-find", "Put cmake find in a debug mode." }, + { "--debug-find-pkg=<pkg-name>[,...]", + "Limit cmake debug-find to the comma-separated list of packages" }, + { "--debug-find-var=<var-name>[,...]", + "Limit cmake debug-find to the comma-separated list of result variables" }, { "--trace", "Put cmake in trace mode." }, { "--trace-expand", "Put cmake in trace mode with variable expansion." }, { "--trace-format=<human|json-v1>", "Set the output format of the trace." }, @@ -441,6 +447,7 @@ int do_build(int ac, char const* const* av) bool cleanFirst = false; bool foundClean = false; bool foundNonClean = false; + PackageResolveMode resolveMode = PackageResolveMode::Default; bool verbose = cmSystemTools::HasEnv("VERBOSE"); std::string presetName; bool listPresets = false; @@ -474,6 +481,22 @@ int do_build(int ac, char const* const* av) } return false; }; + auto resolvePackagesLambda = [&](std::string const& value) -> bool { + std::string v = value; + std::transform(v.begin(), v.end(), v.begin(), ::tolower); + + if (v == "on") { + resolveMode = PackageResolveMode::Force; + } else if (v == "only") { + resolveMode = PackageResolveMode::OnlyResolve; + } else if (v == "off") { + resolveMode = PackageResolveMode::Disable; + } else { + return false; + } + + return true; + }; auto verboseLambda = [&](std::string const&) -> bool { verbose = true; return true; @@ -510,6 +533,8 @@ int do_build(int ac, char const* const* av) cleanFirst = true; return true; } }, + CommandArgument{ "--resolve-package-references", + CommandArgument::Values::One, resolvePackagesLambda }, CommandArgument{ "-v", CommandArgument::Values::Zero, verboseLambda }, CommandArgument{ "--verbose", CommandArgument::Values::Zero, verboseLambda }, @@ -635,6 +660,8 @@ int do_build(int ac, char const* const* av) " --config <cfg> = For multi-configuration tools, choose <cfg>.\n" " --clean-first = Build target 'clean' first, then build.\n" " (To clean only, use --target 'clean'.)\n" + " --resolve-package-references={on|only|off}\n" + " = Restore/resolve package references during build.\n" " --verbose, -v = Enable verbose output - if supported - including\n" " the build commands to be executed. \n" " -- = Pass remaining options to the native tool.\n" @@ -652,8 +679,10 @@ int do_build(int ac, char const* const* av) cmakemainProgressCallback(msg, prog, &cm); }); + cmBuildOptions buildOptions(cleanFirst, false, resolveMode); + return cm.Build(jobs, std::move(dir), std::move(targets), std::move(config), - std::move(nativeOptions), cleanFirst, verbose, presetName, + std::move(nativeOptions), buildOptions, verbose, presetName, listPresets); #endif } diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index 5c27ac1..8921aa0 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -294,7 +294,8 @@ int main() return exit_code; // compile rc file with rc.exe - return process(srcfilename, "", objfile, prefix, binpath + " " + rest); + return process(srcfilename, "", objfile, prefix, binpath + " " + rest, + std::string(), true); } usage("Invalid language specified."); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index bdddc4e..32c01e5 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -58,7 +58,6 @@ #ifdef _WIN32 # include <fcntl.h> // for _O_BINARY # include <io.h> // for _setmode -# include <stdio.h> // for std{out,err} and fileno #endif #include <cm/string_view> @@ -1112,7 +1111,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, int count; if (countFile) { if (1 != fscanf(countFile, "%i", &count)) { - cmSystemTools::Message("Could not read from count file."); + std::cerr << "Could not read from count file.\n"; } fclose(countFile); } else { @@ -1426,8 +1425,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, action = cmSystemTools::TarActionExtract; } break; default: { - cmSystemTools::Message( - std::string("tar: Unknown argument: ") + flag, "Warning"); + std::cerr << "tar: Unknown argument: " << flag << "\n"; } } } @@ -1448,8 +1446,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, } } else if (action == cmSystemTools::TarActionCreate) { if (files.empty()) { - cmSystemTools::Message("tar: No files or directories specified", - "Warning"); + std::cerr << "tar: No files or directories specified\n"; } if (!cmSystemTools::CreateTar(outFile, files, compress, verbose, mtime, format)) { @@ -1588,7 +1585,11 @@ int cmcmd::HashSumFile(std::vector<std::string> const& args, std::cerr << "Error: " << filename << " is a directory" << std::endl; retval++; } else { - std::string value = cmSystemTools::ComputeFileHash(filename, algo); + std::string value +#ifndef CMAKE_BOOTSTRAP + = cmSystemTools::ComputeFileHash(filename, algo) +#endif + ; if (value.empty()) { // To mimic "md5sum/shasum" behavior in a shell: std::cerr << filename << ": No such file or directory" << std::endl; @@ -1684,7 +1685,7 @@ static void cmcmdProgressReport(std::string const& dir, std::string const& num) return; } if (1 != fscanf(progFile, "%i", &count)) { - cmSystemTools::Message("Could not read from progress file."); + std::cerr << "Could not read from progress file.\n"; } fclose(progFile); @@ -2135,8 +2136,8 @@ struct NumberFormatter { } }; -std::ostream& operator<<(std::ostream& stream, - NumberFormatter const& formatter) +static std::ostream& operator<<(std::ostream& stream, + NumberFormatter const& formatter) { auto const& flags = stream.flags(); if (formatter.Format == FORMAT_DECIMAL) { diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 7da5971..2253a83 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -192,6 +192,7 @@ endif() if(KWSYS_USE_Directory) set(KWSYS_USE_Encoding 1) set(KWSYS_USE_Status 1) + set(KWSYS_USE_SystemTools 1) endif() if(KWSYS_USE_DynamicLoader) set(KWSYS_USE_Encoding 1) diff --git a/Source/kwsys/CTestConfig.cmake b/Source/kwsys/CTestConfig.cmake index 12347b6..6484cc2 100644 --- a/Source/kwsys/CTestConfig.cmake +++ b/Source/kwsys/CTestConfig.cmake @@ -3,9 +3,7 @@ set(CTEST_PROJECT_NAME "KWSys") set(CTEST_NIGHTLY_START_TIME "21:00:00 EDT") -if (NOT CTEST_DROP_METHOD STREQUAL "https") - set(CTEST_DROP_METHOD "http") -endif () +set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "open.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=PublicDashboard") set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in index 29a2dd1..8d47340 100644 --- a/Source/kwsys/Configure.hxx.in +++ b/Source/kwsys/Configure.hxx.in @@ -16,11 +16,11 @@ @KWSYS_SYSTEMTOOLS_USE_TRANSLATION_MAP@ #if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute) -# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x) +# define @KWSYS_NAMESPACE@_has_cpp_attribute(x) __has_attribute(x) #elif defined(__has_cpp_attribute) -# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x) +# define @KWSYS_NAMESPACE@_has_cpp_attribute(x) __has_cpp_attribute(x) #else -# define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0 +# define @KWSYS_NAMESPACE@_has_cpp_attribute(x) 0 #endif #if __cplusplus >= 201103L @@ -31,13 +31,13 @@ #ifndef @KWSYS_NAMESPACE@_FALLTHROUGH # if __cplusplus >= 201703L && \ - @KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough) + @KWSYS_NAMESPACE@_has_cpp_attribute(fallthrough) # define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]] # elif __cplusplus >= 201103L && \ - @KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough) + @KWSYS_NAMESPACE@_has_cpp_attribute(gnu::fallthrough) # define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]] # elif __cplusplus >= 201103L && \ - @KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough) + @KWSYS_NAMESPACE@_has_cpp_attribute(clang::fallthrough) # define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]] # endif #endif @@ -45,7 +45,7 @@ # define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast<void>(0) #endif -#undef @KWSYS_NAMESPACE@__has_cpp_attribute +#undef @KWSYS_NAMESPACE@_has_cpp_attribute /* If building a C++ file in kwsys itself, give the source file access to the macros without a configured namespace. */ diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx index 2e8aa83..d520c14 100644 --- a/Source/kwsys/Directory.cxx +++ b/Source/kwsys/Directory.cxx @@ -7,6 +7,8 @@ #include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(SystemTools.hxx) + // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. #if 0 @@ -16,15 +18,48 @@ #endif #include <string> +#include <utility> #include <vector> +#if defined(_WIN32) && !defined(__CYGWIN__) +# include <windows.h> + +# include <ctype.h> +# include <fcntl.h> +# include <io.h> +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# include <sys/stat.h> +# include <sys/types.h> +#endif + namespace KWSYS_NAMESPACE { class DirectoryInternals { public: + struct FileData + { + std::string Name; +#if defined(_WIN32) && !defined(__CYGWIN__) + _wfinddata_t FindData; +#endif + FileData(std::string name +#if defined(_WIN32) && !defined(__CYGWIN__) + , + _wfinddata_t data +#endif + ) + : Name(std::move(name)) +#if defined(_WIN32) && !defined(__CYGWIN__) + , FindData(std::move(data)) +#endif + { + } + }; // Array of Files - std::vector<std::string> Files; + std::vector<FileData> Files; // Path to Open'ed directory std::string Path; @@ -59,10 +94,45 @@ unsigned long Directory::GetNumberOfFiles() const const char* Directory::GetFile(unsigned long dindex) const { - if (dindex >= this->Internal->Files.size()) { - return nullptr; + return this->Internal->Files[dindex].Name.c_str(); +} + +std::string const& Directory::GetFileName(std::size_t i) const +{ + return this->Internal->Files[i].Name; +} + +std::string Directory::GetFilePath(std::size_t i) const +{ + std::string abs = this->Internal->Path; + if (!abs.empty() && abs.back() != '/') { + abs += '/'; } - return this->Internal->Files[dindex].c_str(); + abs += this->Internal->Files[i].Name; + return abs; +} + +bool Directory::FileIsDirectory(std::size_t i) const +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + _wfinddata_t const& data = this->Internal->Files[i].FindData; + return (data.attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; +#else + std::string const& path = this->GetFilePath(i); + return kwsys::SystemTools::FileIsDirectory(path); +#endif +} + +bool Directory::FileIsSymlink(std::size_t i) const +{ + std::string const& path = this->GetFilePath(i); +#if defined(_WIN32) && !defined(__CYGWIN__) + _wfinddata_t const& data = this->Internal->Files[i].FindData; + return kwsys::SystemTools::FileIsSymlinkWithAttr( + Encoding::ToWindowsExtendedPath(path), data.attrib); +#else + return kwsys::SystemTools::FileIsSymlink(path); +#endif } const char* Directory::GetPath() const @@ -81,16 +151,6 @@ void Directory::Clear() // First Windows platforms #if defined(_WIN32) && !defined(__CYGWIN__) -# include <windows.h> - -# include <ctype.h> -# include <fcntl.h> -# include <io.h> -# include <stdio.h> -# include <stdlib.h> -# include <string.h> -# include <sys/stat.h> -# include <sys/types.h> namespace KWSYS_NAMESPACE { @@ -99,18 +159,21 @@ Status Directory::Load(std::string const& name, std::string* errorMessage) this->Clear(); intptr_t srchHandle; char* buf; + size_t bufLength; size_t n = name.size(); if (name.back() == '/' || name.back() == '\\') { - buf = new char[n + 1 + 1]; - sprintf(buf, "%s*", name.c_str()); + bufLength = n + 1 + 1; + buf = new char[bufLength]; + snprintf(buf, bufLength, "%s*", name.c_str()); } else { // Make sure the slashes in the wildcard suffix are consistent with the // rest of the path - buf = new char[n + 2 + 1]; + bufLength = n + 2 + 1; + buf = new char[bufLength]; if (name.find('\\') != std::string::npos) { - sprintf(buf, "%s\\*", name.c_str()); + snprintf(buf, bufLength, "%s\\*", name.c_str()); } else { - sprintf(buf, "%s/*", name.c_str()); + snprintf(buf, bufLength, "%s/*", name.c_str()); } } struct _wfinddata_t data; // data of current file @@ -130,7 +193,7 @@ Status Directory::Load(std::string const& name, std::string* errorMessage) // Loop through names do { - this->Internal->Files.push_back(Encoding::ToNarrow(data.name)); + this->Internal->Files.emplace_back(Encoding::ToNarrow(data.name), data); } while (_wfindnext(srchHandle, &data) != -1); this->Internal->Path = name; if (_findclose(srchHandle) == -1) { @@ -148,13 +211,16 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name, { intptr_t srchHandle; char* buf; + size_t bufLength; size_t n = name.size(); if (name.back() == '/') { + bufLength = n + 1 + 1; buf = new char[n + 1 + 1]; - sprintf(buf, "%s*", name.c_str()); + snprintf(buf, bufLength, "%s*", name.c_str()); } else { + bufLength = n + 2 + 1; buf = new char[n + 2 + 1]; - sprintf(buf, "%s/*", name.c_str()); + snprintf(buf, bufLength, "%s/*", name.c_str()); } struct _wfinddata_t data; // data of current file diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in index d501116..9d0f462 100644 --- a/Source/kwsys/Directory.hxx.in +++ b/Source/kwsys/Directory.hxx.in @@ -6,6 +6,7 @@ #include <@KWSYS_NAMESPACE@/Configure.h> #include <@KWSYS_NAMESPACE@/Status.hxx> +#include <cstddef> #include <string> namespace @KWSYS_NAMESPACE@ { @@ -55,6 +56,26 @@ public: const char* GetFile(unsigned long) const; /** + * Return the name of the file at the given 0-based index. + */ + std::string const& GetFileName(std::size_t i) const; + + /** + * Return the absolute path to the file at the given 0-based index. + */ + std::string GetFilePath(std::size_t i) const; + + /** + * Return whether the file at the given 0-based index is a directory. + */ + bool FileIsDirectory(std::size_t i) const; + + /** + * Return whether the file at the given 0-based index is a symlink. + */ + bool FileIsSymlink(std::size_t i) const; + + /** * Return the path to Open'ed directory */ const char* GetPath() const; diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx index 66ee9ea..8afc2e8 100644 --- a/Source/kwsys/DynamicLoader.cxx +++ b/Source/kwsys/DynamicLoader.cxx @@ -275,20 +275,20 @@ const char* DynamicLoader::LastError() if (length < 1) { /* FormatMessage failed. Use a default message. */ - _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, - "DynamicLoader encountered error 0x%X. " - "FormatMessage failed with error 0x%X", - error, GetLastError()); + snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, + "DynamicLoader encountered error 0x%lX. " + "FormatMessage failed with error 0x%lX", + error, GetLastError()); return str; } if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str, DYNLOAD_ERROR_BUFFER_SIZE, nullptr, nullptr)) { /* WideCharToMultiByte failed. Use a default message. */ - _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, - "DynamicLoader encountered error 0x%X. " - "WideCharToMultiByte failed with error 0x%X", - error, GetLastError()); + snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE, + "DynamicLoader encountered error 0x%lX. " + "WideCharToMultiByte failed with error 0x%lX", + error, GetLastError()); } return str; @@ -436,9 +436,14 @@ namespace KWSYS_NAMESPACE { DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( const std::string& libname, int flags) { - CHECK_OPEN_FLAGS(flags, 0, nullptr); + CHECK_OPEN_FLAGS(flags, RTLDGlobal, nullptr); + + int llFlags = RTLD_LAZY; + if (flags & RTLDGlobal) { + llFlags |= RTLD_GLOBAL; + } - return dlopen(libname.c_str(), RTLD_LAZY); + return dlopen(libname.c_str(), llFlags); } int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) diff --git a/Source/kwsys/DynamicLoader.hxx.in b/Source/kwsys/DynamicLoader.hxx.in index 539c742..4edd31c 100644 --- a/Source/kwsys/DynamicLoader.hxx.in +++ b/Source/kwsys/DynamicLoader.hxx.in @@ -73,7 +73,12 @@ public: // This is currently only supported on Windows. SearchBesideLibrary = 0x00000001, - AllOpenFlags = SearchBesideLibrary + // Make loaded symbols visible globally + // + // This is currently only supported on *nix systems. + RTLDGlobal = 0x00000002, + + AllOpenFlags = SearchBesideLibrary | RTLDGlobal }; /** Load a dynamic library into the current process. diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx index c6d4b19..fa2c295 100644 --- a/Source/kwsys/Glob.cxx +++ b/Source/kwsys/Glob.cxx @@ -213,8 +213,8 @@ bool Glob::RecurseDirectory(std::string::size_type start, fname = kwsys::SystemTools::LowerCase(fname); #endif - bool isDir = kwsys::SystemTools::FileIsDirectory(realname); - bool isSymLink = kwsys::SystemTools::FileIsSymlink(realname); + bool isDir = d.FileIsDirectory(cc); + bool isSymLink = d.FileIsSymlink(cc); if (isDir && (!isSymLink || this->RecurseThroughSymlinks)) { if (isSymLink) { diff --git a/Source/kwsys/MD5.c b/Source/kwsys/MD5.c index fb18a5b..76995e2 100644 --- a/Source/kwsys/MD5.c +++ b/Source/kwsys/MD5.c @@ -10,6 +10,7 @@ #endif #include <stddef.h> /* size_t */ +#include <stdint.h> /* uintptr_t */ #include <stdlib.h> /* malloc, free */ #include <string.h> /* memcpy, strlen */ @@ -202,7 +203,7 @@ static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/) * On little-endian machines, we can process properly aligned * data without copying it. */ - if (!((data - (const md5_byte_t*)0) & 3)) { + if (!((uintptr_t)data & 3)) { /* data are properly aligned */ X = (const md5_word_t*)data; } else { diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index a8a15dd..19bf982 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -41,6 +41,12 @@ do. /* Increase the file descriptor limit for select() before including related system headers. (Default: 64) */ # define FD_SETSIZE 16384 +#elif defined(__APPLE__) +/* Increase the file descriptor limit for select() before including + related system headers. (Default: 1024) */ +# define _DARWIN_UNLIMITED_SELECT +# include <limits.h> /* OPEN_MAX */ +# define FD_SETSIZE OPEN_MAX #endif #include <assert.h> /* assert */ @@ -2287,7 +2293,8 @@ static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int sig, #endif default: cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; - sprintf(cp->ProcessResults[idx].ExitExceptionString, "Signal %d", sig); + snprintf(cp->ProcessResults[idx].ExitExceptionString, + KWSYSPE_PIPE_BUFFER_SIZE + 1, "Signal %d", sig); break; } } @@ -2540,7 +2547,7 @@ static void kwsysProcessKill(pid_t process_id) int pid; if (sscanf(d->d_name, "%d", &pid) == 1 && pid != 0) { struct stat finfo; - sprintf(fname, "/proc/%d/stat", pid); + snprintf(fname, sizeof(fname), "/proc/%d/stat", pid); if (stat(fname, &finfo) == 0) { FILE* f = fopen(fname, "r"); if (f) { diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 8f01684..e97973e 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -29,7 +29,7 @@ a UNIX-style select system call. # define KWSYS_WINDOWS_DEPRECATED_GetVersionEx #endif #include <io.h> /* _unlink */ -#include <stdio.h> /* sprintf */ +#include <stdio.h> /* snprintf */ #include <string.h> /* strlen, strdup */ #ifndef _MAX_FNAME @@ -1867,18 +1867,18 @@ void kwsysProcessCleanup(kwsysProcess* cp, DWORD error) KWSYSPE_PIPE_BUFFER_SIZE, 0); if (length < 1) { /* FormatMessage failed. Use a default message. */ - _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, - "Process execution failed with error 0x%X. " - "FormatMessage failed with error 0x%X", - error, GetLastError()); + snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, + "Process execution failed with error 0x%lX. " + "FormatMessage failed with error 0x%lX", + error, GetLastError()); } if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) { /* WideCharToMultiByte failed. Use a default message. */ - _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, - "Process execution failed with error 0x%X. " - "WideCharToMultiByte failed with error 0x%X", - error, GetLastError()); + snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, + "Process execution failed with error 0x%lX. " + "WideCharToMultiByte failed with error 0x%lX", + error, GetLastError()); } } @@ -2144,8 +2144,8 @@ static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, case STATUS_NO_MEMORY: default: cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; - _snprintf(cp->ProcessResults[idx].ExitExceptionString, - KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code); + snprintf(cp->ProcessResults[idx].ExitExceptionString, + KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code); break; } } diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in index 091334b..d6ae75c 100644 --- a/Source/kwsys/SharedForward.h.in +++ b/Source/kwsys/SharedForward.h.in @@ -457,9 +457,9 @@ static void kwsys_shared_forward_strerror(char* message) message, KWSYS_SHARED_FORWARD_MAXPATH, 0); if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) { /* FormatMessage failed. Use a default message. */ - _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, - "Error 0x%X (FormatMessage failed with error 0x%X)", original, - GetLastError()); + snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, + "Error 0x%lX (FormatMessage failed with error 0x%lX)", original, + GetLastError()); } # else /* Implementation for UNIX. */ diff --git a/Source/kwsys/Status.cxx b/Source/kwsys/Status.cxx index 503d1e1..edda7a0 100644 --- a/Source/kwsys/Status.cxx +++ b/Source/kwsys/Status.cxx @@ -53,7 +53,7 @@ std::string Status::GetString() const LocalFree(message); } break; #endif - }; + } return err; } diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index f2bf85f..e6cc48f 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -1265,9 +1265,10 @@ public: } private: - void* GetRealAddress() const + size_t GetRealAddress() const { - return (void*)((char*)this->Address - (char*)this->BinaryBaseAddress); + return static_cast<size_t>(static_cast<char*>(this->Address) - + static_cast<char*>(this->BinaryBaseAddress)); } std::string GetFileName(const std::string& path) const; @@ -2789,19 +2790,20 @@ bool SystemInformationImplementation::RetrieveProcessorSerialNumber() // ; ecx: middle 32 bits are the processor signature bits // ; edx: bottom 32 bits are the processor signature bits char sn[128]; - sprintf(sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", - ((SerialNumber[1] & 0xff000000) >> 24), - ((SerialNumber[1] & 0x00ff0000) >> 16), - ((SerialNumber[1] & 0x0000ff00) >> 8), - ((SerialNumber[1] & 0x000000ff) >> 0), - ((SerialNumber[2] & 0xff000000) >> 24), - ((SerialNumber[2] & 0x00ff0000) >> 16), - ((SerialNumber[2] & 0x0000ff00) >> 8), - ((SerialNumber[2] & 0x000000ff) >> 0), - ((SerialNumber[3] & 0xff000000) >> 24), - ((SerialNumber[3] & 0x00ff0000) >> 16), - ((SerialNumber[3] & 0x0000ff00) >> 8), - ((SerialNumber[3] & 0x000000ff) >> 0)); + snprintf(sn, sizeof(sn), + "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x", + ((SerialNumber[1] & 0xff000000) >> 24), + ((SerialNumber[1] & 0x00ff0000) >> 16), + ((SerialNumber[1] & 0x0000ff00) >> 8), + ((SerialNumber[1] & 0x000000ff) >> 0), + ((SerialNumber[2] & 0xff000000) >> 24), + ((SerialNumber[2] & 0x00ff0000) >> 16), + ((SerialNumber[2] & 0x0000ff00) >> 8), + ((SerialNumber[2] & 0x000000ff) >> 0), + ((SerialNumber[3] & 0xff000000) >> 24), + ((SerialNumber[3] & 0x00ff0000) >> 16), + ((SerialNumber[3] & 0x0000ff00) >> 8), + ((SerialNumber[3] & 0x000000ff) >> 0)); this->ChipID.SerialNumber = sn; return true; @@ -3260,6 +3262,9 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() case 0x3b: this->ChipID.ProcessorName = "Zhaoxin kx6000"; break; + case 0x5b: + this->ChipID.ProcessorName = "Zhaoxin kh40000"; + break; default: this->ChipID.ProcessorName = "Unknown IDT\\Centaur\\VIA\\Zhaoxin family"; @@ -3293,6 +3298,9 @@ bool SystemInformationImplementation::RetrieveClassicalCPUIdentity() case 0x3b: this->ChipID.ProcessorName = "Zhaoxin kx6000"; break; + case 0x5b: + this->ChipID.ProcessorName = "Zhaoxin kh40000"; + break; default: this->ChipID.ProcessorName = "Unknown Zhaoxin family"; return false; @@ -3749,24 +3757,24 @@ long long SystemInformationImplementation::GetProcMemoryAvailable( ResourceLimitType rlim; ierr = GetResourceLimit(RLIMIT_DATA, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail); } ierr = GetResourceLimit(RLIMIT_AS, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail); } #elif defined(__APPLE__) struct rlimit rlim; int ierr; ierr = getrlimit(RLIMIT_DATA, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail); } ierr = getrlimit(RLIMIT_RSS, &rlim); if ((ierr == 0) && (rlim.rlim_cur != RLIM_INFINITY)) { - memAvail = min((long long)rlim.rlim_cur / 1024, memAvail); + memAvail = min(static_cast<long long>(rlim.rlim_cur) / 1024, memAvail); } #endif @@ -4068,7 +4076,7 @@ void SystemInformationImplementation::SetStackTraceOnError(int enable) // install ours struct sigaction sa; - sa.sa_sigaction = (SigAction)StacktraceSignalHandler; + sa.sa_sigaction = static_cast<SigAction>(StacktraceSignalHandler); sa.sa_flags = SA_SIGINFO | SA_RESETHAND; # ifdef SA_RESTART sa.sa_flags |= SA_RESTART; @@ -4564,7 +4572,8 @@ bool SystemInformationImplementation::ParseSysCtl() this->AvailablePhysicalMemory = 0; vm_statistics_data_t vmstat; mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, + if (host_statistics(mach_host_self(), HOST_VM_INFO, + reinterpret_cast<host_info_t>(&vmstat), &count) == KERN_SUCCESS) { err = kw_sysctlbyname_int64("hw.pagesize", &tempInt64); if (err == 0) { @@ -5395,8 +5404,8 @@ bool SystemInformationImplementation::QueryOSInformation() } } - sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); + snprintf(operatingSystem, sizeof(operatingSystem), "%ls (Build %ld)", + osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF); this->OSVersion = operatingSystem; } else # endif // VER_NT_WORKSTATION @@ -5439,9 +5448,10 @@ bool SystemInformationImplementation::QueryOSInformation() // Display version, service pack (if any), and build number. if (osvi.dwMajorVersion <= 4) { // NB: NT 4.0 and earlier. - sprintf(operatingSystem, "version %ld.%ld %ls (Build %ld)", - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); + snprintf(operatingSystem, sizeof(operatingSystem), + "version %ld.%ld %ls (Build %ld)", osvi.dwMajorVersion, + osvi.dwMinorVersion, osvi.szCSDVersion, + osvi.dwBuildNumber & 0xFFFF); this->OSVersion = operatingSystem; } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { // Windows XP and .NET server. @@ -5467,8 +5477,8 @@ bool SystemInformationImplementation::QueryOSInformation() } } else { // Windows 2000 and everything else. - sprintf(operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, - osvi.dwBuildNumber & 0xFFFF); + snprintf(operatingSystem, sizeof(operatingSystem), "%ls (Build %ld)", + osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF); this->OSVersion = operatingSystem; } break; diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 930d84c..c38b456 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -34,6 +34,10 @@ #include <utility> #include <vector> +#ifdef _WIN32 +# include <cwchar> +#endif + // Work-around CMake dependency scanning limitation. This must // duplicate the above list of headers. #if 0 @@ -103,6 +107,9 @@ # if defined(_MSC_VER) && _MSC_VER >= 1800 # define KWSYS_WINDOWS_DEPRECATED_GetVersionEx # endif +# ifndef IO_REPARSE_TAG_APPEXECLINK +# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL) +# endif // from ntifs.h, which can only be used by drivers typedef struct _REPARSE_DATA_BUFFER { @@ -132,8 +139,46 @@ typedef struct _REPARSE_DATA_BUFFER { UCHAR DataBuffer[1]; } GenericReparseBuffer; + struct + { + ULONG Version; + WCHAR StringList[1]; + // In version 3, there are 4 NUL-terminated strings: + // * Package ID + // * Entry Point + // * Executable Path + // * Application Type + } AppExecLinkReparseBuffer; } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +namespace { +WCHAR* GetAppExecLink(PREPARSE_DATA_BUFFER data, size_t& len) +{ + // We only know the layout of version 3. + if (data->AppExecLinkReparseBuffer.Version != 3) { + return nullptr; + } + + WCHAR* pstr = data->AppExecLinkReparseBuffer.StringList; + + // Skip the package id and entry point strings. + for (int i = 0; i < 2; ++i) { + len = std::wcslen(pstr); + if (len == 0) { + return nullptr; + } + pstr += len + 1; + } + + // The third string is the executable path. + len = std::wcslen(pstr); + if (len == 0) { + return nullptr; + } + return pstr; +} +} #endif #if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H @@ -1343,8 +1388,8 @@ bool SystemTools::FileExists(const std::string& filename) return false; } #if defined(_WIN32) - DWORD attr = - GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str()); + const std::wstring path = Encoding::ToWindowsExtendedPath(filename); + DWORD attr = GetFileAttributesW(path.c_str()); if (attr == INVALID_FILE_ATTRIBUTES) { return false; } @@ -1352,12 +1397,38 @@ bool SystemTools::FileExists(const std::string& filename) if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { // Using 0 instead of GENERIC_READ as it allows reading of file attributes // even if we do not have permission to read the file itself - HANDLE handle = - CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + HANDLE handle = CreateFileW(path.c_str(), 0, 0, nullptr, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (handle == INVALID_HANDLE_VALUE) { - return false; + // A reparse point may be an execution alias (Windows Store app), which + // is similar to a symlink but it cannot be opened as a regular file. + // We must look at the reparse point data explicitly. + handle = CreateFileW( + path.c_str(), 0, 0, nullptr, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr); + + if (handle == INVALID_HANDLE_VALUE) { + return false; + } + + byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + DWORD bytesReturned = 0; + + if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, + nullptr)) { + CloseHandle(handle); + return false; + } + + CloseHandle(handle); + + PREPARSE_DATA_BUFFER data = + reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0]); + + // Assume that file exists if it is an execution alias. + return data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK; } CloseHandle(handle); @@ -2216,7 +2287,7 @@ bool SystemTools::FilesDiffer(const std::string& source, if (statSource.nFileSizeHigh == 0 && statSource.nFileSizeLow == 0) { return false; } - off_t nleft = + auto nleft = ((__int64)statSource.nFileSizeHigh << 32) + statSource.nFileSizeLow; #else @@ -3011,18 +3082,13 @@ bool SystemTools::FileIsDirectory(const std::string& inName) bool SystemTools::FileIsExecutable(const std::string& name) { -#if defined(_WIN32) - return SystemTools::FileExists(name, true); -#else return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE); -#endif } -bool SystemTools::FileIsSymlink(const std::string& name) -{ #if defined(_WIN32) - std::wstring path = Encoding::ToWindowsExtendedPath(name); - DWORD attr = GetFileAttributesW(path.c_str()); +bool SystemTools::FileIsSymlinkWithAttr(const std::wstring& path, + unsigned long attr) +{ if (attr != INVALID_FILE_ATTRIBUTES) { if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { // FILE_ATTRIBUTE_REPARSE_POINT means: @@ -3051,9 +3117,17 @@ bool SystemTools::FileIsSymlink(const std::string& name) (reparseTag == IO_REPARSE_TAG_MOUNT_POINT); } return false; - } else { - return false; } + + return false; +} +#endif + +bool SystemTools::FileIsSymlink(const std::string& name) +{ +#if defined(_WIN32) + std::wstring path = Encoding::ToWindowsExtendedPath(name); + return FileIsSymlinkWithAttr(path, GetFileAttributesW(path.c_str())); #else struct stat fs; if (lstat(name.c_str(), &fs) == 0) { @@ -3164,6 +3238,15 @@ Status SystemTools::ReadSymlink(std::string const& newName, data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR); substituteNameData = data->MountPointReparseBuffer.PathBuffer + data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR); + } else if (data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) { + // The reparse buffer is a list of 0-terminated non-empty strings, + // terminated by an empty string (0-0). We need the third string. + size_t destLen; + substituteNameData = GetAppExecLink(data, destLen); + if (substituteNameData == nullptr || destLen == 0) { + return Status::Windows(ERROR_SYMLINK_NOT_SUPPORTED); + } + substituteNameLength = static_cast<USHORT>(destLen); } else { return Status::Windows(ERROR_REPARSE_TAG_MISMATCH); } @@ -3767,6 +3850,32 @@ bool SystemTools::Split(const std::string& str, return true; } +std::string SystemTools::Join(const std::vector<std::string>& list, + const std::string& separator) +{ + std::string result; + if (list.empty()) { + return result; + } + + size_t total_size = separator.size() * (list.size() - 1); + for (const std::string& string : list) { + total_size += string.size(); + } + + result.reserve(total_size); + bool needs_separator = false; + for (const std::string& string : list) { + if (needs_separator) { + result += separator; + } + result += string; + needs_separator = true; + } + + return result; +} + /** * Return path of a full filename (no trailing slashes). * Warning: returned path is converted to Unix slashes format. @@ -4148,9 +4257,9 @@ std::string SystemTools::MakeCidentifier(const std::string& s) // Convenience function around std::getline which removes a trailing carriage // return and can truncate the buffer as needed. Returns true // if any data were read before the end-of-file was reached. -bool SystemTools::GetLineFromStream(std::istream& is, std::string& line, - bool* has_newline /* = 0 */, - long sizeLimit /* = -1 */) +bool SystemTools::GetLineFromStream( + std::istream& is, std::string& line, bool* has_newline /* = 0 */, + std::string::size_type sizeLimit /* = std::string::npos */) { // Start with an empty line. line = ""; @@ -4175,7 +4284,7 @@ bool SystemTools::GetLineFromStream(std::istream& is, std::string& line, } // if we read too much then truncate the buffer - if (sizeLimit >= 0 && line.size() >= static_cast<size_t>(sizeLimit)) { + if (sizeLimit != std::string::npos && line.size() > sizeLimit) { line.resize(sizeLimit); } } @@ -4526,10 +4635,10 @@ std::string SystemTools::GetOperatingSystemNameAndVersion() } res += " "; - sprintf(buffer, "%ld", osvi.dwMajorVersion); + snprintf(buffer, sizeof(buffer), "%ld", osvi.dwMajorVersion); res += buffer; res += "."; - sprintf(buffer, "%ld", osvi.dwMinorVersion); + snprintf(buffer, sizeof(buffer), "%ld", osvi.dwMinorVersion); res += buffer; } @@ -4549,7 +4658,7 @@ std::string SystemTools::GetOperatingSystemNameAndVersion() if (lRet == ERROR_SUCCESS) { res += " Service Pack 6a (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); + snprintf(buffer, sizeof(buffer), "%ld", osvi.dwBuildNumber & 0xFFFF); res += buffer; res += ")"; } else // Windows NT 4.0 prior to SP6a @@ -4557,7 +4666,7 @@ std::string SystemTools::GetOperatingSystemNameAndVersion() res += " "; res += osvi.szCSDVersion; res += " (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); + snprintf(buffer, sizeof(buffer), "%ld", osvi.dwBuildNumber & 0xFFFF); res += buffer; res += ")"; } @@ -4568,7 +4677,7 @@ std::string SystemTools::GetOperatingSystemNameAndVersion() res += " "; res += osvi.szCSDVersion; res += " (Build "; - sprintf(buffer, "%ld", osvi.dwBuildNumber & 0xFFFF); + snprintf(buffer, sizeof(buffer), "%ld", osvi.dwBuildNumber & 0xFFFF); res += buffer; res += ")"; } diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index e5d115e..acce015 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -214,6 +214,13 @@ public: char separator); /** + * Joins a vector of strings into a single string, with separator in between + * each string. + */ + static std::string Join(const std::vector<std::string>& list, + const std::string& separator); + + /** * Return string with space added between capitalized words * (i.e. EatMyShorts becomes Eat My Shorts ) * (note that IEatShorts becomes IEat Shorts) @@ -516,9 +523,9 @@ public: * end-of-file was reached. If the has_newline argument is specified, it will * be true when the line read had a newline character. */ - static bool GetLineFromStream(std::istream& istr, std::string& line, - bool* has_newline = nullptr, - long sizeLimit = -1); + static bool GetLineFromStream( + std::istream& istr, std::string& line, bool* has_newline = nullptr, + std::string::size_type sizeLimit = std::string::npos); /** * Get the parent directory of the directory or file @@ -681,6 +688,16 @@ public: */ static bool FileIsExecutable(const std::string& name); +#if defined(_WIN32) + /** + * Return true if the file with FileAttributes `attr` is a symlink + * Only available on Windows. This avoids an expensive `GetFileAttributesW` + * call. + */ + static bool FileIsSymlinkWithAttr(const std::wstring& path, + unsigned long attr); +#endif + /** * Return true if the file is a symlink */ diff --git a/Source/kwsys/testDirectory.cxx b/Source/kwsys/testDirectory.cxx index a847462..79bdc98 100644 --- a/Source/kwsys/testDirectory.cxx +++ b/Source/kwsys/testDirectory.cxx @@ -19,7 +19,7 @@ file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ #include <testSystemTools.h> -int _doLongPathTest() +static int _doLongPathTest() { using namespace kwsys; static const int LONG_PATH_THRESHOLD = 512; @@ -77,7 +77,7 @@ int _doLongPathTest() return res; } -int _nonExistentDirectoryTest() +static int _nonExistentDirectoryTest() { using namespace kwsys; int res = 0; @@ -105,7 +105,7 @@ int _nonExistentDirectoryTest() return res; } -int _copyDirectoryTest() +static int _copyDirectoryTest() { using namespace kwsys; const std::string source(TEST_SYSTEMTOOLS_BINARY_DIR diff --git a/Source/kwsys/testDynamicLoader.cxx b/Source/kwsys/testDynamicLoader.cxx index 9ba204e..806c01a 100644 --- a/Source/kwsys/testDynamicLoader.cxx +++ b/Source/kwsys/testDynamicLoader.cxx @@ -11,20 +11,20 @@ // Needed for __GLIBC__ test macro. #ifdef __linux__ # include <features.h> -#endif // Will define LIBDL_SO macro on systems with glibc. -#ifdef __GLIBC__ -# include <gnu/lib-names.h> +# ifdef __GLIBC__ +# include <gnu/lib-names.h> // Define to LIBC_SO, if not defined by above header. -# ifndef LIBDL_SO -# define LIBDL_SO LIBC_SO +# ifndef LIBDL_SO +# define LIBDL_SO LIBC_SO +# endif # endif -#endif // Define the LIBDL_SO macro, if not defined above. -#ifndef LIBDL_SO -# define LIBDL_SO "libdl.so" +# ifndef LIBDL_SO +# define LIBDL_SO "libdl.so" +# endif #endif // Work-around CMake dependency scanning limitation. This must @@ -40,6 +40,10 @@ // left on disk. #include <testSystemTools.h> +// For TestDynamicLoaderData, which, though not referenced literally, +// is referenced semantically. +#include "testDynload.h" + static std::string GetLibName(const char* lname, const char* subdir = nullptr) { // Construct proper name of lib diff --git a/Source/kwsys/testDynload.c b/Source/kwsys/testDynload.c index 33a431e..83056c0 100644 --- a/Source/kwsys/testDynload.c +++ b/Source/kwsys/testDynload.c @@ -6,6 +6,8 @@ # define DL_EXPORT #endif +#include "testDynload.h" + DL_EXPORT int TestDynamicLoaderData = 0; DL_EXPORT void TestDynamicLoaderSymbolPointer(void) diff --git a/Source/kwsys/testDynload.h b/Source/kwsys/testDynload.h new file mode 100644 index 0000000..dc0d7a1 --- /dev/null +++ b/Source/kwsys/testDynload.h @@ -0,0 +1,9 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#ifdef _WIN32 +# define DL_EXPORT __declspec(dllexport) +#else +# define DL_EXPORT +#endif + +extern DL_EXPORT int TestDynamicLoaderData; diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx index ee93e8d..1d605cb 100644 --- a/Source/kwsys/testEncoding.cxx +++ b/Source/kwsys/testEncoding.cxx @@ -80,7 +80,7 @@ static int testRobustEncoding() std::ios::fmtflags const& flags = std::cout.flags(); int ret = 0; - char cstr[] = { (char)-1, 0 }; + char cstr[] = { static_cast<char>(-1), 0 }; // this conversion could fail std::wstring wstr = kwsys::Encoding::ToWide(cstr); @@ -89,7 +89,7 @@ static int testRobustEncoding() const wchar_t* wcstr = wstr.c_str(); std::cout << "ToWide(NULL) returned"; for (size_t i = 0; i < wstr.size(); i++) { - std::cout << " " << std::hex << (int)wcstr[i]; + std::cout << " " << std::hex << static_cast<int>(wcstr[i]); } std::cout << std::endl; ret++; @@ -99,7 +99,7 @@ static int testRobustEncoding() const wchar_t* wcstr = wstr.c_str(); std::cout << "ToWide(\"\") returned"; for (size_t i = 0; i < wstr.size(); i++) { - std::cout << " " << std::hex << (int)wcstr[i]; + std::cout << " " << std::hex << static_cast<int>(wcstr[i]); } std::cout << std::endl; ret++; @@ -160,7 +160,9 @@ static int testCommandLineArguments() { int status = 0; - char const* argv[2] = { "./app.exe", (char const*)helloWorldStrings[1] }; + char const* argv[2] = { + "./app.exe", reinterpret_cast<char const*>(helloWorldStrings[1]) + }; kwsys::Encoding::CommandLineArguments args(2, argv); kwsys::Encoding::CommandLineArguments arg2 = diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 6ccc7a7..487da8d 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -295,12 +295,15 @@ static bool CheckFileOperations() // Reset umask #ifdef __MSYS__ mode_t fullMask = S_IWRITE; + mode_t testPerm = S_IREAD; #elif defined(_WIN32) && !defined(__CYGWIN__) // NOTE: Windows doesn't support toggling _S_IREAD. mode_t fullMask = _S_IWRITE; + mode_t testPerm = 0; #else // On a normal POSIX platform, we can toggle all permissions. mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO; + mode_t testPerm = S_IRUSR; #endif // Test file permissions without umask @@ -311,7 +314,7 @@ static bool CheckFileOperations() res = false; } - if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) { + if (!kwsys::SystemTools::SetPermissions(testNewFile, testPerm)) { std::cerr << "Problem with SetPermissions (1) for: " << testNewFile << std::endl; res = false; @@ -323,17 +326,17 @@ static bool CheckFileOperations() res = false; } - if ((thisPerm & fullMask) != 0) { + if ((thisPerm & fullMask) != testPerm) { std::cerr << "SetPermissions failed to set permissions (1) for: " << testNewFile << ": actual = " << thisPerm - << "; expected = " << 0 << std::endl; + << "; expected = " << testPerm << std::endl; res = false; } // While we're at it, check proper TestFileAccess functionality. bool do_write_test = true; #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ - defined(__NetBSD__) || defined(__DragonFly__) + defined(__NetBSD__) || defined(__DragonFly__) || defined(__HOS_AIX__) // If we are running as root on POSIX-ish systems (Linux and the BSDs, // at least), ignore this check, as root can always write to files. do_write_test = (getuid() != 0); @@ -626,6 +629,16 @@ static bool CheckStringOperations() res = false; } + std::vector<std::string> linesToJoin = { "Mary", "Had", "A", "Little", + "Lamb." }; + std::string joinResult = kwsys::SystemTools::Join(linesToJoin, " "); + if (joinResult != "Mary Had A Little Lamb.") { + std::cerr << "Problem with Join " + "\"Mary Had A Little Lamb.\"" + << std::endl; + res = false; + } + if (kwsys::SystemTools::ConvertToWindowsOutputPath( "L://Local Mojo/Hex Power Pack/Iffy Voodoo") != "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") { @@ -926,7 +939,8 @@ static bool CheckGetLineFromStream() bool result; file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + std::string::npos); if (!result || line.size() != 5) { std::cerr << "First line does not have five characters: " << line.size() << std::endl; @@ -934,7 +948,8 @@ static bool CheckGetLineFromStream() } file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + std::string::npos); if (!result || line.size() != 5) { std::cerr << "First line does not have five characters after rewind: " << line.size() << std::endl; @@ -943,10 +958,10 @@ static bool CheckGetLineFromStream() bool ret = true; - for (size_t size = 1; size <= 5; ++size) { + for (std::string::size_type size = 1; size <= 5; ++size) { file.seekg(0, std::ios::beg); - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, - static_cast<long>(size)); + result = + kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, size); if (!result || line.size() != size) { std::cerr << "Should have read " << size << " characters but got " << line.size() << std::endl; @@ -989,7 +1004,8 @@ static bool CheckGetLineFromStreamLongLine() bool result; // Read first line. - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + std::string::npos); if (!result || line != firstLine) { std::cerr << "First line does not match, expected " << firstLine.size() << " characters, got " << line.size() << std::endl; @@ -1002,7 +1018,8 @@ static bool CheckGetLineFromStreamLongLine() // Read empty line. has_newline = false; - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + std::string::npos); if (!result || !line.empty()) { std::cerr << "Expected successful read with an empty line, got " << line.size() << " characters" << std::endl; @@ -1015,7 +1032,8 @@ static bool CheckGetLineFromStreamLongLine() // Read second line. has_newline = false; - result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1); + result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, + std::string::npos); if (!result || line != secondLine) { std::cerr << "Second line does not match, expected " << secondLine.size() << " characters, got " << line.size() << std::endl; |