diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index 5018a8c26c..1ce506dbd9 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -25,6 +25,7 @@ cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator() this->FindMakeProgramFile = "CMakeBorlandFindMake.cmake"; this->ForceUnixPaths = false; this->ToolSupportsColor = true; + this->UseLinkScript = false; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 0feb91e5a8..d840b8aa81 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -36,6 +36,9 @@ cmGlobalGenerator::cmGlobalGenerator() // By default do not try to support color. this->ToolSupportsColor = false; + + // By default do not use link scripts. + this->UseLinkScript = false; } cmGlobalGenerator::~cmGlobalGenerator() diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index b60d497d85..7a0578353c 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -152,6 +152,9 @@ public: std::string ConvertToRelativePath(const std::vector& local, const char* remote); + /** Get whether the generator should use a script for link commands. */ + bool GetUseLinkScript() { return this->UseLinkScript; } + /* * Determine what program to use for building the project. */ @@ -204,6 +207,7 @@ protected: const cmCustomCommandLines* commandLines, std::vector depends, bool depends_on_all = false); + bool UseLinkScript; bool ForceUnixPaths; bool ToolSupportsColor; cmStdString FindMakeProgramFile; diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx index 16c52cc4b3..8ae0b086cc 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.cxx +++ b/Source/cmGlobalMSYSMakefileGenerator.cxx @@ -24,6 +24,7 @@ cmGlobalMSYSMakefileGenerator::cmGlobalMSYSMakefileGenerator() this->FindMakeProgramFile = "CMakeMSYSFindMake.cmake"; this->ForceUnixPaths = true; this->ToolSupportsColor = true; + this->UseLinkScript = false; } std::string diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx index 7e9ad82a93..f66134c595 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.cxx +++ b/Source/cmGlobalMinGWMakefileGenerator.cxx @@ -23,6 +23,7 @@ cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator() this->FindMakeProgramFile = "CMakeMinGWFindMake.cmake"; this->ForceUnixPaths = true; this->ToolSupportsColor = true; + this->UseLinkScript = true; } void cmGlobalMinGWMakefileGenerator diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index bfb09db26e..35a2a86bf1 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -23,6 +23,7 @@ cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator() this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake"; this->ForceUnixPaths = false; this->ToolSupportsColor = true; + this->UseLinkScript = false; } void cmGlobalNMakeMakefileGenerator diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 387e7e0660..82c87e21aa 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -31,6 +31,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3() this->ToolSupportsColor = true; this->NumberOfSourceFiles = 0; this->NumberOfSourceFilesWritten = 0; + this->UseLinkScript = true; } void cmGlobalUnixMakefileGenerator3 diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index a292605a64..c2de260df2 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -24,6 +24,8 @@ #include "cmTarget.h" #include "cmake.h" +#include // auto_ptr + //---------------------------------------------------------------------------- void cmMakefileLibraryTargetGenerator::WriteRuleFiles() { @@ -376,9 +378,41 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands()); } + // Open the link script if it will be used. + bool useLinkScript = false; + std::string linkScriptName; + std::auto_ptr 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; + linkScriptName += "/link.txt"; + std::auto_ptr lss( + new cmGeneratedFileStream(linkScriptName.c_str())); + linkScriptStream = lss; + } + + std::vector link_script_commands; + // Construct the main link rule. std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar); - cmSystemTools::ExpandListArgument(linkRule, commands1); + if(useLinkScript) + { + 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(), @@ -418,11 +452,19 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules std::string variableName; std::string variableNameExternal; this->WriteObjectsVariable(variableName, variableNameExternal); - std::string buildObjs = "$("; - buildObjs += variableName; - buildObjs += ") $("; - buildObjs += variableNameExternal; - buildObjs += ")"; + std::string buildObjs; + if(useLinkScript) + { + this->WriteObjectsString(buildObjs); + } + else + { + buildObjs = "$("; + buildObjs += variableName; + buildObjs += ") $("; + buildObjs += variableNameExternal; + buildObjs += ")"; + } std::string cleanObjs = "$("; cleanObjs += variableName; cleanObjs += ")"; @@ -493,13 +535,35 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules vars.LanguageCompileFlags = langFlags.c_str(); // Expand placeholders in the commands. this->LocalGenerator->TargetImplib = targetOutPathImport; - for(std::vector::iterator i = commands.begin(); - i != commands.end(); ++i) + if(useLinkScript) { - this->LocalGenerator->ExpandRuleVariables(*i, vars); + for(std::vector::iterator i = link_script_commands.begin(); + i != link_script_commands.end(); ++i) + { + this->LocalGenerator->ExpandRuleVariables(*i, vars); + } + } + else + { + for(std::vector::iterator i = commands.begin(); + i != commands.end(); ++i) + { + this->LocalGenerator->ExpandRuleVariables(*i, vars); + } } this->LocalGenerator->TargetImplib = ""; + // Optionally convert the build rule to use a script to avoid long + // command lines in the make shell. + if(useLinkScript) + { + for(std::vector::iterator cmd = link_script_commands.begin(); + cmd != link_script_commands.end(); ++cmd) + { + (*linkScriptStream) << *cmd << "\n"; + } + } + // Write the build rule. this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0, targetFullPathReal.c_str(), diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 897362704c..0f1a087b46 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -808,6 +808,56 @@ cmMakefileTargetGenerator *this->BuildFileStream << "\n" << "\n"; } +//---------------------------------------------------------------------------- +void +cmMakefileTargetGenerator +::WriteObjectsString(std::string& buildObjs) +{ + std::string object; + const char* no_quoted = + this->Makefile->GetDefinition("CMAKE_NO_QUOTED_OBJECTS"); + const char* space = ""; + for(std::vector::const_iterator i = this->Objects.begin(); + i != this->Objects.end(); ++i) + { + if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() ) + { + continue; + } + buildObjs += space; + space = " "; + if(no_quoted) + { + buildObjs += + this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + } + else + { + buildObjs += + this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str()); + } + } + for(std::vector::const_iterator i = + this->ExternalObjects.begin(); + i != this->ExternalObjects.end(); ++i) + { + buildObjs += space; + space = " "; + if(no_quoted) + { + buildObjs += + this->Convert(i->c_str(), cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + } + else + { + buildObjs += + this->LocalGenerator->ConvertToQuotedOutputPath(i->c_str()); + } + } +} + //---------------------------------------------------------------------------- void cmMakefileTargetGenerator::WriteTargetDriverRule(const char* main_output, bool relink) diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h index 35c702d2c5..a62430592b 100644 --- a/Source/cmMakefileTargetGenerator.h +++ b/Source/cmMakefileTargetGenerator.h @@ -91,6 +91,7 @@ protected: // write out the variable that lists the objects for this target void WriteObjectsVariable(std::string& variableName, std::string& variableNameExternal); + void WriteObjectsString(std::string& buildObjs); // write the driver rule to build target outputs void WriteTargetDriverRule(const char* main_output, bool relink); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 550e0a6984..44efd2372e 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -32,6 +32,7 @@ #endif # include +#include // only build kdevelop generator on non-windows platforms // when not bootstrapping cmake @@ -1178,6 +1179,12 @@ int cmake::ExecuteCMakeCommand(std::vector& args) return 1; } + // Internal CMake link script support. + else if (args[1] == "cmake_link_script" && args.size() >= 3) + { + return cmake::ExecuteLinkScript(args); + } + #ifdef CMAKE_BUILD_WITH_CMAKE // Internal CMake color makefile support. else if (args[1] == "cmake_echo_color") @@ -2643,3 +2650,101 @@ int cmake::ExecuteEchoColor(std::vector&) return 1; } #endif + +//---------------------------------------------------------------------------- +int cmake::ExecuteLinkScript(std::vector& args) +{ + // The arguments are + // argv[0] == + // argv[1] == cmake_link_script + // argv[2] == + // argv[3] == --verbose=? + bool verbose = false; + if(args.size() >= 4) + { + if(args[3].find("--verbose=") == 0) + { + if(!cmSystemTools::IsOff(args[3].substr(10).c_str())) + { + verbose = true; + } + } + } + + // Allocate a process instance. + cmsysProcess* cp = cmsysProcess_New(); + if(!cp) + { + std::cerr << "Error allocating process instance in link script." + << std::endl; + return 1; + } + + // Children should share stdout and stderr with this process. + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDOUT, 1); + cmsysProcess_SetPipeShared(cp, cmsysProcess_Pipe_STDERR, 1); + + // Run the command lines verbatim. + cmsysProcess_SetOption(cp, cmsysProcess_Option_Verbatim, 1); + + // Read command lines from the script. + std::ifstream fin(args[2].c_str()); + if(!fin) + { + std::cerr << "Error opening link script \"" + << args[2] << "\"" << std::endl; + return 1; + } + + // Run one command at a time. + std::string command; + int result = 0; + while(result == 0 && cmSystemTools::GetLineFromStream(fin, command)) + { + // Setup this command line. + const char* cmd[2] = {command.c_str(), 0}; + cmsysProcess_SetCommand(cp, cmd); + + // Report the command if verbose output is enabled. + if(verbose) + { + std::cout << command << std::endl; + } + + // Run the command and wait for it to exit. + cmsysProcess_Execute(cp); + cmsysProcess_WaitForExit(cp, 0); + + // Report failure if any. + switch(cmsysProcess_GetState(cp)) + { + case cmsysProcess_State_Exited: + { + int value = cmsysProcess_GetExitValue(cp); + if(value != 0) + { + result = value; + } + } + break; + case cmsysProcess_State_Exception: + std::cerr << "Error running link command: " + << cmsysProcess_GetExceptionString(cp) << std::endl; + result = 1; + break; + case cmsysProcess_State_Error: + std::cerr << "Error running link command: " + << cmsysProcess_GetErrorString(cp) << std::endl; + result = 2; + break; + default: + break; + }; + } + + // Free the process instance. + cmsysProcess_Delete(cp); + + // Return the final resulting return value. + return result; +} diff --git a/Source/cmake.h b/Source/cmake.h index 71a7713fec..d63cf7e3eb 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -323,6 +323,7 @@ protected: void GenerateGraphViz(const char* fileName); static int ExecuteEchoColor(std::vector& args); + static int ExecuteLinkScript(std::vector& args); cmVariableWatch* VariableWatch;