Ninja: Generate separate compile and link rules for each target

Our <LANG>_COMPILER and <LANG>_<TARGET_TYPE>_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.
This commit is contained in:
Brad King 2015-05-18 13:31:11 -04:00
parent 00ccfff2bc
commit a390de65e0
5 changed files with 49 additions and 10 deletions

View File

@ -21,6 +21,7 @@
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
#include <ctype.h>
const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja"; const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.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"; 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<unsigned int>(*i));
encoded += buf;
}
}
return encoded;
}
static bool IsIdentChar(char c) static bool IsIdentChar(char c)
{ {
return return
@ -120,7 +143,8 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
const cmNinjaDeps& orderOnlyDeps, const cmNinjaDeps& orderOnlyDeps,
const cmNinjaVars& variables, const cmNinjaVars& variables,
const std::string& rspfile, const std::string& rspfile,
int cmdLineLimit) int cmdLineLimit,
bool* usedResponseFile)
{ {
// Make sure there is a rule. // Make sure there is a rule.
if(rule.empty()) if(rule.empty())
@ -205,6 +229,7 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
std::string buildstr = build; std::string buildstr = build;
std::string assignments = variable_assignments.str(); std::string assignments = variable_assignments.str();
const std::string& args = arguments; const std::string& args = arguments;
bool useResponseFile = false;
if (cmdLineLimit > 0 if (cmdLineLimit > 0
&& args.size() + buildstr.size() + assignments.size() && args.size() + buildstr.size() + assignments.size()
> (size_t) cmdLineLimit) { > (size_t) cmdLineLimit) {
@ -213,6 +238,11 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
cmGlobalNinjaGenerator::WriteVariable(variable_assignments, cmGlobalNinjaGenerator::WriteVariable(variable_assignments,
"RSP_FILE", rspfile, "", 1); "RSP_FILE", rspfile, "", 1);
assignments += variable_assignments.str(); assignments += variable_assignments.str();
useResponseFile = true;
}
if (usedResponseFile)
{
*usedResponseFile = useResponseFile;
} }
os << buildstr << args << assignments; os << buildstr << args << assignments;

View File

@ -61,6 +61,7 @@ public:
/// Write a divider in the given output stream @a os. /// Write a divider in the given output stream @a os.
static void WriteDivider(std::ostream& 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 EncodeIdent(const std::string &ident, std::ostream &vars);
static std::string EncodeLiteral(const std::string &lit); static std::string EncodeLiteral(const std::string &lit);
std::string EncodePath(const std::string &path); std::string EncodePath(const std::string &path);
@ -87,7 +88,8 @@ public:
const cmNinjaDeps& orderOnlyDeps, const cmNinjaDeps& orderOnlyDeps,
const cmNinjaVars& variables, const cmNinjaVars& variables,
const std::string& rspfile = std::string(), 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. * Helper to write a build statement with the special 'phony' rule.

View File

@ -94,8 +94,6 @@ void cmNinjaNormalTargetGenerator::Generate()
} }
else else
{ {
this->WriteLinkRule(false); // write rule without rspfile support
this->WriteLinkRule(true); // write rule with rspfile support
this->WriteLinkStatement(); this->WriteLinkStatement();
} }
} }
@ -160,7 +158,9 @@ cmNinjaNormalTargetGenerator
return this->TargetLinkLanguage return this->TargetLinkLanguage
+ "_" + "_"
+ cmTarget::GetTargetTypeName(this->GetTarget()->GetType()) + cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
+ "_LINKER"; + "_LINKER__"
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GetTarget()->GetName())
;
} }
void void
@ -169,8 +169,6 @@ cmNinjaNormalTargetGenerator
{ {
cmTarget::TargetType targetType = this->GetTarget()->GetType(); cmTarget::TargetType targetType = this->GetTarget()->GetType();
std::string ruleName = this->LanguageLinkerRule(); std::string ruleName = this->LanguageLinkerRule();
if (useResponseFile)
ruleName += "_RSP_FILE";
// Select whether to use a response file for objects. // Select whether to use a response file for objects.
std::string rspfile; std::string rspfile;
@ -661,6 +659,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
} }
// Write the build statement for this target. // Write the build statement for this target.
bool usedResponseFile = false;
globalGen.WriteBuild(this->GetBuildFileStream(), globalGen.WriteBuild(this->GetBuildFileStream(),
comment.str(), comment.str(),
this->LanguageLinkerRule(), this->LanguageLinkerRule(),
@ -670,7 +669,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
orderOnlyDeps, orderOnlyDeps,
vars, vars,
rspfile, rspfile,
commandLineLengthLimit); commandLineLengthLimit,
&usedResponseFile);
this->WriteLinkRule(usedResponseFile);
if (targetOutput != targetOutputReal && !target.IsFrameworkOnApple()) if (targetOutput != targetOutputReal && !target.IsFrameworkOnApple())
{ {

View File

@ -97,6 +97,13 @@ std::string const& cmNinjaTargetGenerator::GetConfigName() const
return this->LocalGenerator->GetConfigName(); 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. // TODO: Picked up from cmMakefileTargetGenerator. Refactor it.
const char* cmNinjaTargetGenerator::GetFeature(const std::string& feature) const char* cmNinjaTargetGenerator::GetFeature(const std::string& feature)
{ {

View File

@ -67,8 +67,7 @@ protected:
std::string const& GetConfigName() const; std::string const& GetConfigName() const;
std::string LanguageCompilerRule(const std::string& lang) const std::string LanguageCompilerRule(const std::string& lang) const;
{ return lang + "_COMPILER"; }
const char* GetFeature(const std::string& feature); const char* GetFeature(const std::string& feature);
bool GetFeatureAsBool(const std::string& feature); bool GetFeatureAsBool(const std::string& feature);