From a390de65e09e3ebc496fc14d40848ea4940cc9b0 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 18 May 2015 13:31:11 -0400 Subject: [PATCH] Ninja: Generate separate compile and link rules for each target Our _COMPILER and __LINKER rule generation has access to a specific cmTarget so the results may depend on it. Instead generate separate rules for each target using an encoded target name. In particular, this makes CTEST_USE_LAUNCHERS report proper target information. --- Source/cmGlobalNinjaGenerator.cxx | 32 ++++++++++++++++++++++++- Source/cmGlobalNinjaGenerator.h | 4 +++- Source/cmNinjaNormalTargetGenerator.cxx | 13 +++++----- Source/cmNinjaTargetGenerator.cxx | 7 ++++++ Source/cmNinjaTargetGenerator.h | 3 +-- 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 9a952a376..e064b847b 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -21,6 +21,7 @@ #include #include +#include const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja"; const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja"; @@ -57,6 +58,28 @@ void cmGlobalNinjaGenerator::WriteComment(std::ostream& os, os << "# " << replace.substr(lpos) << "\n\n"; } +std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name) +{ + // Ninja rule names must match "[a-zA-Z0-9_.-]+". Use ".xx" to encode + // "." and all invalid characters as hexadecimal. + std::string encoded; + for (std::string::const_iterator i = name.begin(); + i != name.end(); ++i) + { + if (isalnum(*i) || *i == '_' || *i == '-') + { + encoded += *i; + } + else + { + char buf[16]; + sprintf(buf, ".%02x", static_cast(*i)); + encoded += buf; + } + } + return encoded; +} + static bool IsIdentChar(char c) { return @@ -120,7 +143,8 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables, const std::string& rspfile, - int cmdLineLimit) + int cmdLineLimit, + bool* usedResponseFile) { // Make sure there is a rule. if(rule.empty()) @@ -205,6 +229,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, std::string buildstr = build; std::string assignments = variable_assignments.str(); const std::string& args = arguments; + bool useResponseFile = false; if (cmdLineLimit > 0 && args.size() + buildstr.size() + assignments.size() > (size_t) cmdLineLimit) { @@ -213,7 +238,12 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE", rspfile, "", 1); assignments += variable_assignments.str(); + useResponseFile = true; } + if (usedResponseFile) + { + *usedResponseFile = useResponseFile; + } os << buildstr << args << assignments; } diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 00dc237bd..444c3e2f5 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -61,6 +61,7 @@ public: /// Write a divider in the given output stream @a os. static void WriteDivider(std::ostream& os); + static std::string EncodeRuleName(std::string const& name); static std::string EncodeIdent(const std::string &ident, std::ostream &vars); static std::string EncodeLiteral(const std::string &lit); std::string EncodePath(const std::string &path); @@ -87,7 +88,8 @@ public: const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables, const std::string& rspfile = std::string(), - int cmdLineLimit = -1); + int cmdLineLimit = -1, + bool* usedResponseFile = 0); /** * Helper to write a build statement with the special 'phony' rule. diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 771ecc402..7f9c09f91 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -94,8 +94,6 @@ void cmNinjaNormalTargetGenerator::Generate() } else { - this->WriteLinkRule(false); // write rule without rspfile support - this->WriteLinkRule(true); // write rule with rspfile support this->WriteLinkStatement(); } } @@ -160,7 +158,9 @@ cmNinjaNormalTargetGenerator return this->TargetLinkLanguage + "_" + cmTarget::GetTargetTypeName(this->GetTarget()->GetType()) - + "_LINKER"; + + "_LINKER__" + + cmGlobalNinjaGenerator::EncodeRuleName(this->GetTarget()->GetName()) + ; } void @@ -169,8 +169,6 @@ cmNinjaNormalTargetGenerator { cmTarget::TargetType targetType = this->GetTarget()->GetType(); std::string ruleName = this->LanguageLinkerRule(); - if (useResponseFile) - ruleName += "_RSP_FILE"; // Select whether to use a response file for objects. std::string rspfile; @@ -661,6 +659,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } // Write the build statement for this target. + bool usedResponseFile = false; globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(), this->LanguageLinkerRule(), @@ -670,7 +669,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() orderOnlyDeps, vars, rspfile, - commandLineLengthLimit); + commandLineLengthLimit, + &usedResponseFile); + this->WriteLinkRule(usedResponseFile); if (targetOutput != targetOutputReal && !target.IsFrameworkOnApple()) { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 128a35be9..cdc9cc8c7 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -97,6 +97,13 @@ std::string const& cmNinjaTargetGenerator::GetConfigName() const return this->LocalGenerator->GetConfigName(); } +std::string cmNinjaTargetGenerator::LanguageCompilerRule( + const std::string& lang) const +{ + return lang + "_COMPILER__" + + cmGlobalNinjaGenerator::EncodeRuleName(this->Target->GetName()); +} + // TODO: Picked up from cmMakefileTargetGenerator. Refactor it. const char* cmNinjaTargetGenerator::GetFeature(const std::string& feature) { diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 5733fde4c..4e7d8b3a1 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -67,8 +67,7 @@ protected: std::string const& GetConfigName() const; - std::string LanguageCompilerRule(const std::string& lang) const - { return lang + "_COMPILER"; } + std::string LanguageCompilerRule(const std::string& lang) const; const char* GetFeature(const std::string& feature); bool GetFeatureAsBool(const std::string& feature);