diff options
Diffstat (limited to 'Source')
101 files changed, 2381 insertions, 906 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 311f3f4..9aebfa7 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -260,6 +260,8 @@ set(SRCS cmInstallFilesGenerator.cxx cmInstallScriptGenerator.h cmInstallScriptGenerator.cxx + cmInstallSubdirectoryGenerator.h + cmInstallSubdirectoryGenerator.cxx cmInstallTargetGenerator.h cmInstallTargetGenerator.cxx cmInstallDirectoryGenerator.h @@ -318,6 +320,8 @@ set(SRCS cmQtAutoGen.h cmQtAutoGenerator.cxx cmQtAutoGenerator.h + cmQtAutoGenGlobalInitializer.cxx + cmQtAutoGenGlobalInitializer.h cmQtAutoGenInitializer.cxx cmQtAutoGenInitializer.h cmQtAutoGeneratorMocUic.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 5f103dc..eec8d1a 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 13) -set(CMake_VERSION_PATCH 0) -set(CMake_VERSION_RC 3) +set(CMake_VERSION_PATCH 20181119) +#set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index c083945..7cf69fc 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -21,6 +21,7 @@ #include "cmCPackLog.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" +#include "cmDocumentationFormatter.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateSnapshot.h" @@ -358,8 +359,21 @@ int main(int argc, char const* const* argv) cpackGenerator->SetTraceExpand(traceExpand); } else { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Cannot initialize CPack generator: " << gen - << std::endl); + "Could not create CPack generator: " << gen + << std::endl); + // Print out all the valid generators + cmDocumentation generatorDocs; + std::vector<cmDocumentationEntry> v; + for (auto const& g : generators.GetGeneratorsList()) { + cmDocumentationEntry e; + e.Name = g.first; + e.Brief = g.second; + v.push_back(std::move(e)); + } + generatorDocs.SetSection("Generators", v); + std::cerr << "\n"; + generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators, + std::cerr); parsed = 0; } diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index ecf309a..98872a5 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -12,6 +12,7 @@ #include <stdio.h> #include <stdlib.h> +#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestCurl.h" #include "cmCTestScriptHandler.h" @@ -55,6 +56,7 @@ public: std::string Filename; std::string MD5; std::string Message; + std::string BuildID; private: std::vector<char> CurrentValue; @@ -96,6 +98,8 @@ private: this->MD5 = this->GetCurrentValue(); } else if (name == "message") { this->Message = this->GetCurrentValue(); + } else if (name == "buildId") { + this->BuildID = this->GetCurrentValue(); } } }; @@ -152,10 +156,9 @@ void cmCTestSubmitHandler::Initialize() this->Files.clear(); } -bool cmCTestSubmitHandler::SubmitUsingFTP(const std::string& localprefix, - const std::set<std::string>& files, - const std::string& remoteprefix, - const std::string& url) +bool cmCTestSubmitHandler::SubmitUsingFTP( + const std::string& localprefix, const std::vector<std::string>& files, + const std::string& remoteprefix, const std::string& url) { CURL* curl; CURLcode res; @@ -299,10 +302,9 @@ bool cmCTestSubmitHandler::SubmitUsingFTP(const std::string& localprefix, } // Uploading files is simpler -bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, - const std::set<std::string>& files, - const std::string& remoteprefix, - const std::string& url) +bool cmCTestSubmitHandler::SubmitUsingHTTP( + const std::string& localprefix, const std::vector<std::string>& files, + const std::string& remoteprefix, const std::string& url) { CURL* curl; CURLcode res; @@ -465,6 +467,17 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, cmSystemTools::ComputeFileHash(local_file, cmCryptoHash::AlgoMD5); } + // Generate Done.xml right before it is submitted. + // The reason for this is two-fold: + // 1) It must be generated after some other part has been submitted + // so we have a buildId to refer to in its contents. + // 2) By generating Done.xml here its timestamp will be as late as + // possible. This gives us a more accurate record of how long the + // entire build took to complete. + if (file == "Done.xml") { + this->CTest->GenerateDoneFile(); + } + if (!cmSystemTools::FileExists(local_file)) { cmCTestLog(this->CTest, ERROR_MESSAGE, " Cannot find file: " << local_file << std::endl); @@ -646,6 +659,7 @@ void cmCTestSubmitHandler::ParseResponse( " Submission failed: " << parser.Message << std::endl); return; } + this->CTest->SetBuildID(parser.BuildID); } output = cmSystemTools::UpperCase(output); if (output.find("WARNING") != std::string::npos) { @@ -662,9 +676,9 @@ void cmCTestSubmitHandler::ParseResponse( } } -bool cmCTestSubmitHandler::TriggerUsingHTTP(const std::set<std::string>& files, - const std::string& remoteprefix, - const std::string& url) +bool cmCTestSubmitHandler::TriggerUsingHTTP( + const std::vector<std::string>& files, const std::string& remoteprefix, + const std::string& url) { CURL* curl; char error_buffer[1024]; @@ -792,11 +806,10 @@ bool cmCTestSubmitHandler::TriggerUsingHTTP(const std::set<std::string>& files, return true; } -bool cmCTestSubmitHandler::SubmitUsingSCP(const std::string& scp_command, - const std::string& localprefix, - const std::set<std::string>& files, - const std::string& remoteprefix, - const std::string& url) +bool cmCTestSubmitHandler::SubmitUsingSCP( + const std::string& scp_command, const std::string& localprefix, + const std::vector<std::string>& files, const std::string& remoteprefix, + const std::string& url) { if (scp_command.empty() || localprefix.empty() || files.empty() || remoteprefix.empty() || url.empty()) { @@ -890,7 +903,7 @@ bool cmCTestSubmitHandler::SubmitUsingSCP(const std::string& scp_command, } bool cmCTestSubmitHandler::SubmitUsingCP(const std::string& localprefix, - const std::set<std::string>& files, + const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& destination) { @@ -925,7 +938,7 @@ bool cmCTestSubmitHandler::SubmitUsingCP(const std::string& localprefix, #if defined(CTEST_USE_XMLRPC) bool cmCTestSubmitHandler::SubmitUsingXMLRPC( - const std::string& localprefix, const std::set<std::string>& files, + const std::string& localprefix, const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url) { xmlrpc_env env; @@ -1020,7 +1033,7 @@ bool cmCTestSubmitHandler::SubmitUsingXMLRPC( } #else bool cmCTestSubmitHandler::SubmitUsingXMLRPC( - std::string const& /*unused*/, std::set<std::string> const& /*unused*/, + std::string const& /*unused*/, std::vector<std::string> const& /*unused*/, std::string const& /*unused*/, std::string const& /*unused*/) { return false; @@ -1351,13 +1364,13 @@ int cmCTestSubmitHandler::ProcessHandler() cmGeneratedFileStream ofs; this->StartLogFile("Submit", ofs); - cmCTest::SetOfStrings files; + std::vector<std::string> files; std::string prefix = this->GetSubmitResultsPrefix(); if (!this->Files.empty()) { // Submit the explicitly selected files: // - files.insert(this->Files.begin(), this->Files.end()); + files.insert(files.end(), this->Files.begin(), this->Files.end()); } // Add to the list of files to submit from any selected, existing parts: @@ -1404,7 +1417,21 @@ int cmCTestSubmitHandler::ProcessHandler() // Submit files from this part. std::vector<std::string> const& pfiles = this->CTest->GetSubmitFiles(p); - files.insert(pfiles.begin(), pfiles.end()); + files.insert(files.end(), pfiles.begin(), pfiles.end()); + } + + // Make sure files are unique, but preserve order. + { + // This endPos intermediate is needed to work around non-conformant C++11 + // standard libraries that have erase(iterator,iterator) instead of + // erase(const_iterator,const_iterator). + size_t endPos = cmRemoveDuplicates(files) - files.cbegin(); + files.erase(files.begin() + endPos, files.end()); + } + + // Submit Done.xml last + if (this->SubmitPart[cmCTest::PartDone]) { + files.push_back("Done.xml"); } if (ofs) { diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index b4d0e77..66f2173 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -57,27 +57,27 @@ private: * Submit file using various ways */ bool SubmitUsingFTP(const std::string& localprefix, - const std::set<std::string>& files, + const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url); bool SubmitUsingHTTP(const std::string& localprefix, - const std::set<std::string>& files, + const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url); bool SubmitUsingSCP(const std::string& scp_command, const std::string& localprefix, - const std::set<std::string>& files, + const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url); bool SubmitUsingCP(const std::string& localprefix, - const std::set<std::string>& files, + const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url); - bool TriggerUsingHTTP(const std::set<std::string>& files, + bool TriggerUsingHTTP(const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url); bool SubmitUsingXMLRPC(const std::string& localprefix, - const std::set<std::string>& files, + const std::vector<std::string>& files, const std::string& remoteprefix, const std::string& url); diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index c936910..1d938e6 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -535,11 +535,21 @@ int cmCTestTestHandler::ProcessHandler() percent = 99; } + std::string passColorCode; + std::string failedColorCode; + if (failed.empty()) { + passColorCode = this->CTest->GetColorCode(cmCTest::Color::GREEN); + } else { + failedColorCode = this->CTest->GetColorCode(cmCTest::Color::RED); + } cmCTestLog(this->CTest, HANDLER_OUTPUT, std::endl - << static_cast<int>(percent + .5f) << "% tests passed, " - << failed.size() << " tests failed out of " << total - << std::endl); + << passColorCode << static_cast<int>(percent + .5f) + << "% tests passed" + << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) + << ", " << failedColorCode << failed.size() << " tests failed" + << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) + << " out of " << total << std::endl); if ((!this->CTest->GetLabelsForSubprojects().empty() && this->CTest->GetSubprojectSummary())) { this->PrintLabelOrSubprojectSummary(true); @@ -562,6 +572,8 @@ int cmCTestTestHandler::ProcessHandler() this->StartLogFile("TestsDisabled", ofs); const char* disabled_reason; + cmCTestLog(this->CTest, HANDLER_OUTPUT, + this->CTest->GetColorCode(cmCTest::Color::BLUE)); for (cmCTestTestResult const& dt : disabledTests) { ofs << dt.TestCount << ":" << dt.Name << std::endl; if (dt.CompletionStatus == "Disabled") { @@ -573,6 +585,8 @@ int cmCTestTestHandler::ProcessHandler() "\t" << std::setw(3) << dt.TestCount << " - " << dt.Name << " (" << disabled_reason << ")" << std::endl); } + cmCTestLog(this->CTest, HANDLER_OUTPUT, + this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR)); } if (!failed.empty()) { @@ -587,10 +601,17 @@ int cmCTestTestHandler::ProcessHandler() !cmHasLiteralPrefix(ft.CompletionStatus, "SKIP_RETURN_CODE=") && ft.CompletionStatus != "Disabled") { ofs << ft.TestCount << ":" << ft.Name << std::endl; - cmCTestLog(this->CTest, HANDLER_OUTPUT, - "\t" << std::setw(3) << ft.TestCount << " - " << ft.Name - << " (" << this->GetTestStatus(ft) << ")" - << std::endl); + auto testColor = cmCTest::Color::RED; + if (this->GetTestStatus(ft) == "Not Run") { + testColor = cmCTest::Color::YELLOW; + } + cmCTestLog( + this->CTest, HANDLER_OUTPUT, + "\t" << this->CTest->GetColorCode(testColor) << std::setw(3) + << ft.TestCount << " - " << ft.Name << " (" + << this->GetTestStatus(ft) << ")" + << this->CTest->GetColorCode(cmCTest::Color::CLEAR_COLOR) + << std::endl); } } } @@ -1725,7 +1746,7 @@ void cmCTestTestHandler::UseExcludeRegExp() this->UseExcludeRegExpFirst = !this->UseIncludeRegExpFlag; } -const char* cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result) +std::string cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result) { static const char* statuses[] = { "Not Run", "Timeout", "SEGFAULT", "ILLEGAL", "INTERRUPT", "NUMERICAL", @@ -1737,7 +1758,7 @@ const char* cmCTestTestHandler::GetTestStatus(cmCTestTestResult const& result) return "No Status"; } if (status == cmCTestTestHandler::OTHER_FAULT) { - return result.ExceptionStatus.c_str(); + return result.ExceptionStatus; } return statuses[status]; } diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index d2694a1..bcacf23 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -274,7 +274,7 @@ private: */ std::string FindTheExecutable(const char* exe); - const char* GetTestStatus(cmCTestTestResult const&); + std::string GetTestStatus(cmCTestTestResult const&); void ExpandTestsToRunInformation(size_t numPossibleTests); void ExpandTestsToRunInformationForRerunFailed(); diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx index 83dde3f..0722753 100644 --- a/Source/CTest/cmParseGTMCoverage.cxx +++ b/Source/CTest/cmParseGTMCoverage.cxx @@ -1,5 +1,6 @@ #include "cmParseGTMCoverage.h" +#include "cmAlgorithms.h" #include "cmCTest.h" #include "cmCTestCoverageHandler.h" #include "cmSystemTools.h" @@ -86,6 +87,10 @@ bool cmParseGTMCoverage::ReadMCovFile(const char* file) } // Find the full path to the file bool found = this->FindMumpsFile(routine, filepath); + if (!found && cmHasLiteralSuffix(routine, "%")) { + routine.erase(0, 1); + found = this->FindMumpsFile(routine, filepath); + } if (found) { int lineoffset = 0; if (this->FindFunctionInMumpsFile(filepath, function, lineoffset)) { @@ -192,8 +197,8 @@ bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line, done = true; } } else { - // all chars except ", (, and % get stored in the arg string - if (cur != '\"' && cur != '(' && cur != '%') { + // all chars except " and ( get stored in the arg string + if (cur != '\"' && cur != '(') { arg.append(1, line[pos]); } } diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx index 75bd6fb..75e5aa4 100644 --- a/Source/cmAddSubDirectoryCommand.cxx +++ b/Source/cmAddSubDirectoryCommand.cxx @@ -20,7 +20,7 @@ bool cmAddSubDirectoryCommand::InitialPass( } // store the binpath - std::string const& srcArg = args[0]; + std::string const& srcArg = args.front(); std::string binArg; bool excludeFromAll = false; @@ -84,10 +84,10 @@ bool cmAddSubDirectoryCommand::InitialPass( const std::string& bin = this->Makefile->GetCurrentBinaryDirectory(); size_t srcLen = src.length(); size_t binLen = bin.length(); - if (srcLen > 0 && src[srcLen - 1] == '/') { + if (srcLen > 0 && src.back() == '/') { --srcLen; } - if (binLen > 0 && bin[binLen - 1] == '/') { + if (binLen > 0 && bin.back() == '/') { --binLen; } binPath = bin.substr(0, binLen) + srcPath.substr(srcLen); diff --git a/Source/cmArchiveWrite.cxx b/Source/cmArchiveWrite.cxx index 6031781..3f2e784 100644 --- a/Source/cmArchiveWrite.cxx +++ b/Source/cmArchiveWrite.cxx @@ -178,7 +178,7 @@ bool cmArchiveWrite::Add(std::string path, size_t skip, const char* prefix, bool recursive) { if (this->Okay()) { - if (!path.empty() && path[path.size() - 1] == '/') { + if (!path.empty() && path.back() == '/') { path.erase(path.size() - 1); } this->AddPath(path.c_str(), skip, prefix, recursive); diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx index adf9ef8..3209ea5 100644 --- a/Source/cmCMakePolicyCommand.cxx +++ b/Source/cmCMakePolicyCommand.cxx @@ -46,6 +46,9 @@ bool cmCMakePolicyCommand::InitialPass(std::vector<std::string> const& args, if (args[0] == "VERSION") { return this->HandleVersionMode(args); } + if (args[0] == "GET_WARNING") { + return this->HandleGetWarningMode(args); + } std::ostringstream e; e << "given unknown first argument \"" << args[0] << "\""; @@ -181,3 +184,33 @@ bool cmCMakePolicyCommand::HandleVersionMode( this->Makefile->SetPolicyVersion(version_min, version_max); return true; } + +bool cmCMakePolicyCommand::HandleGetWarningMode( + std::vector<std::string> const& args) +{ + if (args.size() != 3) { + this->SetError( + "GET_WARNING must be given exactly 2 additional arguments."); + return false; + } + + // Get arguments. + std::string const& id = args[1]; + std::string const& var = args[2]; + + // Lookup the policy number. + cmPolicies::PolicyID pid; + if (!cmPolicies::GetPolicyID(id.c_str(), pid)) { + std::ostringstream e; + e << "GET_WARNING given policy \"" << id + << "\" which is not known to this version of CMake."; + this->SetError(e.str()); + return false; + } + + // Lookup the policy warning. + this->Makefile->AddDefinition(var, + cmPolicies::GetPolicyWarning(pid).c_str()); + + return true; +} diff --git a/Source/cmCMakePolicyCommand.h b/Source/cmCMakePolicyCommand.h index b18576c..cca1406 100644 --- a/Source/cmCMakePolicyCommand.h +++ b/Source/cmCMakePolicyCommand.h @@ -37,6 +37,7 @@ private: bool HandleSetMode(std::vector<std::string> const& args); bool HandleGetMode(std::vector<std::string> const& args); bool HandleVersionMode(std::vector<std::string> const& args); + bool HandleGetWarningMode(std::vector<std::string> const& args); }; #endif diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 908eea1..c2b6575 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -294,7 +294,9 @@ cmCTest::cmCTest() this->SuppressUpdatingCTestConfiguration = false; this->DartVersion = 1; this->DropSiteCDash = false; + this->BuildID = ""; this->OutputTestOutputOnTestFailure = false; + this->OutputColorCode = this->ColoredOutputSupportedByConsole(); this->RepeatTests = 1; // default to run each test once this->RepeatUntilFail = false; @@ -320,6 +322,7 @@ cmCTest::cmCTest() this->Parts[PartNotes].SetName("Notes"); this->Parts[PartExtraFiles].SetName("ExtraFiles"); this->Parts[PartUpload].SetName("Upload"); + this->Parts[PartDone].SetName("Done"); // Fill the part name-to-id map. for (Part p = PartStart; p != PartCount; p = Part(p + 1)) { @@ -612,6 +615,7 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command) std::string bld_dir = this->GetCTestConfiguration("BuildDirectory"); this->DartVersion = 1; this->DropSiteCDash = false; + this->BuildID = ""; for (Part p = PartStart; p != PartCount; p = Part(p + 1)) { this->Parts[p].SubmitFiles.clear(); } @@ -724,7 +728,7 @@ bool cmCTest::UpdateCTestConfiguration() if (line.empty()) { continue; } - while (fin && (line[line.size() - 1] == '\\')) { + while (fin && (line.back() == '\\')) { line = line.substr(0, line.size() - 1); buffer[0] = 0; fin.getline(buffer, 1023); @@ -1565,6 +1569,24 @@ int cmCTest::GenerateNotesFile(const char* cfiles) return this->GenerateNotesFile(files); } +int cmCTest::GenerateDoneFile() +{ + cmGeneratedFileStream ofs; + if (!this->OpenOutputFile(this->CurrentTag, "Done.xml", ofs)) { + cmCTestLog(this, ERROR_MESSAGE, "Cannot open done file" << std::endl); + return 1; + } + cmXMLWriter xml(ofs); + xml.StartDocument(); + xml.StartElement("Done"); + xml.Element("buildId", this->BuildID); + xml.Element("time", std::chrono::system_clock::now()); + xml.EndElement(); // Done + xml.EndDocument(); + + return 0; +} + std::string cmCTest::Base64GzipEncodeFile(std::string const& file) { std::string tarFile = file + "_temp.tar.gz"; @@ -2054,7 +2076,18 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, return true; } -bool cmCTest::ProgressOutputSupportedByConsole() const +#if !defined(_WIN32) +bool cmCTest::ConsoleIsNotDumb() +{ + std::string term_env_variable; + if (cmSystemTools::GetEnv("TERM", term_env_variable)) { + return isatty(1) && term_env_variable != "dumb"; + } + return false; +} +#endif + +bool cmCTest::ProgressOutputSupportedByConsole() { #if defined(_WIN32) // On Windows we need a console buffer. @@ -2063,12 +2096,19 @@ bool cmCTest::ProgressOutputSupportedByConsole() const return GetConsoleScreenBufferInfo(console, &csbi); #else // On UNIX we need a non-dumb tty. - std::string term_env_variable; - if (cmSystemTools::GetEnv("TERM", term_env_variable)) { - return isatty(1) && term_env_variable != "dumb"; - } + return ConsoleIsNotDumb(); #endif +} + +bool cmCTest::ColoredOutputSupportedByConsole() +{ +#if defined(_WIN32) + // Not supported on Windows return false; +#else + // On UNIX we need a non-dumb tty. + return ConsoleIsNotDumb(); +#endif } // handle the -S -SR and -SP arguments @@ -2554,7 +2594,7 @@ std::string cmCTest::GetShortPathToFile(const char* cfname) cmSystemTools::ConvertToUnixSlashes(*res); path = "./" + *res; - if (path[path.size() - 1] == '/') { + if (path.back() == '/') { path = path.substr(0, path.size() - 1); } } @@ -2937,6 +2977,20 @@ void cmCTest::Log(int logType, const char* file, int line, const char* msg, } } +std::string cmCTest::GetColorCode(Color color) const +{ + if (this->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 ""; +} + cmDuration cmCTest::GetRemainingTimeAllowed() { if (!this->GetHandler("script")) { diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 345b538..427049d 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -50,6 +50,7 @@ public: PartNotes, PartExtraFiles, PartUpload, + PartDone, PartCount // Update names in constructor when adding a part }; @@ -373,6 +374,9 @@ public: /** Create XML file that contains all the notes specified */ int GenerateNotesFile(const VectorOfStrings& files); + /** Create XML file to indicate that build is complete */ + int GenerateDoneFile(); + /** Submit extra files to the server */ bool SubmitExtraFiles(const char* files); bool SubmitExtraFiles(const VectorOfStrings& files); @@ -401,10 +405,27 @@ public: void Log(int logType, const char* file, int line, const char* msg, bool suppress = false); + /** Color values */ + enum class Color + { + CLEAR_COLOR = 0, + RED = 31, + GREEN = 32, + YELLOW = 33, + BLUE = 34 + }; + + /** Get color code characters for a specific color */ + std::string GetColorCode(Color color) const; + /** Get the version of dart server */ int GetDartVersion() { return this->DartVersion; } int GetDropSiteCDash() { return this->DropSiteCDash; } + /** The Build ID is assigned by CDash */ + void SetBuildID(const std::string& id) { this->BuildID = id; } + std::string GetBuildID() { return this->BuildID; } + /** Add file to be submitted */ void AddSubmitFile(Part part, const char* name); std::vector<std::string> const& GetSubmitFiles(Part part) @@ -567,8 +588,16 @@ private: bool HandleCommandLineArguments(size_t& i, std::vector<std::string>& args, std::string& errormsg); +#if !defined(_WIN32) /** returns true iff the console supports progress output */ - bool ProgressOutputSupportedByConsole() const; + static bool ConsoleIsNotDumb(); +#endif + + /** returns true iff the console supports progress output */ + static bool ProgressOutputSupportedByConsole(); + + /** returns true iff the console supports colored output */ + static bool ColoredOutputSupportedByConsole(); /** handle the -S -SP and -SR arguments */ void HandleScriptArguments(size_t& i, std::vector<std::string>& args, @@ -607,6 +636,8 @@ private: int DartVersion; bool DropSiteCDash; + std::string BuildID; + std::vector<std::string> InitialCommandLineArguments; int SubmitIndex; @@ -615,6 +646,7 @@ private: int OutputLogFileLastTag; bool OutputTestOutputOnTestFailure; + bool OutputColorCode; std::map<std::string, std::string> Definitions; }; diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index b391dc4..0305677 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -415,8 +415,7 @@ void cmCacheManager::OutputValueNoNewlines(std::ostream& fout, std::string const& value) { // if value has trailing space or tab, enclose it in single quotes - if (!value.empty() && - (value[value.size() - 1] == ' ' || value[value.size() - 1] == '\t')) { + if (!value.empty() && (value.back() == ' ' || value.back() == '\t')) { fout << '\'' << value << '\''; } else { fout << value; diff --git a/Source/cmComputeComponentGraph.cxx b/Source/cmComputeComponentGraph.cxx index a7dc1ca..5820df6 100644 --- a/Source/cmComputeComponentGraph.cxx +++ b/Source/cmComputeComponentGraph.cxx @@ -125,8 +125,8 @@ void cmComputeComponentGraph::TransferEdges() if (i_component != j_component) { // We do not attempt to combine duplicate edges, but instead // store the inter-component edges with suitable multiplicity. - this->ComponentGraph[i_component].emplace_back(j_component, - ni.IsStrong()); + this->ComponentGraph[i_component].emplace_back( + j_component, ni.IsStrong(), ni.GetBacktrace()); } } } diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index aa17de6..4717cf6 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -6,6 +6,7 @@ #include "cmComputeComponentGraph.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" @@ -419,7 +420,8 @@ void cmComputeLinkDepends::HandleSharedDependency(SharedDepEntry const& dep) // This shared library dependency must follow the item that listed // it. - this->EntryConstraintGraph[dep.DependerIndex].push_back(index); + this->EntryConstraintGraph[dep.DependerIndex].emplace_back( + index, true, cmListFileBacktrace()); // Target items may have their own dependencies. if (entry.Target) { @@ -522,7 +524,8 @@ void cmComputeLinkDepends::AddLinkEntries(int depender_index, // The dependee must come after the depender. if (depender_index >= 0) { - this->EntryConstraintGraph[depender_index].push_back(dependee_index); + this->EntryConstraintGraph[depender_index].emplace_back( + dependee_index, false, cmListFileBacktrace()); } else { // This is a direct dependency of the target being linked. this->OriginalEntries.push_back(dependee_index); @@ -565,7 +568,7 @@ cmLinkItem cmComputeLinkDepends::ResolveLinkItem(int depender_index, from = depender; } } - return from->ResolveLinkItem(name); + return from->ResolveLinkItem(name, cmListFileBacktrace()); } void cmComputeLinkDepends::InferDependencies() @@ -594,7 +597,10 @@ void cmComputeLinkDepends::InferDependencies() // Add the inferred dependencies to the graph. cmGraphEdgeList& edges = this->EntryConstraintGraph[depender_index]; - edges.insert(edges.end(), common.begin(), common.end()); + edges.reserve(edges.size() + common.size()); + for (auto const& c : common) { + edges.emplace_back(c, true, cmListFileBacktrace()); + } } } diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 0e48ca8..27b8599 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -421,7 +421,8 @@ std::string cmComputeLinkInformation::GetRPathLinkString() const return ""; } - // Construct the linker runtime search path. + // Construct the linker runtime search path. These MUST NOT contain tokens + // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936 return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":"); } @@ -1702,6 +1703,14 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") && this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH"); + // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree. + std::string const& originToken = this->Makefile->GetSafeDefinition( + "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN"); + std::string targetOutputDir = this->Target->GetDirectory(this->Config); + bool use_relative_build_rpath = + this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") && + !originToken.empty() && !targetOutputDir.empty(); + // Construct the RPATH. std::set<std::string> emitted; if (use_install_rpath) { @@ -1711,6 +1720,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, if (use_build_rpath) { // Add directories explicitly specified by user if (const char* build_rpath = this->Target->GetProperty("BUILD_RPATH")) { + // This will not resolve entries to use $ORIGIN, the user is expected to + // do that if necessary. cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted); } } @@ -1728,6 +1739,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); cmSystemTools::ConvertToUnixSlashes(rootPath); std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath(); + std::string const& topBinaryDir = + this->CMakeInstance->GetHomeOutputDirectory(); for (std::string const& ri : rdirs) { // Put this directory in the rpath if using build-tree rpath // support or if using the link path as an rpath. @@ -1741,6 +1754,18 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, d += "/"; d += suffix; cmSystemTools::ConvertToUnixSlashes(d); + } else if (use_relative_build_rpath) { + // If expansion of the $ORIGIN token is supported and permitted per + // policy, use relative paths in the RPATH. + if (cmSystemTools::ComparePath(d, topBinaryDir) || + cmSystemTools::IsSubDirectory(d, topBinaryDir)) { + d = cmSystemTools::RelativePath(targetOutputDir, d); + if (!d.empty()) { + d = originToken + "/" + d; + } else { + d = originToken; + } + } } if (emitted.insert(d).second) { runtimeDirs.push_back(std::move(d)); @@ -1749,8 +1774,6 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, // Do not add any path inside the source or build tree. std::string const& topSourceDir = this->CMakeInstance->GetHomeDirectory(); - std::string const& topBinaryDir = - this->CMakeInstance->GetHomeOutputDirectory(); if (!cmSystemTools::ComparePath(ri, topSourceDir) && !cmSystemTools::ComparePath(ri, topBinaryDir) && !cmSystemTools::IsSubDirectory(ri, topSourceDir) && diff --git a/Source/cmComputeTargetDepends.cxx b/Source/cmComputeTargetDepends.cxx index 268e749..f8ac333 100644 --- a/Source/cmComputeTargetDepends.cxx +++ b/Source/cmComputeTargetDepends.cxx @@ -6,6 +6,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLinkItem.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmPolicies.h" @@ -22,8 +23,6 @@ #include <stdio.h> #include <utility> -class cmListFileBacktrace; - /* This class is meant to analyze inter-target dependencies globally @@ -152,6 +151,7 @@ void cmComputeTargetDepends::GetTargetDirectDepends(cmGeneratorTarget const* t, cmGeneratorTarget const* dep = this->Targets[ni]; cmTargetDependSet::iterator di = deps.insert(dep).first; di->SetType(ni.IsStrong()); + di->SetBacktrace(ni.GetBacktrace()); } } @@ -208,7 +208,8 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) for (cmSourceFile const* o : objectFiles) { std::string const& objLib = o->GetObjectLibrary(); if (!objLib.empty()) { - cmLinkItem const& objItem = depender->ResolveLinkItem(objLib); + cmLinkItem const& objItem = + depender->ResolveLinkItem(objLib, cmListFileBacktrace()); if (emitted.insert(objItem).second) { if (depender->GetType() != cmStateEnums::EXECUTABLE && depender->GetType() != cmStateEnums::STATIC_LIBRARY && @@ -230,7 +231,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) cmLinkImplementation const* impl = depender->GetLinkImplementation(it); // A target should not depend on itself. - emitted.insert(cmLinkItem(depender)); + emitted.insert(cmLinkItem(depender, cmListFileBacktrace())); for (cmLinkImplItem const& lib : impl->Libraries) { // Don't emit the same library twice for this target. if (emitted.insert(lib).second) { @@ -246,7 +247,7 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) std::set<cmLinkItem> const& tutils = depender->GetUtilityItems(); std::set<cmLinkItem> emitted; // A target should not depend on itself. - emitted.insert(cmLinkItem(depender)); + emitted.insert(cmLinkItem(depender, cmListFileBacktrace())); for (cmLinkItem const& litem : tutils) { // Don't emit the same utility twice for this target. if (emitted.insert(litem).second) { @@ -258,7 +259,8 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index) void cmComputeTargetDepends::AddInterfaceDepends( int depender_index, const cmGeneratorTarget* dependee, - const std::string& config, std::set<cmLinkItem>& emitted) + cmListFileBacktrace const& dependee_backtrace, const std::string& config, + std::set<cmLinkItem>& emitted) { cmGeneratorTarget const* depender = this->Targets[depender_index]; if (cmLinkInterface const* iface = @@ -266,8 +268,13 @@ void cmComputeTargetDepends::AddInterfaceDepends( for (cmLinkItem const& lib : iface->Libraries) { // Don't emit the same library twice for this target. if (emitted.insert(lib).second) { - this->AddTargetDepend(depender_index, lib, true); - this->AddInterfaceDepends(depender_index, lib, config, emitted); + // Inject the backtrace of the original link dependency whose + // link interface we are adding. This indicates the line of + // code in the project that caused this dependency to be added. + cmLinkItem libBT = lib; + libBT.Backtrace = dependee_backtrace; + this->AddTargetDepend(depender_index, libBT, true); + this->AddInterfaceDepends(depender_index, libBT, config, emitted); } } } @@ -289,8 +296,9 @@ void cmComputeTargetDepends::AddInterfaceDepends( if (dependee) { // A target should not depend on itself. - emitted.insert(cmLinkItem(depender)); - this->AddInterfaceDepends(depender_index, dependee, config, emitted); + emitted.insert(cmLinkItem(depender, cmListFileBacktrace())); + this->AddInterfaceDepends(depender_index, dependee, + dependee_name.Backtrace, config, emitted); } } @@ -327,13 +335,7 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, e << "The dependency target \"" << dependee_name << "\" of target \"" << depender->GetName() << "\" does not exist."; - cmListFileBacktrace const* backtrace = - depender->GetUtilityBacktrace(dependee_name.AsStr()); - if (backtrace) { - cm->IssueMessage(messageType, e.str(), *backtrace); - } else { - cm->IssueMessage(messageType, e.str()); - } + cm->IssueMessage(messageType, e.str(), dependee_name.Backtrace); } } @@ -346,13 +348,14 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, } if (dependee) { - this->AddTargetDepend(depender_index, dependee, linking); + this->AddTargetDepend(depender_index, dependee, dependee_name.Backtrace, + linking); } } -void cmComputeTargetDepends::AddTargetDepend(int depender_index, - const cmGeneratorTarget* dependee, - bool linking) +void cmComputeTargetDepends::AddTargetDepend( + int depender_index, cmGeneratorTarget const* dependee, + cmListFileBacktrace const& dependee_backtrace, bool linking) { if (dependee->IsImported() || dependee->GetType() == cmStateEnums::INTERFACE_LIBRARY) { @@ -361,7 +364,8 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, std::set<cmLinkItem> const& utils = dependee->GetUtilityItems(); for (cmLinkItem const& i : utils) { if (cmGeneratorTarget const* transitive_dependee = i.Target) { - this->AddTargetDepend(depender_index, transitive_dependee, false); + this->AddTargetDepend(depender_index, transitive_dependee, i.Backtrace, + false); } } } else { @@ -373,7 +377,8 @@ void cmComputeTargetDepends::AddTargetDepend(int depender_index, int dependee_index = tii->second; // Add this entry to the dependency graph. - this->InitialGraph[depender_index].emplace_back(dependee_index, !linking); + this->InitialGraph[depender_index].emplace_back(dependee_index, !linking, + dependee_backtrace); } } @@ -507,7 +512,7 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap, for (cmGraphEdge const& edge : el) { int j = edge; if (cmap[j] == c && edge.IsStrong()) { - this->FinalGraph[i].emplace_back(j, true); + this->FinalGraph[i].emplace_back(j, true, edge.GetBacktrace()); if (!this->IntraComponent(cmap, c, j, head, emitted, visited)) { return false; } @@ -516,7 +521,7 @@ bool cmComputeTargetDepends::IntraComponent(std::vector<int> const& cmap, // Prepend to a linear linked-list of intra-component edges. if (*head >= 0) { - this->FinalGraph[i].emplace_back(*head, false); + this->FinalGraph[i].emplace_back(*head, false, cmListFileBacktrace()); } else { this->ComponentTail[c] = i; } @@ -567,7 +572,7 @@ bool cmComputeTargetDepends::ComputeFinalDepends( int dependee_component = ni; int dependee_component_head = this->ComponentHead[dependee_component]; this->FinalGraph[depender_component_tail].emplace_back( - dependee_component_head, ni.IsStrong()); + dependee_component_head, ni.IsStrong(), ni.GetBacktrace()); } } return true; diff --git a/Source/cmComputeTargetDepends.h b/Source/cmComputeTargetDepends.h index 3046e8a..3840bd7 100644 --- a/Source/cmComputeTargetDepends.h +++ b/Source/cmComputeTargetDepends.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmGraphAdjacencyList.h" +#include "cmListFileCache.h" #include <map> #include <set> @@ -47,6 +48,7 @@ private: void AddTargetDepend(int depender_index, cmLinkItem const& dependee_name, bool linking); void AddTargetDepend(int depender_index, cmGeneratorTarget const* dependee, + cmListFileBacktrace const& dependee_backtrace, bool linking); bool ComputeFinalDepends(cmComputeComponentGraph const& ccg); void AddInterfaceDepends(int depender_index, cmLinkItem const& dependee_name, @@ -54,6 +56,7 @@ private: std::set<cmLinkItem>& emitted); void AddInterfaceDepends(int depender_index, cmGeneratorTarget const* dependee, + cmListFileBacktrace const& dependee_backtrace, const std::string& config, std::set<cmLinkItem>& emitted); cmGlobalGenerator* GlobalGenerator; diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 172ef92..3b4206f 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -495,6 +495,12 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, argP1->GetValue().operator[](argP1len - 1) == '}') { std::string env = argP1->GetValue().substr(4, argP1len - 5); bdef = cmSystemTools::HasEnv(env); + } else if (argP1len > 6 && + argP1->GetValue().substr(0, 6) == "CACHE{" && + argP1->GetValue().operator[](argP1len - 1) == '}') { + std::string cache = argP1->GetValue().substr(6, argP1len - 7); + bdef = + this->Makefile.GetState()->GetCacheEntryValue(cache) != nullptr; } else { bdef = this->Makefile.IsDefinitionSet(argP1->GetValue()); } diff --git a/Source/cmConfigureFileCommand.cxx b/Source/cmConfigureFileCommand.cxx index b5a639a..305262d 100644 --- a/Source/cmConfigureFileCommand.cxx +++ b/Source/cmConfigureFileCommand.cxx @@ -20,11 +20,8 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args, } std::string const& inFile = args[0]; - if (!cmSystemTools::FileIsFullPath(inFile)) { - this->InputFile = this->Makefile->GetCurrentSourceDirectory(); - this->InputFile += "/"; - } - this->InputFile += inFile; + this->InputFile = cmSystemTools::CollapseFullPath( + inFile, this->Makefile->GetCurrentSourceDirectory()); // If the input location is a directory, error out. if (cmSystemTools::FileIsDirectory(this->InputFile)) { @@ -39,11 +36,8 @@ bool cmConfigureFileCommand::InitialPass(std::vector<std::string> const& args, } std::string const& outFile = args[1]; - if (!cmSystemTools::FileIsFullPath(outFile)) { - this->OutputFile = this->Makefile->GetCurrentBinaryDirectory(); - this->OutputFile += "/"; - } - this->OutputFile += outFile; + this->OutputFile = cmSystemTools::CollapseFullPath( + outFile, this->Makefile->GetCurrentBinaryDirectory()); // If the output location is already a directory put the file in it. if (cmSystemTools::FileIsDirectory(this->OutputFile)) { diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index cfd260c..e87eb1e 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -4,16 +4,6 @@ #include "cmMakefile.h" -cmCustomCommand::cmCustomCommand() - : Backtrace() -{ - this->HaveComment = false; - this->EscapeOldStyle = true; - this->EscapeAllowMakeVars = false; - this->UsesTerminal = false; - this->CommandExpandLists = false; -} - cmCustomCommand::cmCustomCommand(cmMakefile const* mf, const std::vector<std::string>& outputs, const std::vector<std::string>& byproducts, diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 9e82f25..d82160b 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -22,9 +22,6 @@ class cmMakefile; class cmCustomCommand { public: - /** Default and copy constructors for STL containers. */ - cmCustomCommand(); - /** Main constructor specifies all information for the command. */ cmCustomCommand(cmMakefile const* mf, const std::vector<std::string>& outputs, @@ -103,11 +100,11 @@ private: std::string Comment; std::string WorkingDirectory; std::string Depfile; - bool HaveComment; - bool EscapeAllowMakeVars; - bool EscapeOldStyle; - bool UsesTerminal; - bool CommandExpandLists; + bool HaveComment = false; + bool EscapeAllowMakeVars = false; + bool EscapeOldStyle = true; + bool UsesTerminal = false; + bool CommandExpandLists = false; }; #endif diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 34f58ad..87ee382 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -976,9 +976,9 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const lg->GetIndividualFileTargets(objectFileTargets); for (std::string const& f : objectFileTargets) { const char* prefix = "[obj] "; - if (f[f.length() - 1] == 's') { + if (f.back() == 's') { prefix = "[to asm] "; - } else if (f[f.length() - 1] == 'i') { + } else if (f.back() == 'i') { prefix = "[pre] "; } this->AppendTarget(xml, f, make, makeArgs, subdir, prefix); @@ -1035,8 +1035,7 @@ std::string cmExtraEclipseCDT4Generator::GetPathBasename( { std::string outputBasename = path; while (!outputBasename.empty() && - (outputBasename[outputBasename.size() - 1] == '/' || - outputBasename[outputBasename.size() - 1] == '\\')) { + (outputBasename.back() == '/' || outputBasename.back() == '\\')) { outputBasename.resize(outputBasename.size() - 1); } std::string::size_type loc = outputBasename.find_last_of("/\\"); diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx index f5c4c93..9410690 100644 --- a/Source/cmExtraKateGenerator.cxx +++ b/Source/cmExtraKateGenerator.cxx @@ -294,8 +294,7 @@ std::string cmExtraKateGenerator::GetPathBasename( { std::string outputBasename = path; while (!outputBasename.empty() && - (outputBasename[outputBasename.size() - 1] == '/' || - outputBasename[outputBasename.size() - 1] == '\\')) { + (outputBasename.back() == '/' || outputBasename.back() == '\\')) { outputBasename.resize(outputBasename.size() - 1); } std::string::size_type loc = outputBasename.find_last_of("/\\"); diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index c4cca07..882d39f 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -384,13 +384,8 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target, language); - // Add the export symbol definition for shared library objects. - if (const char* exportMacro = target->GetExportMacro()) { - lg->AppendDefines(defines, exportMacro); - } - // Add preprocessor definitions for this target and configuration. - lg->AddCompileDefinitions(defines, target, config, language); + lg->GetTargetDefines(target, config, language, defines); const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); if (const char* compile_defs = source->GetProperty(COMPILE_DEFINITIONS)) { lg->AppendDefines( diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 1f76703..f86e5e2 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -2525,7 +2525,7 @@ bool cmFileCommand::HandleCMakePathCommand( // remove double quotes in the path std::string& s = *j; - if (s.size() > 1 && s[0] == '\"' && s[s.size() - 1] == '\"') { + if (s.size() > 1 && s.front() == '\"' && s.back() == '\"') { s = s.substr(1, s.size() - 2); } } diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index 865595b..425546a 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -129,13 +129,13 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn) this->VariableDocumentation += "the (unknown) library be found"; } else if (this->Names.size() == 1) { this->VariableDocumentation += - "the " + this->Names[0] + " library be found"; + "the " + this->Names.front() + " library be found"; } else { this->VariableDocumentation += "one of the "; this->VariableDocumentation += cmJoin(cmMakeRange(this->Names).retreat(1), ", "); this->VariableDocumentation += - " or " + this->Names[this->Names.size() - 1] + " libraries be found"; + " or " + this->Names.back() + " libraries be found"; } } diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index fbaacfc..009f0e3 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -293,13 +293,13 @@ void cmFindCommon::AddPathSuffix(std::string const& arg) if (suffix.empty()) { return; } - if (suffix[0] == '/') { + if (suffix.front() == '/') { suffix = suffix.substr(1); } if (suffix.empty()) { return; } - if (suffix[suffix.size() - 1] == '/') { + if (suffix.back() == '/') { suffix = suffix.substr(0, suffix.size() - 1); } if (suffix.empty()) { diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 96de6ad..bf928fc 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -111,6 +111,8 @@ cmFindPackageCommand::cmFindPackageCommand() this->SortOrder = None; this->SortDirection = Asc; this->AppendSearchPathGroups(); + + this->DeprecatedFindModules["Qt"] = cmPolicies::CMP0084; } void cmFindPackageCommand::AppendSearchPathGroups() @@ -653,8 +655,31 @@ bool cmFindPackageCommand::FindModule(bool& found) std::string module = "Find"; module += this->Name; module += ".cmake"; - std::string mfile = this->Makefile->GetModulesFile(module.c_str()); + bool system = false; + std::string mfile = this->Makefile->GetModulesFile(module.c_str(), system); if (!mfile.empty()) { + if (system) { + auto it = this->DeprecatedFindModules.find(this->Name); + if (it != this->DeprecatedFindModules.end()) { + cmPolicies::PolicyStatus status = + this->Makefile->GetPolicyStatus(it->second); + switch (status) { + case cmPolicies::WARN: { + std::ostringstream e; + e << cmPolicies::GetPolicyWarning(it->second) << "\n"; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str()); + CM_FALLTHROUGH; + } + case cmPolicies::OLD: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + return true; + } + } + } + // Load the module we found, and set "<name>_FIND_MODULE" to true // while inside it. found = true; @@ -1429,7 +1454,7 @@ void cmFindPackageCommand::FillPrefixesUserHints() bool cmFindPackageCommand::SearchDirectory(std::string const& dir) { - assert(!dir.empty() && dir[dir.size() - 1] == '/'); + assert(!dir.empty() && dir.back() == '/'); // Check each path suffix on this directory. for (std::string const& s : this->SearchPathSuffixes) { @@ -1447,7 +1472,7 @@ bool cmFindPackageCommand::SearchDirectory(std::string const& dir) bool cmFindPackageCommand::CheckDirectory(std::string const& dir) { - assert(!dir.empty() && dir[dir.size() - 1] == '/'); + assert(!dir.empty() && dir.back() == '/'); // Look for the file in this directory. std::string d = dir.substr(0, dir.size() - 1); @@ -2001,7 +2026,7 @@ private: bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { - assert(!prefix_in.empty() && prefix_in[prefix_in.size() - 1] == '/'); + assert(!prefix_in.empty() && prefix_in.back() == '/'); if (this->DebugMode) { fprintf(stderr, "Checking prefix [%s]\n", prefix_in.c_str()); } @@ -2157,7 +2182,7 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in) { - assert(!prefix_in.empty() && prefix_in[prefix_in.size() - 1] == '/'); + assert(!prefix_in.empty() && prefix_in.back() == '/'); if (this->DebugMode) { fprintf(stderr, "Checking framework prefix [%s]\n", prefix_in.c_str()); } @@ -2218,7 +2243,7 @@ bool cmFindPackageCommand::SearchFrameworkPrefix(std::string const& prefix_in) bool cmFindPackageCommand::SearchAppBundlePrefix(std::string const& prefix_in) { - assert(!prefix_in.empty() && prefix_in[prefix_in.size() - 1] == '/'); + assert(!prefix_in.empty() && prefix_in.back() == '/'); if (this->DebugMode) { fprintf(stderr, "Checking bundle prefix [%s]\n", prefix_in.c_str()); } diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 48f17ef..05bad49 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -4,6 +4,7 @@ #define cmFindPackageCommand_h #include "cmConfigure.h" // IWYU pragma: keep +#include "cmPolicies.h" #include "cm_kwiml.h" #include <cstddef> @@ -148,6 +149,8 @@ private: }; std::map<std::string, OriginalDef> OriginalDefs; + std::map<std::string, cmPolicies::PolicyID> DeprecatedFindModules; + std::string Name; std::string Variable; std::string Version; diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx index 8d57441..56eb2bf 100644 --- a/Source/cmGeneratorExpressionDAGChecker.cxx +++ b/Source/cmGeneratorExpressionDAGChecker.cxx @@ -166,6 +166,18 @@ bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression() return top->Property == "TARGET_GENEX_EVAL" || top->Property == "GENEX_EVAL"; } +bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression() +{ + const cmGeneratorExpressionDAGChecker* top = this; + const cmGeneratorExpressionDAGChecker* parent = this->Parent; + while (parent) { + top = parent; + parent = parent->Parent; + } + + return top->Property == "INTERFACE_POSITION_INDEPENDENT_CODE"; +} + bool cmGeneratorExpressionDAGChecker::EvaluatingLinkLibraries( cmGeneratorTarget const* tgt) { diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index a5134c3..1525c39 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -66,6 +66,7 @@ struct cmGeneratorExpressionDAGChecker const std::string& expr); bool EvaluatingGenexExpression(); + bool EvaluatingPICExpression(); bool EvaluatingLinkLibraries(cmGeneratorTarget const* tgt = nullptr); #define DECLARE_TRANSITIVE_PROPERTY_METHOD(METHOD) bool METHOD() const; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index f901215..49b97fb 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -1225,7 +1225,8 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode const char* prop = target->GetProperty(propertyName); if (dagCheckerParent) { - if (dagCheckerParent->EvaluatingGenexExpression()) { + if (dagCheckerParent->EvaluatingGenexExpression() || + dagCheckerParent->EvaluatingPICExpression()) { // No check required. } else if (dagCheckerParent->EvaluatingLinkLibraries()) { #define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \ diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 5c294f8..0b28d1e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -439,7 +439,7 @@ static void handleSystemIncludesDep( KindedSources const& kinded = this->GetKindedSources(config); \ for (SourceAndKind const& s : kinded.Sources) { \ if (s.Kind == KIND) { \ - data.push_back(s.Source); \ + data.push_back(s.Source.Value); \ } \ } \ } @@ -495,6 +495,36 @@ const char* cmGeneratorTarget::GetFeature(const std::string& feature, return this->LocalGenerator->GetFeature(feature, config); } +const char* cmGeneratorTarget::GetLinkPIEProperty( + const std::string& config) const +{ + static std::string PICValue; + + PICValue = this->GetLinkInterfaceDependentStringAsBoolProperty( + "POSITION_INDEPENDENT_CODE", config); + + if (PICValue == "(unset)") { + // POSITION_INDEPENDENT_CODE is not set + return nullptr; + } + + switch (this->GetPolicyStatusCMP0083()) { + case cmPolicies::WARN: { + std::ostringstream e; + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0083); + this->LocalGenerator->IssueMessage(cmake::AUTHOR_WARNING, e.str()); + CM_FALLTHROUGH; + } + case cmPolicies::OLD: + return nullptr; + default: + // nothing to do + break; + } + + return PICValue.c_str(); +} + bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang, std::string const& config) const { @@ -674,13 +704,13 @@ std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const { if (!this->UtilityItemsDone) { this->UtilityItemsDone = true; - std::set<std::string> const& utilities = this->GetUtilities(); - for (std::string const& i : utilities) { + std::set<BT<std::string>> const& utilities = this->GetUtilities(); + for (BT<std::string> const& i : utilities) { if (cmGeneratorTarget* gt = - this->LocalGenerator->FindGeneratorTargetToUse(i)) { - this->UtilityItems.insert(cmLinkItem(gt)); + this->LocalGenerator->FindGeneratorTargetToUse(i.Value)) { + this->UtilityItems.insert(cmLinkItem(gt, i.Backtrace)); } else { - this->UtilityItems.insert(cmLinkItem(i)); + this->UtilityItems.insert(cmLinkItem(i.Value, i.Backtrace)); } } } @@ -865,7 +895,8 @@ static void AddObjectEntries( static bool processSources( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& srcs, std::unordered_set<std::string>& uniqueSrcs, + std::vector<BT<std::string>>& srcs, + std::unordered_set<std::string>& uniqueSrcs, cmGeneratorExpressionDAGChecker* dagChecker, std::string const& config, bool debugSources) { @@ -916,7 +947,7 @@ static bool processSources( std::string usedSources; for (std::string const& src : entrySources) { if (uniqueSrcs.insert(src).second) { - srcs.push_back(src); + srcs.emplace_back(src, entry->ge->GetBacktrace()); if (debugSources) { usedSources += " * " + src + "\n"; } @@ -933,9 +964,10 @@ static bool processSources( return contextDependent; } -void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files, - const std::string& config) const +std::vector<BT<std::string>> cmGeneratorTarget::GetSourceFilePaths( + std::string const& config) const { + std::vector<BT<std::string>> files; assert(this->GetType() != cmStateEnums::INTERFACE_LIBRARY); if (!this->LocalGenerator->GetGlobalGenerator()->GetConfigureDoneCMP0026()) { @@ -951,13 +983,13 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files, cmSystemTools::ExpandListArgument(entry, items); for (std::string const& item : items) { if (cmHasLiteralPrefix(item, "$<TARGET_OBJECTS:") && - item[item.size() - 1] == '>') { + item.back() == '>') { continue; } files.push_back(item); } } - return; + return files; } std::vector<std::string> debugProperties; @@ -1009,11 +1041,23 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files, cmDeleteAll(linkInterfaceSourcesEntries); cmDeleteAll(linkObjectsEntries); + return files; } void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, const std::string& config) const { + std::vector<BT<cmSourceFile*>> tmp = this->GetSourceFiles(config); + files.reserve(tmp.size()); + for (BT<cmSourceFile*>& v : tmp) { + files.push_back(v.Value); + } +} + +std::vector<BT<cmSourceFile*>> cmGeneratorTarget::GetSourceFiles( + std::string const& config) const +{ + std::vector<BT<cmSourceFile*>> files; if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) { // Since we are still configuring not all sources may exist yet, // so we need to avoid full source classification because that @@ -1021,16 +1065,15 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, // Since this is only for compatibility with old policies that // projects should not depend on anymore, just compute the files // without memoizing them. - std::vector<std::string> srcs; - this->GetSourceFiles(srcs, config); + std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config); std::set<cmSourceFile*> emitted; - for (std::string const& s : srcs) { - cmSourceFile* sf = this->Makefile->GetOrCreateSource(s); + for (BT<std::string> const& s : srcs) { + cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value); if (emitted.insert(sf).second) { - files.push_back(sf); + files.emplace_back(sf, s.Backtrace); } } - return; + return files; } KindedSources const& kinded = this->GetKindedSources(config); @@ -1038,18 +1081,33 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files, for (SourceAndKind const& si : kinded.Sources) { files.push_back(si.Source); } + return files; } void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries( std::vector<cmSourceFile*>& files, const std::string& config) const { + std::vector<BT<cmSourceFile*>> tmp = + this->GetSourceFilesWithoutObjectLibraries(config); + files.reserve(tmp.size()); + for (BT<cmSourceFile*>& v : tmp) { + files.push_back(v.Value); + } +} + +std::vector<BT<cmSourceFile*>> +cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries( + std::string const& config) const +{ + std::vector<BT<cmSourceFile*>> files; KindedSources const& kinded = this->GetKindedSources(config); files.reserve(kinded.Sources.size()); for (SourceAndKind const& si : kinded.Sources) { - if (si.Source->GetObjectLibrary().empty()) { + if (si.Source.Value->GetObjectLibrary().empty()) { files.push_back(si.Source); } } + return files; } cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources( @@ -1089,16 +1147,15 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, std::string const& config) const { // Get the source file paths by string. - std::vector<std::string> srcs; - this->GetSourceFiles(srcs, config); + std::vector<BT<std::string>> srcs = this->GetSourceFilePaths(config); cmsys::RegularExpression header_regex(CM_HEADER_REGEX); std::vector<cmSourceFile*> badObjLib; std::set<cmSourceFile*> emitted; - for (std::string const& s : srcs) { + for (BT<std::string> const& s : srcs) { // Create each source at most once. - cmSourceFile* sf = this->Makefile->GetOrCreateSource(s); + cmSourceFile* sf = this->Makefile->GetOrCreateSource(s.Value); if (!emitted.insert(sf).second) { continue; } @@ -1161,7 +1218,7 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files, } // Save this classified source file in the result vector. - files.Sources.push_back({ sf, kind }); + files.Sources.push_back({ BT<cmSourceFile*>(sf, s.Backtrace), kind }); } if (!badObjLib.empty()) { @@ -1197,14 +1254,14 @@ void cmGeneratorTarget::ComputeAllConfigSources() const KindedSources const& sources = this->GetKindedSources(configs[ci]); for (SourceAndKind const& src : sources.Sources) { std::map<cmSourceFile const*, size_t>::iterator mi = - index.find(src.Source); + index.find(src.Source.Value); if (mi == index.end()) { AllConfigSource acs; - acs.Source = src.Source; + acs.Source = src.Source.Value; acs.Kind = src.Kind; this->AllConfigSources.push_back(std::move(acs)); std::map<cmSourceFile const*, size_t>::value_type entry( - src.Source, this->AllConfigSources.size() - 1); + src.Source.Value, this->AllConfigSources.size() - 1); mi = index.insert(entry).first; } this->AllConfigSources[mi->second].Configs.push_back(ci); @@ -1710,17 +1767,11 @@ cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const return this->Target->GetBacktrace(); } -const std::set<std::string>& cmGeneratorTarget::GetUtilities() const +const std::set<BT<std::string>>& cmGeneratorTarget::GetUtilities() const { return this->Target->GetUtilities(); } -const cmListFileBacktrace* cmGeneratorTarget::GetUtilityBacktrace( - const std::string& u) const -{ - return this->Target->GetUtilityBacktrace(u); -} - bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const { return this->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -1730,7 +1781,7 @@ bool cmGeneratorTarget::HaveWellDefinedOutputFiles() const this->GetType() == cmStateEnums::EXECUTABLE; } -const char* cmGeneratorTarget::GetExportMacro() const +const std::string* cmGeneratorTarget::GetExportMacro() const { // Define the symbol for targets that export symbols. if (this->GetType() == cmStateEnums::SHARED_LIBRARY || @@ -1743,7 +1794,7 @@ const char* cmGeneratorTarget::GetExportMacro() const in += "_EXPORTS"; this->ExportMacro = cmSystemTools::MakeCidentifier(in); } - return this->ExportMacro.c_str(); + return &this->ExportMacro; } return nullptr; } @@ -2480,7 +2531,7 @@ std::string cmGeneratorTarget::GetCreateRuleVariable( static void processIncludeDirectories( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& includes, + std::vector<BT<std::string>>& includes, std::unordered_set<std::string>& uniqueIncludes, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugIncludes, const std::string& language) @@ -2572,7 +2623,7 @@ static void processIncludeDirectories( std::string inc = entryInclude; if (uniqueIncludes.insert(inc).second) { - includes.push_back(inc); + includes.emplace_back(inc, entry->ge->GetBacktrace()); if (debugIncludes) { usedIncludes += " * " + inc + "\n"; } @@ -2588,10 +2639,10 @@ static void processIncludeDirectories( } } -std::vector<std::string> cmGeneratorTarget::GetIncludeDirectories( +std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( const std::string& config, const std::string& lang) const { - std::vector<std::string> includes; + std::vector<BT<std::string>> includes; std::unordered_set<std::string> uniqueIncludes; cmGeneratorExpressionDAGChecker dagChecker(this, "INCLUDE_DIRECTORIES", @@ -2661,7 +2712,7 @@ enum class OptionsParse static void processOptionsInternal( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugOptions, const char* logName, std::string const& language, @@ -2678,9 +2729,13 @@ static void processOptionsInternal( if (uniqueOptions.insert(opt).second) { if (parse == OptionsParse::Shell && cmHasLiteralPrefix(opt, "SHELL:")) { - cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, options); + std::vector<std::string> tmp; + cmSystemTools::ParseUnixCommandLine(opt.c_str() + 6, tmp); + for (std::string& o : tmp) { + options.emplace_back(std::move(o), entry->ge->GetBacktrace()); + } } else { - options.push_back(opt); + options.emplace_back(opt, entry->ge->GetBacktrace()); } if (debugOptions) { usedOptions += " * " + opt + "\n"; @@ -2700,7 +2755,7 @@ static void processOptionsInternal( static void processCompileOptions( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugOptions, std::string const& language) @@ -2714,6 +2769,17 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const { + std::vector<BT<std::string>> tmp = this->GetCompileOptions(config, language); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( + std::string const& config, std::string const& language) const +{ + std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_OPTIONS", nullptr, @@ -2749,12 +2815,13 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, language); cmDeleteAll(linkInterfaceCompileOptionsEntries); + return result; } static void processCompileFeatures( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugOptions) @@ -2767,6 +2834,17 @@ static void processCompileFeatures( void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result, const std::string& config) const { + std::vector<BT<std::string>> tmp = this->GetCompileFeatures(config); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetCompileFeatures( + std::string const& config) const +{ + std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueFeatures; cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_FEATURES", nullptr, @@ -2799,12 +2877,13 @@ void cmGeneratorTarget::GetCompileFeatures(std::vector<std::string>& result, uniqueFeatures, &dagChecker, config, debugFeatures); cmDeleteAll(linkInterfaceCompileFeaturesEntries); + return result; } static void processCompileDefinitions( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugOptions, std::string const& language) @@ -2815,9 +2894,21 @@ static void processCompileDefinitions( } void cmGeneratorTarget::GetCompileDefinitions( - std::vector<std::string>& list, const std::string& config, + std::vector<std::string>& result, const std::string& config, const std::string& language) const { + std::vector<BT<std::string>> tmp = + this->GetCompileDefinitions(config, language); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( + std::string const& config, std::string const& language) const +{ + std::vector<BT<std::string>> list; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "COMPILE_DEFINITIONS", @@ -2878,13 +2969,14 @@ void cmGeneratorTarget::GetCompileDefinitions( language); cmDeleteAll(linkInterfaceCompileDefinitionsEntries); + return list; } namespace { void processLinkOptions( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugOptions, std::string const& language) @@ -2899,6 +2991,17 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const { + std::vector<BT<std::string>> tmp = this->GetLinkOptions(config, language); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( + std::string const& config, std::string const& language) const +{ + std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_OPTIONS", nullptr, @@ -2952,21 +3055,24 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, const std::string SHELL{ "SHELL:" }; const std::string LINKER_SHELL = LINKER + SHELL; - std::vector<std::string>::iterator entry; + std::vector<BT<std::string>>::iterator entry; while ((entry = std::find_if(result.begin(), result.end(), - [&LINKER](const std::string& item) -> bool { - return item.compare(0, LINKER.length(), - LINKER) == 0; + [&LINKER](BT<std::string> const& item) -> bool { + return item.Value.compare(0, LINKER.length(), + LINKER) == 0; })) != result.end()) { + std::string value = std::move(entry->Value); + cmListFileBacktrace bt = std::move(entry->Backtrace); + entry = result.erase(entry); + std::vector<std::string> linkerOptions; - if (entry->compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) { + if (value.compare(0, LINKER_SHELL.length(), LINKER_SHELL) == 0) { cmSystemTools::ParseUnixCommandLine( - entry->c_str() + LINKER_SHELL.length(), linkerOptions); + value.c_str() + LINKER_SHELL.length(), linkerOptions); } else { linkerOptions = - cmSystemTools::tokenize(entry->substr(LINKER.length()), ","); + cmSystemTools::tokenize(value.substr(LINKER.length()), ","); } - entry = result.erase(entry); if (linkerOptions.empty() || (linkerOptions.size() == 1 && linkerOptions.front().empty())) { @@ -2982,56 +3088,64 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, cmake::FATAL_ERROR, "'SHELL:' prefix is not supported as part of 'LINKER:' arguments.", this->GetBacktrace()); - return; + return result; } + std::vector<BT<std::string>> options; if (wrapperFlag.empty()) { // nothing specified, insert elements as is - result.insert(entry, linkerOptions.begin(), linkerOptions.end()); + options.reserve(linkerOptions.size()); + for (std::string& o : linkerOptions) { + options.emplace_back(std::move(o), bt); + } } else { - std::vector<std::string> options; - if (!wrapperSep.empty()) { if (concatFlagAndArgs) { // insert flag elements except last one - options.insert(options.end(), wrapperFlag.begin(), - wrapperFlag.end() - 1); + for (auto i = wrapperFlag.begin(); i != wrapperFlag.end() - 1; ++i) { + options.emplace_back(*i, bt); + } // concatenate last flag element and all LINKER list values // in one option - options.push_back(wrapperFlag.back() + - cmJoin(linkerOptions, wrapperSep)); + options.emplace_back( + wrapperFlag.back() + cmJoin(linkerOptions, wrapperSep), bt); } else { - options.insert(options.end(), wrapperFlag.begin(), - wrapperFlag.end()); + for (std::string const& i : wrapperFlag) { + options.emplace_back(i, bt); + } // concatenate all LINKER list values in one option - options.push_back(cmJoin(linkerOptions, wrapperSep)); + options.emplace_back(cmJoin(linkerOptions, wrapperSep), bt); } } else { // prefix each element of LINKER list with wrapper if (concatFlagAndArgs) { - std::transform( - linkerOptions.begin(), linkerOptions.end(), linkerOptions.begin(), - [&wrapperFlag](const std::string& value) -> std::string { - return wrapperFlag.back() + value; - }); + std::transform(linkerOptions.begin(), linkerOptions.end(), + linkerOptions.begin(), + [&wrapperFlag](std::string const& o) -> std::string { + return wrapperFlag.back() + o; + }); } - for (const auto& value : linkerOptions) { - options.insert(options.end(), wrapperFlag.begin(), - concatFlagAndArgs ? wrapperFlag.end() - 1 - : wrapperFlag.end()); - options.push_back(value); + for (std::string& o : linkerOptions) { + for (auto i = wrapperFlag.begin(), + e = concatFlagAndArgs ? wrapperFlag.end() - 1 + : wrapperFlag.end(); + i != e; ++i) { + options.emplace_back(*i, bt); + } + options.emplace_back(std::move(o), bt); } } - result.insert(entry, options.begin(), options.end()); } + result.insert(entry, options.begin(), options.end()); } + return result; } namespace { void processStaticLibraryLinkOptions( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, std::string const& language) @@ -3046,6 +3160,18 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions( std::vector<std::string>& result, const std::string& config, const std::string& language) const { + std::vector<BT<std::string>> tmp = + this->GetStaticLibraryLinkOptions(config, language); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( + std::string const& config, std::string const& language) const +{ + std::vector<BT<std::string>> result; std::vector<cmGeneratorTarget::TargetPropertyEntry*> entries; std::unordered_set<std::string> uniqueOptions; @@ -3066,13 +3192,14 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions( &dagChecker, config, language); cmDeleteAll(entries); + return result; } namespace { void processLinkDirectories( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& directories, + std::vector<BT<std::string>>& directories, std::unordered_set<std::string>& uniqueDirectories, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, bool debugDirectories, std::string const& language) @@ -3151,6 +3278,18 @@ void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result, const std::string& config, const std::string& language) const { + std::vector<BT<std::string>> tmp = + this->GetLinkDirectories(config, language); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( + std::string const& config, std::string const& language) const +{ + std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueDirectories; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr, @@ -3186,13 +3325,14 @@ void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result, debugDirectories, language); cmDeleteAll(linkInterfaceLinkDirectoriesEntries); + return result; } namespace { void processLinkDepends( cmGeneratorTarget const* tgt, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, - std::vector<std::string>& options, + std::vector<BT<std::string>>& options, std::unordered_set<std::string>& uniqueOptions, cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config, std::string const& language) @@ -3207,6 +3347,17 @@ void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result, const std::string& config, const std::string& language) const { + std::vector<BT<std::string>> tmp = this->GetLinkDepends(config, language); + result.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + result.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( + std::string const& config, std::string const& language) const +{ + std::vector<BT<std::string>> result; std::vector<cmGeneratorTarget::TargetPropertyEntry*> linkDependsEntries; std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DEPENDS", nullptr, @@ -3228,6 +3379,7 @@ void cmGeneratorTarget::GetLinkDepends(std::vector<std::string>& result, &dagChecker, config, language); cmDeleteAll(linkDependsEntries); + return result; } void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const @@ -3293,10 +3445,9 @@ void cmGeneratorTarget::ComputeTargetManifest(const std::string& config) const bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const { - std::vector<std::string> features; - this->GetCompileFeatures(features, config); - for (std::string const& f : features) { - if (!this->Makefile->AddRequiredTargetFeature(this->Target, f)) { + std::vector<BT<std::string>> features = this->GetCompileFeatures(config); + for (BT<std::string> const& f : features) { + if (!this->Makefile->AddRequiredTargetFeature(this->Target, f.Value)) { return false; } } @@ -4116,6 +4267,29 @@ void cmGeneratorTarget::CheckPropertyCompatibility( } } +template <typename PropertyType> +std::string valueAsString(PropertyType); +template <> +std::string valueAsString<bool>(bool value) +{ + return value ? "TRUE" : "FALSE"; +} +template <> +std::string valueAsString<const char*>(const char* value) +{ + return value ? value : "(unset)"; +} +template <> +std::string valueAsString<std::string>(std::string value) +{ + return value; +} +template <> +std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/) +{ + return "(unset)"; +} + std::string compatibilityType(CompatibleType t) { switch (t) { @@ -4147,34 +4321,49 @@ std::string compatibilityAgree(CompatibleType t, bool dominant) } template <typename PropertyType> -PropertyType getTypedProperty(cmGeneratorTarget const* tgt, - const std::string& prop); +PropertyType getTypedProperty( + cmGeneratorTarget const* tgt, const std::string& prop, + cmGeneratorExpressionInterpreter* genexInterpreter = nullptr); template <> bool getTypedProperty<bool>(cmGeneratorTarget const* tgt, - const std::string& prop) + const std::string& prop, + cmGeneratorExpressionInterpreter* genexInterpreter) { - return tgt->GetPropertyAsBool(prop); -} + if (genexInterpreter == nullptr) { + return tgt->GetPropertyAsBool(prop); + } -template <> -const char* getTypedProperty<const char*>(cmGeneratorTarget const* tgt, - const std::string& prop) -{ - return tgt->GetProperty(prop); + const char* value = tgt->GetProperty(prop); + return cmSystemTools::IsOn(genexInterpreter->Evaluate(value, prop)); } -template <typename PropertyType> -std::string valueAsString(PropertyType); template <> -std::string valueAsString<bool>(bool value) +const char* getTypedProperty<const char*>( + cmGeneratorTarget const* tgt, const std::string& prop, + cmGeneratorExpressionInterpreter* genexInterpreter) { - return value ? "TRUE" : "FALSE"; + const char* value = tgt->GetProperty(prop); + + if (genexInterpreter == nullptr) { + return value; + } + + return genexInterpreter->Evaluate(value, prop).c_str(); } + template <> -std::string valueAsString<const char*>(const char* value) +std::string getTypedProperty<std::string>( + cmGeneratorTarget const* tgt, const std::string& prop, + cmGeneratorExpressionInterpreter* genexInterpreter) { - return value ? value : "(unset)"; + const char* value = tgt->GetProperty(prop); + + if (genexInterpreter == nullptr) { + return valueAsString(value); + } + + return genexInterpreter->Evaluate(value, prop); } template <typename PropertyType> @@ -4189,6 +4378,12 @@ const char* impliedValue<const char*>(const char* /*unused*/) { return ""; } +template <> +std::string impliedValue<std::string>( + std::string /*unused*/) // NOLINT(clang-tidy) +{ + return std::string(); +} template <typename PropertyType> std::pair<bool, PropertyType> consistentProperty(PropertyType lhs, @@ -4209,6 +4404,13 @@ std::pair<bool, const char*> consistentStringProperty(const char* lhs, return std::make_pair(b, b ? lhs : nullptr); } +std::pair<bool, std::string> consistentStringProperty(const std::string& lhs, + const std::string& rhs) +{ + const bool b = lhs == rhs; + return std::make_pair(b, b ? lhs : valueAsString(nullptr)); +} + std::pair<bool, const char*> consistentNumberProperty(const char* lhs, const char* rhs, CompatibleType t) @@ -4251,9 +4453,10 @@ std::pair<bool, const char*> consistentProperty(const char* lhs, const char* const null_ptr = nullptr; switch (t) { - case BoolType: - assert(false && "consistentProperty for strings called with BoolType"); - return std::pair<bool, const char*>(false, null_ptr); + case BoolType: { + bool same = cmSystemTools::IsOn(lhs) == cmSystemTools::IsOn(rhs); + return std::make_pair(same, same ? lhs : nullptr); + } case StringType: return consistentStringProperty(lhs, rhs); case NumberMinType: @@ -4264,6 +4467,40 @@ std::pair<bool, const char*> consistentProperty(const char* lhs, return std::pair<bool, const char*>(false, null_ptr); } +std::pair<bool, std::string> consistentProperty(const std::string& lhs, + const std::string& rhs, + CompatibleType t) +{ + const std::string null_ptr = valueAsString(nullptr); + + if (lhs == null_ptr && rhs == null_ptr) { + return std::make_pair(true, lhs); + } + if (lhs == null_ptr) { + return std::make_pair(true, rhs); + } + if (rhs == null_ptr) { + return std::make_pair(true, lhs); + } + + switch (t) { + case BoolType: { + bool same = cmSystemTools::IsOn(lhs) == cmSystemTools::IsOn(rhs); + return std::make_pair(same, same ? lhs : null_ptr); + } + case StringType: + return consistentStringProperty(lhs, rhs); + case NumberMinType: + case NumberMaxType: { + auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t); + return std::make_pair( + value.first, value.first ? std::string(value.second) : null_ptr); + } + } + assert(false && "Unreachable!"); + return std::pair<bool, std::string>(false, null_ptr); +} + template <typename PropertyType> PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, const std::string& p, @@ -4273,6 +4510,7 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, PropertyType* /*unused*/) { PropertyType propContent = getTypedProperty<PropertyType>(tgt, p); + std::vector<std::string> headPropKeys = tgt->GetPropertyKeys(); const bool explicitlySet = std::find(headPropKeys.begin(), headPropKeys.end(), p) != @@ -4302,6 +4540,11 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, } std::string interfaceProperty = "INTERFACE_" + p; + std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter( + p == "POSITION_INDEPENDENT_CODE" ? new cmGeneratorExpressionInterpreter( + tgt->GetLocalGenerator(), config, tgt) + : nullptr); + for (cmGeneratorTarget const* theTarget : deps) { // An error should be reported if one dependency // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other @@ -4313,8 +4556,8 @@ PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt, const bool ifaceIsSet = std::find(propKeys.begin(), propKeys.end(), interfaceProperty) != propKeys.end(); - PropertyType ifacePropContent = - getTypedProperty<PropertyType>(theTarget, interfaceProperty); + PropertyType ifacePropContent = getTypedProperty<PropertyType>( + theTarget, interfaceProperty, genexInterpreter.get()); std::string reportEntry; if (ifaceIsSet) { @@ -4412,6 +4655,13 @@ bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty( BoolType, nullptr); } +std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty( + const std::string& p, const std::string& config) const +{ + return checkInterfacePropertyCompatibility<std::string>( + this, p, config, "FALSE", BoolType, nullptr); +} + const char* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty( const std::string& p, const std::string& config) const { @@ -4618,6 +4868,7 @@ void cmGeneratorTarget::ReportPropertyOrigin( } void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, + cmListFileBacktrace const& bt, std::vector<cmLinkItem>& items) const { for (std::string const& n : names) { @@ -4625,7 +4876,7 @@ void cmGeneratorTarget::LookupLinkItems(std::vector<std::string> const& names, if (name == this->GetName() || name.empty()) { continue; } - items.push_back(this->ResolveLinkItem(name)); + items.push_back(this->ResolveLinkItem(name, bt)); } } @@ -4647,7 +4898,7 @@ void cmGeneratorTarget::ExpandLinkItems( false, headTarget, this, &dagChecker), libs); - this->LookupLinkItems(libs, items); + this->LookupLinkItems(libs, cge->GetBacktrace(), items); hadHeadSensitiveCondition = cge->GetHadHeadSensitiveCondition(); } @@ -5200,7 +5451,7 @@ const cmLinkInterface* cmGeneratorTarget::GetImportLinkInterface( iface.HadHeadSensitiveCondition); std::vector<std::string> deps; cmSystemTools::ExpandListArgument(info->SharedDeps, deps); - this->LookupLinkItems(deps, iface.SharedDeps); + this->LookupLinkItems(deps, cmListFileBacktrace(), iface.SharedDeps); } return &iface; @@ -5490,8 +5741,7 @@ void cmGeneratorTarget::GetObjectLibrariesCMP0026( std::vector<std::string> files; cmSystemTools::ExpandListArgument(entry, files); for (std::string const& li : files) { - if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && - li[li.size() - 1] == '>') { + if (cmHasLiteralPrefix(li, "$<TARGET_OBJECTS:") && li.back() == '>') { std::string objLibName = li.substr(17, li.size() - 18); if (cmGeneratorExpression::Find(objLibName) != std::string::npos) { @@ -5739,7 +5989,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( } // The entry is meant for this configuration. - impl.Libraries.emplace_back(this->ResolveLinkItem(name), *btIt, + impl.Libraries.emplace_back(this->ResolveLinkItem(name, *btIt), evaluated != *le); } @@ -5767,7 +6017,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( continue; } // Support OLD behavior for CMP0003. - impl.WrongConfigLibraries.push_back(this->ResolveLinkItem(name)); + impl.WrongConfigLibraries.push_back( + this->ResolveLinkItem(name, cmListFileBacktrace())); } } } @@ -5814,12 +6065,13 @@ cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference( return resolved; } -cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name) const +cmLinkItem cmGeneratorTarget::ResolveLinkItem( + std::string const& name, cmListFileBacktrace const& bt) const { TargetOrString resolved = this->ResolveTargetReference(name); if (!resolved.Target) { - return cmLinkItem(resolved.String); + return cmLinkItem(resolved.String, bt); } // Skip targets that will not really be linked. This is probably a @@ -5827,10 +6079,10 @@ cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name) const // within the project. if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE && !resolved.Target->IsExecutableWithExports()) { - return cmLinkItem(resolved.Target->GetName()); + return cmLinkItem(resolved.Target->GetName(), bt); } - return cmLinkItem(resolved.Target); + return cmLinkItem(resolved.Target, bt); } std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 5ed8e5a..52defee 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -75,8 +75,8 @@ public: bool GetPropertyAsBool(const std::string& prop) const; void GetSourceFiles(std::vector<cmSourceFile*>& files, const std::string& config) const; - void GetSourceFilesWithoutObjectLibraries(std::vector<cmSourceFile*>& files, - const std::string& config) const; + std::vector<BT<cmSourceFile*>> GetSourceFiles( + std::string const& config) const; /** Source file kinds (classifications). Generators use this to decide how to treat a source file. */ @@ -99,7 +99,7 @@ public: /** A source file paired with a kind (classification). */ struct SourceAndKind { - cmSourceFile* Source; + BT<cmSourceFile*> Source; SourceKind Kind; }; @@ -173,6 +173,8 @@ public: const char* GetFeature(const std::string& feature, const std::string& config) const; + const char* GetLinkPIEProperty(const std::string& config) const; + bool IsIPOEnabled(std::string const& lang, std::string const& config) const; bool IsLinkInterfaceDependentBoolProperty(const std::string& p, @@ -273,8 +275,7 @@ public: cmListFileBacktrace GetBacktrace() const; - std::set<std::string> const& GetUtilities() const; - cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const; + std::set<BT<std::string>> const& GetUtilities() const; bool LinkLanguagePropagatesToDependents() const { @@ -283,7 +284,7 @@ public: /** Get the macro to define when building sources in this target. If no macro should be defined null is returned. */ - const char* GetExportMacro() const; + const std::string* GetExportMacro() const; /** Get the soname of the target. Allowed only for a shared library. */ std::string GetSOName(const std::string& config) const; @@ -362,7 +363,8 @@ public: }; TargetOrString ResolveTargetReference(std::string const& name) const; - cmLinkItem ResolveLinkItem(std::string const& name) const; + cmLinkItem ResolveLinkItem(std::string const& name, + cmListFileBacktrace const& bt) const; // Compute the set of languages compiled by the target. This is // computed every time it is called because the languages can change @@ -408,34 +410,49 @@ public: std::string const& config) const; /** Get the include directories for this target. */ - std::vector<std::string> GetIncludeDirectories( + std::vector<BT<std::string>> GetIncludeDirectories( const std::string& config, const std::string& lang) const; void GetCompileOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const; + std::vector<BT<std::string>> GetCompileOptions( + std::string const& config, std::string const& language) const; void GetCompileFeatures(std::vector<std::string>& features, const std::string& config) const; + std::vector<BT<std::string>> GetCompileFeatures( + std::string const& config) const; void GetCompileDefinitions(std::vector<std::string>& result, const std::string& config, const std::string& language) const; + std::vector<BT<std::string>> GetCompileDefinitions( + std::string const& config, std::string const& language) const; void GetLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const; + std::vector<BT<std::string>> GetLinkOptions( + std::string const& config, std::string const& language) const; + void GetStaticLibraryLinkOptions(std::vector<std::string>& result, const std::string& config, const std::string& language) const; + std::vector<BT<std::string>> GetStaticLibraryLinkOptions( + std::string const& config, std::string const& language) const; void GetLinkDirectories(std::vector<std::string>& result, const std::string& config, const std::string& language) const; + std::vector<BT<std::string>> GetLinkDirectories( + std::string const& config, std::string const& language) const; void GetLinkDepends(std::vector<std::string>& result, const std::string& config, const std::string& language) const; + std::vector<BT<std::string>> GetLinkDepends( + std::string const& config, std::string const& language) const; bool IsSystemIncludeDirectory(const std::string& dir, const std::string& config, @@ -774,6 +791,9 @@ private: cmHeadToLinkInterfaceMap& GetHeadToLinkInterfaceUsageRequirementsMap( std::string const& config) const; + std::string GetLinkInterfaceDependentStringAsBoolProperty( + const std::string& p, const std::string& config) const; + // Cache import information from properties for each configuration. struct ImportInfo { @@ -834,10 +854,15 @@ private: std::vector<cmLinkItem>& items, bool& hadHeadSensitiveCondition) const; void LookupLinkItems(std::vector<std::string> const& names, + cmListFileBacktrace const& bt, std::vector<cmLinkItem>& items) const; - void GetSourceFiles(std::vector<std::string>& files, - const std::string& config) const; + std::vector<BT<std::string>> GetSourceFilePaths( + std::string const& config) const; + std::vector<BT<cmSourceFile*>> GetSourceFilesWithoutObjectLibraries( + std::string const& config) const; + void GetSourceFilesWithoutObjectLibraries(std::vector<cmSourceFile*>& files, + const std::string& config) const; struct HeadToLinkImplementationMap : public std::map<cmGeneratorTarget const*, cmOptionalLinkImplementation> diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx index 1b358ab..ffb895e 100644 --- a/Source/cmGetFilenameComponentCommand.cxx +++ b/Source/cmGetFilenameComponentCommand.cxx @@ -19,8 +19,8 @@ bool cmGetFilenameComponentCommand::InitialPass( // Check and see if the value has been stored in the cache // already, if so use that value - if (args.size() >= 4 && args[args.size() - 1] == "CACHE") { - const char* cacheValue = this->Makefile->GetDefinition(args[0]); + if (args.size() >= 4 && args.back() == "CACHE") { + const char* cacheValue = this->Makefile->GetDefinition(args.front()); if (cacheValue && !cmSystemTools::IsNOTFOUND(cacheValue)) { return true; } @@ -113,20 +113,20 @@ bool cmGetFilenameComponentCommand::InitialPass( return false; } - if (args.size() >= 4 && args[args.size() - 1] == "CACHE") { + if (args.size() >= 4 && args.back() == "CACHE") { if (!programArgs.empty() && !storeArgs.empty()) { this->Makefile->AddCacheDefinition( storeArgs, programArgs.c_str(), "", args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING); } this->Makefile->AddCacheDefinition( - args[0], result.c_str(), "", + args.front(), result.c_str(), "", args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING); } else { if (!programArgs.empty() && !storeArgs.empty()) { this->Makefile->AddDefinition(storeArgs, programArgs.c_str()); } - this->Makefile->AddDefinition(args[0], result.c_str()); + this->Makefile->AddDefinition(args.front(), result.c_str()); } return true; diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 847230a..4d98d55 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -267,14 +267,9 @@ std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language, if (i == this->DefinesByLanguage.end()) { std::set<std::string> defines; const char* lang = language.c_str(); - // Add the export symbol definition for shared library objects. - if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) { - this->LocalGenerator->AppendDefines(defines, exportMacro); - } - // Add preprocessor definitions for this target and configuration. - this->LocalGenerator->AddCompileDefinitions(defines, this->GeneratorTarget, - config, language); + this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config, + language, defines); std::string definesString; this->LocalGenerator->JoinDefines(defines, definesString, lang); diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 71e844e..2805395 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -34,8 +34,6 @@ #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmPolicies.h" -#include "cmQtAutoGen.h" -#include "cmQtAutoGenInitializer.h" #include "cmSourceFile.h" #include "cmState.h" #include "cmStateDirectory.h" @@ -46,6 +44,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include "cmCryptoHash.h" +# include "cmQtAutoGenGlobalInitializer.h" # include "cm_jsoncpp_value.h" # include "cm_jsoncpp_writer.h" #endif @@ -1469,64 +1468,11 @@ bool cmGlobalGenerator::ComputeTargetDepends() bool cmGlobalGenerator::QtAutoGen() { #ifdef CMAKE_BUILD_WITH_CMAKE - std::vector<std::unique_ptr<cmQtAutoGenInitializer>> autogenInits; - - for (cmLocalGenerator* localGen : this->LocalGenerators) { - const std::vector<cmGeneratorTarget*>& targets = - localGen->GetGeneratorTargets(); - // Find targets that require AUTOGEN processing - for (cmGeneratorTarget* target : targets) { - if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { - continue; - } - if (target->GetType() != cmStateEnums::EXECUTABLE && - target->GetType() != cmStateEnums::STATIC_LIBRARY && - target->GetType() != cmStateEnums::SHARED_LIBRARY && - target->GetType() != cmStateEnums::MODULE_LIBRARY && - target->GetType() != cmStateEnums::OBJECT_LIBRARY) { - continue; - } - if (target->IsImported()) { - continue; - } - - const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); - const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); - const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); - if (!mocEnabled && !uicEnabled && !rccEnabled) { - continue; - } - - auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target); - // don't do anything if there is no Qt4 or Qt5Core (which contains moc) - if (qtVersion.Major != 4 && qtVersion.Major != 5) { - continue; - } - - autogenInits.emplace_back(cm::make_unique<cmQtAutoGenInitializer>( - target, mocEnabled, uicEnabled, rccEnabled, qtVersion)); - } - } - - if (!autogenInits.empty()) { - // Initialize custom targets - for (auto& autoGen : autogenInits) { - if (!autoGen->InitCustomTargets()) { - return false; - } - } - - // Setup custom targets - for (auto& autoGen : autogenInits) { - if (!autoGen->SetupCustomTargets()) { - return false; - } - autoGen.reset(nullptr); - } - } -#endif - + cmQtAutoGenGlobalInitializer initializer(this->LocalGenerators); + return initializer.generate(); +#else return true; +#endif } cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer( @@ -2265,7 +2211,7 @@ bool cmGlobalGenerator::NameResolvesToFramework( inline std::string removeQuotes(const std::string& s) { - if (s[0] == '\"' && s[s.size() - 1] == '\"') { + if (s.front() == '\"' && s.back() == '\"') { return s.substr(1, s.size() - 2); } return s; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index f513403..fbc756c 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -19,6 +19,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpressionEvaluationFile.h" #include "cmGeneratorTarget.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -837,7 +838,7 @@ static void EnsureTrailingSlash(std::string& path) if (path.empty()) { return; } - std::string::value_type last = path[path.size() - 1]; + std::string::value_type last = path.back(); #ifdef _WIN32 if (last != '\\') { path += '\\'; @@ -1008,10 +1009,11 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( { if (target->GetType() == cmStateEnums::GLOBAL_TARGET) { // These depend only on other CMake-provided targets, e.g. "all". - std::set<std::string> const& utils = target->GetUtilities(); - for (std::string const& util : utils) { + std::set<BT<std::string>> const& utils = target->GetUtilities(); + for (BT<std::string> const& util : utils) { std::string d = - target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" + util; + target->GetLocalGenerator()->GetCurrentBinaryDirectory() + "/" + + util.Value; outputs.push_back(this->ConvertToNinjaPath(d)); } } else { diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index ba12fac..3be09b0 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -159,7 +159,7 @@ void cmGlobalVisualStudio71Generator::WriteProjectDepends( // executables to the libraries it uses are also done here void cmGlobalVisualStudio71Generator::WriteExternalProject( std::ostream& fout, const std::string& name, const char* location, - const char* typeGuid, const std::set<std::string>& depends) + const char* typeGuid, const std::set<BT<std::string>>& depends) { fout << "Project(\"{" << (typeGuid ? typeGuid : this->ExternalProjectType(location)) @@ -171,9 +171,10 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject( // project instead of in the global section if (!depends.empty()) { fout << "\tProjectSection(ProjectDependencies) = postProject\n"; - for (std::string const& it : depends) { - if (!it.empty()) { - fout << "\t\t{" << this->GetGUID(it) << "} = {" << this->GetGUID(it) + for (BT<std::string> const& it : depends) { + std::string const& dep = it.Value; + if (!dep.empty()) { + fout << "\t\t{" << this->GetGUID(dep) << "} = {" << this->GetGUID(dep) << "}\n"; } } diff --git a/Source/cmGlobalVisualStudio71Generator.h b/Source/cmGlobalVisualStudio71Generator.h index 054c342..b6e3131 100644 --- a/Source/cmGlobalVisualStudio71Generator.h +++ b/Source/cmGlobalVisualStudio71Generator.h @@ -33,7 +33,7 @@ protected: const std::string& platformMapping = "") override; void WriteExternalProject(std::ostream& fout, const std::string& name, const char* path, const char* typeGuid, - const std::set<std::string>& depends) override; + const std::set<BT<std::string>>& depends) override; void WriteSLNHeader(std::ostream& fout) override; // Folders are not supported by VS 7.1. diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 0c9dd88..251478d 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -145,7 +145,7 @@ protected: virtual void WriteExternalProject( std::ostream& fout, const std::string& name, const char* path, - const char* typeGuid, const std::set<std::string>& dependencies) = 0; + const char* typeGuid, const std::set<BT<std::string>>& dependencies) = 0; std::string ConvertToSolutionPath(const char* path); diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index ba138c2..b155d9c 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -315,9 +315,9 @@ bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies( cmGeneratorTarget* target) { // Look for utility dependencies that magically link. - for (std::string const& ui : target->GetUtilities()) { + for (BT<std::string> const& ui : target->GetUtilities()) { if (cmGeneratorTarget* depTarget = - target->GetLocalGenerator()->FindGeneratorTargetToUse(ui)) { + target->GetLocalGenerator()->FindGeneratorTargetToUse(ui.Value)) { if (depTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY && depTarget->GetProperty("EXTERNAL_MSPROJECT")) { // This utility dependency names an external .vcproj target. diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index e353a37..8a38f9b 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -546,7 +546,7 @@ void cmGlobalXCodeGenerator::AddExtraTargets( target->GetType() == cmStateEnums::STATIC_LIBRARY || target->GetType() == cmStateEnums::SHARED_LIBRARY || target->GetType() == cmStateEnums::MODULE_LIBRARY))) { - makeHelper[makeHelper.size() - 1] = // fill placeholder + makeHelper.back() = // fill placeholder this->PostBuildMakeTarget(target->GetName(), "$(CONFIGURATION)"); cmCustomCommandLines commandLines; commandLines.push_back(makeHelper); @@ -1755,6 +1755,26 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( } } +void cmGlobalXCodeGenerator::AddPositionIndependentLinkAttribute( + cmGeneratorTarget* target, cmXCodeObject* buildSettings, + const std::string& configName) +{ + // For now, only EXECUTABLE is concerned + if (target->GetType() != cmStateEnums::EXECUTABLE) { + return; + } + + const char* PICValue = target->GetLinkPIEProperty(configName); + if (PICValue == nullptr) { + // POSITION_INDEPENDENT_CODE is not set + return; + } + + buildSettings->AddAttribute( + "LD_NO_PIE", + this->CreateString(cmSystemTools::IsOn(PICValue) ? "NO" : "YES")); +} + void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, cmXCodeObject* buildSettings, const std::string& configName) @@ -1806,6 +1826,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("LLVM_LTO", this->CreateString(ltoValue)); } + // Handle PIE linker configuration + this->AddPositionIndependentLinkAttribute(gtgt, buildSettings, configName); + // Add define flags this->CurrentLocalGenerator->AppendFlags( defFlags, this->CurrentMakefile->GetDefineFlags()); @@ -1814,9 +1837,9 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, BuildObjectListOrString ppDefs(this, true); this->AppendDefines( ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\""); - if (const char* exportMacro = gtgt->GetExportMacro()) { + if (const std::string* exportMacro = gtgt->GetExportMacro()) { // Add the export symbol definition for shared library objects. - this->AppendDefines(ppDefs, exportMacro); + this->AppendDefines(ppDefs, exportMacro->c_str()); } std::vector<std::string> targetDefines; if (!langForPreprocessor.empty()) { diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 62f7030..9b0d4fe 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -171,6 +171,9 @@ private: const std::string& configName); cmXCodeObject* CreateUtilityTarget(cmGeneratorTarget* gtgt); void AddDependAndLinkInformation(cmXCodeObject* target); + void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target, + cmXCodeObject* buildSettings, + const std::string& configName); void CreateBuildSettings(cmGeneratorTarget* gtgt, cmXCodeObject* buildSettings, const std::string& buildType); diff --git a/Source/cmGraphAdjacencyList.h b/Source/cmGraphAdjacencyList.h index 6a0a799..fb2eee2 100644 --- a/Source/cmGraphAdjacencyList.h +++ b/Source/cmGraphAdjacencyList.h @@ -5,6 +5,8 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmListFileCache.h" + #include <vector> /** @@ -15,18 +17,22 @@ class cmGraphEdge { public: - cmGraphEdge(int n = 0, bool s = true) + cmGraphEdge(int n, bool s, cmListFileBacktrace const& bt) : Dest(n) , Strong(s) + , Backtrace(bt) { } operator int() const { return this->Dest; } bool IsStrong() const { return this->Strong; } + cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; } + private: int Dest; bool Strong; + cmListFileBacktrace Backtrace; }; struct cmGraphEdgeList : public std::vector<cmGraphEdge> { diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx index fcdf03f..754fa7d 100644 --- a/Source/cmGraphVizWriter.cxx +++ b/Source/cmGraphVizWriter.cxx @@ -68,7 +68,7 @@ const char* getShapeForTarget(const cmGeneratorTarget* target) } std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget( - cmTarget* Target) + cmTarget* Target, const cmGlobalGenerator* globalGenerator) { char sep = ';'; std::map<std::string, LinkLibraryScopeType> tokens; @@ -95,6 +95,13 @@ std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget( } std::string element = interfaceLinkLibraries.substr(start, end - start); + if (globalGenerator->IsAlias(element)) { + const auto tgt = globalGenerator->FindTarget(element); + if (tgt) { + element = tgt->GetName(); + } + } + if (std::string::npos == element.find("$<LINK_ONLY:", 0)) { // we assume first, that this library is an interface library. // if we find it again in the linklibraries property, we promote it to an @@ -116,6 +123,12 @@ std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget( } std::string element = linkLibraries.substr(start, end - start); + if (globalGenerator->IsAlias(element)) { + const auto tgt = globalGenerator->FindTarget(element); + if (tgt) { + element = tgt->GetName(); + } + } if (tokens.find(element) == tokens.end()) { // this library is not found in interfaceLinkLibraries but in @@ -137,13 +150,13 @@ std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget( } } -cmGraphVizWriter::cmGraphVizWriter( - const std::vector<cmLocalGenerator*>& localGenerators) +cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator) : GraphType("digraph") , GraphName("GG") , GraphHeader("node [\n fontsize = \"12\"\n];") , GraphNodePrefix("node") - , LocalGenerators(localGenerators) + , GlobalGenerator(globalGenerator) + , LocalGenerators(globalGenerator->GetLocalGenerators()) , GenerateForExecutables(true) , GenerateForStaticLibs(true) , GenerateForSharedLibs(true) @@ -374,7 +387,8 @@ void cmGraphVizWriter::WriteConnections( std::string myNodeName = this->TargetNamesNodes.find(targetName)->second; std::map<std::string, LinkLibraryScopeType> ll = - getScopedLinkLibrariesFromTarget(targetPtrIt->second->Target); + getScopedLinkLibrariesFromTarget(targetPtrIt->second->Target, + GlobalGenerator); for (auto const& llit : ll) { const char* libName = llit.first.c_str(); @@ -439,7 +453,7 @@ void cmGraphVizWriter::WriteDependerConnections( // Now we have a target, check whether it links against targetName. // If so, draw a connection, and then continue with dependers on that one. std::map<std::string, LinkLibraryScopeType> ll = - getScopedLinkLibrariesFromTarget(tptr.second->Target); + getScopedLinkLibrariesFromTarget(tptr.second->Target, GlobalGenerator); for (auto const& llit : ll) { if (llit.first == targetName) { @@ -540,6 +554,13 @@ int cmGraphVizWriter::CollectAllExternalLibs(int cnt) continue; } + if (GlobalGenerator->IsAlias(libName)) { + const auto tgt = GlobalGenerator->FindTarget(libName); + if (tgt) { + libName = tgt->GetName().c_str(); + } + } + std::map<std::string, const cmGeneratorTarget*>::const_iterator tarIt = this->TargetPtrs.find(libName); if (tarIt == this->TargetPtrs.end()) { diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h index ac20da9..ed242f0 100644 --- a/Source/cmGraphVizWriter.h +++ b/Source/cmGraphVizWriter.h @@ -16,13 +16,14 @@ class cmGeneratedFileStream; class cmGeneratorTarget; class cmLocalGenerator; +class cmGlobalGenerator; /** This class implements writing files for graphviz (dot) for graphs * representing the dependencies between the targets in the project. */ class cmGraphVizWriter { public: - cmGraphVizWriter(const std::vector<cmLocalGenerator*>& localGenerators); + cmGraphVizWriter(const cmGlobalGenerator* globalGenerator); void ReadSettings(const char* settingsFileName, const char* fallbackSettingsFileName); @@ -69,6 +70,7 @@ protected: std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex; + const cmGlobalGenerator* GlobalGenerator; const std::vector<cmLocalGenerator*>& LocalGenerators; std::map<std::string, const cmGeneratorTarget*> TargetPtrs; diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 6e33cf7..7c8458a 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -3,6 +3,7 @@ #include "cmInstallCommand.h" #include "cmsys/Glob.hxx" +#include <set> #include <sstream> #include <stddef.h> #include <utility> @@ -20,6 +21,7 @@ #include "cmInstallGenerator.h" #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmPolicies.h" #include "cmStateTypes.h" @@ -32,6 +34,7 @@ class cmExecutionStatus; static cmInstallTargetGenerator* CreateInstallTargetGenerator( cmTarget& target, const cmInstallCommandArguments& args, bool impLib, + cmListFileBacktrace const& backtrace, const std::string& destination, bool forceOpt = false, bool namelink = false) { cmInstallGenerator::MessageLevel message = @@ -40,24 +43,49 @@ static cmInstallTargetGenerator* CreateInstallTargetGenerator( const char* component = namelink ? args.GetNamelinkComponent().c_str() : args.GetComponent().c_str(); return new cmInstallTargetGenerator( - target.GetName(), args.GetDestination().c_str(), impLib, + target.GetName(), destination.c_str(), impLib, args.GetPermissions().c_str(), args.GetConfigurations(), component, - message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt); + message, args.GetExcludeFromAll(), args.GetOptional() || forceOpt, + backtrace); +} + +static cmInstallTargetGenerator* CreateInstallTargetGenerator( + cmTarget& target, const cmInstallCommandArguments& args, bool impLib, + cmListFileBacktrace const& backtrace, bool forceOpt = false, + bool namelink = false) +{ + return CreateInstallTargetGenerator(target, args, impLib, backtrace, + args.GetDestination(), forceOpt, + namelink); } static cmInstallFilesGenerator* CreateInstallFilesGenerator( cmMakefile* mf, const std::vector<std::string>& absFiles, - const cmInstallCommandArguments& args, bool programs) + const cmInstallCommandArguments& args, bool programs, + const std::string& destination) { cmInstallGenerator::MessageLevel message = cmInstallGenerator::SelectMessageLevel(mf); return new cmInstallFilesGenerator( - absFiles, args.GetDestination().c_str(), programs, - args.GetPermissions().c_str(), args.GetConfigurations(), - args.GetComponent().c_str(), message, args.GetExcludeFromAll(), - args.GetRename().c_str(), args.GetOptional()); + absFiles, destination.c_str(), programs, args.GetPermissions().c_str(), + args.GetConfigurations(), args.GetComponent().c_str(), message, + args.GetExcludeFromAll(), args.GetRename().c_str(), args.GetOptional()); } +static cmInstallFilesGenerator* CreateInstallFilesGenerator( + cmMakefile* mf, const std::vector<std::string>& absFiles, + const cmInstallCommandArguments& args, bool programs) +{ + return CreateInstallFilesGenerator(mf, absFiles, args, programs, + args.GetDestination()); +} + +static const std::set<std::string> allowedTypes{ + "BIN", "SBIN", "LIB", "INCLUDE", "SYSCONF", + "SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA", "INFO", + "LOCALE", "MAN", "DOC", +}; + // cmInstallCommand bool cmInstallCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) @@ -332,6 +360,17 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) "At most one of these two options may be specified."); return false; } + if (!genericArgs.GetType().empty() || !archiveArgs.GetType().empty() || + !libraryArgs.GetType().empty() || !runtimeArgs.GetType().empty() || + !objectArgs.GetType().empty() || !frameworkArgs.GetType().empty() || + !bundleArgs.GetType().empty() || !privateHeaderArgs.GetType().empty() || + !publicHeaderArgs.GetType().empty() || !resourceArgs.GetType().empty()) { + std::ostringstream e; + e << "TARGETS given TYPE option. The TYPE option may only be specified in " + " install(FILES) and install(DIRECTORIES)."; + this->SetError(e.str()); + return false; + } // Select the mode for installing symlinks to versioned shared libraries. cmInstallTargetGenerator::NamelinkModeType namelinkMode = @@ -435,17 +474,21 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // This is a DLL platform. if (!archiveArgs.GetDestination().empty()) { // The import library uses the ARCHIVE properties. - archiveGenerator = - CreateInstallTargetGenerator(target, archiveArgs, true); + archiveGenerator = CreateInstallTargetGenerator( + target, archiveArgs, true, this->Makefile->GetBacktrace()); } if (!runtimeArgs.GetDestination().empty()) { // The DLL uses the RUNTIME properties. - runtimeGenerator = - CreateInstallTargetGenerator(target, runtimeArgs, false); + runtimeGenerator = CreateInstallTargetGenerator( + target, runtimeArgs, false, this->Makefile->GetBacktrace()); } if ((archiveGenerator == nullptr) && (runtimeGenerator == nullptr)) { - this->SetError("Library TARGETS given no DESTINATION!"); - return false; + archiveGenerator = CreateInstallTargetGenerator( + target, archiveArgs, true, this->Makefile->GetBacktrace(), + this->GetArchiveDestination(nullptr)); + runtimeGenerator = CreateInstallTargetGenerator( + target, runtimeArgs, false, this->Makefile->GetBacktrace(), + this->GetRuntimeDestination(nullptr)); } } else { // This is a non-DLL platform. @@ -459,8 +502,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Use the FRAMEWORK properties. if (!frameworkArgs.GetDestination().empty()) { - frameworkGenerator = - CreateInstallTargetGenerator(target, frameworkArgs, false); + frameworkGenerator = CreateInstallTargetGenerator( + target, frameworkArgs, false, this->Makefile->GetBacktrace()); } else { std::ostringstream e; e << "TARGETS given no FRAMEWORK DESTINATION for shared library " @@ -471,29 +514,22 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) } } else { // The shared library uses the LIBRARY properties. - if (!libraryArgs.GetDestination().empty()) { - if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { - libraryGenerator = - CreateInstallTargetGenerator(target, libraryArgs, false); - libraryGenerator->SetNamelinkMode( - cmInstallTargetGenerator::NamelinkModeSkip); - } - if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { - namelinkGenerator = CreateInstallTargetGenerator( - target, libraryArgs, false, false, true); - namelinkGenerator->SetNamelinkMode( - cmInstallTargetGenerator::NamelinkModeOnly); - } - namelinkOnly = - (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); - } else { - std::ostringstream e; - e << "TARGETS given no LIBRARY DESTINATION for shared library " - "target \"" - << target.GetName() << "\"."; - this->SetError(e.str()); - return false; + if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { + libraryGenerator = CreateInstallTargetGenerator( + target, libraryArgs, false, this->Makefile->GetBacktrace(), + this->GetLibraryDestination(&libraryArgs)); + libraryGenerator->SetNamelinkMode( + cmInstallTargetGenerator::NamelinkModeSkip); + } + if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { + namelinkGenerator = CreateInstallTargetGenerator( + target, libraryArgs, false, this->Makefile->GetBacktrace(), + this->GetLibraryDestination(&libraryArgs), false, true); + namelinkGenerator->SetNamelinkMode( + cmInstallTargetGenerator::NamelinkModeOnly); } + namelinkOnly = + (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); } } } break; @@ -508,8 +544,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Use the FRAMEWORK properties. if (!frameworkArgs.GetDestination().empty()) { - frameworkGenerator = - CreateInstallTargetGenerator(target, frameworkArgs, false); + frameworkGenerator = CreateInstallTargetGenerator( + target, frameworkArgs, false, this->Makefile->GetBacktrace()); } else { std::ostringstream e; e << "TARGETS given no FRAMEWORK DESTINATION for static library " @@ -520,24 +556,16 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) } } else { // Static libraries use ARCHIVE properties. - if (!archiveArgs.GetDestination().empty()) { - archiveGenerator = - CreateInstallTargetGenerator(target, archiveArgs, false); - } else { - std::ostringstream e; - e << "TARGETS given no ARCHIVE DESTINATION for static library " - "target \"" - << target.GetName() << "\"."; - this->SetError(e.str()); - return false; - } + archiveGenerator = CreateInstallTargetGenerator( + target, archiveArgs, false, this->Makefile->GetBacktrace(), + this->GetArchiveDestination(&archiveArgs)); } } break; case cmStateEnums::MODULE_LIBRARY: { // Modules use LIBRARY properties. if (!libraryArgs.GetDestination().empty()) { - libraryGenerator = - CreateInstallTargetGenerator(target, libraryArgs, false); + libraryGenerator = CreateInstallTargetGenerator( + target, libraryArgs, false, this->Makefile->GetBacktrace()); libraryGenerator->SetNamelinkMode(namelinkMode); namelinkOnly = (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); @@ -563,8 +591,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) return false; } - objectGenerator = - CreateInstallTargetGenerator(target, objectArgs, false); + objectGenerator = CreateInstallTargetGenerator( + target, objectArgs, false, this->Makefile->GetBacktrace()); } else { // Installing an OBJECT library without a destination transforms // it to an INTERFACE library. It installs no files but can be @@ -575,15 +603,15 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) if (target.IsAppBundleOnApple()) { // Application bundles use the BUNDLE properties. if (!bundleArgs.GetDestination().empty()) { - bundleGenerator = - CreateInstallTargetGenerator(target, bundleArgs, false); + bundleGenerator = CreateInstallTargetGenerator( + target, bundleArgs, false, this->Makefile->GetBacktrace()); } else if (!runtimeArgs.GetDestination().empty()) { bool failure = false; if (this->CheckCMP0006(failure)) { // For CMake 2.4 compatibility fallback to the RUNTIME // properties. - bundleGenerator = - CreateInstallTargetGenerator(target, runtimeArgs, false); + bundleGenerator = CreateInstallTargetGenerator( + target, runtimeArgs, false, this->Makefile->GetBacktrace()); } else if (failure) { return false; } @@ -598,17 +626,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) } } else { // Executables use the RUNTIME properties. - if (!runtimeArgs.GetDestination().empty()) { - runtimeGenerator = - CreateInstallTargetGenerator(target, runtimeArgs, false); - } else { - std::ostringstream e; - e << "TARGETS given no RUNTIME DESTINATION for executable " - "target \"" - << target.GetName() << "\"."; - this->SetError(e.str()); - return false; - } + runtimeGenerator = CreateInstallTargetGenerator( + target, runtimeArgs, false, this->Makefile->GetBacktrace(), + this->GetRuntimeDestination(&runtimeArgs)); } // On DLL platforms an executable may also have an import @@ -617,8 +637,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) if (dll_platform && !archiveArgs.GetDestination().empty() && target.IsExecutableWithExports()) { // The import library uses the ARCHIVE properties. - archiveGenerator = - CreateInstallTargetGenerator(target, archiveArgs, true, true); + archiveGenerator = CreateInstallTargetGenerator( + target, archiveArgs, true, this->Makefile->GetBacktrace(), true); } } break; case cmStateEnums::INTERFACE_LIBRARY: @@ -655,15 +675,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) } // Create the files install generator. - if (!privateHeaderArgs.GetDestination().empty()) { - privateHeaderGenerator = CreateInstallFilesGenerator( - this->Makefile, absFiles, privateHeaderArgs, false); - } else { - std::ostringstream e; - e << "INSTALL TARGETS - target " << target.GetName() << " has " - << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION."; - cmSystemTools::Message(e.str().c_str(), "Warning"); - } + privateHeaderGenerator = CreateInstallFilesGenerator( + this->Makefile, absFiles, privateHeaderArgs, false, + this->GetIncludeDestination(&privateHeaderArgs)); } files = target.GetProperty("PUBLIC_HEADER"); @@ -676,15 +690,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) } // Create the files install generator. - if (!publicHeaderArgs.GetDestination().empty()) { - publicHeaderGenerator = CreateInstallFilesGenerator( - this->Makefile, absFiles, publicHeaderArgs, false); - } else { - std::ostringstream e; - e << "INSTALL TARGETS - target " << target.GetName() << " has " - << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION."; - cmSystemTools::Message(e.str().c_str(), "Warning"); - } + publicHeaderGenerator = CreateInstallFilesGenerator( + this->Makefile, absFiles, publicHeaderArgs, false, + this->GetIncludeDestination(&publicHeaderArgs)); } files = target.GetProperty("RESOURCE"); @@ -820,6 +828,14 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args) return false; } + std::string type = ica.GetType(); + if (!type.empty() && allowedTypes.count(type) == 0) { + std::ostringstream e; + e << args[0] << " given non-type \"" << type << "\" with TYPE argument."; + this->SetError(e.str()); + return false; + } + const std::vector<std::string>& filesVector = files.GetVector(); // Check if there is something to do. @@ -882,7 +898,17 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args) return false; } - if (ica.GetDestination().empty()) { + if (!type.empty() && !ica.GetDestination().empty()) { + std::ostringstream e; + e << args[0] + << " given both TYPE and DESTINATION arguments. You may only specify " + "one."; + this->SetError(e.str()); + return false; + } + + std::string destination = this->GetDestinationForType(&ica, type); + if (destination.empty()) { // A destination is required. std::ostringstream e; e << args[0] << " given no DESTINATION!"; @@ -891,8 +917,8 @@ bool cmInstallCommand::HandleFilesMode(std::vector<std::string> const& args) } // Create the files install generator. - this->Makefile->AddInstallGenerator( - CreateInstallFilesGenerator(this->Makefile, absFiles, ica, programs)); + this->Makefile->AddInstallGenerator(CreateInstallFilesGenerator( + this->Makefile, absFiles, ica, programs, destination)); // Tell the global generator about any installation component names // specified. @@ -916,7 +942,8 @@ bool cmInstallCommand::HandleDirectoryMode( DoingPermsDir, DoingPermsMatch, DoingConfigurations, - DoingComponent + DoingComponent, + DoingType }; Doing doing = DoingDirs; bool in_match_mode = false; @@ -930,6 +957,7 @@ bool cmInstallCommand::HandleDirectoryMode( std::vector<std::string> configurations; std::string component = this->DefaultComponentName; std::string literal_args; + std::string type; for (unsigned int i = 1; i < args.size(); ++i) { if (args[i] == "DESTINATION") { if (in_match_mode) { @@ -942,6 +970,17 @@ bool cmInstallCommand::HandleDirectoryMode( // Switch to setting the destination property. doing = DoingDestination; + } else if (args[i] == "TYPE") { + if (in_match_mode) { + std::ostringstream e; + e << args[0] << " does not allow \"" << args[i] + << "\" after PATTERN or REGEX."; + this->SetError(e.str()); + return false; + } + + // Switch to setting the type. + doing = DoingType; } else if (args[i] == "OPTIONAL") { if (in_match_mode) { std::ostringstream e; @@ -1102,6 +1141,17 @@ bool cmInstallCommand::HandleDirectoryMode( } else if (doing == DoingDestination) { destination = args[i].c_str(); doing = DoingNone; + } else if (doing == DoingType) { + if (allowedTypes.count(args[i]) == 0) { + std::ostringstream e; + e << args[0] << " given non-type \"" << args[i] + << "\" with TYPE argument."; + this->SetError(e.str()); + return false; + } + + type = args[i]; + doing = DoingNone; } else if (doing == DoingPattern) { // Convert the pattern to a regular expression. Require a // leading slash and trailing end-of-string in the matched @@ -1175,10 +1225,22 @@ bool cmInstallCommand::HandleDirectoryMode( if (dirs.empty()) { return true; } + std::string destinationStr; if (!destination) { - // A destination is required. + if (type.empty()) { + // A destination is required. + std::ostringstream e; + e << args[0] << " given no DESTINATION!"; + this->SetError(e.str()); + return false; + } + destinationStr = this->GetDestinationForType(nullptr, type); + destination = destinationStr.c_str(); + } else if (!type.empty()) { std::ostringstream e; - e << args[0] << " given no DESTINATION!"; + e << args[0] + << " given both TYPE and DESTINATION arguments. You may only specify " + "one."; this->SetError(e.str()); return false; } @@ -1452,3 +1514,163 @@ bool cmInstallCommand::CheckCMP0006(bool& failure) } return false; } + +std::string cmInstallCommand::GetDestination( + const cmInstallCommandArguments* args, const std::string& varName, + const std::string& guess) +{ + if (args && !args->GetDestination().empty()) { + return args->GetDestination(); + } + std::string val = this->Makefile->GetSafeDefinition(varName); + if (!val.empty()) { + return val; + } + return guess; +} + +std::string cmInstallCommand::GetRuntimeDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_BINDIR", "bin"); +} + +std::string cmInstallCommand::GetSbinDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_SBINDIR", "sbin"); +} + +std::string cmInstallCommand::GetArchiveDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib"); +} + +std::string cmInstallCommand::GetLibraryDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_LIBDIR", "lib"); +} + +std::string cmInstallCommand::GetIncludeDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_INCLUDEDIR", "include"); +} + +std::string cmInstallCommand::GetSysconfDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_SYSCONFDIR", "etc"); +} + +std::string cmInstallCommand::GetSharedStateDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_SHAREDSTATEDIR", "com"); +} + +std::string cmInstallCommand::GetLocalStateDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_LOCALSTATEDIR", "var"); +} + +std::string cmInstallCommand::GetRunStateDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_RUNSTATEDIR", + this->GetLocalStateDestination(nullptr) + + "/run"); +} + +std::string cmInstallCommand::GetDataRootDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_DATAROOTDIR", "share"); +} + +std::string cmInstallCommand::GetDataDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_DATADIR", + this->GetDataRootDestination(nullptr)); +} + +std::string cmInstallCommand::GetInfoDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_INFODIR", + this->GetDataRootDestination(nullptr) + "/info"); +} + +std::string cmInstallCommand::GetLocaleDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_LOCALEDIR", + this->GetDataRootDestination(nullptr) + + "/locale"); +} + +std::string cmInstallCommand::GetManDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_MANDIR", + this->GetDataRootDestination(nullptr) + "/man"); +} + +std::string cmInstallCommand::GetDocDestination( + const cmInstallCommandArguments* args) +{ + return this->GetDestination(args, "CMAKE_INSTALL_DOCDIR", + this->GetDataRootDestination(nullptr) + "/doc"); +} + +std::string cmInstallCommand::GetDestinationForType( + const cmInstallCommandArguments* args, const std::string& type) +{ + if (args && !args->GetDestination().empty()) { + return args->GetDestination(); + } + if (type == "BIN") { + return this->GetRuntimeDestination(nullptr); + } + if (type == "SBIN") { + return this->GetSbinDestination(nullptr); + } + if (type == "SYSCONF") { + return this->GetSysconfDestination(nullptr); + } + if (type == "SHAREDSTATE") { + return this->GetSharedStateDestination(nullptr); + } + if (type == "LOCALSTATE") { + return this->GetLocalStateDestination(nullptr); + } + if (type == "RUNSTATE") { + return this->GetRunStateDestination(nullptr); + } + if (type == "LIB") { + return this->GetLibraryDestination(nullptr); + } + if (type == "INCLUDE") { + return this->GetIncludeDestination(nullptr); + } + if (type == "DATA") { + return this->GetDataDestination(nullptr); + } + if (type == "INFO") { + return this->GetInfoDestination(nullptr); + } + if (type == "LOCALE") { + return this->GetLocaleDestination(nullptr); + } + if (type == "MAN") { + return this->GetManDestination(nullptr); + } + if (type == "DOC") { + return this->GetDocDestination(nullptr); + } + return ""; +} diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h index 8bd0159..202c438 100644 --- a/Source/cmInstallCommand.h +++ b/Source/cmInstallCommand.h @@ -11,6 +11,7 @@ #include "cmCommand.h" class cmExecutionStatus; +class cmInstallCommandArguments; /** \class cmInstallCommand * \brief Specifies where to install some files @@ -45,6 +46,27 @@ private: std::vector<std::string>& absFiles); bool CheckCMP0006(bool& failure); + std::string GetDestination(const cmInstallCommandArguments* args, + const std::string& varName, + const std::string& guess); + std::string GetRuntimeDestination(const cmInstallCommandArguments* args); + std::string GetSbinDestination(const cmInstallCommandArguments* args); + std::string GetArchiveDestination(const cmInstallCommandArguments* args); + std::string GetLibraryDestination(const cmInstallCommandArguments* args); + std::string GetIncludeDestination(const cmInstallCommandArguments* args); + std::string GetSysconfDestination(const cmInstallCommandArguments* args); + std::string GetSharedStateDestination(const cmInstallCommandArguments* args); + std::string GetLocalStateDestination(const cmInstallCommandArguments* args); + std::string GetRunStateDestination(const cmInstallCommandArguments* args); + std::string GetDataRootDestination(const cmInstallCommandArguments* args); + std::string GetDataDestination(const cmInstallCommandArguments* args); + std::string GetInfoDestination(const cmInstallCommandArguments* args); + std::string GetLocaleDestination(const cmInstallCommandArguments* args); + std::string GetManDestination(const cmInstallCommandArguments* args); + std::string GetDocDestination(const cmInstallCommandArguments* args); + std::string GetDestinationForType(const cmInstallCommandArguments* args, + const std::string& type); + std::string DefaultComponentName; }; diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index 2d6dc12..63bdb00 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -29,6 +29,7 @@ cmInstallCommandArguments::cmInstallCommandArguments( , Optional(&Parser, "OPTIONAL", &ArgumentGroup) , NamelinkOnly(&Parser, "NAMELINK_ONLY", &ArgumentGroup) , NamelinkSkip(&Parser, "NAMELINK_SKIP", &ArgumentGroup) + , Type(&Parser, "TYPE", &ArgumentGroup) , GenericArguments(nullptr) , DefaultComponentName(defaultComponent) { @@ -145,6 +146,11 @@ bool cmInstallCommandArguments::HasNamelinkComponent() const return false; } +const std::string& cmInstallCommandArguments::GetType() const +{ + return this->Type.GetString(); +} + const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations() const { diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index ee6e865..425e58a 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -35,6 +35,7 @@ public: bool GetNamelinkOnly() const; bool GetNamelinkSkip() const; bool HasNamelinkComponent() const; + const std::string& GetType() const; // once HandleDirectoryMode() is also switched to using // cmInstallCommandArguments then these two functions can become non-static @@ -55,6 +56,7 @@ private: cmCAEnabler Optional; cmCAEnabler NamelinkOnly; cmCAEnabler NamelinkSkip; + cmCAString Type; std::string DestinationString; std::string PermissionsString; diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx index 53ac716..2b23658 100644 --- a/Source/cmInstallGenerator.cxx +++ b/Source/cmInstallGenerator.cxx @@ -22,6 +22,19 @@ cmInstallGenerator::~cmInstallGenerator() { } +bool cmInstallGenerator::HaveInstall() +{ + return true; +} + +void cmInstallGenerator::CheckCMP0082(bool& haveSubdirectoryInstall, + bool& haveInstallAfterSubdirectory) +{ + if (haveSubdirectoryInstall) { + haveInstallAfterSubdirectory = true; + } +} + void cmInstallGenerator::AddInstallRule( std::ostream& os, std::string const& dest, cmInstallType type, std::vector<std::string> const& files, bool optional /* = false */, diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h index fc1ce86..e5b88c3 100644 --- a/Source/cmInstallGenerator.h +++ b/Source/cmInstallGenerator.h @@ -38,6 +38,10 @@ public: bool exclude_from_all); ~cmInstallGenerator() override; + virtual bool HaveInstall(); + virtual void CheckCMP0082(bool& haveSubdirectoryInstall, + bool& haveInstallAfterSubdirectory); + void AddInstallRule( std::ostream& os, std::string const& dest, cmInstallType type, std::vector<std::string> const& files, bool optional = false, diff --git a/Source/cmInstallScriptGenerator.cxx b/Source/cmInstallScriptGenerator.cxx index f7e6e44..7d77b7c 100644 --- a/Source/cmInstallScriptGenerator.cxx +++ b/Source/cmInstallScriptGenerator.cxx @@ -30,9 +30,9 @@ void cmInstallScriptGenerator::GenerateScript(std::ostream& os) os << indent << "if(" << component_test << ")\n"; if (this->Code) { - os << indent.Next() << this->Script << "\n"; + os << indent << this->Script << "\n"; } else { - os << indent.Next() << "include(\"" << this->Script << "\")\n"; + os << indent << "include(\"" << this->Script << "\")\n"; } os << indent << "endif()\n\n"; diff --git a/Source/cmInstallSubdirectoryGenerator.cxx b/Source/cmInstallSubdirectoryGenerator.cxx new file mode 100644 index 0000000..ca9f134 --- /dev/null +++ b/Source/cmInstallSubdirectoryGenerator.cxx @@ -0,0 +1,77 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmInstallSubdirectoryGenerator.h" + +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmPolicies.h" +#include "cmScriptGenerator.h" +#include "cmSystemTools.h" + +#include <sstream> +#include <vector> + +cmInstallSubdirectoryGenerator::cmInstallSubdirectoryGenerator( + cmMakefile* makefile, const char* binaryDirectory, bool excludeFromAll) + : cmInstallGenerator(nullptr, std::vector<std::string>(), nullptr, + MessageDefault, excludeFromAll) + , Makefile(makefile) + , BinaryDirectory(binaryDirectory) +{ +} + +cmInstallSubdirectoryGenerator::~cmInstallSubdirectoryGenerator() +{ +} + +bool cmInstallSubdirectoryGenerator::HaveInstall() +{ + for (auto generator : this->Makefile->GetInstallGenerators()) { + if (generator->HaveInstall()) { + return true; + } + } + + return false; +} + +void cmInstallSubdirectoryGenerator::CheckCMP0082( + bool& haveSubdirectoryInstall, bool& /*unused*/) +{ + if (this->HaveInstall()) { + haveSubdirectoryInstall = true; + } +} + +void cmInstallSubdirectoryGenerator::Compute(cmLocalGenerator* lg) +{ + this->LocalGenerator = lg; +} + +void cmInstallSubdirectoryGenerator::GenerateScript(std::ostream& os) +{ + if (!this->ExcludeFromAll) { + cmPolicies::PolicyStatus status = + this->LocalGenerator->GetPolicyStatus(cmPolicies::CMP0082); + switch (status) { + case cmPolicies::WARN: + case cmPolicies::OLD: + // OLD behavior is handled in cmLocalGenerator::GenerateInstallRules() + break; + + case cmPolicies::NEW: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: { + Indent indent; + std::string odir = this->BinaryDirectory; + cmSystemTools::ConvertToUnixSlashes(odir); + os << indent << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n" + << indent.Next() + << "# Include the install script for the subdirectory.\n" + << indent.Next() << "include(\"" << odir + << "/cmake_install.cmake\")\n" + << indent << "endif()\n\n"; + } break; + } + } +} diff --git a/Source/cmInstallSubdirectoryGenerator.h b/Source/cmInstallSubdirectoryGenerator.h new file mode 100644 index 0000000..35471dd --- /dev/null +++ b/Source/cmInstallSubdirectoryGenerator.h @@ -0,0 +1,41 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmInstallSubdirectoryGenerator_h +#define cmInstallSubdirectoryGenerator_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmInstallGenerator.h" + +#include <iosfwd> +#include <string> + +class cmLocalGenerator; +class cmMakefile; + +/** \class cmInstallSubdirectoryGenerator + * \brief Generate target installation rules. + */ +class cmInstallSubdirectoryGenerator : public cmInstallGenerator +{ +public: + cmInstallSubdirectoryGenerator(cmMakefile* makefile, + const char* binaryDirectory, + bool excludeFromAll); + ~cmInstallSubdirectoryGenerator() override; + + bool HaveInstall() override; + void CheckCMP0082(bool& haveSubdirectoryInstall, + bool& haveInstallAfterSubdirectory) override; + + void Compute(cmLocalGenerator* lg) override; + +protected: + void GenerateScript(std::ostream& os) override; + + cmMakefile* Makefile; + std::string BinaryDirectory; + cmLocalGenerator* LocalGenerator; +}; + +#endif diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 8b8f79b..ea3d522 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -24,7 +24,7 @@ cmInstallTargetGenerator::cmInstallTargetGenerator( const std::string& targetName, const char* dest, bool implib, const char* file_permissions, std::vector<std::string> const& configurations, const char* component, MessageLevel message, bool exclude_from_all, - bool optional) + bool optional, cmListFileBacktrace const& backtrace) : cmInstallGenerator(dest, configurations, component, message, exclude_from_all) , TargetName(targetName) @@ -32,6 +32,7 @@ cmInstallTargetGenerator::cmInstallTargetGenerator( , FilePermissions(file_permissions) , ImportLibrary(implib) , Optional(optional) + , Backtrace(backtrace) { this->ActionsPerConfig = true; this->NamelinkMode = NamelinkModeNone; diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index f6bec20..bf625d1 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include "cmInstallGenerator.h" +#include "cmListFileCache.h" #include "cmScriptGenerator.h" #include <iosfwd> @@ -21,11 +22,12 @@ class cmLocalGenerator; class cmInstallTargetGenerator : public cmInstallGenerator { public: - cmInstallTargetGenerator(std::string const& targetName, const char* dest, - bool implib, const char* file_permissions, - std::vector<std::string> const& configurations, - const char* component, MessageLevel message, - bool exclude_from_all, bool optional); + cmInstallTargetGenerator( + std::string const& targetName, const char* dest, bool implib, + const char* file_permissions, + std::vector<std::string> const& configurations, const char* component, + MessageLevel message, bool exclude_from_all, bool optional, + cmListFileBacktrace const& backtrace = cmListFileBacktrace()); ~cmInstallTargetGenerator() override; /** Select the policy for installing shared library linkable name @@ -64,6 +66,8 @@ public: std::string GetDestination(std::string const& config) const; + cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; } + protected: void GenerateScript(std::ostream& os) override; void GenerateScriptForConfig(std::ostream& os, const std::string& config, @@ -108,6 +112,7 @@ protected: NamelinkModeType NamelinkMode; bool ImportLibrary; bool Optional; + cmListFileBacktrace Backtrace; }; #endif diff --git a/Source/cmLinkItem.cxx b/Source/cmLinkItem.cxx index 69b6821..121731d 100644 --- a/Source/cmLinkItem.cxx +++ b/Source/cmLinkItem.cxx @@ -12,15 +12,18 @@ cmLinkItem::cmLinkItem() { } -cmLinkItem::cmLinkItem(std::string const& n) +cmLinkItem::cmLinkItem(std::string const& n, cmListFileBacktrace const& bt) : String(n) , Target(nullptr) + , Backtrace(bt) { } -cmLinkItem::cmLinkItem(cmGeneratorTarget const* t) +cmLinkItem::cmLinkItem(cmGeneratorTarget const* t, + cmListFileBacktrace const& bt) : String() , Target(t) + , Backtrace(bt) { } @@ -58,15 +61,12 @@ std::ostream& operator<<(std::ostream& os, cmLinkItem const& item) cmLinkImplItem::cmLinkImplItem() : cmLinkItem() - , Backtrace() , FromGenex(false) { } -cmLinkImplItem::cmLinkImplItem(cmLinkItem item, cmListFileBacktrace const& bt, - bool fromGenex) +cmLinkImplItem::cmLinkImplItem(cmLinkItem item, bool fromGenex) : cmLinkItem(std::move(item)) - , Backtrace(bt) , FromGenex(fromGenex) { } diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 74fd298..e1ddd22 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -24,10 +24,11 @@ class cmLinkItem public: cmLinkItem(); - explicit cmLinkItem(std::string const& s); - explicit cmLinkItem(cmGeneratorTarget const* t); + cmLinkItem(std::string const& s, cmListFileBacktrace const& bt); + cmLinkItem(cmGeneratorTarget const* t, cmListFileBacktrace const& bt); std::string const& AsStr() const; cmGeneratorTarget const* Target; + cmListFileBacktrace Backtrace; friend bool operator<(cmLinkItem const& l, cmLinkItem const& r); friend bool operator==(cmLinkItem const& l, cmLinkItem const& r); friend std::ostream& operator<<(std::ostream& os, cmLinkItem const& item); @@ -37,9 +38,7 @@ class cmLinkImplItem : public cmLinkItem { public: cmLinkImplItem(); - cmLinkImplItem(cmLinkItem item, cmListFileBacktrace const& bt, - bool fromGenex); - cmListFileBacktrace Backtrace; + cmLinkImplItem(cmLinkItem item, bool fromGenex); bool FromGenex; }; diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index d7de2fa..9b63d24 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -152,7 +152,7 @@ bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args) } const std::string& listName = args[1]; - const std::string& variableName = args[args.size() - 1]; + const std::string& variableName = args.back(); std::vector<std::string> varArgsExpanded; // do not check the return value here // if the list var is not found varArgsExpanded will have size 0 @@ -174,7 +174,7 @@ bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args) } const std::string& listName = args[1]; - const std::string& variableName = args[args.size() - 1]; + const std::string& variableName = args.back(); // expand the variable std::vector<std::string> varArgsExpanded; if (!this->GetList(varArgsExpanded, listName)) { @@ -243,7 +243,7 @@ bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args) } const std::string& listName = args[1]; - const std::string& variableName = args[args.size() - 1]; + const std::string& variableName = args.back(); // expand the variable std::vector<std::string> varArgsExpanded; if (!this->GetList(varArgsExpanded, listName)) { @@ -346,8 +346,7 @@ bool cmListCommand::HandleRemoveItemCommand( // expand the variable std::vector<std::string> varArgsExpanded; if (!this->GetList(varArgsExpanded, listName)) { - this->SetError("sub-command REMOVE_ITEM requires list to be present."); - return false; + return true; } std::vector<std::string> remove(args.begin() + 2, args.end()); @@ -376,8 +375,7 @@ bool cmListCommand::HandleReverseCommand(std::vector<std::string> const& args) // expand the variable std::vector<std::string> varArgsExpanded; if (!this->GetList(varArgsExpanded, listName)) { - this->SetError("sub-command REVERSE requires list to be present."); - return false; + return true; } std::string value = cmJoin(cmReverseRange(varArgsExpanded), ";"); @@ -399,9 +397,7 @@ bool cmListCommand::HandleRemoveDuplicatesCommand( // expand the variable std::vector<std::string> varArgsExpanded; if (!this->GetList(varArgsExpanded, listName)) { - this->SetError( - "sub-command REMOVE_DUPLICATES requires list to be present."); - return false; + return true; } std::vector<std::string>::const_iterator argsEnd = @@ -1152,8 +1148,7 @@ bool cmListCommand::HandleSortCommand(std::vector<std::string> const& args) // expand the variable std::vector<std::string> varArgsExpanded; if (!this->GetList(varArgsExpanded, listName)) { - this->SetError("sub-command SORT requires list to be present."); - return false; + return true; } if ((sortCompare == cmStringSorter::Compare::STRING) && @@ -1181,7 +1176,7 @@ bool cmListCommand::HandleSublistCommand(std::vector<std::string> const& args) } const std::string& listName = args[1]; - const std::string& variableName = args[args.size() - 1]; + const std::string& variableName = args.back(); // expand the variable std::vector<std::string> varArgsExpanded; @@ -1230,13 +1225,17 @@ bool cmListCommand::HandleRemoveAtCommand(std::vector<std::string> const& args) const std::string& listName = args[1]; // expand the variable std::vector<std::string> varArgsExpanded; - if (!this->GetList(varArgsExpanded, listName)) { - this->SetError("sub-command REMOVE_AT requires list to be present."); - return false; - } - // FIXME: Add policy to make non-existing lists an error like empty lists. - if (varArgsExpanded.empty()) { - this->SetError("REMOVE_AT given empty list"); + if (!this->GetList(varArgsExpanded, listName) || varArgsExpanded.empty()) { + std::ostringstream str; + str << "index: "; + for (size_t i = 1; i < args.size(); ++i) { + str << args[i]; + if (i != args.size() - 1) { + str << ", "; + } + } + str << " out of range (0, 0)"; + this->SetError(str.str()); return false; } @@ -1289,14 +1288,6 @@ bool cmListCommand::HandleFilterCommand(std::vector<std::string> const& args) return false; } - const std::string& listName = args[1]; - // expand the variable - std::vector<std::string> varArgsExpanded; - if (!this->GetList(varArgsExpanded, listName)) { - this->SetError("sub-command FILTER requires list to be present."); - return false; - } - const std::string& op = args[2]; bool includeMatches; if (op == "INCLUDE") { @@ -1308,6 +1299,13 @@ bool cmListCommand::HandleFilterCommand(std::vector<std::string> const& args) return false; } + const std::string& listName = args[1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if (!this->GetList(varArgsExpanded, listName)) { + return true; + } + const std::string& mode = args[3]; if (mode == "REGEX") { if (args.size() != 5) { diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 4d7e1e2..4689f42 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -9,10 +9,10 @@ #include "cmSystemTools.h" #include "cmake.h" -#include <algorithm> #include <assert.h> #include <memory> #include <sstream> +#include <utility> cmCommandContext::cmCommandName& cmCommandContext::cmCommandName::operator=( std::string const& name) @@ -474,3 +474,21 @@ bool operator!=(const cmListFileContext& lhs, const cmListFileContext& rhs) { return !(lhs == rhs); } + +std::ostream& operator<<(std::ostream& os, BT<std::string> const& s) +{ + return os << s.Value; +} + +std::vector<BT<std::string>> ExpandListWithBacktrace( + std::string const& list, cmListFileBacktrace const& bt) +{ + std::vector<BT<std::string>> result; + std::vector<std::string> tmp; + cmSystemTools::ExpandListArgument(list, tmp); + result.reserve(tmp.size()); + for (std::string& i : tmp) { + result.emplace_back(std::move(i), bt); + } + return result; +} diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 3d3afdf..9e4a833 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -9,6 +9,7 @@ #include <memory> // IWYU pragma: keep #include <stddef.h> #include <string> +#include <utility> #include <vector> #include "cmStateSnapshot.h" @@ -169,6 +170,38 @@ private: cmListFileBacktrace(std::shared_ptr<Entry const> top); }; +// Wrap type T as a value with a backtrace. For purposes of +// ordering and equality comparison, only the original value is +// used. The backtrace is considered incidental. +template <typename T> +class BT +{ +public: + BT(T v = T(), cmListFileBacktrace bt = cmListFileBacktrace()) + : Value(std::move(v)) + , Backtrace(std::move(bt)) + { + } + T Value; + cmListFileBacktrace Backtrace; + friend bool operator==(BT<T> const& l, BT<T> const& r) + { + return l.Value == r.Value; + } + friend bool operator<(BT<T> const& l, BT<T> const& r) + { + return l.Value < r.Value; + } + friend bool operator==(BT<T> const& l, T const& r) { return l.Value == r; } + friend bool operator==(T const& l, BT<T> const& r) { return l == r.Value; } +}; + +std::ostream& operator<<(std::ostream& os, BT<std::string> const& s); + +std::vector<BT<std::string>> ExpandListWithBacktrace( + std::string const& list, + cmListFileBacktrace const& bt = cmListFileBacktrace()); + struct cmListFile { bool ParseFile(const char* path, cmMessenger* messenger, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 7030725..da48950 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -65,6 +65,7 @@ static const char* ruleReplaceVars[] = { "CMAKE_CURRENT_BINARY_DIR", "CMAKE_RANLIB", "CMAKE_LINKER", + "CMAKE_MT", "CMAKE_CUDA_HOST_COMPILER", "CMAKE_CUDA_HOST_LINK_LAUNCHER", "CMAKE_CL_SHOWINCLUDES_PREFIX" @@ -202,9 +203,10 @@ void cmLocalGenerator::ComputeObjectMaxPath() this->ObjectMaxPathViolations.clear(); } -void cmLocalGenerator::MoveSystemIncludesToEnd( - std::vector<std::string>& includeDirs, const std::string& config, - const std::string& lang, const cmGeneratorTarget* target) const +static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs, + const std::string& config, + const std::string& lang, + const cmGeneratorTarget* target) { if (!target) { return; @@ -218,6 +220,24 @@ void cmLocalGenerator::MoveSystemIncludesToEnd( }); } +static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs, + const std::string& config, + const std::string& lang, + const cmGeneratorTarget* target) +{ + if (!target) { + return; + } + + std::stable_sort(includeDirs.begin(), includeDirs.end(), + [target, &config, &lang](BT<std::string> const& a, + BT<std::string> const& b) { + return !target->IsSystemIncludeDirectory(a.Value, config, + lang) && + target->IsSystemIncludeDirectory(b.Value, config, lang); + }); +} + void cmLocalGenerator::TraceDependencies() { std::vector<std::string> configs; @@ -517,31 +537,62 @@ void cmLocalGenerator::GenerateInstallRules() } // Ask each install generator to write its code. + cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082); std::vector<cmInstallGenerator*> const& installers = this->Makefile->GetInstallGenerators(); - for (cmInstallGenerator* installer : installers) { - installer->Generate(fout, config, configurationTypes); + bool haveSubdirectoryInstall = false; + bool haveInstallAfterSubdirectory = false; + if (status == cmPolicies::WARN) { + for (cmInstallGenerator* installer : installers) { + installer->CheckCMP0082(haveSubdirectoryInstall, + haveInstallAfterSubdirectory); + installer->Generate(fout, config, configurationTypes); + } + } else { + for (cmInstallGenerator* installer : installers) { + installer->Generate(fout, config, configurationTypes); + } } // Write rules from old-style specification stored in targets. this->GenerateTargetInstallRules(fout, config, configurationTypes); // Include install scripts from subdirectories. - std::vector<cmStateSnapshot> children = - this->Makefile->GetStateSnapshot().GetChildren(); - if (!children.empty()) { - fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n"; - fout << " # Include the install script for each subdirectory.\n"; - for (cmStateSnapshot const& c : children) { - if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) { - std::string odir = c.GetDirectory().GetCurrentBinary(); - cmSystemTools::ConvertToUnixSlashes(odir); - fout << " include(\"" << odir << "/cmake_install.cmake\")" - << std::endl; + switch (status) { + case cmPolicies::WARN: + if (haveInstallAfterSubdirectory && + this->Makefile->PolicyOptionalWarningEnabled( + "CMAKE_POLICY_WARNING_CMP0082")) { + std::ostringstream e; + e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n"; + this->IssueMessage(cmake::AUTHOR_WARNING, e.str()); } - } - fout << "\n"; - fout << "endif()\n\n"; + CM_FALLTHROUGH; + case cmPolicies::OLD: { + std::vector<cmStateSnapshot> children = + this->Makefile->GetStateSnapshot().GetChildren(); + if (!children.empty()) { + fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n"; + fout << " # Include the install script for each subdirectory.\n"; + for (cmStateSnapshot const& c : children) { + if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) { + std::string odir = c.GetDirectory().GetCurrentBinary(); + cmSystemTools::ConvertToUnixSlashes(odir); + fout << " include(\"" << odir << "/cmake_install.cmake\")" + << std::endl; + } + } + fout << "\n"; + fout << "endif()\n\n"; + } + } break; + + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // NEW behavior is handled in + // cmInstallSubdirectoryGenerator::GenerateScript() + break; } // Record the install manifest. @@ -676,7 +727,7 @@ std::string cmLocalGenerator::GetIncludeFlags( } std::vector<std::string> includes = includeDirs; - this->MoveSystemIncludesToEnd(includes, config, lang, target); + MoveSystemIncludesToEnd(includes, config, lang, target); OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL; std::ostringstream includeFlags; @@ -756,33 +807,23 @@ std::string cmLocalGenerator::GetIncludeFlags( } std::string includePath = this->ConvertToIncludeReference(i, shellFormat, forceFullPaths); - if (quotePaths && !includePath.empty() && includePath[0] != '\"') { + if (quotePaths && !includePath.empty() && includePath.front() != '\"') { includeFlags << "\""; } includeFlags << includePath; - if (quotePaths && !includePath.empty() && includePath[0] != '\"') { + if (quotePaths && !includePath.empty() && includePath.front() != '\"') { includeFlags << "\""; } includeFlags << sep; } std::string flags = includeFlags.str(); // remove trailing separators - if ((sep[0] != ' ') && !flags.empty() && flags[flags.size() - 1] == sep[0]) { - flags[flags.size() - 1] = ' '; + if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) { + flags.back() = ' '; } return flags; } -void cmLocalGenerator::AddCompileDefinitions(std::set<std::string>& defines, - cmGeneratorTarget const* target, - const std::string& config, - const std::string& lang) const -{ - std::vector<std::string> targetDefines; - target->GetCompileDefinitions(targetDefines, config, lang); - this->AppendDefines(defines, targetDefines); -} - void cmLocalGenerator::AddCompileOptions(std::string& flags, cmGeneratorTarget* target, const std::string& lang, @@ -847,6 +888,21 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, bool stripImplicitDirs, bool appendAllImplicitDirs) const { + std::vector<BT<std::string>> tmp = this->GetIncludeDirectories( + target, lang, config, stripImplicitDirs, appendAllImplicitDirs); + dirs.reserve(tmp.size()); + for (BT<std::string>& v : tmp) { + dirs.emplace_back(std::move(v.Value)); + } +} + +std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectories( + cmGeneratorTarget const* target, std::string const& lang, + std::string const& config, bool stripImplicitDirs, + bool appendAllImplicitDirs) const +{ + std::vector<BT<std::string>> result; + // Do not repeat an include path. std::set<std::string> emitted; @@ -863,7 +919,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, std::string binDir = this->StateSnapshot.GetDirectory().GetCurrentBinary(); if (emitted.insert(binDir).second) { - dirs.push_back(std::move(binDir)); + result.emplace_back(std::move(binDir)); } } // Current source directory @@ -871,13 +927,13 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, std::string srcDir = this->StateSnapshot.GetDirectory().GetCurrentSource(); if (emitted.insert(srcDir).second) { - dirs.push_back(std::move(srcDir)); + result.emplace_back(std::move(srcDir)); } } } if (!target) { - return; + return result; } // Implicit include directories @@ -910,7 +966,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, } // Get the target-specific include directories. - std::vector<std::string> userDirs = + std::vector<BT<std::string>> userDirs = target->GetIncludeDirectories(config, lang); // Support putting all the in-project include directories first if @@ -918,44 +974,44 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) { std::string const &topSourceDir = this->GetState()->GetSourceDirectory(), &topBinaryDir = this->GetState()->GetBinaryDirectory(); - for (std::string const& i : userDirs) { + for (BT<std::string> const& i : userDirs) { // Emit this directory only if it is a subdirectory of the // top-level source or binary tree. - if (cmSystemTools::ComparePath(i, topSourceDir) || - cmSystemTools::ComparePath(i, topBinaryDir) || - cmSystemTools::IsSubDirectory(i, topSourceDir) || - cmSystemTools::IsSubDirectory(i, topBinaryDir)) { - if (emitted.insert(i).second) { - dirs.push_back(i); + if (cmSystemTools::ComparePath(i.Value, topSourceDir) || + cmSystemTools::ComparePath(i.Value, topBinaryDir) || + cmSystemTools::IsSubDirectory(i.Value, topSourceDir) || + cmSystemTools::IsSubDirectory(i.Value, topBinaryDir)) { + if (emitted.insert(i.Value).second) { + result.push_back(i); } } } } // Construct the final ordered include directory list. - for (std::string const& i : userDirs) { - if (emitted.insert(i).second) { - dirs.push_back(i); + for (BT<std::string> const& i : userDirs) { + if (emitted.insert(i.Value).second) { + result.push_back(i); } } - this->MoveSystemIncludesToEnd(dirs, config, lang, target); + MoveSystemIncludesToEnd(result, config, lang, target); // Add standard include directories for this language. { - std::vector<std::string>::size_type const before = userDirs.size(); + std::vector<std::string> userStandardDirs; { std::string key = "CMAKE_"; key += lang; key += "_STANDARD_INCLUDE_DIRECTORIES"; std::string const value = this->Makefile->GetSafeDefinition(key); - cmSystemTools::ExpandListArgument(value, userDirs); + cmSystemTools::ExpandListArgument(value, userStandardDirs); } - for (std::vector<std::string>::iterator i = userDirs.begin() + before, - ie = userDirs.end(); - i != ie; ++i) { - cmSystemTools::ConvertToUnixSlashes(*i); - dirs.push_back(*i); + userDirs.reserve(userDirs.size() + userStandardDirs.size()); + for (std::string& d : userStandardDirs) { + cmSystemTools::ConvertToUnixSlashes(d); + result.emplace_back(d); + userDirs.emplace_back(std::move(d)); } } @@ -963,18 +1019,20 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, // Append only implicit directories that were requested by the user for (std::string const& i : implicitDirs) { if (std::find(userDirs.begin(), userDirs.end(), i) != userDirs.end()) { - dirs.push_back(i); + result.emplace_back(i); } } // Append remaining implicit directories on demand if (appendAllImplicitDirs) { for (std::string const& i : implicitDirs) { - if (std::find(dirs.begin(), dirs.end(), i) == dirs.end()) { - dirs.push_back(i); + if (std::find(result.begin(), result.end(), i) == result.end()) { + result.emplace_back(i); } } } } + + return result; } void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags, @@ -1143,6 +1201,8 @@ void cmLocalGenerator::GetTargetFlags( break; } + this->AppendPositionIndependentLinkerFlags(linkFlags, target, config, + linkLanguage); this->AppendIPOLinkerFlags(linkFlags, target, config, linkLanguage); } @@ -1231,13 +1291,29 @@ void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target, std::string const& lang, std::set<std::string>& defines) const { + std::set<BT<std::string>> tmp = this->GetTargetDefines(target, config, lang); + for (BT<std::string> const& v : tmp) { + defines.emplace(v.Value); + } +} + +std::set<BT<std::string>> cmLocalGenerator::GetTargetDefines( + cmGeneratorTarget const* target, std::string const& config, + std::string const& lang) const +{ + std::set<BT<std::string>> defines; + // Add the export symbol definition for shared library objects. - if (const char* exportMacro = target->GetExportMacro()) { - this->AppendDefines(defines, exportMacro); + if (const std::string* exportMacro = target->GetExportMacro()) { + this->AppendDefines(defines, *exportMacro); } // Add preprocessor definitions for this target and configuration. - this->AddCompileDefinitions(defines, target, config, lang); + std::vector<BT<std::string>> targetDefines = + target->GetCompileDefinitions(config, lang); + this->AppendDefines(defines, targetDefines); + + return defines; } std::string cmLocalGenerator::GetTargetFortranFlags( @@ -1953,6 +2029,36 @@ void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags, } } +void cmLocalGenerator::AppendPositionIndependentLinkerFlags( + std::string& flags, cmGeneratorTarget* target, const std::string& config, + const std::string& lang) +{ + // For now, only EXECUTABLE is concerned + if (target->GetType() != cmStateEnums::EXECUTABLE) { + return; + } + + const char* PICValue = target->GetLinkPIEProperty(config); + if (PICValue == nullptr) { + // POSITION_INDEPENDENT_CODE is not set + return; + } + + std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_"; + name += cmSystemTools::IsOn(PICValue) ? "PIE" : "NO_PIE"; + + auto pieFlags = this->Makefile->GetSafeDefinition(name); + if (pieFlags.empty()) { + return; + } + + std::vector<std::string> flagsList; + cmSystemTools::ExpandListArgument(pieFlags, flagsList); + for (const auto& flag : flagsList) { + this->AppendFlagEscape(flags, flag); + } +} + void cmLocalGenerator::AppendCompileOptions(std::string& options, const char* options_list, const char* regex) const @@ -2035,26 +2141,34 @@ void cmLocalGenerator::AppendIncludeDirectories( } void cmLocalGenerator::AppendDefines(std::set<std::string>& defines, - const char* defines_list) const + std::string const& defines_list) const +{ + std::set<BT<std::string>> tmp; + this->AppendDefines(tmp, ExpandListWithBacktrace(defines_list)); + for (BT<std::string> const& i : tmp) { + defines.emplace(i.Value); + } +} + +void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines, + std::string const& defines_list) const { // Short-circuit if there are no definitions. - if (!defines_list) { + if (defines_list.empty()) { return; } // Expand the list of definitions. - std::vector<std::string> defines_vec; - cmSystemTools::ExpandListArgument(defines_list, defines_vec); - this->AppendDefines(defines, defines_vec); + this->AppendDefines(defines, ExpandListWithBacktrace(defines_list)); } void cmLocalGenerator::AppendDefines( - std::set<std::string>& defines, - const std::vector<std::string>& defines_vec) const + std::set<BT<std::string>>& defines, + const std::vector<BT<std::string>>& defines_vec) const { - for (std::string const& d : defines_vec) { + for (BT<std::string> const& d : defines_vec) { // Skip unsupported definitions. - if (!this->CheckDefinition(d)) { + if (!this->CheckDefinition(d.Value)) { continue; } defines.insert(d); diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 58b7762..2fa0070 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -126,6 +126,10 @@ public: void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target, const std::string& config, const std::string& lang); + void AppendPositionIndependentLinkerFlags(std::string& flags, + cmGeneratorTarget* target, + const std::string& config, + const std::string& lang); ///! Get the include flags for the current makefile and language std::string GetIncludeFlags(const std::vector<std::string>& includes, cmGeneratorTarget* target, @@ -169,14 +173,11 @@ public: * command line. */ void AppendDefines(std::set<std::string>& defines, - const char* defines_list) const; - void AppendDefines(std::set<std::string>& defines, - std::string const& defines_list) const - { - this->AppendDefines(defines, defines_list.c_str()); - } - void AppendDefines(std::set<std::string>& defines, - const std::vector<std::string>& defines_vec) const; + std::string const& defines_list) const; + void AppendDefines(std::set<BT<std::string>>& defines, + std::string const& defines_list) const; + void AppendDefines(std::set<BT<std::string>>& defines, + const std::vector<BT<std::string>>& defines_vec) const; /** * Encode a list of compile options for the compiler @@ -249,12 +250,12 @@ public: const std::string& config = "", bool stripImplicitDirs = true, bool appendAllImplicitDirs = false) const; + std::vector<BT<std::string>> GetIncludeDirectories( + cmGeneratorTarget const* target, std::string const& lang = "C", + std::string const& config = "", bool stripImplicitDirs = true, + bool appendAllImplicitDirs = false) const; void AddCompileOptions(std::string& flags, cmGeneratorTarget* target, const std::string& lang, const std::string& config); - void AddCompileDefinitions(std::set<std::string>& defines, - cmGeneratorTarget const* target, - const std::string& config, - const std::string& lang) const; std::string GetProjectName() const; @@ -336,6 +337,9 @@ public: void GetTargetDefines(cmGeneratorTarget const* target, std::string const& config, std::string const& lang, std::set<std::string>& defines) const; + std::set<BT<std::string>> GetTargetDefines(cmGeneratorTarget const* target, + std::string const& config, + std::string const& lang) const; void GetTargetCompileFlags(cmGeneratorTarget* target, std::string const& config, std::string const& lang, std::string& flags); @@ -418,10 +422,6 @@ private: int targetType); void ComputeObjectMaxPath(); - void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs, - const std::string& config, - const std::string& lang, - cmGeneratorTarget const* target) const; }; #if defined(CMAKE_BUILD_WITH_CMAKE) diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index eb31478..66edc91 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -17,6 +17,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalNinjaGenerator.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmNinjaTargetGenerator.h" #include "cmRulePlaceholderExpander.h" @@ -40,8 +41,7 @@ cmRulePlaceholderExpander* cmLocalNinjaGenerator::CreateRulePlaceholderExpander() const { cmRulePlaceholderExpander* ret = - new cmRulePlaceholderExpander(this->Compilers, this->VariableMappings, - this->CompilerSysroot, this->LinkerSysroot); + this->cmLocalGenerator::CreateRulePlaceholderExpander(); ret->SetTargetImpLib("$TARGET_IMPLIB"); return ret; } diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 4d19b3a..6a535c1 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -17,6 +17,7 @@ #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMakefileTargetGenerator.h" @@ -1546,8 +1547,10 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( if (!text) { text = "Running external command ..."; } - depends.insert(depends.end(), gt->GetUtilities().begin(), - gt->GetUtilities().end()); + depends.reserve(gt->GetUtilities().size()); + for (BT<std::string> const& u : gt->GetUtilities()) { + depends.push_back(u.Value); + } this->AppendEcho(commands, text, cmLocalUnixMakefileGenerator3::EchoGlobal); @@ -1819,8 +1822,8 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( // Build a list of preprocessor definitions for the target. std::set<std::string> defines; - this->AddCompileDefinitions(defines, target, this->ConfigName, - implicitLang.first); + this->GetTargetDefines(target, this->ConfigName, implicitLang.first, + defines); if (!defines.empty()) { /* clang-format off */ cmakefileStream diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 8428672..7630691 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -735,8 +735,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( targetOptions.AddDefine(configDefine); // Add the export symbol definition for shared library objects. - if (const char* exportMacro = target->GetExportMacro()) { - targetOptions.AddDefine(exportMacro); + if (const std::string* exportMacro = target->GetExportMacro()) { + targetOptions.AddDefine(*exportMacro); } // The intermediate directory name consists of a directory for the @@ -1347,7 +1347,7 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( d != dirs.end(); ++d) { // Remove any trailing slash and skip empty paths. std::string dir = *d; - if (dir[dir.size() - 1] == '/') { + if (dir.back() == '/') { dir = dir.substr(0, dir.size() - 1); } if (dir.empty()) { diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8d163b7..790f6e0 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -28,6 +28,7 @@ #include "cmGeneratorExpressionEvaluationFile.h" #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" // IWYU pragma: keep +#include "cmInstallSubdirectoryGenerator.h" #include "cmListFileCache.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" @@ -66,7 +67,7 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, this->WarnUnused = this->GetCMakeInstance()->GetWarnUnused(); this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars(); - this->SuppressWatches = false; + this->SuppressSideEffects = false; // Setup the default include complaint regular expression (match nothing). this->ComplainFileRegularExpression = "^$"; @@ -1669,6 +1670,9 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath, } else { this->UnConfiguredDirectories.push_back(subMf); } + + this->AddInstallGenerator(new cmInstallSubdirectoryGenerator( + subMf, binPath.c_str(), excludeFromAll)); } const std::string& cmMakefile::GetCurrentSourceDirectory() const @@ -2417,7 +2421,7 @@ const std::string* cmMakefile::GetDef(const std::string& name) const } #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); - if (vv && !this->SuppressWatches) { + if (vv && !this->SuppressSideEffects) { bool const watch_function_executed = vv->VariableAccessed(name, def ? cmVariableWatch::VARIABLE_READ_ACCESS @@ -2504,11 +2508,11 @@ const std::string& cmMakefile::ExpandVariablesInString( compareResults = true; // Suppress variable watches to avoid calling hooks twice. Suppress new // dereferences since the OLD behavior is still what is actually used. - this->SuppressWatches = true; + this->SuppressSideEffects = true; newError = ExpandVariablesInStringNew( newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename, line, removeEmpty, replaceAt); - this->SuppressWatches = false; + this->SuppressSideEffects = false; CM_FALLTHROUGH; } case cmPolicies::OLD: @@ -2762,7 +2766,7 @@ cmake::MessageType cmMakefile::ExpandVariablesInStringNew( } else { varresult = value; } - } else if (!removeEmpty) { + } else if (!removeEmpty && !this->SuppressSideEffects) { // check to see if we need to print a warning // if strict mode is on and the variable has // not been "cleared"/initialized with a set(foo ) call @@ -3496,7 +3500,8 @@ void cmMakefile::DisplayStatus(const char* message, float s) const cm->UpdateProgress(message, s); } -std::string cmMakefile::GetModulesFile(const char* filename) const +std::string cmMakefile::GetModulesFile(const char* filename, + bool& system) const { std::string result; @@ -3543,8 +3548,10 @@ std::string cmMakefile::GetModulesFile(const char* filename) const // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file // from which we are being called is located itself in CMAKE_ROOT, then // prefer results from CMAKE_ROOT depending on the policy setting. + system = false; result = moduleInCMakeModulePath; if (result.empty()) { + system = true; result = moduleInCMakeRoot; } @@ -3567,11 +3574,13 @@ std::string cmMakefile::GetModulesFile(const char* filename) const CM_FALLTHROUGH; } case cmPolicies::OLD: + system = false; result = moduleInCMakeModulePath; break; case cmPolicies::REQUIRED_IF_USED: case cmPolicies::REQUIRED_ALWAYS: case cmPolicies::NEW: + system = true; result = moduleInCMakeRoot; break; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index b30f281..aa94054 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -689,7 +689,13 @@ public: /** * Return a location of a file in cmake or custom modules directory */ - std::string GetModulesFile(const char* name) const; + std::string GetModulesFile(const char* name) const + { + bool system; + return this->GetModulesFile(name, system); + } + + std::string GetModulesFile(const char* name, bool& system) const; ///! Set/Get a property of this directory void SetProperty(const std::string& prop, const char* value); @@ -1025,7 +1031,7 @@ private: bool CheckCMP0000; std::set<std::string> WarnedCMP0074; bool IsSourceFileTryCompile; - mutable bool SuppressWatches; + mutable bool SuppressSideEffects; }; #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index f423560..9acae49 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -97,6 +97,9 @@ void cmMakefileTargetGenerator::GetTargetLinkFlags( this->GeneratorTarget->GetLinkOptions(opts, this->ConfigName, linkLanguage); // LINK_OPTIONS are escaped. this->LocalGenerator->AppendCompileOptions(flags, opts); + + this->LocalGenerator->AppendPositionIndependentLinkerFlags( + flags, this->GeneratorTarget, this->ConfigName, linkLanguage); } void cmMakefileTargetGenerator::CreateRuleFile() @@ -590,7 +593,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // mingw32-make incorrectly interprets 'a\ b c' as 'a b' and 'c' // (but 'a\ b "c"' as 'a\', 'b', and 'c'!). Workaround this by // avoiding a trailing backslash in the argument. - targetOutPathCompilePDB[targetOutPathCompilePDB.size() - 1] = '/'; + targetOutPathCompilePDB.back() = '/'; } } cmRulePlaceholderExpander::RuleVariables vars; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 6436969..1386706 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -506,7 +506,6 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact, /*realname=*/true)); cmakeCommand += targetOutputReal; - cmakeCommand += " || true"; linkCmds.push_back(std::move(cmakeCommand)); } return linkCmds; diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index 04a9318..7fd7732 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -186,7 +186,7 @@ bool cmOrderDirectoriesConstraintSOName::FindConflict(std::string const& dir) // file name. Usually the soname starts with the library name. std::string base = this->FileName; std::set<std::string>::const_iterator first = files.lower_bound(base); - ++base[base.size() - 1]; + ++base.back(); std::set<std::string>::const_iterator last = files.upper_bound(base); if (first != last) { return true; diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index dbe6fa1..43a0107 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -118,11 +118,11 @@ std::string cmOutputConverter::ForceToRelativePath( std::string const& local_path, std::string const& remote_path) { // The paths should never be quoted. - assert(local_path[0] != '\"'); - assert(remote_path[0] != '\"'); + assert(local_path.front() != '\"'); + assert(remote_path.front() != '\"'); // The local path should never have a trailing slash. - assert(local_path.empty() || local_path[local_path.size() - 1] != '/'); + assert(local_path.empty() || local_path.back() != '/'); // If the path is already relative then just return the path. if (!cmSystemTools::FileIsFullPath(remote_path)) { diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx index e2de3f9..87c1ec0 100644 --- a/Source/cmOutputRequiredFilesCommand.cxx +++ b/Source/cmOutputRequiredFilesCommand.cxx @@ -340,7 +340,7 @@ protected: } else { // try to guess which include path to use for (std::string incpath : this->IncludeDirectories) { - if (!incpath.empty() && incpath[incpath.size() - 1] != '/') { + if (!incpath.empty() && incpath.back() != '/') { incpath = incpath + "/"; } incpath = incpath + path; @@ -421,7 +421,7 @@ protected: } for (std::string path : this->IncludeDirectories) { - if (!path.empty() && path[path.size() - 1] != '/') { + if (!path.empty() && path.back() != '/') { path = path + "/"; } path = path + fname; @@ -435,7 +435,7 @@ protected: if (extraPath) { std::string path = extraPath; - if (!path.empty() && path[path.size() - 1] != '/') { + if (!path.empty() && path.back() != '/') { path = path + "/"; } path = path + fname; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index a367e47..6b1314f 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -236,11 +236,20 @@ class cmMakefile; "target_link_libraries allows use with targets in other directories.", 3, \ 13, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0080, \ - "BundleUtilities cannot be included at configure time", 3, 13, 0, \ + "BundleUtilities cannot be included at configure time.", 3, 13, 0, \ cmPolicies::WARN) \ SELECT(POLICY, CMP0081, \ "Relative paths not allowed in LINK_DIRECTORIES target property.", \ - 3, 13, 0, cmPolicies::WARN) + 3, 13, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0082, \ + "Install rules from add_subdirectory() are interleaved with those " \ + "in caller.", \ + 3, 14, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0083, "Add PIE options when linking executable.", 3, 14, \ + 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0084, \ + "The FindQt module does not exist for find_package().", 3, 14, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ @@ -267,7 +276,8 @@ class cmMakefile; F(CMP0069) \ F(CMP0073) \ F(CMP0076) \ - F(CMP0081) + F(CMP0081) \ + F(CMP0083) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx new file mode 100644 index 0000000..5470ec3 --- /dev/null +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -0,0 +1,185 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoGenGlobalInitializer.h" +#include "cmQtAutoGen.h" +#include "cmQtAutoGenInitializer.h" + +#include "cmAlgorithms.h" +#include "cmCustomCommandLines.h" +#include "cmGeneratorTarget.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmState.h" +#include "cmStateTypes.h" +#include "cmSystemTools.h" +#include "cmTarget.h" + +#include <memory> +#include <utility> + +cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer( + std::vector<cmLocalGenerator*> const& localGenerators) +{ + for (cmLocalGenerator* localGen : localGenerators) { + // Detect global autogen and autorcc target names + bool globalAutoGenTarget = false; + bool globalAutoRccTarget = false; + { + cmMakefile* makefile = localGen->GetMakefile(); + // Detect global autogen target name + if (cmSystemTools::IsOn( + makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET"))) { + std::string targetName = + makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME"); + if (targetName.empty()) { + targetName = "autogen"; + } + GlobalAutoGenTargets_.emplace(localGen, std::move(targetName)); + globalAutoGenTarget = true; + } + + // Detect global autorcc target name + if (cmSystemTools::IsOn( + makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET"))) { + std::string targetName = + makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME"); + if (targetName.empty()) { + targetName = "autorcc"; + } + GlobalAutoRccTargets_.emplace(localGen, std::move(targetName)); + globalAutoRccTarget = true; + } + } + + // Find targets that require AUTOMOC/UIC/RCC processing + for (cmGeneratorTarget* target : localGen->GetGeneratorTargets()) { + // Process only certain target types + switch (target->GetType()) { + case cmStateEnums::EXECUTABLE: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: + case cmStateEnums::OBJECT_LIBRARY: + // Process target + break; + default: + // Don't process target + continue; + } + if (target->IsImported()) { + // Don't process target + continue; + } + + bool const moc = target->GetPropertyAsBool("AUTOMOC"); + bool const uic = target->GetPropertyAsBool("AUTOUIC"); + bool const rcc = target->GetPropertyAsBool("AUTORCC"); + if (moc || uic || rcc) { + // We support Qt4 and Qt5 + auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target); + if ((qtVersion.Major == 4) || (qtVersion.Major == 5)) { + // Create autogen target initializer + Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>( + this, target, qtVersion, moc, uic, rcc, globalAutoGenTarget, + globalAutoRccTarget)); + } + } + } + } +} + +cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer() +{ +} + +void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget( + cmLocalGenerator* localGen, std::string const& name, + std::string const& comment) +{ + // Test if the target already exists + if (localGen->FindGeneratorTargetToUse(name) == nullptr) { + cmMakefile* makefile = localGen->GetMakefile(); + + // Create utility target + cmTarget* target = makefile->AddUtilityCommand( + name, cmMakefile::TargetOrigin::Generator, true, + makefile->GetHomeOutputDirectory().c_str() /*work dir*/, + std::vector<std::string>() /*output*/, + std::vector<std::string>() /*depends*/, cmCustomCommandLines(), false, + comment.c_str()); + localGen->AddGeneratorTarget(new cmGeneratorTarget(target, localGen)); + + // Set FOLDER property in the target + { + char const* folder = + makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); + if (folder != nullptr) { + target->SetProperty("FOLDER", folder); + } + } + } +} + +void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen( + cmLocalGenerator* localGen, std::string const& targetName) +{ + auto it = GlobalAutoGenTargets_.find(localGen); + if (it != GlobalAutoGenTargets_.end()) { + cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); + if (target != nullptr) { + target->Target->AddUtility(targetName, localGen->GetMakefile()); + } + } +} + +void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc( + cmLocalGenerator* localGen, std::string const& targetName) +{ + auto it = GlobalAutoRccTargets_.find(localGen); + if (it != GlobalAutoRccTargets_.end()) { + cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second); + if (target != nullptr) { + target->Target->AddUtility(targetName, localGen->GetMakefile()); + } + } +} + +bool cmQtAutoGenGlobalInitializer::generate() +{ + return (InitializeCustomTargets() && SetupCustomTargets()); +} + +bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets() +{ + // Initialize global autogen targets + { + std::string const comment = "Global AUTOGEN target"; + for (auto const& pair : GlobalAutoGenTargets_) { + GetOrCreateGlobalTarget(pair.first, pair.second, comment); + } + } + // Initialize global autorcc targets + { + std::string const comment = "Global AUTORCC target"; + for (auto const& pair : GlobalAutoRccTargets_) { + GetOrCreateGlobalTarget(pair.first, pair.second, comment); + } + } + // Initialize per target autogen targets + for (auto& initializer : Initializers_) { + if (!initializer->InitCustomTargets()) { + return false; + } + } + return true; +} + +bool cmQtAutoGenGlobalInitializer::SetupCustomTargets() +{ + for (auto& initializer : Initializers_) { + if (!initializer->SetupCustomTargets()) { + return false; + } + } + return true; +} diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h new file mode 100644 index 0000000..9e6bac0 --- /dev/null +++ b/Source/cmQtAutoGenGlobalInitializer.h @@ -0,0 +1,47 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGenGlobalInitializer_h +#define cmQtAutoGenGlobalInitializer_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <map> +#include <memory> // IWYU pragma: keep +#include <string> +#include <vector> + +class cmLocalGenerator; +class cmQtAutoGenInitializer; + +/// @brief Initializes the QtAutoGen generators +class cmQtAutoGenGlobalInitializer +{ +public: + cmQtAutoGenGlobalInitializer( + std::vector<cmLocalGenerator*> const& localGenerators); + ~cmQtAutoGenGlobalInitializer(); + + bool generate(); + +private: + friend class cmQtAutoGenInitializer; + + bool InitializeCustomTargets(); + bool SetupCustomTargets(); + + void GetOrCreateGlobalTarget(cmLocalGenerator* localGen, + std::string const& name, + std::string const& comment); + + void AddToGlobalAutoGen(cmLocalGenerator* localGen, + std::string const& targetName); + void AddToGlobalAutoRcc(cmLocalGenerator* localGen, + std::string const& targetName); + +private: + std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_; + std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_; + std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_; +}; + +#endif diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 8a202a2..e71feac 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -2,16 +2,17 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenInitializer.h" #include "cmQtAutoGen.h" +#include "cmQtAutoGenGlobalInitializer.h" #include "cmAlgorithms.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmDuration.h" #include "cmFilePathChecksum.h" -#include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLinkItem.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -173,17 +174,116 @@ static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, return cycle; } -cmQtAutoGenInitializer::cmQtAutoGenInitializer(cmGeneratorTarget* target, - bool mocEnabled, - bool uicEnabled, - bool rccEnabled, - IntegerVersion const& qtVersion) - : Target(target) +cmQtAutoGenInitializer::InfoWriter::InfoWriter(std::string const& filename) +{ + Ofs_.SetCopyIfDifferent(true); + Ofs_.Open(filename, false, true); +} + +template <class IT> +std::string cmQtAutoGenInitializer::InfoWriter::ListJoin(IT it_begin, + IT it_end) +{ + std::string res; + for (IT it = it_begin; it != it_end; ++it) { + if (it != it_begin) { + res += ';'; + } + for (const char* c = it->c_str(); *c; ++c) { + if (*c == '"') { + // Escape the double quote to avoid ending the argument. + res += "\\\""; + } else if (*c == '$') { + // Escape the dollar to avoid expanding variables. + res += "\\$"; + } else if (*c == '\\') { + // Escape the backslash to avoid other escapes. + res += "\\\\"; + } else if (*c == ';') { + // Escape the semicolon to avoid list expansion. + res += "\\;"; + } else { + // Other characters will be parsed correctly. + res += *c; + } + } + } + return res; +} + +std::string cmQtAutoGenInitializer::InfoWriter::ConfigKey( + const char* key, std::string const& config) +{ + std::string ckey = key; + ckey += '_'; + ckey += config; + return ckey; +} + +void cmQtAutoGenInitializer::InfoWriter::Write(const char* key, + std::string const& value) +{ + Ofs_ << "set(" << key << " " << cmOutputConverter::EscapeForCMake(value) + << ")\n"; +}; + +void cmQtAutoGenInitializer::InfoWriter::WriteUInt(const char* key, + unsigned int value) +{ + Ofs_ << "set(" << key << " " << value << ")\n"; +}; + +template <class C> +void cmQtAutoGenInitializer::InfoWriter::WriteStrings(const char* key, + C const& container) +{ + Ofs_ << "set(" << key << " \"" + << ListJoin(container.begin(), container.end()) << "\")\n"; +} + +void cmQtAutoGenInitializer::InfoWriter::WriteConfig( + const char* key, std::map<std::string, std::string> const& map) +{ + for (auto const& item : map) { + Write(ConfigKey(key, item.first).c_str(), item.second); + } +}; + +template <class C> +void cmQtAutoGenInitializer::InfoWriter::WriteConfigStrings( + const char* key, std::map<std::string, C> const& map) +{ + for (auto const& item : map) { + WriteStrings(ConfigKey(key, item.first).c_str(), item.second); + } +} + +void cmQtAutoGenInitializer::InfoWriter::WriteNestedLists( + const char* key, std::vector<std::vector<std::string>> const& lists) +{ + std::vector<std::string> seplist; + for (const std::vector<std::string>& list : lists) { + std::string blist = "{"; + blist += ListJoin(list.begin(), list.end()); + blist += "}"; + seplist.push_back(std::move(blist)); + } + Write(key, cmJoin(seplist, cmQtAutoGen::ListSep)); +}; + +cmQtAutoGenInitializer::cmQtAutoGenInitializer( + cmQtAutoGenGlobalInitializer* globalInitializer, cmGeneratorTarget* target, + IntegerVersion const& qtVersion, bool mocEnabled, bool uicEnabled, + bool rccEnabled, bool globalAutogenTarget, bool globalAutoRccTarget) + : GlobalInitializer(globalInitializer) + , Target(target) , QtVersion(qtVersion) { + AutogenTarget.GlobalTarget = globalAutogenTarget; Moc.Enabled = mocEnabled; Uic.Enabled = uicEnabled; Rcc.Enabled = rccEnabled; + Rcc.GlobalTarget = globalAutoRccTarget; } bool cmQtAutoGenInitializer::InitCustomTargets() @@ -321,6 +421,9 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Autogen target: Compute user defined dependencies { + this->AutogenTarget.DependOrigin = + this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS"); + std::string const deps = this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); if (!deps.empty()) { @@ -388,14 +491,15 @@ bool cmQtAutoGenInitializer::InitMoc() { bool const appendImplicit = (this->QtVersion.Major == 5); auto GetIncludeDirs = - [this, localGen, appendImplicit](std::string const& cfg) -> std::string { + [this, localGen, + appendImplicit](std::string const& cfg) -> std::vector<std::string> { // Get the include dirs for this target, without stripping the implicit // include dirs off, see // https://gitlab.kitware.com/cmake/cmake/issues/13667 std::vector<std::string> dirs; localGen->GetIncludeDirectories(dirs, this->Target, "CXX", cfg, false, appendImplicit); - return cmJoin(dirs, ";"); + return dirs; }; // Default configuration include directories @@ -403,7 +507,7 @@ bool cmQtAutoGenInitializer::InitMoc() // Other configuration settings if (this->MultiConfig) { for (std::string const& cfg : this->ConfigsList) { - std::string dirs = GetIncludeDirs(cfg); + std::vector<std::string> dirs = GetIncludeDirs(cfg); if (dirs != this->Moc.Includes) { this->Moc.ConfigIncludes[cfg] = std::move(dirs); } @@ -414,10 +518,10 @@ bool cmQtAutoGenInitializer::InitMoc() // Moc compile definitions { auto GetCompileDefinitions = - [this, localGen](std::string const& cfg) -> std::string { + [this, localGen](std::string const& cfg) -> std::set<std::string> { std::set<std::string> defines; - localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX"); - return cmJoin(defines, ";"); + localGen->GetTargetDefines(this->Target, cfg, "CXX", defines); + return defines; }; // Default configuration defines @@ -425,7 +529,7 @@ bool cmQtAutoGenInitializer::InitMoc() // Other configuration defines if (this->MultiConfig) { for (std::string const& cfg : this->ConfigsList) { - std::string defines = GetCompileDefinitions(cfg); + std::set<std::string> defines = GetCompileDefinitions(cfg); if (defines != this->Moc.Defines) { this->Moc.ConfigDefines[cfg] = std::move(defines); } @@ -459,10 +563,11 @@ bool cmQtAutoGenInitializer::InitUic() } // Uic target options { - auto UicGetOpts = [this](std::string const& cfg) -> std::string { + auto UicGetOpts = + [this](std::string const& cfg) -> std::vector<std::string> { std::vector<std::string> opts; this->Target->GetAutoUicOptions(opts, cfg); - return cmJoin(opts, ";"); + return opts; }; // Default settings @@ -471,7 +576,7 @@ bool cmQtAutoGenInitializer::InitUic() // Configuration specific settings if (this->MultiConfig) { for (std::string const& cfg : this->ConfigsList) { - std::string options = UicGetOpts(cfg); + std::vector<std::string> options = UicGetOpts(cfg); if (options != this->Uic.Options) { this->Uic.ConfigOptions[cfg] = std::move(options); } @@ -878,6 +983,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (!this->AutogenTarget.DependFiles.empty()) { usePRE_BUILD = false; } + // Cannot use PRE_BUILD when a global autogen target is in place + if (AutogenTarget.GlobalTarget) { + usePRE_BUILD = false; + } } // Create the autogen target/command if (usePRE_BUILD) { @@ -903,7 +1012,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Add link library target dependencies to the autogen target // dependencies - { + if (this->AutogenTarget.DependOrigin) { // add_dependencies/addUtility do not support generator expressions. // We depend only on the libraries found in all configs therefore. std::map<cmGeneratorTarget const*, std::size_t> commonTargets; @@ -940,8 +1049,10 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() new cmGeneratorTarget(autogenTarget, localGen)); // Forward origin utilities to autogen target - for (std::string const& depName : this->Target->Target->GetUtilities()) { - autogenTarget->AddUtility(depName, makefile); + if (this->AutogenTarget.DependOrigin) { + for (BT<std::string> const& depName : this->Target->GetUtilities()) { + autogenTarget->AddUtility(depName.Value, makefile); + } } // Add additional autogen target dependencies to autogen target for (cmTarget* depTarget : this->AutogenTarget.DependTargets) { @@ -955,6 +1066,12 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Add autogen target to the origin target dependencies this->Target->Target->AddUtility(this->AutogenTarget.Name, makefile); + + // Add autogen target to the global autogen target dependencies + if (this->AutogenTarget.GlobalTarget) { + this->GlobalInitializer->AddToGlobalAutoGen(localGen, + this->AutogenTarget.Name); + } } return true; @@ -998,7 +1115,7 @@ bool cmQtAutoGenInitializer::InitRccTargets() std::string ccComment = "Automatic RCC for "; ccComment += FileProjectRelativePath(makefile, qrc.QrcFile); - if (qrc.Generated) { + if (qrc.Generated || this->Rcc.GlobalTarget) { // Create custom rcc target std::string ccName; { @@ -1029,6 +1146,11 @@ bool cmQtAutoGenInitializer::InitRccTargets() } // Add autogen target to the origin target dependencies this->Target->Target->AddUtility(ccName, makefile); + + // Add autogen target to the global autogen target dependencies + if (this->Rcc.GlobalTarget) { + this->GlobalInitializer->AddToGlobalAutoRcc(localGen, ccName); + } } else { // Create custom rcc command { @@ -1084,104 +1206,72 @@ bool cmQtAutoGenInitializer::SetupCustomTargets() bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - - cmGeneratedFileStream ofs; - ofs.SetCopyIfDifferent(true); - ofs.Open(this->AutogenTarget.InfoFile, false, true); + InfoWriter ofs(this->AutogenTarget.InfoFile); if (ofs) { // Utility lambdas - auto CWrite = [&ofs](const char* key, std::string const& value) { - ofs << "set(" << key << " " << cmOutputConverter::EscapeForCMake(value) - << ")\n"; - }; - auto CWriteUInt = [&ofs](const char* key, unsigned int value) { - ofs << "set(" << key << " " << value << ")\n"; - }; - auto CWriteList = [&CWrite](const char* key, - std::vector<std::string> const& list) { - CWrite(key, cmJoin(list, ";")); - }; - auto CWriteNestedLists = - [&CWrite](const char* key, - std::vector<std::vector<std::string>> const& lists) { - std::vector<std::string> seplist; - for (const std::vector<std::string>& list : lists) { - std::string blist = "{"; - blist += cmJoin(list, ";"); - blist += "}"; - seplist.push_back(std::move(blist)); - } - CWrite(key, cmJoin(seplist, cmQtAutoGen::ListSep)); - }; - auto CWriteSet = [&CWrite](const char* key, - std::set<std::string> const& list) { - CWrite(key, cmJoin(list, ";")); - }; - auto CWriteMap = [&ofs](const char* key, - std::map<std::string, std::string> const& map) { - for (auto const& item : map) { - ofs << "set(" << key << "_" << item.first << " " - << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; - } - }; + cmMakefile* makefile = this->Target->Target->GetMakefile(); auto MfDef = [makefile](const char* key) { return makefile->GetSafeDefinition(key); }; - // Write - ofs << "# Meta\n"; - CWrite("AM_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); - CWrite("AM_PARALLEL", this->AutogenTarget.Parallel); - CWrite("AM_VERBOSITY", this->Verbosity); - - ofs << "# Directories\n"; - CWrite("AM_CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR")); - CWrite("AM_CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR")); - CWrite("AM_CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR")); - CWrite("AM_CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR")); - CWrite("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", - MfDef("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")); - CWrite("AM_BUILD_DIR", this->Dir.Build); - CWrite("AM_INCLUDE_DIR", this->Dir.Include); - CWriteMap("AM_INCLUDE_DIR", this->Dir.ConfigInclude); - - ofs << "# Files\n"; - CWriteList("AM_SOURCES", this->AutogenTarget.Sources); - CWriteList("AM_HEADERS", this->AutogenTarget.Headers); - CWrite("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile); - CWriteMap("AM_SETTINGS_FILE", this->AutogenTarget.ConfigSettingsFile); - - ofs << "# Qt\n"; - CWriteUInt("AM_QT_VERSION_MAJOR", this->QtVersion.Major); - CWrite("AM_QT_MOC_EXECUTABLE", this->Moc.Executable); - CWrite("AM_QT_UIC_EXECUTABLE", this->Uic.Executable); - + // Write common settings + ofs.Write("# Meta\n"); + ofs.Write("AM_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); + ofs.Write("AM_PARALLEL", this->AutogenTarget.Parallel); + ofs.Write("AM_VERBOSITY", this->Verbosity); + + ofs.Write("# Directories\n"); + ofs.Write("AM_CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR")); + ofs.Write("AM_CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR")); + ofs.Write("AM_CMAKE_CURRENT_SOURCE_DIR", + MfDef("CMAKE_CURRENT_SOURCE_DIR")); + ofs.Write("AM_CMAKE_CURRENT_BINARY_DIR", + MfDef("CMAKE_CURRENT_BINARY_DIR")); + ofs.Write("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", + MfDef("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")); + ofs.Write("AM_BUILD_DIR", this->Dir.Build); + ofs.Write("AM_INCLUDE_DIR", this->Dir.Include); + ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude); + + ofs.Write("# Files\n"); + ofs.WriteStrings("AM_SOURCES", this->AutogenTarget.Sources); + ofs.WriteStrings("AM_HEADERS", this->AutogenTarget.Headers); + ofs.Write("AM_SETTINGS_FILE", this->AutogenTarget.SettingsFile); + ofs.WriteConfig("AM_SETTINGS_FILE", + this->AutogenTarget.ConfigSettingsFile); + + ofs.Write("# Qt\n"); + ofs.WriteUInt("AM_QT_VERSION_MAJOR", this->QtVersion.Major); + ofs.Write("AM_QT_MOC_EXECUTABLE", this->Moc.Executable); + ofs.Write("AM_QT_UIC_EXECUTABLE", this->Uic.Executable); + + // Write moc settings if (this->Moc.Enabled) { - ofs << "# MOC settings\n"; - CWriteSet("AM_MOC_SKIP", this->Moc.Skip); - CWrite("AM_MOC_DEFINITIONS", this->Moc.Defines); - CWriteMap("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines); - CWrite("AM_MOC_INCLUDES", this->Moc.Includes); - CWriteMap("AM_MOC_INCLUDES", this->Moc.ConfigIncludes); - CWrite("AM_MOC_OPTIONS", - this->Target->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); - CWrite("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); - CWrite("AM_MOC_MACRO_NAMES", - this->Target->GetSafeProperty("AUTOMOC_MACRO_NAMES")); - CWrite("AM_MOC_DEPEND_FILTERS", - this->Target->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); - CWrite("AM_MOC_PREDEFS_CMD", this->Moc.PredefsCmd); + ofs.Write("# MOC settings\n"); + ofs.WriteStrings("AM_MOC_SKIP", this->Moc.Skip); + ofs.WriteStrings("AM_MOC_DEFINITIONS", this->Moc.Defines); + ofs.WriteConfigStrings("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines); + ofs.WriteStrings("AM_MOC_INCLUDES", this->Moc.Includes); + ofs.WriteConfigStrings("AM_MOC_INCLUDES", this->Moc.ConfigIncludes); + ofs.Write("AM_MOC_OPTIONS", + this->Target->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); + ofs.Write("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); + ofs.Write("AM_MOC_MACRO_NAMES", + this->Target->GetSafeProperty("AUTOMOC_MACRO_NAMES")); + ofs.Write("AM_MOC_DEPEND_FILTERS", + this->Target->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); + ofs.Write("AM_MOC_PREDEFS_CMD", this->Moc.PredefsCmd); } + // Write uic settings if (this->Uic.Enabled) { - ofs << "# UIC settings\n"; - CWriteSet("AM_UIC_SKIP", this->Uic.Skip); - CWrite("AM_UIC_TARGET_OPTIONS", this->Uic.Options); - CWriteMap("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions); - CWriteList("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles); - CWriteNestedLists("AM_UIC_OPTIONS_OPTIONS", this->Uic.FileOptions); - CWriteList("AM_UIC_SEARCH_PATHS", this->Uic.SearchPaths); + ofs.Write("# UIC settings\n"); + ofs.WriteStrings("AM_UIC_SKIP", this->Uic.Skip); + ofs.WriteStrings("AM_UIC_TARGET_OPTIONS", this->Uic.Options); + ofs.WriteConfigStrings("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions); + ofs.WriteStrings("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles); + ofs.WriteNestedLists("AM_UIC_OPTIONS_OPTIONS", this->Uic.FileOptions); + ofs.WriteStrings("AM_UIC_SEARCH_PATHS", this->Uic.SearchPaths); } } else { std::string err = "AutoGen: Could not write file "; @@ -1196,47 +1286,33 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() bool cmQtAutoGenInitializer::SetupWriteRccInfo() { for (Qrc const& qrc : this->Rcc.Qrcs) { - cmGeneratedFileStream ofs; - ofs.SetCopyIfDifferent(true); - ofs.Open(qrc.InfoFile, false, true); + InfoWriter ofs(qrc.InfoFile); if (ofs) { - // Utility lambdas - auto CWrite = [&ofs](const char* key, std::string const& value) { - ofs << "set(" << key << " " << cmOutputConverter::EscapeForCMake(value) - << ")\n"; - }; - auto CWriteMap = [&ofs](const char* key, - std::map<std::string, std::string> const& map) { - for (auto const& item : map) { - ofs << "set(" << key << "_" << item.first << " " - << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; - } - }; - // Write - ofs << "# Configurations\n"; - CWrite("ARCC_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); - CWrite("ARCC_VERBOSITY", this->Verbosity); - ofs << "# Settings file\n"; - CWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); - CWriteMap("ARCC_SETTINGS_FILE", qrc.ConfigSettingsFile); - - ofs << "# Directories\n"; - CWrite("ARCC_BUILD_DIR", this->Dir.Build); - CWrite("ARCC_INCLUDE_DIR", this->Dir.Include); - CWriteMap("ARCC_INCLUDE_DIR", this->Dir.ConfigInclude); - - ofs << "# Rcc executable\n"; - CWrite("ARCC_RCC_EXECUTABLE", this->Rcc.Executable); - CWrite("ARCC_RCC_LIST_OPTIONS", cmJoin(this->Rcc.ListOptions, ";")); - - ofs << "# Rcc job\n"; - CWrite("ARCC_LOCK_FILE", qrc.LockFile); - CWrite("ARCC_SOURCE", qrc.QrcFile); - CWrite("ARCC_OUTPUT_CHECKSUM", qrc.PathChecksum); - CWrite("ARCC_OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.RccFile)); - CWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); - CWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); + ofs.Write("# Configurations\n"); + ofs.Write("ARCC_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); + ofs.Write("ARCC_VERBOSITY", this->Verbosity); + ofs.Write("# Settings file\n"); + ofs.Write("ARCC_SETTINGS_FILE", qrc.SettingsFile); + ofs.WriteConfig("ARCC_SETTINGS_FILE", qrc.ConfigSettingsFile); + + ofs.Write("# Directories\n"); + ofs.Write("ARCC_BUILD_DIR", this->Dir.Build); + ofs.Write("ARCC_INCLUDE_DIR", this->Dir.Include); + ofs.WriteConfig("ARCC_INCLUDE_DIR", this->Dir.ConfigInclude); + + ofs.Write("# Rcc executable\n"); + ofs.Write("ARCC_RCC_EXECUTABLE", this->Rcc.Executable); + ofs.WriteStrings("ARCC_RCC_LIST_OPTIONS", this->Rcc.ListOptions); + + ofs.Write("# Rcc job\n"); + ofs.Write("ARCC_LOCK_FILE", qrc.LockFile); + ofs.Write("ARCC_SOURCE", qrc.QrcFile); + ofs.Write("ARCC_OUTPUT_CHECKSUM", qrc.PathChecksum); + ofs.Write("ARCC_OUTPUT_NAME", + cmSystemTools::GetFilenameName(qrc.RccFile)); + ofs.WriteStrings("ARCC_OPTIONS", qrc.Options); + ofs.WriteStrings("ARCC_INPUTS", qrc.Resources); } else { std::string err = "AutoRcc: Could not write file "; err += qrc.InfoFile; diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index ce00e00..903ec85 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -4,15 +4,18 @@ #define cmQtAutoGenInitializer_h #include "cmConfigure.h" // IWYU pragma: keep +#include "cmGeneratedFileStream.h" #include "cmQtAutoGen.h" #include <map> +#include <ostream> #include <set> #include <string> #include <vector> class cmGeneratorTarget; class cmTarget; +class cmQtAutoGenGlobalInitializer; /// @brief Initializes the QtAutoGen generators class cmQtAutoGenInitializer : public cmQtAutoGen @@ -43,12 +46,47 @@ public: std::vector<std::string> Resources; }; + /// @brief Writes a CMake info file + class InfoWriter + { + public: + /// @brief Open the given file + InfoWriter(std::string const& filename); + + /// @return True if the file is open + operator bool() const { return static_cast<bool>(Ofs_); } + + void Write(const char* text) { Ofs_ << text; } + void Write(const char* key, std::string const& value); + void WriteUInt(const char* key, unsigned int value); + + template <class C> + void WriteStrings(const char* key, C const& container); + void WriteConfig(const char* key, + std::map<std::string, std::string> const& map); + template <class C> + void WriteConfigStrings(const char* key, + std::map<std::string, C> const& map); + void WriteNestedLists(const char* key, + std::vector<std::vector<std::string>> const& lists); + + private: + template <class IT> + static std::string ListJoin(IT it_begin, IT it_end); + static std::string ConfigKey(const char* key, std::string const& config); + + private: + cmGeneratedFileStream Ofs_; + }; + public: static IntegerVersion GetQtVersion(cmGeneratorTarget const* target); - cmQtAutoGenInitializer(cmGeneratorTarget* target, bool mocEnabled, + cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer, + cmGeneratorTarget* target, + IntegerVersion const& qtVersion, bool mocEnabled, bool uicEnabled, bool rccEnabled, - IntegerVersion const& qtVersion); + bool globalAutogenTarget, bool globalAutoRccTarget); bool InitCustomTargets(); bool SetupCustomTargets(); @@ -76,6 +114,7 @@ private: std::string& errorMessage); private: + cmQtAutoGenGlobalInitializer* GlobalInitializer; cmGeneratorTarget* Target; // Configuration @@ -100,6 +139,7 @@ private: struct { std::string Name; + bool GlobalTarget = false; // Settings std::string Parallel; // Configuration files @@ -107,6 +147,7 @@ private: std::string SettingsFile; std::map<std::string, std::string> ConfigSettingsFile; // Dependencies + bool DependOrigin = false; std::set<std::string> DependFiles; std::set<cmTarget*> DependTargets; // Sources to process @@ -123,10 +164,10 @@ private: std::string Executable; std::string PredefsCmd; std::set<std::string> Skip; - std::string Includes; - std::map<std::string, std::string> ConfigIncludes; - std::string Defines; - std::map<std::string, std::string> ConfigDefines; + std::vector<std::string> Includes; + std::map<std::string, std::vector<std::string>> ConfigIncludes; + std::set<std::string> Defines; + std::map<std::string, std::set<std::string>> ConfigDefines; std::string MocsCompilation; } Moc; @@ -137,8 +178,8 @@ private: std::string Executable; std::set<std::string> Skip; std::vector<std::string> SearchPaths; - std::string Options; - std::map<std::string, std::string> ConfigOptions; + std::vector<std::string> Options; + std::map<std::string, std::vector<std::string>> ConfigOptions; std::vector<std::string> FileFiles; std::vector<std::vector<std::string>> FileOptions; } Uic; @@ -147,6 +188,7 @@ private: struct { bool Enabled = false; + bool GlobalTarget = false; std::string Executable; std::vector<std::string> ListOptions; std::vector<Qrc> Qrcs; diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx index 32ad0b0..8a04c1f 100644 --- a/Source/cmRST.cxx +++ b/Source/cmRST.cxx @@ -228,8 +228,7 @@ void cmRST::ProcessLine(std::string const& line) else { this->NormalLine(line); this->LastLineEndedInColonColon = - (line.size() >= 2 && line[line.size() - 2] == ':' && - line[line.size() - 1] == ':'); + (line.size() >= 2 && line[line.size() - 2] == ':' && line.back() == ':'); } } diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index a71861a..0dfb797 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -110,7 +110,7 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (replaceValues.Target) { if (variable == "TARGET_QUOTED") { std::string targetQuoted = replaceValues.Target; - if (!targetQuoted.empty() && targetQuoted[0] != '\"') { + if (!targetQuoted.empty() && targetQuoted.front() != '\"') { targetQuoted = '\"'; targetQuoted += replaceValues.Target; targetQuoted += '\"'; @@ -120,7 +120,7 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable( if (variable == "TARGET_UNQUOTED") { std::string unquoted = replaceValues.Target; std::string::size_type sz = unquoted.size(); - if (sz > 2 && unquoted[0] == '\"' && unquoted[sz - 1] == '\"') { + if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') { unquoted = unquoted.substr(1, sz - 2); } return unquoted; diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx index 985aac8..1a2d1c6 100644 --- a/Source/cmSetCommand.cxx +++ b/Source/cmSetCommand.cxx @@ -54,7 +54,7 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, } // SET (VAR PARENT_SCOPE) // Removes the definition of VAR // in the parent scope. - if (args.size() == 2 && args[args.size() - 1] == "PARENT_SCOPE") { + if (args.size() == 2 && args.back() == "PARENT_SCOPE") { this->Makefile->RaiseScope(variable, nullptr); return true; } @@ -74,12 +74,12 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, unsigned int ignoreLastArgs = 0; // look for PARENT_SCOPE argument - if (args.size() > 1 && args[args.size() - 1] == "PARENT_SCOPE") { + if (args.size() > 1 && args.back() == "PARENT_SCOPE") { parentScope = true; ignoreLastArgs++; } else { // look for FORCE argument - if (args.size() > 4 && args[args.size() - 1] == "FORCE") { + if (args.size() > 4 && args.back() == "FORCE") { force = true; ignoreLastArgs++; } @@ -103,7 +103,7 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, // we should be nice and try to catch some simple screwups if the last or // next to last args are CACHE then they screwed up. If they used FORCE // without CACHE they screwed up - if ((args[args.size() - 1] == "CACHE") || + if ((args.back() == "CACHE") || (args.size() > 1 && args[args.size() - 2] == "CACHE") || (force && !cache)) { this->SetError("given invalid arguments for CACHE mode."); diff --git a/Source/cmState.cxx b/Source/cmState.cxx index a2008a0..4bbd2e0 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -867,8 +867,8 @@ static bool ParseEntryWithoutType(const std::string& entry, std::string& var, // if value is enclosed in single quotes ('foo') then remove them // it is used to enclose trailing space or tab - if (flag && value.size() >= 2 && value[0] == '\'' && - value[value.size() - 1] == '\'') { + if (flag && value.size() >= 2 && value.front() == '\'' && + value.back() == '\'') { value = value.substr(1, value.size() - 2); } @@ -900,8 +900,8 @@ bool cmState::ParseCacheEntry(const std::string& entry, std::string& var, // if value is enclosed in single quotes ('foo') then remove them // it is used to enclose trailing space or tab - if (flag && value.size() >= 2 && value[0] == '\'' && - value[value.size() - 1] == '\'') { + if (flag && value.size() >= 2 && value.front() == '\'' && + value.back() == '\'') { value = value.substr(1, value.size() - 2); } diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 1605fd7..91d6190 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -156,7 +156,7 @@ bool cmStringCommand::HandleAsciiCommand(std::vector<std::string> const& args) return false; } std::string::size_type cc; - std::string const& outvar = args[args.size() - 1]; + std::string const& outvar = args.back(); std::string output; for (cc = 1; cc < args.size() - 1; cc++) { int ch = atoi(args[cc].c_str()); @@ -755,7 +755,7 @@ bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args) this->SetError("sub-command RANDOM invoked with bad length."); return false; } - const std::string& variableName = args[args.size() - 1]; + const std::string& variableName = args.back(); std::vector<char> result; @@ -765,8 +765,7 @@ bool cmStringCommand::HandleRandomCommand(std::vector<std::string> const& args) } const char* alphaPtr = alphabet.c_str(); - int cc; - for (cc = 0; cc < length; cc++) { + for (int cc = 0; cc < length; cc++) { int idx = static_cast<int>(sizeofAlphabet * rand() / (RAND_MAX + 1.0)); result.push_back(*(alphaPtr + idx)); } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 568ee82..9866d13 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1301,7 +1301,7 @@ bool cmSystemTools::SimpleGlob(const std::string& glob, int type /* = 0 */) { files.clear(); - if (glob[glob.size() - 1] != '*') { + if (glob.back() != '*') { return false; } std::string path = cmSystemTools::GetFilenamePath(glob); @@ -1318,7 +1318,7 @@ bool cmSystemTools::SimpleGlob(const std::string& glob, if ((std::string(d.GetFile(i)) != ".") && (std::string(d.GetFile(i)) != "..")) { std::string fname = path; - if (path[path.size() - 1] != '/') { + if (path.back() != '/') { fname += "/"; } fname += d.GetFile(i); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index f0d6519..92d5505 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -87,7 +87,7 @@ const char* cmTargetPropertyComputer::GetSources<cmTarget>( cmSystemTools::ExpandListArgument(entry, files); for (std::string const& file : files) { if (cmHasLiteralPrefix(file, "$<TARGET_OBJECTS:") && - file[file.size() - 1] == '>') { + file.back() == '>') { std::string objLibName = file.substr(17, file.size() - 18); if (cmGeneratorExpression::Find(objLibName) != std::string::npos) { @@ -218,6 +218,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", nullptr); this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr); this->SetPropertyDefault("BUILD_RPATH", nullptr); + this->SetPropertyDefault("BUILD_RPATH_USE_ORIGIN", nullptr); this->SetPropertyDefault("INSTALL_NAME_DIR", nullptr); this->SetPropertyDefault("INSTALL_RPATH", ""); this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF"); @@ -238,6 +239,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("AUTOMOC", nullptr); this->SetPropertyDefault("AUTOUIC", nullptr); this->SetPropertyDefault("AUTORCC", nullptr); + this->SetPropertyDefault("AUTOGEN_ORIGIN_DEPENDS", nullptr); this->SetPropertyDefault("AUTOGEN_PARALLEL", nullptr); this->SetPropertyDefault("AUTOMOC_COMPILER_PREDEFINES", nullptr); this->SetPropertyDefault("AUTOMOC_DEPEND_FILTERS", nullptr); @@ -486,24 +488,10 @@ cmGlobalGenerator* cmTarget::GetGlobalGenerator() const return this->GetMakefile()->GetGlobalGenerator(); } -void cmTarget::AddUtility(const std::string& u, cmMakefile* makefile) +void cmTarget::AddUtility(std::string const& u, cmMakefile* mf) { - if (this->Utilities.insert(u).second && makefile) { - this->UtilityBacktraces.insert( - std::make_pair(u, makefile->GetBacktrace())); - } -} - -cmListFileBacktrace const* cmTarget::GetUtilityBacktrace( - const std::string& u) const -{ - std::map<std::string, cmListFileBacktrace>::const_iterator i = - this->UtilityBacktraces.find(u); - if (i == this->UtilityBacktraces.end()) { - return nullptr; - } - - return &i->second; + BT<std::string> util(u, mf ? mf->GetBacktrace() : cmListFileBacktrace()); + this->Utilities.insert(util); } cmListFileBacktrace const& cmTarget::GetBacktrace() const diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 694de1c..aa2859d 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -190,10 +190,12 @@ public: * name as would be specified to the ADD_EXECUTABLE or UTILITY_SOURCE * commands. It is not a full path nor does it have an extension. */ - void AddUtility(const std::string& u, cmMakefile* makefile = nullptr); + void AddUtility(std::string const& u, cmMakefile* mf = nullptr); ///! Get the utilities used by this target - std::set<std::string> const& GetUtilities() const { return this->Utilities; } - cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const; + std::set<BT<std::string>> const& GetUtilities() const + { + return this->Utilities; + } ///! Set/Get a property of this target file void SetProperty(const std::string& prop, const char* value); @@ -307,8 +309,7 @@ private: bool IsGeneratorProvided; cmPropertyMap Properties; std::set<std::string> SystemIncludeDirectories; - std::set<std::string> Utilities; - std::map<std::string, cmListFileBacktrace> UtilityBacktraces; + std::set<BT<std::string>> Utilities; cmPolicies::PolicyMap PolicyMap; std::string Name; std::string InstallPath; diff --git a/Source/cmTargetDepend.h b/Source/cmTargetDepend.h index b698db6..5ea0085 100644 --- a/Source/cmTargetDepend.h +++ b/Source/cmTargetDepend.h @@ -19,6 +19,7 @@ class cmTargetDepend // mutable members to achieve a map with set syntax. mutable bool Link; mutable bool Util; + mutable cmListFileBacktrace Backtrace; public: cmTargetDepend(cmGeneratorTarget const* t) @@ -42,8 +43,13 @@ public: this->Link = true; } } + void SetBacktrace(cmListFileBacktrace const& bt) const + { + this->Backtrace = bt; + } bool IsLink() const { return this->Link; } bool IsUtil() const { return this->Util; } + cmListFileBacktrace const& GetBacktrace() const { return this->Backtrace; } }; /** Unordered set of (direct) dependencies of a target. */ diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 9a8fd96..1b8ee81 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -84,15 +84,6 @@ bool cmTargetPropCommandBase::ProcessContentArgs( this->SetError("called with invalid arguments"); return false; } - if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY && - scope != "INTERFACE") { - this->SetError("may only set INTERFACE properties on INTERFACE targets"); - return false; - } - if (this->Target->IsImported() && scope != "INTERFACE") { - this->SetError("may only set INTERFACE properties on IMPORTED targets"); - return false; - } ++argIndex; @@ -101,10 +92,21 @@ bool cmTargetPropCommandBase::ProcessContentArgs( for (unsigned int i = argIndex; i < args.size(); ++i, ++argIndex) { if (args[i] == "PUBLIC" || args[i] == "PRIVATE" || args[i] == "INTERFACE") { - return this->PopulateTargetProperies(scope, content, prepend, system); + break; } content.push_back(args[i]); } + if (!content.empty()) { + if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY && + scope != "INTERFACE") { + this->SetError("may only set INTERFACE properties on INTERFACE targets"); + return false; + } + if (this->Target->IsImported() && scope != "INTERFACE") { + this->SetError("may only set INTERFACE properties on IMPORTED targets"); + return false; + } + } return this->PopulateTargetProperies(scope, content, prepend, system); } @@ -112,6 +114,9 @@ bool cmTargetPropCommandBase::PopulateTargetProperies( const std::string& scope, const std::vector<std::string>& content, bool prepend, bool system) { + if (content.empty()) { + return true; + } if (scope == "PRIVATE" || scope == "PUBLIC") { if (!this->HandleDirectContent(this->Target, content, prepend, system)) { return false; diff --git a/Source/cmVS141CLFlagTable.h b/Source/cmVS141CLFlagTable.h index 2a9944a..7d219be 100644 --- a/Source/cmVS141CLFlagTable.h +++ b/Source/cmVS141CLFlagTable.h @@ -194,6 +194,8 @@ static cmVS7FlagTable cmVS141CLFlagTable[] = { { "EnablePREfast", "analyze", "", "true", 0 }, { "UseFullPaths", "FC", "", "true", 0 }, { "OmitDefaultLibName", "Zl", "", "true", 0 }, + { "SupportJustMyCode", "JMC-", "", "false", 0 }, + { "SupportJustMyCode", "JMC", "", "true", 0 }, // Bool Properties With Argument { "MultiProcessorCompilation", "MP", "", "true", diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 334c15b..e9a1a67 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -45,24 +45,21 @@ struct cmVisualStudio10TargetGenerator::Elem bool HasContent = false; std::string Tag; - Elem(std::ostream& s) + Elem(std::ostream& s, const char* tag) : S(s) , Indent(0) + , Tag(tag) { + this->StartElement(); } Elem(const Elem&) = delete; - Elem(Elem& par) - : S(par.S) - , Indent(par.Indent + 1) - { - par.SetHasElements(); - } Elem(Elem& par, const char* tag) : S(par.S) , Indent(par.Indent + 1) + , Tag(tag) { par.SetHasElements(); - this->StartElement(tag); + this->StartElement(); } void SetHasElements() { @@ -72,12 +69,7 @@ struct cmVisualStudio10TargetGenerator::Elem } } std::ostream& WriteString(const char* line); - Elem& StartElement(const std::string& tag) - { - this->Tag = tag; - this->WriteString("<") << tag; - return *this; - } + void StartElement() { this->WriteString("<") << this->Tag; } void Element(const char* tag, const std::string& val) { Elem(*this, tag).Content(val); @@ -87,8 +79,6 @@ struct cmVisualStudio10TargetGenerator::Elem this->S << " " << an << "=\"" << cmVS10EscapeAttr(av) << "\""; return *this; } - // This method for now assumes that this->Tag has been set, e.g. by calling - // StartElement(). void Content(const std::string& val) { if (!this->HasContent) { @@ -379,8 +369,7 @@ void cmVisualStudio10TargetGenerator::Generate() << this->GlobalGenerator->Encoding() << "\"?>" << "\n"; { - Elem e0(BuildFileStream); - e0.StartElement("Project"); + Elem e0(BuildFileStream, "Project"); e0.Attribute("DefaultTargets", "Build"); e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion()); e0.Attribute("xmlns", @@ -921,8 +910,8 @@ void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0) xamlType = "Page"; } - Elem e2(e1); - this->WriteSource(e2, xamlType, oi); + Elem e2(e1, xamlType); + this->WriteSource(e2, oi); e2.SetHasElements(); if (this->ProjectType == csproj && !this->InSourceBuild) { // add <Link> tag to written XAML source if necessary @@ -1278,15 +1267,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( std::unique_ptr<Elem> spe2; if (this->ProjectType != csproj) { spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); - spe2 = cm::make_unique<Elem>(*spe1); - this->WriteSource(*spe2, "CustomBuild", source); + spe2 = cm::make_unique<Elem>(*spe1, "CustomBuild"); + this->WriteSource(*spe2, source); spe2->SetHasElements(); } else { Elem e1(e0, "ItemGroup"); - Elem e2(e1); + Elem e2(e1, "None"); std::string link; this->GetCSharpSourceLink(source, link); - this->WriteSource(e2, "None", source); + this->WriteSource(e2, source); e2.SetHasElements(); if (!link.empty()) { e2.Element("Link", link); @@ -1419,8 +1408,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() << this->GlobalGenerator->Encoding() << "\"?>" << "\n"; { - Elem e0(fout); - e0.StartElement("Project"); + Elem e0(fout, "Project"); e0.Attribute("ToolsVersion", this->GlobalGenerator->GetToolsVersion()); e0.Attribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003"); @@ -1571,8 +1559,8 @@ void cmVisualStudio10TargetGenerator::WriteHeaderSource(Elem& e1, cmSourceFile const* sf) { std::string const& fileName = sf->GetFullPath(); - Elem e2(e1); - this->WriteSource(e2, "ClInclude", sf); + Elem e2(e1, "ClInclude"); + this->WriteSource(e2, sf); if (this->IsResxHeader(fileName)) { e2.Element("FileType", "CppForm"); } else if (this->IsXamlHeader(fileName)) { @@ -1740,8 +1728,8 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } } - Elem e2(e1); - this->WriteSource(e2, tool, sf); + Elem e2(e1, tool); + this->WriteSource(e2, sf); if (toolHasSettings) { e2.SetHasElements(); @@ -1861,7 +1849,6 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(Elem& e1, } void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, - std::string const& tool, cmSourceFile const* sf) { // Visual Studio tools append relative paths to the current dir, as in: @@ -1897,11 +1884,10 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, } } ConvertToWindowsSlash(sourceFile); - e2.StartElement(tool); e2.Attribute("Include", sourceFile); ToolSource toolSource = { sf, forceRelative }; - this->Tools[tool].push_back(toolSource); + this->Tools[e2.Tag].push_back(toolSource); } void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) @@ -2005,8 +1991,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) include_configs.begin(), include_configs.end(), std::back_inserter(exclude_configs)); - Elem e2(e1); - this->WriteSource(e2, tool, si.Source); + Elem e2(e1, tool); + this->WriteSource(e2, si.Source); if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) { this->OutputSourceSpecificFlags(e2, si.Source); } @@ -2582,8 +2568,9 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( configDefine += configName; configDefine += "\""; clOptions.AddDefine(configDefine); - if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) { - clOptions.AddDefine(exportMacro); + if (const std::string* exportMacro = + this->GeneratorTarget->GetExportMacro()) { + clOptions.AddDefine(*exportMacro); } if (this->MSTools) { @@ -2879,8 +2866,9 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( configDefine += configName; configDefine += "\""; cudaOptions.AddDefine(configDefine); - if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) { - cudaOptions.AddDefine(exportMacro); + if (const std::string* exportMacro = + this->GeneratorTarget->GetExportMacro()) { + cudaOptions.AddDefine(*exportMacro); } // Get includes for this target @@ -3884,15 +3872,13 @@ void cmVisualStudio10TargetGenerator::WriteSinglePlatformExtension( void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0) { std::vector<std::string> sdkReferences; - Elem e1(e0); - bool hasWrittenItemGroup = false; + std::unique_ptr<Elem> spe1; if (const char* vsSDKReferences = this->GeneratorTarget->GetProperty("VS_SDK_REFERENCES")) { cmSystemTools::ExpandListArgument(vsSDKReferences, sdkReferences); - e1.StartElement("ItemGroup"); - hasWrittenItemGroup = true; + spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); for (std::string const& ri : sdkReferences) { - Elem(e1, "SDKReference").Attribute("Include", ri); + Elem(*spe1, "SDKReference").Attribute("Include", ri); } } @@ -3908,19 +3894,20 @@ void cmVisualStudio10TargetGenerator::WriteSDKReferences(Elem& e0) if (desktopExtensionsVersion || mobileExtensionsVersion || iotExtensionsVersion) { - if (!hasWrittenItemGroup) { - e1.StartElement("ItemGroup"); + if (!spe1) { + spe1 = cm::make_unique<Elem>(e0, "ItemGroup"); } if (desktopExtensionsVersion) { - this->WriteSingleSDKReference(e1, "WindowsDesktop", + this->WriteSingleSDKReference(*spe1, "WindowsDesktop", desktopExtensionsVersion); } if (mobileExtensionsVersion) { - this->WriteSingleSDKReference(e1, "WindowsMobile", + this->WriteSingleSDKReference(*spe1, "WindowsMobile", mobileExtensionsVersion); } if (iotExtensionsVersion) { - this->WriteSingleSDKReference(e1, "WindowsIoT", iotExtensionsVersion); + this->WriteSingleSDKReference(*spe1, "WindowsIoT", + iotExtensionsVersion); } } } diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 0dc03b6..b17b5f8 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -63,7 +63,7 @@ private: void WriteExtraSource(Elem& e1, cmSourceFile const* sf); void WriteNsightTegraConfigurationValues(Elem& e1, std::string const& config); - void WriteSource(Elem& e2, std::string const& tool, cmSourceFile const* sf); + void WriteSource(Elem& e2, cmSourceFile const* sf); void WriteExcludeFromBuild(Elem& e2, std::vector<size_t> const& exclude_configs); void WriteAllSources(Elem& e0); diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx index a9acb3f..9353276 100644 --- a/Source/cmVisualStudioSlnParser.cxx +++ b/Source/cmVisualStudioSlnParser.cxx @@ -602,8 +602,8 @@ bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag, } const std::string& arg = cmSystemTools::TrimWhitespace( fullTag.substr(idxLeftParen + 1, idxRightParen - idxLeftParen - 1)); - if (arg[0] == '"') { - if (arg[arg.size() - 1] != '"') { + if (arg.front() == '"') { + if (arg.back() != '"') { this->LastResult.SetError(ResultErrorInputStructure, state.GetCurrentLine()); return false; @@ -620,7 +620,7 @@ bool cmVisualStudioSlnParser::ParseValue(const std::string& value, const std::string& trimmed = cmSystemTools::TrimWhitespace(value); if (trimmed.empty()) parsedLine.AddValue(trimmed); - else if (trimmed[0] == '"' && trimmed[trimmed.size() - 1] == '"') + else if (trimmed.front() == '"' && trimmed.back() == '"') parsedLine.AddQuotedValue(trimmed.substr(1, trimmed.size() - 2)); else parsedLine.AddValue(trimmed); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 889a5fb..35730b8 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -676,10 +676,25 @@ void cmake::SetArgs(const std::vector<std::string>& args, #endif else if (arg.find("-D", 0) == 0) { // skip for now + // in case '-D var=val' is given, also skip the next + // in case '-Dvar=val' is given, don't skip the next + if (arg.size() == 2) { + ++i; + } } else if (arg.find("-U", 0) == 0) { // skip for now + // in case '-U var' is given, also skip the next + // in case '-Uvar' is given, don't skip the next + if (arg.size() == 2) { + ++i; + } } else if (arg.find("-C", 0) == 0) { // skip for now + // in case '-C path' is given, also skip the next + // in case '-Cpath' is given, don't skip the next + if (arg.size() == 2) { + ++i; + } } else if (arg.find("-P", 0) == 0) { // skip for now i++; @@ -2114,7 +2129,7 @@ void cmake::TruncateOutputLog(const char* fname) inline std::string removeQuotes(const std::string& s) { - if (s[0] == '\"' && s[s.size() - 1] == '\"') { + if (s.front() == '\"' && s.back() == '\"') { return s.substr(1, s.size() - 2); } return s; @@ -2128,7 +2143,7 @@ void cmake::MarkCliAsUsed(const std::string& variable) void cmake::GenerateGraphViz(const char* fileName) const { #ifdef CMAKE_BUILD_WITH_CMAKE - cmGraphVizWriter gvWriter(this->GetGlobalGenerator()->GetLocalGenerators()); + cmGraphVizWriter gvWriter(this->GetGlobalGenerator()); std::string settingsFile = this->GetHomeOutputDirectory(); settingsFile += "/CMakeGraphVizOptions.cmake"; diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx index 0c5bbe2..1a10666 100644 --- a/Source/cmcldeps.cxx +++ b/Source/cmcldeps.cxx @@ -221,7 +221,7 @@ static int process(const std::string& srcfilename, const std::string& dfile, while (std::getline(ss, line)) { if (startsWith(line, prefix)) { std::string inc = trimLeadingSpace(line.substr(prefix.size()).c_str()); - if (inc[inc.size() - 1] == '\r') // blech, stupid \r\n + if (inc.back() == '\r') // blech, stupid \r\n inc = inc.substr(0, inc.size() - 1); includes.push_back(inc); } else { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 1d2f741..45881aa 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -323,11 +323,15 @@ static int HandleCppCheck(const std::string& runCmd, stdErr.find("(performance)") != std::string::npos || stdErr.find("(portability)") != std::string::npos || stdErr.find("(information)") != std::string::npos) { - std::cerr << "Warning: cppcheck reported diagnostics:\n"; + if (ret == 0) { + std::cerr << "Warning: cppcheck reported diagnostics:\n"; + } else { + std::cerr << "Error: cppcheck reported failure:\n"; + } } std::cerr << stdErr; - // ignore errors so build continues - return 0; + + return ret; } typedef int (*CoCompileHandler)(const std::string&, const std::string&, @@ -464,18 +468,18 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // If multiple source files specified, // then destination must be directory if ((args.size() > 4) && - (!cmSystemTools::FileIsDirectory(args[args.size() - 1]))) { - std::cerr << "Error: Target (for copy command) \"" - << args[args.size() - 1] << "\" is not a directory.\n"; + (!cmSystemTools::FileIsDirectory(args.back()))) { + std::cerr << "Error: Target (for copy command) \"" << args.back() + << "\" is not a directory.\n"; return 1; } // If error occurs we want to continue copying next files. bool return_value = false; for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) { if (!cmSystemTools::cmCopyFile(args[cc].c_str(), - args[args.size() - 1].c_str())) { + args.back().c_str())) { std::cerr << "Error copying file \"" << args[cc] << "\" to \"" - << args[args.size() - 1] << "\".\n"; + << args.back() << "\".\n"; return_value = true; } } @@ -487,18 +491,18 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // If multiple source files specified, // then destination must be directory if ((args.size() > 4) && - (!cmSystemTools::FileIsDirectory(args[args.size() - 1]))) { + (!cmSystemTools::FileIsDirectory(args.back()))) { std::cerr << "Error: Target (for copy_if_different command) \"" - << args[args.size() - 1] << "\" is not a directory.\n"; + << args.back() << "\" is not a directory.\n"; return 1; } // If error occurs we want to continue copying next files. bool return_value = false; for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) { - if (!cmSystemTools::CopyFileIfDifferent( - args[cc].c_str(), args[args.size() - 1].c_str())) { + if (!cmSystemTools::CopyFileIfDifferent(args[cc].c_str(), + args.back().c_str())) { std::cerr << "Error copying file (if different) from \"" << args[cc] - << "\" to \"" << args[args.size() - 1] << "\".\n"; + << "\" to \"" << args.back() << "\".\n"; return_value = true; } } @@ -510,9 +514,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) // If error occurs we want to continue copying next files. bool return_value = false; for (std::string::size_type cc = 2; cc < args.size() - 1; cc++) { - if (!cmSystemTools::CopyADirectory(args[cc], args[args.size() - 1])) { + if (!cmSystemTools::CopyADirectory(args[cc], args.back())) { std::cerr << "Error copying directory from \"" << args[cc] - << "\" to \"" << args[args.size() - 1] << "\".\n"; + << "\" to \"" << args.back() << "\".\n"; return_value = true; } } @@ -1517,6 +1521,8 @@ class cmVSLink std::string ManifestFileRC; std::string ManifestFileRes; std::string TargetFile; + std::string MtPath; + std::string RcPath; public: cmVSLink(int type, bool verbose) @@ -1660,6 +1666,12 @@ bool cmVSLink::Parse(std::vector<std::string>::const_iterator argBeg, } else if (cmHasLiteralPrefix(*arg, "--intdir=")) { intDir = arg->substr(9); ++arg; + } else if (cmHasLiteralPrefix(*arg, "--rc=")) { + this->RcPath = arg->substr(5); + ++arg; + } else if (cmHasLiteralPrefix(*arg, "--mt=")) { + this->MtPath = arg->substr(5); + ++arg; } else { std::cerr << "unknown argument '" << *arg << "'\n"; return false; @@ -1799,7 +1811,7 @@ int cmVSLink::LinkIncremental() // Compile the resource file. std::vector<std::string> rcCommand; - rcCommand.push_back("rc"); + rcCommand.push_back(this->RcPath.empty() ? "rc" : this->RcPath); rcCommand.push_back("/fo" + this->ManifestFileRes); rcCommand.push_back(this->ManifestFileRC); if (!RunCommand("RC Pass 1", rcCommand, this->Verbose, FORMAT_DECIMAL)) { @@ -1858,7 +1870,7 @@ int cmVSLink::LinkNonIncremental() int cmVSLink::RunMT(std::string const& out, bool notify) { std::vector<std::string> mtCommand; - mtCommand.push_back("mt"); + mtCommand.push_back(this->MtPath.empty() ? "mt" : this->MtPath); mtCommand.push_back("/nologo"); mtCommand.push_back("/manifest"); if (this->LinkGeneratesManifest) { diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 43aec00..a2fcc16 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -90,6 +90,7 @@ FOREACH(p CMP0048 # CMake 3.0, Let the project command manage version variables. CMP0056 # CMake 3.2, Honor link flags in try_compile() source-file signature. CMP0063 # CMake 3.3, Honor visibility properties for all target types. + CMP0069 # CMake 3.9, INTERPROCEDURAL_OPTIMIZATION is enforced when enabled. ) IF(POLICY ${p}) CMAKE_POLICY(SET ${p} NEW) |