Add ResolvedTargetData::GetLinkedFrameworks()

This CL removes Target::all_framework_dirs(), Target::all_frameworks()
and Target::all_weak_frameworks(), moving their computation to the
ResolvedTargetData class, where they will be created on demand, and
returned by the GetLinkedFrameworkDirs(), GetLinkedFrameworks() and
GetLinkedWeakFrameworks() methods respectively.

Bug: 331
Change-Id: Iecefbcc4182265113d5939f8a854d12c2670b8f5
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15324
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/gn/desc_builder.cc b/src/gn/desc_builder.cc
index f82c079..58bebef 100644
--- a/src/gn/desc_builder.cc
+++ b/src/gn/desc_builder.cc
@@ -608,7 +608,7 @@
     }
 
     if (what(variables::kFrameworks)) {
-      const auto& all_frameworks = target_->all_frameworks();
+      const auto& all_frameworks = resolved.GetLinkedFrameworks(target_);
       if (!all_frameworks.empty()) {
         auto frameworks = std::make_unique<base::ListValue>();
         for (size_t i = 0; i < all_frameworks.size(); i++)
@@ -618,7 +618,7 @@
       }
     }
     if (what(variables::kWeakFrameworks)) {
-      const auto& weak_frameworks = target_->all_weak_frameworks();
+      const auto& weak_frameworks = resolved.GetLinkedWeakFrameworks(target_);
       if (!weak_frameworks.empty()) {
         auto frameworks = std::make_unique<base::ListValue>();
         for (size_t i = 0; i < weak_frameworks.size(); i++)
@@ -629,7 +629,7 @@
     }
 
     if (what(variables::kFrameworkDirs)) {
-      const auto& all_framework_dirs = target_->all_framework_dirs();
+      const auto& all_framework_dirs = resolved.GetLinkedFrameworkDirs(target_);
       if (!all_framework_dirs.empty()) {
         auto framework_dirs = std::make_unique<base::ListValue>();
         for (size_t i = 0; i < all_framework_dirs.size(); i++)
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc
index d9d403f..b1dbbef 100644
--- a/src/gn/ninja_binary_target_writer.cc
+++ b/src/gn/ninja_binary_target_writer.cc
@@ -341,7 +341,7 @@
     }
   }
 
-  const auto& all_framework_dirs = target_->all_framework_dirs();
+  const auto& all_framework_dirs = resolved().GetLinkedFrameworkDirs(target_);
   if (!all_framework_dirs.empty()) {
     // Since we're passing these on the command line to the linker and not
     // to Ninja, we need to do shell escaping.
@@ -398,13 +398,13 @@
                                               const Tool* tool) {
   // Frameworks that have been recursively pushed through the dependency tree.
   FrameworksWriter writer(tool->framework_switch());
-  const auto& all_frameworks = target_->all_frameworks();
+  const auto& all_frameworks = resolved().GetLinkedFrameworks(target_);
   for (size_t i = 0; i < all_frameworks.size(); i++) {
     writer(all_frameworks[i], out);
   }
 
   FrameworksWriter weak_writer(tool->weak_framework_switch());
-  const auto& all_weak_frameworks = target_->all_weak_frameworks();
+  const auto& all_weak_frameworks = resolved().GetLinkedWeakFrameworks(target_);
   for (size_t i = 0; i < all_weak_frameworks.size(); i++) {
     weak_writer(all_weak_frameworks[i], out);
   }
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
index 722858d..3208f04 100644
--- a/src/gn/resolved_target_data.cc
+++ b/src/gn/resolved_target_data.cc
@@ -36,3 +36,29 @@
   info->libs = all_libs.release();
   info->has_lib_info = true;
 }
+
+void ResolvedTargetData::ComputeFrameworkInfo(TargetInfo* info) const {
+  UniqueVector<SourceDir> all_framework_dirs;
+  UniqueVector<std::string> all_frameworks;
+  UniqueVector<std::string> all_weak_frameworks;
+
+  for (ConfigValuesIterator iter(info->target); !iter.done(); iter.Next()) {
+    const ConfigValues& cur = iter.cur();
+    all_framework_dirs.Append(cur.framework_dirs());
+    all_frameworks.Append(cur.frameworks());
+    all_weak_frameworks.Append(cur.weak_frameworks());
+  }
+  for (const Target* dep : info->deps.linked_deps()) {
+    if (!dep->IsFinal() || dep->output_type() == Target::STATIC_LIBRARY) {
+      const TargetInfo* dep_info = GetTargetFrameworkInfo(dep);
+      all_framework_dirs.Append(dep_info->framework_dirs);
+      all_frameworks.Append(dep_info->frameworks);
+      all_weak_frameworks.Append(dep_info->weak_frameworks);
+    }
+  }
+
+  info->framework_dirs = all_framework_dirs.release();
+  info->frameworks = all_frameworks.release();
+  info->weak_frameworks = all_weak_frameworks.release();
+  info->has_framework_info = true;
+}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h
index 13d7797..754abc2 100644
--- a/src/gn/resolved_target_data.h
+++ b/src/gn/resolved_target_data.h
@@ -75,6 +75,27 @@
     return GetTargetLibInfo(target)->libs;
   }
 
+  // The list of framework directories search paths to use at link time
+  // when generating macOS or iOS linkable binaries.
+  const std::vector<SourceDir>& GetLinkedFrameworkDirs(
+      const Target* target) const {
+    return GetTargetFrameworkInfo(target)->framework_dirs;
+  }
+
+  // The list of framework names to use at link time when generating macOS
+  // or iOS linkable binaries.
+  const std::vector<std::string>& GetLinkedFrameworks(
+      const Target* target) const {
+    return GetTargetFrameworkInfo(target)->frameworks;
+  }
+
+  // The list of weak framework names to use at link time when generating macOS
+  // or iOS linkable binaries.
+  const std::vector<std::string>& GetLinkedWeakFrameworks(
+      const Target* target) const {
+    return GetTargetFrameworkInfo(target)->weak_frameworks;
+  }
+
  private:
   // The information associated with a given Target pointer.
   struct TargetInfo {
@@ -90,10 +111,16 @@
     ResolvedTargetDeps deps;
 
     bool has_lib_info = false;
+    bool has_framework_info = false;
 
     // Only valid if |has_lib_info| is true.
     std::vector<SourceDir> lib_dirs;
     std::vector<LibFile> libs;
+
+    // Only valid if |has_framework_info| is true.
+    std::vector<SourceDir> framework_dirs;
+    std::vector<std::string> frameworks;
+    std::vector<std::string> weak_frameworks;
   };
 
   // Retrieve TargetInfo value associated with |target|. Create
@@ -109,10 +136,20 @@
     return info;
   }
 
+  const TargetInfo* GetTargetFrameworkInfo(const Target* target) const {
+    TargetInfo* info = GetTargetInfo(target);
+    if (!info->has_framework_info) {
+      ComputeFrameworkInfo(info);
+      DCHECK(info->has_framework_info);
+    }
+    return info;
+  }
+
   // Compute the portion of TargetInfo guarded by one of the |has_xxx|
   // booleans. This performs recursive and expensive computations and
   // should only be called once per TargetInfo instance.
   void ComputeLibInfo(TargetInfo* info) const;
+  void ComputeFrameworkInfo(TargetInfo* info) const;
 
   // A { Target* -> TargetInfo } map that will create entries
   // on demand (hence the mutable qualifier). Implemented with a
diff --git a/src/gn/resolved_target_data_unittest.cc b/src/gn/resolved_target_data_unittest.cc
index 440c604..5871d39 100644
--- a/src/gn/resolved_target_data_unittest.cc
+++ b/src/gn/resolved_target_data_unittest.cc
@@ -109,3 +109,61 @@
   const auto& all_lib_dirs3 = resolved.GetLinkedLibraryDirs(&exec);
   EXPECT_EQ(0u, all_lib_dirs3.size());
 }
