diff options
Diffstat (limited to 'Source')
39 files changed, 353 insertions, 108 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e427beb..8cb8ed9 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 28) -set(CMake_VERSION_PATCH 20231023) +set(CMake_VERSION_PATCH 20231107) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index c9c069c..b7b6785 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -5,6 +5,8 @@ #include <cstring> #include <map> #include <ostream> +#include <unordered_map> +#include <unordered_set> #include <utility> #include <vector> @@ -17,6 +19,121 @@ #include "cmValue.h" #include "cmWorkingDirectory.h" +enum class DeduplicateStatus +{ + Skip, + Add, + Error +}; + +/** + * @class cmCPackArchiveGenerator::Deduplicator + * @brief A utility class for deduplicating files, folders, and symlinks. + * + * This class is responsible for identifying duplicate files, folders, and + * symlinks when generating an archive. It keeps track of the paths that have + * been processed and helps in deciding whether a new path should be added, + * skipped, or flagged as an error. + */ +class cmCPackArchiveGenerator::Deduplicator +{ +private: + /** + * @brief Compares a file with already processed files. + * + * @param path The path of the file to compare. + * @param localTopLevel The top-level directory for the file. + * @return DeduplicateStatus indicating whether to add, skip, or flag an + * error for the file. + */ + DeduplicateStatus CompareFile(const std::string& path, + const std::string& localTopLevel) + { + auto fileItr = this->Files.find(path); + if (fileItr != this->Files.end()) { + return cmSystemTools::FilesDiffer(path, fileItr->second) + ? DeduplicateStatus::Error + : DeduplicateStatus::Skip; + } + + this->Files[path] = cmStrCat(localTopLevel, "/", path); + return DeduplicateStatus::Add; + } + + /** + * @brief Compares a folder with already processed folders. + * + * @param path The path of the folder to compare. + * @return DeduplicateStatus indicating whether to add or skip the folder. + */ + DeduplicateStatus CompareFolder(const std::string& path) + { + if (this->Folders.find(path) != this->Folders.end()) { + return DeduplicateStatus::Skip; + } + + this->Folders.emplace(path); + return DeduplicateStatus::Add; + } + + /** + * @brief Compares a symlink with already processed symlinks. + * + * @param path The path of the symlink to compare. + * @return DeduplicateStatus indicating whether to add, skip, or flag an + * error for the symlink. + */ + DeduplicateStatus CompareSymlink(const std::string& path) + { + auto symlinkItr = this->Symlink.find(path); + std::string symlinkValue; + auto status = cmSystemTools::ReadSymlink(path, symlinkValue); + if (!status.IsSuccess()) { + return DeduplicateStatus::Error; + } + + if (symlinkItr != this->Symlink.end()) { + return symlinkValue == symlinkItr->second ? DeduplicateStatus::Skip + : DeduplicateStatus::Error; + } + + this->Symlink[path] = symlinkValue; + return DeduplicateStatus::Add; + } + +public: + /** + * @brief Determines the deduplication status of a given path. + * + * This method identifies whether the given path is a file, folder, or + * symlink and then delegates to the appropriate comparison method. + * + * @param path The path to check for deduplication. + * @param localTopLevel The top-level directory for the path. + * @return DeduplicateStatus indicating the action to take for the given + * path. + */ + DeduplicateStatus IsDeduplicate(const std::string& path, + const std::string& localTopLevel) + { + DeduplicateStatus status; + if (cmSystemTools::FileIsDirectory(path)) { + status = this->CompareFolder(path); + } else if (cmSystemTools::FileIsSymlink(path)) { + status = this->CompareSymlink(path); + } else { + status = this->CompareFile(path, localTopLevel); + } + + return status; + } + +private: + std::unordered_map<std::string, std::string> Symlink; + std::unordered_set<std::string> Folders; + std::unordered_map<std::string, std::string> Files; +}; + cmCPackGenerator* cmCPackArchiveGenerator::Create7ZGenerator() { return new cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "7zip", @@ -110,7 +227,8 @@ int cmCPackArchiveGenerator::InitializeInternal() } int cmCPackArchiveGenerator::addOneComponentToArchive( - cmArchiveWrite& archive, cmCPackComponent* component) + cmArchiveWrite& archive, cmCPackComponent* component, + Deduplicator* deduplicator) { cmCPackLogger(cmCPackLog::LOG_VERBOSE, " - packaging component: " << component->Name << std::endl); @@ -139,8 +257,25 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( } for (std::string const& file : component->Files) { std::string rp = filePrefix + file; - cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file: " << rp << std::endl); - archive.Add(rp, 0, nullptr, false); + + DeduplicateStatus status = DeduplicateStatus::Add; + if (deduplicator != nullptr) { + status = deduplicator->IsDeduplicate(rp, localToplevel); + } + + if (deduplicator == nullptr || status == DeduplicateStatus::Add) { + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file: " << rp << std::endl); + archive.Add(rp, 0, nullptr, false); + } else if (status == DeduplicateStatus::Error) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "ERROR The data in files with the " + "same filename is different."); + return 0; + } else { + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Passing file: " << rp << std::endl); + } + if (!archive) { cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging files: " << archive.GetError() @@ -197,6 +332,8 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) std::string packageFileName = std::string(this->toplevel) + "/" + this->GetArchiveComponentFileName(compG.first, true); + Deduplicator deduplicator; + // open a block in order to automatically close archive // at the end of the block { @@ -204,7 +341,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) // now iterate over the component of this group for (cmCPackComponent* comp : (compG.second).Components) { // Add the files of this component to the archive - this->addOneComponentToArchive(archive, comp); + this->addOneComponentToArchive(archive, comp, &deduplicator); } } // add the generated package to package file names list @@ -231,7 +368,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) { DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive); // Add the files of this component to the archive - this->addOneComponentToArchive(archive, &(comp.second)); + this->addOneComponentToArchive(archive, &(comp.second), nullptr); } // add the generated package to package file names list this->packageFileNames.push_back(std::move(packageFileName)); @@ -252,7 +389,7 @@ int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup) { DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive); // Add the files of this component to the archive - this->addOneComponentToArchive(archive, &(comp.second)); + this->addOneComponentToArchive(archive, &(comp.second), nullptr); } // add the generated package to package file names list this->packageFileNames.push_back(std::move(packageFileName)); @@ -282,10 +419,12 @@ int cmCPackArchiveGenerator::PackageComponentsAllInOne() << std::endl); DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive); + Deduplicator deduplicator; + // The ALL COMPONENTS in ONE package case for (auto& comp : this->Components) { // Add the files of this component to the archive - this->addOneComponentToArchive(archive, &(comp.second)); + this->addOneComponentToArchive(archive, &(comp.second), &deduplicator); } // archive goes out of scope so it will finalized and closed. diff --git a/Source/CPack/cmCPackArchiveGenerator.h b/Source/CPack/cmCPackArchiveGenerator.h index 8a9bbc6..b8a1afa 100644 --- a/Source/CPack/cmCPackArchiveGenerator.h +++ b/Source/CPack/cmCPackArchiveGenerator.h @@ -47,6 +47,8 @@ private: std::string GetArchiveComponentFileName(const std::string& component, bool isGroupName); + class Deduplicator; + protected: int InitializeInternal() override; /** @@ -54,9 +56,11 @@ protected: * to the provided (already opened) archive. * @param[in,out] archive the archive object * @param[in] component the component whose file will be added to archive + * @param[in] deduplicator file deduplicator utility. */ int addOneComponentToArchive(cmArchiveWrite& archive, - cmCPackComponent* component); + cmCPackComponent* component, + Deduplicator* deduplicator); /** * The main package file method. diff --git a/Source/CPack/cmCPackInnoSetupGenerator.cxx b/Source/CPack/cmCPackInnoSetupGenerator.cxx index b8bf070..bf90b06 100644 --- a/Source/CPack/cmCPackInnoSetupGenerator.cxx +++ b/Source/CPack/cmCPackInnoSetupGenerator.cxx @@ -579,8 +579,9 @@ bool cmCPackInnoSetupGenerator::ProcessFiles() bool cmCPackInnoSetupGenerator::ProcessComponents() { - codeIncludes.push_back("{ The following lines are required by CPack because " - "this script uses components }"); + codeIncludes.emplace_back( + "{ The following lines are required by CPack because " + "this script uses components }"); // Installation types std::vector<cmCPackInstallationType*> types(InstallationTypes.size()); @@ -607,7 +608,7 @@ bool cmCPackInnoSetupGenerator::ProcessComponents() "\"{code:CPackGetCustomInstallationMessage}\""; customTypeParams["Flags"] = "iscustom"; - allTypes.push_back("custom"); + allTypes.emplace_back("custom"); typeInstructions.push_back(ISKeyValueLine(customTypeParams)); // Components @@ -633,6 +634,7 @@ bool cmCPackInnoSetupGenerator::ProcessComponents() } else if (!component->InstallationTypes.empty()) { std::vector<std::string> installationTypes; + installationTypes.reserve(component->InstallationTypes.size()); for (cmCPackInstallationType* j : component->InstallationTypes) { installationTypes.push_back(j->Name); } diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h index 2ab2f8e..347b0f7 100644 --- a/Source/CPack/cmCPackLog.h +++ b/Source/CPack/cmCPackLog.h @@ -29,7 +29,7 @@ public: cmCPackLog(const cmCPackLog&) = delete; cmCPackLog& operator=(const cmCPackLog&) = delete; - enum __log_tags + enum cm_log_tags { NOTAG = 0, LOG_OUTPUT = 0x1, diff --git a/Source/CTest/cmCTestBZR.cxx b/Source/CTest/cmCTestBZR.cxx index 36df344..87081f0 100644 --- a/Source/CTest/cmCTestBZR.cxx +++ b/Source/CTest/cmCTestBZR.cxx @@ -374,7 +374,7 @@ bool cmCTestBZR::UpdateImpl() // Use "bzr pull" to update the working tree. std::vector<std::string> bzr_update; bzr_update.push_back(this->CommandLineTool); - bzr_update.push_back("pull"); + bzr_update.emplace_back("pull"); cm::append(bzr_update, args); diff --git a/Source/CTest/cmCTestCVS.cxx b/Source/CTest/cmCTestCVS.cxx index ef95b25..badd43e 100644 --- a/Source/CTest/cmCTestCVS.cxx +++ b/Source/CTest/cmCTestCVS.cxx @@ -92,8 +92,8 @@ bool cmCTestCVS::UpdateImpl() // Run "cvs update" to update the work tree. std::vector<std::string> cvs_update; cvs_update.push_back(this->CommandLineTool); - cvs_update.push_back("-z3"); - cvs_update.push_back("update"); + cvs_update.emplace_back("-z3"); + cvs_update.emplace_back("update"); cm::append(cvs_update, args); UpdateParser out(this, "up-out> "); diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index ca8659e..984c837 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -159,7 +159,7 @@ bool cmCTestGIT::UpdateByFetchAndReset() // Use "git fetch" to get remote commits. std::vector<std::string> git_fetch; git_fetch.push_back(git); - git_fetch.push_back("fetch"); + git_fetch.emplace_back("fetch"); // Add user-specified update options. std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions"); diff --git a/Source/CTest/cmCTestHG.cxx b/Source/CTest/cmCTestHG.cxx index e1a945d..3d56be0 100644 --- a/Source/CTest/cmCTestHG.cxx +++ b/Source/CTest/cmCTestHG.cxx @@ -137,9 +137,9 @@ bool cmCTestHG::UpdateImpl() // TODO: if(this->CTest->GetTestModel() == cmCTest::NIGHTLY) std::vector<std::string> hg_update; - hg_update.push_back(this->CommandLineTool.c_str()); - hg_update.push_back("update"); - hg_update.push_back("-v"); + hg_update.emplace_back(this->CommandLineTool); + hg_update.emplace_back("update"); + hg_update.emplace_back("-v"); // Add user-specified update options. std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions"); diff --git a/Source/CTest/cmCTestP4.cxx b/Source/CTest/cmCTestP4.cxx index 5d71b84..20bd0ec 100644 --- a/Source/CTest/cmCTestP4.cxx +++ b/Source/CTest/cmCTestP4.cxx @@ -151,9 +151,9 @@ cmCTestP4::User cmCTestP4::GetUserData(const std::string& username) if (it == this->Users.end()) { std::vector<std::string> p4_users; this->SetP4Options(p4_users); - p4_users.push_back("users"); - p4_users.push_back("-m"); - p4_users.push_back("1"); + p4_users.emplace_back("users"); + p4_users.emplace_back("-m"); + p4_users.emplace_back("1"); p4_users.push_back(username); UserParser out(this, "users-out> "); @@ -335,10 +335,10 @@ std::string cmCTestP4::GetWorkingRevision() std::vector<std::string> p4_identify; this->SetP4Options(p4_identify); - p4_identify.push_back("changes"); - p4_identify.push_back("-m"); - p4_identify.push_back("1"); - p4_identify.push_back("-t"); + p4_identify.emplace_back("changes"); + p4_identify.emplace_back("-m"); + p4_identify.emplace_back("1"); + p4_identify.emplace_back("-t"); std::string source = this->SourceDirectory + "/...#have"; p4_identify.push_back(source); @@ -403,7 +403,7 @@ bool cmCTestP4::LoadRevisions() .append(",") .append(this->NewRevision); - p4_changes.push_back("changes"); + p4_changes.emplace_back("changes"); p4_changes.push_back(range); ChangesParser out(this, "p4_changes-out> "); @@ -420,8 +420,8 @@ bool cmCTestP4::LoadRevisions() std::vector<std::string> p4_describe; for (std::string const& i : cmReverseRange(this->ChangeLists)) { this->SetP4Options(p4_describe); - p4_describe.push_back("describe"); - p4_describe.push_back("-s"); + p4_describe.emplace_back("describe"); + p4_describe.emplace_back("-s"); p4_describe.push_back(i); DescribeParser outDescribe(this, "p4_describe-out> "); @@ -436,10 +436,10 @@ bool cmCTestP4::LoadModifications() std::vector<std::string> p4_diff; this->SetP4Options(p4_diff); - p4_diff.push_back("diff"); + p4_diff.emplace_back("diff"); // Ideally we would use -Od but not all clients support it - p4_diff.push_back("-dn"); + p4_diff.emplace_back("-dn"); std::string source = this->SourceDirectory + "/..."; p4_diff.push_back(source); @@ -480,7 +480,7 @@ bool cmCTestP4::UpdateImpl() std::vector<std::string> p4_sync; this->SetP4Options(p4_sync); - p4_sync.push_back("sync"); + p4_sync.emplace_back("sync"); // Get user-specified update options. std::string opts = this->CTest->GetCTestConfiguration("UpdateOptions"); diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index 14bc510..fc7051c 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -34,7 +34,7 @@ cmCTestSVN::~cmCTestSVN() = default; void cmCTestSVN::CleanupImpl() { std::vector<std::string> svn_cleanup; - svn_cleanup.push_back("cleanup"); + svn_cleanup.emplace_back("cleanup"); OutputLogger out(this->Log, "cleanup-out> "); OutputLogger err(this->Log, "cleanup-err> "); this->RunSVNCommand(svn_cleanup, &out, &err); @@ -89,7 +89,7 @@ std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo) { // Run "svn info" to get the repository info from the work tree. std::vector<std::string> svn_info; - svn_info.push_back("info"); + svn_info.emplace_back("info"); svn_info.push_back(svninfo.LocalPath); std::string rev; InfoParser out(this, "info-out> ", rev, svninfo); @@ -252,7 +252,7 @@ bool cmCTestSVN::UpdateImpl() } std::vector<std::string> svn_update; - svn_update.push_back("update"); + svn_update.emplace_back("update"); cm::append(svn_update, args); UpdateParser out(this, "up-out> "); @@ -270,7 +270,7 @@ bool cmCTestSVN::RunSVNCommand(std::vector<std::string> const& parameters, std::vector<std::string> args; args.push_back(this->CommandLineTool); cm::append(args, parameters); - args.push_back("--non-interactive"); + args.emplace_back("--non-interactive"); std::string userOptions = this->CTest->GetCTestConfiguration("SVNOptions"); @@ -388,11 +388,11 @@ bool cmCTestSVN::LoadRevisions(SVNInfo& svninfo) // Run "svn log" to get all global revisions of interest. std::vector<std::string> svn_log; - svn_log.push_back("log"); - svn_log.push_back("--xml"); - svn_log.push_back("-v"); - svn_log.push_back(revs.c_str()); - svn_log.push_back(svninfo.LocalPath.c_str()); + svn_log.emplace_back("log"); + svn_log.emplace_back("--xml"); + svn_log.emplace_back("-v"); + svn_log.emplace_back(revs); + svn_log.emplace_back(svninfo.LocalPath); LogParser out(this, "log-out> ", svninfo); OutputLogger err(this->Log, "log-err> "); return this->RunSVNCommand(svn_log, &out, &err); @@ -467,7 +467,7 @@ bool cmCTestSVN::LoadModifications() { // Run "svn status" which reports local modifications. std::vector<std::string> svn_status; - svn_status.push_back("status"); + svn_status.emplace_back("status"); StatusParser out(this, "status-out> "); OutputLogger err(this->Log, "status-err> "); this->RunSVNCommand(svn_status, &out, &err); @@ -529,7 +529,7 @@ bool cmCTestSVN::LoadRepositories() // Run "svn status" to get the list of external repositories std::vector<std::string> svn_status; - svn_status.push_back("status"); + svn_status.emplace_back("status"); ExternalParser out(this, "external-out> "); OutputLogger err(this->Log, "external-err> "); return this->RunSVNCommand(svn_status, &out, &err); diff --git a/Source/Checks/Curses/CheckCurses.c b/Source/Checks/Curses/CheckCurses.c index 7d827e6..3264fa0 100644 --- a/Source/Checks/Curses/CheckCurses.c +++ b/Source/Checks/Curses/CheckCurses.c @@ -8,7 +8,7 @@ # include <curses.h> #endif -int main() +int main(void) { curses_version(); return 0; diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index b7232f3..6e684a3 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -2257,11 +2257,6 @@ bool cmCTest::ProgressOutputSupportedByConsole() bool cmCTest::ColoredOutputSupportedByConsole() { -#if defined(_WIN32) - // Not supported on Windows - return false; -#else - // On UNIX we need a non-dumb tty. std::string clicolor_force; if (cmSystemTools::GetEnv("CLICOLOR_FORCE", clicolor_force) && !clicolor_force.empty() && clicolor_force != "0") { @@ -2271,6 +2266,11 @@ bool cmCTest::ColoredOutputSupportedByConsole() if (cmSystemTools::GetEnv("CLICOLOR", clicolor) && clicolor == "0") { return false; } +#if defined(_WIN32) + // Not supported on Windows + return false; +#else + // On UNIX we need a non-dumb tty. return ConsoleIsNotDumb(); #endif } @@ -3736,12 +3736,7 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg, std::string cmCTest::GetColorCode(Color color) const { if (this->Impl->OutputColorCode) { -#if defined(_WIN32) - // Not supported on Windows - static_cast<void>(color); -#else return "\033[0;" + std::to_string(static_cast<int>(color)) + "m"; -#endif } return ""; diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 2ee4f47..91f7691 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -219,9 +219,11 @@ void GetScriptingCommands(cmState* state) state->AddDisallowedCommand( "use_mangled_mesa", cmUseMangledMesaCommand, cmPolicies::CMP0030, "The use_mangled_mesa command should not be called; see CMP0030."); - state->AddDisallowedCommand( - "exec_program", cmExecProgramCommand, cmPolicies::CMP0153, - "The exec_program command should not be called; see CMP0153."); + state->AddDisallowedCommand("exec_program", cmExecProgramCommand, + cmPolicies::CMP0153, + "The exec_program command should not be called; " + "see CMP0153. Use execute_process() instead.", + "Use execute_process() instead."); #endif } diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 7394d86..596572b 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -27,6 +27,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" +#include "cmSourceFile.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" @@ -320,6 +321,9 @@ cmComputeLinkDepends::Compute() // Follow the link dependencies of the target to be linked. this->AddDirectLinkEntries(); + // Add dependencies on targets named by $<TARGET_OBJECTS:...> sources. + this->AddTargetObjectEntries(); + // Complete the breadth-first search of dependencies. while (!this->BFSQueue.empty()) { // Get the next entry. @@ -513,6 +517,7 @@ void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item) LinkEntry& entry = this->EntryList[index]; entry.Item = BT<std::string>(item.AsStr(), item.Backtrace); entry.Kind = LinkEntry::Object; + entry.Target = item.Target; // Record explicitly linked object files separately. this->ObjectEntries.emplace_back(index); @@ -701,6 +706,21 @@ void cmComputeLinkDepends::AddDirectLinkEntries() } } +void cmComputeLinkDepends::AddTargetObjectEntries() +{ + std::vector<cmSourceFile const*> externalObjects; + this->Target->GetExternalObjects(externalObjects, this->Config); + for (auto const* externalObject : externalObjects) { + std::string const& objLib = externalObject->GetObjectLibrary(); + if (objLib.empty()) { + continue; + } + cmLinkItem const& objItem = + this->Target->ResolveLinkItem(BT<std::string>(objLib)); + this->AddLinkObject(objItem); + } +} + template <typename T> void cmComputeLinkDepends::AddLinkEntries(size_t depender_index, std::vector<T> const& libs) diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 22c4e2a..63c289c 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -100,6 +100,7 @@ private: void AddLinkObject(cmLinkItem const& item); void AddVarLinkEntries(size_t depender_index, const char* value); void AddDirectLinkEntries(); + void AddTargetObjectEntries(); template <typename T> void AddLinkEntries(size_t depender_index, std::vector<T> const& libs); void AddLinkObjects(std::vector<cmLinkItem> const& objs); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 4cf3042..bd7ebed 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1252,7 +1252,7 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) this->AddFullItem(entry); this->AddLibraryRuntimeInfo(item.Value); } - } else { + } else if (entry.Kind != cmComputeLinkDepends::LinkEntry::Object) { // This is a library or option specified by the user. this->AddUserItem(entry, true); } diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 6f9f541..eba4c57 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -33,6 +33,9 @@ auto const keyCOMMAND = "COMMAND"_s; auto const keyDEFINED = "DEFINED"_s; auto const keyEQUAL = "EQUAL"_s; auto const keyEXISTS = "EXISTS"_s; +auto const keyIS_READABLE = "IS_READABLE"_s; +auto const keyIS_WRITABLE = "IS_WRITABLE"_s; +auto const keyIS_EXECUTABLE = "IS_EXECUTABLE"_s; auto const keyGREATER = "GREATER"_s; auto const keyGREATER_EQUAL = "GREATER_EQUAL"_s; auto const keyIN_LIST = "IN_LIST"_s; @@ -568,6 +571,24 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, newArgs.ReduceOneArg(cmSystemTools::FileExists(args.next->GetValue()), args); } + // check if a file is readable + else if (this->IsKeyword(keyIS_READABLE, *args.current)) { + newArgs.ReduceOneArg(cmSystemTools::TestFileAccess( + args.next->GetValue(), cmsys::TEST_FILE_READ), + args); + } + // check if a file is writable + else if (this->IsKeyword(keyIS_WRITABLE, *args.current)) { + newArgs.ReduceOneArg(cmSystemTools::TestFileAccess( + args.next->GetValue(), cmsys::TEST_FILE_WRITE), + args); + } + // check if a file is executable + else if (this->IsKeyword(keyIS_EXECUTABLE, *args.current)) { + newArgs.ReduceOneArg(cmSystemTools::TestFileAccess( + args.next->GetValue(), cmsys::TEST_FILE_EXECUTE), + args); + } // does a directory with this name exist else if (this->IsKeyword(keyIS_DIRECTORY, *args.current)) { newArgs.ReduceOneArg( diff --git a/Source/cmDebuggerStackFrame.h b/Source/cmDebuggerStackFrame.h index dc3b2ab..f4e6612 100644 --- a/Source/cmDebuggerStackFrame.h +++ b/Source/cmDebuggerStackFrame.h @@ -28,6 +28,10 @@ public: std::string const& GetFileName() const noexcept { return this->FileName; } int64_t GetLine() const noexcept; cmMakefile* GetMakefile() const noexcept { return this->Makefile; } + cmListFileFunction const& GetFunction() const noexcept + { + return this->Function; + } }; } // namespace cmDebugger diff --git a/Source/cmDebuggerThread.cxx b/Source/cmDebuggerThread.cxx index fd52f5a..f7a1778 100644 --- a/Source/cmDebuggerThread.cxx +++ b/Source/cmDebuggerThread.cxx @@ -13,6 +13,7 @@ #include "cmDebuggerVariables.h" #include "cmDebuggerVariablesHelper.h" #include "cmDebuggerVariablesManager.h" +#include "cmListFileCache.h" namespace cmDebugger { @@ -135,8 +136,7 @@ dap::StackTraceResponse GetStackTraceResponse( #endif stackFrame.line = thread->Frames[i]->GetLine(); stackFrame.column = 1; - stackFrame.name = thread->Frames[i]->GetFileName() + " Line " + - std::to_string(stackFrame.line); + stackFrame.name = thread->Frames[i]->GetFunction().OriginalName(); stackFrame.id = thread->Frames[i]->GetId(); stackFrame.source = source; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f7a6a4e..d24867f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -9259,7 +9259,8 @@ void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const // If the generator doesn't support modules at all, error that we have // sources that require the support. - if (!this->GetGlobalGenerator()->CheckCxxModuleSupport()) { + if (!this->GetGlobalGenerator()->CheckCxxModuleSupport( + cmGlobalGenerator::CxxModuleSupportQuery::Expected)) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, cmStrCat( @@ -9317,7 +9318,8 @@ bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang, return false; } return this->HaveCxxModuleSupport(config) == Cxx20SupportLevel::Supported && - this->GetGlobalGenerator()->CheckCxxModuleSupport(); + this->GetGlobalGenerator()->CheckCxxModuleSupport( + cmGlobalGenerator::CxxModuleSupportQuery::Inspect); } bool cmGeneratorTarget::NeedDyndep(std::string const& lang, @@ -9361,14 +9363,20 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, return true; } + bool haveRule = false; switch (this->HaveCxxModuleSupport(config)) { case Cxx20SupportLevel::MissingCxx: case Cxx20SupportLevel::NoCxx20: return false; case Cxx20SupportLevel::MissingRule: + break; case Cxx20SupportLevel::Supported: + haveRule = true; break; } + bool haveGeneratorSupport = + this->GetGlobalGenerator()->CheckCxxModuleSupport( + cmGlobalGenerator::CxxModuleSupportQuery::Inspect); auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); if (sfProp.IsSet()) { return sfProp.IsOn(); @@ -9388,8 +9396,9 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, case cmPolicies::REQUIRED_ALWAYS: case cmPolicies::REQUIRED_IF_USED: case cmPolicies::NEW: - // The NEW behavior is to scan the source. - policyAnswer = true; + // The NEW behavior is to scan the source if the compiler supports + // scanning and the generator supports it. + policyAnswer = haveRule && haveGeneratorSupport; break; } return policyAnswer; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index e798d3e..ef0f40f 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -874,7 +874,11 @@ void cmGlobalGenerator::EnableLanguage( noCompiler << "The " << compilerName << ":\n" " " << *compilerFile << "\n" - "is not a full path and was not found in the PATH.\n" + "is not a full path and was not found in the PATH." +#ifdef _WIN32 + " Perhaps the extension is missing?" +#endif + "\n" ; /* clang-format on */ } else if (!cmSystemTools::FileExists(*compilerFile)) { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 6d29dc1..aa54f69 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -156,7 +156,17 @@ public: virtual bool InspectConfigTypeVariables() { return true; } - virtual bool CheckCxxModuleSupport() { return false; } + enum class CxxModuleSupportQuery + { + // Support is expected at the call site. + Expected, + // The call site is querying for support and handles problems by itself. + Inspect, + }; + virtual bool CheckCxxModuleSupport(CxxModuleSupportQuery /*query*/) + { + return false; + } virtual bool IsGNUMakeJobServerAware() const { return false; } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 02f900c..9fac513 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -897,13 +897,14 @@ bool cmGlobalNinjaGenerator::CheckLanguages( return true; } -bool cmGlobalNinjaGenerator::CheckCxxModuleSupport() +bool cmGlobalNinjaGenerator::CheckCxxModuleSupport(CxxModuleSupportQuery query) { if (this->NinjaSupportsDyndepsCxx) { return true; } bool const diagnose = !this->DiagnosedCxxModuleNinjaSupport && - !this->CMakeInstance->GetIsInTryCompile(); + !this->CMakeInstance->GetIsInTryCompile() && + query == CxxModuleSupportQuery::Expected; if (diagnose) { std::ostringstream e; /* clang-format off */ diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index d731b16..8f6c808 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -475,7 +475,7 @@ public: bool IsSingleConfigUtility(cmGeneratorTarget const* target) const; - bool CheckCxxModuleSupport() override; + bool CheckCxxModuleSupport(CxxModuleSupportQuery query) override; protected: void Generate() override; diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 8f0345f..49643ea 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -48,7 +48,7 @@ public: const char* GetAndroidApplicationTypeRevision() const override; - bool CheckCxxModuleSupport() override + bool CheckCxxModuleSupport(CxxModuleSupportQuery /*query*/) override { return this->SupportsCxxModuleDyndep(); } diff --git a/Source/cmJSONState.cxx b/Source/cmJSONState.cxx index 1abdaa6..5c44fba 100644 --- a/Source/cmJSONState.cxx +++ b/Source/cmJSONState.cxx @@ -45,7 +45,7 @@ cmJSONState::cmJSONState(const std::string& filename, Json::Value* root) void cmJSONState::AddError(std::string const& errMsg) { - this->errors.push_back(Error(errMsg)); + this->errors.emplace_back(errMsg); } void cmJSONState::AddErrorAtValue(std::string const& errMsg, @@ -65,7 +65,7 @@ void cmJSONState::AddErrorAtOffset(std::string const& errMsg, this->AddError(errMsg); } else { Location loc = LocateInDocument(offset); - this->errors.push_back(Error(loc, errMsg)); + this->errors.emplace_back(loc, errMsg); } } @@ -118,7 +118,7 @@ const Json::Value* cmJSONState::value_after(std::string const& k) void cmJSONState::push_stack(std::string const& k, const Json::Value* value) { - this->parseStack.push_back(JsonPair(k, value)); + this->parseStack.emplace_back(k, value); } void cmJSONState::pop_stack() diff --git a/Source/cmLinkItemGraphVisitor.cxx b/Source/cmLinkItemGraphVisitor.cxx index 0ad846b..a63b794 100644 --- a/Source/cmLinkItemGraphVisitor.cxx +++ b/Source/cmLinkItemGraphVisitor.cxx @@ -82,7 +82,7 @@ bool cmLinkItemGraphVisitor::ItemVisited(cmLinkItem const& item) bool cmLinkItemGraphVisitor::LinkVisited(cmLinkItem const& depender, cmLinkItem const& dependee) { - auto const link = std::make_pair<>(depender.AsStr(), dependee.AsStr()); + auto const link = std::make_pair(depender.AsStr(), dependee.AsStr()); bool const linkVisited = this->VisitedLinks.find(link) != this->VisitedLinks.cend(); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 76e36ab..be18c29 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3063,8 +3063,17 @@ cmLocalGenerator::AddUnityFilesModeAuto( chunk = std::min(itemsLeft, batchSize); - std::string filename = cmStrCat(filename_base, "unity_", batch, - (lang == "C") ? "_c.c" : "_cxx.cxx"); + std::string extension; + if (lang == "C") { + extension = "_c.c"; + } else if (lang == "CXX") { + extension = "_cxx.cxx"; + } else if (lang == "OBJC") { + extension = "_m.m"; + } else if (lang == "OBJCXX") { + extension = "_mm.mm"; + } + std::string filename = cmStrCat(filename_base, "unity_", batch, extension); auto const begin = filtered_sources.begin() + batch * batchSize; auto const end = begin + chunk; unity_files.emplace_back(this->WriteUnitySource( @@ -3155,7 +3164,7 @@ void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target) cmValue afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE"); cmValue unityMode = target->GetProperty("UNITY_BUILD_MODE"); - for (std::string lang : { "C", "CXX" }) { + for (std::string lang : { "C", "CXX", "OBJC", "OBJCXX" }) { std::vector<UnityBatchedSource> filtered_sources; std::copy_if(unitySources.begin(), unitySources.end(), std::back_inserter(filtered_sources), diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 40d769d..9ed422d 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1215,8 +1215,8 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( std::move(cc), - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - std::unique_ptr<cmCustomCommand> tcc) { + [this, t, type](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + std::unique_ptr<cmCustomCommand> tcc) { BacktraceGuard guard(this->Backtrace, lfbt); tcc->SetBacktrace(lfbt); detail::AddCustomCommandToTarget(lg, cmCommandOrigin::Project, t, type, @@ -1254,8 +1254,9 @@ void cmMakefile::AddCustomCommandToOutput( // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( std::move(cc), - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - std::unique_ptr<cmCustomCommand> tcc) { + [this, replace, callback](cmLocalGenerator& lg, + const cmListFileBacktrace& lfbt, + std::unique_ptr<cmCustomCommand> tcc) { BacktraceGuard guard(this->Backtrace, lfbt); tcc->SetBacktrace(lfbt); cmSourceFile* sf = detail::AddCustomCommandToOutput( @@ -1341,7 +1342,8 @@ void cmMakefile::AppendCustomCommandToOutput( if (this->ValidateCustomCommand(commandLines)) { // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { + [this, output, depends, implicit_depends, + commandLines](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) { BacktraceGuard guard(this->Backtrace, lfbt); detail::AppendCustomCommandToOutput(lg, lfbt, output, depends, implicit_depends, commandLines); @@ -1372,8 +1374,8 @@ cmTarget* cmMakefile::AddUtilityCommand(const std::string& utilityName, // Dispatch command creation to allow generator expressions in outputs. this->AddGeneratorAction( std::move(cc), - [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, - std::unique_ptr<cmCustomCommand> tcc) { + [this, target](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, + std::unique_ptr<cmCustomCommand> tcc) { BacktraceGuard guard(this->Backtrace, lfbt); tcc->SetBacktrace(lfbt); detail::AddUtilityCommand(lg, cmCommandOrigin::Project, target, diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 3f76cf4..5a674e7 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1257,8 +1257,6 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, { cmNinjaBuild scanBuild(ruleName); - scanBuild.RspFile = "$out.rsp"; - if (compilePP) { // Move compilation dependencies to the scan/preprocessing build statement. std::swap(scanBuild.ExplicitDeps, objBuild.ExplicitDeps); @@ -1299,6 +1297,7 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName, // Tell dependency scanner where to store dyndep intermediate results. std::string ddiFileName = cmStrCat(objectFileName, ".ddi"); scanBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFileName; + scanBuild.RspFile = cmStrCat(ddiFileName, ".rsp"); // Outputs of the scan/preprocessor build statement. if (compilePP) { diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 1ea2ce2..8838de4 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -470,10 +470,10 @@ class cmMakefile; POLICY, CMP0154, \ "Generated files are private by default in targets using file sets.", 3, \ 28, 0, cmPolicies::WARN) \ - SELECT( \ - POLICY, CMP0155, \ - "C++ sources in targets with at least C++20 are scanned for imports", 3, \ - 28, 0, cmPolicies::WARN) + SELECT(POLICY, CMP0155, \ + "C++ sources in targets with at least C++20 are scanned for " \ + "imports when supported.", \ + 3, 28, 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/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index ece657d..50110ed 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -190,7 +190,7 @@ public: { public: // -- Parse Cache - std::atomic<bool> ParseCacheChanged = ATOMIC_VAR_INIT(false); + std::atomic<bool> ParseCacheChanged{ false }; cmFileTime ParseCacheTime; ParseCacheT ParseCache; @@ -583,7 +583,7 @@ private: std::string SettingsStringMoc_; std::string SettingsStringUic_; // -- Worker thread pool - std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false); + std::atomic<bool> JobError_{ false }; cmWorkerPool WorkerPool_; // -- Concurrent processing mutable std::mutex CMakeLibMutex_; diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 4b1685f..bb92856 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -280,8 +280,11 @@ static bool processTree(cmMakefile& mf, ParsedArguments& parsedArguments, ? "" : parsedArguments[kPrefixOptionName].front(); - std::vector<std::string> files = parsedArguments[kFilesOptionName]; - if (files.empty()) { + std::vector<std::string> files; + auto filesArgIt = parsedArguments.find(kFilesOptionName); + if (filesArgIt != parsedArguments.end()) { + files = filesArgIt->second; + } else { const std::vector<std::unique_ptr<cmSourceFile>>& srcFiles = mf.GetSourceFiles(); for (const auto& srcFile : srcFiles) { diff --git a/Source/cmState.cxx b/Source/cmState.cxx index d41e8e5..8ae2166 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -447,17 +447,23 @@ void cmState::AddFlowControlCommand(std::string const& name, void cmState::AddDisallowedCommand(std::string const& name, BuiltinCommand command, cmPolicies::PolicyID policy, - const char* message) + const char* message, + const char* additionalWarning) { this->AddBuiltinCommand( name, - [command, policy, message](const std::vector<cmListFileArgument>& args, - cmExecutionStatus& status) -> bool { + [command, policy, message, + additionalWarning](const std::vector<cmListFileArgument>& args, + cmExecutionStatus& status) -> bool { cmMakefile& mf = status.GetMakefile(); switch (mf.GetPolicyStatus(policy)) { - case cmPolicies::WARN: - mf.IssueMessage(MessageType::AUTHOR_WARNING, - cmPolicies::GetPolicyWarning(policy)); + case cmPolicies::WARN: { + std::string warning = cmPolicies::GetPolicyWarning(policy); + if (additionalWarning) { + warning = cmStrCat(warning, '\n', additionalWarning); + } + mf.IssueMessage(MessageType::AUTHOR_WARNING, warning); + } CM_FALLTHROUGH; case cmPolicies::OLD: break; diff --git a/Source/cmState.h b/Source/cmState.h index b79f3e6..702b06f 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -183,7 +183,8 @@ public: void AddFlowControlCommand(std::string const& name, Command command); void AddFlowControlCommand(std::string const& name, BuiltinCommand command); void AddDisallowedCommand(std::string const& name, BuiltinCommand command, - cmPolicies::PolicyID policy, const char* message); + cmPolicies::PolicyID policy, const char* message, + const char* additionalWarning = nullptr); void AddUnexpectedCommand(std::string const& name, const char* error); void AddUnexpectedFlowControlCommand(std::string const& name, const char* error); diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index fe421ba..f606c22 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -576,7 +576,9 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command, cmDuration timeout, Encoding encoding) { cmUVProcessChainBuilder builder; - builder.AddCommand(command); + builder + .SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT, cm_fileno(stdin)) + .AddCommand(command); if (dir) { builder.SetWorkingDirectory(dir); } diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index 72805d3..5310166 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -285,7 +285,8 @@ int main() return exit_code; // compile rc file with rc.exe - return process(srcfilename, "", objfile, prefix, binpath + " " + rest, + std::string rc = cmStrCat('"', binpath, '"'); + return process(srcfilename, "", objfile, prefix, cmStrCat(rc, ' ', rest), std::string(), true); } diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 43a945f..93b0086 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -203,11 +203,16 @@ bool cmTarFilesFrom(std::string const& file, std::vector<std::string>& files) void cmCatFile(const std::string& fileToAppend) { #ifdef _WIN32 + _setmode(fileno(stdin), _O_BINARY); _setmode(fileno(stdout), _O_BINARY); #endif - cmsys::ifstream source(fileToAppend.c_str(), - (std::ios::binary | std::ios::in)); - std::cout << source.rdbuf(); + std::streambuf* buf = std::cin.rdbuf(); + cmsys::ifstream source; + if (fileToAppend != "-") { + source.open(fileToAppend.c_str(), (std::ios::binary | std::ios::in)); + buf = source.rdbuf(); + } + std::cout << buf; } bool cmRemoveDirectory(const std::string& dir, bool recursive = true) @@ -1147,7 +1152,12 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, int return_value = 0; bool doing_options = true; for (auto const& arg : cmMakeRange(args).advance(2)) { - if (doing_options && cmHasLiteralPrefix(arg, "-")) { + if (arg == "-") { + doing_options = false; + // Destroy console buffers to drop cout/cerr encoding transform. + consoleBuf.reset(); + cmCatFile(arg); + } else if (doing_options && cmHasLiteralPrefix(arg, "-")) { if (arg == "--") { doing_options = false; } else { |