Merge branch 'ninja-rspfile' into no-std-stringstream

Conflicts:
	Source/cmGlobalNinjaGenerator.cxx
	Source/cmLocalNinjaGenerator.cxx
	Source/cmNinjaNormalTargetGenerator.cxx
This commit is contained in:
Brad King 2012-06-06 15:26:48 -04:00
commit 32313fd0d4
5 changed files with 143 additions and 50 deletions

View File

@ -89,7 +89,10 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string &path)
{ {
std::string result = path; std::string result = path;
#ifdef _WIN32 #ifdef _WIN32
cmSystemTools::ReplaceString(result, "/", "\\"); if(UsingMinGW)
cmSystemTools::ReplaceString(result, "\\", "/");
else
cmSystemTools::ReplaceString(result, "/", "\\");
#endif #endif
return EncodeLiteral(result); return EncodeLiteral(result);
} }
@ -101,7 +104,8 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
const cmNinjaDeps& explicitDeps, const cmNinjaDeps& explicitDeps,
const cmNinjaDeps& implicitDeps, const cmNinjaDeps& implicitDeps,
const cmNinjaDeps& orderOnlyDeps, const cmNinjaDeps& orderOnlyDeps,
const cmNinjaVars& variables) const cmNinjaVars& variables,
int cmdLineLimit)
{ {
// Make sure there is a rule. // Make sure there is a rule.
if(rule.empty()) if(rule.empty())
@ -123,10 +127,41 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
cmGlobalNinjaGenerator::WriteComment(os, comment); cmGlobalNinjaGenerator::WriteComment(os, comment);
cmOStringStream builds; cmOStringStream arguments;
// TODO: Better formatting for when there are multiple input/output files. // TODO: Better formatting for when there are multiple input/output files.
// Write explicit dependencies.
for(cmNinjaDeps::const_iterator i = explicitDeps.begin();
i != explicitDeps.end();
++i)
arguments << " " << EncodeIdent(EncodePath(*i), os);
// Write implicit dependencies.
if(!implicitDeps.empty())
{
arguments << " |";
for(cmNinjaDeps::const_iterator i = implicitDeps.begin();
i != implicitDeps.end();
++i)
arguments << " " << EncodeIdent(EncodePath(*i), os);
}
// Write order-only dependencies.
if(!orderOnlyDeps.empty())
{
arguments << " ||";
for(cmNinjaDeps::const_iterator i = orderOnlyDeps.begin();
i != orderOnlyDeps.end();
++i)
arguments << " " << EncodeIdent(EncodePath(*i), os);
}
arguments << "\n";
cmOStringStream builds;
// Write outputs files. // Write outputs files.
builds << "build"; builds << "build";
for(cmNinjaDeps::const_iterator i = outputs.begin(); for(cmNinjaDeps::const_iterator i = outputs.begin();
@ -135,38 +170,16 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
builds << " " << EncodeIdent(EncodePath(*i), os); builds << " " << EncodeIdent(EncodePath(*i), os);
builds << ":"; builds << ":";
// Write the rule. // Write the rule.
builds << " " << rule; builds << " " << rule;
// Write explicit dependencies. // check if a response file rule should be used
for(cmNinjaDeps::const_iterator i = explicitDeps.begin(); const std::string args = arguments.str();
i != explicitDeps.end(); if (cmdLineLimit > 0 && args.size() > (size_t)cmdLineLimit)
++i) builds << "_RSPFILE";
builds << " " << EncodeIdent(EncodePath(*i), os);
// Write implicit dependencies. os << builds.str() << args;
if(!implicitDeps.empty())
{
builds << " |";
for(cmNinjaDeps::const_iterator i = implicitDeps.begin();
i != implicitDeps.end();
++i)
builds << " " << EncodeIdent(EncodePath(*i), os);
}
// Write order-only dependencies.
if(!orderOnlyDeps.empty())
{
builds << " ||";
for(cmNinjaDeps::const_iterator i = orderOnlyDeps.begin();
i != orderOnlyDeps.end();
++i)
builds << " " << EncodeIdent(EncodePath(*i), os);
}
builds << "\n";
os << builds.str();
// Write the variables bound to this build statement. // Write the variables bound to this build statement.
for(cmNinjaVars::const_iterator i = variables.begin(); for(cmNinjaVars::const_iterator i = variables.begin();
@ -200,6 +213,7 @@ void cmGlobalNinjaGenerator::AddCustomCommandRule()
"$DESC", "$DESC",
"Rule for running custom commands.", "Rule for running custom commands.",
/*depfile*/ "", /*depfile*/ "",
/*rspfile*/ "",
/*restat*/ true); /*restat*/ true);
} }
@ -211,10 +225,17 @@ cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command,
const cmNinjaDeps& deps, const cmNinjaDeps& deps,
const cmNinjaDeps& orderOnlyDeps) const cmNinjaDeps& orderOnlyDeps)
{ {
std::string cmd = command;
#ifdef _WIN32
if (cmd.empty())
// TODO Shouldn't an empty command be handled by ninja?
cmd = "cmd.exe /c";
#endif
this->AddCustomCommandRule(); this->AddCustomCommandRule();
cmNinjaVars vars; cmNinjaVars vars;
vars["COMMAND"] = command; vars["COMMAND"] = cmd;
vars["DESC"] = EncodeLiteral(description); vars["DESC"] = EncodeLiteral(description);
cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream, cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream,
@ -233,6 +254,7 @@ void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
const std::string& description, const std::string& description,
const std::string& comment, const std::string& comment,
const std::string& depfile, const std::string& depfile,
const std::string& rspfile,
bool restat, bool restat,
bool generator) bool generator)
{ {
@ -277,6 +299,14 @@ void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
os << "description = " << description << "\n"; os << "description = " << description << "\n";
} }
if(!rspfile.empty())
{
cmGlobalNinjaGenerator::Indent(os, 1);
os << "rspfile = " << rspfile << "\n";
cmGlobalNinjaGenerator::Indent(os, 1);
os << "rspfile_content = $in" << "\n";
}
if(restat) if(restat)
{ {
cmGlobalNinjaGenerator::Indent(os, 1); cmGlobalNinjaGenerator::Indent(os, 1);
@ -404,16 +434,19 @@ void cmGlobalNinjaGenerator
cmMakefile *mf, cmMakefile *mf,
bool optional) bool optional)
{ {
this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
std::string path; std::string path;
for(std::vector<std::string>::const_iterator l = languages.begin(); for(std::vector<std::string>::const_iterator l = languages.begin();
l != languages.end(); ++l) l != languages.end(); ++l)
{ {
std::vector<std::string> language;
language.push_back(*l);
if(*l == "NONE") if(*l == "NONE")
{ {
this->cmGlobalGenerator::EnableLanguage(language, mf, optional);
continue; continue;
} }
if(*l == "Fortran") else if(*l == "Fortran")
{ {
std::string message = "The \""; std::string message = "The \"";
message += this->GetName(); message += this->GetName();
@ -422,10 +455,26 @@ void cmGlobalNinjaGenerator
message += "\" yet."; message += "\" yet.";
cmSystemTools::Error(message.c_str()); cmSystemTools::Error(message.c_str());
} }
else if(*l == "RC")
{
// check if mingw is used
const char* cc = mf->GetDefinition("CMAKE_C_COMPILER");
if(cc && std::string(cc).find("gcc.exe") != std::string::npos)
{
UsingMinGW = true;
std::string rc = cmSystemTools::FindProgram("windres");
if(rc.empty())
rc = "windres.exe";;
mf->AddDefinition("CMAKE_RC_COMPILER", rc.c_str());
}
}
this->cmGlobalGenerator::EnableLanguage(language, mf, optional);
this->ResolveLanguageCompiler(*l, mf, optional); this->ResolveLanguageCompiler(*l, mf, optional);
} }
} }
bool cmGlobalNinjaGenerator::UsingMinGW = false;
// Implemented by: // Implemented by:
// cmGlobalUnixMakefileGenerator3 // cmGlobalUnixMakefileGenerator3
// cmGlobalVisualStudio10Generator // cmGlobalVisualStudio10Generator
@ -483,6 +532,7 @@ void cmGlobalNinjaGenerator::AddRule(const std::string& name,
const std::string& description, const std::string& description,
const std::string& comment, const std::string& comment,
const std::string& depfile, const std::string& depfile,
const std::string& rspfile,
bool restat, bool restat,
bool generator) bool generator)
{ {
@ -497,6 +547,7 @@ void cmGlobalNinjaGenerator::AddRule(const std::string& name,
description, description,
comment, comment,
depfile, depfile,
rspfile,
restat, restat,
generator); generator);
} }
@ -841,6 +892,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
"Re-running CMake...", "Re-running CMake...",
"Rule for re-running cmake.", "Rule for re-running cmake.",
/*depfile=*/ "", /*depfile=*/ "",
/*rspfile=*/ "",
/*restat=*/ false, /*restat=*/ false,
/*generator=*/ true); /*generator=*/ true);
@ -878,6 +930,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
"Cleaning all built files...", "Cleaning all built files...",
"Rule for cleaning all built files.", "Rule for cleaning all built files.",
/*depfile=*/ "", /*depfile=*/ "",
/*rspfile=*/ "",
/*restat=*/ false, /*restat=*/ false,
/*generator=*/ false); /*generator=*/ false);
WriteBuild(os, WriteBuild(os,
@ -898,6 +951,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
"All primary targets available:", "All primary targets available:",
"Rule for printing all primary targets available.", "Rule for printing all primary targets available.",
/*depfile=*/ "", /*depfile=*/ "",
/*rspfile=*/ "",
/*restat=*/ false, /*restat=*/ false,
/*generator=*/ false); /*generator=*/ false);
WriteBuild(os, WriteBuild(os,

View File

@ -81,7 +81,8 @@ public:
const cmNinjaDeps& explicitDeps, const cmNinjaDeps& explicitDeps,
const cmNinjaDeps& implicitDeps, const cmNinjaDeps& implicitDeps,
const cmNinjaDeps& orderOnlyDeps, const cmNinjaDeps& orderOnlyDeps,
const cmNinjaVars& variables); const cmNinjaVars& variables,
int cmdLineLimit = -1);
/** /**
* Helper to write a build statement with the special 'phony' rule. * Helper to write a build statement with the special 'phony' rule.
@ -113,6 +114,7 @@ public:
const std::string& description, const std::string& description,
const std::string& comment = "", const std::string& comment = "",
const std::string& depfile = "", const std::string& depfile = "",
const std::string& rspfile = "" ,
bool restat = false, bool restat = false,
bool generator = false); bool generator = false);
@ -226,6 +228,7 @@ public:
const std::string& description, const std::string& description,
const std::string& comment = "", const std::string& comment = "",
const std::string& depfile = "", const std::string& depfile = "",
const std::string& rspfile = "",
bool restat = false, bool restat = false,
bool generator = false); bool generator = false);
@ -341,6 +344,8 @@ private:
TargetAliasMap TargetAliases; TargetAliasMap TargetAliases;
static cmLocalGenerator* LocalGenerator; static cmLocalGenerator* LocalGenerator;
static bool UsingMinGW;
}; };
#endif // ! cmGlobalNinjaGenerator_h #endif // ! cmGlobalNinjaGenerator_h

View File

@ -275,16 +275,16 @@ std::string cmLocalNinjaGenerator::BuildCommandLine(
return ":"; return ":";
#endif #endif
// TODO: This will work only on Unix platforms. I don't
// want to use a link.txt file because I will lose the benefit of the
// $in variables. A discussion about dealing with multiple commands in
// a rule is started here:
// groups.google.com/group/ninja-build/browse_thread/thread/d515f23a78986008
cmOStringStream cmd; cmOStringStream cmd;
for (std::vector<std::string>::const_iterator li = cmdLines.begin(); for (std::vector<std::string>::const_iterator li = cmdLines.begin();
li != cmdLines.end(); ++li) { li != cmdLines.end(); ++li) {
if (li != cmdLines.begin()) if (li != cmdLines.begin()) {
cmd << " && "; cmd << " && ";
#ifdef _WIN32
} else if (cmdLines.size() > 1) {
cmd << "cmd.exe /c ";
#endif
}
cmd << *li; cmd << *li;
} }
return cmd.str(); return cmd.str();

View File

@ -90,7 +90,10 @@ void cmNinjaNormalTargetGenerator::Generate()
} }
else else
{ {
this->WriteLinkRule(); this->WriteLinkRule(false);
#ifdef _WIN32 // TODO response file support only Linux
this->WriteLinkRule(true);
#endif
this->WriteLinkStatement(); this->WriteLinkStatement();
} }
@ -144,17 +147,39 @@ cmNinjaNormalTargetGenerator
void void
cmNinjaNormalTargetGenerator cmNinjaNormalTargetGenerator
::WriteLinkRule() ::WriteLinkRule(bool useResponseFile)
{ {
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 += "_RSPFILE";
// Select whether to use a response file for objects.
std::string rspfile;
if (!this->GetGlobalGenerator()->HasRule(ruleName)) { if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
cmLocalGenerator::RuleVariables vars; cmLocalGenerator::RuleVariables vars;
vars.RuleLauncher = "RULE_LAUNCH_LINK"; vars.RuleLauncher = "RULE_LAUNCH_LINK";
vars.CMTarget = this->GetTarget(); vars.CMTarget = this->GetTarget();
vars.Language = this->TargetLinkLanguage; vars.Language = this->TargetLinkLanguage;
vars.Objects = "$in";
std::string responseFlag;
if (!useResponseFile) {
vars.Objects = "$in";
} else {
// handle response file
std::string cmakeLinkVar = std::string("CMAKE_") +
this->TargetLinkLanguage + "_RESPONSE_FILE_LINK_FLAG";
const char * flag = GetMakefile()->GetDefinition(cmakeLinkVar.c_str());
if(flag) {
responseFlag = flag;
} else {
responseFlag = "@";
}
rspfile = "$out.rsp";
responseFlag += rspfile;
vars.Objects = responseFlag.c_str();
}
std::string objdir = std::string objdir =
this->GetLocalGenerator()->GetHomeRelativeOutputPath(); this->GetLocalGenerator()->GetHomeRelativeOutputPath();
objdir += objdir.empty() ? "" : "/"; objdir += objdir.empty() ? "" : "/";
@ -201,7 +226,7 @@ cmNinjaNormalTargetGenerator
vars.LanguageCompileFlags = langFlags.c_str(); vars.LanguageCompileFlags = langFlags.c_str();
} }
// Rule for linking library. // Rule for linking library/executable.
std::vector<std::string> linkCmds = this->ComputeLinkCmd(); std::vector<std::string> linkCmds = this->ComputeLinkCmd();
for(std::vector<std::string>::iterator i = linkCmds.begin(); for(std::vector<std::string>::iterator i = linkCmds.begin();
i != linkCmds.end(); i != linkCmds.end();
@ -214,7 +239,7 @@ cmNinjaNormalTargetGenerator
std::string linkCmd = std::string linkCmd =
this->GetLocalGenerator()->BuildCommandLine(linkCmds); this->GetLocalGenerator()->BuildCommandLine(linkCmds);
// Write the linker rule. // Write the linker rule with response file if needed.
cmOStringStream comment; cmOStringStream comment;
comment << "Rule for linking " << this->TargetLinkLanguage << " " comment << "Rule for linking " << this->TargetLinkLanguage << " "
<< this->GetVisibleTypeName() << "."; << this->GetVisibleTypeName() << ".";
@ -224,7 +249,9 @@ cmNinjaNormalTargetGenerator
this->GetGlobalGenerator()->AddRule(ruleName, this->GetGlobalGenerator()->AddRule(ruleName,
linkCmd, linkCmd,
description.str(), description.str(),
comment.str()); comment.str(),
/*depfile*/ "",
rspfile);
} }
if (this->TargetNameOut != this->TargetNameReal) { if (this->TargetNameOut != this->TargetNameReal) {
@ -456,6 +483,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
symlinkVars["POST_BUILD"] = postBuildCmdLine; symlinkVars["POST_BUILD"] = postBuildCmdLine;
} }
int cmdLineLimit = -1;
#ifdef _WIN32
cmdLineLimit = 8100;
#else
// TODO
#endif
// Write the build statement for this target. // Write the build statement for this target.
cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
comment.str(), comment.str(),
@ -464,7 +497,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
explicitDeps, explicitDeps,
implicitDeps, implicitDeps,
emptyDeps, emptyDeps,
vars); vars,
cmdLineLimit);
if (targetOutput != targetOutputReal) { if (targetOutput != targetOutputReal) {
if (targetType == cmTarget::EXECUTABLE) { if (targetType == cmTarget::EXECUTABLE) {

View File

@ -30,7 +30,7 @@ private:
std::string LanguageLinkerRule() const; std::string LanguageLinkerRule() const;
const char* GetVisibleTypeName() const; const char* GetVisibleTypeName() const;
void WriteLanguagesRules(); void WriteLanguagesRules();
void WriteLinkRule(); void WriteLinkRule(bool useResponseFile);
void WriteLinkStatement(); void WriteLinkStatement();
void WriteObjectLibStatement(); void WriteObjectLibStatement();
std::vector<std::string> ComputeLinkCmd(); std::vector<std::string> ComputeLinkCmd();