Ninja: add response file support on Windows
When MinGW is used slashes are used for dependencies because ar.exe can't read rsp files with backslashes. Many thx to Claus Klein for starting working on this.
This commit is contained in:
parent
7687d557dc
commit
ad4a768d59
|
@ -89,6 +89,9 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string &path)
|
||||||
{
|
{
|
||||||
std::string result = path;
|
std::string result = path;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
if(UsingMinGW)
|
||||||
|
cmSystemTools::ReplaceString(result, "\\", "/");
|
||||||
|
else
|
||||||
cmSystemTools::ReplaceString(result, "/", "\\");
|
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);
|
||||||
|
|
||||||
std::ostringstream builds;
|
std::stringstream 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";
|
||||||
|
|
||||||
|
|
||||||
|
std::ostringstream 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +247,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 +292,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);
|
||||||
|
@ -424,7 +447,16 @@ void cmGlobalNinjaGenerator
|
||||||
}
|
}
|
||||||
this->ResolveLanguageCompiler(*l, mf, optional);
|
this->ResolveLanguageCompiler(*l, mf, optional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for mingw
|
||||||
|
std::string cc = mf->GetDefinition("CMAKE_C_COMPILER");
|
||||||
|
if(cc.find("gcc.exe") != std::string::npos)
|
||||||
|
{
|
||||||
|
UsingMinGW = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmGlobalNinjaGenerator::UsingMinGW = false;
|
||||||
|
|
||||||
// Implemented by:
|
// Implemented by:
|
||||||
// cmGlobalUnixMakefileGenerator3
|
// cmGlobalUnixMakefileGenerator3
|
||||||
|
@ -483,6 +515,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 +530,7 @@ void cmGlobalNinjaGenerator::AddRule(const std::string& name,
|
||||||
description,
|
description,
|
||||||
comment,
|
comment,
|
||||||
depfile,
|
depfile,
|
||||||
|
rspfile,
|
||||||
restat,
|
restat,
|
||||||
generator);
|
generator);
|
||||||
}
|
}
|
||||||
|
@ -841,6 +875,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 +913,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 +934,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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
std::ostringstream cmd;
|
std::ostringstream 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();
|
||||||
|
|
|
@ -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,38 @@ 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();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
std::string responseFlag;
|
||||||
|
if (!useResponseFile) {
|
||||||
vars.Objects = "$in";
|
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 = "@";
|
||||||
|
}
|
||||||
|
ruleName += "_RSPFILE";
|
||||||
|
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 +225,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 +238,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.
|
||||||
std::ostringstream comment;
|
std::ostringstream comment;
|
||||||
comment << "Rule for linking " << this->TargetLinkLanguage << " "
|
comment << "Rule for linking " << this->TargetLinkLanguage << " "
|
||||||
<< this->GetVisibleTypeName() << ".";
|
<< this->GetVisibleTypeName() << ".";
|
||||||
|
@ -224,7 +248,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 +482,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
||||||
symlinkVars["POST_BUILD"] = postBuildCmdLine;
|
symlinkVars["POST_BUILD"] = postBuildCmdLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cmdLineLimit = -1;
|
||||||
|
#ifdef _WIN32
|
||||||
|
cmdLineLimit = 30000;
|
||||||
|
#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 +496,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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue