Browse Source

Merge topic 'custom-command-multiple-outputs'

66a9c90c Makefile: Fix multiple custom command outputs regression (#15116)
Brad King 10 years ago
parent
commit
387466dd95

+ 0 - 1
Source/cmGlobalBorlandMakefileGenerator.cxx

@@ -49,7 +49,6 @@ cmLocalGenerator *cmGlobalBorlandMakefileGenerator::CreateLocalGenerator()
   lg->SetUnixCD(false);
   lg->SetMakeCommandEscapeTargetTwice(true);
   lg->SetBorlandMakeCurlyHack(true);
-  lg->SetNoMultiOutputMultiDepRules(true);
   return lg;
 }
 

+ 2 - 54
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -92,7 +92,6 @@ cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3()
   this->SkipAssemblySourceRules = false;
   this->MakeCommandEscapeTargetTwice = false;
   this->BorlandMakeCurlyHack = false;
-  this->NoMultiOutputMultiDepRules = false;
 }
 
 //----------------------------------------------------------------------------
@@ -600,7 +599,6 @@ const std::string &cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
   return this->HomeRelativeOutputPath;
 }
 
-
 //----------------------------------------------------------------------------
 void
 cmLocalUnixMakefileGenerator3
@@ -619,30 +617,6 @@ cmLocalUnixMakefileGenerator3
                          comment);
     return;
     }
-  std::vector<std::string> outputs(1, target);
-  this->WriteMakeRule(os, comment,
-                      outputs, depends, commands,
-                      symbolic, in_help);
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalUnixMakefileGenerator3
-::WriteMakeRule(std::ostream& os,
-                const char* comment,
-                const std::vector<std::string>& outputs,
-                const std::vector<std::string>& depends,
-                const std::vector<std::string>& commands,
-                bool symbolic,
-                bool in_help)
-{
-  // Make sure there is an output.
-  if(outputs.empty())
-    {
-    cmSystemTools::Error("No outputs for WriteMakeRule! called with comment: ",
-                         comment);
-    return;
-    }
 
   std::string replace;
 
@@ -661,17 +635,7 @@ cmLocalUnixMakefileGenerator3
     }
 
   // Construct the left hand side of the rule.
-  std::string tgt;
-  {
-  const char* sep = "";
-  for (std::vector<std::string>::const_iterator i = outputs.begin();
-       i != outputs.end(); ++i)
-    {
-    tgt += sep;
-    tgt += this->Convert(*i,HOME_OUTPUT,MAKERULE);
-    sep = " ";
-    }
-  }
+  std::string tgt = this->Convert(target, HOME_OUTPUT, MAKERULE);
 
   const char* space = "";
   if(tgt.size() == 1)
@@ -697,19 +661,6 @@ cmLocalUnixMakefileGenerator3
     // No dependencies.  The commands will always run.
     os << cmMakeSafe(tgt) << space << ":\n";
     }
-  else if(this->NoMultiOutputMultiDepRules && outputs.size() >= 2)
-    {
-    // Borland make does not understand multiple dependency rules when
-    // there are multiple outputs, so write them all on one line.
-    os << cmMakeSafe(tgt) << space << ":";
-    for(std::vector<std::string>::const_iterator dep = depends.begin();
-        dep != depends.end(); ++dep)
-      {
-      replace = this->Convert(*dep, HOME_OUTPUT, MAKERULE);
-      os << " " << cmMakeSafe(replace);
-      }
-    os << "\n";
-    }
   else
     {
     // Split dependencies into multiple rule lines.  This allows for
@@ -733,8 +684,7 @@ cmLocalUnixMakefileGenerator3
   // Add the output to the local help if requested.
   if(in_help)
     {
-    this->LocalHelp.insert(this->LocalHelp.end(),
-                           outputs.begin(), outputs.end());
+    this->LocalHelp.push_back(target);
     }
 }
 
@@ -1754,8 +1704,6 @@ cmLocalUnixMakefileGenerator3
 //----------------------------------------------------------------------------
 void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
 {
-  // Nothing populates multiple output pairs anymore, but we need to
-  // honor it when working in a build tree generated by an older CMake.
   cmMakefile* mf = this->Makefile;
 
   // Get the string listing the multiple output pairs.

+ 0 - 11
Source/cmLocalUnixMakefileGenerator3.h

@@ -61,13 +61,6 @@ public:
                      const std::vector<std::string>& commands,
                      bool symbolic,
                      bool in_help = false);
-  void WriteMakeRule(std::ostream& os,
-                     const char* comment,
-                     const std::vector<std::string>& outputs,
-                     const std::vector<std::string>& depends,
-                     const std::vector<std::string>& commands,
-                     bool symbolic,
-                     bool in_help = false);
 
   // write the main variables used by the makefiles
   void WriteMakeVariables(std::ostream& makefileStream);
@@ -161,9 +154,6 @@ public:
   void SetBorlandMakeCurlyHack(bool b)
     { this->BorlandMakeCurlyHack = b; }
 
-  void SetNoMultiOutputMultiDepRules(bool b)
-    { this->NoMultiOutputMultiDepRules = b; }
-
   // used in writing out Cmake files such as WriteDirectoryInformation
   static void WriteCMakeArgument(std::ostream& os, const char* s);
 
