Selaa lähdekoodia

ENH: Add a depends check step to custom targets. Add support for the IMPLICIT_DEPENDS feature of custom commands when building in custom targets. Convert multiple-output pair checks to be per-target instead of global.

Brad King 18 vuotta sitten
vanhempi
sitoutus
d83b4cd255

+ 0 - 7
Source/cmGlobalGenerator.cxx

@@ -1680,13 +1680,6 @@ void cmGlobalGenerator::AppendDirectoryForConfig(const char*, const char*,
   // configuration.
 }
 
-//----------------------------------------------------------------------------
-void cmGlobalGenerator::CheckMultipleOutputs(cmMakefile*, bool)
-{
-  // Only certain generators need this check.  They define this
-  // method.
-}
-
 //----------------------------------------------------------------------------
 std::vector<cmTarget *>& cmGlobalGenerator
 ::GetTargetDepends(cmTarget& target)

+ 0 - 3
Source/cmGlobalGenerator.h

@@ -211,9 +211,6 @@ public:
 
   void AddTarget(cmTargets::value_type &v);
 
-  /** Support for multiple custom command outputs.  */
-  virtual void CheckMultipleOutputs(cmMakefile* mf, bool verbose);
-
   virtual const char* GetAllTargetName()          { return "ALL_BUILD"; }
   virtual const char* GetInstallTargetName()      { return "INSTALL"; }
   virtual const char* GetInstallLocalTargetName() { return 0; }

+ 9 - 78
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -132,16 +132,6 @@ void cmGlobalUnixMakefileGenerator3
     "default make target.  A \"make install\" target is also provided.";
 }
 
-//----------------------------------------------------------------------------
-void
-cmGlobalUnixMakefileGenerator3
-::AddMultipleOutputPair(const char* depender, const char* dependee)
-{
-  MultipleOutputPairsType::value_type p(depender, dependee);
-  this->MultipleOutputPairs.insert(p);
-}
-
-
 //----------------------------------------------------------------------------
 void cmGlobalUnixMakefileGenerator3::Generate() 
 {
@@ -373,62 +363,6 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
 
   this->WriteMainCMakefileLanguageRules(cmakefileStream, 
                                         this->LocalGenerators);
-
-  if(!this->MultipleOutputPairs.empty())
-    {
-    cmakefileStream
-      << "\n"
-      << "SET(CMAKE_MULTIPLE_OUTPUT_PAIRS\n";
-    for(MultipleOutputPairsType::const_iterator pi =
-          this->MultipleOutputPairs.begin();
-        pi != this->MultipleOutputPairs.end(); ++pi)
-      {
-      cmakefileStream << "  \"" << pi->first << "\" \""
-                      << pi->second << "\"\n";
-      }
-    cmakefileStream << "  )\n\n";
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmGlobalUnixMakefileGenerator3::CheckMultipleOutputs(cmMakefile* mf,
-                                                          bool verbose)
-{
-  // Get the string listing the multiple output pairs.
-  const char* pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
-  if(!pairs_string)
-    {
-    return;
-    }
-
-  // Convert the string to a list and preserve empty entries.
-  std::vector<std::string> pairs;
-  cmSystemTools::ExpandListArgument(pairs_string, pairs, true);
-  for(std::vector<std::string>::const_iterator i = pairs.begin();
-      i != pairs.end(); ++i)
-    {
-    const std::string& depender = *i;
-    if(++i != pairs.end())
-      {
-      const std::string& dependee = *i;
-
-      // If the depender is missing then delete the dependee to make
-      // sure both will be regenerated.
-      if(cmSystemTools::FileExists(dependee.c_str()) &&
-         !cmSystemTools::FileExists(depender.c_str()))
-        {
-        if(verbose)
-          {
-          cmOStringStream msg;
-          msg << "Deleting primary custom command output \"" << dependee
-              << "\" because another output \""
-              << depender << "\" does not exist." << std::endl;
-          cmSystemTools::Stdout(msg.str().c_str());
-          }
-        cmSystemTools::RemoveFile(dependee.c_str());
-        }
-      }
-    }
 }
 
 void cmGlobalUnixMakefileGenerator3
@@ -763,21 +697,18 @@ cmGlobalUnixMakefileGenerator3
         << localName << "\n\n";
     
       commands.clear();        
-      if (t->second.GetType() != cmTarget::UTILITY)
+      makeTargetName = localName;
+      makeTargetName += "/depend";
+      commands.push_back(lg->GetRecursiveMakeCall
+                         (makefileName.c_str(),makeTargetName.c_str()));
+
+      // add requires if we need it for this generator
+      if (needRequiresStep)
         {
         makeTargetName = localName;
-        makeTargetName += "/depend";
+        makeTargetName += "/requires";
         commands.push_back(lg->GetRecursiveMakeCall
-                            (makefileName.c_str(),makeTargetName.c_str()));
-        
-        // add requires if we need it for this generator
-        if (needRequiresStep)
-          {
-          makeTargetName = localName;
-          makeTargetName += "/requires";
-          commands.push_back(lg->GetRecursiveMakeCall
-                              (makefileName.c_str(),makeTargetName.c_str()));
-          }
+                           (makefileName.c_str(),makeTargetName.c_str()));
         }
       makeTargetName = localName;
       makeTargetName += "/build";

+ 0 - 16
Source/cmGlobalUnixMakefileGenerator3.h

@@ -98,19 +98,6 @@ public:
   void WriteConvenienceRules(std::ostream& ruleFileStream, 
                              std::set<cmStdString> &emitted);
 
-  /** In order to support parallel builds for custom commands with
-      multiple outputs the outputs are given a serial order, and only
-      the first output actually has the build rule.  Other outputs
-      just depend on the first one.  The check-build-system step must
-      remove a dependee if the depender is missing to make sure both
-      are regenerated properly.  This method is used by the local
-      makefile generators to register such pairs.  */
-  void AddMultipleOutputPair(const char* depender, const char* dependee);
-
-  /** Support for multiple custom command outputs.  Called during
-      check-build-system step.  */
-  virtual void CheckMultipleOutputs(cmMakefile* mf, bool verbose);
-
   /** Get the command to use for a target that has no rule.  This is
       used for multiple output dependencies and for cmake_force.  */
   std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; }