+
+// Tests that framework[_dir]s are inherited across deps boundaries for static
+// libraries but not executables.
+TEST(ResolvedTargetDataTest, FrameworkInheritance) {
+  TestWithScope setup;
+  Err err;
+
+  const std::string framework("Foo.framework");
+  const SourceDir frameworkdir("//out/foo/");
+
+  // Leaf target with ldflags set.
+  TestTarget z(setup, "//foo:z", Target::STATIC_LIBRARY);
+  z.config_values().frameworks().push_back(framework);
+  z.config_values().framework_dirs().push_back(frameworkdir);
+  ASSERT_TRUE(z.OnResolved(&err));
+
+  ResolvedTargetData resolved;
+
+  // All framework[_dir]s should be set when target is resolved.
+  const auto& frameworks = resolved.GetLinkedFrameworks(&z);
+  ASSERT_EQ(1u, frameworks.size());
+  EXPECT_EQ(framework, frameworks[0]);
+
+  const auto& framework_dirs = resolved.GetLinkedFrameworkDirs(&z);
+  ASSERT_EQ(1u, framework_dirs.size());
+  EXPECT_EQ(frameworkdir, framework_dirs[0]);
+
+  // Shared library target should inherit the libs from the static library
+  // and its own. Its own flag should be before the inherited one.
+  const std::string second_framework("Bar.framework");
+  const SourceDir second_frameworkdir("//out/bar/");
+  TestTarget shared(setup, "//foo:shared", Target::SHARED_LIBRARY);
+  shared.config_values().frameworks().push_back(second_framework);
+  shared.config_values().framework_dirs().push_back(second_frameworkdir);
+  shared.private_deps().push_back(LabelTargetPair(&z));
+  ASSERT_TRUE(shared.OnResolved(&err));
+
+  const auto& frameworks2 = resolved.GetLinkedFrameworks(&shared);
+  ASSERT_EQ(2u, frameworks2.size());
+  EXPECT_EQ(second_framework, frameworks2[0]);
+  EXPECT_EQ(framework, frameworks2[1]);
+
+  const auto& framework_dirs2 = resolved.GetLinkedFrameworkDirs(&shared);
+  ASSERT_EQ(2u, framework_dirs2.size());
+  EXPECT_EQ(second_frameworkdir, framework_dirs2[0]);
+  EXPECT_EQ(frameworkdir, framework_dirs2[1]);
+
+  // Executable target shouldn't get either by depending on shared.
+  TestTarget exec(setup, "//foo:exec", Target::EXECUTABLE);
+  exec.private_deps().push_back(LabelTargetPair(&shared));
+  ASSERT_TRUE(exec.OnResolved(&err));
+
+  const auto& frameworks3 = resolved.GetLinkedFrameworks(&exec);
+  EXPECT_EQ(0u, frameworks3.size());
+
+  const auto& framework_dirs3 = resolved.GetLinkedFrameworkDirs(&exec);
+  EXPECT_EQ(0u, framework_dirs3.size());
+}
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 4d8cc56..0ad2dd2 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -483,23 +483,6 @@
                              dep.ptr->public_configs().end());
   }
 
-  // Copy our own libs and lib_dirs to the final set. This will be from our
-  // target and all of our configs. We do this specially since these must be
-  // inherited through the dependency tree (other flags don't work this way).
-  //
-  // This needs to happen after we pull dependent target configs for the
-  // public config's libs to be included here. And it needs to happen
-  // before pulling the dependent target libs so the libs are in the correct
-  // order (local ones first, then the dependency's).
-  for (ConfigValuesIterator iter(this); !iter.done(); iter.Next()) {
-    const ConfigValues& cur = iter.cur();
-    all_framework_dirs_.Append(cur.framework_dirs().begin(),
-                               cur.framework_dirs().end());
-    all_frameworks_.Append(cur.frameworks().begin(), cur.frameworks().end());
-    all_weak_frameworks_.Append(cur.weak_frameworks().begin(),
-                                cur.weak_frameworks().end());
-  }
-
   PullRecursiveBundleData();
   PullDependentTargetLibs();
   PullRecursiveHardDeps();
@@ -856,13 +839,6 @@
       }
     }
   }
-
-  // Library settings are always inherited across static library boundaries.
-  if (!dep->IsFinal() || dep->output_type() == STATIC_LIBRARY) {
-    all_framework_dirs_.Append(dep->all_framework_dirs());
-    all_frameworks_.Append(dep->all_frameworks());
-    all_weak_frameworks_.Append(dep->all_weak_frameworks());
-  }
 }
 
 void Target::PullDependentTargetLibs() {
diff --git a/src/gn/target.h b/src/gn/target.h
index c6f93c4..899e06b 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -332,16 +332,6 @@
     return rust_transitive_inheritable_libs_;
   }
 
