소스 검색

ENH: Add SKIP_RULE_DEPENDS option for add_custom_command()

  - Allows make rules to be created with no dependencies.
  - Such rules will not re-run even if the commands themselves change.
  - Useful to create rules that run only if the output is missing.
Brad King 17 년 전
부모
커밋
600e5e274e

+ 18 - 3
Source/cmAddCustomCommandCommand.cxx

@@ -40,6 +40,7 @@ bool cmAddCustomCommandCommand
   std::vector<std::string> depends, outputs, output;
   bool verbatim = false;
   bool append = false;
+  bool skip_rule_depends = false;
   std::string implicit_depends_lang;
   cmCustomCommand::ImplicitDependsList implicit_depends;
 
@@ -103,6 +104,11 @@ bool cmAddCustomCommandCommand
       {
       verbatim = true;
       }
+    else if(copy == "SKIP_RULE_DEPENDS")
+      {
+      doing = doing_nothing;
+      skip_rule_depends = true;
+      }
     else if(copy == "APPEND")
       {
       append = true;
@@ -310,8 +316,8 @@ bool cmAddCustomCommandCommand
                                              working.c_str(), false,
                                              escapeOldStyle);
 
-    // Add implicit dependency scanning requests if any were given.
-    if(!implicit_depends.empty())
+    // Get the rule object to add some extra information.
+    if(!implicit_depends.empty() || skip_rule_depends)
       {
       bool okay = false;
       if(cmSourceFile* sf =
@@ -320,7 +326,16 @@ bool cmAddCustomCommandCommand
         if(cmCustomCommand* cc = sf->GetCustomCommand())
           {
           okay = true;
-          cc->SetImplicitDepends(implicit_depends);
+
+          // Add implicit dependency scanning requests if any were
+          // given.
+          if(!implicit_depends.empty())
+            {
+            cc->SetImplicitDepends(implicit_depends);
+            }
+
+          // Set the rule dependency state.
+          cc->SetSkipRuleDepends(skip_rule_depends);
           }
         }
       if(!okay)

+ 7 - 1
Source/cmAddCustomCommandCommand.h

@@ -71,7 +71,7 @@ public:
       "                     COMMAND command1 [ARGS] [args1...]\n"
       "                     [COMMAND command2 [ARGS] [args2...] ...]\n"
       "                     [MAIN_DEPENDENCY depend]\n"
-      "                     [DEPENDS [depends...]]\n"
+      "                     [DEPENDS [depends...]] [SKIP_RULE_DEPENDS]\n"
       "                     [IMPLICIT_DEPENDS <lang1> depend1 ...]\n"
       "                     [WORKING_DIRECTORY dir]\n"
       "                     [COMMENT comment] [VERBATIM] [APPEND])\n"
@@ -134,6 +134,12 @@ public:
       "created as a file on disk it should be marked as SYMBOLIC with "
       "SET_SOURCE_FILES_PROPERTIES.\n"
 
+      "The SKIP_RULE_DEPENDS option prevents the custom build rule from "
+      "having a dependency on itself.  This prevents the rule from running "
+      "again just because the command changed but is useful to create "
+      "rules that have absolutely no dependencies.  Such rules run only "
+      "when the output file is missing.\n"
+
       "The IMPLICIT_DEPENDS option requests scanning of implicit "
       "dependencies of an input file.  The language given specifies the "
       "programming language whose corresponding dependency scanner should "

+ 15 - 3
Source/cmCustomCommand.cxx

@@ -22,6 +22,7 @@ cmCustomCommand::cmCustomCommand()
   this->HaveComment = false;
   this->EscapeOldStyle = true;
   this->EscapeAllowMakeVars = false;
+  this->SkipRuleDepends = false;
 }
 
 //----------------------------------------------------------------------------