@@ -191,9 +178,6 @@ protected:
   // in the rule to satisfy the make program.
   std::string EmptyRuleHackCommand;
 
-  typedef std::map<cmStdString, cmStdString> MultipleOutputPairsType;
-  MultipleOutputPairsType MultipleOutputPairs;
-
   std::map<cmStdString, int > TargetSourceFileCount;
   bool ForceVerboseMakefiles;
 };

+ 57 - 13
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -1229,6 +1229,16 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(const char* tgtInfo,
                                                        bool verbose,
                                                        bool color)
 {
+  // read in the target info file
+  if(!this->Makefile->ReadListFile(0, tgtInfo) ||
+     cmSystemTools::GetErrorOccuredFlag())
+    {
+    cmSystemTools::Error("Target DependInfo.cmake file not found");
+    }
+
+  // Check if any multiple output pairs have a missing file.
+  this->CheckMultipleOutputs(verbose);
+
   std::string dir = cmSystemTools::GetFilenamePath(tgtInfo);
   std::string internalDependFile = dir + "/depend.internal";
   std::string dependFile = dir + "/depend.make";
@@ -1257,7 +1267,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(const char* tgtInfo,
     fprintf(stdout, "%s\n", message.c_str());
 #endif
 
-    return this->ScanDependencies(tgtInfo);
+    return this->ScanDependencies(dir.c_str());
     }
   else
     {
@@ -1267,11 +1277,10 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(const char* tgtInfo,
 }
 
 //----------------------------------------------------------------------------
-bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
+bool
+cmLocalUnixMakefileGenerator3
+::ScanDependencies(const char* targetDir)
 {
-  // The info file for this target
-  std::string infoFile = tgtInfo;
-
   // Read the directory information file.
   cmMakefile* mf = this->Makefile;
   bool haveDirectoryInfo = false;
@@ -1284,13 +1293,6 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
     haveDirectoryInfo = true;
     }
   
-  // read in the target info file
-  if(!mf->ReadListFile(0, infoFile.c_str()) ||
-     cmSystemTools::GetErrorOccuredFlag())
-    {
-    cmSystemTools::Error("Target DependInfo.cmake file not found");    
-    }
-
   // Lookup useful directory information.
   if(haveDirectoryInfo)
     {
@@ -1322,7 +1324,7 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
     }
 
   // create the file stream for the depends file
-  std::string dir = cmSystemTools::GetFilenamePath(infoFile);
+  std::string dir = targetDir;
   
   // Open the rule file.  This should be copy-if-different because the
   // rules may depend on this file itself.
@@ -1449,6 +1451,48 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(const char* tgtInfo)
   return true;
 }
 
+//----------------------------------------------------------------------------
+void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
+{
+  cmMakefile* mf = this->Makefile;
+
+  // Get the string listing the multiple output pairs.
+  const char* pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
+  if(!pairs_string)
+    {
+    return;
+    }
+
+  // Convert the string to a list and preserve empty entries.
+  std::vector<std::string> pairs;
+  cmSystemTools::ExpandListArgument(pairs_string, pairs, true);
+  for(std::vector<std::string>::const_iterator i = pairs.begin();
+      i != pairs.end(); ++i)
+    {
+    const std::string& depender = *i;
+    if(++i != pairs.end())
+      {
+      const std::string& dependee = *i;
+
+      // If the depender is missing then delete the dependee to make
+      // sure both will be regenerated.
+      if(cmSystemTools::FileExists(dependee.c_str()) &&
+         !cmSystemTools::FileExists(depender.c_str()))
+        {
+        if(verbose)
+          {
+          cmOStringStream msg;
+          msg << "Deleting primary custom command output \"" << dependee
+              << "\" because another output \""
+              << depender << "\" does not exist." << std::endl;
+          cmSystemTools::Stdout(msg.str().c_str());
+          }
+        cmSystemTools::RemoveFile(dependee.c_str());
+        }
+      }
+    }
+}
+
 //----------------------------------------------------------------------------
 void cmLocalUnixMakefileGenerator3
 ::WriteLocalAllRules(std::ostream& ruleFileStream)

+ 4 - 3
Source/cmLocalUnixMakefileGenerator3.h

@@ -203,9 +203,6 @@ public:
   virtual bool UpdateDependencies(const char* tgtInfo,
                                   bool verbose, bool color);
 
-  /** Called from command-line hook to scan dependencies.  */
-  bool ScanDependencies(const char* tgtInfo);
-
   /** Called from command-line hook to clear dependencies.  */
   virtual void ClearDependencies(cmMakefile* mf, bool verbose);
   
@@ -325,6 +322,10 @@ protected:
 
   std::map<cmStdString, std::vector<int> > ProgressFiles;
 
+  // Helper methods for dependeny updates.
+  bool ScanDependencies(const char* targetDir);
+  void CheckMultipleOutputs(bool verbose);
+
 private:
   friend class cmMakefileTargetGenerator;
   friend class cmMakefileExecutableTargetGenerator;

+ 4 - 3
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -45,9 +45,6 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
   // write the per-target per-language flags
   this->WriteTargetLanguageFlags();
 
-  // Write the dependency generation rule.
-  this->WriteTargetDependRules();
-
   // write the link rules
   this->WriteExecutableRule(false);
   if(this->Target->NeedRelinkBeforeInstall())
@@ -62,6 +59,10 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
   // Write clean target
   this->WriteTargetCleanRules();
 
+  // Write the dependency generation rule.  This must be done last so
+  // that multiple output pair information is available.
+  this->WriteTargetDependRules();
+
   // close the streams
   this->CloseFileStreams();
 }

