Bläddra i källkod

ENH: Added generation of link rules into script files executed by a cmake -E command in order to support longer link lines. This is needed only on platforms without response file support and that may have weak shells.

Brad King 19 år sedan
förälder
incheckning
0bbcb49f65

+ 1 - 0
Source/cmGlobalBorlandMakefileGenerator.cxx

@@ -25,6 +25,7 @@ cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator()
   this->FindMakeProgramFile = "CMakeBorlandFindMake.cmake";
   this->ForceUnixPaths = false;
   this->ToolSupportsColor = true;
+  this->UseLinkScript = false;
 }
 
 

+ 3 - 0
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()

+ 4 - 0
Source/cmGlobalGenerator.h

@@ -152,6 +152,9 @@ public:
   std::string ConvertToRelativePath(const std::vector<std::string>& 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<std::string> depends, bool depends_on_all = false);
 
+  bool UseLinkScript;
   bool ForceUnixPaths;
   bool ToolSupportsColor;
   cmStdString FindMakeProgramFile;

+ 1 - 0
Source/cmGlobalMSYSMakefileGenerator.cxx

@@ -24,6 +24,7 @@ cmGlobalMSYSMakefileGenerator::cmGlobalMSYSMakefileGenerator()
   this->FindMakeProgramFile = "CMakeMSYSFindMake.cmake";
   this->ForceUnixPaths = true;
   this->ToolSupportsColor = true;
+  this->UseLinkScript = false;
 }
 
 std::string 

+ 1 - 0
Source/cmGlobalMinGWMakefileGenerator.cxx

@@ -23,6 +23,7 @@ cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator()
   this->FindMakeProgramFile = "CMakeMinGWFindMake.cmake";
   this->ForceUnixPaths = true;
   this->ToolSupportsColor = true;
+  this->UseLinkScript = true;
 }
 
 void cmGlobalMinGWMakefileGenerator

+ 1 - 0
Source/cmGlobalNMakeMakefileGenerator.cxx

@@ -23,6 +23,7 @@ cmGlobalNMakeMakefileGenerator::cmGlobalNMakeMakefileGenerator()
   this->FindMakeProgramFile = "CMakeNMakeFindMake.cmake";
   this->ForceUnixPaths = false;
   this->ToolSupportsColor = true;
+  this->UseLinkScript = false;
 }
 
 void cmGlobalNMakeMakefileGenerator

+ 1 - 0
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -31,6 +31,7 @@ cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3()
   this->ToolSupportsColor = true;
   this->NumberOfSourceFiles = 0;
   this->NumberOfSourceFilesWritten = 0;
+  this->UseLinkScript = true;
 }
 
 void cmGlobalUnixMakefileGenerator3

+ 73 - 9
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -24,6 +24,8 @@
 #include "cmTarget.h"
 #include "cmake.h"
 
+#include <memory> // 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<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;
+    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.
   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<std::string>::iterator i = commands.begin();
-      i != commands.end(); ++i)
+  if(useLinkScript)
+    {
+    for(std::vector<std::string>::iterator i = link_script_commands.begin();
+        i != link_script_commands.end(); ++i)
+      {
+      this->LocalGenerator->ExpandRuleVariables(*i, vars);
+      }
+    }
+  else
     {
-    this->LocalGenerator->ExpandRuleVariables(*i, vars);
+    for(std::vector<std::string>::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<std::string>::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(),

+ 50 - 0
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<std::string>::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<std::string>::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)

+ 1 - 0
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);

+ 105 - 0
Source/cmake.cxx

@@ -32,6 +32,7 @@
 #endif
 
 # include <cmsys/Directory.hxx>
+#include <cmsys/Process.h>
 
 // only build kdevelop generator on non-windows platforms
 // when not bootstrapping cmake
@@ -1178,6 +1179,12 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& 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<std::string>&)
   return 1;
 }
 #endif
+
+//----------------------------------------------------------------------------
+int cmake::ExecuteLinkScript(std::vector<std::string>& args)
+{
+  // The arguments are
+  //   argv[0] == <cmake-executable>
+  //   argv[1] == cmake_link_script
+  //   argv[2] == <link-script-name>
+  //   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;
+}

+ 1 - 0
Source/cmake.h

@@ -323,6 +323,7 @@ protected:
   void GenerateGraphViz(const char* fileName);
 
   static int ExecuteEchoColor(std::vector<std::string>& args);
+  static int ExecuteLinkScript(std::vector<std::string>& args);
   
   cmVariableWatch* VariableWatch;