diff options
Diffstat (limited to 'Source')
133 files changed, 3539 insertions, 1205 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 4a7d9bc591..2354f3d999 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1018,6 +1018,7 @@ add_library( CPack/cmCPackGeneratorFactory.cxx CPack/cmCPackGenerator.cxx CPack/cmCPackLog.cxx + CPack/cmCPackInnoSetupGenerator.cxx CPack/cmCPackNSISGenerator.cxx CPack/cmCPackNuGetGenerator.cxx CPack/cmCPackSTGZGenerator.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 34eb248804..524f706433 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 26) -set(CMake_VERSION_PATCH 20230411) +set(CMake_VERSION_PATCH 20230505) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/IFW/cmCPackIFWCommon.cxx b/Source/CPack/IFW/cmCPackIFWCommon.cxx index 5d995c335d..4a868ae88f 100644 --- a/Source/CPack/IFW/cmCPackIFWCommon.cxx +++ b/Source/CPack/IFW/cmCPackIFWCommon.cxx @@ -5,12 +5,11 @@ #include <cstddef> // IWYU pragma: keep #include <sstream> #include <utility> -#include <vector> #include "cmCPackGenerator.h" #include "cmCPackIFWGenerator.h" #include "cmCPackLog.h" // IWYU pragma: keep -#include "cmStringAlgorithms.h" +#include "cmList.h" #include "cmSystemTools.h" #include "cmTimestamp.h" #include "cmVersionConfig.h" @@ -76,13 +75,13 @@ bool cmCPackIFWCommon::IsVersionEqual(const char* version) const void cmCPackIFWCommon::ExpandListArgument( const std::string& arg, std::map<std::string, std::string>& argsOut) { - std::vector<std::string> args = cmExpandedList(arg, false); + cmList args{ arg }; if (args.empty()) { return; } - std::size_t i = 0; - std::size_t c = args.size(); + cmList::size_type i = 0; + auto c = args.size(); if (c % 2) { argsOut[""] = args[i]; ++i; @@ -97,13 +96,13 @@ void cmCPackIFWCommon::ExpandListArgument( void cmCPackIFWCommon::ExpandListArgument( const std::string& arg, std::multimap<std::string, std::string>& argsOut) { - std::vector<std::string> args = cmExpandedList(arg, false); + cmList args{ arg }; if (args.empty()) { return; } - std::size_t i = 0; - std::size_t c = args.size(); + cmList::size_type i = 0; + auto c = args.size(); if (c % 2) { argsOut.insert(std::pair<std::string, std::string>("", args[i])); ++i; diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx index bc14eb40b1..5724175510 100644 --- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx +++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx @@ -14,6 +14,7 @@ #include "cmCPackLog.h" // IWYU pragma: keep #include "cmDuration.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -409,8 +410,8 @@ int cmCPackIFWGenerator::InitializeInternal() // Repositories if (cmValue RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) { - std::vector<std::string> RepoAllVector = cmExpandedList(RepoAllStr); - for (std::string const& r : RepoAllVector) { + cmList RepoAllList{ RepoAllStr }; + for (std::string const& r : RepoAllList) { this->GetRepository(r); } } diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index 69440d9748..a77c22fa81 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -12,6 +12,7 @@ #include "cmCPackIFWRepository.h" #include "cmCPackLog.h" // IWYU pragma: keep #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx index 1668fb5d56..083f1ef7b1 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.cxx +++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx @@ -15,6 +15,7 @@ #include "cmCPackIFWInstaller.h" #include "cmCPackLog.h" // IWYU pragma: keep #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTimestamp.h" @@ -427,16 +428,16 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix) } // QtIFW dependencies - std::vector<std::string> deps; + cmList deps; option = prefix + "DEPENDS"; if (cmValue value = this->GetOption(option)) { - cmExpandList(value, deps); + deps.assign(value); } option = prefix + "DEPENDENCIES"; if (cmValue value = this->GetOption(option)) { - cmExpandList(value, deps); + deps.append(value); } - for (std::string const& d : deps) { + for (auto const& d : deps) { DependenceStruct dep(d); if (this->Generator->Packages.count(dep.Name)) { cmCPackIFWPackage& depPkg = this->Generator->Packages[dep.Name]; @@ -455,7 +456,7 @@ int cmCPackIFWPackage::ConfigureFromPrefix(const std::string& prefix) if (this->IsSetToEmpty(option)) { this->AlienAutoDependOn.clear(); } else if (cmValue value = this->GetOption(option)) { - std::vector<std::string> depsOn = cmExpandedList(value); + cmList depsOn{ value }; for (std::string const& d : depsOn) { DependenceStruct dep(d); if (this->Generator->Packages.count(dep.Name)) { diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index aeb3db3539..1ea78fdc3d 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -18,6 +18,7 @@ #include "cmCryptoHash.h" #include "cmGeneratedFileStream.h" #include "cmInstalledFile.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmUuid.h" @@ -239,7 +240,7 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() cmValue patchFilePath = GetOption("CPACK_WIX_PATCH_FILE"); if (patchFilePath) { - std::vector<std::string> patchFilePaths = cmExpandedList(patchFilePath); + cmList patchFilePaths{ patchFilePath }; for (std::string const& p : patchFilePaths) { if (!this->Patch->LoadFragments(p)) { @@ -322,8 +323,7 @@ void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream) if (!cpackWixExtraObjects) return; - std::vector<std::string> expandedExtraObjects = - cmExpandedList(cpackWixExtraObjects); + cmList expandedExtraObjects{ cpackWixExtraObjects }; for (std::string const& obj : expandedExtraObjects) { stream << " " << QuotePath(obj); @@ -681,10 +681,10 @@ bool cmCPackWIXGenerator::AddComponentsToFeature( featureDefinitions.BeginElement("FeatureRef"); featureDefinitions.AddAttribute("Id", featureId); - std::vector<std::string> cpackPackageExecutablesList; + cmList cpackPackageExecutablesList; cmValue cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES"); if (cpackPackageExecutables) { - cmExpandList(cpackPackageExecutables, cpackPackageExecutablesList); + cpackPackageExecutablesList.assign(cpackPackageExecutables); if (cpackPackageExecutablesList.size() % 2 != 0) { cmCPackLogger( cmCPackLog::LOG_ERROR, @@ -695,10 +695,10 @@ bool cmCPackWIXGenerator::AddComponentsToFeature( } } - std::vector<std::string> cpackPackageDesktopLinksList; + cmList cpackPackageDesktopLinksList; cmValue cpackPackageDesktopLinks = GetOption("CPACK_CREATE_DESKTOP_LINKS"); if (cpackPackageDesktopLinks) { - cmExpandList(cpackPackageDesktopLinks, cpackPackageDesktopLinksList); + cpackPackageDesktopLinksList.assign(cpackPackageDesktopLinks); } AddDirectoryAndFileDefinitions( @@ -1160,7 +1160,7 @@ void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName, if (!variableContent) return; - std::vector<std::string> list = cmExpandedList(variableContent); + cmList list{ variableContent }; extensions.insert(list.begin(), list.end()); } @@ -1172,7 +1172,7 @@ void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName, return; } - std::vector<std::string> list = cmExpandedList(variableContent); + cmList list{ variableContent }; for (std::string const& str : list) { auto pos = str.find('='); if (pos != std::string::npos) { @@ -1200,7 +1200,7 @@ void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName, if (!variableContent) return; - std::vector<std::string> list = cmExpandedList(variableContent); + cmList list{ variableContent }; for (std::string const& i : list) { stream << " " << QuotePath(i); diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx index 9685a7f495..2261a66e0f 100644 --- a/Source/CPack/WiX/cmWIXAccessControlList.cxx +++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx @@ -19,10 +19,9 @@ cmWIXAccessControlList::cmWIXAccessControlList( bool cmWIXAccessControlList::Apply() { - std::vector<std::string> entries; - this->InstalledFile.GetPropertyAsList("CPACK_WIX_ACL", entries); + auto entries = this->InstalledFile.GetPropertyAsList("CPACK_WIX_ACL"); - for (std::string const& entry : entries) { + for (auto const& entry : entries) { this->CreatePermissionElement(entry); } diff --git a/Source/CPack/WiX/cmWIXShortcut.cxx b/Source/CPack/WiX/cmWIXShortcut.cxx index cd1988a1cb..c3eb219a9d 100644 --- a/Source/CPack/WiX/cmWIXShortcut.cxx +++ b/Source/CPack/WiX/cmWIXShortcut.cxx @@ -91,10 +91,9 @@ void cmWIXShortcuts::CreateFromProperty(std::string const& propertyName, std::string const& directoryId, cmInstalledFile const& installedFile) { - std::vector<std::string> list; - installedFile.GetPropertyAsList(propertyName, list); + auto list = installedFile.GetPropertyAsList(propertyName); - for (std::string const& label : list) { + for (auto const& label : list) { cmWIXShortcut shortcut; shortcut.label = label; shortcut.workingDirectoryId = directoryId; diff --git a/Source/CPack/cmCPackBundleGenerator.cxx b/Source/CPack/cmCPackBundleGenerator.cxx index b3d425aa51..7e6e4737dd 100644 --- a/Source/CPack/cmCPackBundleGenerator.cxx +++ b/Source/CPack/cmCPackBundleGenerator.cxx @@ -6,6 +6,7 @@ #include <vector> #include "cmCPackLog.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -191,7 +192,7 @@ int cmCPackBundleGenerator::SignBundle(const std::string& src_dir) cmValue sign_files = this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES"); - std::vector<std::string> relFiles = cmExpandedList(sign_files); + cmList relFiles{ sign_files }; // sign the files supplied by the user, ie. frameworks. for (auto const& file : relFiles) { diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 6ba28d166c..34c56c9993 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -20,6 +20,7 @@ #include "cmCPackLog.h" #include "cmCryptoHash.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -427,8 +428,7 @@ bool DebGenerator::generateControlTar(std::string const& md5Filename) const // default control_tar.ClearPermissions(); - std::vector<std::string> controlExtraList = - cmExpandedList(this->ControlExtra); + cmList controlExtraList{ this->ControlExtra }; for (std::string const& i : controlExtraList) { std::string filenamename = cmsys::SystemTools::GetFilenameName(i); std::string localcopy = this->WorkDir + "/" + filenamename; diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index 68e7ba3651..768bfbe08d 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -19,6 +19,7 @@ #include "cmCPackLog.h" #include "cmDuration.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -128,8 +129,7 @@ int cmCPackDragNDropGenerator::InitializeInternal() return 0; } - std::vector<std::string> languages = - cmExpandedList(this->GetOption("CPACK_DMG_SLA_LANGUAGES")); + cmList languages{ this->GetOption("CPACK_DMG_SLA_LANGUAGES") }; if (languages.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_DMG_SLA_LANGUAGES set but empty" << std::endl); @@ -543,9 +543,9 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, std::string sla_xml = cmStrCat(this->GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/sla.xml"); - std::vector<std::string> languages; + cmList languages; if (!oldStyle) { - cmExpandList(cpack_dmg_languages, languages); + languages.assign(cpack_dmg_languages); } std::vector<uint16_t> header_data; @@ -574,7 +574,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, header_data.push_back(0); header_data.push_back(languages.size()); - for (size_t i = 0; i < languages.size(); ++i) { + for (cmList::size_type i = 0; i < languages.size(); ++i) { CFStringRef language_cfstring = CFStringCreateWithCString( nullptr, languages[i].c_str(), kCFStringEncodingUTF8); CFStringRef iso_language = diff --git a/Source/CPack/cmCPackExternalGenerator.cxx b/Source/CPack/cmCPackExternalGenerator.cxx index 4c92592d03..8ba015c8a6 100644 --- a/Source/CPack/cmCPackExternalGenerator.cxx +++ b/Source/CPack/cmCPackExternalGenerator.cxx @@ -15,8 +15,8 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" +#include "cmList.h" #include "cmMakefile.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -79,7 +79,7 @@ int cmCPackExternalGenerator::PackageFiles() cmValue builtPackages = this->GetOption("CPACK_EXTERNAL_BUILT_PACKAGES"); if (builtPackages) { - cmExpandList(builtPackages, this->packageFileNames, false); + cmExpandList(builtPackages, this->packageFileNames); } } diff --git a/Source/CPack/cmCPackFreeBSDGenerator.cxx b/Source/CPack/cmCPackFreeBSDGenerator.cxx index ea7b24b488..0840e33cc8 100644 --- a/Source/CPack/cmCPackFreeBSDGenerator.cxx +++ b/Source/CPack/cmCPackFreeBSDGenerator.cxx @@ -2,15 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCPackFreeBSDGenerator.h" -#include "cmArchiveWrite.h" -#include "cmCPackArchiveGenerator.h" -#include "cmCPackLog.h" -#include "cmGeneratedFileStream.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" -#include "cmWorkingDirectory.h" - -// Needed for ::open() and ::stat() #include <algorithm> #include <ostream> #include <utility> @@ -21,6 +12,15 @@ #include <sys/stat.h> +#include "cmArchiveWrite.h" +#include "cmCPackArchiveGenerator.h" +#include "cmCPackLog.h" +#include "cmGeneratedFileStream.h" +#include "cmList.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmWorkingDirectory.h" + // Suffix used to tell libpkg what compression to use static const char FreeBSDPackageCompression[] = "txz"; static const char FreeBSDPackageSuffix_17[] = ".pkg"; @@ -292,8 +292,7 @@ void cmCPackFreeBSDGenerator::write_manifest_fields( manifest << ManifestKeyValue( "desc", var_lookup("CPACK_FREEBSD_PACKAGE_DESCRIPTION")); manifest << ManifestKeyValue("www", var_lookup("CPACK_FREEBSD_PACKAGE_WWW")); - std::vector<std::string> licenses = - cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_LICENSE")); + cmList licenses{ var_lookup("CPACK_FREEBSD_PACKAGE_LICENSE") }; std::string licenselogic("single"); if (licenses.empty()) { cmSystemTools::SetFatalErrorOccurred(); @@ -302,12 +301,10 @@ void cmCPackFreeBSDGenerator::write_manifest_fields( } manifest << ManifestKeyValue("licenselogic", licenselogic); manifest << (ManifestKeyListValue("licenses") << licenses); - std::vector<std::string> categories = - cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_CATEGORIES")); + cmList categories{ var_lookup("CPACK_FREEBSD_PACKAGE_CATEGORIES") }; manifest << (ManifestKeyListValue("categories") << categories); manifest << ManifestKeyValue("prefix", var_lookup("CMAKE_INSTALL_PREFIX")); - std::vector<std::string> deps = - cmExpandedList(var_lookup("CPACK_FREEBSD_PACKAGE_DEPS")); + cmList deps{ var_lookup("CPACK_FREEBSD_PACKAGE_DEPS") }; if (!deps.empty()) { manifest << (ManifestKeyDepsValue("deps") << deps); } diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index 2ac5b3dc77..afd85cda75 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -19,6 +19,7 @@ #include "cmFileTimes.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateSnapshot.h" @@ -216,8 +217,7 @@ int cmCPackGenerator::InstallProject() cmValue default_dir_install_permissions = this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); if (cmNonempty(default_dir_install_permissions)) { - std::vector<std::string> items = - cmExpandedList(default_dir_install_permissions); + cmList items{ default_dir_install_permissions }; for (const auto& arg : items) { if (!cmFSPermissions::stringToModeT(arg, default_dir_mode_v)) { cmCPackLogger(cmCPackLog::LOG_ERROR, @@ -266,7 +266,7 @@ int cmCPackGenerator::InstallProject() // Run pre-build actions cmValue preBuildScripts = this->GetOption("CPACK_PRE_BUILD_SCRIPTS"); if (preBuildScripts) { - const auto scripts = cmExpandedList(preBuildScripts, false); + const cmList scripts{ preBuildScripts }; for (const auto& script : scripts) { cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Executing pre-build script: " << script << std::endl); @@ -296,8 +296,7 @@ int cmCPackGenerator::InstallProjectViaInstallCommands( std::string tempInstallDirectoryEnv = cmStrCat("CMAKE_INSTALL_PREFIX=", tempInstallDirectory); cmSystemTools::PutEnv(tempInstallDirectoryEnv); - std::vector<std::string> installCommandsVector = - cmExpandedList(installCommands); + cmList installCommandsVector{ installCommands }; for (std::string const& ic : installCommandsVector) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl); std::string output; @@ -333,8 +332,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( std::vector<cmsys::RegularExpression> ignoreFilesRegex; cmValue cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES"); if (cpackIgnoreFiles) { - std::vector<std::string> ignoreFilesRegexString = - cmExpandedList(cpackIgnoreFiles); + cmList ignoreFilesRegexString{ cpackIgnoreFiles }; for (std::string const& ifr : ignoreFilesRegexString) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Create ignore files regex for: " << ifr << std::endl); @@ -343,9 +341,8 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( } cmValue installDirectories = this->GetOption("CPACK_INSTALLED_DIRECTORIES"); if (cmNonempty(installDirectories)) { - std::vector<std::string> installDirectoriesVector = - cmExpandedList(installDirectories); - if (installDirectoriesVector.size() % 2 != 0) { + cmList installDirectoriesList{ installDirectories }; + if (installDirectoriesList.size() % 2 != 0) { cmCPackLogger( cmCPackLog::LOG_ERROR, "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> " @@ -355,10 +352,10 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( << std::endl); return 0; } - std::vector<std::string>::iterator it; + cmList::iterator it; const std::string& tempDir = tempInstallDirectory; - for (it = installDirectoriesVector.begin(); - it != installDirectoriesVector.end(); ++it) { + for (it = installDirectoriesList.begin(); + it != installDirectoriesList.end(); ++it) { std::vector<std::pair<std::string, std::string>> symlinkedFiles; cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl); cmsys::Glob gl; @@ -485,7 +482,7 @@ int cmCPackGenerator::InstallProjectViaInstallScript( if (cmakeScripts && !cmakeScripts->empty()) { cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Install scripts: " << cmakeScripts << std::endl); - std::vector<std::string> cmakeScriptsVector = cmExpandedList(cmakeScripts); + cmList cmakeScriptsVector{ cmakeScripts }; for (std::string const& installScript : cmakeScriptsVector) { cmCPackLogger(cmCPackLog::LOG_OUTPUT, @@ -549,14 +546,12 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( << std::endl); return 0; } - std::vector<std::string> cmakeProjectsVector = - cmExpandedList(cmakeProjects); - std::vector<std::string>::iterator it; - for (it = cmakeProjectsVector.begin(); it != cmakeProjectsVector.end(); - ++it) { - if (it + 1 == cmakeProjectsVector.end() || - it + 2 == cmakeProjectsVector.end() || - it + 3 == cmakeProjectsVector.end()) { + cmList cmakeProjectsList{ cmakeProjects }; + cmList::iterator it; + for (it = cmakeProjectsList.begin(); it != cmakeProjectsList.end(); ++it) { + if (it + 1 == cmakeProjectsList.end() || + it + 2 == cmakeProjectsList.end() || + it + 3 == cmakeProjectsList.end()) { cmCPackLogger( cmCPackLog::LOG_ERROR, "Not enough items on list: CPACK_INSTALL_CMAKE_PROJECTS. " @@ -578,7 +573,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( ++it; project.SubDirectory = *it; - std::vector<std::string> componentsVector; + cmList componentsList; bool componentInstall = false; /* @@ -593,10 +588,9 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( std::string installTypesVar = "CPACK_" + cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES"; cmValue installTypes = this->GetOption(installTypesVar); - if (cmNonempty(installTypes)) { - std::vector<std::string> installTypesVector = - cmExpandedList(installTypes); - for (std::string const& installType : installTypesVector) { + if (!installTypes.IsEmpty()) { + cmList installTypesList{ installTypes }; + for (std::string const& installType : installTypesList) { project.InstallationTypes.push_back( this->GetInstallationType(project.ProjectName, installType)); } @@ -606,23 +600,23 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( std::string componentsVar = "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component); cmValue components = this->GetOption(componentsVar); - if (cmNonempty(components)) { - cmExpandList(components, componentsVector); - for (std::string const& comp : componentsVector) { + if (!components.IsEmpty()) { + componentsList.assign(components); + for (auto const& comp : componentsList) { project.Components.push_back( this->GetComponent(project.ProjectName, comp)); } componentInstall = true; } } - if (componentsVector.empty()) { - componentsVector.push_back(project.Component); + if (componentsList.empty()) { + componentsList.push_back(project.Component); } - std::vector<std::string> buildConfigs; + cmList buildConfigs; // Try get configuration names given via `-C` CLI option - cmExpandList(this->GetOption("CPACK_BUILD_CONFIG"), buildConfigs); + buildConfigs.assign(this->GetOption("CPACK_BUILD_CONFIG")); // Remove duplicates std::sort(buildConfigs.begin(), buildConfigs.end()); @@ -661,7 +655,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( << buildConfig << ']' << std::endl); // Run the installation for each component - for (std::string const& component : componentsVector) { + for (std::string const& component : componentsList) { if (!this->InstallCMakeProject( setDestDir, project.Directory, baseTempInstallDirectory, default_dir_mode, component, componentInstall, @@ -894,9 +888,8 @@ int cmCPackGenerator::InstallCMakeProject( mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1"); } - std::vector<std::string> custom_variables; - this->MakefileMap->GetDefExpandList("CPACK_CUSTOM_INSTALL_VARIABLES", - custom_variables); + cmList custom_variables{ this->MakefileMap->GetDefinition( + "CPACK_CUSTOM_INSTALL_VARIABLES") }; for (auto const& custom_variable : custom_variables) { std::string value; @@ -1129,7 +1122,7 @@ int cmCPackGenerator::DoPackage() this->MakefileMap->AddDefinition("CPACK_PACKAGE_FILES", cmJoin(this->packageFileNames, ";")); - const auto scripts = cmExpandedList(postBuildScripts, false); + const cmList scripts{ postBuildScripts }; for (const auto& script : scripts) { cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Executing post-build script: " << script << std::endl); @@ -1595,9 +1588,8 @@ cmCPackComponent* cmCPackGenerator::GetComponent( // Determine the installation types. cmValue installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES"); if (cmNonempty(installTypes)) { - std::vector<std::string> installTypesVector = - cmExpandedList(installTypes); - for (std::string const& installType : installTypesVector) { + cmList installTypesList{ installTypes }; + for (auto const& installType : installTypesList) { component->InstallationTypes.push_back( this->GetInstallationType(projectName, installType)); } @@ -1606,8 +1598,8 @@ cmCPackComponent* cmCPackGenerator::GetComponent( // Determine the component dependencies. cmValue depends = this->GetOption(macroPrefix + "_DEPENDS"); if (cmNonempty(depends)) { - std::vector<std::string> dependsVector = cmExpandedList(depends); - for (std::string const& depend : dependsVector) { + cmList dependsList{ depends }; + for (auto const& depend : dependsList) { cmCPackComponent* child = this->GetComponent(projectName, depend); component->Dependencies.push_back(child); child->ReverseDependencies.push_back(component); diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index efb94b9d8f..6ca48bf938 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -13,6 +13,7 @@ #include "cmCPackDebGenerator.h" #include "cmCPackExternalGenerator.h" #include "cmCPackGenerator.h" +#include "cmCPackInnoSetupGenerator.h" #include "cmCPackLog.h" #include "cmCPackNSISGenerator.h" #include "cmCPackNuGetGenerator.h" @@ -60,6 +61,10 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("STGZ", "Self extracting Tar GZip compression", cmCPackSTGZGenerator::CreateGenerator); } + if (cmCPackInnoSetupGenerator::CanGenerate()) { + this->RegisterGenerator("INNOSETUP", "Inno Setup packages", + cmCPackInnoSetupGenerator::CreateGenerator); + } if (cmCPackNSISGenerator::CanGenerate()) { this->RegisterGenerator("NSIS", "Null Soft Installer", cmCPackNSISGenerator::CreateGenerator); diff --git a/Source/CPack/cmCPackInnoSetupGenerator.cxx b/Source/CPack/cmCPackInnoSetupGenerator.cxx new file mode 100644 index 0000000000..d8825d46b5 --- /dev/null +++ b/Source/CPack/cmCPackInnoSetupGenerator.cxx @@ -0,0 +1,1159 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmCPackInnoSetupGenerator.h" + +#include <algorithm> +#include <cctype> +#include <cstdlib> +#include <ostream> +#include <stack> +#include <utility> + +#include "cmsys/RegularExpression.hxx" + +#include "cmCPackComponentGroup.h" +#include "cmCPackLog.h" +#include "cmDuration.h" +#include "cmGeneratedFileStream.h" +#include "cmList.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +cmCPackInnoSetupGenerator::cmCPackInnoSetupGenerator() = default; +cmCPackInnoSetupGenerator::~cmCPackInnoSetupGenerator() = default; + +bool cmCPackInnoSetupGenerator::CanGenerate() +{ + // Inno Setup is only available for Windows +#ifdef _WIN32 + return true; +#else + return false; +#endif +} + +int cmCPackInnoSetupGenerator::InitializeInternal() +{ + if (cmIsOn(GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) { + cmCPackLogger(cmCPackLog::LOG_WARNING, + "Inno Setup Generator cannot work with " + "CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. " + "This option will be reset to 0 (for this generator only)." + << std::endl); + SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", nullptr); + } + + std::vector<std::string> path; + +#ifdef _WIN32 + path.push_back("C:\\Program Files (x86)\\Inno Setup 5"); + path.push_back("C:\\Program Files (x86)\\Inno Setup 6"); +#endif + + SetOptionIfNotSet("CPACK_INNOSETUP_EXECUTABLE", "ISCC"); + const std::string& isccPath = cmSystemTools::FindProgram( + GetOption("CPACK_INNOSETUP_EXECUTABLE"), path, false); + + if (isccPath.empty()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot find Inno Setup compiler ISCC: " + "likely it is not installed, or not in your PATH" + << std::endl); + + return 0; + } + + const std::string isccCmd = cmStrCat(QuotePath(isccPath), "/?"); + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Test Inno Setup version: " << isccCmd << std::endl); + std::string output; + cmSystemTools::RunSingleCommand(isccCmd, &output, &output, nullptr, nullptr, + this->GeneratorVerbose, cmDuration::zero()); + cmsys::RegularExpression vRex("Inno Setup ([0-9]+)"); + if (!vRex.find(output)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem checking Inno Setup version with command: " + << isccCmd << std::endl + << "Have you downloaded Inno Setup from " + "https://jrsoftware.org/isinfo.php?" + << std::endl); + return 0; + } + + const int isccVersion = atoi(vRex.match(1).c_str()); + const int minIsccVersion = 6; + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Inno Setup Version: " << isccVersion << std::endl); + + if (isccVersion < minIsccVersion) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPack requires Inno Setup Version 6 or greater. " + "Inno Setup found on the system was: " + << isccVersion << std::endl); + return 0; + } + + SetOption("CPACK_INSTALLER_PROGRAM", isccPath); + + return this->Superclass::InitializeInternal(); +} + +int cmCPackInnoSetupGenerator::PackageFiles() +{ + // Includes + if (IsSet("CPACK_INNOSETUP_EXTRA_SCRIPTS")) { + const cmList extraScripts(GetOption("CPACK_INNOSETUP_EXTRA_SCRIPTS")); + + for (const std::string& i : extraScripts) { + includeDirectives.push_back(cmStrCat( + "#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel)))); + } + } + + // [Languages] section + SetOptionIfNotSet("CPACK_INNOSETUP_LANGUAGES", "english"); + const cmList languages(GetOption("CPACK_INNOSETUP_LANGUAGES")); + for (std::string i : languages) { + cmCPackInnoSetupKeyValuePairs params; + + params["Name"] = Quote(i); + + if (cmSystemTools::LowerCase(i) == "english") { + params["MessagesFile"] = "\"compiler:Default.isl\""; + } else { + i[0] = static_cast<char>(std::toupper(i[0])); + params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\""); + } + + languageInstructions.push_back(ISKeyValueLine(params)); + } + + if (!Components.empty() && !ProcessComponents()) { + return false; + } + + if (!(ProcessSetupSection() && ProcessFiles())) { + return false; + } + + // [Code] section + if (IsSet("CPACK_INNOSETUP_CODE_FILES")) { + const cmList codeFiles(GetOption("CPACK_INNOSETUP_CODE_FILES")); + + for (const std::string& i : codeFiles) { + codeIncludes.push_back(cmStrCat( + "#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel)))); + } + } + + return ConfigureISScript() && Compile(); +} + +bool cmCPackInnoSetupGenerator::ProcessSetupSection() +{ + if (!RequireOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY")) { + return false; + } + setupDirectives["AppId"] = GetOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY"); + + if (!RequireOption("CPACK_PACKAGE_NAME")) { + return false; + } + setupDirectives["AppName"] = GetOption("CPACK_PACKAGE_NAME"); + setupDirectives["UninstallDisplayName"] = GetOption("CPACK_PACKAGE_NAME"); + + if (!RequireOption("CPACK_PACKAGE_VERSION")) { + return false; + } + setupDirectives["AppVersion"] = GetOption("CPACK_PACKAGE_VERSION"); + + if (!RequireOption("CPACK_PACKAGE_VENDOR")) { + return false; + } + setupDirectives["AppPublisher"] = GetOption("CPACK_PACKAGE_VENDOR"); + + if (IsSet("CPACK_PACKAGE_HOMEPAGE_URL")) { + setupDirectives["AppPublisherURL"] = + GetOption("CPACK_PACKAGE_HOMEPAGE_URL"); + setupDirectives["AppSupportURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL"); + setupDirectives["AppUpdatesURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL"); + } + + SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE", "OFF"); + if (IsSet("CPACK_RESOURCE_FILE_LICENSE") && + !GetOption("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE").IsOn()) { + setupDirectives["LicenseFile"] = cmSystemTools::ConvertToWindowsOutputPath( + GetOption("CPACK_RESOURCE_FILE_LICENSE")); + } + + SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_README_PAGE", "ON"); + if (IsSet("CPACK_RESOURCE_FILE_README") && + !GetOption("CPACK_INNOSETUP_IGNORE_README_PAGE").IsOn()) { + setupDirectives["InfoBeforeFile"] = + cmSystemTools::ConvertToWindowsOutputPath( + GetOption("CPACK_RESOURCE_FILE_README")); + } + + SetOptionIfNotSet("CPACK_INNOSETUP_USE_MODERN_WIZARD", "OFF"); + if (GetOption("CPACK_INNOSETUP_USE_MODERN_WIZARD").IsOn()) { + setupDirectives["WizardStyle"] = "modern"; + } else { + setupDirectives["WizardStyle"] = "classic"; + setupDirectives["WizardSmallImageFile"] = + "compiler:WizClassicSmallImage.bmp"; + setupDirectives["WizardImageFile"] = "compiler:WizClassicImage.bmp"; + setupDirectives["SetupIconFile"] = "compiler:SetupClassicIcon.ico"; + } + + if (IsSet("CPACK_INNOSETUP_ICON_FILE")) { + setupDirectives["SetupIconFile"] = + cmSystemTools::ConvertToWindowsOutputPath( + GetOption("CPACK_INNOSETUP_ICON_FILE")); + } + + if (IsSet("CPACK_PACKAGE_ICON")) { + setupDirectives["WizardSmallImageFile"] = + cmSystemTools::ConvertToWindowsOutputPath( + GetOption("CPACK_PACKAGE_ICON")); + } + + if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) { + return false; + } + SetOptionIfNotSet("CPACK_INNOSETUP_INSTALL_ROOT", "{autopf}"); + setupDirectives["DefaultDirName"] = + cmSystemTools::ConvertToWindowsOutputPath( + cmStrCat(GetOption("CPACK_INNOSETUP_INSTALL_ROOT"), '\\', + GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY"))); + + SetOptionIfNotSet("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY", "ON"); + if (GetOption("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY").IsOff()) { + setupDirectives["DisableDirPage"] = "yes"; + } + + SetOptionIfNotSet("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER", + GetOption("CPACK_PACKAGE_NAME")); + if (GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER") == ".") { + setupDirectives["DisableProgramGroupPage"] = "yes"; + toplevelProgramFolder = true; + } else { + setupDirectives["DefaultGroupName"] = + GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER"); + toplevelProgramFolder = false; + } + + if (IsSet("CPACK_INNOSETUP_PASSWORD")) { + setupDirectives["Password"] = GetOption("CPACK_INNOSETUP_PASSWORD"); + setupDirectives["Encryption"] = "yes"; + } + + /* + * These directives can only be modified using the + * CPACK_INNOSETUP_SETUP_<directive> variables + */ + setupDirectives["ShowLanguageDialog"] = "auto"; + setupDirectives["AllowNoIcons"] = "yes"; + setupDirectives["Compression"] = "lzma"; + setupDirectives["SolidCompression"] = "yes"; + + // Output file and directory + if (!RequireOption("CPACK_PACKAGE_FILE_NAME")) { + return false; + } + setupDirectives["OutputBaseFilename"] = GetOption("CPACK_PACKAGE_FILE_NAME"); + + if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY")) { + return false; + } + setupDirectives["OutputDir"] = cmSystemTools::ConvertToWindowsOutputPath( + GetOption("CPACK_TOPLEVEL_DIRECTORY")); + + setupDirectives["SourceDir"] = + cmSystemTools::ConvertToWindowsOutputPath(toplevel); + + // Target architecture + if (!RequireOption("CPACK_INNOSETUP_ARCHITECTURE")) { + return false; + } + + const std::string& architecture = GetOption("CPACK_INNOSETUP_ARCHITECTURE"); + if (architecture != "x86" && architecture != "x64" && + architecture != "arm64" && architecture != "ia64") { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_INNOSETUP_ARCHITECTURE must be either x86, x64, " + "arm64 or ia64" + << std::endl); + return false; + } + + // The following directives must not be set to target x86 + if (architecture != "x86") { + setupDirectives["ArchitecturesAllowed"] = architecture; + setupDirectives["ArchitecturesInstallIn64BitMode"] = architecture; + } + + /* + * Handle custom directives (they have higher priority than other variables, + * so they have to be processed after all other variables) + */ + for (const std::string& i : GetOptions()) { + if (cmHasPrefix(i, "CPACK_INNOSETUP_SETUP_")) { + const std::string& directive = + i.substr(cmStrLen("CPACK_INNOSETUP_SETUP_")); + setupDirectives[directive] = GetOption(i); + } + } + + return true; +} + +bool cmCPackInnoSetupGenerator::ProcessFiles() +{ + std::map<std::string, std::string> customFileInstructions; + if (IsSet("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")) { + const cmList instructions( + GetOption("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")); + if (instructions.size() % 2 != 0) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS should " + "contain pairs of <path> and <instruction>" + << std::endl); + return false; + } + + for (auto it = instructions.begin(); it != instructions.end(); ++it) { + const std::string& key = + QuotePath(cmSystemTools::CollapseFullPath(*it, toplevel)); + customFileInstructions[key] = *(++it); + } + } + + const std::string& iconsPrefix = + toplevelProgramFolder ? "{autoprograms}\\" : "{group}\\"; + + std::map<std::string, std::string> icons; + if (IsSet("CPACK_PACKAGE_EXECUTABLES")) { + const cmList executables(GetOption("CPACK_PACKAGE_EXECUTABLES")); + if (executables.size() % 2 != 0) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_PACKAGE_EXECUTABLES should should contain pairs of " + "<executable> and <text label>" + << std::endl); + return false; + } + + for (auto it = executables.begin(); it != executables.end(); ++it) { + const std::string& key = *it; + icons[key] = *(++it); + } + } + + std::vector<std::string> desktopIcons; + if (IsSet("CPACK_CREATE_DESKTOP_LINKS")) { + cmExpandList(GetOption("CPACK_CREATE_DESKTOP_LINKS"), desktopIcons); + } + + std::vector<std::string> runExecutables; + if (IsSet("CPACK_INNOSETUP_RUN_EXECUTABLES")) { + cmExpandList(GetOption("CPACK_INNOSETUP_RUN_EXECUTABLES"), runExecutables); + } + + for (const std::string& i : files) { + cmCPackInnoSetupKeyValuePairs params; + + std::string toplevelDirectory; + std::string outputDir; + cmCPackComponent* component = nullptr; + std::string componentParam; + if (!Components.empty()) { + const std::string& fileName = cmSystemTools::RelativePath(toplevel, i); + const std::string::size_type pos = fileName.find('/'); + + // Use the custom component install directory if we have one + if (pos != std::string::npos) { + const std::string& componentName = fileName.substr(0, pos); + component = &Components[componentName]; + + toplevelDirectory = + cmSystemTools::CollapseFullPath(componentName, toplevel); + outputDir = CustomComponentInstallDirectory(component); + componentParam = + CreateRecursiveComponentPath(component->Group, component->Name); + + if (component->IsHidden && component->IsDisabledByDefault) { + continue; + } + + if (component->IsHidden) { + componentParam.clear(); + } + } else { + // Don't install component directories + continue; + } + } else { + toplevelDirectory = toplevel; + outputDir = "{app}"; + } + + if (!componentParam.empty()) { + params["Components"] = componentParam; + } + + if (cmSystemTools::FileIsDirectory(i)) { + // Custom instructions replace the automatic generated instructions + if (customFileInstructions.count(QuotePath(i))) { + dirInstructions.push_back(customFileInstructions[QuotePath(i)]); + } else { + std::string destDir = cmSystemTools::ConvertToWindowsOutputPath( + cmStrCat(outputDir, '\\', + cmSystemTools::RelativePath(toplevelDirectory, i))); + cmStripSuffixIfExists(destDir, '\\'); + + params["Name"] = QuotePath(destDir); + + dirInstructions.push_back(ISKeyValueLine(params)); + } + } else { + // Custom instructions replace the automatic generated instructions + if (customFileInstructions.count(QuotePath(i))) { + fileInstructions.push_back(customFileInstructions[QuotePath(i)]); + } else { + std::string destDir = cmSystemTools::ConvertToWindowsOutputPath( + cmStrCat(outputDir, '\\', + cmSystemTools::GetParentDirectory( + cmSystemTools::RelativePath(toplevelDirectory, i)))); + cmStripSuffixIfExists(destDir, '\\'); + + params["DestDir"] = QuotePath(destDir); + + if (component != nullptr && component->IsDownloaded) { + const std::string& archiveName = + cmSystemTools::GetFilenameWithoutLastExtension( + component->ArchiveFile); + const std::string& relativePath = + cmSystemTools::RelativePath(toplevelDirectory, i); + + params["Source"] = + QuotePath(cmStrCat("{tmp}\\", archiveName, '\\', relativePath)); + params["ExternalSize"] = + std::to_string(cmSystemTools::FileLength(i)); + params["Flags"] = "external ignoreversion"; + params["BeforeInstall"] = + cmStrCat("CPackExtractFile('", archiveName, "', '", + cmRemoveQuotes(cmSystemTools::ConvertToWindowsOutputPath( + relativePath)), + "')"); + } else { + params["Source"] = QuotePath(i); + params["Flags"] = "ignoreversion"; + } + + fileInstructions.push_back(ISKeyValueLine(params)); + + // Icon + const std::string& name = + cmSystemTools::GetFilenameWithoutLastExtension(i); + const std::string& extension = + cmSystemTools::GetFilenameLastExtension(i); + if ((extension == ".exe" || extension == ".com") && // only .exe, .com + icons.count(name)) { + cmCPackInnoSetupKeyValuePairs iconParams; + + iconParams["Name"] = QuotePath(cmStrCat(iconsPrefix, icons[name])); + iconParams["Filename"] = + QuotePath(cmStrCat(destDir, '\\', name, extension)); + + if (!componentParam.empty()) { + iconParams["Components"] = componentParam; + } + + iconInstructions.push_back(ISKeyValueLine(iconParams)); + + // Desktop icon + if (std::find(desktopIcons.begin(), desktopIcons.end(), name) != + desktopIcons.end()) { + iconParams["Name"] = + QuotePath(cmStrCat("{autodesktop}\\", icons[name])); + iconParams["Tasks"] = "desktopicon"; + + if (!componentParam.empty() && + std::find(desktopIconComponents.begin(), + desktopIconComponents.end(), + componentParam) == desktopIconComponents.end()) { + desktopIconComponents.push_back(componentParam); + } + iconInstructions.push_back(ISKeyValueLine(iconParams)); + } + + // [Run] section + if (std::find(runExecutables.begin(), runExecutables.end(), name) != + runExecutables.end()) { + cmCPackInnoSetupKeyValuePairs runParams; + + runParams["Filename"] = iconParams["Filename"]; + runParams["Description"] = cmStrCat( + "\"{cm:LaunchProgram,", PrepareForConstant(icons[name]), "}\""); + runParams["Flags"] = "nowait postinstall skipifsilent"; + + if (!componentParam.empty()) { + runParams["Components"] = componentParam; + } + + runInstructions.push_back(ISKeyValueLine(runParams)); + } + } + } + } + } + + // Additional icons + static cmsys::RegularExpression urlRegex( + "^(mailto:|(ftps?|https?|news)://).*$"); + + if (IsSet("CPACK_INNOSETUP_MENU_LINKS")) { + const cmList menuIcons(GetOption("CPACK_INNOSETUP_MENU_LINKS")); + if (menuIcons.size() % 2 != 0) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_INNOSETUP_MENU_LINKS should " + "contain pairs of <shortcut target> and <shortcut label>" + << std::endl); + return false; + } + + for (auto it = menuIcons.begin(); it != menuIcons.end(); ++it) { + const std::string& target = *it; + const std::string& label = *(++it); + cmCPackInnoSetupKeyValuePairs params; + + params["Name"] = QuotePath(cmStrCat(iconsPrefix, label)); + if (urlRegex.find(target)) { + params["Filename"] = Quote(target); + } else { + std::string dir = "{app}"; + std::string componentName; + for (const auto& i : Components) { + if (cmSystemTools::FileExists(cmSystemTools::CollapseFullPath( + cmStrCat(i.second.Name, '\\', target), toplevel))) { + dir = CustomComponentInstallDirectory(&i.second); + componentName = + CreateRecursiveComponentPath(i.second.Group, i.second.Name); + + if (i.second.IsHidden && i.second.IsDisabledByDefault) { + goto continueOuterLoop; + } else if (i.second.IsHidden) { + componentName.clear(); + } + + break; + } + } + + params["Filename"] = QuotePath(cmStrCat(dir, '\\', target)); + + if (!componentName.empty()) { + params["Components"] = componentName; + } + } + + iconInstructions.push_back(ISKeyValueLine(params)); + continueOuterLoop:; + } + } + + SetOptionIfNotSet("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK", "OFF"); + if (GetOption("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK").IsOn()) { + cmCPackInnoSetupKeyValuePairs params; + + params["Name"] = QuotePath( + cmStrCat(iconsPrefix, "{cm:UninstallProgram,", + PrepareForConstant(GetOption("CPACK_PACKAGE_NAME")), '}')); + params["Filename"] = "\"{uninstallexe}\""; + + iconInstructions.push_back(ISKeyValueLine(params)); + } + + return true; +} + +bool cmCPackInnoSetupGenerator::ProcessComponents() +{ + codeIncludes.push_back("{ The following lines are required by CPack because " + "this script uses components }"); + + // Installation types + bool noTypes = true; + std::vector<cmCPackInstallationType*> types(InstallationTypes.size()); + for (auto& i : InstallationTypes) { + noTypes = false; + types[i.second.Index - 1] = &i.second; + } + + std::vector<std::string> allTypes; // For required components + for (cmCPackInstallationType* i : types) { + cmCPackInnoSetupKeyValuePairs params; + + params["Name"] = Quote(i->Name); + params["Description"] = Quote(i->DisplayName); + + allTypes.push_back(i->Name); + typeInstructions.push_back(ISKeyValueLine(params)); + } + + if (!noTypes) { + // Inno Setup requires the "custom" type + cmCPackInnoSetupKeyValuePairs params; + + params["Name"] = "\"custom\""; + params["Description"] = "\"{code:CPackGetCustomInstallationMessage}\""; + params["Flags"] = "iscustom"; + + allTypes.push_back("custom"); + typeInstructions.push_back(ISKeyValueLine(params)); + } + + // Components + std::vector<cmCPackComponent*> downloadedComponents; + std::stack<cmCPackComponentGroup*> groups; + for (auto& i : Components) { + cmCPackInnoSetupKeyValuePairs params; + cmCPackComponent* component = &i.second; + + if (component->IsHidden) { + continue; + } + + CreateRecursiveComponentGroups(component->Group); + + params["Name"] = + Quote(CreateRecursiveComponentPath(component->Group, component->Name)); + params["Description"] = Quote(component->DisplayName); + + if (component->IsRequired) { + params["Types"] = cmJoin(allTypes, " "); + params["Flags"] = "fixed"; + } else if (!component->InstallationTypes.empty()) { + std::vector<std::string> installationTypes; + + for (cmCPackInstallationType* j : component->InstallationTypes) { + installationTypes.push_back(j->Name); + } + + params["Types"] = cmJoin(installationTypes, " "); + } + + componentInstructions.push_back(ISKeyValueLine(params)); + + if (component->IsDownloaded) { + downloadedComponents.push_back(component); + + if (component->ArchiveFile.empty()) { + // Compute the name of the archive. + if (!RequireOption("CPACK_TEMPORARY_DIRECTORY")) { + return false; + } + + std::string packagesDir = + cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), ".dummy"); + component->ArchiveFile = + cmStrCat(cmSystemTools::GetFilenameWithoutLastExtension(packagesDir), + '-', component->Name, ".zip"); + } else if (!cmHasSuffix(component->ArchiveFile, ".zip")) { + component->ArchiveFile = cmStrCat(component->ArchiveFile, ".zip"); + } + } + } + + // Downloaded components + if (!downloadedComponents.empty()) { + // Create the directory for the upload area + cmValue userUploadDirectory = GetOption("CPACK_UPLOAD_DIRECTORY"); + std::string uploadDirectory; + if (cmNonempty(userUploadDirectory)) { + uploadDirectory = *userUploadDirectory; + } else { + if (!RequireOption("CPACK_PACKAGE_DIRECTORY")) { + return false; + } + + uploadDirectory = + cmStrCat(GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads"); + } + + if (!cmSystemTools::FileExists(uploadDirectory)) { + if (!cmSystemTools::MakeDirectory(uploadDirectory)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Unable to create Inno Setup upload directory " + << uploadDirectory << std::endl); + return false; + } + } + + if (!RequireOption("CPACK_DOWNLOAD_SITE")) { + return false; + } + + SetOptionIfNotSet("CPACK_INNOSETUP_VERIFY_DOWNLOADS", "ON"); + const bool verifyDownloads = + GetOption("CPACK_INNOSETUP_VERIFY_DOWNLOADS").IsOn(); + + const std::string& urlPrefix = + cmHasSuffix(GetOption("CPACK_DOWNLOAD_SITE").GetCStr(), '/') + ? GetOption("CPACK_DOWNLOAD_SITE") + : cmStrCat(GetOption("CPACK_DOWNLOAD_SITE"), '/'); + + std::vector<std::string> archiveUrls; + std::vector<std::string> archiveFiles; + std::vector<std::string> archiveHashes; + std::vector<std::string> archiveComponents; + for (cmCPackComponent* i : downloadedComponents) { + std::string hash; + if (!BuildDownloadedComponentArchive( + i, uploadDirectory, (verifyDownloads ? &hash : nullptr))) { + return false; + } + + archiveUrls.push_back(Quote(cmStrCat(urlPrefix, i->ArchiveFile))); + archiveFiles.push_back( + Quote(cmSystemTools::GetFilenameWithoutLastExtension(i->ArchiveFile))); + archiveHashes.push_back(Quote(hash)); + archiveComponents.push_back( + Quote(CreateRecursiveComponentPath(i->Group, i->Name))); + } + + SetOption("CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL", + std::to_string(archiveFiles.size())); + SetOption("CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL", + cmJoin(archiveUrls, ", ")); + SetOption("CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL", + cmJoin(archiveFiles, ", ")); + SetOption("CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL", + cmJoin(archiveHashes, ", ")); + SetOption("CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL", + cmJoin(archiveComponents, ", ")); + + static const std::string& downloadLines = + "#define protected CPackDownloadCount " + "@CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL@\n" + "#dim protected CPackDownloadUrls[CPackDownloadCount] " + "{@CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL@}\n" + "#dim protected CPackDownloadArchives[CPackDownloadCount] " + "{@CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL@}\n" + "#dim protected CPackDownloadHashes[CPackDownloadCount] " + "{@CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL@}\n" + "#dim protected CPackDownloadComponents[CPackDownloadCount] " + "{@CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL@}"; + + std::string output; + if (!ConfigureString(downloadLines, output)) { + return false; + } + codeIncludes.push_back(output); + } + + // Add the required script + const std::string& componentsScriptTemplate = + FindTemplate("ISComponents.pas"); + if (componentsScriptTemplate.empty()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Could not find additional Inno Setup script file." + << std::endl); + return false; + } + + codeIncludes.push_back("#include " + QuotePath(componentsScriptTemplate) + + "\n"); + + return true; +} + +bool cmCPackInnoSetupGenerator::ConfigureISScript() +{ + const std::string& isScriptTemplate = FindTemplate("ISScript.template.in"); + const std::string& isScriptFile = + cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss"); + + if (isScriptTemplate.empty()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Could not find Inno Setup installer template file." + << std::endl); + return false; + } + + // Create internal variables + std::vector<std::string> setupSection; + for (const auto& i : setupDirectives) { + setupSection.push_back(cmStrCat(i.first, '=', TranslateBool(i.second))); + } + + // Also create comments if the sections are empty + const std::string& defaultMessage = + "; CPack didn't find any entries for this section"; + + if (IsSet("CPACK_CREATE_DESKTOP_LINKS") && + !GetOption("CPACK_CREATE_DESKTOP_LINKS").Get()->empty()) { + cmCPackInnoSetupKeyValuePairs tasks; + tasks["Name"] = "\"desktopicon\""; + tasks["Description"] = "\"{cm:CreateDesktopIcon}\""; + tasks["GroupDescription"] = "\"{cm:AdditionalIcons}\""; + tasks["Flags"] = "unchecked"; + + if (!desktopIconComponents.empty()) { + tasks["Components"] = cmJoin(desktopIconComponents, " "); + } + + SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", ISKeyValueLine(tasks)); + } else { + SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", defaultMessage); + } + + SetOption("CPACK_INNOSETUP_INCLUDES_INTERNAL", + includeDirectives.empty() ? "; No extra script files specified" + : cmJoin(includeDirectives, "\n")); + SetOption("CPACK_INNOSETUP_SETUP_INTERNAL", + setupSection.empty() ? defaultMessage + : cmJoin(setupSection, "\n")); + SetOption("CPACK_INNOSETUP_LANGUAGES_INTERNAL", + languageInstructions.empty() ? defaultMessage + : cmJoin(languageInstructions, "\n")); + SetOption("CPACK_INNOSETUP_DIRS_INTERNAL", + dirInstructions.empty() ? defaultMessage + : cmJoin(dirInstructions, "\n")); + SetOption("CPACK_INNOSETUP_FILES_INTERNAL", + fileInstructions.empty() ? defaultMessage + : cmJoin(fileInstructions, "\n")); + SetOption("CPACK_INNOSETUP_TYPES_INTERNAL", + typeInstructions.empty() ? defaultMessage + : cmJoin(typeInstructions, "\n")); + SetOption("CPACK_INNOSETUP_COMPONENTS_INTERNAL", + componentInstructions.empty() + ? defaultMessage + : cmJoin(componentInstructions, "\n")); + SetOption("CPACK_INNOSETUP_ICONS_INTERNAL", + iconInstructions.empty() ? defaultMessage + : cmJoin(iconInstructions, "\n")); + SetOption("CPACK_INNOSETUP_RUN_INTERNAL", + runInstructions.empty() ? defaultMessage + : cmJoin(runInstructions, "\n")); + SetOption("CPACK_INNOSETUP_CODE_INTERNAL", + codeIncludes.empty() ? "{ No extra code files specified }" + : cmJoin(codeIncludes, "\n")); + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Configure file: " << isScriptTemplate << " to " + << isScriptFile << std::endl); + + return ConfigureFile(isScriptTemplate, isScriptFile); +} + +bool cmCPackInnoSetupGenerator::Compile() +{ + const std::string& isScriptFile = + cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss"); + const std::string& isccLogFile = + cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISCCOutput.log"); + + std::vector<std::string> isccArgs; + + // Custom defines + for (const std::string& i : GetOptions()) { + if (cmHasPrefix(i, "CPACK_INNOSETUP_DEFINE_")) { + const std::string& name = i.substr(cmStrLen("CPACK_INNOSETUP_DEFINE_")); + isccArgs.push_back( + cmStrCat("\"/D", name, '=', TranslateBool(GetOption(i)), '"')); + } + } + + if (IsSet("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")) { + const cmList args(GetOption("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")); + + isccArgs.insert(isccArgs.end(), args.begin(), args.end()); + } + + const std::string& isccCmd = + cmStrCat(QuotePath(GetOption("CPACK_INSTALLER_PROGRAM")), ' ', + cmJoin(isccArgs, " "), ' ', QuotePath(isScriptFile)); + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << isccCmd << std::endl); + + std::string output; + int retVal = 1; + const bool res = cmSystemTools::RunSingleCommand( + isccCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose, + cmDuration::zero()); + + if (!res || retVal) { + cmGeneratedFileStream ofs(isccLogFile); + ofs << "# Run command: " << isccCmd << std::endl + << "# Output:" << std::endl + << output << std::endl; + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem running ISCC. Please check " + << isccLogFile << " for errors." << std::endl); + return false; + } + + return true; +} + +bool cmCPackInnoSetupGenerator::BuildDownloadedComponentArchive( + cmCPackComponent* component, const std::string& uploadDirectory, + std::string* hash) +{ + // Remove the old archive, if one exists + const std::string& archiveFile = + uploadDirectory + '/' + component->ArchiveFile; + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Building downloaded component archive: " << archiveFile + << std::endl); + if (cmSystemTools::FileExists(archiveFile, true)) { + if (!cmSystemTools::RemoveFile(archiveFile)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Unable to remove archive file " << archiveFile + << std::endl); + return false; + } + } + + // Find a ZIP program + if (!IsSet("ZIP_EXECUTABLE")) { + ReadListFile("Internal/CPack/CPackZIP.cmake"); + + if (!IsSet("ZIP_EXECUTABLE")) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Unable to find ZIP program" << std::endl); + return false; + } + } + + if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY") || + !RequireOption("CPACK_TEMPORARY_DIRECTORY") || + !RequireOption("CPACK_ZIP_NEED_QUOTES") || + !RequireOption("CPACK_ZIP_COMMAND")) { + return false; + } + + // The directory where this component's files reside + const std::string& dirName = + cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), '/', component->Name); + + // Build the list of files to go into this archive + const std::string& zipListFileName = + cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), "/winZip.filelist"); + const bool needQuotesInFile = cmIsOn(GetOption("CPACK_ZIP_NEED_QUOTES")); + { // the scope is needed for cmGeneratedFileStream + cmGeneratedFileStream out(zipListFileName); + for (const std::string& i : component->Files) { + out << (needQuotesInFile ? Quote(i) : i) << std::endl; + } + } + + // Build the archive in the upload area + std::string cmd = GetOption("CPACK_ZIP_COMMAND"); + cmsys::SystemTools::ReplaceString(cmd, "<ARCHIVE>", archiveFile.c_str()); + cmsys::SystemTools::ReplaceString(cmd, "<FILELIST>", + zipListFileName.c_str()); + std::string output; + int retVal = -1; + const bool res = cmSystemTools::RunSingleCommand( + cmd, &output, &output, &retVal, dirName.c_str(), this->GeneratorVerbose, + cmDuration::zero()); + if (!res || retVal) { + std::string tmpFile = + cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/CompressZip.log"); + cmGeneratedFileStream ofs(tmpFile); + ofs << "# Run command: " << cmd << std::endl + << "# Output:" << std::endl + << output << std::endl; + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem running zip command: " << cmd << std::endl + << "Please check " << tmpFile + << " for errors" + << std::endl); + return false; + } + + // Try to get the SHA256 hash of the archive file + if (hash == nullptr) { + return true; + } + +#ifdef _WIN32 + const std::string& hashCmd = + cmStrCat("certutil -hashfile ", QuotePath(archiveFile), " SHA256"); + + std::string hashOutput; + int hashRetVal = -1; + const bool hashRes = cmSystemTools::RunSingleCommand( + hashCmd, &hashOutput, &hashOutput, &hashRetVal, nullptr, + this->GeneratorVerbose, cmDuration::zero()); + if (!hashRes || hashRetVal) { + cmCPackLogger(cmCPackLog::LOG_WARNING, + "Problem running certutil command: " << hashCmd + << std::endl); + } + *hash = cmTrimWhitespace(cmTokenize(hashOutput, "\n").at(1)); + + if (hash->length() != 64) { + cmCPackLogger(cmCPackLog::LOG_WARNING, + "Problem parsing certutil output of command: " << hashCmd + << std::endl); + hash->clear(); + } +#endif + + return true; +} + +cmValue cmCPackInnoSetupGenerator::RequireOption(const std::string& key) +{ + cmValue value = GetOption(key); + + if (!value) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Required variable " << key << " not set" << std::endl); + } + + return value; +} + +std::string cmCPackInnoSetupGenerator::CustomComponentInstallDirectory( + const cmCPackComponent* component) +{ + cmValue outputDir = GetOption( + cmStrCat("CPACK_INNOSETUP_", component->Name, "_INSTALL_DIRECTORY")); + if (outputDir) { + std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(outputDir); + cmStripSuffixIfExists(destDir, '\\'); + + /* + * Add a dir instruction for the custom directory + * (only once and not for Inno Setup constants ending with '}') + */ + static std::vector<std::string> customDirectories; + if (!cmHasSuffix(destDir, '}') && + std::find(customDirectories.begin(), customDirectories.end(), + component->Name) == customDirectories.end()) { + cmCPackInnoSetupKeyValuePairs params; + params["Name"] = QuotePath(destDir); + params["Components"] = + CreateRecursiveComponentPath(component->Group, component->Name); + + dirInstructions.push_back(ISKeyValueLine(params)); + customDirectories.push_back(component->Name); + } + return destDir; + } + + return "{app}"; +} + +std::string cmCPackInnoSetupGenerator::TranslateBool(const std::string& value) +{ + if (value.empty()) { + return value; + } + + SetOptionIfNotSet("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT", "ON"); + if (GetOption("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT").IsOn()) { + if (cmIsOn(value)) { + return "yes"; + } + if (cmIsOff(value)) { + return "no"; + } + } + + return value; +} + +std::string cmCPackInnoSetupGenerator::ISKeyValueLine( + const cmCPackInnoSetupKeyValuePairs& params) +{ + /* + * To simplify readability of the generated code, the keys are sorted. + * Unknown keys are ignored to avoid errors during compilation. + */ + static const char* const availableKeys[] = { + "Source", "DestDir", "Name", "Filename", + "Description", "GroupDescription", "MessagesFile", "Types", + "ExternalSize", "BeforeInstall", "Flags", "Components", + "Tasks" + }; + + std::vector<std::string> keys; + for (const char* i : availableKeys) { + if (params.count(i)) { + keys.push_back(cmStrCat(i, ": ", params.at(i))); + } + } + + return cmJoin(keys, "; "); +} + +std::string cmCPackInnoSetupGenerator::CreateRecursiveComponentPath( + cmCPackComponentGroup* group, const std::string& path) +{ + if (group == nullptr) { + return path; + } + + const std::string& newPath = + path.empty() ? group->Name : cmStrCat(group->Name, '\\', path); + return CreateRecursiveComponentPath(group->ParentGroup, newPath); +} + +void cmCPackInnoSetupGenerator::CreateRecursiveComponentGroups( + cmCPackComponentGroup* group) +{ + if (group == nullptr) { + return; + } + + CreateRecursiveComponentGroups(group->ParentGroup); + + static std::vector<cmCPackComponentGroup*> processedGroups; + if (std::find(processedGroups.begin(), processedGroups.end(), group) == + processedGroups.end()) { + processedGroups.push_back(group); + + cmCPackInnoSetupKeyValuePairs params; + + params["Name"] = Quote(CreateRecursiveComponentPath(group)); + params["Description"] = Quote(group->DisplayName); + + componentInstructions.push_back(ISKeyValueLine(params)); + } +} + +std::string cmCPackInnoSetupGenerator::Quote(const std::string& string) +{ + if (cmHasPrefix(string, '"') && cmHasSuffix(string, '"')) { + return Quote(string.substr(1, string.length() - 2)); + } + + // Double quote syntax + std::string nString = string; + cmSystemTools::ReplaceString(nString, "\"", "\"\""); + return cmStrCat('"', nString, '"'); +} + +std::string cmCPackInnoSetupGenerator::QuotePath(const std::string& path) +{ + return Quote(cmSystemTools::ConvertToWindowsOutputPath(path)); +} + +std::string cmCPackInnoSetupGenerator::PrepareForConstant( + const std::string& string) +{ + std::string nString = string; + + cmSystemTools::ReplaceString(nString, "%", "%25"); // First replacement! + cmSystemTools::ReplaceString(nString, "\"", "%22"); + cmSystemTools::ReplaceString(nString, ",", "%2c"); + cmSystemTools::ReplaceString(nString, "|", "%7c"); + cmSystemTools::ReplaceString(nString, "}", "%7d"); + + return nString; +} diff --git a/Source/CPack/cmCPackInnoSetupGenerator.h b/Source/CPack/cmCPackInnoSetupGenerator.h new file mode 100644 index 0000000000..342f227e00 --- /dev/null +++ b/Source/CPack/cmCPackInnoSetupGenerator.h @@ -0,0 +1,116 @@ +/* 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 <string> +#include <vector> + +#include "cmCPackGenerator.h" +#include "cmValue.h" + +using cmCPackInnoSetupKeyValuePairs = std::map<std::string, std::string>; + +class cmCPackComponentGroup; +class cmCPackComponent; + +/** \class cmCPackInnoSetupGenerator + * \brief A generator for Inno Setup + * + * https://jrsoftware.org/isinfo.php + */ +class cmCPackInnoSetupGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackInnoSetupGenerator, cmCPackGenerator); + + /** + * Construct generator + */ + cmCPackInnoSetupGenerator(); + ~cmCPackInnoSetupGenerator() override; + + static bool CanGenerate(); + +protected: + int InitializeInternal() override; + int PackageFiles() override; + + inline const char* GetOutputExtension() override { return ".exe"; } + + inline cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir() + const override + { + return cmCPackGenerator::SETDESTDIR_UNSUPPORTED; + } + + inline bool SupportsAbsoluteDestination() const override { return false; } + inline bool SupportsComponentInstallation() const override { return true; } + +private: + bool ProcessSetupSection(); + bool ProcessFiles(); + bool ProcessComponents(); + + bool ConfigureISScript(); + bool Compile(); + + bool BuildDownloadedComponentArchive(cmCPackComponent* component, + const std::string& uploadDirectory, + std::string* hash); + + /** + * Returns the option's value or an empty string if the option isn't set. + */ + cmValue RequireOption(const std::string& key); + + std::string CustomComponentInstallDirectory( + const cmCPackComponent* component); + + /** + * Translates boolean expressions into "yes" or "no", as required in + * Inno Setup (only if "CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT" is on). + */ + std::string TranslateBool(const std::string& value); + + /** + * Creates a typical line of key and value pairs using the given map. + * + * (e.g.: Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; + * GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked) + */ + std::string ISKeyValueLine(const cmCPackInnoSetupKeyValuePairs& params); + + std::string CreateRecursiveComponentPath(cmCPackComponentGroup* group, + const std::string& path = ""); + + void CreateRecursiveComponentGroups(cmCPackComponentGroup* group); + + /** + * These functions add quotes if the given value hasn't already quotes. + * Paths are converted into the format used by Windows before. + */ + std::string Quote(const std::string& string); + std::string QuotePath(const std::string& path); + + /** + * This function replaces the following 5 characters with their %-encoding: + * '|' '}' ',' '%' '"' + * Required for Inno Setup constants like {cm:...} + */ + std::string PrepareForConstant(const std::string& string); + + std::vector<std::string> includeDirectives; + cmCPackInnoSetupKeyValuePairs setupDirectives; + bool toplevelProgramFolder; + std::vector<std::string> languageInstructions; + std::vector<std::string> fileInstructions; + std::vector<std::string> dirInstructions; + std::vector<std::string> typeInstructions; + std::vector<std::string> componentInstructions; + std::vector<std::string> iconInstructions; + std::vector<std::string> desktopIconComponents; + std::vector<std::string> runInstructions; + std::vector<std::string> codeIncludes; +}; diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx index d7119c5223..7749b29303 100644 --- a/Source/CPack/cmCPackNSISGenerator.cxx +++ b/Source/CPack/cmCPackNSISGenerator.cxx @@ -19,6 +19,7 @@ #include "cmCPackLog.h" #include "cmDuration.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -245,8 +246,7 @@ int cmCPackNSISGenerator::PackageFiles() std::string nsisPreArguments; if (cmValue nsisArguments = this->GetOption("CPACK_NSIS_EXECUTABLE_PRE_ARGUMENTS")) { - std::vector<std::string> expandedArguments; - cmExpandList(nsisArguments, expandedArguments); + cmList expandedArguments{ nsisArguments }; for (auto& arg : expandedArguments) { if (!cmHasPrefix(arg, NSIS_OPT)) { @@ -259,8 +259,7 @@ int cmCPackNSISGenerator::PackageFiles() std::string nsisPostArguments; if (cmValue nsisArguments = this->GetOption("CPACK_NSIS_EXECUTABLE_POST_ARGUMENTS")) { - std::vector<std::string> expandedArguments; - cmExpandList(nsisArguments, expandedArguments); + cmList expandedArguments{ nsisArguments }; for (auto& arg : expandedArguments) { if (!cmHasPrefix(arg, NSIS_OPT)) { nsisPostArguments = cmStrCat(nsisPostArguments, NSIS_OPT); @@ -545,14 +544,14 @@ int cmCPackNSISGenerator::InitializeInternal() this->GetOption("CPACK_CREATE_DESKTOP_LINKS"); cmValue cpackNsisExecutablesDirectory = this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY"); - std::vector<std::string> cpackPackageDesktopLinksVector; + cmList cpackPackageDesktopLinksList; if (cpackPackageDeskTopLinks) { cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: " << cpackPackageDeskTopLinks << std::endl); - cmExpandList(cpackPackageDeskTopLinks, cpackPackageDesktopLinksVector); - for (std::string const& cpdl : cpackPackageDesktopLinksVector) { + cpackPackageDesktopLinksList.assign(cpackPackageDeskTopLinks); + for (std::string const& cpdl : cpackPackageDesktopLinksList) { cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: " << cpdl << std::endl); } @@ -569,9 +568,8 @@ int cmCPackNSISGenerator::InitializeInternal() cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: " << cpackPackageExecutables << "." << std::endl); - std::vector<std::string> cpackPackageExecutablesVector = - cmExpandedList(cpackPackageExecutables); - if (cpackPackageExecutablesVector.size() % 2 != 0) { + cmList cpackPackageExecutablesList{ cpackPackageExecutables }; + if (cpackPackageExecutablesList.size() % 2 != 0) { cmCPackLogger( cmCPackLog::LOG_ERROR, "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and " @@ -579,9 +577,9 @@ int cmCPackNSISGenerator::InitializeInternal() << std::endl); return 0; } - std::vector<std::string>::iterator it; - for (it = cpackPackageExecutablesVector.begin(); - it != cpackPackageExecutablesVector.end(); ++it) { + cmList::iterator it; + for (it = cpackPackageExecutablesList.begin(); + it != cpackPackageExecutablesList.end(); ++it) { std::string execName = *it; ++it; std::string linkName = *it; @@ -592,7 +590,7 @@ int cmCPackNSISGenerator::InitializeInternal() << ".lnk\"" << std::endl; // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on // if so add a desktop link - if (cm::contains(cpackPackageDesktopLinksVector, execName)) { + if (cm::contains(cpackPackageDesktopLinksList, execName)) { str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n"; str << " CreateShortCut \"$DESKTOP\\" << linkName << R"(.lnk" "$INSTDIR\)" << cpackNsisExecutablesDirectory << "\\" @@ -622,9 +620,8 @@ void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str, } cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackMenuLinks: " << cpackMenuLinks << "." << std::endl); - std::vector<std::string> cpackMenuLinksVector = - cmExpandedList(cpackMenuLinks); - if (cpackMenuLinksVector.size() % 2 != 0) { + cmList cpackMenuLinksList{ cpackMenuLinks }; + if (cpackMenuLinksList.size() % 2 != 0) { cmCPackLogger( cmCPackLog::LOG_ERROR, "CPACK_NSIS_MENU_LINKS should contain pairs of <shortcut target> and " @@ -636,9 +633,8 @@ void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str, static cmsys::RegularExpression urlRegex( "^(mailto:|(ftps?|https?|news)://).*$"); - std::vector<std::string>::iterator it; - for (it = cpackMenuLinksVector.begin(); it != cpackMenuLinksVector.end(); - ++it) { + cmList::iterator it; + for (it = cpackMenuLinksList.begin(); it != cpackMenuLinksList.end(); ++it) { std::string sourceName = *it; const bool url = urlRegex.find(sourceName); diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index 234bc59352..90716e6e0d 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -29,6 +29,7 @@ #include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmJSONState.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateSnapshot.h" @@ -509,8 +510,8 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "CPack generator not specified\n"); } else { - std::vector<std::string> generatorsVector = cmExpandedList(*genList); - for (std::string const& gen : generatorsVector) { + cmList generatorsList{ *genList }; + for (std::string const& gen : generatorsList) { cmMakefile::ScopePushPop raii(&globalMF); cmMakefile* mf = &globalMF; cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index c6387ab353..882b579fff 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -17,6 +17,7 @@ #include "cmDuration.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmProcessOutput.h" #include "cmStringAlgorithms.h" diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index 1f3633de5b..bae1f54011 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -4,13 +4,13 @@ #include <cstring> #include <sstream> -#include <vector> #include <cmext/string_view> #include "cmCTest.h" #include "cmCTestConfigureHandler.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -25,10 +25,10 @@ void cmCTestConfigureCommand::BindArguments() cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() { - std::vector<std::string> options; + cmList options; if (!this->Options.empty()) { - cmExpandList(this->Options, options); + options.assign(this->Options); } if (this->CTest->GetCTestConfiguration("BuildDirectory").empty()) { diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index b2fb069fd5..a6e7ac52c8 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -14,6 +14,7 @@ #include "cmCTest.h" #include "cmCTestVC.h" +#include "cmList.h" #include "cmProcessOutput.h" #include "cmProcessTools.h" #include "cmStringAlgorithms.h" @@ -215,7 +216,7 @@ bool cmCTestGIT::UpdateByFetchAndReset() bool cmCTestGIT::UpdateByCustom(std::string const& custom) { - std::vector<std::string> git_custom_command = cmExpandedList(custom, true); + cmList git_custom_command{ custom, cmList::EmptyElements::Yes }; std::vector<char const*> git_custom; git_custom.reserve(git_custom_command.size() + 1); for (std::string const& i : git_custom_command) { diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index 0e67c4122e..e22ec4b556 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -13,9 +13,9 @@ #include "cmCTest.h" #include "cmCTestVC.h" +#include "cmList.h" #include "cmProcessTools.h" #include "cmRange.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmCTestP4::cmCTestP4(cmCTest* ct, std::ostream& log) @@ -460,7 +460,7 @@ bool cmCTestP4::LoadModifications() bool cmCTestP4::UpdateCustom(const std::string& custom) { - std::vector<std::string> p4_custom_command = cmExpandedList(custom, true); + cmList p4_custom_command{ custom, cmList::EmptyElements::Yes }; std::vector<char const*> p4_custom; p4_custom.reserve(p4_custom_command.size() + 1); diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx index ee06b29c67..461ad1a947 100644 --- a/Source/CTest/cmCTestScriptHandler.cxx +++ b/Source/CTest/cmCTestScriptHandler.cxx @@ -33,6 +33,7 @@ #include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -521,7 +522,7 @@ int cmCTestScriptHandler::RunCurrentScript() // set any environment variables if (!this->CTestEnv.empty()) { - std::vector<std::string> envArgs = cmExpandedList(this->CTestEnv); + cmList envArgs{ this->CTestEnv }; cmSystemTools::AppendEnv(envArgs); } @@ -625,7 +626,7 @@ int cmCTestScriptHandler::PerformExtraUpdates() // do an initial cvs update as required command = this->UpdateCmd; for (std::string const& eu : this->ExtraUpdates) { - std::vector<std::string> cvsArgs = cmExpandedList(eu); + cmList cvsArgs{ eu }; if (cvsArgs.size() == 2) { std::string fullCommand = cmStrCat(command, " update ", cvsArgs[1]); output.clear(); @@ -764,7 +765,7 @@ int cmCTestScriptHandler::RunConfigurationDashboard() } // run ctest, it may be more than one command in here - std::vector<std::string> ctestCommands = cmExpandedList(this->CTestCmd); + cmList ctestCommands{ this->CTestCmd }; // for each variable/argument do a putenv for (std::string const& ctestCommand : ctestCommands) { command = ctestCommand; diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index a1933cccb1..a92f9f28ec 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -13,10 +13,10 @@ #include "cmCTest.h" #include "cmCTestSubmitHandler.h" #include "cmCommand.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -64,14 +64,14 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() cmValue notesFilesVariable = this->Makefile->GetDefinition("CTEST_NOTES_FILES"); if (notesFilesVariable) { - std::vector<std::string> notesFiles = cmExpandedList(*notesFilesVariable); + cmList notesFiles{ *notesFilesVariable }; this->CTest->GenerateNotesFile(notesFiles); } cmValue extraFilesVariable = this->Makefile->GetDefinition("CTEST_EXTRA_SUBMIT_FILES"); if (extraFilesVariable) { - std::vector<std::string> extraFiles = cmExpandedList(*extraFilesVariable); + cmList extraFiles{ *extraFilesVariable }; if (!this->CTest->SubmitExtraFiles(extraFiles)) { this->SetError("problem submitting extra files."); return nullptr; diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 3ff8c8f280..a095e5dc63 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -22,6 +22,7 @@ #include "cmCurl.h" #include "cmDuration.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -160,7 +161,7 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP( /* In windows, this will init the winsock stuff */ ::curl_global_init(CURL_GLOBAL_ALL); std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions")); - std::vector<std::string> args = cmExpandedList(curlopt); + cmList args{ curlopt }; bool verifyPeerOff = false; bool verifyHostOff = false; for (std::string const& arg : args) { @@ -499,7 +500,7 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, cmCTestCurl curl(this->CTest); curl.SetQuiet(this->Quiet); std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions")); - std::vector<std::string> args = cmExpandedList(curlopt); + cmList args{ curlopt }; curl.SetCurlOptions(args); auto submitInactivityTimeout = this->GetSubmitInactivityTimeout(); if (submitInactivityTimeout != 0) { diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index f693ace4b5..3a1cb64708 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -38,6 +38,7 @@ #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmJSONState.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateSnapshot.h" @@ -2203,9 +2204,8 @@ bool cmCTestTestHandler::SetTestsProperties( for (cmCTestTestProperties& rt : this->TestList) { if (t == rt.Name) { if (key == "_BACKTRACE_TRIPLES"_s) { - std::vector<std::string> triples; // allow empty args in the triples - cmExpandList(val, triples, true); + cmList triples{ val, cmList::EmptyElements::Yes }; // Ensure we have complete triples otherwise the data is corrupt. if (triples.size() % 3 == 0) { @@ -2214,7 +2214,7 @@ bool cmCTestTestHandler::SetTestsProperties( // the first entry represents the top of the trace so we need to // reconstruct the backtrace in reverse - for (size_t i = triples.size(); i >= 3; i -= 3) { + for (auto i = triples.size(); i >= 3; i -= 3) { cmListFileContext fc; fc.FilePath = triples[i - 3]; long line = 0; @@ -2235,19 +2235,19 @@ bool cmCTestTestHandler::SetTestsProperties( } else if (key == "ATTACHED_FILES_ON_FAIL"_s) { cmExpandList(val, rt.AttachOnFail); } else if (key == "RESOURCE_LOCK"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; rt.LockedResources.insert(lval.begin(), lval.end()); } else if (key == "FIXTURES_SETUP"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; rt.FixturesSetup.insert(lval.begin(), lval.end()); } else if (key == "FIXTURES_CLEANUP"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; rt.FixturesCleanup.insert(lval.begin(), lval.end()); } else if (key == "FIXTURES_REQUIRED"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; rt.FixturesRequired.insert(lval.begin(), lval.end()); } else if (key == "TIMEOUT"_s) { @@ -2260,12 +2260,12 @@ bool cmCTestTestHandler::SetTestsProperties( } else if (key == "RUN_SERIAL"_s) { rt.RunSerial = cmIsOn(val); } else if (key == "FAIL_REGULAR_EXPRESSION"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; for (std::string const& cr : lval) { rt.ErrorRegularExpressions.emplace_back(cr, cr); } } else if (key == "SKIP_REGULAR_EXPRESSION"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; for (std::string const& cr : lval) { rt.SkipRegularExpressions.emplace_back(cr, cr); } @@ -2292,7 +2292,7 @@ bool cmCTestTestHandler::SetTestsProperties( } else if (key == "ENVIRONMENT_MODIFICATION"_s) { cmExpandList(val, rt.EnvironmentModification); } else if (key == "LABELS"_s) { - std::vector<std::string> Labels = cmExpandedList(val); + cmList Labels{ val }; rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end()); // sort the array std::sort(rt.Labels.begin(), rt.Labels.end()); @@ -2309,21 +2309,21 @@ bool cmCTestTestHandler::SetTestsProperties( rt.Measurements[val] = "1"; } } else if (key == "PASS_REGULAR_EXPRESSION"_s) { - std::vector<std::string> lval = cmExpandedList(val); + cmList lval{ val }; for (std::string const& cr : lval) { rt.RequiredRegularExpressions.emplace_back(cr, cr); } } else if (key == "WORKING_DIRECTORY"_s) { rt.Directory = val; } else if (key == "TIMEOUT_AFTER_MATCH"_s) { - std::vector<std::string> propArgs = cmExpandedList(val); + cmList propArgs{ val }; if (propArgs.size() != 2) { cmCTestLog(this->CTest, WARNING, "TIMEOUT_AFTER_MATCH expects two arguments, found " << propArgs.size() << std::endl); } else { rt.AlternateTimeout = cmDuration(atof(propArgs[0].c_str())); - std::vector<std::string> lval = cmExpandedList(propArgs[1]); + cmList lval{ propArgs[1] }; for (std::string const& cr : lval) { rt.TimeoutRegularExpressions.emplace_back(cr, cr); } @@ -2365,7 +2365,7 @@ bool cmCTestTestHandler::SetDirectoryProperties( std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); if (cwd == rt.Directory) { if (key == "LABELS"_s) { - std::vector<std::string> DirectoryLabels = cmExpandedList(val); + cmList DirectoryLabels{ val }; rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(), DirectoryLabels.end()); diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx index e9ec09ee28..fc5450ef2b 100644 --- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx @@ -4,7 +4,6 @@ #include <cassert> #include <utility> -#include <vector> #include <cm/memory> @@ -15,9 +14,9 @@ #include "cmCursesPathWidget.h" #include "cmCursesStringWidget.h" #include "cmCursesWidget.h" +#include "cmList.h" #include "cmState.h" #include "cmStateTypes.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -76,7 +75,7 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( if (stringsProp) { auto ow = cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1); - for (std::string const& opt : cmExpandedList(*stringsProp)) { + for (auto const& opt : cmList{ *stringsProp }) { ow->AddOption(opt); } ow->SetOption(*value); diff --git a/Source/Modules/CMakeBuildUtilities.cmake b/Source/Modules/CMakeBuildUtilities.cmake index 3dc099f7c8..d6e3e884dc 100644 --- a/Source/Modules/CMakeBuildUtilities.cmake +++ b/Source/Modules/CMakeBuildUtilities.cmake @@ -279,7 +279,7 @@ else() set(ENABLE_LIBXML2 OFF) set(ENABLE_EXPAT OFF) set(ENABLE_PCREPOSIX OFF) - set(ENABLE_LibGCC OFF) + set(ENABLE_LIBGCC OFF) set(ENABLE_CNG OFF) set(ENABLE_TAR OFF) set(ENABLE_TAR_SHARED OFF) diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 58129a06b6..8bfd7c87c7 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -21,10 +21,12 @@ #include "cmArgumentParser.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmValue.h" #include "cmWindowsRegistry.h" #ifdef _WIN32 @@ -303,7 +305,8 @@ std::map<std::string, std::string> GetOSReleaseVariables( } // 2. User provided (append to the CMake prvided) - makefile.GetDefExpandList("CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS", scripts); + cmList::append( + scripts, makefile.GetDefinition("CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS")); // Filter out files that are not in format `NNN-name.cmake` auto checkName = [](std::string const& filepath) -> bool { @@ -330,11 +333,11 @@ std::map<std::string, std::string> GetOSReleaseVariables( }); // Name of the variable to put the results - auto const result_variable = "CMAKE_GET_OS_RELEASE_FALLBACK_RESULT"_s; + std::string const result_variable{ "CMAKE_GET_OS_RELEASE_FALLBACK_RESULT" }; for (auto const& script : scripts) { // Unset the result variable - makefile.RemoveDefinition(result_variable.data()); + makefile.RemoveDefinition(result_variable); // include FATAL_ERROR and ERROR in the return status if (!makefile.ReadListFile(script) || @@ -343,8 +346,8 @@ std::map<std::string, std::string> GetOSReleaseVariables( continue; } - std::vector<std::string> variables; - if (!makefile.GetDefExpandList(result_variable.data(), variables)) { + cmList variables{ makefile.GetDefinition(result_variable) }; + if (variables.empty()) { // Heh, this script didn't found anything... go try the next one. continue; } @@ -370,7 +373,7 @@ std::map<std::string, std::string> GetOSReleaseVariables( } } - makefile.RemoveDefinition(result_variable.data()); + makefile.RemoveDefinition(result_variable); return data; } diff --git a/Source/cmCMakePathCommand.cxx b/Source/cmCMakePathCommand.cxx index 7755082236..0c8f53781a 100644 --- a/Source/cmCMakePathCommand.cxx +++ b/Source/cmCMakePathCommand.cxx @@ -18,6 +18,7 @@ #include "cmArgumentParserTypes.h" #include "cmCMakePath.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmStringAlgorithms.h" @@ -626,12 +627,12 @@ bool HandleConvertCommand(std::vector<std::string> const& args, return false; } - std::vector<std::string> paths; + cmList paths; if (action == cmakePath) { paths = cmSystemTools::SplitString(args[1], pathSep.front()); } else { - cmExpandList(args[1], paths); + paths.assign(args[1]); } for (auto& path : paths) { @@ -648,7 +649,7 @@ bool HandleConvertCommand(std::vector<std::string> const& args, } } - auto value = cmJoin(paths, action == cmakePath ? ";"_s : pathSep); + auto value = action == cmakePath ? paths.to_string() : paths.join(pathSep); status.GetMakefile().AddDefinition(args[3], value); return true; diff --git a/Source/cmCMakePresetsGraph.cxx b/Source/cmCMakePresetsGraph.cxx index 13e8bad1f1..13eddbe24f 100644 --- a/Source/cmCMakePresetsGraph.cxx +++ b/Source/cmCMakePresetsGraph.cxx @@ -4,7 +4,6 @@ #include <algorithm> #include <cassert> -#include <cstdlib> #include <functional> #include <iostream> #include <iterator> @@ -49,6 +48,7 @@ template <typename T> using PresetPair = cmCMakePresetsGraph::PresetPair<T>; using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult; using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander; +using cmCMakePresetsGraphInternal::ExpandMacros; void InheritString(std::string& child, const std::string& parent) { @@ -204,14 +204,6 @@ bool IsValidMacroNamespace(const std::string& str) ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, const std::vector<MacroExpander>& macroExpanders, int version); -ExpandMacroResult ExpandMacros( - std::string& out, const std::vector<MacroExpander>& macroExpanders, - int version); -ExpandMacroResult ExpandMacro(std::string& out, - const std::string& macroNamespace, - const std::string& macroName, - const std::vector<MacroExpander>& macroExpanders, - int version); bool ExpandMacros(const cmCMakePresetsGraph& graph, const ConfigurePreset& preset, @@ -448,9 +440,9 @@ bool ExpandMacros(cmCMakePresetsGraph& graph, const T& preset, if (macroName.empty()) { return ExpandMacroResult::Error; } - const char* value = std::getenv(macroName.c_str()); - if (value) { - result += value; + if (cm::optional<std::string> value = + cmSystemTools::GetEnvVar(macroName)) { + result += *value; } return ExpandMacroResult::Ok; } @@ -515,8 +507,9 @@ ExpandMacroResult VisitEnv(std::string& value, CycleStatus& status, status = CycleStatus::Verified; return ExpandMacroResult::Ok; } +} -ExpandMacroResult ExpandMacros( +ExpandMacroResult cmCMakePresetsGraphInternal::ExpandMacros( std::string& out, const std::vector<MacroExpander>& macroExpanders, int version) { @@ -595,11 +588,10 @@ ExpandMacroResult ExpandMacros( return ExpandMacroResult::Ok; } -ExpandMacroResult ExpandMacro(std::string& out, - const std::string& macroNamespace, - const std::string& macroName, - const std::vector<MacroExpander>& macroExpanders, - int version) +ExpandMacroResult cmCMakePresetsGraphInternal::ExpandMacro( + std::string& out, const std::string& macroNamespace, + const std::string& macroName, + const std::vector<MacroExpander>& macroExpanders, int version) { for (auto const& macroExpander : macroExpanders) { auto result = macroExpander(macroNamespace, macroName, out, version); @@ -615,6 +607,7 @@ ExpandMacroResult ExpandMacro(std::string& out, return ExpandMacroResult::Error; } +namespace { template <typename T> bool SetupWorkflowConfigurePreset(const T& preset, const ConfigurePreset*& configurePreset, diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h index db784c341a..f133efb124 100644 --- a/Source/cmCMakePresetsGraphInternal.h +++ b/Source/cmCMakePresetsGraphInternal.h @@ -28,6 +28,16 @@ enum class ExpandMacroResult using MacroExpander = std::function<ExpandMacroResult( const std::string&, const std::string&, std::string&, int version)>; + +ExpandMacroResult ExpandMacros( + std::string& out, const std::vector<MacroExpander>& macroExpanders, + int version); + +ExpandMacroResult ExpandMacro(std::string& out, + const std::string& macroNamespace, + const std::string& macroName, + const std::vector<MacroExpander>& macroExpanders, + int version); } class cmCMakePresetsGraph::Condition diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index bc829f3e44..54fea409c4 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -33,6 +33,9 @@ using PackagePreset = cmCMakePresetsGraph::PackagePreset; using WorkflowPreset = cmCMakePresetsGraph::WorkflowPreset; using ArchToolsetStrategy = cmCMakePresetsGraph::ArchToolsetStrategy; using JSONHelperBuilder = cmJSONHelperBuilder; +using ExpandMacroResult = cmCMakePresetsGraphInternal::ExpandMacroResult; +using MacroExpander = cmCMakePresetsGraphInternal::MacroExpander; +using cmCMakePresetsGraphInternal::ExpandMacros; constexpr int MIN_VERSION = 1; constexpr int MAX_VERSION = 7; @@ -688,7 +691,39 @@ bool cmCMakePresetsGraph::ReadJSONFile(const std::string& filename, return true; }; - for (auto include : presets.Include) { + std::vector<MacroExpander> macroExpanders; + + MacroExpander environmentMacroExpander = + [](const std::string& macroNamespace, const std::string& macroName, + std::string& expanded, int /*version*/) -> ExpandMacroResult { + if (macroNamespace == "penv") { + if (macroName.empty()) { + return ExpandMacroResult::Error; + } + if (cm::optional<std::string> value = + cmSystemTools::GetEnvVar(macroName)) { + expanded += *value; + } + return ExpandMacroResult::Ok; + } + + return ExpandMacroResult::Ignore; + }; + + macroExpanders.push_back(environmentMacroExpander); + + for (Json::ArrayIndex i = 0; i < presets.Include.size(); ++i) { + auto include = presets.Include[i]; + + // Support for macro expansion in includes added in version 7 + if (v >= 7) { + if (ExpandMacros(include, macroExpanders, v) != ExpandMacroResult::Ok) { + cmCMakePresetErrors::INVALID_INCLUDE(&root["include"][i], + &this->parseState); + return false; + } + } + if (!cmSystemTools::FileIsFullPath(include)) { auto directory = cmSystemTools::GetFilenamePath(filename); include = cmStrCat(directory, '/', include); diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index c8eea38b75..a3110413f8 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -55,6 +55,7 @@ #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmJSONState.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmProcessOutput.h" #include "cmState.h" @@ -1468,7 +1469,7 @@ void cmCTest::AddSiteProperties(cmXMLWriter& xml) ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels"); if (labels) { xml.StartElement("Labels"); - std::vector<std::string> args = cmExpandedList(*labels); + cmList args{ *labels }; for (std::string const& i : args) { xml.Element("Label", i); } @@ -1500,7 +1501,7 @@ std::vector<std::string> cmCTest::GetLabelsForSubprojects() { std::string labelsForSubprojects = this->GetCTestConfiguration("LabelsForSubprojects"); - std::vector<std::string> subprojects = cmExpandedList(labelsForSubprojects); + cmList subprojects{ labelsForSubprojects }; // sort the array std::sort(subprojects.begin(), subprojects.end()); @@ -1508,7 +1509,7 @@ std::vector<std::string> cmCTest::GetLabelsForSubprojects() auto new_end = std::unique(subprojects.begin(), subprojects.end()); subprojects.erase(new_end, subprojects.end()); - return subprojects; + return std::move(subprojects.data()); } void cmCTest::EndXML(cmXMLWriter& xml) @@ -3098,8 +3099,7 @@ void cmCTest::PopulateCustomVector(cmMakefile* mf, const std::string& def, } cmCTestLog(this, DEBUG, "PopulateCustomVector: " << def << std::endl); - vec.clear(); - cmExpandList(*dval, vec); + cmList::assign(vec, *dval); for (std::string const& it : vec) { cmCTestLog(this, DEBUG, " -- " << it << std::endl); diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index b9d1f66d2a..d95dcc44ce 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -12,6 +12,7 @@ #include "cmsys/Glob.hxx" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmMessageType.h" #include "cmMessenger.h" #include "cmState.h" @@ -531,15 +532,11 @@ void cmCacheManager::AddCacheEntry(const std::string& key, cmValue value, // make sure we only use unix style paths if (type == cmStateEnums::FILEPATH || type == cmStateEnums::PATH) { if (e.Value.find(';') != std::string::npos) { - std::vector<std::string> paths = cmExpandedList(e.Value); - const char* sep = ""; - e.Value = ""; + cmList paths{ e.Value }; for (std::string& i : paths) { cmSystemTools::ConvertToUnixSlashes(i); - e.Value += sep; - e.Value += i; - sep = ";"; } + e.Value = paths.to_string(); } else { cmSystemTools::ConvertToUnixSlashes(e.Value); } diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index f6fdd48969..1cb62b39d8 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -15,6 +15,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalCommonGenerator.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalCommonGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -303,8 +304,7 @@ std::string cmCommonTargetGenerator::GetLinkerLauncher( *launcherProp, this->LocalCommonGenerator, config, this->GeneratorTarget, &dagChecker, this->GeneratorTarget, lang); // Convert ;-delimited list to single string - std::vector<std::string> args = - cmExpandedList(evaluatedLinklauncher, true); + cmList args{ evaluatedLinklauncher, cmList::EmptyElements::Yes }; if (!args.empty()) { args[0] = this->LocalCommonGenerator->ConvertToOutputFormat( args[0], cmOutputConverter::SHELL); diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 5f408d0c65..f51a1c895c 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -20,6 +20,7 @@ #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -627,7 +628,7 @@ void cmComputeLinkDepends::AddVarLinkEntries(size_t depender_index, // This is called to add the dependencies named by // <item>_LIB_DEPENDS. The variable contains a semicolon-separated // list. The list contains link-type;item pairs and just items. - std::vector<std::string> deplist = cmExpandedList(value); + cmList deplist{ value }; // Look for entries meant for this configuration. std::vector<cmLinkItem> actual_libs; diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index a93477b924..5d44a6ae70 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -15,6 +15,7 @@ #include "cmComputeLinkDepends.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -858,8 +859,8 @@ bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature) return false; } - auto items = cmExpandListWithBacktrace(*langFeature, - this->Target->GetBacktrace(), true); + auto items = cmExpandListWithBacktrace( + *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes); if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) || (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) { @@ -1016,8 +1017,8 @@ cmComputeLinkInformation::GetGroupFeature(std::string const& feature) .first->second; } - auto items = cmExpandListWithBacktrace(*langFeature, - this->Target->GetBacktrace(), true); + auto items = cmExpandListWithBacktrace( + *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes); // replace LINKER: pattern this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true); @@ -1072,8 +1073,8 @@ void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang) } if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(cmStrCat( "CMAKE_", lang, "_RUNTIME_LIBRARY_LINK_OPTIONS_", runtimeLibrary))) { - std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions); - for (std::string const& i : libsVec) { + cmList libs{ *runtimeLinkOptions }; + for (auto const& i : libs) { if (!cm::contains(this->ImplicitLinkLibs, i)) { this->AddItem({ i }); } @@ -1087,8 +1088,8 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) // linker language. std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES"); if (cmValue libs = this->Makefile->GetDefinition(libVar)) { - std::vector<std::string> libsVec = cmExpandedList(*libs); - for (std::string const& i : libsVec) { + cmList libsList{ *libs }; + for (auto const& i : libsList) { if (!cm::contains(this->ImplicitLinkLibs, i)) { this->AddItem({ i }); } @@ -1099,8 +1100,8 @@ void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang) // implied by the linker language. std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES"); if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) { - std::vector<std::string> dirsVec = cmExpandedList(*dirs); - this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec); + cmList dirsList{ *dirs }; + this->OrderLinkerSearchPath->AddLanguageDirectories(dirsList); } } @@ -1370,15 +1371,15 @@ void cmComputeLinkInformation::ComputeItemParserInfo() LinkUnknown); if (cmValue linkSuffixes = mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) { - std::vector<std::string> linkSuffixVec = cmExpandedList(*linkSuffixes); - for (std::string const& i : linkSuffixVec) { + cmList linkSuffixList{ *linkSuffixes }; + for (auto const& i : linkSuffixList) { this->AddLinkExtension(i, LinkUnknown); } } if (cmValue sharedSuffixes = mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) { - std::vector<std::string> sharedSuffixVec = cmExpandedList(*sharedSuffixes); - for (std::string const& i : sharedSuffixVec) { + cmList sharedSuffixList{ *sharedSuffixes }; + for (std::string const& i : sharedSuffixList) { this->AddLinkExtension(i, LinkShared); } } @@ -1916,19 +1917,18 @@ void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item) void cmComputeLinkInformation::ComputeFrameworkInfo() { // Avoid adding implicit framework paths. - std::vector<std::string> implicitDirVec; + cmList implicitDirs; // Get platform-wide implicit directories. - this->Makefile->GetDefExpandList( - "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", implicitDirVec); + implicitDirs.assign(this->Makefile->GetDefinition( + "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES")); // Get language-specific implicit directories. std::string implicitDirVar = cmStrCat( "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"); - this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec); + implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar)); - this->FrameworkPathsEmitted.insert(implicitDirVec.begin(), - implicitDirVec.end()); + this->FrameworkPathsEmitted.insert(implicitDirs.begin(), implicitDirs.end()); } void cmComputeLinkInformation::AddFrameworkPath(std::string const& p) @@ -2138,17 +2138,15 @@ void cmComputeLinkInformation::PrintLinkPolicyDiagnosis(std::ostream& os) void cmComputeLinkInformation::LoadImplicitLinkInfo() { - std::vector<std::string> implicitDirVec; - // Get platform-wide implicit directories. - this->Makefile->GetDefExpandList("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES", - implicitDirVec); + cmList implicitDirs{ this->Makefile->GetDefinition( + "CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES") }; // Append library architecture to all implicit platform directories // and add them to the set if (cmValue libraryArch = this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) { - for (std::string const& i : implicitDirVec) { + for (auto const& i : implicitDirs) { this->ImplicitLinkDirs.insert(cmStrCat(i, '/', *libraryArch)); } } @@ -2156,19 +2154,18 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() // Get language-specific implicit directories. std::string implicitDirVar = cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES"); - this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec); + implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar)); // Store implicit link directories. - this->ImplicitLinkDirs.insert(implicitDirVec.begin(), implicitDirVec.end()); + this->ImplicitLinkDirs.insert(implicitDirs.begin(), implicitDirs.end()); // Get language-specific implicit libraries. - std::vector<std::string> implicitLibVec; std::string implicitLibVar = cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES"); - this->Makefile->GetDefExpandList(implicitLibVar, implicitLibVec); + cmList implicitLibs{ this->Makefile->GetDefinition(implicitLibVar) }; // Store implicit link libraries. - for (std::string const& item : implicitLibVec) { + for (auto const& item : implicitLibs) { // Items starting in '-' but not '-l' are flags, not libraries, // and should not be filtered by this implicit list. if (item[0] != '-' || item[1] == 'l') { @@ -2177,8 +2174,8 @@ void cmComputeLinkInformation::LoadImplicitLinkInfo() } // Get platform specific rpath link directories - this->Makefile->GetDefExpandList("CMAKE_PLATFORM_RUNTIME_PATH", - this->RuntimeLinkDirs); + cmList::append(this->RuntimeLinkDirs, + this->Makefile->GetDefinition("CMAKE_PLATFORM_RUNTIME_PATH")); } std::vector<std::string> const& @@ -2279,7 +2276,7 @@ static void cmCLI_ExpandListUnique(std::string const& str, std::vector<std::string>& out, std::set<std::string>& emitted) { - std::vector<std::string> tmp = cmExpandedList(str); + cmList tmp{ str }; for (std::string const& i : tmp) { if (emitted.insert(i).second) { out.push_back(i); diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 5de012a7fa..288e107d0a 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -18,6 +18,7 @@ #include "cmCMakePath.h" #include "cmExpandedCommandArgument.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmState.h" @@ -764,7 +765,9 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, cmValue rhs = this->Makefile.GetDefinition(args.nextnext->GetValue()); newArgs.ReduceTwoArgs( - rhs && cm::contains(cmExpandedList(*rhs, true), *lhs), args); + rhs && + cm::contains(cmList{ *rhs, cmList::EmptyElements::Yes }, *lhs), + args); } else if (this->Policy57Status == cmPolicies::WARN) { diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 3149ccfa9c..7d4ab50967 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -20,6 +20,7 @@ #include "cmConfigureLog.h" #include "cmExportTryCompileFileGenerator.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmOutputConverter.h" @@ -125,7 +126,7 @@ ArgumentParser::Continue TryCompileLangProp(Arguments& args, ArgumentParser::Continue TryCompileCompileDefs(Arguments& args, cm::string_view val) { - cmExpandList(val, args.CompileDefs); + args.CompileDefs.append(val); return ArgumentParser::Continue::Yes; } @@ -788,7 +789,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( if (!arguments.CompileDefs.empty()) { // Pass using bracket arguments to preserve content. fprintf(fout, "add_definitions([==[%s]==])\n", - cmJoin(arguments.CompileDefs, "]==] [==[").c_str()); + arguments.CompileDefs.join("]==] [==[").c_str()); } if (!targets.empty()) { @@ -1024,7 +1025,7 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( if (cmValue varListStr = this->Makefile->GetDefinition( kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES)) { - std::vector<std::string> varList = cmExpandedList(*varListStr); + cmList varList{ *varListStr }; vars.insert(varList.begin(), varList.end()); } diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index ba38c196b8..c185c68feb 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -12,6 +12,7 @@ #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" +#include "cmList.h" #include "cmStateTypes.h" class cmConfigureLog; @@ -65,7 +66,7 @@ public: ArgumentParser::MaybeEmpty<std::vector<std::string>> CMakeFlags{ 1, "CMAKE_FLAGS" }; // fake argv[0] - std::vector<std::string> CompileDefs; + cmList CompileDefs; cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> LinkLibraries; ArgumentParser::MaybeEmpty<std::vector<std::string>> LinkOptions; diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 14c22e3a45..7623ccfd18 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -17,6 +17,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" @@ -116,7 +117,7 @@ std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths, /*outputConfig=*/outputConfig, /*commandConfig=*/commandConfig, /*target=*/nullptr); - cm::append(depends, cmExpandedList(ep)); + cm::append(depends, cmList{ ep }); } for (std::string& p : depends) { if (cmSystemTools::FileIsFullPath(p)) { @@ -196,7 +197,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator( clarg, ge, this->LG, useOutputConfig, this->OutputConfig, this->CommandConfig, target, &this->Utilities); if (this->CC->GetCommandExpandLists()) { - cm::append(argv, cmExpandedList(parsed_arg)); + cm::append(argv, cmList{ parsed_arg }); } else { argv.push_back(std::move(parsed_arg)); } diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index eca1abdaae..04bccce5e7 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -9,6 +9,7 @@ #include "cmFileTime.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" +#include "cmList.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" @@ -28,11 +29,11 @@ bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends) std::map<std::string, std::set<std::string>> dependencies; { // Lookup the set of sources to scan. - std::vector<std::string> pairs; + cmList pairs; { std::string const srcLang = "CMAKE_DEPENDS_CHECK_" + this->Language; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - cmExpandList(mf->GetSafeDefinition(srcLang), pairs); + pairs.assign(mf->GetSafeDefinition(srcLang)); } for (auto si = pairs.begin(); si != pairs.end();) { // Get the source and object file. diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 25278090a4..408a85b325 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -8,6 +8,7 @@ #include "cmFileTime.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmList.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" @@ -393,10 +394,10 @@ void cmDependsC::Scan(std::istream& is, const std::string& directory, void cmDependsC::SetupTransforms() { // Get the transformation rules. - std::vector<std::string> transformRules; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - mf->GetDefExpandList("CMAKE_INCLUDE_TRANSFORMS", transformRules, true); - for (std::string const& tr : transformRules) { + cmList transformRules{ mf->GetDefinition("CMAKE_INCLUDE_TRANSFORMS"), + cmList::EmptyElements::Yes }; + for (auto const& tr : transformRules) { this->ParseTransform(tr); } diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx index 0cc4946e48..c8061c36ee 100644 --- a/Source/cmDependsCompiler.cxx +++ b/Source/cmDependsCompiler.cxx @@ -128,7 +128,7 @@ bool cmDependsCompiler::CheckDependencies( } std::string line; - if (!isValidPath) { + if (!isValidPath && !source.empty()) { // insert source as first dependency depends.push_back(source); } @@ -158,14 +158,16 @@ bool cmDependsCompiler::CheckDependencies( } // ensure source file is the first dependency - if (depends.front() != source) { - cm::erase(depends, source); - if (!isValidPath) { - depends.insert(depends.begin(), source); + if (!source.empty()) { + if (depends.front() != source) { + cm::erase(depends, source); + if (!isValidPath) { + depends.insert(depends.begin(), source); + } + } else if (isValidPath) { + // remove first dependency because it must not be filtered out + depends.erase(depends.begin()); } - } else if (isValidPath) { - // remove first dependency because it must not be filtered out - depends.erase(depends.begin()); } } else { // unknown format, ignore it @@ -174,8 +176,10 @@ bool cmDependsCompiler::CheckDependencies( if (isValidPath) { cm::erase_if(depends, isValidPath); - // insert source as first dependency - depends.insert(depends.begin(), source); + if (!source.empty()) { + // insert source as first dependency + depends.insert(depends.begin(), source); + } } dependencies[target] = std::move(depends); diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 718097f0be..aede3fecff 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -13,6 +13,7 @@ #include "cmFortranParser.h" /* Interface to parser object. */ #include "cmGeneratedFileStream.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmList.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -78,9 +79,8 @@ cmDependsFortran::cmDependsFortran(cmLocalUnixMakefileGenerator3* lg) this->SetIncludePathFromLanguage("Fortran"); // Get the list of definitions. - std::vector<std::string> definitions; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - mf->GetDefExpandList("CMAKE_TARGET_DEFINITIONS_Fortran", definitions); + cmList definitions{ mf->GetDefinition("CMAKE_TARGET_DEFINITIONS_Fortran") }; // translate i.e. FOO=BAR to FOO and add it to the list of defined // preprocessor symbols @@ -244,9 +244,9 @@ bool cmDependsFortran::LocateModules() // Load information about other targets. cmMakefile* mf = this->LocalGenerator->GetMakefile(); - std::vector<std::string> infoFiles; - mf->GetDefExpandList("CMAKE_Fortran_TARGET_LINKED_INFO_FILES", infoFiles); - for (std::string const& i : infoFiles) { + cmList infoFiles{ mf->GetDefinition( + "CMAKE_Fortran_TARGET_LINKED_INFO_FILES") }; + for (auto const& i : infoFiles) { std::string targetDir = cmSystemTools::GetFilenamePath(i); std::string fname = targetDir + "/fortran.internal"; cmsys::ifstream fin(fname.c_str()); diff --git a/Source/cmEvaluatedTargetProperty.cxx b/Source/cmEvaluatedTargetProperty.cxx index 1173690318..b82c29b75c 100644 --- a/Source/cmEvaluatedTargetProperty.cxx +++ b/Source/cmEvaluatedTargetProperty.cxx @@ -8,7 +8,7 @@ #include "cmGeneratorExpressionContext.h" #include "cmGeneratorTarget.h" #include "cmLinkItem.h" -#include "cmStringAlgorithms.h" +#include "cmList.h" struct cmGeneratorExpressionDAGChecker; diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx index 5d0b208931..5e7008b957 100644 --- a/Source/cmExportBuildAndroidMKGenerator.cxx +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -10,6 +10,7 @@ #include "cmGeneratorTarget.h" #include "cmLinkItem.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" @@ -148,7 +149,7 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( } } else if (property.first == "INTERFACE_INCLUDE_DIRECTORIES") { std::string includes = property.second; - std::vector<std::string> includeList = cmExpandedList(includes); + cmList includeList{ includes }; os << "LOCAL_EXPORT_C_INCLUDES := "; std::string end; for (std::string const& i : includeList) { @@ -158,9 +159,8 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( os << "\n"; } else if (property.first == "INTERFACE_LINK_OPTIONS") { os << "LOCAL_EXPORT_LDFLAGS := "; - std::vector<std::string> linkFlagsList = - cmExpandedList(property.second); - os << cmJoin(linkFlagsList, " ") << "\n"; + cmList linkFlagsList{ property.second }; + os << linkFlagsList.join(" ") << "\n"; } else { os << "# " << property.first << " " << (property.second) << "\n"; } diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index e997158c3e..22276ae508 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -17,6 +17,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmLinkItem.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -507,7 +508,7 @@ static void getPropertyContents(cmGeneratorTarget const* tgt, if (!p) { return; } - std::vector<std::string> content = cmExpandedList(*p); + cmList content{ *p }; ifaceProperties.insert(content.begin(), content.end()); } @@ -1261,7 +1262,7 @@ bool cmExportFileGenerator::PopulateExportProperties( const auto& targetProperties = gte->Target->GetProperties(); if (cmValue exportProperties = targetProperties.GetPropertyValue("EXPORT_PROPERTIES")) { - for (auto& prop : cmExpandedList(*exportProperties)) { + for (auto& prop : cmList{ *exportProperties }) { /* Black list reserved properties */ if (cmHasLiteralPrefix(prop, "IMPORTED_") || cmHasLiteralPrefix(prop, "INTERFACE_")) { @@ -1325,7 +1326,22 @@ void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte, << this->GetFileSetFiles(gte, fileSet, te) << "\n"; } - os << " )\nendif()\n\n"; + os << " )\nelse()\n set_property(TARGET " << targetName + << "\n APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES"; + 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 << "\n " << this->GetFileSetDirectories(gte, fileSet, te); + } + os << "\n )\nendif()\n\n"; } } diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index c6ebad5c2d..f30c3c3ba4 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -12,6 +12,7 @@ #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -126,7 +127,7 @@ void cmExportTryCompileFileGenerator::PopulateProperties( std::string evalResult = this->FindTargets(p, target, std::string(), emitted); - std::vector<std::string> depends = cmExpandedList(evalResult); + cmList depends{ evalResult }; for (std::string const& li : depends) { cmGeneratorTarget* tgt = target->GetLocalGenerator()->FindGeneratorTargetToUse(li); diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index e9e2921316..8d7f33e7ef 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -14,6 +14,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmRange.h" @@ -567,13 +568,13 @@ void cmExtraCodeBlocksGenerator::AppendTarget( std::string systemIncludeDirs = makefile->GetSafeDefinition( "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) { - cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs)); + cm::append(allIncludeDirs, cmList{ systemIncludeDirs }); } systemIncludeDirs = makefile->GetSafeDefinition( "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) { - cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs)); + cm::append(allIncludeDirs, cmList{ systemIncludeDirs }); } auto end = cmRemoveDuplicates(allIncludeDirs); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 6201889f22..c7ce5b0676 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -16,6 +16,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -418,7 +419,7 @@ void cmExtraEclipseCDT4Generator::CreateProjectFile() if (cmValue extraNaturesProp = mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) { - std::vector<std::string> extraNatures = cmExpandedList(*extraNaturesProp); + cmList extraNatures{ *extraNaturesProp }; for (std::string const& n : extraNatures) { xml.Element("nature", n); } @@ -798,7 +799,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const mf->GetDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS"); if (this->CEnabled && cDefs) { // Expand the list. - std::vector<std::string> defs = cmExpandedList(*cDefs, true); + cmList defs{ *cDefs, cmList::EmptyElements::Yes }; // the list must contain only definition-value pairs: if ((defs.size() % 2) == 0) { @@ -830,7 +831,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const mf->GetDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS"); if (this->CXXEnabled && cxxDefs) { // Expand the list. - std::vector<std::string> defs = cmExpandedList(*cxxDefs, true); + cmList defs{ *cxxDefs, cmList::EmptyElements::Yes }; // the list must contain only definition-value pairs: if ((defs.size() % 2) == 0) { @@ -879,14 +880,14 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const if (this->CEnabled && !compiler.empty()) { std::string systemIncludeDirs = mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); - std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs); + cmList dirs{ systemIncludeDirs }; this->AppendIncludeDirectories(xml, dirs, emitted); } compiler = mf->GetSafeDefinition("CMAKE_CXX_COMPILER"); if (this->CXXEnabled && !compiler.empty()) { std::string systemIncludeDirs = mf->GetSafeDefinition("CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); - std::vector<std::string> dirs = cmExpandedList(systemIncludeDirs); + cmList dirs{ systemIncludeDirs }; this->AppendIncludeDirectories(xml, dirs, emitted); } diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 33901ac594..205a691f21 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -14,6 +14,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -138,7 +139,7 @@ void cmExtraSublimeTextGenerator::CreateNewProjectFile( // End of build_systems fout << "\n\t]"; std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME"); - std::vector<std::string> tokens = cmExpandedList(this->EnvSettings); + cmList tokens{ this->EnvSettings }; if (!this->EnvSettings.empty()) { fout << ","; diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx index fe2972fabf..a51ae2048e 100644 --- a/Source/cmFileAPIToolchains.cxx +++ b/Source/cmFileAPIToolchains.cxx @@ -10,6 +10,7 @@ #include "cmFileAPI.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -124,10 +125,11 @@ void Toolchains::DumpToolchainVariable(cmMakefile const* mf, cmStrCat("CMAKE_", lang, "_", variable.VariableSuffix); if (variable.IsList) { - std::vector<std::string> values; - if (mf->GetDefExpandList(variableName, values)) { + cmValue data = mf->GetDefinition(variableName); + if (data) { + cmList values(data); Json::Value jsonArray = Json::arrayValue; - for (std::string const& value : values) { + for (auto const& value : values) { jsonArray.append(value); } object[variable.ObjectKey] = jsonArray; diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx index ef55abfd14..663bddcece 100644 --- a/Source/cmFileCopier.cxx +++ b/Source/cmFileCopier.cxx @@ -9,6 +9,7 @@ #include "cmExecutionStatus.h" #include "cmFSPermissions.h" #include "cmFileTimes.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -169,8 +170,7 @@ bool cmFileCopier::GetDefaultDirectoryPermissions(mode_t** mode) cmValue default_dir_install_permissions = this->Makefile->GetDefinition( "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); if (cmNonempty(default_dir_install_permissions)) { - std::vector<std::string> items = - cmExpandedList(*default_dir_install_permissions); + cmList items{ *default_dir_install_permissions }; for (const auto& arg : items) { if (!this->CheckPermissions(arg, **mode)) { this->Status.SetError( diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx index b96ba6e886..48a2570d56 100644 --- a/Source/cmFileSet.cxx +++ b/Source/cmFileSet.cxx @@ -12,6 +12,7 @@ #include "cmsys/RegularExpression.hxx" #include "cmGeneratorExpression.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -113,7 +114,7 @@ cmFileSet::CompileFileEntries() const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result; for (auto const& entry : this->FileEntries) { - for (auto const& ex : cmExpandedList(entry.Value)) { + for (auto const& ex : cmList{ entry.Value }) { cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace); auto cge = ge.Parse(ex); result.push_back(std::move(cge)); @@ -129,7 +130,7 @@ cmFileSet::CompileDirectoryEntries() const std::vector<std::unique_ptr<cmCompiledGeneratorExpression>> result; for (auto const& entry : this->DirectoryEntries) { - for (auto const& ex : cmExpandedList(entry.Value)) { + for (auto const& ex : cmList{ entry.Value }) { cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace); auto cge = ge.Parse(ex); result.push_back(std::move(cge)); @@ -148,7 +149,7 @@ std::vector<std::string> cmFileSet::EvaluateDirectoryEntries( std::vector<std::string> result; for (auto const& cge : cges) { auto entry = cge->Evaluate(lg, config, target, dagChecker); - auto dirs = cmExpandedList(entry); + cmList dirs{ entry }; for (std::string dir : dirs) { if (!cmSystemTools::FileIsFullPath(dir)) { dir = cmStrCat(lg->GetCurrentSourceDirectory(), '/', dir); @@ -184,7 +185,7 @@ void cmFileSet::EvaluateFileEntry( cmGeneratorExpressionDAGChecker* dagChecker) const { auto files = cge->Evaluate(lg, config, target, dagChecker); - for (std::string file : cmExpandedList(files)) { + for (std::string file : cmList{ files }) { if (!cmSystemTools::FileIsFullPath(file)) { file = cmStrCat(lg->GetCurrentSourceDirectory(), '/', file); } diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index 4df81d5773..929c6c1c82 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -15,6 +15,7 @@ #include "cmCMakePath.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -154,7 +155,7 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) } // ensure a macro is not specified as validator const auto& validatorName = args[j]; - auto macros = cmExpandedList(this->Makefile->GetProperty("MACROS")); + cmList macros{ this->Makefile->GetProperty("MACROS") }; if (std::find_if(macros.begin(), macros.end(), [&validatorName](const std::string& item) { return cmSystemTools::Strucmp(validatorName.c_str(), @@ -403,7 +404,7 @@ void cmFindBase::FillCMakeSystemVariablePath() this->Makefile->GetDefinition("CMAKE_SYSTEM_PREFIX_PATH"); // remove entries from CMAKE_SYSTEM_PREFIX_PATH - std::vector<std::string> expanded = cmExpandedList(*prefix_paths); + cmList expanded{ *prefix_paths }; install_entry.remove_self(expanded); staging_entry.remove_self(expanded); diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index c3fb9077da..bec6369211 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -9,6 +9,7 @@ #include <cmext/algorithm> #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" @@ -238,9 +239,9 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) } // Construct the list of path roots with no trailing slashes. - std::vector<std::string> roots; + cmList roots; if (rootPath) { - cmExpandList(*rootPath, roots); + roots.assign(*rootPath); } if (sysrootCompile) { roots.emplace_back(*sysrootCompile); @@ -251,14 +252,14 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) if (sysroot) { roots.emplace_back(*sysroot); } - for (std::string& r : roots) { + for (auto& r : roots) { cmSystemTools::ConvertToUnixSlashes(r); } cmValue stagePrefix = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX"); // Copy the original set of unrooted paths. - std::vector<std::string> unrootedPaths = paths; + auto unrootedPaths = paths; paths.clear(); auto isSameDirectoryOrSubDirectory = [](std::string const& l, @@ -267,8 +268,8 @@ void cmFindCommon::RerootPaths(std::vector<std::string>& paths) cmSystemTools::IsSubDirectory(l, r); }; - for (std::string const& r : roots) { - for (std::string const& up : unrootedPaths) { + for (auto const& r : roots) { + for (auto 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. @@ -308,7 +309,7 @@ void cmFindCommon::GetIgnoredPaths(std::vector<std::string>& ignore) // 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); + cmList::append(ignore, this->Makefile->GetDefinition(pathName)); } for (std::string& i : ignore) { @@ -333,7 +334,7 @@ void cmFindCommon::GetIgnoredPrefixPaths(std::vector<std::string>& ignore) // 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); + cmList::append(ignore, this->Makefile->GetDefinition(pathName)); } for (std::string& i : ignore) { diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index 6296a60aeb..9eb060357a 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -11,6 +11,7 @@ #include "cmsys/RegularExpression.hxx" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStateTypes.h" @@ -196,8 +197,8 @@ struct cmFindLibraryHelper cmGlobalGenerator* GG; // List of valid prefixes and suffixes. - std::vector<std::string> Prefixes; - std::vector<std::string> Suffixes; + cmList Prefixes; + cmList Suffixes; std::string PrefixRegexStr; std::string SuffixRegexStr; @@ -223,7 +224,7 @@ struct cmFindLibraryHelper std::string TestPath; void RegexFromLiteral(std::string& out, std::string const& in); - void RegexFromList(std::string& out, std::vector<std::string> const& in); + void RegexFromList(std::string& out, cmList const& in); size_type GetPrefixIndex(std::string const& prefix) { return std::find(this->Prefixes.begin(), this->Prefixes.end(), prefix) - @@ -307,8 +308,8 @@ cmFindLibraryHelper::cmFindLibraryHelper(std::string debugName, cmMakefile* mf, std::string const& prefixes_list = get_prefixes(this->Makefile); std::string const& suffixes_list = get_suffixes(this->Makefile); - cmExpandList(prefixes_list, this->Prefixes, true); - cmExpandList(suffixes_list, this->Suffixes, true); + this->Prefixes.assign(prefixes_list, cmList::EmptyElements::Yes); + this->Suffixes.assign(suffixes_list, cmList::EmptyElements::Yes); this->RegexFromList(this->PrefixRegexStr, this->Prefixes); this->RegexFromList(this->SuffixRegexStr, this->Suffixes); @@ -334,14 +335,13 @@ void cmFindLibraryHelper::RegexFromLiteral(std::string& out, } } -void cmFindLibraryHelper::RegexFromList(std::string& out, - std::vector<std::string> const& in) +void cmFindLibraryHelper::RegexFromList(std::string& out, cmList const& in) { // Surround the list in parens so the '|' does not apply to anything // else and the result can be checked after matching. out += "("; const char* sep = ""; - for (std::string const& s : in) { + for (auto const& s : in) { // Separate from previous item. out += sep; sep = "|"; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index b1029e62c8..98b085cdc0 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -23,6 +23,7 @@ #include "cmAlgorithms.h" #include "cmDependencyProvider.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -1781,28 +1782,20 @@ bool cmFindPackageCommand::ReadListFile(const std::string& f, void cmFindPackageCommand::AppendToFoundProperty(const bool found) { - std::vector<std::string> foundContents; + cmList foundContents; cmValue foundProp = this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND"); - if (cmNonempty(foundProp)) { - cmExpandList(*foundProp, foundContents, false); - auto nameIt = - std::find(foundContents.begin(), foundContents.end(), this->Name); - if (nameIt != foundContents.end()) { - foundContents.erase(nameIt); - } + if (!foundProp.IsEmpty()) { + foundContents.assign(*foundProp); + foundContents.remove_items({ this->Name }); } - std::vector<std::string> notFoundContents; + cmList notFoundContents; cmValue notFoundProp = this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND"); - if (cmNonempty(notFoundProp)) { - cmExpandList(*notFoundProp, notFoundContents, false); - auto nameIt = - std::find(notFoundContents.begin(), notFoundContents.end(), this->Name); - if (nameIt != notFoundContents.end()) { - notFoundContents.erase(nameIt); - } + if (!notFoundProp.IsEmpty()) { + notFoundContents.assign(*notFoundProp); + notFoundContents.remove_items({ this->Name }); } if (found) { @@ -1811,12 +1804,11 @@ void cmFindPackageCommand::AppendToFoundProperty(const bool found) notFoundContents.push_back(this->Name); } - std::string tmp = cmJoin(foundContents, ";"); - this->Makefile->GetState()->SetGlobalProperty("PACKAGES_FOUND", tmp.c_str()); + this->Makefile->GetState()->SetGlobalProperty( + "PACKAGES_FOUND", foundContents.to_string().c_str()); - tmp = cmJoin(notFoundContents, ";"); - this->Makefile->GetState()->SetGlobalProperty("PACKAGES_NOT_FOUND", - tmp.c_str()); + this->Makefile->GetState()->SetGlobalProperty( + "PACKAGES_NOT_FOUND", notFoundContents.to_string().c_str()); } void cmFindPackageCommand::AppendSuccessInformation() @@ -2338,7 +2330,7 @@ void cmFindPackageCommand::FillPrefixesCMakeSystemVariable() cmValue prefix_paths = this->Makefile->GetDefinition("CMAKE_SYSTEM_PREFIX_PATH"); // remove entry from CMAKE_SYSTEM_PREFIX_PATH - std::vector<std::string> expanded = cmExpandedList(*prefix_paths); + cmList expanded{ *prefix_paths }; long count = 0; for (const auto& path : expanded) { bool const to_add = diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 3465c230f8..21a140d02c 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -23,6 +23,7 @@ #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -156,16 +157,16 @@ bool cmForEachFunctionBlocker::ReplayZipLists( auto& mf = inStatus.GetMakefile(); // Expand the list of list-variables into a list of lists of strings - std::vector<std::vector<std::string>> values; + std::vector<cmList> values; values.reserve(this->Args.size() - this->IterationVarsCount); // Also track the longest list size std::size_t maxItems = 0u; for (auto const& var : cmMakeRange(this->Args).advance(this->IterationVarsCount)) { - std::vector<std::string> items; + cmList items; auto const& value = mf.GetSafeDefinition(var); if (!value.empty()) { - cmExpandList(value, items, true); + items.assign(value, cmList::EmptyElements::Yes); } maxItems = std::max(maxItems, items.size()); values.emplace_back(std::move(items)); @@ -344,7 +345,7 @@ bool HandleInMode(std::vector<std::string> const& args, } else if (doing == DoingLists) { auto const& value = makefile.GetSafeDefinition(arg); if (!value.empty()) { - cmExpandList(value, fb->Args, true); + cmExpandList(value, fb->Args, cmList::EmptyElements::Yes); } } else if (doing == DoingItems || doing == DoingZipLists) { diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx index 34c88248a0..87377de401 100644 --- a/Source/cmGccDepfileLexerHelper.cxx +++ b/Source/cmGccDepfileLexerHelper.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGccDepfileLexerHelper.h" +#include <algorithm> #include <cstdio> #include <memory> #include <string> @@ -113,6 +114,11 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) void cmGccDepfileLexerHelper::sanitizeContent() { for (auto it = this->Content.begin(); it != this->Content.end();) { + // remove duplicate path entries + std::sort(it->paths.begin(), it->paths.end()); + auto last = std::unique(it->paths.begin(), it->paths.end()); + it->paths.erase(last, it->paths.end()); + // Remove empty paths and normalize windows paths for (auto pit = it->paths.begin(); pit != it->paths.end();) { if (pit->empty()) { diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index c5ae31bd38..04decd239c 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -14,6 +14,7 @@ #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorExpressionLexer.h" #include "cmGeneratorExpressionParser.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index ca61f75ffa..bb4fc7e271 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -19,7 +19,6 @@ #include <cm/iterator> #include <cm/optional> #include <cm/string_view> -#include <cm/vector> #include <cmext/algorithm> #include <cmext/string_view> @@ -635,22 +634,48 @@ public: using Arguments = Range<std::vector<std::string>>; -bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx, - const GeneratorExpressionContent* cnt, - cm::string_view option, std::size_t count, - int required = 1, bool exactly = true) +bool CheckGenExParameters(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view genex, cm::string_view option, + std::size_t count, int required = 1, + bool exactly = true) { if (static_cast<int>(count) < required || (exactly && static_cast<int>(count) > required)) { + std::string nbParameters; + switch (required) { + case 1: + nbParameters = "one parameter"; + break; + case 2: + nbParameters = "two parameters"; + break; + case 3: + nbParameters = "three parameters"; + break; + case 4: + nbParameters = "four parameters"; + break; + default: + nbParameters = cmStrCat(std::to_string(required), " parameters"); + } reportError(ctx, cnt->GetOriginalExpression(), - cmStrCat("$<PATH:", option, "> expression requires ", - (exactly ? "exactly" : "at least"), ' ', - (required == 1 ? "one parameter" : "two parameters"), + cmStrCat("$<", genex, ':', option, "> expression requires ", + (exactly ? "exactly" : "at least"), ' ', nbParameters, '.')); return false; } return true; }; + +bool CheckPathParametersEx(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view option, std::size_t count, + int required = 1, bool exactly = true) +{ + return CheckGenExParameters(ctx, cnt, "PATH"_s, option, count, required, + exactly); +} bool CheckPathParameters(cmGeneratorExpressionContext* ctx, const GeneratorExpressionContent* cnt, cm::string_view option, const Arguments& args, @@ -658,6 +683,7 @@ bool CheckPathParameters(cmGeneratorExpressionContext* ctx, { return CheckPathParametersEx(ctx, cnt, option, args.size(), required); }; + std::string ToString(bool isTrue) { return isTrue ? "1" : "0"; @@ -681,9 +707,9 @@ static const struct PathNode : public cmGeneratorExpressionNode static auto processList = [](std::string const& arg, std::function<void(std::string&)> transform) -> std::string { - auto list = cmExpandedList(arg); + cmList list{ arg }; std::for_each(list.begin(), list.end(), std::move(transform)); - return cmJoin(list, ";"); + return list.to_string(); }; static std::unordered_map< @@ -1108,6 +1134,675 @@ static const struct PathEqualNode : public cmGeneratorExpressionNode } } pathEqualNode; +namespace { +inline bool CheckListParametersEx(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view option, std::size_t count, + int required = 1, bool exactly = true) +{ + return CheckGenExParameters(ctx, cnt, "LIST"_s, option, count, required, + exactly); +} +inline bool CheckListParameters(cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + cm::string_view option, const Arguments& args, + int required = 1) +{ + return CheckListParametersEx(ctx, cnt, option, args.size(), required); +}; + +inline cmList GetList(std::string const& list) +{ + return list.empty() ? cmList{} : cmList{ list, cmList::EmptyElements::Yes }; +} + +bool GetNumericArgument(const std::string& arg, cmList::index_type& value) +{ + try { + std::size_t pos; + + if (sizeof(cmList::index_type) == sizeof(long)) { + value = std::stol(arg, &pos); + } else { + value = std::stoll(arg, &pos); + } + + if (pos != arg.length()) { + // this is not a number + return false; + } + } catch (const std::invalid_argument&) { + return false; + } + + return true; +} + +bool GetNumericArguments( + cmGeneratorExpressionContext* ctx, const GeneratorExpressionContent* cnt, + Arguments const& args, std::vector<cmList::index_type>& indexes, + cmList::ExpandElements expandElements = cmList::ExpandElements::No) +{ + using IndexRange = cmRange<Arguments::const_iterator>; + IndexRange arguments(args.begin(), args.end()); + cmList list; + if (expandElements == cmList::ExpandElements::Yes) { + list = cmList{ args.begin(), args.end(), expandElements }; + arguments = IndexRange{ list.begin(), list.end() }; + } + + for (auto const& value : arguments) { + cmList::index_type index; + if (!GetNumericArgument(value, index)) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("index: \"", value, "\" is not a valid index")); + return false; + } + indexes.push_back(index); + } + return true; +} +} + +static const struct ListNode : public cmGeneratorExpressionNode +{ + ListNode() {} // NOLINT(modernize-use-equals-default) + + int NumExpectedParameters() const override { return TwoOrMoreParameters; } + + bool AcceptsArbitraryContentParameter() const override { return true; } + + std::string Evaluate( + const std::vector<std::string>& parameters, + cmGeneratorExpressionContext* context, + const GeneratorExpressionContent* content, + cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override + { + static std::unordered_map< + cm::string_view, + std::function<std::string(cmGeneratorExpressionContext*, + const GeneratorExpressionContent*, + Arguments&)>> + listCommands{ + { "LENGTH"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "LENGTH"_s, args)) { + return std::to_string(GetList(args.front()).size()); + } + return std::string{}; + } }, + { "GET"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "GET"_s, args.size(), 2, + false)) { + auto list = GetList(args.front()); + if (list.empty()) { + reportError(ctx, cnt->GetOriginalExpression(), + "given empty list"); + return std::string{}; + } + + std::vector<cmList::index_type> indexes; + if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes, + cmList::ExpandElements::Yes)) { + return std::string{}; + } + try { + return list.get_items(indexes.begin(), indexes.end()) + .to_string(); + } catch (std::out_of_range& e) { + reportError(ctx, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "JOIN"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "JOIN"_s, args, 2)) { + return GetList(args.front()).join(args[1]); + } + return std::string{}; + } }, + { "SUBLIST"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "SUBLIST"_s, args, 3)) { + auto list = GetList(args.front()); + if (!list.empty()) { + std::vector<cmList::index_type> indexes; + if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes)) { + return std::string{}; + } + if (indexes[0] < 0) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("begin index: ", indexes[0], + " is out of range 0 - ", + list.size() - 1)); + return std::string{}; + } + if (indexes[1] < -1) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("length: ", indexes[1], + " should be -1 or greater")); + return std::string{}; + } + try { + return list + .sublist(static_cast<cmList::size_type>(indexes[0]), + static_cast<cmList::size_type>(indexes[1])) + .to_string(); + } catch (std::out_of_range& e) { + reportError(ctx, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + } + return std::string{}; + } }, + { "FIND"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "FIND"_s, args, 2)) { + auto list = GetList(args.front()); + auto index = list.find(args[1]); + return index == cmList::npos ? "-1" : std::to_string(index); + } + return std::string{}; + } }, + { "APPEND"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "APPEND"_s, args.size(), 2, + false)) { + auto list = args.front(); + args.advance(1); + return cmList::append(list, args.begin(), args.end()); + } + return std::string{}; + } }, + { "PREPEND"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "PREPEND"_s, args.size(), 2, + false)) { + auto list = args.front(); + args.advance(1); + return cmList::prepend(list, args.begin(), args.end()); + } + return std::string{}; + } }, + { "INSERT"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "INSERT"_s, args.size(), 3, + false)) { + cmList::index_type index; + if (!GetNumericArgument(args[1], index)) { + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat("index: \"", args[1], "\" is not a valid index")); + return std::string{}; + } + try { + auto list = GetList(args.front()); + args.advance(2); + list.insert_items(index, args.begin(), args.end()); + return list.to_string(); + } catch (std::out_of_range& e) { + reportError(ctx, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "POP_BACK"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "POP_BACK"_s, args)) { + auto list = GetList(args.front()); + if (!list.empty()) { + list.pop_back(); + return list.to_string(); + } + } + return std::string{}; + } }, + { "POP_FRONT"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "POP_FRONT"_s, args)) { + auto list = GetList(args.front()); + if (!list.empty()) { + list.pop_front(); + return list.to_string(); + } + } + return std::string{}; + } }, + { "REMOVE_DUPLICATES"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "REMOVE_DUPLICATES"_s, args)) { + return GetList(args.front()).remove_duplicates().to_string(); + } + return std::string{}; + } }, + { "REMOVE_ITEM"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "REMOVE_ITEM"_s, args.size(), + 2, false)) { + auto list = GetList(args.front()); + args.advance(1); + cmList items{ args.begin(), args.end(), + cmList::ExpandElements::Yes }; + return list.remove_items(items.begin(), items.end()).to_string(); + } + return std::string{}; + } }, + { "REMOVE_AT"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "REMOVE_AT"_s, args.size(), 2, + false)) { + auto list = GetList(args.front()); + std::vector<cmList::index_type> indexes; + if (!GetNumericArguments(ctx, cnt, args.advance(1), indexes, + cmList::ExpandElements::Yes)) { + return std::string{}; + } + try { + return list.remove_items(indexes.begin(), indexes.end()) + .to_string(); + } catch (std::out_of_range& e) { + reportError(ctx, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + return std::string{}; + } }, + { "FILTER"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "FILTER"_s, args, 3)) { + auto const& op = args[1]; + if (op != "INCLUDE"_s && op != "EXCLUDE"_s) { + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command FILTER does not recognize operator \"", + op, "\". It must be either INCLUDE or EXCLUDE.")); + return std::string{}; + } + try { + return GetList(args.front()) + .filter(args[2], + op == "INCLUDE"_s ? cmList::FilterMode::INCLUDE + : cmList::FilterMode::EXCLUDE) + .to_string(); + } catch (std::invalid_argument&) { + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command FILTER, failed to compile regex \"", + args[2], "\".")); + return std::string{}; + } + } + return std::string{}; + } }, + { "TRANSFORM"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "TRANSFORM"_s, args.size(), 2, + false)) { + auto list = GetList(args.front()); + if (!list.empty()) { + struct ActionDescriptor + { + ActionDescriptor(std::string name) + : Name(std::move(name)) + { + } + ActionDescriptor(std::string name, + cmList::TransformAction action, int arity) + : Name(std::move(name)) + , Action(action) + , Arity(arity) + { + } + + operator const std::string&() const { return this->Name; } + + std::string Name; + cmList::TransformAction Action; + int Arity = 0; + }; + + static std::set< + ActionDescriptor, + std::function<bool(const std::string&, const std::string&)>> + descriptors{ + { { "APPEND", cmList::TransformAction::APPEND, 1 }, + { "PREPEND", cmList::TransformAction::PREPEND, 1 }, + { "TOUPPER", cmList::TransformAction::TOUPPER, 0 }, + { "TOLOWER", cmList::TransformAction::TOLOWER, 0 }, + { "STRIP", cmList::TransformAction::STRIP, 0 }, + { "REPLACE", cmList::TransformAction::REPLACE, 2 } }, + [](const std::string& x, const std::string& y) { + return x < y; + } + }; + + auto descriptor = descriptors.find(args.advance(1).front()); + if (descriptor == descriptors.end()) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat(" sub-command TRANSFORM, ", + args.front(), " invalid action.")); + return std::string{}; + } + + // Action arguments + args.advance(1); + if (args.size() < descriptor->Arity) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command TRANSFORM, action ", + descriptor->Name, " expects ", + descriptor->Arity, " argument(s).")); + return std::string{}; + } + std::vector<std::string> arguments; + if (descriptor->Arity > 0) { + arguments = std::vector<std::string>( + args.begin(), args.begin() + descriptor->Arity); + args.advance(descriptor->Arity); + } + + const std::string REGEX{ "REGEX" }; + const std::string AT{ "AT" }; + const std::string FOR{ "FOR" }; + std::unique_ptr<cmList::TransformSelector> selector; + + try { + // handle optional arguments + while (!args.empty()) { + if ((args.front() == REGEX || args.front() == AT || + args.front() == FOR) && + selector) { + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command TRANSFORM, selector " + "already specified (", + selector->GetTag(), ").")); + + return std::string{}; + } + + // REGEX selector + if (args.front() == REGEX) { + if (args.advance(1).empty()) { + reportError( + ctx, cnt->GetOriginalExpression(), + "sub-command TRANSFORM, selector REGEX expects " + "'regular expression' argument."); + return std::string{}; + } + + selector = cmList::TransformSelector::New< + cmList::TransformSelector::REGEX>(args.front()); + + args.advance(1); + continue; + } + + // AT selector + if (args.front() == AT) { + args.advance(1); + // get all specified indexes + std::vector<cmList::index_type> indexes; + while (!args.empty()) { + cmList indexList{ args.front() }; + for (auto const& index : indexList) { + cmList::index_type value; + + if (!GetNumericArgument(index, value)) { + // this is not a number, stop processing + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command TRANSFORM, selector AT: '", + index, "': unexpected argument.")); + return std::string{}; + } + indexes.push_back(value); + } + args.advance(1); + } + + if (indexes.empty()) { + reportError(ctx, cnt->GetOriginalExpression(), + "sub-command TRANSFORM, selector AT " + "expects at least one " + "numeric value."); + return std::string{}; + } + + selector = cmList::TransformSelector::New< + cmList::TransformSelector::AT>(std::move(indexes)); + + continue; + } + + // FOR selector + if (args.front() == FOR) { + if (args.advance(1).size() < 2) { + reportError(ctx, cnt->GetOriginalExpression(), + "sub-command TRANSFORM, selector FOR " + "expects, at least," + " two arguments."); + return std::string{}; + } + + cmList::index_type start = 0; + cmList::index_type stop = 0; + cmList::index_type step = 1; + bool valid = false; + + if (GetNumericArgument(args.front(), start) && + GetNumericArgument(args.advance(1).front(), stop)) { + valid = true; + } + + if (!valid) { + reportError( + ctx, cnt->GetOriginalExpression(), + "sub-command TRANSFORM, selector FOR expects, " + "at least, two numeric values."); + return std::string{}; + } + // try to read a third numeric value for step + if (!args.advance(1).empty()) { + if (!GetNumericArgument(args.front(), step)) { + // this is not a number + step = -1; + } + args.advance(1); + } + + if (step <= 0) { + reportError( + ctx, cnt->GetOriginalExpression(), + "sub-command TRANSFORM, selector FOR expects " + "positive numeric value for <step>."); + return std::string{}; + } + + selector = cmList::TransformSelector::New< + cmList::TransformSelector::FOR>({ start, stop, step }); + continue; + } + + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command TRANSFORM, '", + cmJoin(args, ", "), + "': unexpected argument(s).")); + return std::string{}; + } + + return list + .transform(descriptor->Action, arguments, + std::move(selector)) + .to_string(); + } catch (cmList::transform_error& e) { + reportError(ctx, cnt->GetOriginalExpression(), e.what()); + return std::string{}; + } + } + } + return std::string{}; + } }, + { "REVERSE"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParameters(ctx, cnt, "REVERSE"_s, args)) { + return GetList(args.front()).reverse().to_string(); + } + return std::string{}; + } }, + { "SORT"_s, + [](cmGeneratorExpressionContext* ctx, + const GeneratorExpressionContent* cnt, + Arguments& args) -> std::string { + if (CheckListParametersEx(ctx, cnt, "SORT"_s, args.size(), 1, + false)) { + auto list = GetList(args.front()); + args.advance(1); + const auto COMPARE = "COMPARE:"_s; + const auto CASE = "CASE:"_s; + const auto ORDER = "ORDER:"_s; + using SortConfig = cmList::SortConfiguration; + SortConfig sortConfig; + for (auto const& arg : args) { + if (cmHasPrefix(arg, COMPARE)) { + if (sortConfig.Compare != + SortConfig::CompareMethod::DEFAULT) { + reportError(ctx, cnt->GetOriginalExpression(), + "sub-command SORT, COMPARE option has been " + "specified multiple times."); + return std::string{}; + } + auto option = + cm::string_view{ arg.c_str() + COMPARE.length() }; + if (option == "STRING"_s) { + sortConfig.Compare = SortConfig::CompareMethod::STRING; + continue; + } + if (option == "FILE_BASENAME"_s) { + sortConfig.Compare = + SortConfig::CompareMethod::FILE_BASENAME; + continue; + } + if (option == "NATURAL"_s) { + sortConfig.Compare = SortConfig::CompareMethod::NATURAL; + continue; + } + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat( + "sub-command SORT, an invalid COMPARE option has been " + "specified: \"", + option, "\".")); + return std::string{}; + } + if (cmHasPrefix(arg, CASE)) { + if (sortConfig.Case != + SortConfig::CaseSensitivity::DEFAULT) { + reportError(ctx, cnt->GetOriginalExpression(), + "sub-command SORT, CASE option has been " + "specified multiple times."); + return std::string{}; + } + auto option = cm::string_view{ arg.c_str() + CASE.length() }; + if (option == "SENSITIVE"_s) { + sortConfig.Case = SortConfig::CaseSensitivity::SENSITIVE; + continue; + } + if (option == "INSENSITIVE"_s) { + sortConfig.Case = SortConfig::CaseSensitivity::INSENSITIVE; + continue; + } + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat( + "sub-command SORT, an invalid CASE option has been " + "specified: \"", + option, "\".")); + return std::string{}; + } + if (cmHasPrefix(arg, ORDER)) { + if (sortConfig.Order != SortConfig::OrderMode::DEFAULT) { + reportError(ctx, cnt->GetOriginalExpression(), + "sub-command SORT, ORDER option has been " + "specified multiple times."); + return std::string{}; + } + auto option = + cm::string_view{ arg.c_str() + ORDER.length() }; + if (option == "ASCENDING"_s) { + sortConfig.Order = SortConfig::OrderMode::ASCENDING; + continue; + } + if (option == "DESCENDING"_s) { + sortConfig.Order = SortConfig::OrderMode::DESCENDING; + continue; + } + reportError( + ctx, cnt->GetOriginalExpression(), + cmStrCat( + "sub-command SORT, an invalid ORDER option has been " + "specified: \"", + option, "\".")); + return std::string{}; + } + reportError(ctx, cnt->GetOriginalExpression(), + cmStrCat("sub-command SORT, option \"", arg, + "\" is invalid.")); + return std::string{}; + } + + return list.sort(sortConfig).to_string(); + } + return std::string{}; + } } + }; + + if (cm::contains(listCommands, parameters.front())) { + auto args = Arguments{ parameters }.advance(1); + return listCommands[parameters.front()](context, content, args); + } + + reportError(context, content->GetOriginalExpression(), + cmStrCat(parameters.front(), ": invalid option.")); + return std::string{}; + } +} listNode; + static const struct MakeCIdentifierNode : public cmGeneratorExpressionNode { MakeCIdentifierNode() {} // NOLINT(modernize-use-equals-default) @@ -1472,11 +2167,11 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode // This imported target has an appropriate location // for this (possibly mapped) config. // Check if there is a proper config mapping for the tested config. - std::vector<std::string> mappedConfigs; + cmList mappedConfigs; std::string mapProp = cmStrCat( "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config)); if (cmValue mapValue = context->CurrentTarget->GetProperty(mapProp)) { - cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs); + mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue)); for (auto const& param : parameters) { if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) { @@ -1581,7 +2276,8 @@ static const struct CompileLanguageAndIdNode : public cmGeneratorExpressionNode // reportError(context, content->GetOriginalExpression(), ""); reportError( context, content->GetOriginalExpression(), - "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary targets " + "$<COMPILE_LANG_AND_ID:lang,id> may only be used with binary " + "targets " "to specify include directories, compile definitions, and compile " "options. It may not be used with the add_custom_command, " "add_custom_target, or file(GENERATE) commands."); @@ -1726,7 +2422,8 @@ static const struct LinkLanguageAndIdNode : public cmGeneratorExpressionNode reportError( context, content->GetOriginalExpression(), "$<LINK_LANG_AND_ID:lang,id> may only be used with binary targets " - "to specify link libraries, link directories, link options, and link " + "to specify link libraries, link directories, link options, and " + "link " "depends."); return std::string(); } @@ -1785,8 +2482,7 @@ static const struct LinkLibraryNode : public cmGeneratorExpressionNode return std::string(); } - std::vector<std::string> list; - cmExpandLists(parameters.begin(), parameters.end(), list); + cmList list{ parameters.begin(), parameters.end() }; if (list.empty()) { reportError( context, content->GetOriginalExpression(), @@ -1871,8 +2567,7 @@ static const struct LinkGroupNode : public cmGeneratorExpressionNode return std::string(); } - std::vector<std::string> list; - cmExpandLists(parameters.begin(), parameters.end(), list); + cmList list{ parameters.begin(), parameters.end() }; if (list.empty()) { reportError( context, content->GetOriginalExpression(), @@ -1962,8 +2657,7 @@ static const struct DeviceLinkNode : public cmGeneratorExpressionNode } if (context->HeadTarget->IsDeviceLink()) { - std::vector<std::string> list; - cmExpandLists(parameters.begin(), parameters.end(), list); + cmList list{ parameters.begin(), parameters.end() }; const auto DL_BEGIN = "<DEVICE_LINK>"_s; const auto DL_END = "</DEVICE_LINK>"_s; cm::erase_if(list, [&](const std::string& item) { @@ -2108,7 +2802,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode reportError( context, content->GetOriginalExpression(), "$<TARGET_PROPERTY:prop> may only be used with binary targets. " - "It may not be used with add_custom_command or add_custom_target. " + "It may not be used with add_custom_command or add_custom_target. " + " " " " "Specify the target to read a property from using the " "$<TARGET_PROPERTY:tgt,prop> signature instead."); @@ -2373,14 +3068,14 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode } } - std::vector<std::string> objects; + cmList objects; if (gt->IsImported()) { cmValue loc = nullptr; cmValue imp = nullptr; std::string suffix; if (gt->Target->GetMappedConfig(context->Config, loc, imp, suffix)) { - cmExpandList(*loc, objects); + objects.assign(*loc); } context->HadContextSensitiveCondition = true; } else { @@ -2398,7 +3093,7 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode context->HadContextSensitiveCondition = true; } - for (std::string& o : objects) { + for (auto& o : objects) { o = cmStrCat(obj_dir, o); } } @@ -2518,7 +3213,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode } context->HadHeadSensitiveCondition = true; - using LangMap = std::map<std::string, std::vector<std::string>>; + using LangMap = std::map<std::string, cmList>; static LangMap availableFeatures; LangMap testedFeatures; @@ -2540,7 +3235,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode reportError(context, content->GetOriginalExpression(), error); return std::string(); } - cmExpandList(featuresKnown, availableFeatures[lang]); + availableFeatures[lang].assign(featuresKnown); } } @@ -3691,7 +4386,7 @@ static const struct ShellPathNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* content, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - std::vector<std::string> listIn = cmExpandedList(parameters.front()); + cmList listIn{ parameters.front() }; if (listIn.empty()) { reportError(context, content->GetOriginalExpression(), "\"\" is not an absolute path."); @@ -3802,6 +4497,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "IN_LIST", &inListNode }, { "FILTER", &filterNode }, { "REMOVE_DUPLICATES", &removeDuplicatesNode }, + { "LIST", &listNode }, { "LOWER_CASE", &lowerCaseNode }, { "UPPER_CASE", &upperCaseNode }, { "PATH", &pathNode }, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 7e5ef0a7cb..28ba60f4ed 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -36,6 +36,7 @@ #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorExpressionNode.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -730,6 +731,29 @@ void cmGeneratorTarget::AddIncludeDirectory(const std::string& src, BT<std::string>(src, this->Makefile->GetBacktrace()), true)); } +void cmGeneratorTarget::AddSystemIncludeDirectory(std::string const& inc, + std::string const& lang) +{ + std::string config_upper; + auto const& configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + + for (auto const& config : configs) { + std::string inc_with_config = inc; + if (!config.empty()) { + cmSystemTools::ReplaceString(inc_with_config, "$<CONFIG>", config); + config_upper = cmSystemTools::UpperCase(config); + } + auto const& key = cmStrCat(config_upper, "/", lang); + this->Target->AddSystemIncludeDirectories({ inc_with_config }); + this->SystemIncludesCache[key].emplace_back(inc_with_config); + + // SystemIncludesCache should be sorted so that binary search can be used + std::sort(this->SystemIncludesCache[key].begin(), + this->SystemIncludesCache[key].end()); + } +} + std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends( cmSourceFile const* sf) const { @@ -746,14 +770,13 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, const std::string& config, cmGeneratorTarget const* headTarget, cmGeneratorExpressionDAGChecker* dagChecker, - std::vector<std::string>& result, - bool excludeImported, std::string const& language) + cmList& result, bool excludeImported, + std::string const& language) { if (cmValue dirs = depTgt->GetProperty("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")) { - cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, - dagChecker, depTgt, language), - result); + result.append(cmGeneratorExpression::Evaluate( + *dirs, lg, config, headTarget, dagChecker, depTgt, language)); } if (!depTgt->GetPropertyAsBool("SYSTEM")) { return; @@ -768,9 +791,8 @@ void handleSystemIncludesDep(cmLocalGenerator* lg, } if (cmValue dirs = depTgt->GetProperty("INTERFACE_INCLUDE_DIRECTORIES")) { - cmExpandList(cmGeneratorExpression::Evaluate(*dirs, lg, config, headTarget, - dagChecker, depTgt, language), - result); + result.append(cmGeneratorExpression::Evaluate( + *dirs, lg, config, headTarget, dagChecker, depTgt, language)); } } } @@ -1264,12 +1286,11 @@ bool cmGeneratorTarget::IsSystemIncludeDirectory( bool excludeImported = this->GetPropertyAsBool("NO_SYSTEM_FROM_IMPORTED"); - std::vector<std::string> result; + cmList result; for (std::string const& it : this->Target->GetSystemIncludeDirectories()) { - cmExpandList(cmGeneratorExpression::Evaluate(it, this->LocalGenerator, - config, this, &dagChecker, - nullptr, language), - result); + result.append(cmGeneratorExpression::Evaluate(it, this->LocalGenerator, + config, this, &dagChecker, + nullptr, language)); } std::vector<cmGeneratorTarget const*> const& deps = @@ -1634,20 +1655,20 @@ void AddFileSetEntries(cmGeneratorTarget const* headTarget, EvaluatedTargetPropertyEntries& entries) { for (auto const& entry : headTarget->Target->GetHeaderSetsEntries()) { - for (auto const& name : cmExpandedList(entry.Value)) { + for (auto const& name : cmList{ entry.Value }) { auto const* headerSet = headTarget->Target->GetFileSet(name); addFileSetEntry(headTarget, config, dagChecker, headerSet, entries); } } for (auto const& entry : headTarget->Target->GetCxxModuleSetsEntries()) { - for (auto const& name : cmExpandedList(entry.Value)) { + for (auto const& name : cmList{ entry.Value }) { auto const* cxxModuleSet = headTarget->Target->GetFileSet(name); addFileSetEntry(headTarget, config, dagChecker, cxxModuleSet, entries); } } for (auto const& entry : headTarget->Target->GetCxxModuleHeaderSetsEntries()) { - for (auto const& name : cmExpandedList(entry.Value)) { + for (auto const& name : cmList{ entry.Value }) { auto const* cxxModuleHeaderSet = headTarget->Target->GetFileSet(name); addFileSetEntry(headTarget, config, dagChecker, cxxModuleHeaderSet, entries); @@ -1740,8 +1761,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( cmBTStringRange sourceEntries = this->Target->GetSourceEntries(); for (auto const& entry : sourceEntries) { - std::vector<std::string> items = cmExpandedList(entry.Value); - for (std::string const& item : items) { + cmList items{ entry.Value }; + for (auto const& item : items) { if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") && item.back() == '>') { continue; @@ -1752,10 +1773,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( return files; } - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugSources = !this->DebugSourcesDone && cm::contains(debugProperties, "SOURCES"); @@ -3105,8 +3124,8 @@ void cmTargetTraceDependencies::Trace() // Queue dependencies added explicitly by the user. if (cmValue additionalDeps = sf->GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> objDeps = cmExpandedList(*additionalDeps); - for (std::string& objDep : objDeps) { + cmList objDeps{ *additionalDeps }; + for (auto& objDep : objDeps) { if (cmSystemTools::FileIsFullPath(objDep)) { objDep = cmSystemTools::CollapseFullPath(objDep); } @@ -3299,9 +3318,9 @@ std::string cmGeneratorTarget::GetCompilePDBDirectory( std::vector<std::string> cmGeneratorTarget::GetAppleArchs( std::string const& config, cm::optional<std::string> lang) const { - std::vector<std::string> archVec; + cmList archList; if (!this->IsApple()) { - return archVec; + return std::move(archList.data()); } cmValue archs = nullptr; if (!config.empty()) { @@ -3313,17 +3332,18 @@ std::vector<std::string> cmGeneratorTarget::GetAppleArchs( archs = this->GetProperty("OSX_ARCHITECTURES"); } if (archs) { - cmExpandList(*archs, archVec); + archList.assign(*archs); } - if (archVec.empty() && + if (archList.empty() && // Fall back to a default architecture if no compiler target is set. (!lang || this->Makefile ->GetDefinition(cmStrCat("CMAKE_", *lang, "_COMPILER_TARGET")) .IsEmpty())) { - this->Makefile->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", archVec); + archList.assign( + this->Makefile->GetDefinition("_CMAKE_APPLE_ARCHS_DEFAULT")); } - return archVec; + return std::move(archList.data()); } void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags, @@ -3432,10 +3452,9 @@ void cmGeneratorTarget::AddCUDAArchitectureFlags(cmBuildStep compileOrLink, std::vector<CudaArchitecture> architectures; { - std::vector<std::string> options; - cmExpandList(property, options); + cmList options(property); - for (std::string& option : options) { + for (auto& option : options) { CudaArchitecture architecture; // Architecture name is up to the first specifier. @@ -3526,8 +3545,7 @@ void cmGeneratorTarget::AddISPCTargetFlags(std::string& flags) const this->Makefile->GetSafeDefinition("CMAKE_ISPC_COMPILER_ID"); if (compiler == "Intel") { - std::vector<std::string> targets; - cmExpandList(property, targets); + cmList targets(property); if (!targets.empty()) { flags += cmStrCat(" --target=", cmWrap("", targets, "", ",")); } @@ -3549,8 +3567,7 @@ void cmGeneratorTarget::AddHIPArchitectureFlags(std::string& flags) const return; } - std::vector<std::string> options; - cmExpandList(property, options); + cmList options(property); for (std::string& option : options) { flags += " --offload-arch=" + option; @@ -3762,10 +3779,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugIncludes = !this->DebugIncludesDone && cm::contains(debugProperties, "INCLUDE_DIRECTORIES"); @@ -4021,10 +4036,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugOptions = !this->DebugCompileOptionsDone && cm::contains(debugProperties, "COMPILE_OPTIONS"); @@ -4064,10 +4077,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugFeatures = !this->DebugCompileFeaturesDone && cm::contains(debugProperties, "COMPILE_FEATURES"); @@ -4116,10 +4127,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugDefines = !this->DebugCompileDefinitionsDone && cm::contains(debugProperties, "COMPILE_DEFINITIONS"); @@ -4182,10 +4191,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugDefines = !this->DebugPrecompileHeadersDone && std::find(debugProperties.begin(), debugProperties.end(), "PRECOMPILE_HEADERS") != debugProperties.end(); @@ -4579,10 +4586,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugOptions = !this->DebugLinkOptionsDone && cm::contains(debugProperties, "LINK_OPTIONS"); @@ -4606,7 +4611,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( // wrap host link options const std::string wrapper(this->Makefile->GetSafeDefinition( "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG")); - std::vector<std::string> wrapperFlag = cmExpandedList(wrapper); + cmList wrapperFlag{ wrapper }; const std::string wrapperSep(this->Makefile->GetSafeDefinition( "CMAKE_" + language + "_DEVICE_COMPILER_WRAPPER_FLAG_SEP")); bool concatFlagAndArgs = true; @@ -4665,7 +4670,7 @@ std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( "CMAKE_" + language + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG" : "_LINKER_WRAPPER_FLAG"))); - std::vector<std::string> wrapperFlag = cmExpandedList(wrapper); + cmList wrapperFlag{ wrapper }; const std::string wrapperSep(this->Makefile->GetSafeDefinition( "CMAKE_" + language + (this->IsDeviceLink() ? "_DEVICE_LINKER_WRAPPER_FLAG_SEP" @@ -4863,10 +4868,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr, nullptr); - std::vector<std::string> debugProperties; - this->Makefile->GetDefExpandList("CMAKE_DEBUG_TARGET_PROPERTIES", - debugProperties); - + cmList debugProperties{ this->Makefile->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugDirectories = !this->DebugLinkDirectoriesDone && cm::contains(debugProperties, "LINK_DIRECTORIES"); @@ -4911,7 +4914,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( EvaluatedTargetPropertyEntries entries; if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) { - std::vector<std::string> depends = cmExpandedList(*linkDepends); + cmList depends{ *linkDepends }; for (const auto& depend : depends) { std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry( *this->LocalGenerator->GetCMakeInstance(), depend); @@ -5590,8 +5593,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const // Process public headers to mark the source files. if (cmValue files = this->GetProperty("PUBLIC_HEADER")) { - std::vector<std::string> relFiles = cmExpandedList(*files); - for (std::string const& relFile : relFiles) { + cmList relFiles{ *files }; + for (auto const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; flags.MacFolder = "Headers"; @@ -5603,8 +5606,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const // Process private headers after public headers so that they take // precedence if a file is listed in both. if (cmValue files = this->GetProperty("PRIVATE_HEADER")) { - std::vector<std::string> relFiles = cmExpandedList(*files); - for (std::string const& relFile : relFiles) { + cmList relFiles{ *files }; + for (auto const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; flags.MacFolder = "PrivateHeaders"; @@ -5615,8 +5618,8 @@ void cmGeneratorTarget::ConstructSourceFileFlags() const // Mark sources listed as resources. if (cmValue files = this->GetProperty("RESOURCE")) { - std::vector<std::string> relFiles = cmExpandedList(*files); - for (std::string const& relFile : relFiles) { + cmList relFiles{ *files }; + for (auto const& relFile : relFiles) { if (cmSourceFile* sf = this->Makefile->GetSource(relFile)) { SourceFileFlags& flags = this->SourceFlagsMap[sf]; flags.MacFolder = ""; @@ -5643,8 +5646,7 @@ cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const for (cmGeneratorTarget const* li : deps) { #define CM_READ_COMPATIBLE_INTERFACE(X, x) \ if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) { \ - std::vector<std::string> props; \ - cmExpandList(*prop, props); \ + cmList props(*prop); \ compat.Props##x.insert(props.begin(), props.end()); \ } CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool) @@ -5757,7 +5759,7 @@ void checkPropertyConsistency(cmGeneratorTarget const* depender, return; } - std::vector<std::string> props = cmExpandedList(*prop); + cmList props{ *prop }; std::string pdir = cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/"); @@ -6718,10 +6720,8 @@ void cmGeneratorTarget::ReportPropertyOrigin( const std::string& p, const std::string& result, const std::string& report, const std::string& compatibilityType) const { - std::vector<std::string> debugProperties; - this->Target->GetMakefile()->GetDefExpandList( - "CMAKE_DEBUG_TARGET_PROPERTIES", debugProperties); - + cmList debugProperties{ this->Target->GetMakefile()->GetDefinition( + "CMAKE_DEBUG_TARGET_PROPERTIES") }; bool debugOrigin = !this->DebugCompatiblePropertiesDone[p] && cm::contains(debugProperties, p); @@ -6800,10 +6800,10 @@ void cmGeneratorTarget::ExpandLinkItems( 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) { + cmList libs{ cge->Evaluate(this->LocalGenerator, config, headTarget, + &dagChecker, this, + headTarget->LinkerLanguage) }; + for (auto const& lib : libs) { if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( lib, cge->GetBacktrace(), &scope, field == LinkInterfaceField::Libraries ? LookupSelf::No @@ -7467,10 +7467,10 @@ std::vector<ValueType> computeImplicitLanguageTargets( currentTarget->GetRuntimeLinkLibrary(lang, config); if (cmValue runtimeLinkOptions = currentTarget->Makefile->GetDefinition( "CMAKE_" + lang + "_RUNTIME_LIBRARIES_" + runtimeLibrary)) { - std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions); - result.reserve(libsVec.size()); + cmList libsList{ *runtimeLinkOptions }; + result.reserve(libsList.size()); - for (std::string const& i : libsVec) { + for (auto const& i : libsList) { cmGeneratorTarget::TargetOrString resolved = currentTarget->ResolveTargetReference(i, lg); if (resolved.Target) { @@ -7551,9 +7551,9 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( this->ExpandLinkItems(info->LibrariesProp, cmMakeRange(info->Libraries), config, headTarget, interfaceFor, LinkInterfaceField::Libraries, iface); - std::vector<std::string> deps = cmExpandedList(info->SharedDeps); + cmList deps{ info->SharedDeps }; LookupLinkItemScope scope{ this->LocalGenerator }; - for (std::string const& dep : deps) { + for (auto const& dep : deps) { if (cm::optional<cmLinkItem> maybeItem = this->LookupLinkItem( dep, cmListFileBacktrace(), &scope, LookupSelf::No)) { iface.SharedDeps.emplace_back(std::move(*maybeItem)); @@ -7874,8 +7874,8 @@ void cmGeneratorTarget::GetObjectLibrariesCMP0026( // behavior of CMP0024 and CMP0026 only. cmBTStringRange rng = this->Target->GetSourceEntries(); for (auto const& entry : rng) { - std::vector<std::string> files = cmExpandedList(entry.Value); - for (std::string const& li : files) { + cmList files{ entry.Value }; + for (auto const& li : files) { if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') { std::string objLibName = li.substr(17, li.size() - 18); @@ -8223,7 +8223,6 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cmBTStringRange entryRange = this->Target->GetLinkImplementationEntries(); // Collect libraries directly linked in this configuration. for (auto const& entry : entryRange) { - std::vector<std::string> llibs; // Keep this logic in sync with ExpandLinkItems. cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_LIBRARIES", nullptr, nullptr); @@ -8251,7 +8250,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cge->Evaluate(this->LocalGenerator, config, head, &dagChecker, nullptr, this->LinkerLanguage); bool const checkCMP0027 = evaluated != entry.Value; - cmExpandList(evaluated, llibs); + cmList llibs(evaluated); if (cge->GetHadHeadSensitiveCondition()) { impl.HadHeadSensitiveCondition = true; } @@ -8262,7 +8261,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( impl.HadLinkLanguageSensitiveCondition = true; } - for (std::string const& lib : llibs) { + for (auto const& lib : llibs) { if (this->IsLinkLookupScope(lib, lg)) { continue; } @@ -8430,16 +8429,16 @@ bool cmGeneratorTarget::HasPackageReferences() const std::vector<std::string> cmGeneratorTarget::GetPackageReferences() const { - std::vector<std::string> packageReferences; + cmList packageReferences; if (this->IsInBuildSystem()) { if (cmValue vsPackageReferences = this->GetProperty("VS_PACKAGE_REFERENCES")) { - cmExpandList(*vsPackageReferences, packageReferences); + packageReferences.assign(*vsPackageReferences); } } - return packageReferences; + return std::move(packageReferences.data()); } std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const @@ -8544,6 +8543,30 @@ bool cmGeneratorTarget::IsLinkable() const this->IsExecutableWithExports()); } +bool cmGeneratorTarget::HasLinkDependencyFile(std::string const& config) const +{ + if (this->GetType() != cmStateEnums::EXECUTABLE && + this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::MODULE_LIBRARY) { + return false; + } + + if (this->Target->GetProperty("LINK_DEPENDS_NO_SHARED").IsOn()) { + // Do not use the linker dependency file because it includes shared + // libraries as well + return false; + } + + const std::string depsUseLinker{ "CMAKE_LINK_DEPENDS_USE_LINKER" }; + auto linkLanguage = this->GetLinkerLanguage(config); + const std::string langDepsUseLinker{ cmStrCat("CMAKE_", linkLanguage, + "_LINK_DEPENDS_USE_LINKER") }; + + return (!this->Makefile->IsDefinitionSet(depsUseLinker) || + this->Makefile->IsOn(depsUseLinker)) && + this->Makefile->IsOn(langDepsUseLinker); +} + bool cmGeneratorTarget::IsFrameworkOnApple() const { return this->Target->IsFrameworkOnApple(); @@ -8638,7 +8661,7 @@ bool cmGeneratorTarget::AddHeaderSetVerification() const bool all = verifyValue.IsEmpty(); std::set<std::string> verifySet; if (!all) { - auto verifyList = cmExpandedList(verifyValue); + cmList verifyList{ verifyValue }; verifySet.insert(verifyList.begin(), verifyList.end()); } @@ -8651,7 +8674,7 @@ bool cmGeneratorTarget::AddHeaderSetVerification() std::set<cmFileSet*> fileSets; for (auto const& entry : interfaceFileSetEntries) { - for (auto const& name : cmExpandedList(entry.Value)) { + for (auto const& name : cmList{ entry.Value }) { if (all || verifySet.count(name)) { fileSets.insert(this->Target->GetFileSet(name)); verifySet.erase(name); diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 87227fd29c..78945c3fa9 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -805,6 +805,9 @@ public: /** Return whether this target may be used to link another target. */ bool IsLinkable() const; + /** Return whether the link step generates a dependency file. */ + bool HasLinkDependencyFile(std::string const& config) const; + /** Return whether this target is a shared library Framework on Apple. */ bool IsFrameworkOnApple() const; @@ -912,6 +915,8 @@ public: std::vector<std::string> GetGeneratedISPCObjects( std::string const& config) const; + void AddSystemIncludeDirectory(std::string const& inc, + std::string const& lang); bool AddHeaderSetVerification(); std::string GenerateHeaderSetVerificationFile( cmSourceFile& source, const std::string& dir, diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 8471dfe615..a1e0650d20 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -17,6 +17,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGhsMultiGenerator.h" #include "cmLinkLineComputer.h" // IWYU pragma: keep +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" @@ -484,7 +485,7 @@ void cmGhsMultiTargetGenerator::WriteSourceProperty( { cmValue prop = sf->GetProperty(propName); if (prop) { - std::vector<std::string> list = cmExpandedList(*prop); + cmList list{ *prop }; for (const std::string& p : list) { fout << " " << propFlag << p << '\n'; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 3563a1a17d..040f500519 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -42,6 +42,7 @@ #include "cmInstallGenerator.h" #include "cmInstallRuntimeDependencySet.h" #include "cmLinkLineComputer.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMSVC60LinkLineComputer.h" #include "cmMakefile.h" @@ -238,10 +239,10 @@ void cmGlobalGenerator::ResolveLanguageCompiler(const std::string& lang, this->GetCMakeInstance()->GetState()->GetInitializedCacheValue(langComp); // Split compiler from arguments - std::vector<std::string> cnameArgVec; + cmList cnameArgList; if (cname && !cname->empty()) { - cmExpandList(*cname, cnameArgVec); - cname = cmValue(cnameArgVec.front()); + cnameArgList.assign(*cname); + cname = cmValue(cnameArgList.front()); } std::string changeVars; @@ -670,7 +671,7 @@ void cmGlobalGenerator::EnableLanguage( mf->GetState()->SetInTopLevelIncludes(true); std::string includes = mf->GetSafeDefinition("CMAKE_PROJECT_TOP_LEVEL_INCLUDES"); - std::vector<std::string> includesList = cmExpandedList(includes); + cmList includesList{ includes }; for (std::string const& setupFile : includesList) { std::string absSetupFile = cmSystemTools::CollapseFullPath( setupFile, mf->GetCurrentSourceDirectory()); @@ -1234,7 +1235,7 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const std::string& l, std::string ignoreExtensionsVar = std::string("CMAKE_") + std::string(l) + std::string("_IGNORE_EXTENSIONS"); std::string ignoreExts = mf->GetSafeDefinition(ignoreExtensionsVar); - std::vector<std::string> extensionList = cmExpandedList(ignoreExts); + cmList extensionList{ ignoreExts }; for (std::string const& i : extensionList) { this->IgnoreExtensions[i] = true; } @@ -1246,7 +1247,7 @@ void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l, std::string extensionsVar = std::string("CMAKE_") + std::string(l) + std::string("_SOURCE_FILE_EXTENSIONS"); const std::string& exts = mf->GetSafeDefinition(extensionsVar); - std::vector<std::string> extensionList = cmExpandedList(exts); + cmList extensionList{ exts }; for (std::string const& i : extensionList) { this->ExtensionToLanguage[i] = l; } @@ -1887,10 +1888,9 @@ void cmGlobalGenerator::FinalizeTargetConfiguration() "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES"; std::string const& standardIncludesStr = mf->GetSafeDefinition(standardIncludesVar); - std::vector<std::string> standardIncludesVec = - cmExpandedList(standardIncludesStr); - standardIncludesSet.insert(standardIncludesVec.begin(), - standardIncludesVec.end()); + cmList standardIncludesList{ standardIncludesStr }; + standardIncludesSet.insert(standardIncludesList.begin(), + standardIncludesList.end()); } mf->AddSystemIncludeDirectories(standardIncludesSet); } @@ -1985,7 +1985,6 @@ void cmGlobalGenerator::CheckTargetProperties() notFoundMap[varName] = text; } } - std::vector<std::string> incs; cmValue incDirProp = target.second.GetProperty("INCLUDE_DIRECTORIES"); if (!incDirProp) { continue; @@ -1994,7 +1993,7 @@ void cmGlobalGenerator::CheckTargetProperties() std::string incDirs = cmGeneratorExpression::Preprocess( *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); - cmExpandList(incDirs, incs); + cmList incs(incDirs); for (std::string const& incDir : incs) { if (incDir.size() > 9 && cmIsNOTFOUND(incDir)) { @@ -2789,11 +2788,9 @@ void cmGlobalGenerator::AddGlobalTarget_Test( cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCTestCommand()); singleLine.push_back("--force-new-ctest-process"); - std::vector<std::string> args; - if (mf->GetDefExpandList("CMAKE_CTEST_ARGUMENTS", args)) { - for (auto const& arg : args) { - singleLine.push_back(arg); - } + cmList args(mf->GetDefinition("CMAKE_CTEST_ARGUMENTS")); + for (auto const& arg : args) { + singleLine.push_back(arg); } if (cmNonempty(cmakeCfgIntDir) && cmakeCfgIntDir[0] != '.') { singleLine.push_back("-C"); @@ -3348,12 +3345,12 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) cmSystemTools::MakeDirectory(dir); cmGeneratedFileStream fout(file); - std::vector<std::string> labels; + cmList labels; // List the target-wide labels. All sources in the target get // these labels. if (targetLabels) { - cmExpandList(*targetLabels, labels); + labels.assign(*targetLabels); if (!labels.empty()) { fout << "# Target labels\n"; for (std::string const& l : labels) { @@ -3364,27 +3361,27 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) } // List directory labels - std::vector<std::string> directoryLabelsList; - std::vector<std::string> cmakeDirectoryLabelsList; + cmList directoryLabelsList; + cmList cmakeDirectoryLabelsList; if (directoryLabels) { - cmExpandList(*directoryLabels, directoryLabelsList); + directoryLabelsList.assign(*directoryLabels); } if (cmakeDirectoryLabels) { - cmExpandList(*cmakeDirectoryLabels, cmakeDirectoryLabelsList); + cmakeDirectoryLabelsList.assign(*cmakeDirectoryLabels); } if (!directoryLabelsList.empty() || !cmakeDirectoryLabelsList.empty()) { fout << "# Directory labels\n"; } - for (std::string const& li : directoryLabelsList) { + for (auto const& li : directoryLabelsList) { fout << " " << li << "\n"; lj_target_labels.append(li); } - for (std::string const& li : cmakeDirectoryLabelsList) { + for (auto const& li : cmakeDirectoryLabelsList) { fout << " " << li << "\n"; lj_target_labels.append(li); } @@ -3405,10 +3402,9 @@ void cmGlobalGenerator::WriteSummary(cmGeneratorTarget* target) fout << sfp << "\n"; lj_source["file"] = sfp; if (cmValue svalue = sf->GetProperty("LABELS")) { - labels.clear(); Json::Value& lj_source_labels = lj_source["labels"] = Json::arrayValue; - cmExpandList(*svalue, labels); - for (std::string const& label : labels) { + labels.assign(*svalue); + for (auto const& label : labels) { fout << " " << label << "\n"; lj_source_labels.append(label); } diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index dde364886e..79fe52c193 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -546,6 +546,8 @@ public: return cm::nullopt; } + virtual bool SupportsLinkerDependencyFile() const { return false; } + std::string GetSharedLibFlagsForLanguage(std::string const& lang) const; /** Generate an <output>.rule file path for a given command output. */ diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index b1f2b4a393..578e805332 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -18,6 +18,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGhsMultiGpj.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" @@ -531,7 +532,7 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout, fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n'; cmValue ghsGpjMacros = root->GetMakefile()->GetDefinition("GHS_GPJ_MACROS"); if (ghsGpjMacros) { - std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros); + cmList expandedList{ *ghsGpjMacros }; for (std::string const& arg : expandedList) { fout << "macro " << arg << '\n'; } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 0c28776a82..84c85e07e6 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -32,6 +32,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLinkLineComputer.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" @@ -3031,19 +3032,17 @@ void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() { - std::vector<std::string> configsVec; - cmExpandList( - this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"), - configsVec); - if (configsVec.empty()) { - configsVec.emplace_back(); + cmList configsList{ this->Makefiles.front()->GetDefinition( + "CMAKE_CONFIGURATION_TYPES") }; + if (configsList.empty()) { + configsList.emplace_back(); } - std::set<std::string> configs(configsVec.cbegin(), configsVec.cend()); + std::set<std::string> configs(configsList.cbegin(), configsList.cend()); this->DefaultFileConfig = this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE"); if (this->DefaultFileConfig.empty()) { - this->DefaultFileConfig = configsVec.front(); + this->DefaultFileConfig = configsList.front(); } if (!configs.count(this->DefaultFileConfig)) { std::ostringstream msg; @@ -3055,11 +3054,9 @@ bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() return false; } - std::vector<std::string> crossConfigsVec; - cmExpandList( - this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"), - crossConfigsVec); - auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec); + cmList crossConfigsList{ this->Makefiles.front()->GetSafeDefinition( + "CMAKE_CROSS_CONFIGS") }; + auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsList); if (!crossConfigs) { std::ostringstream msg; msg << "CMAKE_CROSS_CONFIGS is not a subset of " @@ -3086,12 +3083,11 @@ bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() return false; } - std::vector<std::string> defaultConfigsVec; - cmExpandList(defaultConfigsString, defaultConfigsVec); + cmList defaultConfigsList(defaultConfigsString); if (!this->DefaultFileConfig.empty()) { auto defaultConfigs = ListSubsetWithAll(this->GetCrossConfigs(this->DefaultFileConfig), - this->CrossConfigs, defaultConfigsVec); + this->CrossConfigs, defaultConfigsList); if (!defaultConfigs) { std::ostringstream msg; msg << "CMAKE_DEFAULT_CONFIGS is not a subset of CMAKE_CROSS_CONFIGS"; diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index bd541685c9..bfbe57f22b 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -236,6 +236,8 @@ public: return cmDepfileFormat::GccDepfile; } + bool SupportsLinkerDependencyFile() const override { return true; } + virtual cmGeneratedFileStream* GetImplFileStream( const std::string& /*config*/) const { diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 214ba2af51..760679a051 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -99,6 +99,12 @@ public: */ bool SupportsCustomCommandDepfile() const override { return true; } + /** + * Utilized to determine if this generator + * supports linker dependency file. + */ + bool SupportsLinkerDependencyFile() const override { return true; } + /** Get the documentation entry for this generator. */ static cmDocumentationEntry GetDocumentation(); diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index de139241ed..bcb26cc1cb 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -8,6 +8,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalVisualStudioGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -205,12 +206,12 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations( !platformMapping.empty() ? platformMapping : this->GetPlatformName(); std::string guid = this->GetGUID(name); for (std::string const& i : configs) { - std::vector<std::string> mapConfig; + cmList mapConfig; const char* dstConfig = i.c_str(); if (target.GetProperty("EXTERNAL_MSPROJECT")) { if (cmValue m = target.GetProperty("MAP_IMPORTED_CONFIG_" + cmSystemTools::UpperCase(i))) { - cmExpandList(*m, mapConfig); + mapConfig.assign(*m); if (!mapConfig.empty()) { dstConfig = mapConfig[0].c_str(); } diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 5de3a55939..694698e559 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -17,6 +17,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmLocalVisualStudio7Generator.h" #include "cmMakefile.h" @@ -580,7 +581,7 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( } fout << "\tGlobalSection(" << name << ") = " << sectionType << "\n"; cmValue p = root->GetMakefile()->GetProperty(it); - std::vector<std::string> keyValuePairs = cmExpandedList(p ? *p : ""); + cmList keyValuePairs{ *p }; for (std::string const& itPair : keyValuePairs) { const std::string::size_type posEqual = itPair.find('='); if (posEqual != std::string::npos) { diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 2aba46fe2c..819bb09b1a 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -20,6 +20,7 @@ #include "cmGlobalGenerator.h" #include "cmGlobalVisualStudio7Generator.h" #include "cmGlobalVisualStudioGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalVisualStudio7Generator.h" @@ -262,6 +263,33 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() cmTarget* tgt = lg.AddUtilityCommand(CMAKE_CHECK_BUILD_SYSTEM_TARGET, false, std::move(cc)); + // Collect the input files used to generate all targets in this + // project. + std::vector<std::string> listFiles; + for (const auto& gen : generators) { + cm::append(listFiles, gen->GetMakefile()->GetListFiles()); + } + // Sort the list of input files and remove duplicates. + std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>()); + auto new_end = std::unique(listFiles.begin(), listFiles.end()); + listFiles.erase(new_end, listFiles.end()); + + // Add all cmake input files which are used by the project + // so Visual Studio does not close them when reloading it. + for (const std::string& listFile : listFiles) { + if (listFile.find("/CMakeFiles/") != std::string::npos) { + continue; + } + if (!cmSystemTools::IsSubDirectory(listFile, + lg.GetMakefile()->GetHomeDirectory()) && + !cmSystemTools::IsSubDirectory( + listFile, lg.GetMakefile()->GetHomeOutputDirectory())) { + continue; + } + + tgt->AddSource(listFile); + } + auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg); auto* gt = ptr.get(); lg.AddGeneratorTarget(std::move(ptr)); @@ -295,13 +323,6 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // The custom rule runs cmake so set UTF-8 pipes. bool stdPipesUTF8 = true; - // Collect the input files used to generate all targets in this - // project. - std::vector<std::string> listFiles; - for (const auto& gen : generators) { - cm::append(listFiles, gen->GetMakefile()->GetListFiles()); - } - // Add a custom prebuild target to run the VerifyGlobs script. cmake* cm = this->GetCMakeInstance(); if (cm->DoWriteGlobVerifyTarget()) { @@ -325,11 +346,6 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() listFiles.push_back(cm->GetGlobVerifyStamp()); } - // Sort the list of input files and remove duplicates. - std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>()); - auto new_end = std::unique(listFiles.begin(), listFiles.end()); - listFiles.erase(new_end, listFiles.end()); - // Create a rule to re-run CMake. std::string argS = cmStrCat("-S", lg.GetSourceDirectory()); std::string argB = cmStrCat("-B", lg.GetBinaryDirectory()); @@ -396,12 +412,12 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations( { std::string guid = this->GetGUID(name); for (std::string const& i : configs) { - std::vector<std::string> mapConfig; + cmList mapConfig; const char* dstConfig = i.c_str(); if (target.GetProperty("EXTERNAL_MSPROJECT")) { if (cmValue m = target.GetProperty("MAP_IMPORTED_CONFIG_" + cmSystemTools::UpperCase(i))) { - cmExpandList(*m, mapConfig); + mapConfig.assign(*m); if (!mapConfig.empty()) { dstConfig = mapConfig[0].c_str(); } diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 139635797f..60f46e5aca 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -30,6 +30,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGeneratorFactory.h" #include "cmLinkItem.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalXCodeGenerator.h" @@ -1027,7 +1028,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( cmValue extraFileAttributes = sf->GetProperty("XCODE_FILE_ATTRIBUTES"); if (extraFileAttributes) { // Expand the list of attributes. - std::vector<std::string> attributes = cmExpandedList(*extraFileAttributes); + cmList attributes{ *extraFileAttributes }; // Store the attributes. for (const auto& attribute : attributes) { @@ -1171,7 +1172,7 @@ template <class T> std::string GetTargetObjectDirArch(T const& target, const std::string& defaultVal) { - auto archs = cmExpandedList(target.GetSafeProperty("OSX_ARCHITECTURES")); + cmList archs{ target.GetSafeProperty("OSX_ARCHITECTURES") }; if (archs.size() > 1) { return "$(CURRENT_ARCH)"; } else if (archs.size() == 1) { @@ -3127,8 +3128,8 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateUtilityTarget( std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target, cmGeneratorTarget* gtgt) { - std::vector<std::string> const configVector = cmExpandedList( - this->CurrentMakefile->GetRequiredDefinition("CMAKE_CONFIGURATION_TYPES")); + cmList const configList{ this->CurrentMakefile->GetRequiredDefinition( + "CMAKE_CONFIGURATION_TYPES") }; cmXCodeObject* configlist = this->CreateObject(cmXCodeObject::XCConfigurationList); cmXCodeObject* buildConfigurations = @@ -3140,7 +3141,7 @@ std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target, configlist->SetComment(comment); target->AddAttribute("buildConfigurationList", this->CreateObjectReference(configlist)); - for (auto const& i : configVector) { + for (auto const& i : configList) { cmXCodeObject* config = this->CreateObject(cmXCodeObject::XCBuildConfiguration); buildConfigurations->AddObject(config); @@ -3153,12 +3154,12 @@ std::string cmGlobalXCodeGenerator::AddConfigurations(cmXCodeObject* target, this->CreateTargetXCConfigSettings(gtgt, config, i); } - if (!configVector.empty()) { + if (!configList.empty()) { configlist->AddAttribute("defaultConfigurationName", - this->CreateString(configVector[0])); + this->CreateString(configList[0])); configlist->AddAttribute("defaultConfigurationIsVisible", this->CreateString("0")); - return configVector[0]; + return configList[0]; } return ""; } @@ -4029,7 +4030,7 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects( this->CreateString("0")); cmXCodeObject* buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST); // Collect all embedded frameworks and dylibs and add them to build phase - std::vector<std::string> relFiles = cmExpandedList(*files); + cmList relFiles{ *files }; for (std::string const& relFile : relFiles) { cmXCodeObject* buildFile{ nullptr }; std::string filePath = relFile; @@ -4599,13 +4600,12 @@ std::string cmGlobalXCodeGenerator::GetTargetTempDir( void cmGlobalXCodeGenerator::ComputeArchitectures(cmMakefile* mf) { this->Architectures.clear(); - cmValue sysroot = mf->GetDefinition("CMAKE_OSX_SYSROOT"); - if (sysroot) { - mf->GetDefExpandList("CMAKE_OSX_ARCHITECTURES", this->Architectures); - } + cmList::append(this->Architectures, + mf->GetDefinition("CMAKE_OSX_ARCHITECTURES")); if (this->Architectures.empty()) { - mf->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", this->Architectures); + cmList::append(this->Architectures, + mf->GetDefinition("_CMAKE_APPLE_ARCHS_DEFAULT")); } if (this->Architectures.empty()) { @@ -5008,7 +5008,7 @@ void cmGlobalXCodeGenerator::AppendDefines(BuildObjectListOrString& defs, } // Expand the list of definitions. - std::vector<std::string> defines = cmExpandedList(defines_list); + cmList defines{ defines_list }; // Store the definitions in the string. this->AppendDefines(defs, defines, dflag); diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index 2bb438d7d4..a8a7abb087 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -15,6 +15,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLinkItem.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -255,9 +256,8 @@ void cmGraphVizWriter::ReadSettings( this->TargetsToIgnoreRegex.clear(); if (!ignoreTargetsRegexes.empty()) { - std::vector<std::string> ignoreTargetsRegExVector = - cmExpandedList(ignoreTargetsRegexes); - for (std::string const& currentRegexString : ignoreTargetsRegExVector) { + cmList ignoreTargetsRegExList{ ignoreTargetsRegexes }; + for (std::string const& currentRegexString : ignoreTargetsRegExList) { cmsys::RegularExpression currentRegex; if (!currentRegex.compile(currentRegexString)) { std::cerr << "Could not compile bad regex \"" << currentRegexString diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index 9468d4abdb..f94faf88b8 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -12,6 +12,7 @@ #include "cmsys/String.h" #include "cmIDEFlagTable.h" +#include "cmList.h" #include "cmStringAlgorithms.h" cmIDEOptions::cmIDEOptions() diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 40230d9fb6..7f5f15b3c9 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -39,6 +39,7 @@ #include "cmInstallRuntimeDependencySetGenerator.h" #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPolicies.h" @@ -1079,7 +1080,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) { cmValue files = target.GetProperty("PRIVATE_HEADER"); if (cmNonempty(files)) { - std::vector<std::string> relFiles = cmExpandedList(*files); + cmList relFiles{ *files }; std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) { return false; @@ -1101,7 +1102,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, files = target.GetProperty("PUBLIC_HEADER"); if (cmNonempty(files)) { - std::vector<std::string> relFiles = cmExpandedList(*files); + cmList relFiles{ *files }; std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) { return false; @@ -1123,7 +1124,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, files = target.GetProperty("RESOURCE"); if (cmNonempty(files)) { - std::vector<std::string> relFiles = cmExpandedList(*files); + cmList relFiles{ *files }; std::vector<std::string> absFiles; if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) { return false; @@ -1145,8 +1146,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args, 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()))); + cmList interfaceFileSetEntries{ target.GetSafeProperty( + cmTarget::GetInterfaceFileSetsPropertyName(fileSet->GetType())) }; if (std::find(interfaceFileSetEntries.begin(), interfaceFileSetEntries.end(), fileSetArgs[i].GetFileSet()) != diff --git a/Source/cmInstallDirectoryGenerator.cxx b/Source/cmInstallDirectoryGenerator.cxx index d358763c71..6aa99102bd 100644 --- a/Source/cmInstallDirectoryGenerator.cxx +++ b/Source/cmInstallDirectoryGenerator.cxx @@ -6,6 +6,7 @@ #include "cmGeneratorExpression.h" #include "cmInstallType.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -53,17 +54,16 @@ bool cmInstallDirectoryGenerator::Compute(cmLocalGenerator* lg) std::vector<std::string> cmInstallDirectoryGenerator::GetDirectories( std::string const& config) const { - std::vector<std::string> directories; + cmList directories; if (this->ActionsPerConfig) { for (std::string const& f : this->Directories) { - cmExpandList( - cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config), - directories); + directories.append( + cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config)); } } else { directories = this->Directories; } - return directories; + return std::move(directories.data()); } void cmInstallDirectoryGenerator::GenerateScriptActions(std::ostream& os, diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index 18a852b210..43dc656a75 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -6,8 +6,8 @@ #include "cmGeneratorExpression.h" #include "cmInstallType.h" +#include "cmList.h" #include "cmListFileCache.h" -#include "cmStringAlgorithms.h" class cmLocalGenerator; @@ -69,17 +69,15 @@ std::string cmInstallFilesGenerator::GetRename(std::string const& config) const std::vector<std::string> cmInstallFilesGenerator::GetFiles( std::string const& config) const { - std::vector<std::string> files; if (this->ActionsPerConfig) { + cmList files; for (std::string const& f : this->Files) { - cmExpandList( - cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config), - files); + files.append( + cmGeneratorExpression::Evaluate(f, this->LocalGenerator, config)); } - } else { - files = this->Files; + return std::move(files.data()); } - return files; + return this->Files; } void cmInstallFilesGenerator::AddFilesInstallRule( diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx index 5bf8320bbb..381c91bac1 100644 --- a/Source/cmInstalledFile.cxx +++ b/Source/cmInstalledFile.cxx @@ -5,9 +5,9 @@ #include <utility> #include "cmGeneratorExpression.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" -#include "cmStringAlgorithms.h" #include "cmValue.h" cmInstalledFile::cmInstalledFile() = default; @@ -97,12 +97,11 @@ bool cmInstalledFile::GetPropertyAsBool(const std::string& prop) const return isSet && cmIsOn(value); } -void cmInstalledFile::GetPropertyAsList(const std::string& prop, - std::vector<std::string>& list) const +std::vector<std::string> cmInstalledFile::GetPropertyAsList( + const std::string& prop) const { std::string value; this->GetProperty(prop, value); - list.clear(); - cmExpandList(value, list); + return std::move(cmList(value).data()); } diff --git a/Source/cmInstalledFile.h b/Source/cmInstalledFile.h index 82474f5203..373c34938a 100644 --- a/Source/cmInstalledFile.h +++ b/Source/cmInstalledFile.h @@ -59,8 +59,7 @@ public: bool GetPropertyAsBool(const std::string& prop) const; - void GetPropertyAsList(const std::string& prop, - std::vector<std::string>& list) const; + std::vector<std::string> GetPropertyAsList(const std::string& prop) const; void SetName(cmMakefile* mf, const std::string& name); diff --git a/Source/cmLDConfigLDConfigTool.cxx b/Source/cmLDConfigLDConfigTool.cxx index cce6178dae..0752b3353d 100644 --- a/Source/cmLDConfigLDConfigTool.cxx +++ b/Source/cmLDConfigLDConfigTool.cxx @@ -9,9 +9,9 @@ #include "cmsys/RegularExpression.hxx" +#include "cmList.h" #include "cmMakefile.h" #include "cmRuntimeDependencyArchive.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmUVProcessChain.h" @@ -34,7 +34,7 @@ bool cmLDConfigLDConfigTool::GetLDConfigPaths(std::vector<std::string>& paths) } } - std::vector<std::string> ldConfigCommand = cmExpandedList(ldConfigPath); + cmList ldConfigCommand{ ldConfigPath }; ldConfigCommand.emplace_back("-v"); ldConfigCommand.emplace_back("-N"); // Don't rebuild the cache. ldConfigCommand.emplace_back("-X"); // Don't update links. diff --git a/Source/cmList.cxx b/Source/cmList.cxx index bf5a65459a..022fcd2b4c 100644 --- a/Source/cmList.cxx +++ b/Source/cmList.cxx @@ -287,18 +287,20 @@ protected: : TransformSelector(std::move(tag)) { } - TransformSelectorIndexes(std::string&& tag, std::vector<int> const& indexes) + TransformSelectorIndexes(std::string&& tag, + std::vector<index_type> const& indexes) : TransformSelector(std::move(tag)) , Indexes(indexes) { } - TransformSelectorIndexes(std::string&& tag, std::vector<int>&& indexes) + TransformSelectorIndexes(std::string&& tag, + std::vector<index_type>&& indexes) : TransformSelector(std::move(tag)) , Indexes(indexes) { } - int NormalizeIndex(index_type index, std::size_t count) + index_type NormalizeIndex(index_type index, std::size_t count) { if (index < 0) { index = static_cast<index_type>(count) + index; @@ -338,7 +340,7 @@ public: class TransformSelectorFor : public TransformSelectorIndexes { public: - TransformSelectorFor(int start, int stop, int step) + TransformSelectorFor(index_type start, index_type stop, index_type step) : TransformSelectorIndexes("FOR") , Start(start) , Stop(stop) @@ -369,7 +371,7 @@ public: auto start = this->Start; auto step = this->Step; std::generate(this->Indexes.begin(), this->Indexes.end(), - [&start, step]() -> int { + [&start, step]() -> index_type { auto r = start; start += step; return r; @@ -805,7 +807,7 @@ std::string cmList::join(cm::string_view glue) const return cmJoin(this->Values, glue); } -std::string& cmList::append(cm::string_view value, std::string& list) +std::string& cmList::append(std::string& list, cm::string_view value) { if (list.empty()) { list = std::string(value); @@ -816,7 +818,7 @@ std::string& cmList::append(cm::string_view value, std::string& list) return list; } -std::string& cmList::prepend(cm::string_view value, std::string& list) +std::string& cmList::prepend(std::string& list, cm::string_view value) { if (list.empty()) { list = std::string(value); @@ -835,18 +837,19 @@ cmList::size_type cmList::ComputeIndex(index_type pos, bool boundCheck) const cmStrCat("index: ", pos, " out of range (0, 0)")); } + auto index = pos; if (!this->Values.empty()) { auto length = this->Values.size(); - if (pos < 0) { - pos = static_cast<index_type>(length) + pos; + if (index < 0) { + index = static_cast<index_type>(length) + index; } - if (pos < 0 || length <= static_cast<size_type>(pos)) { + if (index < 0 || length <= static_cast<size_type>(index)) { throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-", this->Values.size(), ", ", this->Values.size() - 1, ")")); } } - return pos; + return index; } return pos < 0 ? this->Values.size() + pos : pos; @@ -860,18 +863,19 @@ cmList::size_type cmList::ComputeInsertIndex(index_type pos, cmStrCat("index: ", pos, " out of range (0, 0)")); } + auto index = pos; if (!this->Values.empty()) { auto length = this->Values.size(); - if (pos < 0) { - pos = static_cast<index_type>(length) + pos; + if (index < 0) { + index = static_cast<index_type>(length) + index; } - if (pos < 0 || length < static_cast<size_type>(pos)) { + if (index < 0 || length < static_cast<size_type>(index)) { throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-", this->Values.size(), ", ", this->Values.size(), ")")); } } - return pos; + return index; } return pos < 0 ? this->Values.size() + pos : pos; @@ -882,7 +886,7 @@ cmList cmList::GetItems(std::vector<index_type>&& indexes) const cmList listItems; for (auto index : indexes) { - listItems.emplace_back(this->at(index)); + listItems.emplace_back(this->get_item(index)); } return listItems; @@ -896,9 +900,10 @@ cmList& cmList::RemoveItems(std::vector<index_type>&& indexes) // compute all indexes std::vector<size_type> idx(indexes.size()); - std::transform( - indexes.cbegin(), indexes.cend(), idx.begin(), - [this](const index_type& index) { return this->ComputeIndex(index); }); + std::transform(indexes.cbegin(), indexes.cend(), idx.begin(), + [this](const index_type& index) -> size_type { + return this->ComputeIndex(index); + }); std::sort(idx.begin(), idx.end(), [](size_type l, size_type r) { return l > r; }); @@ -925,8 +930,8 @@ cmList& cmList::RemoveItems(std::vector<std::string>&& items) } cmList::container_type::iterator cmList::Insert( - container_type::const_iterator pos, std::string&& value, - container_type& container, ExpandElements expandElements, + container_type& container, container_type::const_iterator pos, + std::string&& value, ExpandElements expandElements, EmptyElements emptyElements) { auto delta = std::distance(container.cbegin(), pos); diff --git a/Source/cmList.h b/Source/cmList.h index d994ad3890..d9ce9510c6 100644 --- a/Source/cmList.h +++ b/Source/cmList.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <algorithm> +#include <cstdint> #include <initializer_list> #include <iterator> #include <memory> @@ -16,19 +17,25 @@ #include <vector> #include <cm/string_view> +#include <cm/type_traits> +#include <cmext/iterator> #include "cmValue.h" /** * CMake lists management + * A CMake list is a string where list elements are separated by the ';' + * character. * * For all operations, input arguments (single value like cm::string_view or * multiple values specified through pair of iterators) are, by default, * expanded. The expansion can be controlled by the cmList::ExpandElements * option. * - * There is an exception to this rule. The following methods do not expand - * their argument: cmList::push_back, cmList::emplace and cmList::emplace_back. + * There ate some exceptions to this rule: + * * When the input argument is a cmList instance, the value is not expanded. + * * The following methods do not expand their argument: cmList::push_back, + * cmList::emplace and cmList::emplace_back. */ class cmList @@ -38,7 +45,7 @@ public: using value_type = container_type::value_type; using allocator_type = container_type::allocator_type; - using index_type = int; + using index_type = std::intptr_t; using size_type = container_type::size_type; using difference_type = container_type::difference_type; using reference = container_type::reference; @@ -74,8 +81,18 @@ public: this->assign(value, expandElements, emptyElements); } cmList(cm::string_view value, EmptyElements emptyElements) + : cmList(value, ExpandElements::Yes, emptyElements) + { + } + cmList(std::string const& value, + ExpandElements expandElements = ExpandElements::Yes, + EmptyElements emptyElements = EmptyElements::No) + { + this->assign(value, expandElements, emptyElements); + } + cmList(std::string const& value, EmptyElements emptyElements) + : cmList(value, ExpandElements::Yes, emptyElements) { - this->assign(value, ExpandElements::Yes, emptyElements); } cmList(cmValue list, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) @@ -135,6 +152,11 @@ public: this->assign(value); return *this; } + cmList& operator=(std::string const& value) + { + this->assign(value); + return *this; + } cmList& operator=(cmValue value) { if (value) { @@ -175,6 +197,17 @@ public: { this->assign(value, ExpandElements::Yes, emptyElements); } + void assign(std::string const& value, + ExpandElements expandElements = ExpandElements::Yes, + EmptyElements emptyElements = EmptyElements::No) + { + this->clear(); + this->append(value, expandElements, emptyElements); + } + void assign(std::string const& value, EmptyElements emptyElements) + { + this->assign(value, ExpandElements::Yes, emptyElements); + } void assign(cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) @@ -204,17 +237,17 @@ public: this->assign(first, last, ExpandElements::Yes, emptyElements); } void assign(const cmList& init, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { this->assign(init.begin(), init.end(), expandElements, emptyElements); } void assign(const cmList& init, EmptyElements emptyElements) { - this->assign(init, ExpandElements::Yes, emptyElements); + this->assign(init, ExpandElements::No, emptyElements); } void assign(cmList&& init, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { this->assign(std::make_move_iterator(init.begin()), @@ -224,7 +257,7 @@ public: } void assign(cmList&& init, EmptyElements emptyElements) { - this->assign(std::move(init), ExpandElements::Yes, emptyElements); + this->assign(std::move(init), ExpandElements::No, emptyElements); } void assign(const container_type& init, ExpandElements expandElements = ExpandElements::Yes, @@ -265,24 +298,21 @@ public: operator container_type&&() && noexcept { return std::move(this->Values); } // Element access - reference at(index_type pos) + reference at(size_type pos) { return this->Values.at(pos); } + const_reference at(size_type pos) const { return this->Values.at(pos); } + + reference operator[](size_type pos) { return this->Values[pos]; } + const_reference operator[](size_type pos) const { return this->Values[pos]; } + + reference get_item(index_type pos) { return this->Values.at(this->ComputeIndex(pos)); } - const_reference at(index_type pos) const + const_reference get_item(index_type pos) const { return this->Values.at(this->ComputeIndex(pos)); } - reference operator[](index_type pos) - { - return this->Values[this->ComputeIndex(pos, false)]; - } - const_reference operator[](index_type pos) const - { - return this->Values[this->ComputeIndex(pos, false)]; - } - reference front() { return this->Values.front(); } const_reference front() const { return this->Values.front(); } @@ -361,7 +391,7 @@ public: ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { - return cmList::Insert(pos, std::string(value), this->Values, + return cmList::Insert(this->Values, pos, std::string(value), expandElements, emptyElements); } iterator insert(const_iterator pos, cm::string_view value, @@ -369,6 +399,18 @@ public: { return this->insert(pos, value, ExpandElements::Yes, emptyElements); } + iterator insert(const_iterator pos, std::string const& value, + ExpandElements expandElements = ExpandElements::Yes, + EmptyElements emptyElements = EmptyElements::No) + { + return cmList::Insert(this->Values, pos, value, expandElements, + emptyElements); + } + iterator insert(const_iterator pos, std::string const& value, + EmptyElements emptyElements) + { + return this->insert(pos, value, ExpandElements::Yes, emptyElements); + } iterator insert(const_iterator pos, cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) @@ -390,7 +432,7 @@ public: ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { - return cmList::Insert(pos, first, last, this->Values, expandElements, + return cmList::Insert(this->Values, pos, first, last, expandElements, emptyElements); } template <typename InputIterator> @@ -400,7 +442,7 @@ public: return this->insert(pos, first, last, ExpandElements::Yes, emptyElements); } iterator insert(const_iterator pos, const cmList& values, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { return this->insert(pos, values.begin(), values.end(), expandElements, @@ -409,10 +451,10 @@ public: iterator insert(const_iterator pos, const cmList& values, EmptyElements emptyElements) { - return this->insert(pos, values, ExpandElements::Yes, emptyElements); + return this->insert(pos, values, ExpandElements::No, emptyElements); } iterator insert(const_iterator pos, cmList&& values, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { auto result = this->insert(pos, std::make_move_iterator(values.begin()), @@ -425,7 +467,7 @@ public: iterator insert(const_iterator pos, cmList&& values, EmptyElements emptyElements) { - return this->insert(pos, std::move(values), ExpandElements::Yes, + return this->insert(pos, std::move(values), ExpandElements::No, emptyElements); } iterator insert(const_iterator pos, const container_type& values, @@ -472,6 +514,16 @@ public: { return this->append(value, ExpandElements::Yes, emptyElements); } + iterator append(std::string const& value, + ExpandElements expandElements = ExpandElements::Yes, + EmptyElements emptyElements = EmptyElements::No) + { + return this->insert(this->cend(), value, expandElements, emptyElements); + } + iterator append(std::string const& value, EmptyElements emptyElements) + { + return this->append(value, ExpandElements::Yes, emptyElements); + } iterator append(cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) @@ -501,7 +553,7 @@ public: return this->append(first, last, ExpandElements::Yes, emptyElements); } iterator append(const cmList& values, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { return this->append(values.begin(), values.end(), expandElements, @@ -509,10 +561,10 @@ public: } iterator append(const cmList& values, EmptyElements emptyElements) { - return this->append(values, ExpandElements::Yes, emptyElements); + return this->append(values, ExpandElements::No, emptyElements); } iterator append(cmList&& values, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { auto result = this->append(std::make_move_iterator(values.begin()), @@ -524,7 +576,7 @@ public: } iterator append(cmList&& values, EmptyElements emptyElements) { - return this->append(std::move(values), ExpandElements::Yes, emptyElements); + return this->append(std::move(values), ExpandElements::No, emptyElements); } iterator append(const container_type& values, ExpandElements expandElements = ExpandElements::Yes, @@ -567,6 +619,16 @@ public: { return this->prepend(value, ExpandElements::Yes, emptyElements); } + iterator prepend(std::string const& value, + ExpandElements expandElements = ExpandElements::Yes, + EmptyElements emptyElements = EmptyElements::No) + { + return this->insert(this->cbegin(), value, expandElements, emptyElements); + } + iterator prepend(std::string const& value, EmptyElements emptyElements) + { + return this->prepend(value, ExpandElements::Yes, emptyElements); + } iterator prepend(cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) @@ -596,7 +658,7 @@ public: return this->prepend(first, last, ExpandElements::Yes, emptyElements); } iterator prepend(const cmList& values, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { return this->prepend(values.begin(), values.end(), expandElements, @@ -604,10 +666,10 @@ public: } iterator prepend(const cmList& values, EmptyElements emptyElements) { - return this->prepend(values, ExpandElements::Yes, emptyElements); + return this->prepend(values, ExpandElements::No, emptyElements); } iterator prepend(cmList&& values, - ExpandElements expandElements = ExpandElements::Yes, + ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { auto result = this->prepend(std::make_move_iterator(values.begin()), @@ -619,8 +681,7 @@ public: } iterator prepend(cmList&& values, EmptyElements emptyElements) { - return this->prepend(std::move(values), ExpandElements::Yes, - emptyElements); + return this->prepend(std::move(values), ExpandElements::No, emptyElements); } iterator prepend(const container_type& values, ExpandElements expandElements = ExpandElements::Yes, @@ -654,6 +715,7 @@ public: return this->insert(this->cbegin(), ilist); } + void push_back(std::string const& value) { this->Values.push_back(value); } void push_back(cm::string_view value) { this->Values.push_back(std::string{ value }); @@ -733,6 +795,8 @@ public: cmList& remove_duplicates(); + void resize(size_type count) { this->Values.resize(count); } + enum class FilterMode { INCLUDE, @@ -880,46 +944,61 @@ public: // ============== // these methods can be used to store CMake list expansion directly in a // std::vector. - static void assign(cm::string_view value, - std::vector<std::string>& container, + static void assign(std::vector<std::string>& container, + cm::string_view value, + EmptyElements emptyElements = EmptyElements::No) + { + container.clear(); + cmList::append(container, value, emptyElements); + } + static void assign(std::vector<std::string>& container, + std::string const& value, EmptyElements emptyElements = EmptyElements::No) { container.clear(); - cmList::append(value, container, emptyElements); + cmList::append(container, value, emptyElements); } - static void assign(cmValue value, std::vector<std::string>& container, + static void assign(std::vector<std::string>& container, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { - cmList::assign(*value, container, emptyElements); + cmList::assign(container, *value, emptyElements); } else { container.clear(); } } template <typename InputIterator> - static void assign(InputIterator first, InputIterator last, - std::vector<std::string>& container, + static void assign(std::vector<std::string>& container, InputIterator first, + InputIterator last, EmptyElements emptyElements = EmptyElements::No) { container.clear(); - cmList::append(first, last, container, emptyElements); + cmList::append(container, first, last, emptyElements); } static std::vector<std::string>::iterator insert( - std::vector<std::string>::const_iterator pos, cm::string_view value, std::vector<std::string>& container, + std::vector<std::string>::const_iterator pos, cm::string_view value, EmptyElements emptyElements = EmptyElements::No) { - return cmList::Insert(pos, std::string(value), container, + return cmList::Insert(container, pos, std::string(value), ExpandElements::Yes, emptyElements); } static std::vector<std::string>::iterator insert( - std::vector<std::string>::const_iterator pos, cmValue value, std::vector<std::string>& container, + std::vector<std::string>::const_iterator pos, std::string const& value, + EmptyElements emptyElements = EmptyElements::No) + { + return cmList::Insert(container, pos, value, ExpandElements::Yes, + emptyElements); + } + static std::vector<std::string>::iterator insert( + std::vector<std::string>& container, + std::vector<std::string>::const_iterator pos, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { - return cmList::insert(pos, *value, container, emptyElements); + return cmList::insert(container, pos, *value, emptyElements); } auto delta = std::distance(container.cbegin(), pos); @@ -927,63 +1006,73 @@ public: } template <typename InputIterator> static std::vector<std::string>::iterator insert( + std::vector<std::string>& container, std::vector<std::string>::const_iterator pos, InputIterator first, - InputIterator last, std::vector<std::string>& container, - EmptyElements emptyElements = EmptyElements::No) + InputIterator last, EmptyElements emptyElements = EmptyElements::No) { - return cmList::Insert(pos, first, last, container, ExpandElements::Yes, + return cmList::Insert(container, pos, first, last, ExpandElements::Yes, emptyElements); } static std::vector<std::string>::iterator append( - cm::string_view value, std::vector<std::string>& container, + std::vector<std::string>& container, cm::string_view value, EmptyElements emptyElements = EmptyElements::No) { - return cmList::insert(container.cend(), value, container, emptyElements); + return cmList::insert(container, container.cend(), value, emptyElements); } static std::vector<std::string>::iterator append( - cmValue value, std::vector<std::string>& container, + std::vector<std::string>& container, std::string const& value, + EmptyElements emptyElements = EmptyElements::No) + { + return cmList::insert(container, container.cend(), value, emptyElements); + } + static std::vector<std::string>::iterator append( + std::vector<std::string>& container, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { - return cmList::append(*value, container, emptyElements); + return cmList::append(container, *value, emptyElements); } return container.end(); } template <typename InputIterator> static std::vector<std::string>::iterator append( - InputIterator first, InputIterator last, - std::vector<std::string>& container, - EmptyElements emptyElements = EmptyElements::No) + std::vector<std::string>& container, InputIterator first, + InputIterator last, EmptyElements emptyElements = EmptyElements::No) { - return cmList::insert(container.cend(), first, last, container, + return cmList::insert(container, container.cend(), first, last, emptyElements); } static std::vector<std::string>::iterator prepend( - cm::string_view value, std::vector<std::string>& container, + std::vector<std::string>& container, cm::string_view value, + EmptyElements emptyElements = EmptyElements::No) + { + return cmList::insert(container, container.cbegin(), value, emptyElements); + } + static std::vector<std::string>::iterator prepend( + std::vector<std::string>& container, std::string const& value, EmptyElements emptyElements = EmptyElements::No) { - return cmList::insert(container.cbegin(), value, container, emptyElements); + return cmList::insert(container, container.cbegin(), value, emptyElements); } static std::vector<std::string>::iterator prepend( - cmValue value, std::vector<std::string>& container, + std::vector<std::string>& container, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { - return cmList::prepend(*value, container, emptyElements); + return cmList::prepend(container, *value, emptyElements); } return container.begin(); } template <typename InputIterator> static std::vector<std::string>::iterator prepend( - InputIterator first, InputIterator last, - std::vector<std::string>& container, - EmptyElements emptyElements = EmptyElements::No) + std::vector<std::string>& container, InputIterator first, + InputIterator last, EmptyElements emptyElements = EmptyElements::No) { - return cmList::insert(container.cbegin(), first, last, container, + return cmList::insert(container, container.cbegin(), first, last, emptyElements); } @@ -991,40 +1080,40 @@ public: // but without any intermediate expansion. So the operation is simply a // string concatenation with special handling for the CMake list item // separator - static std::string& append(cm::string_view value, std::string& list); + static std::string& append(std::string& list, cm::string_view value); template <typename InputIterator> - static std::string& append(InputIterator first, InputIterator last, - std::string& list) + static std::string& append(std::string& list, InputIterator first, + InputIterator last) { if (first == last) { return list; } - return cmList::append(cm::string_view{ std::accumulate( + return cmList::append(list, + cm::string_view{ std::accumulate( std::next(first), last, *first, [](std::string a, const std::string& b) { return std::move(a) + std::string(cmList::element_separator) + b; - }) }, - list); + }) }); } - static std::string& prepend(cm::string_view value, std::string& list); + static std::string& prepend(std::string& list, cm::string_view value); template <typename InputIterator> - static std::string& prepend(InputIterator first, InputIterator last, - std::string& list) + static std::string& prepend(std::string& list, InputIterator first, + InputIterator last) { if (first == last) { return list; } - return cmList::prepend(cm::string_view{ std::accumulate( + return cmList::prepend(list, + cm::string_view{ std::accumulate( std::next(first), last, *first, [](std::string a, const std::string& b) { return std::move(a) + std::string(cmList::element_separator) + b; - }) }, - list); + }) }); } // Non-members @@ -1047,26 +1136,26 @@ private: cmList& RemoveItems(std::vector<index_type>&& indexes); cmList& RemoveItems(std::vector<std::string>&& items); - static container_type::iterator Insert(container_type::const_iterator pos, + static container_type::iterator Insert(container_type& container, + container_type::const_iterator pos, std::string&& value, - container_type& container, ExpandElements expandElements, EmptyElements emptyElements); - static container_type::iterator Insert(container_type::const_iterator pos, + static container_type::iterator Insert(container_type& container, + container_type::const_iterator pos, const std::string& value, - container_type& container, ExpandElements expandElements, EmptyElements emptyElements) { auto tmp = value; - return cmList::Insert(pos, std::move(tmp), container, expandElements, + return cmList::Insert(container, pos, std::move(tmp), expandElements, emptyElements); } template <typename InputIterator> - static container_type::iterator Insert(container_type::const_iterator pos, + static container_type::iterator Insert(container_type& container, + container_type::const_iterator pos, InputIterator first, InputIterator last, - container_type& container, ExpandElements expandElements, EmptyElements emptyElements) { @@ -1080,7 +1169,7 @@ private: if (expandElements == ExpandElements::Yes) { for (; first != last; ++first) { auto size = container.size(); - insertPos = cmList::Insert(insertPos, *first, container, + insertPos = cmList::Insert(container, insertPos, *first, expandElements, emptyElements); insertPos += container.size() - size; } @@ -1177,6 +1266,13 @@ inline std::vector<std::string>& operator+=(std::vector<std::string>& l, return l; } +namespace std { +inline void swap(cmList& lhs, cmList& rhs) noexcept +{ + lhs.swap(rhs); +} +} // namespace std + namespace cm { inline void erase(cmList& list, const std::string& value) { @@ -1188,11 +1284,69 @@ inline void erase_if(cmList& list, Predicate pred) { list.erase(std::remove_if(list.begin(), list.end(), pred), list.end()); } + +// +// Provide a special implementation of cm::append because, in this case, +// expansion must not be applied to the inserted elements +// +#if defined(__SUNPRO_CC) && defined(__sparc) +// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile +// templates with constraints. +// So, on this platform, use only simple templates. +template <typename InputIt, + cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = 0> +void append(cmList& v, InputIt first, InputIt last) +{ + v.append(first, last, cmList::ExpandElements::No); } -namespace srd { -inline void swap(cmList& lhs, cmList& rhs) noexcept +template <typename Range, + cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> +void append(cmList& v, Range const& r) { - lhs.swap(rhs); + v.append(r.begin(), r.end(), cmList::ExpandElements::No); +} + +#else + +template < + typename InputIt, + cm::enable_if_t< + cm::is_input_iterator<InputIt>::value && + std::is_convertible<typename std::iterator_traits<InputIt>::value_type, + cmList::value_type>::value, + int> = 0> +void append(cmList& v, InputIt first, InputIt last) +{ + v.append(first, last, cmList::ExpandElements::No); +} + +template <typename Range, + cm::enable_if_t<cm::is_input_range<Range>::value && + std::is_convertible<typename Range::value_type, + cmList::value_type>::value, + int> = 0> +void append(cmList& v, Range const& r) +{ + v.append(r.begin(), r.end(), cmList::ExpandElements::No); } +#endif + +} // namespace cm + +/** + * Helper functions for legacy support. Use preferably cmList class directly + * or the static methods of the class. + */ +inline void cmExpandList( + cm::string_view arg, std::vector<std::string>& argsOut, + cmList::EmptyElements emptyElements = cmList::EmptyElements::No) +{ + cmList::append(argsOut, arg, emptyElements); +} +inline void cmExpandList( + cmValue arg, std::vector<std::string>& argsOut, + cmList::EmptyElements emptyElements = cmList::EmptyElements::No) +{ + cmList::append(argsOut, arg, emptyElements); } diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index 40be0ceeb5..acffa2ec81 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -205,7 +205,7 @@ bool HandleAppendCommand(std::vector<std::string> const& args, GetListString(listString, listName, makefile); makefile.AddDefinition( - listName, cmList::append(args.begin() + 2, args.end(), listString)); + listName, cmList::append(listString, args.begin() + 2, args.end())); return true; } @@ -226,7 +226,7 @@ bool HandlePrependCommand(std::vector<std::string> const& args, GetListString(listString, listName, makefile); makefile.AddDefinition( - listName, cmList::prepend(args.begin() + 2, args.end(), listString)); + listName, cmList::prepend(listString, args.begin() + 2, args.end())); return true; } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 6270c825f2..97f5de9697 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -11,10 +11,10 @@ # include <cmsys/Encoding.hxx> #endif +#include "cmList.h" #include "cmListFileLexer.h" #include "cmMessageType.h" #include "cmMessenger.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" struct cmListFileParser @@ -496,10 +496,11 @@ std::ostream& operator<<(std::ostream& os, BT<std::string> const& s) } std::vector<BT<std::string>> cmExpandListWithBacktrace( - std::string const& list, cmListFileBacktrace const& bt, bool emptyArgs) + std::string const& list, cmListFileBacktrace const& bt, + cmList::EmptyElements emptyArgs) { std::vector<BT<std::string>> result; - std::vector<std::string> tmp = cmExpandedList(list, emptyArgs); + cmList tmp{ list, emptyArgs }; result.reserve(tmp.size()); for (std::string& i : tmp) { result.emplace_back(std::move(i), bt); diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 05539892c9..e4e6eb37ed 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -13,6 +13,7 @@ #include <cm/optional> #include "cmConstStack.h" +#include "cmList.h" #include "cmSystemTools.h" /** \class cmListFileCache @@ -232,7 +233,7 @@ public: std::vector<BT<std::string>> cmExpandListWithBacktrace( std::string const& list, cmListFileBacktrace const& bt = cmListFileBacktrace(), - bool emptyArgs = false); + cmList::EmptyElements emptyArgs = cmList::EmptyElements::No); struct cmListFile { diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index eca7a9eb6e..aa953f469d 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -8,7 +8,6 @@ #include "cmGeneratorTarget.h" #include "cmMakefile.h" #include "cmOutputConverter.h" -#include "cmState.h" #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" @@ -17,9 +16,8 @@ class cmGlobalGenerator; cmLocalCommonGenerator::cmLocalCommonGenerator(cmGlobalGenerator* gg, - cmMakefile* mf, WorkDir wd) + cmMakefile* mf) : cmLocalGenerator(gg, mf) - , WorkingDirectory(wd) { this->ConfigNames = this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); @@ -29,21 +27,9 @@ cmLocalCommonGenerator::~cmLocalCommonGenerator() = default; std::string const& cmLocalCommonGenerator::GetWorkingDirectory() const { - if (this->WorkingDirectory == WorkDir::TopBin) { - return this->GetState()->GetBinaryDirectory(); - } return this->StateSnapshot.GetDirectory().GetCurrentBinary(); } -std::string cmLocalCommonGenerator::MaybeRelativeToWorkDir( - std::string const& path) const -{ - if (this->WorkingDirectory == WorkDir::TopBin) { - return this->MaybeRelativeToTopBinDir(path); - } - return this->MaybeRelativeToCurBinDir(path); -} - std::string cmLocalCommonGenerator::GetTargetFortranFlags( cmGeneratorTarget const* target, std::string const& config) { diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h index 0505c138d1..52f7a9e5e6 100644 --- a/Source/cmLocalCommonGenerator.h +++ b/Source/cmLocalCommonGenerator.h @@ -20,15 +20,8 @@ class cmSourceFile; */ class cmLocalCommonGenerator : public cmLocalGenerator { -protected: - enum class WorkDir - { - TopBin, - CurBin, - }; - public: - cmLocalCommonGenerator(cmGlobalGenerator* gg, cmMakefile* mf, WorkDir wd); + cmLocalCommonGenerator(cmGlobalGenerator* gg, cmMakefile* mf); ~cmLocalCommonGenerator() override; std::vector<std::string> const& GetConfigNames() const @@ -36,9 +29,7 @@ public: return this->ConfigNames; } - std::string const& GetWorkingDirectory() const; - - std::string MaybeRelativeToWorkDir(std::string const& path) const; + virtual std::string const& GetWorkingDirectory() const; std::string GetTargetFortranFlags(cmGeneratorTarget const* target, std::string const& config) override; @@ -48,8 +39,6 @@ public: cmGeneratorTarget const* gt = nullptr) override; protected: - WorkDir WorkingDirectory; - std::vector<std::string> ConfigNames; friend class cmCommonTargetGenerator; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 01e4241360..4089fd440b 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -38,6 +38,7 @@ #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" #include "cmLinkLineDeviceComputer.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmRulePlaceholderExpander.h" @@ -146,12 +147,10 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) { std::string const& appleArchs = this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES"); - std::vector<std::string> archs; - std::vector<std::string> sysroots; - cmExpandList(appleArchs, archs); - cmExpandList(*appleArchSysroots, sysroots, true); + cmList archs(appleArchs); + cmList sysroots{ appleArchSysroots, cmList::EmptyElements::Yes }; if (archs.size() == sysroots.size()) { - for (size_t i = 0; i < archs.size(); ++i) { + for (cmList::size_type i = 0; i < archs.size(); ++i) { this->AppleArchSysroots[archs[i]] = sysroots[i]; } } else { @@ -208,12 +207,12 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile) } } -cmRulePlaceholderExpander* cmLocalGenerator::CreateRulePlaceholderExpander() - const +std::unique_ptr<cmRulePlaceholderExpander> +cmLocalGenerator::CreateRulePlaceholderExpander() const { - return new cmRulePlaceholderExpander(this->Compilers, this->VariableMappings, - this->CompilerSysroot, - this->LinkerSysroot); + return cm::make_unique<cmRulePlaceholderExpander>( + this->Compilers, this->VariableMappings, this->CompilerSysroot, + this->LinkerSysroot); } cmLocalGenerator::~cmLocalGenerator() = default; @@ -347,7 +346,7 @@ void cmLocalGenerator::GenerateTestFiles() cmValue testIncludeFiles = this->Makefile->GetProperty("TEST_INCLUDE_FILES"); if (testIncludeFiles) { - std::vector<std::string> includesList = cmExpandedList(*testIncludeFiles); + cmList includesList{ *testIncludeFiles }; for (std::string const& i : includesList) { fout << "include(\"" << i << "\")\n"; } @@ -1064,9 +1063,9 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, std::string isJMCEnabled = cmGeneratorExpression::Evaluate(*jmcExprGen, this, config); if (cmIsOn(isJMCEnabled)) { - std::vector<std::string> optVec = cmExpandedList(*jmc); + cmList optList{ *jmc }; std::string jmcFlags; - this->AppendCompileOptions(jmcFlags, optVec); + this->AppendCompileOptions(jmcFlags, optList); if (!jmcFlags.empty()) { flags.emplace_back(std::move(jmcFlags)); } @@ -1168,11 +1167,11 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( // Standard include directories to be added unconditionally at the end. // These are intended to simulate additional implicit include directories. - std::vector<std::string> userStandardDirs; + cmList userStandardDirs; { std::string const value = this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_STANDARD_INCLUDE_DIRECTORIES")); - cmExpandList(value, userStandardDirs); + userStandardDirs.assign(value); for (std::string& usd : userStandardDirs) { cmSystemTools::ConvertToUnixSlashes(usd); } @@ -1195,13 +1194,12 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit( // directories for modules ('.mod' files). if (lang != "Fortran") { size_t const impDirVecOldSize = impDirVec.size(); - if (this->Makefile->GetDefExpandList( - cmStrCat("CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES"), - impDirVec)) { - // FIXME: Use cmRange with 'advance()' when it supports non-const. - for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) { - cmSystemTools::ConvertToUnixSlashes(impDirVec[i]); - } + cmList::append(impDirVec, + this->Makefile->GetDefinition(cmStrCat( + "CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES"))); + // FIXME: Use cmRange with 'advance()' when it supports non-const. + for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) { + cmSystemTools::ConvertToUnixSlashes(impDirVec[i]); } } @@ -1588,6 +1586,8 @@ void cmLocalGenerator::GetTargetFlags( this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config, linkLanguage); this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage); + this->AppendDependencyInfoLinkerFlags(extraLinkFlags, target, config, + linkLanguage); this->AppendModuleDefinitionFlag(extraLinkFlags, target, linkLineComputer, config); @@ -1954,8 +1954,8 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, cmValue opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef); if (opt) { - std::vector<std::string> optVec = cmExpandedList(*opt); - for (std::string const& i : optVec) { + cmList optList{ *opt }; + for (std::string const& i : optList) { this->AppendFlagEscape(flags, i); } } @@ -2426,7 +2426,7 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIC")); } if (!picFlags.empty()) { - std::vector<std::string> options = cmExpandedList(picFlags); + cmList options{ picFlags }; for (std::string const& o : options) { this->AppendFlagEscape(flags, o); } @@ -2447,10 +2447,9 @@ void cmLocalGenerator::AddColorDiagnosticsFlags(std::string& flags, cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_COLOR_DIAGNOSTICS_OFF"); } - std::vector<std::string> options; - this->Makefile->GetDefExpandList(colorFlagName, options); + cmList options{ this->Makefile->GetDefinition(colorFlagName) }; - for (std::string const& option : options) { + for (auto const& option : options) { this->AppendFlagEscape(flags, option); } } @@ -2973,6 +2972,7 @@ void cmLocalGenerator::WriteUnitySourceInclude( unity_file << *beforeInclude << "\n"; } + unity_file << "// NOLINTNEXTLINE(bugprone-suspicious-include)\n"; unity_file << "#include \"" << sf_full_path << "\"\n"; if (afterInclude) { @@ -3163,7 +3163,7 @@ void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags, return; } - std::vector<std::string> flagsList = cmExpandedList(*rawFlagsList); + cmList flagsList{ *rawFlagsList }; for (std::string const& o : flagsList) { this->AppendFlagEscape(flags, o); } @@ -3198,12 +3198,47 @@ void cmLocalGenerator::AppendPositionIndependentLinkerFlags( return; } - std::vector<std::string> flagsList = cmExpandedList(pieFlags); + cmList flagsList{ pieFlags }; for (const auto& flag : flagsList) { this->AppendFlagEscape(flags, flag); } } +void cmLocalGenerator::AppendDependencyInfoLinkerFlags( + std::string& flags, cmGeneratorTarget* target, const std::string& config, + const std::string& linkLanguage) +{ + if (!this->GetGlobalGenerator()->SupportsLinkerDependencyFile() || + !target->HasLinkDependencyFile(config)) { + return; + } + + auto depFlag = *this->Makefile->GetDefinition( + cmStrCat("CMAKE_", linkLanguage, "_LINKER_DEPFILE_FLAGS")); + if (depFlag.empty()) { + return; + } + + auto depFile = this->ConvertToOutputFormat( + this->MaybeRelativeToWorkDir(this->GetLinkDependencyFile(target, config)), + cmOutputConverter::SHELL); + auto rulePlaceholderExpander = this->CreateRulePlaceholderExpander(); + cmRulePlaceholderExpander::RuleVariables linkDepsVariables; + linkDepsVariables.DependencyFile = depFile.c_str(); + rulePlaceholderExpander->ExpandRuleVariables(this, depFlag, + linkDepsVariables); + auto depFlags = cmExpandListWithBacktrace(depFlag); + target->ResolveLinkerWrapper(depFlags, linkLanguage); + + this->AppendFlags(flags, depFlags); +} + +std::string cmLocalGenerator::GetLinkDependencyFile( + cmGeneratorTarget* /*target*/, const std::string& /*config*/) const +{ + return "link.d"; +} + void cmLocalGenerator::AppendModuleDefinitionFlag( std::string& flags, cmGeneratorTarget const* target, cmLinkLineComputer* linkLineComputer, std::string const& config) @@ -3264,7 +3299,7 @@ void cmLocalGenerator::AppendCompileOptions(std::string& options, } // Expand the list of options. - std::vector<std::string> options_vec = cmExpandedList(options_list); + cmList options_vec{ options_list }; this->AppendCompileOptions(options, options_vec, regex); } @@ -3322,7 +3357,7 @@ void cmLocalGenerator::AppendIncludeDirectories( } // Expand the list of includes. - std::vector<std::string> includes_vec = cmExpandedList(includes_list); + cmList includes_vec{ includes_list }; this->AppendIncludeDirectories(includes, includes_vec, sourceFile); } @@ -3454,7 +3489,7 @@ void cmLocalGenerator::AppendFeatureOptions(std::string& flags, cmValue optionList = this->Makefile->GetDefinition( cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature)); if (optionList) { - std::vector<std::string> options = cmExpandedList(*optionList); + cmList options{ *optionList }; for (std::string const& o : options) { this->AppendFlagEscape(flags, o); } @@ -4385,12 +4420,11 @@ void AddUtilityCommand(cmLocalGenerator& lg, cmCommandOrigin origin, std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target) { - const std::string& targetProperty = - target->GetSafeProperty("ISPC_INSTRUCTION_SETS"); - std::vector<std::string> ispcTargets; + const cmValue targetProperty = target->GetProperty("ISPC_INSTRUCTION_SETS"); + cmList ispcTargets; - if (!cmIsOff(targetProperty)) { - cmExpandList(targetProperty, ispcTargets); + if (!targetProperty.IsOff()) { + ispcTargets.assign(targetProperty); for (auto& ispcTarget : ispcTargets) { // transform targets into the suffixes auto pos = ispcTarget.find('-'); @@ -4402,7 +4436,7 @@ std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target) ispcTarget = target_suffix; } } - return ispcTargets; + return std::move(ispcTargets.data()); } std::vector<std::string> ComputeISPCExtraObjects( @@ -4500,11 +4534,11 @@ cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc, std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths( cmCompiledGeneratorExpression const& cge, std::string const& config) { - std::vector<std::string> paths = cmExpandedList(cge.Evaluate(this, config)); + cmList paths{ cge.Evaluate(this, config) }; for (std::string& p : paths) { p = cmSystemTools::CollapseFullPath(p, this->GetCurrentBinaryDirectory()); } - return paths; + return std::move(paths.data()); } std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex( diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index bda82bce00..c811408138 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -89,7 +89,7 @@ class cmLocalGenerator : public cmOutputConverter { public: cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile); - virtual ~cmLocalGenerator(); + ~cmLocalGenerator() override; /** * Generate the makefile for this directory. @@ -137,7 +137,8 @@ public: return this->GlobalGenerator; } - virtual cmRulePlaceholderExpander* CreateRulePlaceholderExpander() const; + virtual std::unique_ptr<cmRulePlaceholderExpander> + CreateRulePlaceholderExpander() const; std::string GetLinkLibsCMP0065(std::string const& linkLanguage, cmGeneratorTarget& tgt) const; @@ -183,6 +184,12 @@ public: cmGeneratorTarget* target, const std::string& config, const std::string& lang); + void AppendDependencyInfoLinkerFlags(std::string& flags, + cmGeneratorTarget* target, + const std::string& config, + const std::string& lang); + virtual std::string GetLinkDependencyFile(cmGeneratorTarget* target, + const std::string& config) const; void AppendModuleDefinitionFlag(std::string& flags, cmGeneratorTarget const* target, cmLinkLineComputer* linkLineComputer, diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index d0bd3758f4..4b0604c55e 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -22,6 +22,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalNinjaGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -40,19 +41,18 @@ cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg, cmMakefile* mf) - : cmLocalCommonGenerator(gg, mf, WorkDir::TopBin) + : cmLocalCommonGenerator(gg, mf) { } // Virtual public methods. -cmRulePlaceholderExpander* +std::unique_ptr<cmRulePlaceholderExpander> cmLocalNinjaGenerator::CreateRulePlaceholderExpander() const { - cmRulePlaceholderExpander* ret = - this->cmLocalGenerator::CreateRulePlaceholderExpander(); + auto ret = this->cmLocalGenerator::CreateRulePlaceholderExpander(); ret->SetTargetImpLib("$TARGET_IMPLIB"); - return ret; + return std::unique_ptr<cmRulePlaceholderExpander>(std::move(ret)); } cmLocalNinjaGenerator::~cmLocalNinjaGenerator() = default; @@ -187,6 +187,26 @@ cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator() return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator()); } +std::string const& cmLocalNinjaGenerator::GetWorkingDirectory() const +{ + return this->GetState()->GetBinaryDirectory(); +} + +std::string cmLocalNinjaGenerator::MaybeRelativeToWorkDir( + std::string const& path) const +{ + return this->GetGlobalNinjaGenerator()->NinjaOutputPath( + this->MaybeRelativeToTopBinDir(path)); +} + +std::string cmLocalNinjaGenerator::GetLinkDependencyFile( + cmGeneratorTarget* target, std::string const& config) const +{ + return cmStrCat(target->GetSupportDirectory(), + this->GetGlobalNinjaGenerator()->ConfigDirectory(config), + "/link.d"); +} + // Virtual protected methods. std::string cmLocalNinjaGenerator::ConvertToIncludeReference( @@ -301,7 +321,7 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) if (jobpools) { cmGlobalNinjaGenerator::WriteComment( os, "Pools defined by global property JOB_POOLS"); - std::vector<std::string> pools = cmExpandedList(*jobpools); + cmList pools{ *jobpools }; for (std::string const& pool : pools) { const std::string::size_type eq = pool.find('='); unsigned int jobs; @@ -892,8 +912,7 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( } vars.Output = output.c_str(); - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = this->CreateRulePlaceholderExpander(); std::string launcher = *property_value; rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars); @@ -908,14 +927,11 @@ void cmLocalNinjaGenerator::AdditionalCleanFiles(const std::string& config) { if (cmValue prop_value = this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) { - std::vector<std::string> cleanFiles; - { - cmExpandList(cmGeneratorExpression::Evaluate(*prop_value, this, config), - cleanFiles); - } + cmList cleanFiles{ cmGeneratorExpression::Evaluate(*prop_value, this, + config) }; std::string const& binaryDir = this->GetCurrentBinaryDirectory(); cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator(); - for (std::string const& cleanFile : cleanFiles) { + for (auto const& cleanFile : cleanFiles) { // Support relative paths gg->AddAdditionalCleanFile( cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config); diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index 4d393d9c3a..74b8b3b3f8 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -6,6 +6,7 @@ #include <iosfwd> #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -41,7 +42,8 @@ public: void Generate() override; - cmRulePlaceholderExpander* CreateRulePlaceholderExpander() const override; + std::unique_ptr<cmRulePlaceholderExpander> CreateRulePlaceholderExpander() + const override; std::string GetTargetDirectory( cmGeneratorTarget const* target) const override; @@ -52,6 +54,10 @@ public: const cmake* GetCMakeInstance() const; cmake* GetCMakeInstance(); + std::string const& GetWorkingDirectory() const override; + + std::string MaybeRelativeToWorkDir(std::string const& path) const override; + /// @returns the relative path between the HomeOutputDirectory and this /// local generators StartOutputDirectory. std::string GetHomeRelativeOutputPath() const @@ -90,6 +96,9 @@ public: bool HasUniqueByproducts(std::vector<std::string> const& byproducts, cmListFileBacktrace const& bt); + std::string GetLinkDependencyFile(cmGeneratorTarget* target, + std::string const& config) const override; + protected: std::string ConvertToIncludeReference( std::string const& path, cmOutputConverter::OutputFormat format) override; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 56a41b1a98..cfe4eb629d 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -29,6 +29,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -110,7 +111,7 @@ private: cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3( cmGlobalGenerator* gg, cmMakefile* mf) - : cmLocalCommonGenerator(gg, mf, WorkDir::CurBin) + : cmLocalCommonGenerator(gg, mf) { this->MakefileVariableSize = 0; this->ColorMakefile = false; @@ -238,6 +239,12 @@ void cmLocalUnixMakefileGenerator3::GetIndividualFileTargets( } } +std::string cmLocalUnixMakefileGenerator3::GetLinkDependencyFile( + cmGeneratorTarget* target, std::string const& /*config*/) const +{ + return cmStrCat(target->GetSupportDirectory(), "/link.d"); +} + void cmLocalUnixMakefileGenerator3::WriteLocalMakefile() { // generate the includes @@ -962,8 +969,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( *content << dir; } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = this->CreateRulePlaceholderExpander(); // Add each command line to the set of commands. std::vector<std::string> commands1; @@ -1129,14 +1135,13 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand( std::vector<std::string>& commands) { - std::vector<std::string> cleanFiles; + cmList cleanFiles; // Look for additional files registered for cleaning in this directory. if (cmValue prop_value = this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) { - cmExpandList(cmGeneratorExpression::Evaluate( - *prop_value, this, - this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")), - cleanFiles); + cleanFiles.assign(cmGeneratorExpression::Evaluate( + *prop_value, this, + this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))); } if (cleanFiles.empty()) { return; @@ -1434,7 +1439,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies( this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES"); if (!depends.empty()) { // dependencies are managed by compiler - auto depFiles = cmExpandedList(depends, true); + cmList depFiles{ depends, cmList::EmptyElements::Yes }; std::string const internalDepFile = targetDir + "/compiler_depend.internal"; std::string const depFile = targetDir + "/compiler_depend.make"; @@ -1556,8 +1561,7 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( this->WriteDisclaimer(internalRuleFileStream); // for each language we need to scan, scan it - std::vector<std::string> langs = - cmExpandedList(mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES")); + cmList langs{ mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES") }; for (std::string const& lang : langs) { // construct the checker // Create the scanner for this language @@ -1602,7 +1606,7 @@ void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose) } // Convert the string to a list and preserve empty entries. - std::vector<std::string> pairs = cmExpandedList(*pairs_string, true); + cmList pairs{ *pairs_string, cmList::EmptyElements::Yes }; for (auto i = pairs.begin(); i != pairs.end() && (i + 1) != pairs.end();) { const std::string& depender = *i++; const std::string& dependee = *i++; @@ -1822,7 +1826,7 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf, if (!infoDef) { return; } - std::vector<std::string> files = cmExpandedList(*infoDef); + cmList files{ *infoDef }; // Each depend information file corresponds to a target. Clear the // dependencies for that target. @@ -1863,7 +1867,7 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf, cmSystemTools::Touch(DepTimestamp.GenericString(), true); // clear the dependencies files generated by the compiler - std::vector<std::string> dependencies = cmExpandedList(depsFiles, true); + cmList dependencies{ depsFiles, cmList::EmptyElements::Yes }; cmDependsCompiler depsManager; depsManager.SetVerbose(verbose); depsManager.ClearDependencies(dependencies); @@ -1973,14 +1977,14 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( // Store include transform rule properties. Write the directory // rules first because they may be overridden by later target rules. - std::vector<std::string> transformRules; + cmList transformRules; if (cmValue xform = this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { - cmExpandList(*xform, transformRules); + transformRules.assign(*xform); } if (cmValue xform = target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) { - cmExpandList(*xform, transformRules); + transformRules.append(*xform); } if (!transformRules.empty()) { cmakefileStream << "\nset(CMAKE_INCLUDE_TRANSFORMS\n"; @@ -2009,6 +2013,18 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( << this->MaybeRelativeToTopBinDir(src) << "\"\n"; } } + } else if (compilerLang.first == "LINK"_s) { + auto depFormat = this->Makefile->GetDefinition( + cmStrCat("CMAKE_", target->GetLinkerLanguage(this->GetConfigName()), + "_LINKER_DEPFILE_FORMAT")); + for (auto const& compilerPair : compilerPairs) { + for (auto const& src : compilerPair.second) { + cmakefileStream << R"( "" ")" + << this->MaybeRelativeToTopBinDir(compilerPair.first) + << "\" \"" << depFormat << "\" \"" + << this->MaybeRelativeToTopBinDir(src) << "\"\n"; + } + } } else { auto depFormat = this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT")); diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 78aa7f9c2f..7d5a9224b4 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -191,6 +191,9 @@ public: // Eclipse generator. void GetIndividualFileTargets(std::vector<std::string>& targets); + std::string GetLinkDependencyFile(cmGeneratorTarget* target, + std::string const& config) const override; + protected: void WriteLocalMakefile(); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 239748db67..a7ea0dff2c 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -29,6 +29,7 @@ #include "cmGlobalGenerator.h" #include "cmGlobalVisualStudio7Generator.h" #include "cmGlobalVisualStudioGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -1576,12 +1577,12 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( // Check for extra object-file dependencies. if (cmValue deps = sf.GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> depends = cmExpandedList(*deps); - const char* sep = ""; - for (const std::string& d : depends) { - fc.AdditionalDeps += sep; - fc.AdditionalDeps += lg->ConvertToXMLOutputPath(d); - sep = ";"; + cmList depends{ *deps }; + if (!depends.empty()) { + for (std::string& d : depends) { + d = lg->ConvertToXMLOutputPath(d); + } + fc.AdditionalDeps += depends.to_string(); needfc = true; } } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 3a69b2eeed..01afc44f28 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -43,6 +43,7 @@ #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" // IWYU pragma: keep #include "cmInstallSubdirectoryGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMessageType.h" @@ -1448,15 +1449,13 @@ bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove) if (remove) { if (cmValue cdefs = this->GetProperty("COMPILE_DEFINITIONS")) { // Expand the list. - std::vector<std::string> defs = cmExpandedList(*cdefs); + cmList defs{ *cdefs }; // Recompose the list without the definition. - auto defEnd = std::remove(defs.begin(), defs.end(), define); - auto defBegin = defs.begin(); - std::string ndefs = cmJoin(cmMakeRange(defBegin, defEnd), ";"); + defs.remove_items({ define }); // Store the new list. - this->SetProperty("COMPILE_DEFINITIONS", ndefs); + this->SetProperty("COMPILE_DEFINITIONS", defs.to_string()); } } else { // Append the definition to the directory property. @@ -1958,21 +1957,15 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value, value = existingValue->c_str(); } if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) { - std::vector<std::string>::size_type cc; - std::vector<std::string> files; nvalue = value ? value : ""; - cmExpandList(nvalue, files); - nvalue.clear(); - for (cc = 0; cc < files.size(); cc++) { - if (!cmIsOff(files[cc])) { - files[cc] = cmSystemTools::CollapseFullPath(files[cc]); + cmList files(nvalue); + for (auto& file : files) { + if (!cmIsOff(file)) { + file = cmSystemTools::CollapseFullPath(file); } - if (cc > 0) { - nvalue += ";"; - } - nvalue += files[cc]; } + nvalue = files.to_string(); this->GetCMakeInstance()->AddCacheEntry(name, nvalue, doc, type); nvalue = *this->GetState()->GetInitializedCacheValue(name); @@ -2064,7 +2057,7 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target) } if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { - std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp); + cmList linkLibs{ *linkLibsProp }; for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) { std::string libraryName = *j; @@ -2378,7 +2371,7 @@ void cmMakefile::ExpandVariablesCMP0019() } if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) { - std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp); + cmList linkLibs{ *linkLibsProp }; for (auto l = linkLibs.begin(); l != linkLibs.end(); ++l) { std::string libName = *l; @@ -2614,18 +2607,6 @@ const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const return this->GetDefinition(name); } -bool cmMakefile::GetDefExpandList(const std::string& name, - std::vector<std::string>& out, - bool emptyArgs) const -{ - cmValue def = this->GetDefinition(name); - if (!def) { - return false; - } - cmExpandList(*def, out, emptyArgs); - return true; -} - std::vector<std::string> cmMakefile::GetDefinitions() const { std::vector<std::string> res = this->StateSnapshot.ClosureKeys(); @@ -3266,9 +3247,9 @@ std::string cmMakefile::GetDefaultConfiguration() const std::vector<std::string> cmMakefile::GetGeneratorConfigs( GeneratorConfigQuery mode) const { - std::vector<std::string> configs; + cmList configs; if (this->GetGlobalGenerator()->IsMultiConfig()) { - this->GetDefExpandList("CMAKE_CONFIGURATION_TYPES", configs); + configs.assign(this->GetDefinition("CMAKE_CONFIGURATION_TYPES")); } else if (mode != cmMakefile::OnlyMultiConfig) { const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE"); if (!buildType.empty()) { @@ -3278,7 +3259,7 @@ std::vector<std::string> cmMakefile::GetGeneratorConfigs( if (mode == cmMakefile::IncludeEmptyConfig && configs.empty()) { configs.emplace_back(); } - return configs; + return std::move(configs.data()); } bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff, @@ -3406,7 +3387,7 @@ bool cmMakefile::ExpandArguments( if (i.Delim == cmListFileArgument::Quoted) { outArgs.emplace_back(value, true); } else { - std::vector<std::string> stringArgs = cmExpandedList(value); + cmList stringArgs{ value }; for (std::string const& stringArg : stringArgs) { outArgs.emplace_back(stringArg, false); } @@ -3812,7 +3793,7 @@ std::string cmMakefile::GetModulesFile(const std::string& filename, // Always search in CMAKE_MODULE_PATH: cmValue cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH"); if (cmakeModulePath) { - std::vector<std::string> modulePath = cmExpandedList(*cmakeModulePath); + cmList modulePath{ *cmakeModulePath }; // Look through the possible module directories. for (std::string itempl : modulePath) { @@ -4155,11 +4136,11 @@ void cmMakefile::GetTests(const std::string& config, void cmMakefile::AddCMakeDependFilesFromUser() { - std::vector<std::string> deps; + cmList deps; if (cmValue deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) { - cmExpandList(*deps_str, deps); + deps.assign(*deps_str); } - for (std::string const& dep : deps) { + for (auto const& dep : deps) { if (cmSystemTools::FileIsFullPath(dep)) { this->AddCMakeDependFile(dep); } else { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index a43ff41f9c..d1f5be53a0 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -518,8 +518,6 @@ public: const std::string& GetRequiredDefinition(const std::string& name) const; bool IsDefinitionSet(const std::string&) const; bool IsNormalDefinitionSet(const std::string&) const; - bool GetDefExpandList(const std::string& name, std::vector<std::string>& out, - bool emptyArgs = false) const; /** * Get the list of all variables in the current space. If argument * cacheonly is specified and is greater than 0, then only cache diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 196007328e..4a2b9e8996 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -16,6 +16,7 @@ #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" #include "cmLinkLineDeviceComputer.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -69,6 +70,8 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles() this->WriteExecutableRule(true); } + this->WriteTargetLinkDependRules(); + // Write clean target this->WriteTargetCleanRules(); @@ -151,11 +154,10 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); // Construct the main link rule. - std::vector<std::string> real_link_commands; const std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE"; const std::string linkRule = this->GetLinkRule(linkRuleVar); std::vector<std::string> commands1; - cmExpandList(linkRule, real_link_commands); + cmList real_link_commands(linkRule); bool useResponseFileForObjects = this->CheckUseResponseFileForObjects(linkLanguage); @@ -230,12 +232,12 @@ void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule( launcher = cmStrCat(val, ' '); } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->LocalGenerator->CreateRulePlaceholderExpander(); // Expand placeholders in the commands. rulePlaceholderExpander->SetTargetImpLib(targetOutput); - for (std::string& real_link_command : real_link_commands) { + for (auto& real_link_command : real_link_commands) { real_link_command = cmStrCat(launcher, real_link_command); rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, real_link_command, vars); @@ -466,18 +468,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); // Construct the main link rule. - std::vector<std::string> real_link_commands; std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable( linkLanguage, this->GetConfigName()); std::string linkRule = this->GetLinkRule(linkRuleVar); std::vector<std::string> commands1; - cmExpandList(linkRule, real_link_commands); + cmList real_link_commands(linkRule); + if (this->GeneratorTarget->IsExecutableWithExports()) { // If a separate rule for creating an import library is specified // add it now. std::string implibRuleVar = cmStrCat("CMAKE_", linkLanguage, "_CREATE_IMPORT_LIBRARY"); - this->Makefile->GetDefExpandList(implibRuleVar, real_link_commands); + real_link_commands.append(this->Makefile->GetDefinition(implibRuleVar)); } bool useResponseFileForObjects = @@ -596,12 +598,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) launcher = cmStrCat(val, ' '); } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->LocalGenerator->CreateRulePlaceholderExpander(); // Expand placeholders in the commands. rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport); - for (std::string& real_link_command : real_link_commands) { + for (auto& real_link_command : real_link_commands) { real_link_command = cmStrCat(launcher, real_link_command); rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, real_link_command, vars); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 3e4a08ee27..b07a74b568 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -16,6 +16,7 @@ #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" #include "cmLinkLineDeviceComputer.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" @@ -61,6 +62,9 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles() // write in rules for object files and custom commands this->WriteTargetBuildRules(); + // Write in the rules for the link dependency file + this->WriteTargetLinkDependRules(); + // write the link rules // Write the rule for this target type. switch (this->GeneratorTarget->GetType()) { @@ -304,7 +308,7 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( vars.Language = linkLanguage.c_str(); // Expand the rule variables. - std::vector<std::string> real_link_commands; + cmList real_link_commands; { // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); @@ -369,16 +373,16 @@ void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( launcher = cmStrCat(val, ' '); } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->LocalGenerator->CreateRulePlaceholderExpander(); // Construct the main link rule and expand placeholders. rulePlaceholderExpander->SetTargetImpLib(targetOutput); std::string linkRule = this->GetLinkRule(linkRuleVar); - cmExpandList(linkRule, real_link_commands); + real_link_commands.append(linkRule); // Expand placeholders. - for (std::string& real_link_command : real_link_commands) { + for (auto& real_link_command : real_link_commands) { real_link_command = cmStrCat(launcher, real_link_command); rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, real_link_command, vars); @@ -640,9 +644,9 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // For static libraries there might be archiving rules. bool haveStaticLibraryRule = false; - std::vector<std::string> archiveCreateCommands; - std::vector<std::string> archiveAppendCommands; - std::vector<std::string> archiveFinishCommands; + cmList archiveCreateCommands; + cmList archiveAppendCommands; + cmList archiveFinishCommands; std::string::size_type archiveCommandLimit = std::string::npos; if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { haveStaticLibraryRule = this->Makefile->IsDefinitionSet(linkRuleVar); @@ -652,21 +656,23 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( arCreateVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( arCreateVar, linkLanguage, this->GetConfigName()); - this->Makefile->GetDefExpandList(arCreateVar, archiveCreateCommands); + archiveCreateCommands.assign(this->Makefile->GetDefinition(arCreateVar)); + std::string arAppendVar = cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_APPEND"); arAppendVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( arAppendVar, linkLanguage, this->GetConfigName()); - this->Makefile->GetDefExpandList(arAppendVar, archiveAppendCommands); + archiveAppendCommands.assign(this->Makefile->GetDefinition(arAppendVar)); + std::string arFinishVar = cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_FINISH"); arFinishVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( arFinishVar, linkLanguage, this->GetConfigName()); - this->Makefile->GetDefExpandList(arFinishVar, archiveFinishCommands); + archiveFinishCommands.assign(this->Makefile->GetDefinition(arFinishVar)); } // Decide whether to use archiving rules. @@ -690,11 +696,11 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( } // Expand the rule variables. - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->LocalGenerator->CreateRulePlaceholderExpander(); bool useWatcomQuote = this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); - std::vector<std::string> real_link_commands; + cmList real_link_commands; { // Set path conversion for link script shells. this->LocalGenerator->SetLinkScriptShell(useLinkScript); @@ -879,7 +885,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( } else { // Get the set of commands. std::string linkRule = this->GetLinkRule(linkRuleVar); - cmExpandList(linkRule, real_link_commands); + real_link_commands.append(linkRule); if (this->UseLWYU) { cmValue lwyuCheck = this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK"); @@ -895,7 +901,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( } // Expand placeholders. - for (std::string& real_link_command : real_link_commands) { + for (auto& real_link_command : real_link_commands) { real_link_command = cmStrCat(launcher, real_link_command); rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, real_link_command, vars); @@ -965,7 +971,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) { auto genStubsRule = this->Makefile->GetDefinition("CMAKE_CREATE_TEXT_STUBS"); - auto genStubs_commands = cmExpandedList(genStubsRule); + cmList genStubs_commands{ genStubsRule }; std::string TBDFullPath = cmStrCat(outpathImp, this->TargetNames.ImportOutput); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 3112acd578..02cdf57275 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -29,6 +29,7 @@ #include "cmGlobalCommonGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" // IWYU pragma: keep +#include "cmList.h" #include "cmLocalCommonGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" @@ -149,6 +150,8 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags( this->LocalGenerator->AppendPositionIndependentLinkerFlags( flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); + this->LocalGenerator->AppendDependencyInfoLinkerFlags( + flags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); } void cmMakefileTargetGenerator::CreateRuleFile() @@ -207,27 +210,24 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() // -- Write the custom commands for this target // Evaluates generator expressions and expands prop_value - auto evaluatedFiles = - [this](const std::string& prop_value) -> std::vector<std::string> { - std::vector<std::string> files; - cmExpandList(cmGeneratorExpression::Evaluate( - prop_value, this->LocalGenerator, this->GetConfigName(), - this->GeneratorTarget), - files); + auto evaluatedFiles = [this](const std::string& prop_value) -> cmList { + cmList files{ cmGeneratorExpression::Evaluate( + prop_value, this->LocalGenerator, this->GetConfigName(), + this->GeneratorTarget) }; return files; }; // Look for additional files registered for cleaning in this directory. if (cmValue prop_value = this->Makefile->GetProperty("ADDITIONAL_MAKE_CLEAN_FILES")) { - std::vector<std::string> const files = evaluatedFiles(*prop_value); + auto const files = evaluatedFiles(*prop_value); this->CleanFiles.insert(files.begin(), files.end()); } // Look for additional files registered for cleaning in this target. if (cmValue prop_value = this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) { - std::vector<std::string> const files = evaluatedFiles(*prop_value); + auto const files = evaluatedFiles(*prop_value); // For relative path support std::string const& binaryDir = this->LocalGenerator->GetCurrentBinaryDirectory(); @@ -416,8 +416,10 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() this->GlobalGenerator->SupportsCompilerDependencies() && (!this->Makefile->IsDefinitionSet(depsUseCompiler) || this->Makefile->IsOn(depsUseCompiler)); + bool linkerGenerateDeps = + this->GeneratorTarget->HasLinkDependencyFile(this->GetConfigName()); - if (compilerGenerateDeps || ccGenerateDeps) { + if (compilerGenerateDeps || linkerGenerateDeps || ccGenerateDeps) { std::string compilerDependFile = cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make"); *this->BuildFileStream << "# Include any dependencies generated by the " @@ -965,8 +967,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( bool const lang_has_assembly = lang_has_preprocessor; bool const lang_can_export_cmds = lang_has_preprocessor; - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->LocalGenerator->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->LocalGenerator->CreateRulePlaceholderExpander(); // Construct the compile rules. { @@ -1002,10 +1004,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( vars.CudaCompileMode = cudaCompileMode.c_str(); } - std::vector<std::string> compileCommands; + cmList compileCommands; const std::string& compileRule = this->Makefile->GetRequiredDefinition( "CMAKE_" + lang + "_COMPILE_OBJECT"); - cmExpandList(compileRule, compileCommands); + compileCommands.assign(compileRule); if (this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS") && lang_can_export_cmds && compileCommands.size() == 1) { @@ -1200,7 +1202,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // If compiler launcher was specified and not consumed above, it // goes to the beginning of the command line. if (!compileCommands.empty() && !compilerLauncher.empty()) { - std::vector<std::string> args = cmExpandedList(compilerLauncher, true); + cmList args{ compilerLauncher, cmList::EmptyElements::Yes }; if (!args.empty()) { args[0] = this->LocalGenerator->ConvertToOutputFormat( args[0], cmOutputConverter::SHELL); @@ -1208,7 +1210,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( i = this->LocalGenerator->EscapeForShell(i); } } - compileCommands.front().insert(0, cmJoin(args, " ") + " "); + compileCommands.front().insert(0, args.join(" ") + " "); } std::string launcher; @@ -1240,9 +1242,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( const auto& extraCommands = this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS")); if (!extraCommands.empty()) { - auto commandList = cmExpandedList(extraCommands); - compileCommands.insert(compileCommands.end(), commandList.cbegin(), - commandList.cend()); + compileCommands.append(extraCommands); } const auto& depFormat = this->Makefile->GetRequiredDefinition( @@ -1283,14 +1283,15 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } // Check for extra outputs created by the compilation. - std::vector<std::string> outputs(1, relativeObj); + cmList outputs; + outputs.emplace_back(relativeObj); if (cmValue extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) { std::string evaluated_outputs = cmGeneratorExpression::Evaluate( *extra_outputs_str, this->LocalGenerator, config); if (!evaluated_outputs.empty()) { // Register these as extra files to clean. - cmExpandList(evaluated_outputs, outputs); + outputs.append(evaluated_outputs); } } if (!ispcHeaderRelative.empty()) { @@ -1341,8 +1342,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmStrCat("CMAKE_", lang, "_CREATE_PREPROCESSED_SOURCE"); if (cmValue preprocessRule = this->Makefile->GetDefinition(preprocessRuleVar)) { - std::vector<std::string> preprocessCommands = - cmExpandedList(*preprocessRule); + cmList preprocessCommands{ *preprocessRule }; std::string shellObjI = this->LocalGenerator->ConvertToOutputFormat( objI, cmOutputConverter::SHELL); @@ -1386,8 +1386,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( cmStrCat("CMAKE_", lang, "_CREATE_ASSEMBLY_SOURCE"); if (cmValue assemblyRule = this->Makefile->GetDefinition(assemblyRuleVar)) { - std::vector<std::string> assemblyCommands = - cmExpandedList(*assemblyRule); + cmList assemblyCommands{ *assemblyRule }; std::string shellObjS = this->LocalGenerator->ConvertToOutputFormat( objS, cmOutputConverter::SHELL); @@ -1504,6 +1503,21 @@ bool cmMakefileTargetGenerator::WriteMakeRule( return symbolic; } +void cmMakefileTargetGenerator::WriteTargetLinkDependRules() +{ + if (!this->GeneratorTarget->HasLinkDependencyFile(this->GetConfigName())) { + return; + } + + auto depFile = this->LocalGenerator->GetLinkDependencyFile( + this->GeneratorTarget, this->GetConfigName()); + this->CleanFiles.insert(depFile); + this->LocalGenerator->AddImplicitDepends( + this->GeneratorTarget, "LINK", + this->GeneratorTarget->GetFullPath(this->GetConfigName()), depFile, + cmDependencyScannerKind::Compiler); +} + void cmMakefileTargetGenerator::WriteTargetDependRules() { // must write the targets depend info file @@ -1674,7 +1688,7 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( } cmLocalUnixMakefileGenerator3* localGen{ this->LocalGenerator }; - std::vector<std::string> architectures = cmExpandedList(architecturesStr); + cmList architectures{ architecturesStr }; std::string const& relPath = localGen->GetHomeRelativeOutputPath(); // Ensure there are no duplicates. @@ -1775,8 +1789,7 @@ void cmMakefileTargetGenerator::WriteDeviceLinkRule( vars.Flags = flags.c_str(); std::string compileCmd = this->GetLinkRule("CMAKE_CUDA_DEVICE_LINK_COMPILE"); - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - localGen->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = localGen->CreateRulePlaceholderExpander(); rulePlaceholderExpander->ExpandRuleVariables(localGen, compileCmd, vars); commands.emplace_back(compileCmd); @@ -2057,8 +2070,14 @@ void cmMakefileTargetGenerator::AppendTargetDepends( return; } - // Loop over all library dependencies. const std::string& cfg = this->GetConfigName(); + + if (this->GeneratorTarget->HasLinkDependencyFile(cfg)) { + depends.push_back( + cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")); + } + + // Loop over all library dependencies. if (cmComputeLinkInformation* cli = this->GeneratorTarget->GetLinkInformation(cfg)) { cm::append(depends, cli->GetDepends()); diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 98c3a0e8db..ef7a60fa62 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -77,6 +77,8 @@ protected: // write the clean rules for this target void WriteTargetCleanRules(); + // write the linker depend rules for this target + void WriteTargetLinkDependRules(); // write the depend rules for this target void WriteTargetDependRules(); diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index 52373f3160..baf40f8258 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -10,6 +10,7 @@ #include "cmConfigureLog.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmMessenger.h" @@ -31,13 +32,13 @@ enum class CheckingType std::string IndentText(std::string text, cmMakefile& mf) { auto indent = - cmJoin(cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT")), ""); + cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_INDENT") }.join(""); const auto showContext = mf.GetCMakeInstance()->GetShowLogContext() || mf.IsOn("CMAKE_MESSAGE_CONTEXT_SHOW"); if (showContext) { - auto context = cmJoin( - cmExpandedList(mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT")), "."); + auto context = + cmList{ mf.GetSafeDefinition("CMAKE_MESSAGE_CONTEXT") }.join("."); if (!context.empty()) { indent.insert(0u, cmStrCat("["_s, context, "] "_s)); } diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 4d68460521..063ca6ba6a 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -23,6 +23,7 @@ #include "cmGlobalNinjaGenerator.h" #include "cmLinkLineComputer.h" #include "cmLinkLineDeviceComputer.h" +#include "cmList.h" #include "cmLocalCommonGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" @@ -213,6 +214,22 @@ std::string cmNinjaNormalTargetGenerator::TextStubsGeneratorRule( '_', config); } +bool cmNinjaNormalTargetGenerator::CheckUseResponseFileForLibraries( + const std::string& l) const +{ + // Check for an explicit setting one way or the other. + std::string const responseVar = + "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES"; + + // If the option is defined, read it's value + if (cmValue val = this->Makefile->GetDefinition(responseVar)) { + return val.IsOn(); + } + + // Default to true + return true; +} + struct cmNinjaRemoveNoOpCommands { bool operator()(std::string const& cmd) @@ -251,9 +268,16 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule( } else { rule.RspContent = "$in_newline"; } - rule.RspContent += " $LINK_LIBRARIES"; + + // add the link command in the file if necessary + if (this->CheckUseResponseFileForLibraries("CUDA")) { + rule.RspContent += " $LINK_LIBRARIES"; + vars.LinkLibraries = ""; + } else { + vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES"; + } + vars.Objects = responseFlag.c_str(); - vars.LinkLibraries = ""; } vars.ObjectDir = "$OBJECT_DIR"; @@ -278,8 +302,8 @@ void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule( launcher = cmStrCat(val, ' '); } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->GetLocalGenerator()->CreateRulePlaceholderExpander(); // Rule for linking library/executable. std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd(); @@ -338,8 +362,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules( std::string compileCmd = this->GetMakefile()->GetRequiredDefinition( "CMAKE_CUDA_DEVICE_LINK_COMPILE"); - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->GetLocalGenerator()->CreateRulePlaceholderExpander(); rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), compileCmd, vars); @@ -393,6 +417,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, std::string cmakeVarLang = cmStrCat("CMAKE_", this->TargetLinkLanguage(config)); + if (this->GeneratorTarget->HasLinkDependencyFile(config)) { + auto DepFileFormat = this->GetMakefile()->GetDefinition( + cmStrCat(cmakeVarLang, "_LINKER_DEPFILE_FORMAT")); + rule.DepType = DepFileFormat; + rule.DepFile = "$DEP_FILE"; + } + // build response file name std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG"; cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar); @@ -416,13 +447,20 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, } else { rule.RspContent = "$in_newline"; } - rule.RspContent += " $LINK_PATH $LINK_LIBRARIES"; + + // If libraries in rsp is enable + if (this->CheckUseResponseFileForLibraries(lang)) { + rule.RspContent += " $LINK_PATH $LINK_LIBRARIES"; + vars.LinkLibraries = ""; + } else { + vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES"; + } + if (this->TargetLinkLanguage(config) == "Swift") { vars.SwiftSources = responseFlag.c_str(); } else { vars.Objects = responseFlag.c_str(); } - vars.LinkLibraries = ""; } vars.ObjectDir = "$OBJECT_DIR"; @@ -473,8 +511,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, launcher = cmStrCat(val, ' '); } - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->GetLocalGenerator()->CreateRulePlaceholderExpander(); // Rule for linking library/executable. std::vector<std::string> linkCmds = this->ComputeLinkCmd(config); @@ -546,8 +584,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, std::string cmd = this->GetMakefile()->GetDefinition("CMAKE_CREATE_TEXT_STUBS"); - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->GetLocalGenerator()->CreateRulePlaceholderExpander(); cmRulePlaceholderExpander::RuleVariables vars; vars.Target = "$in"; rulePlaceholderExpander->SetTargetImpLib("$out"); @@ -579,7 +617,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd() { - std::vector<std::string> linkCmds; + cmList linkCmds; // this target requires separable cuda compilation // now build the correct command depending on if the target is @@ -588,23 +626,23 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd() case cmStateEnums::STATIC_LIBRARY: case cmStateEnums::SHARED_LIBRARY: case cmStateEnums::MODULE_LIBRARY: { - this->GetMakefile()->GetDefExpandList("CMAKE_CUDA_DEVICE_LINK_LIBRARY", - linkCmds); + linkCmds.assign( + this->GetMakefile()->GetDefinition("CMAKE_CUDA_DEVICE_LINK_LIBRARY")); } break; case cmStateEnums::EXECUTABLE: { - this->GetMakefile()->GetDefExpandList( - "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE", linkCmds); + linkCmds.assign(this->GetMakefile()->GetDefinition( + "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE")); } break; default: break; } - return linkCmds; + return std::move(linkCmds.data()); } std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( const std::string& config) { - std::vector<std::string> linkCmds; + cmList linkCmds; cmMakefile* mf = this->GetMakefile(); { // If we have a rule variable prefer it. In the case of static libraries @@ -623,7 +661,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( linkCmdStr += *rule; } } - cmExpandList(linkCmdStr, linkCmds); + linkCmds.assign(linkCmdStr); if (this->UseLWYU) { cmValue lwyuCheck = mf->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK"); if (lwyuCheck) { @@ -642,7 +680,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( linkCmds.push_back(std::move(cmakeCommand)); } } - return linkCmds; + return std::move(linkCmds.data()); } } switch (this->GetGeneratorTarget()->GetType()) { @@ -663,7 +701,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( linkCmdVar, this->TargetLinkLanguage(config), config); std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar); - cmExpandList(linkCmd, linkCmds); + linkCmds.append(linkCmd); } { std::string linkCmdVar = cmStrCat( @@ -673,7 +711,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( linkCmdVar, this->TargetLinkLanguage(config), config); std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar); - cmExpandList(linkCmd, linkCmds); + linkCmds.append(linkCmd); } #ifdef __APPLE__ // On macOS ranlib truncates the fractional part of the static archive @@ -697,7 +735,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd( default: assert(false && "Unexpected target type"); } - return linkCmds; + return std::move(linkCmds.data()); } void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( @@ -754,7 +792,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( } this->WriteDeviceLinkRules(config); - this->WriteDeviceLinkStatements(config, cmExpandedList(architecturesStr), + this->WriteDeviceLinkStatements(config, cmList{ architecturesStr }, targetOutputReal); } else { this->WriteNvidiaDeviceLinkStatement(config, fileConfig, targetOutputDir, @@ -1103,6 +1141,14 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmNinjaBuild linkBuild(this->LanguageLinkerRule(config)); cmNinjaVars& vars = linkBuild.Variables; + if (this->GeneratorTarget->HasLinkDependencyFile(config)) { + vars["DEP_FILE"] = this->GetLocalGenerator()->ConvertToOutputFormat( + this->ConvertToNinjaPath( + this->GetLocalGenerator()->GetLinkDependencyFile(this->GeneratorTarget, + config)), + cmOutputConverter::SHELL); + } + // Compute the comment. linkBuild.Comment = cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', targetOutputReal); diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index 85f42a4487..187ea4627a 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -26,7 +26,7 @@ private: const std::string& config) const; std::string LanguageLinkerCudaFatbinaryRule(const std::string& config) const; std::string TextStubsGeneratorRule(const std::string& config) const; - + bool CheckUseResponseFileForLibraries(const std::string& config) const; const char* GetVisibleTypeName() const; void WriteLanguagesRules(const std::string& config); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 5dbc283fac..4ed491d33c 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -9,6 +9,7 @@ #include <iterator> #include <map> #include <ostream> +#include <type_traits> #include <unordered_map> #include <unordered_set> #include <utility> @@ -21,8 +22,6 @@ #include <cm3p/json/value.h> #include <cm3p/json/writer.h> -#include "cmsys/RegularExpression.hxx" - #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" #include "cmDyndepCollation.h" @@ -32,6 +31,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalCommonGenerator.h" #include "cmGlobalNinjaGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -665,8 +665,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, std::string const modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->GetLocalGenerator()->CreateRulePlaceholderExpander(); std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat( this->ConvertToNinjaPath(this->GetTargetDependInfoPath(lang, config)), @@ -689,7 +689,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, // Rule to scan dependencies of sources that need preprocessing. { - std::vector<std::string> scanCommands; + cmList scanCommands; std::string scanRuleName; std::string ppFileName; if (compilationPreprocesses) { @@ -697,8 +697,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, ppFileName = "$PREPROCESSED_OUTPUT_FILE"; std::string const& scanCommand = mf->GetRequiredDefinition( cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE")); - cmExpandList(scanCommand, scanCommands); - for (std::string& i : scanCommands) { + scanCommands.assign(scanCommand); + for (auto& i : scanCommands) { i = cmStrCat(launcher, i); } } else { @@ -706,8 +706,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, ppFileName = "$out"; std::string const& ppCommmand = mf->GetRequiredDefinition( cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE")); - cmExpandList(ppCommmand, scanCommands); - for (std::string& i : scanCommands) { + scanCommands.assign(ppCommmand); + for (auto& i : scanCommands) { i = cmStrCat(launcher, i); } scanCommands.emplace_back(GetScanCommand(cmakeCmd, tdi, lang, "$out", @@ -886,10 +886,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } // 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); + cmList compileCmds(compileCmd); // See if we need to use a compiler launcher like ccache or distcc std::string compilerLauncher; @@ -1038,7 +1037,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, // If compiler launcher was specified and not consumed above, it // goes to the beginning of the command line. if (!compileCmds.empty() && !compilerLauncher.empty()) { - std::vector<std::string> args = cmExpandedList(compilerLauncher, true); + cmList args{ compilerLauncher, cmList::EmptyElements::Yes }; if (!args.empty()) { args[0] = this->LocalGenerator->ConvertToOutputFormat( args[0], cmOutputConverter::SHELL); @@ -1046,7 +1045,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, i = this->LocalGenerator->EscapeForShell(i); } } - compileCmds.front().insert(0, cmStrCat(cmJoin(args, " "), ' ')); + compileCmds.front().insert(0, cmStrCat(args.join(" "), ' ')); } if (!compileCmds.empty()) { @@ -1056,12 +1055,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, const auto& extraCommands = this->GetMakefile()->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_DEPENDS_EXTRA_COMMANDS")); if (!extraCommands.empty()) { - auto commandList = cmExpandedList(extraCommands); - compileCmds.insert(compileCmds.end(), commandList.cbegin(), - commandList.cend()); + compileCmds.append(extraCommands); } - for (std::string& i : compileCmds) { + for (auto& i : compileCmds) { i = cmStrCat(launcher, i); rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i, vars); @@ -1261,7 +1258,6 @@ namespace { cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, const std::string& ppFileName, bool compilePP, bool compilePPWithDefines, - cmValue ppExcludeFlagsRegex, cmNinjaBuild& objBuild, cmNinjaVars& vars, const std::string& objectFileName, cmLocalGenerator* lg) @@ -1290,20 +1286,6 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, // Scanning and compilation generally use the same flags. scanBuild.Variables["FLAGS"] = vars["FLAGS"]; - // Exclude flags not valid during preprocessing. - if (compilePP && !ppExcludeFlagsRegex.IsEmpty()) { - std::string in = std::move(scanBuild.Variables["FLAGS"]); - std::string out; - cmsys::RegularExpression regex(*ppExcludeFlagsRegex); - std::string::size_type pos = 0; - while (regex.find(in.c_str() + pos)) { - out = cmStrCat(out, in.substr(pos, regex.start()), ' '); - pos += regex.end(); - } - out = cmStrCat(out, in.substr(pos)); - scanBuild.Variables["FLAGS"] = std::move(out); - } - if (compilePP && !compilePPWithDefines) { // Move preprocessor definitions to the scan/preprocessor build statement. std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]); @@ -1468,7 +1450,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } if (cmValue objectDeps = source->GetProperty("OBJECT_DEPENDS")) { - std::vector<std::string> objDepList = cmExpandedList(*objectDeps); + cmList objDepList{ *objectDeps }; std::copy(objDepList.begin(), objDepList.end(), std::back_inserter(depList)); } @@ -1528,22 +1510,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::string scanRuleName; std::string ppFileName; - cmValue ppExcludeFlagsRegex; if (compilePP) { scanRuleName = this->LanguagePreprocessAndScanRule(language, config); ppFileName = this->ConvertToNinjaPath( this->GetPreprocessedFilePath(source, config)); - ppExcludeFlagsRegex = this->Makefile->GetDefinition(cmStrCat( - "CMAKE_", language, "_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX")); } else { scanRuleName = this->LanguageScanRule(language, config); ppFileName = cmStrCat(objectFileName, ".ddi.i"); } cmNinjaBuild ppBuild = GetScanBuildStatement( - scanRuleName, ppFileName, compilePP, compilePPWithDefines, - ppExcludeFlagsRegex, objBuild, vars, objectFileName, - this->LocalGenerator); + scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild, + vars, objectFileName, this->LocalGenerator); if (compilePP) { // In case compilation requires flags that are incompatible with @@ -1688,7 +1666,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( if (!evaluatedObjectOutputs.empty()) { cmNinjaBuild build("phony"); build.Comment = "Additional output files."; - build.Outputs = cmExpandedList(evaluatedObjectOutputs); + build.Outputs = cmList{ evaluatedObjectOutputs }.data(); std::transform(build.Outputs.begin(), build.Outputs.end(), build.Outputs.begin(), this->MapToNinjaPath()); build.ExplicitDeps = objBuild.Outputs; @@ -1882,16 +1860,15 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( compileObjectVars.CudaCompileMode = cudaCompileMode.c_str(); } - std::vector<std::string> compileCmds; const std::string cmdVar = cmStrCat("CMAKE_", language, "_COMPILE_OBJECT"); const std::string& compileCmd = this->Makefile->GetRequiredDefinition(cmdVar); - cmExpandList(compileCmd, compileCmds); + cmList compileCmds(compileCmd); - std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander( - this->GetLocalGenerator()->CreateRulePlaceholderExpander()); + auto rulePlaceholderExpander = + this->GetLocalGenerator()->CreateRulePlaceholderExpander(); - for (std::string& i : compileCmds) { + for (auto& i : compileCmds) { // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), i, compileObjectVars); @@ -1909,13 +1886,11 @@ void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config) if (cmValue prop_value = this->GeneratorTarget->GetProperty("ADDITIONAL_CLEAN_FILES")) { cmLocalNinjaGenerator* lg = this->LocalGenerator; - std::vector<std::string> cleanFiles; - cmExpandList(cmGeneratorExpression::Evaluate(*prop_value, lg, config, - this->GeneratorTarget), - cleanFiles); + cmList cleanFiles(cmGeneratorExpression::Evaluate(*prop_value, lg, config, + this->GeneratorTarget)); std::string const& binaryDir = lg->GetCurrentBinaryDirectory(); cmGlobalNinjaGenerator* gg = lg->GetGlobalNinjaGenerator(); - for (std::string const& cleanFile : cleanFiles) { + for (auto const& cleanFile : cleanFiles) { // Support relative paths gg->AddAdditionalCleanFile( cmSystemTools::CollapseFullPath(cleanFile, binaryDir), config); diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 6c54e01e3d..53cb21e59d 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -6,16 +6,15 @@ #include <cassert> #include <cctype> #include <set> -#include <vector> #ifdef _WIN32 # include <unordered_map> # include <utility> #endif +#include "cmList.h" #include "cmState.h" #include "cmStateDirectory.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" @@ -176,7 +175,12 @@ std::string cmOutputConverter::ConvertToOutputForExisting( } std::string tmp{}; - cmSystemTools::GetShortPath(remote, tmp); + cmsys::Status status = cmSystemTools::GetShortPath(remote, tmp); + if (!status) { + // Fallback for cases when Windows refuses to resolve the short path, + // like for C:\Program Files\WindowsApps\... + tmp = remote; + } shortPathCache[remote] = tmp; return tmp; }(); @@ -319,7 +323,7 @@ cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat( { FortranFormat format = FortranFormatNone; if (!value.empty()) { - for (std::string const& fi : cmExpandedList(value)) { + for (std::string const& fi : cmList(value)) { if (fi == "FIXED") { format = FortranFormatFixed; } diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index 2717bdd1c2..625d89768c 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -16,6 +16,7 @@ class cmOutputConverter { public: cmOutputConverter(cmStateSnapshot const& snapshot); + virtual ~cmOutputConverter() = default; /** * Convert the given remote path to a relative path with respect to @@ -27,6 +28,15 @@ public: std::string MaybeRelativeToTopBinDir(std::string const& path) const; std::string MaybeRelativeToCurBinDir(std::string const& path) const; + /** + * The effective working directory can be different for each generator. + * By default, equivalent to the current binary directory. + */ + virtual std::string MaybeRelativeToWorkDir(std::string const& path) const + { + return this->MaybeRelativeToCurBinDir(path); + } + std::string const& GetRelativePathTopSource() const; std::string const& GetRelativePathTopBinary() const; void SetRelativePathTop(std::string const& topSource, diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx index ad276d2f70..f147ed22de 100644 --- a/Source/cmOutputRequiredFilesCommand.cxx +++ b/Source/cmOutputRequiredFilesCommand.cxx @@ -14,6 +14,7 @@ #include "cmExecutionStatus.h" #include "cmGeneratorExpression.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmSourceFile.h" #include "cmStringAlgorithms.h" @@ -126,9 +127,9 @@ public: std::string incDirs = cmGeneratorExpression::Preprocess( *incDirProp, cmGeneratorExpression::StripAllGeneratorExpressions); - std::vector<std::string> includes = cmExpandedList(incDirs); + cmList includes{ incDirs }; - for (std::string& path : includes) { + for (auto& path : includes) { this->Makefile->ExpandVariablesInString(path); if (uniqueIncludes.insert(path).second) { orderedAndUniqueIncludes.push_back(path); diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 7e195664e2..b0462f056a 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -12,6 +12,7 @@ #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" @@ -169,17 +170,15 @@ bool cmParseArgumentsCommand(std::vector<std::string> const& args, }; // the second argument is a (cmake) list of options without argument - std::vector<std::string> list = cmExpandedList(*argIter++); + cmList list{ *argIter++ }; parser.Bind(list, options, duplicateKey); // the third argument is a (cmake) list of single argument options - list.clear(); - cmExpandList(*argIter++, list); + list.assign(*argIter++); parser.Bind(list, singleValArgs, duplicateKey); // the fourth argument is a (cmake) list of multi argument options - list.clear(); - cmExpandList(*argIter++, list); + list.assign(*argIter++); parser.Bind(list, multiValArgs, duplicateKey); list.clear(); @@ -187,7 +186,7 @@ bool cmParseArgumentsCommand(std::vector<std::string> const& args, // Flatten ;-lists in the arguments into a single list as was done // by the original function(CMAKE_PARSE_ARGUMENTS). for (; argIter != argEnd; ++argIter) { - cmExpandList(*argIter, list); + list.append(*argIter); } } else { // in the PARSE_ARGV move read the arguments from ARGC and ARGV# diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index fe883826aa..a0030d3dc1 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -450,7 +450,16 @@ class cmMakefile; 27, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0149, \ "Visual Studio generators select latest Windows SDK by default.", 3, \ - 27, 0, cmPolicies::WARN) + 27, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0150, \ + "ExternalProject_Add and FetchContent_Declare commands " \ + "treat relative GIT_REPOSITORY paths as being relative " \ + "to the parent project's remote.", \ + 3, 27, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0151, \ + "AUTOMOC include directory is a system include directory by " \ + "default.", \ + 3, 27, 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/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 782c154653..d897f0e5be 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -35,6 +35,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLinkItem.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -507,7 +508,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() std::string const& deps = this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); if (!deps.empty()) { - for (std::string const& depName : cmExpandedList(deps)) { + for (auto const& depName : cmList{ deps }) { // Allow target and file dependencies auto* depTarget = this->Makefile->FindTargetToUse(depName); if (depTarget) { @@ -545,8 +546,8 @@ bool cmQtAutoGenInitializer::InitCustomTargets() this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames), this->Moc.MacroNames.end()); { - auto filterList = cmExpandedList( - this->GenTarget->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); + cmList filterList = { this->GenTarget->GetSafeProperty( + "AUTOMOC_DEPEND_FILTERS") }; if ((filterList.size() % 2) != 0) { cmSystemTools::Error( cmStrCat("AutoMoc: AUTOMOC_DEPEND_FILTERS predefs size ", @@ -558,7 +559,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() "Q_PLUGIN_METADATA", "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\(" "[^\\)]*FILE[ \t]*\"([^\"]+)\""); - for (std::size_t ii = 0; ii != filterList.size(); ii += 2) { + for (cmList::size_type ii = 0; ii != filterList.size(); ii += 2) { this->Moc.DependFilters.emplace_back(filterList[ii], filterList[ii + 1]); } @@ -573,7 +574,31 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Add autogen include directory to the origin target INCLUDE_DIRECTORIES if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) { - this->GenTarget->AddIncludeDirectory(this->Dir.IncludeGenExp, true); + auto addBefore = false; + auto const& value = + this->GenTarget->GetProperty("AUTOGEN_USE_SYSTEM_INCLUDE"); + if (value.IsSet()) { + if (cmIsOn(value)) { + this->GenTarget->AddSystemIncludeDirectory(this->Dir.IncludeGenExp, + "CXX"); + } else { + addBefore = true; + } + } else { + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0151)) { + case cmPolicies::WARN: + case cmPolicies::OLD: + addBefore = true; + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + this->GenTarget->AddSystemIncludeDirectory(this->Dir.IncludeGenExp, + "CXX"); + break; + } + } + this->GenTarget->AddIncludeDirectory(this->Dir.IncludeGenExp, addBefore); } // Scan files @@ -613,8 +638,9 @@ bool cmQtAutoGenInitializer::InitMoc() if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && (this->QtVersion >= IntegerVersion(5, 8))) { // Command - this->Makefile->GetDefExpandList("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND", - this->Moc.PredefsCmd); + cmList::assign( + this->Moc.PredefsCmd, + this->Makefile->GetDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); // Header if (!this->Moc.PredefsCmd.empty()) { this->ConfigFileNames(this->Moc.PredefsFile, @@ -701,7 +727,7 @@ bool cmQtAutoGenInitializer::InitUic() this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS"); if (!usp.empty()) { this->Uic.SearchPaths = - SearchPathSanitizer(this->Makefile)(cmExpandedList(usp)); + SearchPathSanitizer(this->Makefile)(cmList{ usp }); } } // Uic target options @@ -961,8 +987,8 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (uicOpts.empty()) { this->Uic.UiFilesNoOptions.emplace_back(fullPath); } else { - this->Uic.UiFilesWithOptions.emplace_back(fullPath, - cmExpandedList(uicOpts)); + this->Uic.UiFilesWithOptions.emplace_back( + fullPath, std::move(cmList{ uicOpts }.data())); } auto uiHeaderRelativePath = cmSystemTools::RelativePath( @@ -1063,8 +1089,8 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (!this->Rcc.Qrcs.empty()) { const bool modernQt = (this->QtVersion.Major >= 5); // Target rcc options - std::vector<std::string> optionsTarget = - cmExpandedList(this->GenTarget->GetSafeProperty(kw.AUTORCC_OPTIONS)); + cmList optionsTarget{ this->GenTarget->GetSafeProperty( + kw.AUTORCC_OPTIONS) }; // Check if file name is unique for (Qrc& qrc : this->Rcc.Qrcs) { diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx index 8af13ae2b4..65a2268bc8 100644 --- a/Source/cmRemoveCommand.cxx +++ b/Source/cmRemoveCommand.cxx @@ -3,8 +3,8 @@ #include "cmRemoveCommand.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" -#include "cmStringAlgorithms.h" #include "cmValue.h" // cmRemoveCommand @@ -25,12 +25,11 @@ bool cmRemoveCommand(std::vector<std::string> const& args, } // expand the variable - std::vector<std::string> const varArgsExpanded = cmExpandedList(*cacheValue); + cmList const varArgsExpanded{ *cacheValue }; // expand the args // check for REMOVE(VAR v1 v2 ... vn) - std::vector<std::string> const argsExpanded = - cmExpandedLists(args.begin() + 1, args.end()); + cmList const argsExpanded{ args.begin() + 1, args.end() }; // now create the new value std::string value; diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx index 4dfdfae4f9..2fbf2fa04c 100644 --- a/Source/cmRuntimeDependencyArchive.cxx +++ b/Source/cmRuntimeDependencyArchive.cxx @@ -3,13 +3,21 @@ #include "cmRuntimeDependencyArchive.h" +#include <algorithm> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#include <cm/memory> + #include "cmBinUtilsLinuxELFLinker.h" #include "cmBinUtilsMacOSMachOLinker.h" #include "cmBinUtilsWindowsPELinker.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmStateTypes.h" -#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #if defined(_WIN32) @@ -22,14 +30,6 @@ # include "cmVSSetupHelper.h" #endif -#include <algorithm> -#include <sstream> -#include <string> -#include <utility> -#include <vector> - -#include <cm/memory> - #if defined(_WIN32) static void AddVisualStudioPath(std::vector<std::string>& paths, const std::string& prefix, diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index d5f6f0dc21..2b992ef285 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -9,6 +9,7 @@ #include <cm/optional> #include "cmFindCommon.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -71,7 +72,7 @@ void cmSearchPath::AddCMakePath(const std::string& variable) // Get a path from a CMake variable. if (cmValue value = this->FC->Makefile->GetDefinition(variable)) { - std::vector<std::string> expanded = cmExpandedList(*value); + cmList expanded{ *value }; for (std::string const& p : expanded) { this->AddPathInternal( @@ -95,7 +96,7 @@ void cmSearchPath::AddCMakePrefixPath(const std::string& variable) // Get a path from a CMake variable. if (cmValue value = this->FC->Makefile->GetDefinition(variable)) { - std::vector<std::string> expanded = cmExpandedList(*value); + cmList expanded{ *value }; this->AddPrefixPaths( expanded, this->FC->Makefile->GetCurrentSourceDirectory().c_str()); diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index d2eac0cd7b..f6e8bc6f34 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -18,6 +18,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -349,7 +350,7 @@ struct StandardLevelComputer for (size_t i = 0; i < this->Levels.size(); ++i) { if (cmValue prop = makefile->GetDefinition( cmStrCat(prefix, this->LevelsAsStrings[i], "_COMPILE_FEATURES"))) { - std::vector<std::string> props = cmExpandedList(*prop); + cmList props{ *prop }; if (cm::contains(props, feature)) { maxLevel = { static_cast<int>(i), this->Levels[i] }; } @@ -468,7 +469,7 @@ bool cmStandardLevelResolver::CheckCompileFeaturesAvailable( return false; } - std::vector<std::string> availableFeatures = cmExpandedList(features); + cmList availableFeatures{ features }; if (!cm::contains(availableFeatures, feature)) { std::ostringstream e; e << "The compiler feature \"" << feature << "\" is not known to " << lang diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index 66bf383941..e352d8dd22 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -80,77 +80,6 @@ std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep) return tokens; } -void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut, - bool emptyArgs) -{ - // If argument is empty, it is an empty list. - if (!emptyArgs && arg.empty()) { - return; - } - - // if there are no ; in the name then just copy the current string - if (arg.find(';') == cm::string_view::npos) { - argsOut.emplace_back(arg); - return; - } - - std::string newArg; - // Break the string at non-escaped semicolons not nested in []. - int squareNesting = 0; - cm::string_view::iterator last = arg.begin(); - cm::string_view::iterator const cend = arg.end(); - for (cm::string_view::iterator c = last; c != cend; ++c) { - switch (*c) { - case '\\': { - // We only want to allow escaping of semicolons. Other - // escapes should not be processed here. - cm::string_view::iterator cnext = c + 1; - if ((cnext != cend) && *cnext == ';') { - newArg.append(last, c); - // Skip over the escape character - last = cnext; - c = cnext; - } - } break; - case '[': { - ++squareNesting; - } break; - case ']': { - --squareNesting; - } break; - case ';': { - // Break the string here if we are not nested inside square - // brackets. - if (squareNesting == 0) { - newArg.append(last, c); - // Skip over the semicolon - last = c + 1; - if (!newArg.empty() || emptyArgs) { - // Add the last argument if the string is not empty. - argsOut.push_back(newArg); - newArg.clear(); - } - } - } break; - default: { - // Just append this character. - } break; - } - } - newArg.append(last, cend); - if (!newArg.empty() || emptyArgs) { - // Add the last argument if the string is not empty. - argsOut.push_back(std::move(newArg)); - } -} - -std::vector<std::string> cmExpandedList(cm::string_view arg, bool emptyArgs) -{ - std::vector<std::string> argsOut; - cmExpandList(arg, argsOut, emptyArgs); - return argsOut; -} - namespace { template <std::size_t N, typename T> inline void MakeDigits(cm::string_view& view, char (&digits)[N], diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 9ea74919f6..4a9840b166 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -88,63 +88,6 @@ std::string cmJoin(cmStringRange const& rng, cm::string_view separator, /** Extract tokens that are separated by any of the characters in @a sep. */ std::vector<std::string> cmTokenize(cm::string_view str, cm::string_view sep); -/** - * Expand the ; separated string @a arg into multiple arguments. - * All found arguments are appended to @a argsOut. - */ -void cmExpandList(cm::string_view arg, std::vector<std::string>& argsOut, - bool emptyArgs = false); -inline void cmExpandList(cmValue arg, std::vector<std::string>& argsOut, - bool emptyArgs = false) -{ - if (arg) { - cmExpandList(*arg, argsOut, emptyArgs); - } -} - -/** - * Expand out any arguments in the string range [@a first, @a last) that have - * ; separated strings into multiple arguments. All found arguments are - * appended to @a argsOut. - */ -template <class InputIt> -void cmExpandLists(InputIt first, InputIt last, - std::vector<std::string>& argsOut) -{ - for (; first != last; ++first) { - cmExpandList(*first, argsOut); - } -} - -/** - * Same as cmExpandList but a new vector is created containing - * the expanded arguments from the string @a arg. - */ -std::vector<std::string> cmExpandedList(cm::string_view arg, - bool emptyArgs = false); -inline std::vector<std::string> cmExpandedList(cmValue arg, - bool emptyArgs = false) -{ - if (!arg) { - return {}; - } - return cmExpandedList(*arg, emptyArgs); -} - -/** - * Same as cmExpandList but a new vector is created containing the expanded - * versions of all arguments in the string range [@a first, @a last). - */ -template <class InputIt> -std::vector<std::string> cmExpandedLists(InputIt first, InputIt last) -{ - std::vector<std::string> argsOut; - for (; first != last; ++first) { - cmExpandList(*first, argsOut); - } - return argsOut; -} - /** Concatenate string pieces into a single string. */ std::string cmCatViews( std::initializer_list<std::pair<cm::string_view, std::string*>> views); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 5e558714e2..0fbe430140 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -23,6 +23,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -92,7 +93,7 @@ cmValue cmTargetPropertyComputer::GetSources<cmTarget>(cmTarget const* tgt, std::ostringstream ss; const char* sep = ""; for (auto const& entry : entries) { - std::vector<std::string> files = cmExpandedList(entry.Value); + cmList files{ entry.Value }; for (std::string const& file : files) { if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") && file.back() == '>') { @@ -396,6 +397,10 @@ TargetProperty const StaticTargetProperties[] = { { "MSVC_DEBUG_INFORMATION_FORMAT"_s, IC::CanCompileSources }, { "MSVC_RUNTIME_LIBRARY"_s, IC::CanCompileSources }, { "VS_JUST_MY_CODE_DEBUGGING"_s, IC::CanCompileSources }, + { "VS_DEBUGGER_COMMAND"_s, IC::ExecutableTarget }, + { "VS_DEBUGGER_COMMAND_ARGUMENTS"_s, IC::ExecutableTarget }, + { "VS_DEBUGGER_ENVIRONMENT"_s, IC::ExecutableTarget }, + { "VS_DEBUGGER_WORKING_DIRECTORY"_s, IC::ExecutableTarget }, // ---- OpenWatcom { "WATCOM_RUNTIME_LIBRARY"_s, IC::CanCompileSources }, // -- Language @@ -545,6 +550,7 @@ TargetProperty const StaticTargetProperties[] = { // -- Autogen { "AUTOGEN_ORIGIN_DEPENDS"_s, IC::CanCompileSources }, { "AUTOGEN_PARALLEL"_s, IC::CanCompileSources }, + { "AUTOGEN_USE_SYSTEM_INCLUDE"_s, IC::CanCompileSources }, // -- moc { "AUTOMOC_DEPEND_FILTERS"_s, IC::CanCompileSources }, // -- C++ @@ -1115,7 +1121,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, if (globals) { const std::string genName = mf->GetGlobalGenerator()->GetName(); if (cmHasLiteralPrefix(genName, "Visual Studio")) { - std::vector<std::string> props = cmExpandedList(*globals); + cmList props{ *globals }; const std::string vsGlobal = "VS_GLOBAL_"; for (const std::string& i : props) { // split NAME=VALUE @@ -1428,7 +1434,7 @@ public: bool operator()(BT<std::string> const& entry) { - std::vector<std::string> files = cmExpandedList(entry.Value); + cmList files{ entry.Value }; std::vector<cmSourceFileLocation> locations; locations.reserve(files.size()); std::transform(files.begin(), files.end(), std::back_inserter(locations), @@ -2967,7 +2973,7 @@ std::vector<std::string> cmTarget::GetAllInterfaceFileSets() const auto appendEntries = [=](const std::vector<BT<std::string>>& entries) { for (auto const& entry : entries) { - auto expanded = cmExpandedList(entry.Value); + cmList expanded{ entry.Value }; std::copy(expanded.begin(), expanded.end(), inserter); } }; @@ -3029,11 +3035,11 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, cmValue& loc, // Track the configuration-specific property suffix. suffix = cmStrCat('_', config_upper); - std::vector<std::string> mappedConfigs; + cmList mappedConfigs; { std::string mapProp = cmStrCat("MAP_IMPORTED_CONFIG_", config_upper); if (cmValue mapValue = this->GetProperty(mapProp)) { - cmExpandList(*mapValue, mappedConfigs, true); + mappedConfigs.assign(*mapValue, cmList::EmptyElements::Yes); } } @@ -3115,9 +3121,9 @@ bool cmTarget::GetMappedConfig(std::string const& desired_config, cmValue& loc, // If we have not yet found it then the project is willing to try // any available configuration. if (!loc && !imp) { - std::vector<std::string> availableConfigs; + cmList availableConfigs; if (cmValue iconfigs = this->GetProperty("IMPORTED_CONFIGURATIONS")) { - cmExpandList(*iconfigs, availableConfigs); + availableConfigs.assign(*iconfigs); } for (auto aci = availableConfigs.begin(); !loc && !imp && aci != availableConfigs.end(); ++aci) { diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index 53e25b5d3f..cd7ff7419d 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -13,6 +13,7 @@ #include "cmExperimental.h" #include "cmFileSet.h" #include "cmGeneratorExpression.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" @@ -320,7 +321,7 @@ bool TargetSourcesImpl::HandleOneFileSet( fileSet.first->AddDirectoryEntry( BT<std::string>(baseDirectories, this->Makefile->GetBacktrace())); if (type == "HEADERS"_s || type == "CXX_MODULE_HEADER_UNITS"_s) { - for (auto const& dir : cmExpandedList(baseDirectories)) { + for (auto const& dir : cmList{ baseDirectories }) { auto interfaceDirectoriesGenex = cmStrCat("$<BUILD_INTERFACE:", dir, ">"); if (cmFileSetVisibilityIsForSelf(visibility)) { diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index 5e325dd221..c4a2bc220d 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -13,6 +13,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -147,16 +148,15 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, } // Evaluate command line arguments - std::vector<std::string> argv = - this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config); - - // Expand arguments if COMMAND_EXPAND_LISTS is set - if (this->Test->GetCommandExpandLists()) { - argv = cmExpandedLists(argv.begin(), argv.end()); - // Expanding lists on an empty command may have left it empty - if (argv.empty()) { - argv.emplace_back(); - } + cmList argv{ + this->EvaluateCommandLineArguments(this->Test->GetCommand(), ge, config), + // Expand arguments if COMMAND_EXPAND_LISTS is set + this->Test->GetCommandExpandLists() ? cmList::ExpandElements::Yes + : cmList::ExpandElements::No + }; + // Expanding lists on an empty command may have left it empty + if (argv.empty()) { + argv.emplace_back(); } // Check whether the command executable is a target whose name is to @@ -170,7 +170,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, // Prepend with the emulator when cross compiling if required. cmValue emulator = target->GetProperty("CROSSCOMPILING_EMULATOR"); if (cmNonempty(emulator)) { - std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator); + cmList emulatorWithArgs{ *emulator }; std::string emulatorExe(emulatorWithArgs[0]); cmSystemTools::ConvertToUnixSlashes(emulatorExe); os << cmOutputConverter::EscapeForCMake(emulatorExe) << " "; diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index b648d9b94f..368155c346 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -15,6 +15,7 @@ #include "cmCoreTryCompile.h" #include "cmDuration.h" #include "cmExecutionStatus.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" @@ -271,7 +272,7 @@ void TryRunCommandImpl::RunExecutable(const std::string& runArgs, const std::string& emulator = this->Makefile->GetSafeDefinition("CMAKE_CROSSCOMPILING_EMULATOR"); if (!emulator.empty()) { - std::vector<std::string> emulatorWithArgs = cmExpandedList(emulator); + cmList emulatorWithArgs{ emulator }; finalCommand += cmSystemTools::ConvertToRunCommandPath(emulatorWithArgs[0]); finalCommand += " "; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 8926f9ed15..7360bf5d75 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -9,6 +9,7 @@ #include <set> #include <sstream> +#include <cm/filesystem> #include <cm/memory> #include <cm/optional> #include <cm/string_view> @@ -31,6 +32,7 @@ #include "cmGlobalVisualStudio7Generator.h" #include "cmGlobalVisualStudioGenerator.h" #include "cmLinkLineDeviceComputer.h" +#include "cmList.h" #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalVisualStudio10Generator.h" @@ -50,6 +52,8 @@ #include "cmValue.h" #include "cmVisualStudioGeneratorOptions.h" +const std::string kBuildSystemSources = "Buildsystem Input Files"; + struct cmIDEFlagTable; static void ConvertToWindowsSlash(std::string& s); @@ -1090,10 +1094,10 @@ void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0) void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0) { - std::vector<std::string> references; + cmList references; if (cmValue vsDotNetReferences = this->GeneratorTarget->GetProperty("VS_DOTNET_REFERENCES")) { - cmExpandList(*vsDotNetReferences, references); + references.assign(*vsDotNetReferences); } cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties(); for (auto const& i : props.GetList()) { @@ -1110,7 +1114,7 @@ void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0) } if (!references.empty() || !this->DotNetHintReferences.empty()) { Elem e1(e0, "ItemGroup"); - for (std::string const& ri : references) { + for (auto const& ri : references) { // if the entry from VS_DOTNET_REFERENCES is an existing file, generate // a new hint-reference and name it from the filename if (cmsys::SystemTools::FileExists(ri, true)) { @@ -1167,7 +1171,7 @@ void cmVisualStudio10TargetGenerator::WriteImports(Elem& e0) cmValue imports = this->GeneratorTarget->Target->GetProperty("VS_PROJECT_IMPORT"); if (imports) { - std::vector<std::string> argsSplit = cmExpandedList(*imports, false); + cmList argsSplit{ *imports }; for (auto& path : argsSplit) { if (!cmsys::SystemTools::FileIsFullPath(path)) { path = this->Makefile->GetCurrentSourceDirectory() + "/" + path; @@ -1365,20 +1369,20 @@ void cmVisualStudio10TargetGenerator::WriteTargetsFileReferences(Elem& e1) void cmVisualStudio10TargetGenerator::WriteWinRTReferences(Elem& e0) { - std::vector<std::string> references; + cmList references; if (cmValue vsWinRTReferences = this->GeneratorTarget->GetProperty("VS_WINRT_REFERENCES")) { - cmExpandList(*vsWinRTReferences, references); + references.assign(*vsWinRTReferences); } if (this->GlobalGenerator->TargetsWindowsPhone() && this->GlobalGenerator->GetSystemVersion() == "8.0" && references.empty()) { - references.push_back("platform.winmd"); + references.push_back(std::string{ "platform.winmd" }); } if (!references.empty()) { Elem e1(e0, "ItemGroup"); - for (std::string const& ri : references) { + for (auto const& ri : references) { Elem e2(e1, "Reference"); e2.Attribute("Include", ri); e2.Element("IsWinMDFile", "true"); @@ -1949,7 +1953,13 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "http://schemas.microsoft.com/developer/msbuild/2003"); for (auto const& ti : this->Tools) { - this->WriteGroupSources(e0, ti.first, ti.second, sourceGroups); + if ((this->GeneratorTarget->GetName() == + CMAKE_CHECK_BUILD_SYSTEM_TARGET) && + (ti.first == "None")) { + this->WriteBuildSystemSources(e0, ti.first, ti.second); + } else { + this->WriteGroupSources(e0, ti.first, ti.second, sourceGroups); + } } // Added files are images and the manifest. @@ -2020,6 +2030,18 @@ void cmVisualStudio10TargetGenerator::WriteGroups() "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;" "gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms"); } + + if (this->GeneratorTarget->GetName() == + CMAKE_CHECK_BUILD_SYSTEM_TARGET) { + for (const std::string& filter : this->BuildSystemSourcesFilters) { + std::string guidName = "SG_Filter_"; + guidName += filter; + std::string guid = this->GlobalGenerator->GetGUID(guidName); + Elem e2(e1, "Filter"); + e2.Attribute("Include", filter); + e2.Element("UniqueIdentifier", "{" + guid + "}"); + } + } } } fout << '\n'; @@ -2086,6 +2108,39 @@ void cmVisualStudio10TargetGenerator::WriteGroupSources( } } +void cmVisualStudio10TargetGenerator::WriteBuildSystemSources( + Elem& e0, std::string const& name, ToolSources const& sources) +{ + const std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); + const std::string::size_type srcDirLength = srcDir.length(); + + Elem e1(e0, "ItemGroup"); + e1.SetHasElements(); + for (ToolSource const& s : sources) { + cmSourceFile const* sf = s.SourceFile; + std::string const& source = sf->GetFullPath(); + + cm::filesystem::path sourcePath(source); + bool isInSrcDir = cmHasPrefix(source, srcDir); + + std::string filter = kBuildSystemSources; + if (isInSrcDir) { + std::string parentPath = sourcePath.parent_path().string(); + if (srcDir != parentPath) { + filter += parentPath.substr(srcDirLength); + } + ConvertToWindowsSlash(filter); + this->BuildSystemSourcesFilters.insert(filter); + } + + std::string path = this->ConvertPath(source, s.RelativePath); + ConvertToWindowsSlash(path); + Elem e2(e1, name); + e2.Attribute("Include", path); + e2.Element("Filter", filter); + } +} + void cmVisualStudio10TargetGenerator::WriteHeaderSource( Elem& e1, cmSourceFile const* sf, ConfigToSettings const& toolSettings) { @@ -2113,8 +2168,8 @@ void cmVisualStudio10TargetGenerator::ParseSettingsProperty( for (const std::string& config : this->Configurations) { std::string evaluated = cge->Evaluate(this->LocalGenerator, config); - std::vector<std::string> settings = cmExpandedList(evaluated); - for (const std::string& setting : settings) { + cmList settings{ evaluated }; + for (const auto& setting : settings) { const std::string::size_type assignment = setting.find('='); if (assignment != std::string::npos) { const std::string propName = setting.substr(0, assignment); @@ -2714,16 +2769,11 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( 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) { + cmList depends{ *objectDeps }; + for (auto& d : depends) { ConvertToWindowsSlash(d); - dependencies += sep; - dependencies += d; - sep = ";"; } - e2.Element("AdditionalDependencies", dependencies); + e2.Element("AdditionalDependencies", depends.join(";")); } } @@ -4767,13 +4817,13 @@ void cmVisualStudio10TargetGenerator::WriteSinglePlatformExtension( void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0) { - std::vector<std::string> sdkReferences; + cmList sdkReferences; std::unique_ptr<Elem> spe1; if (cmValue vsSDKReferences = this->GeneratorTarget->GetProperty("VS_SDK_REFERENCES")) { - cmExpandList(*vsSDKReferences, sdkReferences); + sdkReferences.assign(*vsSDKReferences); spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); - for (std::string const& ri : sdkReferences) { + for (auto const& ri : sdkReferences) { Elem(*spe1, "SDKReference").Attribute("Include", ri); } } diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 97ae69fc37..a87cb01b7e 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -193,6 +193,9 @@ private: void WriteGroupSources(Elem& e0, std::string const& name, ToolSources const& sources, std::vector<cmSourceGroup>&); + void WriteBuildSystemSources(Elem& e0, std::string const& name, + ToolSources const& sources); + void AddMissingSourceGroups(std::set<cmSourceGroup const*>& groupsUsed, const std::vector<cmSourceGroup>& allGroups); bool IsResxHeader(const std::string& headerFile); @@ -243,6 +246,7 @@ private: std::set<std::string> ASanEnabledConfigurations; std::set<std::string> FuzzerEnabledConfigurations; std::map<std::string, std::string> SpectreMitigation; + std::set<std::string> BuildSystemSourcesFilters; cmGlobalVisualStudio10Generator* const GlobalGenerator; cmLocalVisualStudio10Generator* const LocalGenerator; std::set<std::string> CSharpCustomCommandNames; diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx index e727d22141..7f26fd8b23 100644 --- a/Source/cmXCodeScheme.cxx +++ b/Source/cmXCodeScheme.cxx @@ -13,6 +13,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmList.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -270,7 +271,7 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, if (cmValue argList = this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ARGUMENTS")) { - std::vector<std::string> arguments = cmExpandedList(*argList); + cmList arguments{ *argList }; if (!arguments.empty()) { xout.StartElement("CommandLineArguments"); @@ -290,7 +291,7 @@ void cmXCodeScheme::WriteLaunchAction(cmXMLWriter& xout, if (cmValue envList = this->Target->GetTarget()->GetProperty("XCODE_SCHEME_ENVIRONMENT")) { - std::vector<std::string> envs = cmExpandedList(*envList); + cmList envs{ *envList }; if (!envs.empty()) { xout.StartElement("EnvironmentVariables"); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 8dee5cc13c..0fd7461339 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -53,6 +53,7 @@ # include "cmMakefileProfilingData.h" #endif #include "cmJSONState.h" +#include "cmList.h" #include "cmMessenger.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -813,7 +814,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) } } else if (mode == "COMPILE"_s) { std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS"); - std::vector<std::string> includeDirs = cmExpandedList(includes); + cmList includeDirs{ includes }; this->GlobalGenerator->CreateGenerationObjects(); const auto& lg = this->GlobalGenerator->LocalGenerators[0]; @@ -829,7 +830,7 @@ bool cmake::FindPackage(const std::vector<std::string>& args) tgt->SetProperty("LINKER_LANGUAGE", language); std::string libs = mf->GetSafeDefinition("PACKAGE_LIBRARIES"); - std::vector<std::string> libList = cmExpandedList(libs); + cmList libList{ libs }; for (std::string const& lib : libList) { tgt->AddLinkLibrary(*mf, lib, GENERAL_LibraryType); } @@ -1026,7 +1027,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) CommandArgument{ "--check-build-system", CommandArgument::Values::Two, [](std::string const& value, cmake* state) -> bool { - std::vector<std::string> values = cmExpandedList(value); + cmList values{ value }; state->CheckBuildSystemArgument = values[0]; state->ClearBuildSystem = (atoi(values[1].c_str()) > 0); return true; @@ -2163,7 +2164,7 @@ struct SaveCacheEntry int cmake::HandleDeleteCacheVariables(const std::string& var) { - std::vector<std::string> argsSplit = cmExpandedList(var, true); + cmList argsSplit{ var, cmList::EmptyElements::Yes }; // erase the property to avoid infinite recursion this->State->SetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_", ""); if (this->GetIsInTryCompile()) { @@ -3140,9 +3141,8 @@ int cmake::CheckBuildSystem() } // If any byproduct of makefile generation is missing we must re-run. - std::vector<std::string> products; - mf.GetDefExpandList("CMAKE_MAKEFILE_PRODUCTS", products); - for (std::string const& p : products) { + cmList products{ mf.GetDefinition("CMAKE_MAKEFILE_PRODUCTS") }; + for (auto const& p : products) { if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) { if (verbose) { cmSystemTools::Stdout( @@ -3153,10 +3153,10 @@ int cmake::CheckBuildSystem() } // Get the set of dependencies and outputs. - std::vector<std::string> depends; - std::vector<std::string> outputs; - if (mf.GetDefExpandList("CMAKE_MAKEFILE_DEPENDS", depends)) { - mf.GetDefExpandList("CMAKE_MAKEFILE_OUTPUTS", outputs); + cmList depends{ mf.GetDefinition("CMAKE_MAKEFILE_DEPENDS") }; + cmList outputs; + if (!depends.empty()) { + outputs.assign(mf.GetDefinition("CMAKE_MAKEFILE_OUTPUTS")); } if (depends.empty() || outputs.empty()) { // Not enough information was provided to do the test. Just rerun. @@ -3432,19 +3432,18 @@ void cmake::IssueMessage(MessageType t, std::string const& text, std::vector<std::string> cmake::GetDebugConfigs() { - std::vector<std::string> configs; + cmList configs; if (cmValue config_list = this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) { // Expand the specified list and convert to upper-case. - cmExpandList(*config_list, configs); - std::transform(configs.begin(), configs.end(), configs.begin(), - cmSystemTools::UpperCase); + configs.assign(*config_list); + configs.transform(cmList::TransformAction::TOUPPER); } // If no configurations were specified, use a default list. if (configs.empty()) { configs.emplace_back("DEBUG"); } - return configs; + return std::move(configs.data()); } int cmake::Build(int jobs, std::string dir, std::vector<std::string> targets, diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index f4e602bf02..ad27443596 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -26,6 +26,7 @@ #include "cmConsoleBuf.h" #include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmMakefile.h" #include "cmMessageMetadata.h" #include "cmState.h" @@ -457,7 +458,7 @@ int do_build(int ac, char const* const* av) }; auto targetLambda = [&](std::string const& value) -> bool { if (!value.empty()) { - std::vector<std::string> values = cmExpandedList(value); + cmList values{ value }; for (auto const& v : values) { targets.emplace_back(v); if (v == "clean") { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index a2a9e09cfc..9929e85905 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -3,6 +3,7 @@ #include "cmcmd.h" #include <functional> +#include <iterator> #include <cm/optional> #include <cmext/algorithm> @@ -14,6 +15,7 @@ #include "cmConsoleBuf.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" +#include "cmList.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmQtAutoMocUic.h" @@ -342,10 +344,9 @@ int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */, { // Construct the iwyu command line by taking what was given // and adding all the arguments we give to the compiler. - std::vector<std::string> iwyu_cmd = cmExpandedList(runCmd, true); + cmList iwyu_cmd{ runCmd, cmList::EmptyElements::Yes }; cm::append(iwyu_cmd, orig_cmd.begin() + 1, orig_cmd.end()); // Run the iwyu command line. Capture its stderr and hide its stdout. - // Ignore its return code because the tool always returns non-zero. std::string stdErr; int ret; if (!cmSystemTools::RunSingleCommand(iwyu_cmd, nullptr, &stdErr, &ret, @@ -359,14 +360,21 @@ int HandleIWYU(const std::string& runCmd, const std::string& /* sourceFile */, std::cerr << "Warning: include-what-you-use reported diagnostics:\n" << stdErr << "\n"; } - // always return 0 we don't want to break the compile - return 0; + // Older versions of iwyu always returned a non-zero exit code, + // so ignore it unless the user has enabled errors. + auto has_error_opt = std::find_if( + iwyu_cmd.cbegin(), iwyu_cmd.cend(), + [](std::string const& opt) { return cmHasLiteralPrefix(opt, "--error"); }); + bool errors_enabled = has_error_opt != iwyu_cmd.cend() && + has_error_opt != iwyu_cmd.cbegin() && + *std::prev(has_error_opt) == "-Xiwyu"; + return errors_enabled ? ret : 0; } int HandleTidy(const std::string& runCmd, const std::string& sourceFile, const std::vector<std::string>& orig_cmd) { - std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true); + cmList tidy_cmd{ runCmd, cmList::EmptyElements::Yes }; tidy_cmd.push_back(sourceFile); for (auto const& arg : tidy_cmd) { @@ -416,7 +424,7 @@ int HandleLWYU(const std::string& runCmd, const std::string& sourceFile, { // Construct the ldd -r -u (link what you use lwyu) command line // ldd -u -r lwuy target - std::vector<std::string> lwyu_cmd = cmExpandedList(runCmd, true); + cmList lwyu_cmd{ runCmd, cmList::EmptyElements::Yes }; lwyu_cmd.push_back(sourceFile); // Run the lwyu check command line, currently ldd is expected. @@ -444,7 +452,7 @@ int HandleCppLint(const std::string& runCmd, const std::string& sourceFile, const std::vector<std::string>&) { // Construct the cpplint command line. - std::vector<std::string> cpplint_cmd = cmExpandedList(runCmd, true); + cmList cpplint_cmd{ runCmd, cmList::EmptyElements::Yes }; cpplint_cmd.push_back(sourceFile); // Run the cpplint command line. Capture its output. @@ -471,7 +479,7 @@ int HandleCppCheck(const std::string& runCmd, const std::string& sourceFile, const std::vector<std::string>& orig_cmd) { // Construct the cpplint command line. - std::vector<std::string> cppcheck_cmd = cmExpandedList(runCmd, true); + cmList cppcheck_cmd{ runCmd, cmList::EmptyElements::Yes }; // extract all the -D, -U, and -I options from the compile line for (auto const& opt : orig_cmd) { if (opt.size() > 2) { @@ -551,8 +559,8 @@ struct CoCompileJob int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args) { std::vector<CoCompileJob> jobs; - std::string sourceFile; // store --source= - std::vector<std::string> launchers; // store --launcher= + std::string sourceFile; // store --source= + cmList launchers; // store --launcher= // Default is to run the original command found after -- if the option // does not need to do that, it should be specified here, currently only @@ -585,7 +593,7 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args) if (cmHasLiteralPrefix(arg, "--source=")) { sourceFile = arg.substr(9); } else if (cmHasLiteralPrefix(arg, "--launcher=")) { - cmExpandList(arg.substr(11), launchers, true); + launchers.append(arg.substr(11), cmList::EmptyElements::Yes); } else { // if it was not a co-compiler or --source/--launcher then error std::cerr << "__run_co_compile given unknown argument: " << arg |