Explorar o código

Makefile: Avoid link line object list lengths nearing system limits

Use response files for object file lists that approach the scale of the
system `ARG_MAX` limit.

Fixes #16206.
Brad King %!s(int64=9) %!d(string=hai) anos
pai
achega
c7a7c655f0
Modificáronse 1 ficheiros con 39 adicións e 0 borrados
  1. 39 0
      Source/cmMakefileTargetGenerator.cxx

+ 39 - 0
Source/cmMakefileTargetGenerator.cxx

@@ -31,6 +31,10 @@
 
 #include <ctype.h>
 
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
 cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
   : cmCommonTargetGenerator(target)
   , OSXBundleGenerator(CM_NULLPTR)
@@ -1447,6 +1451,15 @@ void cmMakefileTargetGenerator::CreateLinkScript(
   makefile_depends.push_back(linkScriptName);
 }
 
+static size_t calculateCommandLineLengthLimit()
+{
+#if defined(_SC_ARG_MAX)
+  return ((size_t)sysconf(_SC_ARG_MAX)) - 1000;
+#else
+  return 0;
+#endif
+}
+
 bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
   std::string const& l) const
 {
@@ -1459,6 +1472,32 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
     }
   }
 
+  // Check for a system limit.
+  if (size_t const limit = calculateCommandLineLengthLimit()) {
+    // Compute the total length of our list of object files with room
+    // for argument separation and quoting.  This does not convert paths
+    // relative to START_OUTPUT like the final list will be, so the actual
+    // list will likely be much shorter than this.  However, in the worst
+    // case all objects will remain as absolute paths.
+    size_t length = 0;
+    for (std::vector<std::string>::const_iterator i = this->Objects.begin();
+         i != this->Objects.end(); ++i) {
+      length += i->size() + 3;
+    }
+    for (std::vector<std::string>::const_iterator i =
+           this->ExternalObjects.begin();
+         i != this->ExternalObjects.end(); ++i) {
+      length += i->size() + 3;
+    }
+
+    // We need to guarantee room for both objects and libraries, so
+    // if the objects take up more than half then use a response file
+    // for them.
+    if (length > (limit / 2)) {
+      return true;
+    }
+  }
+
   // We do not need a response file for objects.
   return false;
 }