浏览代码

Depend: Hook up automatic target-level dependencies via byproducts

Target-level dependencies to utility targets are added from another target if
the other target requires a byproduct of the utility target or if it requires a
byproduct of PRE_BUILD, PRE_LINK, or POST_BUILD build events of a target.

Issue: #19005
Daniel Eiband 6 年之前
父节点
当前提交
f6574c9a81
共有 3 个文件被更改,包括 29 次插入18 次删除
  1. 3 3
      Help/command/add_custom_command.rst
  2. 3 3
      Help/command/add_custom_target.rst
  3. 23 12
      Source/cmGeneratorTarget.cxx

+ 3 - 3
Help/command/add_custom_command.rst

@@ -68,9 +68,6 @@ The options are:
   order-only dependencies to ensure the byproducts will be
   available before their dependents build.
 
-  The ``BYPRODUCTS`` option is ignored on non-Ninja generators
-  except to mark byproducts ``GENERATED``.
-
 ``COMMAND``
   Specify the command-line(s) to execute at build time.
   If more than one ``COMMAND`` is specified they will be executed in order,
@@ -111,6 +108,9 @@ The options are:
   an ``OUTPUT`` of another custom command in the same directory
   (``CMakeLists.txt`` file) CMake automatically brings the other
   custom command into the target in which this command is built.
+  A target-level dependency is added if any dependency is listed as
+  ``BYPRODUCTS`` of a target or any of its build events in the same
+  directory to ensure the byproducts will be available.
   If ``DEPENDS`` is not specified the command will run whenever
   the ``OUTPUT`` is missing; if the command does not actually
   create the ``OUTPUT`` then the rule will always run.

+ 3 - 3
Help/command/add_custom_target.rst

@@ -49,9 +49,6 @@ The options are:
   order-only dependencies to ensure the byproducts will be
   available before their dependents build.
 
-  The ``BYPRODUCTS`` option is ignored on non-Ninja generators
-  except to mark byproducts ``GENERATED``.
-
 ``COMMAND``
   Specify the command-line(s) to execute at build time.
   If more than one ``COMMAND`` is specified they will be executed in order,
@@ -86,6 +83,9 @@ The options are:
   :command:`add_custom_command` command calls in the same directory
   (``CMakeLists.txt`` file).  They will be brought up to date when
   the target is built.
+  A target-level dependency is added if any dependency is a byproduct
+  of a target or any of its build events in the same directory to ensure
+  the byproducts will be available before this target is built.
 
   Use the :command:`add_dependencies` command to add dependencies
   on other targets.

+ 23 - 12
Source/cmGeneratorTarget.cxx

@@ -2599,7 +2599,7 @@ private:
   SourceEntry* CurrentEntry;
   std::queue<cmSourceFile*> SourceQueue;
   std::set<cmSourceFile*> SourcesQueued;
-  using NameMapType = std::map<std::string, cmSourceFile*>;
+  using NameMapType = std::map<std::string, cmSourcesWithOutput>;
   NameMapType NameMap;
   std::vector<std::string> NewSources;
 
@@ -2705,19 +2705,30 @@ void cmTargetTraceDependencies::QueueSource(cmSourceFile* sf)
 
 void cmTargetTraceDependencies::FollowName(std::string const& name)
 {
-  auto i = this->NameMap.find(name);
-  if (i == this->NameMap.end()) {
+  // Use lower bound with key comparison to not repeat the search for the
+  // insert position if the name could not be found (which is the common case).
+  auto i = this->NameMap.lower_bound(name);
+  if (i == this->NameMap.end() || i->first != name) {
     // Check if we know how to generate this file.
-    cmSourceFile* sf = this->Makefile->GetSourceFileWithOutput(name);
-    NameMapType::value_type entry(name, sf);
-    i = this->NameMap.insert(entry).first;
-  }
-  if (cmSourceFile* sf = i->second) {
-    // Record the dependency we just followed.
-    if (this->CurrentEntry) {
-      this->CurrentEntry->Depends.push_back(sf);
+    cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
+    i = this->NameMap.emplace_hint(i, name, sources);
+  }
+  if (cmTarget* t = i->second.Target) {
+    // The name is a byproduct of a utility target or a PRE_BUILD, PRE_LINK, or
+    // POST_BUILD command.
+    this->GeneratorTarget->Target->AddUtility(t->GetName());
+  }
+  if (cmSourceFile* sf = i->second.Source) {
+    // For now only follow the dependency if the source file is not a
+    // byproduct.  Semantics of byproducts in a non-Ninja context will have to
+    // be defined first.
+    if (!i->second.SourceIsByproduct) {
+      // Record the dependency we just followed.
+      if (this->CurrentEntry) {
+        this->CurrentEntry->Depends.push_back(sf);
+      }
+      this->QueueSource(sf);
     }
-    this->QueueSource(sf);
   }
 }