-  const UniqueVector<SourceDir>& all_framework_dirs() const {
-    return all_framework_dirs_;
-  }
-  const UniqueVector<std::string>& all_frameworks() const {
-    return all_frameworks_;
-  }
-  const UniqueVector<std::string>& all_weak_frameworks() const {
-    return all_weak_frameworks_;
-  }
-
   const TargetSet& recursive_hard_deps() const { return recursive_hard_deps_; }
 
   std::vector<LabelPattern>& friends() { return friends_; }
@@ -501,12 +491,6 @@
   // that need to be linked.
   InheritedLibraries inherited_libraries_;
 
-  // These frameworks and dirs are inherited from statically linked deps and
-  // all configs applying to this target.
-  UniqueVector<SourceDir> all_framework_dirs_;
-  UniqueVector<std::string> all_frameworks_;
-  UniqueVector<std::string> all_weak_frameworks_;
-
   // All hard deps from this target and all dependencies. Filled in when this
   // target is marked resolved. This will not include the current target.
   TargetSet recursive_hard_deps_;
diff --git a/src/gn/target_unittest.cc b/src/gn/target_unittest.cc
index 7a3ca6e..6031fed 100644
--- a/src/gn/target_unittest.cc
+++ b/src/gn/target_unittest.cc
@@ -37,52 +37,6 @@
 
 using TargetTest = TestWithScheduler;
 
-// Tests that framework[_dir]s are inherited across deps boundaries for static
-// libraries but not executables.
-TEST_F(TargetTest, FrameworkInheritance) {
-  TestWithScope setup;
-  Err err;
-
-  const std::string framework("Foo.framework");
-  const SourceDir frameworkdir("//out/foo/");
-
-  // Leaf target with ldflags set.
-  TestTarget z(setup, "//foo:z", Target::STATIC_LIBRARY);
-  z.config_values().frameworks().push_back(framework);
-  z.config_values().framework_dirs().push_back(frameworkdir);
-  ASSERT_TRUE(z.OnResolved(&err));
-
-  // All framework[_dir]s should be set when target is resolved.
-  ASSERT_EQ(1u, z.all_frameworks().size());
-  EXPECT_EQ(framework, z.all_frameworks()[0]);
-  ASSERT_EQ(1u, z.all_framework_dirs().size());
-  EXPECT_EQ(frameworkdir, z.all_framework_dirs()[0]);
-
-  // Shared library target should inherit the libs from the static library
-  // and its own. Its own flag should be before the inherited one.
-  const std::string second_framework("Bar.framework");
-  const SourceDir second_frameworkdir("//out/bar/");
-  TestTarget shared(setup, "//foo:shared", Target::SHARED_LIBRARY);
-  shared.config_values().frameworks().push_back(second_framework);
-  shared.config_values().framework_dirs().push_back(second_frameworkdir);
-  shared.private_deps().push_back(LabelTargetPair(&z));
-  ASSERT_TRUE(shared.OnResolved(&err));
-
-  ASSERT_EQ(2u, shared.all_frameworks().size());
-  EXPECT_EQ(second_framework, shared.all_frameworks()[0]);
-  EXPECT_EQ(framework, shared.all_frameworks()[1]);
-  ASSERT_EQ(2u, shared.all_framework_dirs().size());
-  EXPECT_EQ(second_frameworkdir, shared.all_framework_dirs()[0]);
-  EXPECT_EQ(frameworkdir, shared.all_framework_dirs()[1]);
-
-  // Executable target shouldn't get either by depending on shared.
-  TestTarget exec(setup, "//foo:exec", Target::EXECUTABLE);
-  exec.private_deps().push_back(LabelTargetPair(&shared));
-  ASSERT_TRUE(exec.OnResolved(&err));
-  EXPECT_EQ(0u, exec.all_frameworks().size());
-  EXPECT_EQ(0u, exec.all_framework_dirs().size());
-}
-
 // Test all_dependent_configs and public_config inheritance.
 TEST_F(TargetTest, DependentConfigs) {
   TestWithScope setup;