ENH: Simplified and moved link script implementation up from cmMakefileLibraryTargetGenerator to cmMakefileTargetGenerator and use for cmMakefileExecutableTargetGenerator too. This addresses bug #6192.

This commit is contained in:
Brad King 2007-12-28 14:59:06 -05:00
parent 0a7bb41129
commit 59aa144516
4 changed files with 151 additions and 127 deletions

View File

@ -339,14 +339,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
->AppendCustomCommands(commands, this->Target->GetPreLinkCommands()); ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
} }
// Determine whether a link script will be used.
bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
// Construct the main link rule. // Construct the main link rule.
std::vector<std::string> real_link_commands;
std::string linkRuleVar = "CMAKE_"; std::string linkRuleVar = "CMAKE_";
linkRuleVar += linkLanguage; linkRuleVar += linkLanguage;
linkRuleVar += "_LINK_EXECUTABLE"; linkRuleVar += "_LINK_EXECUTABLE";
std::string linkRule = std::string linkRule =
this->Makefile->GetRequiredDefinition(linkRuleVar.c_str()); this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
std::vector<std::string> commands1; std::vector<std::string> commands1;
cmSystemTools::ExpandListArgument(linkRule, commands1); cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
if(this->Target->GetPropertyAsBool("ENABLE_EXPORTS")) if(this->Target->GetPropertyAsBool("ENABLE_EXPORTS"))
{ {
// If a separate rule for creating an import library is specified // If a separate rule for creating an import library is specified
@ -357,37 +361,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
if(const char* rule = if(const char* rule =
this->Makefile->GetDefinition(implibRuleVar.c_str())) this->Makefile->GetDefinition(implibRuleVar.c_str()))
{ {
cmSystemTools::ExpandListArgument(rule, commands1); cmSystemTools::ExpandListArgument(rule, real_link_commands);
} }
} }
this->LocalGenerator->CreateCDCommand
(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
// Add a rule to create necessary symlinks for the library.
if(targetOutPath != targetOutPathReal)
{
std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
symlink += targetOutPathReal;
symlink += " ";
symlink += targetOutPath;
commands1.clear();
commands1.push_back(symlink);
this->LocalGenerator->CreateCDCommand(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
}
// Add the post-build rules when building but not when relinking.
if(!relink)
{
this->LocalGenerator->
AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
}
// Expand the rule variables.
{
// Collect up flags to link in needed libraries. // Collect up flags to link in needed libraries.
cmOStringStream linklibs; cmOStringStream linklibs;
this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink); this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
@ -397,11 +376,19 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
std::string variableName; std::string variableName;
std::string variableNameExternal; std::string variableNameExternal;
this->WriteObjectsVariable(variableName, variableNameExternal); this->WriteObjectsVariable(variableName, variableNameExternal);
std::string buildObjs = "$("; std::string buildObjs;
buildObjs += variableName; if(useLinkScript)
buildObjs += ") $("; {
buildObjs += variableNameExternal; this->WriteObjectsString(buildObjs);
buildObjs += ")"; }
else
{
buildObjs = "$(";
buildObjs += variableName;
buildObjs += ") $(";
buildObjs += variableNameExternal;
buildObjs += ")";
}
std::string cleanObjs = "$("; std::string cleanObjs = "$(";
cleanObjs += variableName; cleanObjs += variableName;
cleanObjs += ")"; cleanObjs += ")";
@ -435,12 +422,55 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
vars.LinkFlags = linkFlags.c_str(); vars.LinkFlags = linkFlags.c_str();
// Expand placeholders in the commands. // Expand placeholders in the commands.
this->LocalGenerator->TargetImplib = targetOutPathImport; this->LocalGenerator->TargetImplib = targetOutPathImport;
for(std::vector<std::string>::iterator i = commands.begin(); for(std::vector<std::string>::iterator i = real_link_commands.begin();
i != commands.end(); ++i) i != real_link_commands.end(); ++i)
{ {
this->LocalGenerator->ExpandRuleVariables(*i, vars); this->LocalGenerator->ExpandRuleVariables(*i, vars);
} }
this->LocalGenerator->TargetImplib = ""; this->LocalGenerator->TargetImplib = "";
}
// Optionally convert the build rule to use a script to avoid long
// command lines in the make shell.
if(useLinkScript)
{
// Use a link script.
const char* name = (relink? "relink.txt" : "link.txt");
this->CreateLinkScript(name, real_link_commands, commands1);
}
else
{
// No link script. Just use the link rule directly.
commands1 = real_link_commands;
}
this->LocalGenerator->CreateCDCommand
(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
// Add a rule to create necessary symlinks for the library.
if(targetOutPath != targetOutPathReal)
{
std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
symlink += targetOutPathReal;
symlink += " ";
symlink += targetOutPath;
commands1.push_back(symlink);
this->LocalGenerator->CreateCDCommand(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
}
// Add the post-build rules when building but not when relinking.
if(!relink)
{
this->LocalGenerator->
AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
}
// Write the build rule. // Write the build rule.
this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,

View File

@ -668,77 +668,16 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
->AppendCustomCommands(commands, this->Target->GetPreLinkCommands()); ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
} }
// Open the link script if it will be used. // Determine whether a link script will be used.
bool useLinkScript = false; bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
std::string linkScriptName;
std::auto_ptr<cmGeneratedFileStream> linkScriptStream;
if(this->GlobalGenerator->GetUseLinkScript() &&
(this->Target->GetType() == cmTarget::STATIC_LIBRARY ||
this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
this->Target->GetType() == cmTarget::MODULE_LIBRARY))
{
useLinkScript = true;
linkScriptName = this->TargetBuildDirectoryFull;
if(relink)
{
linkScriptName += "/relink.txt";
}
else
{
linkScriptName += "/link.txt";
}
std::auto_ptr<cmGeneratedFileStream> lss(
new cmGeneratedFileStream(linkScriptName.c_str()));
linkScriptStream = lss;
}
std::vector<std::string> link_script_commands;
// Construct the main link rule. // Construct the main link rule.
std::vector<std::string> real_link_commands;
std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
if(useLinkScript) cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
{
cmSystemTools::ExpandListArgument(linkRule, link_script_commands);
std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script ";
link_command += this->Convert(linkScriptName.c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::SHELL);
link_command += " --verbose=$(VERBOSE)";
commands1.push_back(link_command);
}
else
{
cmSystemTools::ExpandListArgument(linkRule, commands1);
}
this->LocalGenerator->CreateCDCommand
(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
// Add a rule to create necessary symlinks for the library.
if(targetOutPath != targetOutPathReal)
{
std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
symlink += targetOutPathReal;
symlink += " ";
symlink += targetOutPathSO;
symlink += " ";
symlink += targetOutPath;
commands1.clear();
commands1.push_back(symlink);
this->LocalGenerator->CreateCDCommand(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
}
// Add the post-build rules when building but not when relinking.
if(!relink)
{
this->LocalGenerator->
AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
}
// Expand the rule variables.
{
// Collect up flags to link in needed libraries. // Collect up flags to link in needed libraries.
cmOStringStream linklibs; cmOStringStream linklibs;
this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink); this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
@ -834,38 +773,55 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
vars.LanguageCompileFlags = langFlags.c_str(); vars.LanguageCompileFlags = langFlags.c_str();
// Expand placeholders in the commands. // Expand placeholders in the commands.
this->LocalGenerator->TargetImplib = targetOutPathImport; this->LocalGenerator->TargetImplib = targetOutPathImport;
if(useLinkScript) for(std::vector<std::string>::iterator i = real_link_commands.begin();
i != real_link_commands.end(); ++i)
{ {
for(std::vector<std::string>::iterator i = link_script_commands.begin(); this->LocalGenerator->ExpandRuleVariables(*i, vars);
i != link_script_commands.end(); ++i)
{
this->LocalGenerator->ExpandRuleVariables(*i, vars);
}
}
else
{
for(std::vector<std::string>::iterator i = commands.begin();
i != commands.end(); ++i)
{
this->LocalGenerator->ExpandRuleVariables(*i, vars);
}
} }
this->LocalGenerator->TargetImplib = ""; this->LocalGenerator->TargetImplib = "";
}
// Optionally convert the build rule to use a script to avoid long // Optionally convert the build rule to use a script to avoid long
// command lines in the make shell. // command lines in the make shell.
if(useLinkScript) if(useLinkScript)
{ {
for(std::vector<std::string>::iterator cmd = link_script_commands.begin(); // Use a link script.
cmd != link_script_commands.end(); ++cmd) const char* name = (relink? "relink.txt" : "link.txt");
{ this->CreateLinkScript(name, real_link_commands, commands1);
// Do not write out empty commands or commands beginning in the }
// shell no-op ":". else
if(!cmd->empty() && (*cmd)[0] != ':') {
{ // No link script. Just use the link rule directly.
(*linkScriptStream) << *cmd << "\n"; commands1 = real_link_commands;
} }
} this->LocalGenerator->CreateCDCommand
(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
// Add a rule to create necessary symlinks for the library.
if(targetOutPath != targetOutPathReal)
{
std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
symlink += targetOutPathReal;
symlink += " ";
symlink += targetOutPathSO;
symlink += " ";
symlink += targetOutPath;
commands1.push_back(symlink);
this->LocalGenerator->CreateCDCommand(commands1,
this->Makefile->GetStartOutputDirectory(),
this->Makefile->GetHomeOutputDirectory());
commands.insert(commands.end(), commands1.begin(), commands1.end());
commands1.clear();
}
// Add the post-build rules when building but not when relinking.
if(!relink)
{
this->LocalGenerator->
AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
} }
// Write the build rule. // Write the build rule.

View File

@ -1391,3 +1391,35 @@ cmMakefileTargetGenerator
MultipleOutputPairsType::value_type p(depender, dependee); MultipleOutputPairsType::value_type p(depender, dependee);
this->MultipleOutputPairs.insert(p); this->MultipleOutputPairs.insert(p);
} }
//----------------------------------------------------------------------------
void
cmMakefileTargetGenerator
::CreateLinkScript(const char* name,
std::vector<std::string> const& link_commands,
std::vector<std::string>& makefile_commands)
{
// Create the link script file.
std::string linkScriptName = this->TargetBuildDirectoryFull;
linkScriptName += "/";
linkScriptName += name;
cmGeneratedFileStream linkScriptStream(linkScriptName.c_str());
for(std::vector<std::string>::const_iterator cmd = link_commands.begin();
cmd != link_commands.end(); ++cmd)
{
// Do not write out empty commands or commands beginning in the
// shell no-op ":".
if(!cmd->empty() && (*cmd)[0] != ':')
{
linkScriptStream << *cmd << "\n";
}
}
// Create the makefile command to invoke the link script.
std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script ";
link_command += this->Convert(linkScriptName.c_str(),
cmLocalGenerator::START_OUTPUT,
cmLocalGenerator::SHELL);
link_command += " --verbose=$(VERBOSE)";
makefile_commands.push_back(link_command);
}

View File

@ -128,6 +128,12 @@ protected:
makefile generators to register such pairs. */ makefile generators to register such pairs. */
void AddMultipleOutputPair(const char* depender, const char* dependee); void AddMultipleOutputPair(const char* depender, const char* dependee);
/** Create a script to hold link rules and a command to invoke the
script at build time. */
void CreateLinkScript(const char* name,
std::vector<std::string> const& link_commands,
std::vector<std::string>& makefile_commands);
virtual void CloseFileStreams(); virtual void CloseFileStreams();
void RemoveForbiddenFlags(const char* flagVar, const char* linkLang, void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
std::string& linkFlags); std::string& linkFlags);