+ 4 - 3
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -47,9 +47,6 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
   // write the per-target per-language flags
   this->WriteTargetLanguageFlags();
 
-  // Write the dependency generation rule.
-  this->WriteTargetDependRules();
-
   // write the link rules
   // Write the rule for this target type.
   switch(this->Target->GetType())
@@ -85,6 +82,10 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
   // Write clean target
   this->WriteTargetCleanRules();
 
+  // Write the dependency generation rule.  This must be done last so
+  // that multiple output pair information is available.
+  this->WriteTargetDependRules();
+
   // close the streams
   this->CloseFileStreams();
 }

+ 27 - 1
Source/cmMakefileTargetGenerator.cxx

@@ -775,6 +775,23 @@ 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 << "  \"" << pi->first << "\" \""
+                            << pi->second << "\"\n";
+      }
+    *this->InfoFileStream << "  )\n\n";
+    }
+
   // and now write the rule to use it
   std::vector<std::string> depends;
   std::vector<std::string> commands;
@@ -993,7 +1010,7 @@ cmMakefileTargetGenerator
   // the check-build-system step will remove the primary output if any
   // extra outputs are missing.  This forces the rule to regenerate
   // all outputs.
-  this->GlobalGenerator->AddMultipleOutputPair(out, in);
+  this->AddMultipleOutputPair(out, in);
 }
 
 //----------------------------------------------------------------------------
