summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/release/dev/link-libraries-response-files.rst5
-rw-r--r--Modules/Platform/Windows-GNU.cmake5
-rw-r--r--Source/cmLocalGenerator.cxx70
-rw-r--r--Source/cmLocalGenerator.h18
-rw-r--r--Source/cmLocalNinjaGenerator.cxx10
-rw-r--r--Source/cmLocalNinjaGenerator.h6
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx28
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx29
-rw-r--r--Source/cmMakefileTargetGenerator.cxx40
-rw-r--r--Source/cmMakefileTargetGenerator.h5
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,