Browse Source

AUTOMOC: Automatically use options file for moc compiler

Daniel Gehriger 3 years ago
parent
commit
1c9cead051
3 changed files with 63 additions and 0 deletions
  1. 7 0
      Source/cmQtAutoGen.cxx
  2. 5 0
      Source/cmQtAutoGen.h
  3. 51 0
      Source/cmQtAutoMocUic.cxx

+ 7 - 0
Source/cmQtAutoGen.cxx

@@ -76,6 +76,13 @@ static void MergeOptions(std::vector<std::string>& baseOpts,
 
 unsigned int const cmQtAutoGen::ParallelMax = 64;
 
+#ifdef _WIN32
+// Actually 32767 (see
+// https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553) but we
+// allow for a small margin
+size_t const cmQtAutoGen::CommandLineLengthMax = 32000;
+#endif
+
 cm::string_view cmQtAutoGen::GeneratorName(GenT genType)
 {
   switch (genType) {

+ 5 - 0
Source/cmQtAutoGen.h

@@ -64,6 +64,11 @@ public:
   /// @brief Maximum number of parallel threads/processes in a generator
   static unsigned int const ParallelMax;
 
+#ifdef _WIN32
+  /// @brief Maximum number of characters on command line
+  static size_t const CommandLineLengthMax;
+#endif
+
   /// @brief Returns the generator name
   static cm::string_view GeneratorName(GenT genType);
   /// @brief Returns the generator name in upper case

+ 51 - 0
Source/cmQtAutoMocUic.cxx

@@ -497,6 +497,10 @@ public:
 
   protected:
     ParseCacheT::FileHandleT CacheEntry;
+
+  private:
+    void MaybeWriteMocResponseFile(std::string const& outputFile,
+                                   std::vector<std::string>& cmd) const;
   };
 
   /** uic compiles a file.  */
@@ -2025,6 +2029,8 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
     cmd.push_back(outputFile);
     // Add source file
     cmd.push_back(sourceFile);
+
+    MaybeWriteMocResponseFile(outputFile, cmd);
   }
 
   // Execute moc command
@@ -2070,6 +2076,51 @@ void cmQtAutoMocUicT::JobCompileMocT::Process()
   }
 }
 
+/*
+ * Check if command line exceeds maximum length supported by OS
+ * (if on Windows) and switch to using a response file instead.
+ */
+void cmQtAutoMocUicT::JobCompileMocT::MaybeWriteMocResponseFile(
+  std::string const& outputFile, std::vector<std::string>& cmd) const
+{
+#ifdef _WIN32
+  // Ensure cmd is less than CommandLineLengthMax characters
+  size_t commandLineLength = cmd.size(); // account for separating spaces
+  for (std::string const& str : cmd) {
+    commandLineLength += str.length();
+  }
+  if (commandLineLength >= CommandLineLengthMax) {
+    // Command line exceeds maximum size allowed by OS
+    // => create response file
+    std::string const responseFile = cmStrCat(outputFile, ".rsp");
+
+    cmsys::ofstream fout(responseFile.c_str());
+    if (!fout) {
+      this->LogError(
+        GenT::MOC,
+        cmStrCat("AUTOMOC was unable to create a response file at\n  ",
+                 this->MessagePath(responseFile)));
+      return;
+    }
+
+    auto it = cmd.begin();
+    while (++it != cmd.end()) {
+      fout << *it << "\n";
+    }
+    fout.close();
+
+    // Keep all but executable
+    cmd.resize(1);
+
+    // Specify response file
+    cmd.push_back(cmStrCat('@', responseFile));
+  }
+#else
+  static_cast<void>(outputFile);
+  static_cast<void>(cmd);
+#endif
+}
+
 void cmQtAutoMocUicT::JobCompileUicT::Process()
 {
   std::string const& sourceFile = this->Mapping->SourceFile->FileName;