@@ -1334,3 +1351,12 @@ void cmMakefileTargetGenerator::WriteProgressVariables(unsigned long total,
   current += this->NumberOfProgressActions;
   delete progressFileStream;
 }
+
+//----------------------------------------------------------------------------
+void
+cmMakefileTargetGenerator
+::AddMultipleOutputPair(const char* depender, const char* dependee)
+{
+  MultipleOutputPairsType::value_type p(depender, dependee);
+  this->MultipleOutputPairs.insert(p);
+}

+ 11 - 0
Source/cmMakefileTargetGenerator.h

@@ -119,6 +119,15 @@ protected:
   // append intertarget dependencies
   void AppendTargetDepends(std::vector<std::string>& depends);
 
+  /** In order to support parallel builds for custom commands with
+      multiple outputs the outputs are given a serial order, and only
+      the first output actually has the build rule.  Other outputs
+      just depend on the first one.  The check-build-system step must
+      remove a dependee if the depender is missing to make sure both
+      are regenerated properly.  This method is used by the local
+      makefile generators to register such pairs.  */
+  void AddMultipleOutputPair(const char* depender, const char* dependee);
+
   virtual void CloseFileStreams();
   void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
                             std::string& linkFlags);
@@ -166,6 +175,8 @@ protected:
   // Set of object file names that will be built in this directory.
   std::set<cmStdString> ObjectFiles;
 
+  typedef std::map<cmStdString, cmStdString> MultipleOutputPairsType;
+  MultipleOutputPairsType MultipleOutputPairs;
 
   //==================================================================
   // Convenience routines that do nothing more than forward to

+ 4 - 0
Source/cmMakefileUtilityTargetGenerator.cxx

@@ -89,6 +89,10 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
   // Write clean target
   this->WriteTargetCleanRules();
 
+  // Write the dependency generation rule.  This must be done last so
+  // that multiple output pair information is available.
+  this->WriteTargetDependRules();
+
   // close the streams
   this->CloseFileStreams();
 }

+ 13 - 18
Source/cmake.cxx

@@ -2547,29 +2547,24 @@ int cmake::CheckBuildSystem()
     return 1;
     }
 
-  // Now that we know the generator used to build the project, use it
-  // to check the dependency integrity.
-  const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
-  if (!genName || genName[0] == '\0')
+  if(this->ClearBuildSystem)
     {
-    genName = "Unix Makefiles";
-    }
-  // this global generator is never set to the cmake object so it is never
-  // deleted, so make it an auto_ptr
-  std::auto_ptr<cmGlobalGenerator> ggd(this->CreateGlobalGenerator(genName));
-  if (ggd.get())
-    {
-    // Check the dependencies in case source files were removed.
-    std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
-    lgd->SetGlobalGenerator(ggd.get());
+    // Get the generator used for this build system.
+    const char* genName = mf->GetDefinition("CMAKE_DEPENDS_GENERATOR");
+    if(!genName || genName[0] == '\0')
+      {
+      genName = "Unix Makefiles";
+      }
 
-    if(this->ClearBuildSystem)
+    // Create the generator and use it to clear the dependencies.
+    std::auto_ptr<cmGlobalGenerator>
+      ggd(this->CreateGlobalGenerator(genName));
+    if(ggd.get())
       {
+      std::auto_ptr<cmLocalGenerator> lgd(ggd->CreateLocalGenerator());
+      lgd->SetGlobalGenerator(ggd.get());
       lgd->ClearDependencies(mf, verbose);
       }
-
-    // Check for multiple output pairs.
-    ggd->CheckMultipleOutputs(mf, verbose);
     }
 
   // Get the set of dependencies and outputs.

+ 10 - 6
Tests/BuildDepends/CMakeLists.txt

@@ -13,6 +13,8 @@ write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx
 
 file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot.hxx.in
   "static const char* zot = \"zot\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_custom.hxx.in
