Merge topic 'link-libraries-response-files'

489b1c23 Windows: Use response files to specify link libraries for GNU tools
745caae6 Makefile: Rename linker response file boolean to be more specific
5e8e4d0f cmLocalGenerator: Add response file option to OutputLinkLibraries
b9aa5041 cmLocalGenerator: Simplify GetIncludeFlags output formatting
971653b7 cmLocalGenerator: Add format option to ConvertToLinkReference
0c0ef9e7 cmLocalGenerator: Add format option to ConvertToIncludeReference
02bebd60 cmLocalGenerator: Add format option to ConvertToOutputForExisting
c8751709 Makefile: Factor out some duplicate link libraries generation
This commit is contained in:
Brad King 2014-03-06 09:46:50 -05:00 committed by CMake Topic Stage
commit 7c9041bdab
10 changed files with 148 additions and 68 deletions

View File

@ -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.

View File

@ -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()

View File

@ -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 << " ";
}

View File

@ -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;

View File

@ -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);
}
//----------------------------------------------------------------------------

View File

@ -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:

View File

@ -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";

View File

@ -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();

View File

@ -1830,6 +1830,46 @@ cmMakefileTargetGenerator
return responseFileName;
}
//----------------------------------------------------------------------------
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

View File

@ -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,