Exclude action's dep on shared library from runtime dep propagation.

Shared library in deps of action and action_foreach was treated
as a runtime dependency, which is unwanted behaviour.

Bug: 748113
Change-Id: Ifdf103a71a8f15fdd6ba6b802a2cd5df182b3bd2
Reviewed-on: https://chromium-review.googlesource.com/584832
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Grigoriy Kraynov <kraynov@google.com>
Cr-Original-Commit-Position: refs/heads/master@{#494453}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 655a12bcfb7014f35fe14afd293bfb9066878f46
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 4402316..2d7a0c0 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -6090,6 +6090,13 @@
   itself).
 ```
 
+#### **Shared libraries**
+
+```
+  The results of shared_library targets are runtime dependencies, unless the
+  targets are depended upon only through action/action_foreach.
+```
+
 #### **Multiple outputs**
 
 ```
@@ -6235,4 +6242,3 @@
     *   [-v: Verbose logging.](#-v)
     *   [--version: Prints the GN version number and exits.](#--version)
 ```
-
diff --git a/tools/gn/runtime_deps.cc b/tools/gn/runtime_deps.cc
index 14e13e3..0545617 100644
--- a/tools/gn/runtime_deps.cc
+++ b/tools/gn/runtime_deps.cc
@@ -117,6 +117,13 @@
   for (const auto& dep_pair : target->GetDeps(Target::DEPS_LINKED)) {
     if (dep_pair.ptr->output_type() == Target::EXECUTABLE)
       continue;  // Skip executables that aren't data deps.
+    if (dep_pair.ptr->output_type() == Target::SHARED_LIBRARY &&
+        (target->output_type() == Target::ACTION ||
+         target->output_type() == Target::ACTION_FOREACH)) {
+      // Skip shared libraries that action depends on,
+      // unless it were listed in data deps.
+      continue;
+    }
     RecursiveCollectRuntimeDeps(dep_pair.ptr, false,
                                 deps, seen_targets, found_files);
   }
diff --git a/tools/gn/runtime_deps_unittest.cc b/tools/gn/runtime_deps_unittest.cc
index c242ec6..ad1fbdc 100644
--- a/tools/gn/runtime_deps_unittest.cc
+++ b/tools/gn/runtime_deps_unittest.cc
@@ -165,6 +165,46 @@
       << GetVectorDescription(result);
 }
 
+TEST(RuntimeDeps, ActionSharedLib) {
+  TestWithScope setup;
+  Err err;
+
+  // Dependency hierarchy: main(exe) -> action -> datadep(shared library)
+  //                                           -> dep(shared library)
+  // Datadep should be included, dep should not be.
+
+  Target dep(setup.settings(), Label(SourceDir("//"), "dep"), {});
+  InitTargetWithType(setup, &dep, Target::SHARED_LIBRARY);
+  ASSERT_TRUE(dep.OnResolved(&err));
+
+  Target datadep(setup.settings(), Label(SourceDir("//"), "datadep"), {});
+  InitTargetWithType(setup, &datadep, Target::SHARED_LIBRARY);
+  ASSERT_TRUE(datadep.OnResolved(&err));
+
+  Target action(setup.settings(), Label(SourceDir("//"), "action"), {});
+  InitTargetWithType(setup, &action, Target::ACTION);
+  action.private_deps().push_back(LabelTargetPair(&dep));
+  action.data_deps().push_back(LabelTargetPair(&datadep));
+  action.action_values().outputs() =
+      SubstitutionList::MakeForTest("//action.output");
+  ASSERT_TRUE(action.OnResolved(&err));
+
+  Target main(setup.settings(), Label(SourceDir("//"), "main"), {});
+  InitTargetWithType(setup, &main, Target::EXECUTABLE);
+  main.private_deps().push_back(LabelTargetPair(&action));
+  ASSERT_TRUE(main.OnResolved(&err));
+
+  std::vector<std::pair<OutputFile, const Target*>> result =
+      ComputeRuntimeDeps(&main);
+
+  // The result should have deps of main and data_dep.
+  ASSERT_EQ(2u, result.size()) << GetVectorDescription(result);
+
+  // The first one should always be the main exe.
+  EXPECT_TRUE(MakePair("./main", &main) == result[0]);
+  EXPECT_TRUE(MakePair("./libdatadep.so", &datadep) == result[1]);
+}
+
 // Tests that action and copy outputs are considered if they're data deps, but
 // not if they're regular deps. Action and copy "data" files are always
 // included.