Browse Source

BUG: Target names in the COMMAND part of a custom command should not create a file-level dependency that forces the command to rerun when the executable target rebuilds, but the target-level dependency should still be created. Target names in a DEPENDS should do both a target-level and file-level dependency. Updated the BuildDepends test to check that this works.

Brad King 18 years ago
parent
commit
c288da754a

+ 17 - 1
Source/cmAddCustomCommandCommand.h

@@ -124,7 +124,23 @@ public:
       "it is an option is to preserve compatibility with older CMake code.\n"
       "it is an option is to preserve compatibility with older CMake code.\n"
       "If the output of the custom command is not actually "
       "If the output of the custom command is not actually "
       "created as a file on disk it should be marked as SYMBOLIC with "
       "created as a file on disk it should be marked as SYMBOLIC with "
-      "SET_SOURCE_FILES_PROPERTIES.";
+      "SET_SOURCE_FILES_PROPERTIES.\n"
+
+      "If COMMAND specifies an executable target (created by "
+      "ADD_EXECUTABLE) it will automatically be replaced by the location "
+      "of the executable created at build time.  Additionally a "
+      "target-level dependency will be added so that the executable target "
+      "will be built before any target using this custom command.  However "
+      "this does NOT add a file-level dependency that would cause the "
+      "custom command to re-run whenever the executable is recompiled.\n"
+
+      "If DEPENDS specifies any target (created by an ADD_* command) "
+      "a target-level dependency is created to make sure the target is "
+      "built before any target using this custom command.  Additionally, "
+      "if the target is an executable or library a file-level dependency "
+      "is created to cause the custom command to re-run whenever the target "
+      "is recompiled.\n"
+      ;
     }
     }
   
   
   cmTypeMacro(cmAddCustomCommandCommand, cmCommand);
   cmTypeMacro(cmAddCustomCommandCommand, cmCommand);

+ 32 - 38
Source/cmTarget.cxx

@@ -409,7 +409,29 @@ void cmTarget::SetMakefile(cmMakefile* mf)
 }
 }
 
 
 
 
-void 
+void cmTarget::CheckForTargetsAsCommand(const cmCustomCommand& cc)
+{
+  for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
+      cit != cc.GetCommandLines().end(); ++cit )
+    {
+    std::string const& command = *cit->begin();
+    // Look for a non-imported target with this name.
+    if(cmTarget* t = this->Makefile->GetLocalGenerator()->
+       GetGlobalGenerator()->FindTarget(0, command.c_str(), false))
+      {
+      if(t->GetType() == cmTarget::EXECUTABLE)
+        {
+        // The command refers to an executable target built in
+        // this project.  Add the target-level dependency to make
+        // sure the executable is up to date before this custom
+        // command possibly runs.
+        this->AddUtility(command.c_str());
+        }
+      }
+    }
+}
+
+void
 cmTarget
 cmTarget
 ::CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands)
 ::CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands)
 {
 {
@@ -417,20 +439,7 @@ cmTarget
         cli != commands.end();
         cli != commands.end();
         ++cli )
         ++cli )
     {
     {
-    for(cmCustomCommandLines::const_iterator cit = 
-          cli->GetCommandLines().begin();
-        cit!=cli->GetCommandLines().end();
-        ++cit )
-      {
-      std::string command = *cit->begin();
-      // see if we can find a target with this name
-      cmTarget* t = this->Makefile->GetLocalGenerator()->
-                    GetGlobalGenerator()->FindTarget(0, command.c_str(), false);
-      if ( ( t ) && ( t->GetType() ==cmTarget::EXECUTABLE ) )
-        {
-        this->AddUtility ( command.c_str() );
-        }
-      }
+    this->CheckForTargetsAsCommand(*cli);
     }
     }
 }
 }
 
 
@@ -566,24 +575,8 @@ void cmTarget::TraceVSDependencies(std::string projFile,
           }
           }
         }
         }
 
 
