diff options
-rw-r--r-- | Help/release/dev/link-libraries-response-files.rst | 5 | ||||
-rw-r--r-- | Modules/Platform/Windows-GNU.cmake | 5 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 70 | ||||
-rw-r--r-- | Source/cmLocalGenerator.h | 18 | ||||
-rw-r--r-- | Source/cmLocalNinjaGenerator.cxx | 10 | ||||
-rw-r--r-- | Source/cmLocalNinjaGenerator.h | 6 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.cxx | 28 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 29 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 40 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.h | 5 |
10 files changed, 148 insertions, 68 deletions
diff --git a/Help/release/dev/link-libraries-response-files.rst b/Help/release/dev/link-libraries-response-files.rst new file mode 100644 index 0000000..cecf7f6 --- /dev/null +++ b/Help/release/dev/link-libraries-response-files.rst @@ -0,0 +1,5 @@ +link-libraries-response-files +----------------------------- + +* The Makefile generators learned to use response files with GNU tools + on Windows to pass library directories and names to the linker. diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake index 2bb7a20..5c5b360 100644 --- a/Modules/Platform/Windows-GNU.cmake +++ b/Modules/Platform/Windows-GNU.cmake @@ -87,6 +87,7 @@ macro(__windows_compiler_gnu lang) set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "") set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS ${__WINDOWS_GNU_LD_RESPONSE}) + set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES ${__WINDOWS_GNU_LD_RESPONSE}) set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1) # We prefer "@" for response files but it is not supported by gcc 3. @@ -103,7 +104,9 @@ macro(__windows_compiler_gnu lang) endif() # The GNU 3.x compilers do not support response files (only linkers). set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 0) - elseif(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS) + # Link libraries are generated only for the front-end. + set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 0) + else() # Use "@" to pass the response file to the front-end. set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "@") endif() diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4266dd0..b86a956 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1228,7 +1228,8 @@ void cmLocalGenerator::InsertRuleLauncher(std::string& s, cmTarget* target, //---------------------------------------------------------------------------- std::string cmLocalGenerator::ConvertToOutputForExistingCommon(const char* remote, - std::string const& result) + std::string const& result, + OutputFormat format) { // If this is a windows shell, the result has a space, and the path // already exists, we can use a short-path to reference it without a @@ -1239,7 +1240,7 @@ cmLocalGenerator::ConvertToOutputForExistingCommon(const char* remote, std::string tmp; if(cmSystemTools::GetShortPath(remote, tmp)) { - return this->Convert(tmp.c_str(), NONE, SHELL, true); + return this->Convert(tmp.c_str(), NONE, format, true); } } @@ -1250,33 +1251,36 @@ cmLocalGenerator::ConvertToOutputForExistingCommon(const char* remote, //---------------------------------------------------------------------------- std::string cmLocalGenerator::ConvertToOutputForExisting(const char* remote, - RelativeRoot local) + RelativeRoot local, + OutputFormat format) { // Perform standard conversion. - std::string result = this->Convert(remote, local, SHELL, true); + std::string result = this->Convert(remote, local, format, true); // Consider short-path. - return this->ConvertToOutputForExistingCommon(remote, result); + return this->ConvertToOutputForExistingCommon(remote, result, format); } //---------------------------------------------------------------------------- std::string cmLocalGenerator::ConvertToOutputForExisting(RelativeRoot remote, - const char* local) + const char* local, + OutputFormat format) { // Perform standard conversion. - std::string result = this->Convert(remote, local, SHELL, true); + std::string result = this->Convert(remote, local, format, true); // Consider short-path. const char* remotePath = this->GetRelativeRootPath(remote); - return this->ConvertToOutputForExistingCommon(remotePath, result); + return this->ConvertToOutputForExistingCommon(remotePath, result, format); } //---------------------------------------------------------------------------- std::string -cmLocalGenerator::ConvertToIncludeReference(std::string const& path) +cmLocalGenerator::ConvertToIncludeReference(std::string const& path, + OutputFormat format) { - return this->ConvertToOutputForExisting(path.c_str()); + return this->ConvertToOutputForExisting(path.c_str(), START_OUTPUT, format); } //---------------------------------------------------------------------------- @@ -1291,6 +1295,7 @@ std::string cmLocalGenerator::GetIncludeFlags( return ""; } + OutputFormat shellFormat = forResponseFile? RESPONSE : SHELL; cmOStringStream includeFlags; std::string flagVar = "CMAKE_INCLUDE_FLAG_"; @@ -1350,10 +1355,9 @@ std::string cmLocalGenerator::GetIncludeFlags( frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir.c_str()); if(emitted.insert(frameworkDir).second) { - OutputFormat format = forResponseFile? RESPONSE : SHELL; includeFlags << fwSearchFlag << this->Convert(frameworkDir.c_str(), - START_OUTPUT, format, true) + START_OUTPUT, shellFormat, true) << " "; } continue; @@ -1372,16 +1376,8 @@ std::string cmLocalGenerator::GetIncludeFlags( } flagUsed = true; } - std::string includePath; - if(forResponseFile) - { - includePath = this->Convert(i->c_str(), START_OUTPUT, - RESPONSE, true); - } - else - { - includePath = this->ConvertToIncludeReference(*i); - } + std::string includePath = + this->ConvertToIncludeReference(*i, shellFormat); if(quotePaths && includePath.size() && includePath[0] != '\"') { includeFlags << "\""; @@ -1675,7 +1671,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, } } this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, - *target, false); + *target, false, false); } break; case cmTarget::EXECUTABLE: @@ -1700,7 +1696,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, } this->AddLanguageFlags(flags, linkLanguage, buildType.c_str()); this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, - *target, false); + *target, false, false); if(cmSystemTools::IsOn (this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) { @@ -1755,7 +1751,8 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, } } -std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib) +std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, + OutputFormat format) { #if defined(_WIN32) && !defined(__CYGWIN__) // Work-ardound command line parsing limitations in MSVC 6.0 and @@ -1777,14 +1774,14 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib) sp += lib.substr(pos); // Convert to an output path. - return this->Convert(sp.c_str(), NONE, SHELL); + return this->Convert(sp.c_str(), NONE, format); } } } #endif // Normal behavior. - return this->Convert(lib.c_str(), START_OUTPUT, SHELL); + return this->Convert(lib.c_str(), START_OUTPUT, format); } /** @@ -1796,8 +1793,11 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget &tgt, - bool relink) + bool relink, + bool forResponseFile) { + OutputFormat shellFormat = forResponseFile? RESPONSE : SHELL; + bool escapeAllowMakeVars = !forResponseFile; cmOStringStream fout; const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); cmComputeLinkInformation* pcli = tgt.Target->GetLinkInformation(config); @@ -1840,7 +1840,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, fdi != fwDirs.end(); ++fdi) { frameworkPath += fwSearchFlag; - frameworkPath += this->Convert(fdi->c_str(), NONE, SHELL, false); + frameworkPath += this->Convert(fdi->c_str(), NONE, shellFormat, false); frameworkPath += " "; } } @@ -1850,7 +1850,9 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, for(std::vector<std::string>::const_iterator libDir = libDirs.begin(); libDir != libDirs.end(); ++libDir) { - std::string libpath = this->ConvertToOutputForExisting(libDir->c_str()); + std::string libpath = this->ConvertToOutputForExisting(libDir->c_str(), + START_OUTPUT, + shellFormat); linkPath += " " + libPathFlag; linkPath += libpath; linkPath += libPathTerminator; @@ -1868,7 +1870,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, } if(li->IsPath) { - linkLibs += this->ConvertToLinkReference(li->Value); + linkLibs += this->ConvertToLinkReference(li->Value, shellFormat); } else { @@ -1893,7 +1895,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, ri != runtimeDirs.end(); ++ri) { rpath += cli.GetRuntimeFlag(); - rpath += this->Convert(ri->c_str(), NONE, SHELL, false); + rpath += this->Convert(ri->c_str(), NONE, shellFormat, false); rpath += " "; } fout << rpath; @@ -1907,7 +1909,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, if(!rpath.empty()) { fout << cli.GetRuntimeFlag(); - fout << this->EscapeForShell(rpath.c_str(), true); + fout << this->EscapeForShell(rpath.c_str(), escapeAllowMakeVars); fout << " "; } } @@ -1917,7 +1919,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, if(!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) { fout << cli.GetRPathLinkFlag(); - fout << this->EscapeForShell(rpath_link.c_str(), true); + fout << this->EscapeForShell(rpath_link.c_str(), escapeAllowMakeVars); fout << " "; } diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 0f7fd25..2e05804 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -198,14 +198,17 @@ public: ///! for existing files convert to output path and short path if spaces std::string ConvertToOutputForExisting(const char* remote, - RelativeRoot local = START_OUTPUT); + RelativeRoot local = START_OUTPUT, + OutputFormat format = SHELL); /** For existing path identified by RelativeRoot convert to output path and short path if spaces. */ std::string ConvertToOutputForExisting(RelativeRoot remote, - const char* local = 0); + const char* local = 0, + OutputFormat format = SHELL); - virtual std::string ConvertToIncludeReference(std::string const& path); + virtual std::string ConvertToIncludeReference(std::string const& path, + OutputFormat format = SHELL); /** Called from command-line hook to clear dependencies. */ virtual void ClearDependencies(cmMakefile* /* mf */, @@ -369,7 +372,8 @@ protected: std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget &, - bool relink); + bool relink, + bool forResponseFile); // Expand rule variables in CMake of the type found in language rules void ExpandRuleVariables(std::string& string, @@ -412,7 +416,8 @@ protected: std::string FindRelativePathTopBinary(); void SetupPathConversions(); - virtual std::string ConvertToLinkReference(std::string const& lib); + virtual std::string ConvertToLinkReference(std::string const& lib, + OutputFormat format = SHELL); /** Check whether the native build system supports the given definition. Issues a warning. */ @@ -465,7 +470,8 @@ protected: bool BackwardsCompatibilityFinal; private: std::string ConvertToOutputForExistingCommon(const char* remote, - std::string const& result); + std::string const& result, + OutputFormat format); void AddSharedFlags(std::string& flags, const char* lang, bool shared); bool GetShouldUseOldFlags(bool shared, const std::string &lang) const; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index cd12c9d..862823f 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -143,15 +143,17 @@ cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator() // Virtual protected methods. std::string -cmLocalNinjaGenerator::ConvertToLinkReference(std::string const& lib) +cmLocalNinjaGenerator::ConvertToLinkReference(std::string const& lib, + OutputFormat format) { - return this->Convert(lib.c_str(), HOME_OUTPUT, SHELL); + return this->Convert(lib.c_str(), HOME_OUTPUT, format); } std::string -cmLocalNinjaGenerator::ConvertToIncludeReference(std::string const& path) +cmLocalNinjaGenerator::ConvertToIncludeReference(std::string const& path, + OutputFormat format) { - return this->Convert(path.c_str(), HOME_OUTPUT, SHELL); + return this->Convert(path.c_str(), HOME_OUTPUT, format); } //---------------------------------------------------------------------------- diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h index ea854c6..8b26806 100644 --- a/Source/cmLocalNinjaGenerator.h +++ b/Source/cmLocalNinjaGenerator.h @@ -97,11 +97,13 @@ public: void AppendCustomCommandDeps(const cmCustomCommand *cc, cmNinjaDeps &ninjaDeps); - virtual std::string ConvertToLinkReference(std::string const& lib); + virtual std::string ConvertToLinkReference(std::string const& lib, + OutputFormat format = SHELL); protected: - virtual std::string ConvertToIncludeReference(std::string const& path); + virtual std::string ConvertToIncludeReference(std::string const& path, + OutputFormat format = SHELL); private: diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 03fdda2..1802054 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -307,14 +307,26 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) } // Select whether to use a response file for objects. - bool useResponseFile = false; + bool useResponseFileForObjects = false; { std::string responseVar = "CMAKE_"; responseVar += linkLanguage; responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS"; if(this->Makefile->IsOn(responseVar.c_str())) { - useResponseFile = true; + useResponseFileForObjects = true; + } + } + + // Select whether to use a response file for libraries. + bool useResponseFileForLibs = false; + { + std::string responseVar = "CMAKE_"; + responseVar += linkLanguage; + responseVar += "_USE_RESPONSE_FILE_FOR_LIBRARIES"; + if(this->Makefile->IsOn(responseVar.c_str())) + { + useResponseFileForLibs = true; } } @@ -325,17 +337,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // Collect up flags to link in needed libraries. std::string linkLibs; - std::string frameworkPath; - std::string linkPath; - this->LocalGenerator->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, - *this->GeneratorTarget, - relink); - linkLibs = frameworkPath + linkPath + linkLibs; + this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends); + // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; - this->CreateObjectLists(useLinkScript, false, useResponseFile, - buildObjs, depends); + this->CreateObjectLists(useLinkScript, false, + useResponseFileForObjects, buildObjs, depends); cmLocalGenerator::RuleVariables vars; vars.RuleLauncher = "RULE_LAUNCH_LINK"; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 807aca8..39e00b2 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -474,14 +474,26 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); // Select whether to use a response file for objects. - bool useResponseFile = false; + bool useResponseFileForObjects = false; { std::string responseVar = "CMAKE_"; responseVar += linkLanguage; responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS"; if(this->Makefile->IsOn(responseVar.c_str())) { - useResponseFile = true; + useResponseFileForObjects = true; + } + } + + // Select whether to use a response file for libraries. + bool useResponseFileForLibs = false; + { + std::string responseVar = "CMAKE_"; + responseVar += linkLanguage; + responseVar += "_USE_RESPONSE_FILE_FOR_LIBRARIES"; + if(this->Makefile->IsOn(responseVar.c_str())) + { + useResponseFileForLibs = true; } } @@ -528,7 +540,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules useLinkScript = true; // Archiving rules never use a response file. - useResponseFile = false; + useResponseFileForObjects = false; // Limit the length of individual object lists to less than the // 32K command line length limit on Windows. We could make this a @@ -546,19 +558,14 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules std::string linkLibs; if(this->Target->GetType() != cmTarget::STATIC_LIBRARY) { - std::string frameworkPath; - std::string linkPath; - this->LocalGenerator - ->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, - *this->GeneratorTarget, relink); - linkLibs = frameworkPath + linkPath + linkLibs; + this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends); } // Construct object file lists that may be needed to expand the // rule. std::string buildObjs; - this->CreateObjectLists(useLinkScript, useArchiveRules, useResponseFile, - buildObjs, depends); + this->CreateObjectLists(useLinkScript, useArchiveRules, + useResponseFileForObjects, buildObjs, depends); cmLocalGenerator::RuleVariables vars; vars.TargetPDB = targetOutPathPDB.c_str(); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index e8a9fd1..facbcc6 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1833,6 +1833,46 @@ cmMakefileTargetGenerator //---------------------------------------------------------------------------- void cmMakefileTargetGenerator +::CreateLinkLibs(std::string& linkLibs, bool relink, + bool useResponseFile, + std::vector<std::string>& makefile_depends) +{ + std::string frameworkPath; + std::string linkPath; + this->LocalGenerator + ->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, + *this->GeneratorTarget, relink, + useResponseFile); + linkLibs = frameworkPath + linkPath + linkLibs; + + if(useResponseFile) + { + // Lookup the response file reference flag. + std::string responseFlagVar = "CMAKE_"; + responseFlagVar += this->Target->GetLinkerLanguage(this->ConfigName); + responseFlagVar += "_RESPONSE_FILE_LINK_FLAG"; + const char* responseFlag = + this->Makefile->GetDefinition(responseFlagVar.c_str()); + if(!responseFlag) + { + responseFlag = "@"; + } + + // Create this response file. + std::string link_rsp = + this->CreateResponseFile("linklibs.rsp", linkLibs, makefile_depends); + + // Reference the response file. + linkLibs = responseFlag; + linkLibs += this->Convert(link_rsp.c_str(), + cmLocalGenerator::NONE, + cmLocalGenerator::SHELL); + } +} + +//---------------------------------------------------------------------------- +void +cmMakefileTargetGenerator ::CreateObjectLists(bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, std::vector<std::string>& makefile_depends) diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 4f8fafa..72dc6bc 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -163,6 +163,11 @@ protected: std::string const& options, std::vector<std::string>& makefile_depends); + /** Create list of flags for link libraries. */ + void CreateLinkLibs(std::string& linkLibs, bool relink, + bool useResponseFile, + std::vector<std::string>& makefile_depends); + /** Create lists of object files for linking and cleaning. */ void CreateObjectLists(bool useLinkScript, bool useArchiveRules, bool useResponseFile, std::string& buildObjs, |