@@ -349,7 +339,6 @@ private:
   bool PassMakeflags;
   bool MakeCommandEscapeTargetTwice;
   bool BorlandMakeCurlyHack;
-  bool NoMultiOutputMultiDepRules;
   //==========================================================================
 
   std::string HomeRelativeOutputPath;

+ 2 - 3
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -769,9 +769,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
     }
 
   // Write the build rule.
-  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
-                                      outputs, depends, commands, false);
-
+  this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
+                      depends, commands, false);
 
   // Write the main driver rule to build everything in this target.
   this->WriteTargetDriverRule(targetFullPath, relink);

+ 74 - 5
Source/cmMakefileTargetGenerator.cxx

@@ -769,8 +769,8 @@ cmMakefileTargetGenerator
     }
 
   // Write the rule.
-  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
-                                      outputs, depends, commands, false);
+  this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
+                      depends, commands, false);
 
   bool do_preprocess_rules = lang_has_preprocessor &&
     this->LocalGenerator->GetCreatePreprocessedSourceRules();
@@ -991,6 +991,57 @@ void cmMakefileTargetGenerator::WriteTargetCleanRules()
                                       depends, commands, true);
 }
 
+//----------------------------------------------------------------------------
+void cmMakefileTargetGenerator::WriteMakeRule(
+  std::ostream& os,
+  const char* comment,
+  const std::vector<std::string>& outputs,
+  const std::vector<std::string>& depends,
+  const std::vector<std::string>& commands,
+  bool symbolic,
+  bool in_help)
+{
+  if (outputs.size() == 0)
+    {
+    return;
+    }
+
+  // We always attach the actual commands to the first output.
+  this->LocalGenerator->WriteMakeRule(os, comment, outputs[0], depends,
+                                      commands, symbolic, in_help);
+
+  // For single outputs, we are done.
+  if (outputs.size() == 1)
+    {
+    return;
+    }
+
+  // For multiple outputs, make the extra ones depend on the first one.
+  std::vector<std::string> const output_depends(1, outputs[0]);
+  for (std::vector<std::string>::const_iterator o = outputs.begin()+1;
+       o != outputs.end(); ++o)
+    {
+    // Touch the extra output so "make" knows that it was updated,
+    // but only if the output was acually created.
+    std::string const out = this->Convert(*o, cmLocalGenerator::HOME_OUTPUT,
+                                          cmLocalGenerator::SHELL);
+    std::vector<std::string> output_commands;
+    if (!symbolic)
+      {
+      output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
+      }
+    this->LocalGenerator->WriteMakeRule(os, 0, *o, output_depends,
+                                        output_commands, symbolic, in_help);
+
+    if (!symbolic)
+      {
+      // At build time, remove the first output if this one does not exist
+      // so that "make" will rerun the real commands that create this one.
+      MultipleOutputPairsType::value_type p(*o, outputs[0]);
+      this->MultipleOutputPairs.insert(p);
+      }
+    }
+}
 
 //----------------------------------------------------------------------------
 void cmMakefileTargetGenerator::WriteTargetDependRules()
@@ -1011,6 +1062,25 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
   this->LocalGenerator->
     WriteDependLanguageInfo(*this->InfoFileStream,*this->Target);
 
+  // Store multiple output pairs in the depend info file.
+  if(!this->MultipleOutputPairs.empty())
+    {
+    *this->InfoFileStream
+      << "\n"
+      << "# Pairs of files generated by the same build rule.\n"
+      << "set(CMAKE_MULTIPLE_OUTPUT_PAIRS\n";
+    for(MultipleOutputPairsType::const_iterator pi =
+          this->MultipleOutputPairs.begin();
+        pi != this->MultipleOutputPairs.end(); ++pi)
+      {
+      *this->InfoFileStream
+        << "  " << this->LocalGenerator->EscapeForCMake(pi->first)
+        << " "  << this->LocalGenerator->EscapeForCMake(pi->second)
+        << "\n";
+      }
+    *this->InfoFileStream << "  )\n\n";
+    }
+
   // Store list of targets linked directly or transitively.
   {
   *this->InfoFileStream
@@ -1240,9 +1310,8 @@ void cmMakefileTargetGenerator
       symbolic = sf->GetPropertyAsBool("SYMBOLIC");
       }
     }
-  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
-                                      outputs, depends, commands,
-                                      symbolic);
+  this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
+                      depends, commands, symbolic);
 
   // If the rule has changed make sure the output is rebuilt.
   if(!symbolic)

+ 10 - 0
Source/cmMakefileTargetGenerator.h

@@ -222,6 +222,16 @@ protected:
   // Set of extra output files to be driven by the build.
   std::set<std::string> ExtraFiles;
 
+  typedef std::map<std::string, std::string> MultipleOutputPairsType;
+  MultipleOutputPairsType MultipleOutputPairs;
+  void WriteMakeRule(std::ostream& os,
+                     const char* comment,
+                     const std::vector<std::string>& outputs,
+                     const std::vector<std::string>& depends,
+                     const std::vector<std::string>& commands,
+                     bool symbolic,
+                     bool in_help = false);
+
   // Target name info.
   std::string TargetNameOut;
   std::string TargetNameSO;