-      // check if commands for this custom commands are names of targets and
-      // if that's the case add these targets as dependencies
-      std::vector<std::string> automaticTargetDepends;
-      for(cmCustomCommandLines::const_iterator it=
-          outsf->GetCustomCommand()->GetCommandLines().begin();
-          it!=outsf->GetCustomCommand()->GetCommandLines().end();
-          ++it)
-        {
-        const std::string& currentCommand = (*it)[0];
-        // see if we can find a target with this name
-        cmTarget* t =  this->Makefile->GetLocalGenerator()->
-            GetGlobalGenerator()->FindTarget(0, currentCommand.c_str(), false);
-        if (( t) && (t->GetType()==cmTarget::EXECUTABLE))
-          {
-          automaticTargetDepends.push_back(currentCommand);
-          }
-        }
-        outsf->GetCustomCommand()->AppendDepends(automaticTargetDepends);
+      // Add target-level dependencies for the commands.
+      this->CheckForTargetsAsCommand(*outsf->GetCustomCommand());
 
 
       // add its dependencies to the list to check
       // add its dependencies to the list to check
       for (unsigned int i = 0; 
       for (unsigned int i = 0; 
@@ -598,10 +591,9 @@ void cmTarget::TraceVSDependencies(std::string projFile,
           dep = cmSystemTools::GetFilenameWithoutLastExtension(dep);
           dep = cmSystemTools::GetFilenameWithoutLastExtension(dep);
           }
           }
         bool isUtility = false;
         bool isUtility = false;
-        // see if we can find a target with this name
-        cmTarget* t =  this->Makefile->GetLocalGenerator()->
-          GetGlobalGenerator()->FindTarget(0, dep.c_str(), false);
-        if(t)
+        // Check for a non-imported target with this name.
+        if(cmTarget* t =  this->Makefile->GetLocalGenerator()->
+           GetGlobalGenerator()->FindTarget(0, dep.c_str(), false))
           {
           {
           // if we find the target and the dep was given as a full
           // if we find the target and the dep was given as a full
           // path, then make sure it was not a full path to something
           // path, then make sure it was not a full path to something
@@ -629,7 +621,9 @@ void cmTarget::TraceVSDependencies(std::string projFile,
           }
           }
         if(isUtility)
         if(isUtility)
           {
           {
-          // add the depend as a utility on the target
+          // The dependency refers to a target built in this project.
+          // Add the target-level dependency to make sure the target
+          // is up to date before this custom command possibly runs.
           this->AddUtility(dep.c_str());
           this->AddUtility(dep.c_str());
           }
           }
         else
         else

+ 3 - 2
Source/cmTarget.h

@@ -296,9 +296,10 @@ private:
                          const LibraryID& dep);
                          const LibraryID& dep);
 
 
   /*
   /*
-   * Checks the prebuild, prelink and postbuild custom commands for known
-   * targets and adds them to the dependencies.
+   * Check custom commands for known targets and add a target-level
+   * dependency.
    */
    */
+  void CheckForTargetsAsCommand(const cmCustomCommand& cc);
   void CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands);
   void CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands);
   
   
   
   

+ 1 - 1
Tests/BuildDepends/CMakeLists.txt

@@ -60,5 +60,5 @@ message("${out}")
 if("${out}" STREQUAL "foo changed ")
 if("${out}" STREQUAL "foo changed ")
   message("Worked!")
   message("Worked!")
 else("${out}" STREQUAL "foo changed ")
 else("${out}" STREQUAL "foo changed ")
-  message(SEND_ERROR "Program did not rebuild with changed file")
+  message(SEND_ERROR "Project did not rebuild properly!")
 endif("${out}" STREQUAL "foo changed ")
 endif("${out}" STREQUAL "foo changed ")

+ 27 - 1
Tests/BuildDepends/Project/CMakeLists.txt

@@ -1,4 +1,30 @@
 project(testRebuild)
 project(testRebuild)
 add_library(foo STATIC ${testRebuild_BINARY_DIR}/foo.cxx)
 add_library(foo STATIC ${testRebuild_BINARY_DIR}/foo.cxx)
-add_executable(bar bar.cxx)
+
+# Add a generated header that regenerates when the generator is
+# rebuilt.
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/regen.h
+  COMMAND generator ${CMAKE_CURRENT_BINARY_DIR}/regen.h regen
+  DEPENDS generator # adds file-level dependency to re-run rule
+  )
+
+# Add a generated header that does NOT regenerate when the generator
+# is rebuilt.
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/noregen.h
+  COMMAND generator ${CMAKE_CURRENT_BINARY_DIR}/noregen.h noregen
+  )
+
+# Test that the generator rebuilds when the static library source file
+# changes.  This should cause regen.h to be recreated also.
+add_executable(generator generator.cxx)
+target_link_libraries(generator foo)
+
+# Build an executable to drive the build and rebuild.
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+add_executable(bar bar.cxx
+  ${CMAKE_CURRENT_BINARY_DIR}/regen.h
+  ${CMAKE_CURRENT_BINARY_DIR}/noregen.h
+  )
 target_link_libraries(bar foo)
 target_link_libraries(bar foo)

+ 13 - 4
Tests/BuildDepends/Project/bar.cxx

@@ -1,10 +1,19 @@
-#include "stdio.h"
+#include <stdio.h>
+#include <string.h>
+#include <regen.h>
+#include <noregen.h>
 
 
-const char* foo();
 int main()
 int main()
 {
 {
-  int i;
-  printf("%s\n", foo());
+  /* Make sure the noregen header was not regenerated.  */
+  if(strcmp("foo", noregen_string) != 0)
+    {
+    printf("FAILED: noregen.h was regenerated!\n");
+    return 1;
+    }
+
+  /* Print out the string that should have been regenerated.  */
+  printf("%s\n", regen_string);
   fflush(stdout);
   fflush(stdout);
   for(;;);
   for(;;);
   return 0;
   return 0;