diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 0e89fab74..6717c3f70 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -89,7 +89,10 @@ std::string cmGlobalNinjaGenerator::EncodePath(const std::string &path) { std::string result = path; #ifdef _WIN32 - cmSystemTools::ReplaceString(result, "/", "\\"); + if(UsingMinGW) + cmSystemTools::ReplaceString(result, "\\", "/"); + else + cmSystemTools::ReplaceString(result, "/", "\\"); #endif return EncodeLiteral(result); } @@ -101,7 +104,8 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables) + const cmNinjaVars& variables, + int cmdLineLimit) { // Make sure there is a rule. if(rule.empty()) @@ -123,10 +127,41 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, cmGlobalNinjaGenerator::WriteComment(os, comment); - std::ostringstream builds; + std::stringstream arguments; // 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. builds << "build"; for(cmNinjaDeps::const_iterator i = outputs.begin(); @@ -135,38 +170,16 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, builds << " " << EncodeIdent(EncodePath(*i), os); builds << ":"; + // Write the rule. builds << " " << rule; - // Write explicit dependencies. - for(cmNinjaDeps::const_iterator i = explicitDeps.begin(); - i != explicitDeps.end(); - ++i) - builds << " " << EncodeIdent(EncodePath(*i), os); + // check if a response file rule should be used + const std::string args = arguments.str(); + if (cmdLineLimit > 0 && args.size() > (size_t)cmdLineLimit) + builds << "_RSPFILE"; - // Write implicit dependencies. - 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(); + os << builds.str() << args; // Write the variables bound to this build statement. for(cmNinjaVars::const_iterator i = variables.begin(); @@ -200,6 +213,7 @@ void cmGlobalNinjaGenerator::AddCustomCommandRule() "$DESC", "Rule for running custom commands.", /*depfile*/ "", + /*rspfile*/ "", /*restat*/ true); } @@ -233,6 +247,7 @@ void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, const std::string& description, const std::string& comment, const std::string& depfile, + const std::string& rspfile, bool restat, bool generator) { @@ -277,6 +292,14 @@ void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, 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) { cmGlobalNinjaGenerator::Indent(os, 1); @@ -424,8 +447,17 @@ void cmGlobalNinjaGenerator } 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: // cmGlobalUnixMakefileGenerator3 // cmGlobalVisualStudio10Generator @@ -483,6 +515,7 @@ void cmGlobalNinjaGenerator::AddRule(const std::string& name, const std::string& description, const std::string& comment, const std::string& depfile, + const std::string& rspfile, bool restat, bool generator) { @@ -497,6 +530,7 @@ void cmGlobalNinjaGenerator::AddRule(const std::string& name, description, comment, depfile, + rspfile, restat, generator); } @@ -841,6 +875,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) "Re-running CMake...", "Rule for re-running cmake.", /*depfile=*/ "", + /*rspfile=*/ "", /*restat=*/ false, /*generator=*/ true); @@ -878,6 +913,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) "Cleaning all built files...", "Rule for cleaning all built files.", /*depfile=*/ "", + /*rspfile=*/ "", /*restat=*/ false, /*generator=*/ false); WriteBuild(os, @@ -898,6 +934,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) "All primary targets available:", "Rule for printing all primary targets available.", /*depfile=*/ "", + /*rspfile=*/ "", /*restat=*/ false, /*generator=*/ false); WriteBuild(os, diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 7b6b9b7ee..0c740e8dc 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -81,7 +81,8 @@ public: const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables); + const cmNinjaVars& variables, + int cmdLineLimit = -1); /** * Helper to write a build statement with the special 'phony' rule. @@ -113,6 +114,7 @@ public: const std::string& description, const std::string& comment = "", const std::string& depfile = "", + const std::string& rspfile = "" , bool restat = false, bool generator = false); @@ -226,6 +228,7 @@ public: const std::string& description, const std::string& comment = "", const std::string& depfile = "", + const std::string& rspfile = "", bool restat = false, bool generator = false); @@ -341,6 +344,8 @@ private: TargetAliasMap TargetAliases; static cmLocalGenerator* LocalGenerator; + + static bool UsingMinGW; }; #endif // ! cmGlobalNinjaGenerator_h diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 425b21917..a0141cfe2 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -275,16 +275,16 @@ std::string cmLocalNinjaGenerator::BuildCommandLine( return ":"; #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; for (std::vector::const_iterator li = cmdLines.begin(); li != cmdLines.end(); ++li) { - if (li != cmdLines.begin()) + if (li != cmdLines.begin()) { cmd << " && "; +#ifdef _WIN32 + } else if (cmdLines.size() > 1) { + cmd << "cmd.exe /c "; +#endif + } cmd << *li; } return cmd.str(); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 8b86a98d2..a99167fa7 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -90,7 +90,10 @@ void cmNinjaNormalTargetGenerator::Generate() } else { - this->WriteLinkRule(); + this->WriteLinkRule(false); +#ifdef _WIN32 // TODO response file support only Linux + this->WriteLinkRule(true); +#endif this->WriteLinkStatement(); } @@ -144,17 +147,38 @@ cmNinjaNormalTargetGenerator void cmNinjaNormalTargetGenerator -::WriteLinkRule() +::WriteLinkRule(bool useResponseFile) { cmTarget::TargetType targetType = this->GetTarget()->GetType(); std::string ruleName = this->LanguageLinkerRule(); + // Select whether to use a response file for objects. + std::string rspfile; + if (!this->GetGlobalGenerator()->HasRule(ruleName)) { cmLocalGenerator::RuleVariables vars; vars.RuleLauncher = "RULE_LAUNCH_LINK"; vars.CMTarget = this->GetTarget(); 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 = "@"; + } + ruleName += "_RSPFILE"; + rspfile = "$out.rsp"; + responseFlag += rspfile; + vars.Objects = responseFlag.c_str(); + } std::string objdir = this->GetLocalGenerator()->GetHomeRelativeOutputPath(); objdir += objdir.empty() ? "" : "/"; @@ -201,7 +225,7 @@ cmNinjaNormalTargetGenerator vars.LanguageCompileFlags = langFlags.c_str(); } - // Rule for linking library. + // Rule for linking library/executable. std::vector linkCmds = this->ComputeLinkCmd(); for(std::vector::iterator i = linkCmds.begin(); i != linkCmds.end(); @@ -214,7 +238,7 @@ cmNinjaNormalTargetGenerator std::string linkCmd = this->GetLocalGenerator()->BuildCommandLine(linkCmds); - // Write the linker rule. + // Write the linker rule with response file if needed. std::ostringstream comment; comment << "Rule for linking " << this->TargetLinkLanguage << " " << this->GetVisibleTypeName() << "."; @@ -224,7 +248,9 @@ cmNinjaNormalTargetGenerator this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(), - comment.str()); + comment.str(), + /*depfile*/ "", + rspfile); } if (this->TargetNameOut != this->TargetNameReal) { @@ -456,6 +482,12 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() symlinkVars["POST_BUILD"] = postBuildCmdLine; } + int cmdLineLimit = -1; +#ifdef _WIN32 + cmdLineLimit = 30000; +#else + // TODO +#endif // Write the build statement for this target. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), comment.str(), @@ -464,7 +496,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() explicitDeps, implicitDeps, emptyDeps, - vars); + vars, + cmdLineLimit); if (targetOutput != targetOutputReal) { if (targetType == cmTarget::EXECUTABLE) { diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h index 7acbe8f6f..3be1c94e1 100644 --- a/Source/cmNinjaNormalTargetGenerator.h +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -30,7 +30,7 @@ private: std::string LanguageLinkerRule() const; const char* GetVisibleTypeName() const; void WriteLanguagesRules(); - void WriteLinkRule(); + void WriteLinkRule(bool useResponseFile); void WriteLinkStatement(); void WriteObjectLibStatement(); std::vector ComputeLinkCmd();