@@ -50,10 +51,9 @@ cmCustomCommand::cmCustomCommand(const std::vector<std::string>& outputs,
   Comment(comment?comment:""),
   WorkingDirectory(workingDirectory?workingDirectory:""),
   EscapeAllowMakeVars(false),
-  EscapeOldStyle(true)
+  EscapeOldStyle(true),
+  SkipRuleDepends(false)
 {
-  this->EscapeOldStyle = true;
-  this->EscapeAllowMakeVars = false;
 }
 
 //----------------------------------------------------------------------------
@@ -135,6 +135,18 @@ void cmCustomCommand::SetEscapeAllowMakeVars(bool b)
   this->EscapeAllowMakeVars = b;
 }
 
+//----------------------------------------------------------------------------
+bool cmCustomCommand::GetSkipRuleDepends() const
+{
+  return this->SkipRuleDepends;
+}
+
+//----------------------------------------------------------------------------
+void cmCustomCommand::SetSkipRuleDepends(bool b)
+{
+  this->SkipRuleDepends = b;
+}
+
 //----------------------------------------------------------------------------
 cmCustomCommand::ImplicitDependsList const&
 cmCustomCommand::GetImplicitDepends() const

+ 5 - 0
Source/cmCustomCommand.h

@@ -68,6 +68,10 @@ public:
   bool GetEscapeAllowMakeVars() const;
   void SetEscapeAllowMakeVars(bool b);
 
+  /** Set/Get whether to skip the dependency on the rule itself.  */
+  bool GetSkipRuleDepends() const;
+  void SetSkipRuleDepends(bool b);
+
   typedef std::pair<cmStdString, cmStdString> ImplicitDependsPair;
   class ImplicitDependsList: public std::vector<ImplicitDependsPair> {};
   void SetImplicitDepends(ImplicitDependsList const&);
@@ -83,6 +87,7 @@ private:
   std::string WorkingDirectory;
   bool EscapeAllowMakeVars;
   bool EscapeOldStyle;
+  bool SkipRuleDepends;
   ImplicitDependsList ImplicitDepends;
 };
 

+ 5 - 2
Source/cmMakefileTargetGenerator.cxx

@@ -1122,8 +1122,11 @@ void cmMakefileTargetGenerator
   this->LocalGenerator->AppendCustomDepend(depends, cc);
 
   // Add a dependency on the rule file itself.
-  this->LocalGenerator->AppendRuleDepend(depends,
-                                         this->BuildFileNameFull.c_str());
+  if(!cc.GetSkipRuleDepends())
+    {
+    this->LocalGenerator->AppendRuleDepend(depends,
+                                           this->BuildFileNameFull.c_str());
+    }
 
   // Check whether we need to bother checking for a symbolic output.
   bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();

+ 8 - 0
Tests/CustomCommand/CMakeLists.txt

@@ -151,6 +151,14 @@ ADD_EXECUTABLE(CustomCommand
   ${PROJECT_BINARY_DIR}/generated.c
   ${PROJECT_BINARY_DIR}/not_included.h
   gen_redirect.c # default location for custom commands is in build tree
+  gen_once.c
+  )
+
+# Add a rule with no dependencies.
+ADD_CUSTOM_COMMAND(
+  OUTPUT gen_once.c
+  COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/gen_once.c.in ${PROJECT_BINARY_DIR}/gen_once.c
+  SKIP_RULE_DEPENDS
   )
 
 # Add the rule to create generated.c at build time.  This is placed

+ 2 - 1
Tests/CustomCommand/foo.in

@@ -6,10 +6,11 @@
 
 int generated();
 int wrapped();
+int gen_once(void);
 
 int main ()
 {
-  if (generated()*wrapped()*doc() == 3*5*7)
+  if (generated()*wrapped()*doc()*gen_once() == 3*5*7*11)
     {
     FILE* fin = fopen(PROJECT_BINARY_DIR "/not_included.h", "r");
     if(fin)

+ 1 - 0
Tests/CustomCommand/gen_once.c.in

@@ -0,0 +1 @@
+int gen_once(void) { return 11; }