+  "static const char* zot_custom = \"zot_custom\";\n")
 
 message("Building project first time")
 try_compile(RESULT 
@@ -70,11 +72,11 @@ execute_process(COMMAND ${zot} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
 string(REGEX REPLACE "[\r\n]" " " out "${out}")
 message("Run result: ${runResult} Output: \"${out}\"")
 
-if("${out}" STREQUAL "zot ")
+if("${out}" STREQUAL "[zot] [zot_custom] ")
   message("Worked!")
-else("${out}" STREQUAL "zot ")
+else("${out}" STREQUAL "[zot] [zot_custom] ")
   message(SEND_ERROR "Project did not initially build properly: ${out}")
-endif("${out}" STREQUAL "zot ")
+endif("${out}" STREQUAL "[zot] [zot_custom] ")
 
 message("Waiting 3 seconds...")
 # any additional argument will cause ${bar} to wait forever
@@ -85,6 +87,8 @@ write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx
   "const char* foo() { return \"foo changed\";}" )
 file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot.hxx.in
   "static const char* zot = \"zot changed\";\n")
+file(WRITE ${BuildDepends_BINARY_DIR}/Project/zot_custom.hxx.in
+  "static const char* zot_custom = \"zot_custom changed\";\n")
 
 message("Building project second time")
 try_compile(RESULT 
@@ -137,8 +141,8 @@ execute_process(COMMAND ${zot} OUTPUT_VARIABLE out RESULT_VARIABLE runResult)
 string(REGEX REPLACE "[\r\n]" " " out "${out}")
 message("Run result: ${runResult} Output: \"${out}\"")
 
-if("${out}" STREQUAL "zot changed ")
+if("${out}" STREQUAL "[zot changed] [zot_custom changed] ")
   message("Worked!")
-else("${out}" STREQUAL "zot changed ")
+else("${out}" STREQUAL "[zot changed] [zot_custom changed] ")
   message(SEND_ERROR "Project did not rebuild properly!")
-endif("${out}" STREQUAL "zot changed ")
+endif("${out}" STREQUAL "[zot changed] [zot_custom changed] ")

+ 14 - 0
Tests/BuildDepends/Project/CMakeLists.txt

@@ -32,9 +32,12 @@ add_executable(bar bar.cxx
 IF("${CMAKE_GENERATOR}" MATCHES "Make")
   # Test the IMPLICIT_DEPENDS feature.
   SET(ZOT_DEPENDS IMPLICIT_DEPENDS CXX ${CMAKE_CURRENT_SOURCE_DIR}/dep.cxx)
+  SET(ZOT_CUSTOM_DEP
+    IMPLICIT_DEPENDS CXX ${CMAKE_CURRENT_SOURCE_DIR}/dep_custom.cxx)
 ELSE("${CMAKE_GENERATOR}" MATCHES "Make")
   # No IMPLICIT_DEPENDS...just depend directly.
   SET(ZOT_DEPENDS DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx.in)
+  SET(ZOT_CUSTOM_DEP DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx.in)
 ENDIF("${CMAKE_GENERATOR}" MATCHES "Make")
 add_custom_command(
   OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx
@@ -44,4 +47,15 @@ add_custom_command(
   ${ZOT_DEPENDS}
   )
 
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx
+  COMMAND ${CMAKE_COMMAND} -E copy
+  ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx.in
+  ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx
+  ${ZOT_CUSTOM_DEP}
+  )
+add_custom_target(zot_custom ALL DEPENDS
+  ${CMAKE_CURRENT_BINARY_DIR}/zot_custom.hxx)
+
 add_executable(zot zot.cxx ${CMAKE_CURRENT_BINARY_DIR}/zot.hxx)
+add_dependencies(zot zot_custom)

+ 1 - 0
Tests/BuildDepends/Project/dep_custom.cxx

@@ -0,0 +1 @@
+#include <zot_custom.hxx.in>

+ 2 - 1
Tests/BuildDepends/Project/zot.cxx

@@ -1,9 +1,10 @@
 #include <zot.hxx>
+#include <zot_custom.hxx>
 #include <stdio.h>
 
 int main()
 {
-  printf("%s\n", zot);
+  printf("[%s] [%s]\n", zot, zot_custom);
   fflush(stdout);
   return 0;
 }