ソースを参照

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 年 前
コミット
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;