Add ResolvedTargetData::GetInheritedLibraries()
This CL removes Target::inherited_libraries() and moves
the computation of the corresponding value to the
ResolvedTargetData class instead, where it will be
created on-demand by the GetInheritedLibraries() method.
Bug: 331
Change-Id: I65f73d9d895f4db1318363b6c8a8775d7225252b
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15326
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc
index b1dbbef..5fb8929 100644
--- a/src/gn/ninja_binary_target_writer.cc
+++ b/src/gn/ninja_binary_target_writer.cc
@@ -137,8 +137,8 @@
}
// Inherited libraries.
- for (auto* inherited_target : target_->inherited_libraries().GetOrdered()) {
- ClassifyDependency(inherited_target, &classified_deps);
+ for (const auto& inherited : resolved().GetInheritedLibraries(target_)) {
+ ClassifyDependency(inherited.target(), &classified_deps);
}
// Data deps.
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index f74d208..9978b63 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -668,7 +668,8 @@
// rlibs only depended on inside a shared library dependency).
std::vector<OutputFile> transitive_rustlibs;
if (target_->IsFinal()) {
- for (const auto* dep : target_->inherited_libraries().GetOrdered()) {
+ for (const auto& inherited : resolved().GetInheritedLibraries(target_)) {
+ const Target* dep = inherited.target();
if (dep->output_type() == Target::RUST_LIBRARY) {
transitive_rustlibs.push_back(dep->dependency_output_file());
implicit_deps.push_back(dep->dependency_output_file());
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
index 467e2fb..d944123 100644
--- a/src/gn/resolved_target_data.cc
+++ b/src/gn/resolved_target_data.cc
@@ -88,3 +88,86 @@
info->hard_deps = std::move(all_hard_deps);
info->has_hard_deps = true;
}
+
+void ResolvedTargetData::ComputeInheritedLibs(TargetInfo* info) const {
+ TargetPublicPairListBuilder inherited_libraries;
+
+ ComputeInheritedLibsFor(info->deps.public_deps(), true, &inherited_libraries);
+ ComputeInheritedLibsFor(info->deps.private_deps(), false,
+ &inherited_libraries);
+
+ info->inherited_libs = inherited_libraries.Build();
+ info->has_inherited_libs = true;
+}
+
+void ResolvedTargetData::ComputeInheritedLibsFor(
+ base::span<const Target*> deps,
+ bool is_public,
+ TargetPublicPairListBuilder* inherited_libraries) const {
+ for (const Target* dep : deps) {
+ // Direct dependent libraries.
+ if (dep->output_type() == Target::STATIC_LIBRARY ||
+ dep->output_type() == Target::SHARED_LIBRARY ||
+ dep->output_type() == Target::RUST_LIBRARY ||
+ dep->output_type() == Target::SOURCE_SET ||
+ (dep->output_type() == Target::CREATE_BUNDLE &&
+ dep->bundle_data().is_framework())) {
+ inherited_libraries->Append(dep, is_public);
+ }
+ if (dep->output_type() == Target::SHARED_LIBRARY) {
+ // Shared library dependendencies are inherited across public shared
+ // library boundaries.
+ //
+ // In this case:
+ // EXE -> INTERMEDIATE_SHLIB --[public]--> FINAL_SHLIB
+ // The EXE will also link to to FINAL_SHLIB. The public dependency means
+ // that the EXE can use the headers in FINAL_SHLIB so the FINAL_SHLIB
+ // will need to appear on EXE's link line.
+ //
+ // However, if the dependency is private:
+ // EXE -> INTERMEDIATE_SHLIB --[private]--> FINAL_SHLIB
+ // the dependency will not be propagated because INTERMEDIATE_SHLIB is
+ // not granting permission to call functions from FINAL_SHLIB. If EXE
+ // wants to use functions (and link to) FINAL_SHLIB, it will need to do
+ // so explicitly.
+ //
+ // Static libraries and source sets aren't inherited across shared
+ // library boundaries because they will be linked into the shared
+ // library. Rust dylib deps are handled above and transitive deps are
+ // resolved by the compiler.
+ const TargetInfo* dep_info = GetTargetInheritedLibs(dep);
+ for (const auto& pair : dep_info->inherited_libs) {
+ if (pair.target()->output_type() == Target::SHARED_LIBRARY &&
+ pair.is_public()) {
+ inherited_libraries->Append(pair.target(), is_public);
+ }
+ }
+ } else if (!dep->IsFinal()) {
+ // The current target isn't linked, so propagate linked deps and
+ // libraries up the dependency tree.
+ const TargetInfo* dep_info = GetTargetInheritedLibs(dep);
+ for (const auto& pair : dep_info->inherited_libs) {
+ // Proc macros are not linked into targets that depend on them, so do
+ // not get inherited; they are consumed by the Rust compiler and only
+ // need to be specified in --extern.
+ if (pair.target()->output_type() != Target::RUST_PROC_MACRO)
+ inherited_libraries->Append(pair.target(),
+ is_public && pair.is_public());
+ }
+ } else if (dep->complete_static_lib()) {
+ // Inherit only final targets through _complete_ static libraries.
+ //
+ // Inherited final libraries aren't linked into complete static
+ // libraries. They are forwarded here so that targets that depend on
+ // complete static libraries can link them in. Conversely, since
+ // complete static libraries link in non-final targets, they shouldn't be
+ // inherited.
+ const TargetInfo* dep_info = GetTargetInheritedLibs(dep);
+ for (const auto& pair : dep_info->inherited_libs) {
+ if (pair.target()->IsFinal())
+ inherited_libraries->Append(pair.target(),
+ is_public && pair.is_public());
+ }
+ }
+ }
+}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h
index bc992a1..0dc36be 100644
--- a/src/gn/resolved_target_data.h
+++ b/src/gn/resolved_target_data.h
@@ -103,6 +103,13 @@
return GetTargetHardDeps(target)->hard_deps;
}
+ // Retrieves an ordered list of (target, is_public) pairs for all link-time
+ // libraries inherited by this target.
+ const std::vector<TargetPublicPair>& GetInheritedLibraries(
+ const Target* target) const {
+ return GetTargetInheritedLibs(target)->inherited_libs;
+ }
+
private:
// The information associated with a given Target pointer.
struct TargetInfo {
@@ -120,6 +127,7 @@
bool has_lib_info = false;
bool has_framework_info = false;
bool has_hard_deps = false;
+ bool has_inherited_libs = false;
// Only valid if |has_lib_info| is true.
std::vector<SourceDir> lib_dirs;
@@ -132,6 +140,9 @@
// Only valid if |has_hard_deps| is true.
TargetSet hard_deps;
+
+ // Only valid if |has_inherited_libs| is true.
+ std::vector<TargetPublicPair> inherited_libs;
};
// Retrieve TargetInfo value associated with |target|. Create
@@ -165,12 +176,28 @@
return info;
}
+ const TargetInfo* GetTargetInheritedLibs(const Target* target) const {
+ TargetInfo* info = GetTargetInfo(target);
+ if (!info->has_inherited_libs) {
+ ComputeInheritedLibs(info);
+ DCHECK(info->has_inherited_libs);
+ }
+ 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;
void ComputeHardDeps(TargetInfo* info) const;
+ void ComputeInheritedLibs(TargetInfo* info) const;
+
+ // Helper function usde by ComputeInheritedLibs().
+ void ComputeInheritedLibsFor(
+ base::span<const Target*> deps,
+ bool is_public,
+ TargetPublicPairListBuilder* inherited_libraries) 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 5871d39..d4f60b4 100644
--- a/src/gn/resolved_target_data_unittest.cc
+++ b/src/gn/resolved_target_data_unittest.cc
@@ -167,3 +167,244 @@
const auto& framework_dirs3 = resolved.GetLinkedFrameworkDirs(&exec);
EXPECT_EQ(0u, framework_dirs3.size());
}
+
+TEST(ResolvedTargetDataTest, InheritLibs) {
+ TestWithScope setup;
+ Err err;
+
+ // Create a dependency chain:
+ // A (executable) -> B (shared lib) -> C (static lib) -> D (source set)
+ TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+ TestTarget b(setup, "//foo:b", Target::SHARED_LIBRARY);
+ TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
+ TestTarget d(setup, "//foo:d", Target::SOURCE_SET);
+ a.private_deps().push_back(LabelTargetPair(&b));
+ b.private_deps().push_back(LabelTargetPair(&c));
+ c.private_deps().push_back(LabelTargetPair(&d));
+
+ ASSERT_TRUE(d.OnResolved(&err));
+ ASSERT_TRUE(c.OnResolved(&err));
+ ASSERT_TRUE(b.OnResolved(&err));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ ResolvedTargetData resolved;
+
+ // C should have D in its inherited libs.
+ const auto& c_inherited_libs = resolved.GetInheritedLibraries(&c);
+ ASSERT_EQ(1u, c_inherited_libs.size());
+ EXPECT_EQ(&d, c_inherited_libs[0].target());
+
+ // B should have C and D in its inherited libs.
+ const auto& b_inherited = resolved.GetInheritedLibraries(&b);
+ ASSERT_EQ(2u, b_inherited.size());
+ EXPECT_EQ(&c, b_inherited[0].target());
+ EXPECT_EQ(&d, b_inherited[1].target());
+
+ // A should have B in its inherited libs, but not any others (the shared
+ // library will include the static library and source set).
+ const auto& a_inherited = resolved.GetInheritedLibraries(&a);
+ ASSERT_EQ(1u, a_inherited.size());
+ EXPECT_EQ(&b, a_inherited[0].target());
+}
+
+TEST(ResolvedTargetData, NoActionDepPropgation) {
+ TestWithScope setup;
+ Err err;
+ ResolvedTargetData resolved;
+ // Create a dependency chain:
+ // A (exe) -> B (action) -> C (source_set)
+ {
+ TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+ TestTarget b(setup, "//foo:b", Target::ACTION);
+ TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
+
+ a.private_deps().push_back(LabelTargetPair(&b));
+ b.private_deps().push_back(LabelTargetPair(&c));
+
+ ASSERT_TRUE(c.OnResolved(&err));
+ ASSERT_TRUE(b.OnResolved(&err));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ // The executable should not have inherited the source set across the
+ // action.
+ ASSERT_TRUE(resolved.GetInheritedLibraries(&a).empty());
+ }
+}
+
+TEST(ResolvedTargetDataTest, InheritCompleteStaticLib) {
+ TestWithScope setup;
+ Err err;
+
+ ResolvedTargetData resolved;
+
+ // Create a dependency chain:
+ // A (executable) -> B (complete static lib) -> C (source set)
+ TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+ TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
+ b.set_complete_static_lib(true);
+
+ const LibFile lib("foo");
+ const SourceDir lib_dir("/foo_dir/");
+ TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
+ c.config_values().libs().push_back(lib);
+ c.config_values().lib_dirs().push_back(lib_dir);
+
+ a.public_deps().push_back(LabelTargetPair(&b));
+ b.public_deps().push_back(LabelTargetPair(&c));
+
+ ASSERT_TRUE(c.OnResolved(&err));
+ ASSERT_TRUE(b.OnResolved(&err));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ // B should have C in its inherited libs.
+ const auto& b_inherited = resolved.GetInheritedLibraries(&b);
+ ASSERT_EQ(1u, b_inherited.size());
+ EXPECT_EQ(&c, b_inherited[0].target());
+
+ // A should have B in its inherited libs, but not any others (the complete
+ // static library will include the source set).
+ const auto& a_inherited = resolved.GetInheritedLibraries(&a);
+ ASSERT_EQ(1u, a_inherited.size());
+ EXPECT_EQ(&b, a_inherited[0].target());
+
+ // A should inherit the libs and lib_dirs from the C.
+ const auto& a_libs = resolved.GetLinkedLibraries(&a);
+ ASSERT_EQ(1u, a_libs.size());
+ EXPECT_EQ(lib, a_libs[0]);
+
+ const auto& a_lib_dirs = resolved.GetLinkedLibraryDirs(&a);
+ ASSERT_EQ(1u, a_lib_dirs.size());
+ EXPECT_EQ(lib_dir, a_lib_dirs[0]);
+}
+
+TEST(ResolvedTargetDataTest, InheritCompleteStaticLibStaticLibDeps) {
+ TestWithScope setup;
+ Err err;
+
+ // Create a dependency chain:
+ // A (executable) -> B (complete static lib) -> C (static lib)
+ TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+ TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
+ b.set_complete_static_lib(true);
+ TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
+ a.public_deps().push_back(LabelTargetPair(&b));
+ b.public_deps().push_back(LabelTargetPair(&c));
+
+ ASSERT_TRUE(c.OnResolved(&err));
+ ASSERT_TRUE(b.OnResolved(&err));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ ResolvedTargetData resolved;
+
+ // B should have C in its inherited libs.
+ const auto& b_inherited = resolved.GetInheritedLibraries(&b);
+ ASSERT_EQ(1u, b_inherited.size());
+ EXPECT_EQ(&c, b_inherited[0].target());
+
+ // A should have B in its inherited libs, but not any others (the complete
+ // static library will include the static library).
+ const auto& a_inherited = resolved.GetInheritedLibraries(&a);
+ ASSERT_EQ(1u, a_inherited.size());
+ EXPECT_EQ(&b, a_inherited[0].target());
+}
+
+TEST(ResolvedTargetDataTest,
+ InheritCompleteStaticLibInheritedCompleteStaticLibDeps) {
+ TestWithScope setup;
+ Err err;
+
+ // Create a dependency chain:
+ // A (executable) -> B (complete static lib) -> C (complete static lib)
+ TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+ TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
+ b.set_complete_static_lib(true);
+ TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
+ c.set_complete_static_lib(true);
+
+ a.private_deps().push_back(LabelTargetPair(&b));
+ b.private_deps().push_back(LabelTargetPair(&c));
+
+ ASSERT_TRUE(c.OnResolved(&err));
+ ASSERT_TRUE(b.OnResolved(&err));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ ResolvedTargetData resolved;
+
+ // B should have C in its inherited libs.
+ const auto& b_inherited = resolved.GetInheritedLibraries(&b);
+ ASSERT_EQ(1u, b_inherited.size());
+ EXPECT_EQ(&c, b_inherited[0].target());
+
+ // A should have B and C in its inherited libs.
+ const auto& a_inherited = resolved.GetInheritedLibraries(&a);
+ ASSERT_EQ(2u, a_inherited.size());
+ EXPECT_EQ(&b, a_inherited[0].target());
+ EXPECT_EQ(&c, a_inherited[1].target());
+}
+
+TEST(ResolvedTargetDataTest, NoActionDepPropgation) {
+ TestWithScope setup;
+ Err err;
+ ResolvedTargetData resolved;
+
+ // Create a dependency chain:
+ // A (exe) -> B (action) -> C (source_set)
+ {
+ TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+ TestTarget b(setup, "//foo:b", Target::ACTION);
+ TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
+
+ a.private_deps().push_back(LabelTargetPair(&b));
+ b.private_deps().push_back(LabelTargetPair(&c));
+
+ ASSERT_TRUE(c.OnResolved(&err));
+ ASSERT_TRUE(b.OnResolved(&err));
+ ASSERT_TRUE(a.OnResolved(&err));
+
+ // The executable should not have inherited the source set across the
+ // action.
+ const auto& libs = resolved.GetInheritedLibraries(&a);
+ ASSERT_TRUE(libs.empty());
+ }
+}
+
+// Shared libraries should be inherited across public shared library
+// boundaries.
+TEST(ResolvedTargetDataTest, SharedInheritance) {
+ TestWithScope setup;
+ Err err;
+
+ // Create two leaf shared libraries.
+ TestTarget pub(setup, "//foo:pub", Target::SHARED_LIBRARY);
+ ASSERT_TRUE(pub.OnResolved(&err));
+
+ TestTarget priv(setup, "//foo:priv", Target::SHARED_LIBRARY);
+ ASSERT_TRUE(priv.OnResolved(&err));
+
+ // Intermediate shared library with the leaf shared libraries as
+ // dependencies, one public, one private.
+ TestTarget inter(setup, "//foo:inter", Target::SHARED_LIBRARY);
+ inter.public_deps().push_back(LabelTargetPair(&pub));
+ inter.private_deps().push_back(LabelTargetPair(&priv));
+ ASSERT_TRUE(inter.OnResolved(&err));
+
+ // The intermediate shared library should have both "pub" and "priv" in its
+ // inherited libraries.
+ ResolvedTargetData resolved;
+ const auto& inter_inherited = resolved.GetInheritedLibraries(&inter);
+ ASSERT_EQ(2u, inter_inherited.size());
+ EXPECT_EQ(&pub, inter_inherited[0].target());
+ EXPECT_EQ(&priv, inter_inherited[1].target());
+
+ // Make a toplevel executable target depending on the intermediate one.
+ TestTarget exe(setup, "//foo:exe", Target::SHARED_LIBRARY);
+ exe.private_deps().push_back(LabelTargetPair(&inter));
+ ASSERT_TRUE(exe.OnResolved(&err));
+
+ // The exe's inherited libraries should be "inter" (because it depended
+ // directly on it) and "pub" (because inter depended publicly on it).
+ const auto& exe_inherited = resolved.GetInheritedLibraries(&exe);
+ ASSERT_EQ(2u, exe_inherited.size());
+ EXPECT_EQ(&inter, exe_inherited[0].target());
+ EXPECT_EQ(&pub, exe_inherited[1].target());
+}
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 84cfbfa..5bdfdef 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -739,16 +739,6 @@
}
void Target::PullDependentTargetLibsFrom(const Target* dep, bool is_public) {
- // Direct dependent libraries.
- if (dep->output_type() == STATIC_LIBRARY ||
- dep->output_type() == SHARED_LIBRARY ||
- dep->output_type() == RUST_LIBRARY ||
- dep->output_type() == SOURCE_SET ||
- (dep->output_type() == CREATE_BUNDLE &&
- dep->bundle_data().is_framework())) {
- inherited_libraries_.Append(dep, is_public);
- }
-
// Collect Rust libraries that are accessible from the current target, or
// transitively part of the current target.
if (dep->output_type() == STATIC_LIBRARY ||
@@ -780,64 +770,6 @@
rust_transitive_inherited_libs_.Append(dep, true);
rust_transitive_inheritable_libs_.Append(dep, is_public);
}
-
- if (dep->output_type() == SHARED_LIBRARY) {
- // Shared library dependendencies are inherited across public shared
- // library boundaries.
- //
- // In this case:
- // EXE -> INTERMEDIATE_SHLIB --[public]--> FINAL_SHLIB
- // The EXE will also link to to FINAL_SHLIB. The public dependency means
- // that the EXE can use the headers in FINAL_SHLIB so the FINAL_SHLIB
- // will need to appear on EXE's link line.
- //
- // However, if the dependency is private:
- // EXE -> INTERMEDIATE_SHLIB --[private]--> FINAL_SHLIB
- // the dependency will not be propagated because INTERMEDIATE_SHLIB is
- // not granting permission to call functions from FINAL_SHLIB. If EXE
- // wants to use functions (and link to) FINAL_SHLIB, it will need to do
- // so explicitly.
- //
- // Static libraries and source sets aren't inherited across shared
- // library boundaries because they will be linked into the shared
- // library. Rust dylib deps are handled above and transitive deps are
- // resolved by the compiler.
- inherited_libraries_.AppendPublicSharedLibraries(dep->inherited_libraries(),
- is_public);
- } else {
- InheritedLibraries transitive;
-
- if (!dep->IsFinal()) {
- // The current target isn't linked, so propagate linked deps and
- // libraries up the dependency tree.
- for (const auto& [inherited, inherited_is_public] :
- dep->inherited_libraries().GetOrderedAndPublicFlag()) {
- transitive.Append(inherited, is_public && inherited_is_public);
- }
- } else if (dep->complete_static_lib()) {
- // Inherit only final targets through _complete_ static libraries.
- //
- // Inherited final libraries aren't linked into complete static libraries.
- // They are forwarded here so that targets that depend on complete
- // static libraries can link them in. Conversely, since complete static
- // libraries link in non-final targets they shouldn't be inherited.
- for (const auto& [inherited, inherited_is_public] :
- dep->inherited_libraries().GetOrderedAndPublicFlag()) {
- if (inherited->IsFinal()) {
- transitive.Append(inherited, is_public && inherited_is_public);
- }
- }
- }
-
- for (const auto& [target, pub] : transitive.GetOrderedAndPublicFlag()) {
- // Proc macros are not linked into targets that depend on them, so do not
- // get inherited; they are consumed by the Rust compiler and only need to
- // be specified in --extern.
- if (target->output_type() != RUST_PROC_MACRO) {
- inherited_libraries_.Append(target, pub);
- }
- }
- }
}
void Target::PullDependentTargetLibs() {
diff --git a/src/gn/target.h b/src/gn/target.h
index d672985..348f49f 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -14,7 +14,6 @@
#include "gn/action_values.h"
#include "gn/bundle_data.h"
#include "gn/config_values.h"
-#include "gn/inherited_libraries.h"
#include "gn/item.h"
#include "gn/label_pattern.h"
#include "gn/label_ptr.h"
@@ -298,10 +297,6 @@
const LabelPtrPair<Pool>& pool() const { return pool_; }
void set_pool(LabelPtrPair<Pool> pool) { pool_ = std::move(pool); }
- const InheritedLibraries& inherited_libraries() const {
- return inherited_libraries_;
- }
-
// This config represents the configuration set directly on this target.
ConfigValues& config_values();
const ConfigValues& config_values() const;
@@ -485,10 +480,6 @@
LabelPtrPair<Pool> pool_;
- // Static libraries, shared libraries, and source sets from transitive deps
- // that need to be linked.
- InheritedLibraries inherited_libraries_;
-
std::vector<LabelPattern> friends_;
std::vector<LabelPattern> assert_no_deps_;
diff --git a/src/gn/target_unittest.cc b/src/gn/target_unittest.cc
index 6031fed..d6554fd 100644
--- a/src/gn/target_unittest.cc
+++ b/src/gn/target_unittest.cc
@@ -203,173 +203,6 @@
EXPECT_EQ(&all_dependent, a.all_dependent_configs()[0].ptr);
}
-TEST_F(TargetTest, InheritLibs) {
- TestWithScope setup;
- Err err;
-
- // Create a dependency chain:
- // A (executable) -> B (shared lib) -> C (static lib) -> D (source set)
- TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
- TestTarget b(setup, "//foo:b", Target::SHARED_LIBRARY);
- TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
- TestTarget d(setup, "//foo:d", Target::SOURCE_SET);
- a.private_deps().push_back(LabelTargetPair(&b));
- b.private_deps().push_back(LabelTargetPair(&c));
- c.private_deps().push_back(LabelTargetPair(&d));
-
- ASSERT_TRUE(d.OnResolved(&err));
- ASSERT_TRUE(c.OnResolved(&err));
- ASSERT_TRUE(b.OnResolved(&err));
- ASSERT_TRUE(a.OnResolved(&err));
-
- // C should have D in its inherited libs.
- std::vector<const Target*> c_inherited = c.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, c_inherited.size());
- EXPECT_EQ(&d, c_inherited[0]);
-
- // B should have C and D in its inherited libs.
- std::vector<const Target*> b_inherited = b.inherited_libraries().GetOrdered();
- ASSERT_EQ(2u, b_inherited.size());
- EXPECT_EQ(&c, b_inherited[0]);
- EXPECT_EQ(&d, b_inherited[1]);
-
- // A should have B in its inherited libs, but not any others (the shared
- // library will include the static library and source set).
- std::vector<const Target*> a_inherited = a.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, a_inherited.size());
- EXPECT_EQ(&b, a_inherited[0]);
-}
-
-TEST_F(TargetTest, InheritCompleteStaticLib) {
- TestWithScope setup;
- Err err;
-
- // Create a dependency chain:
- // A (executable) -> B (complete static lib) -> C (source set)
- TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
- TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
- b.set_complete_static_lib(true);
-
- const LibFile lib("foo");
- const SourceDir lib_dir("/foo_dir/");
- TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
- c.config_values().libs().push_back(lib);
- c.config_values().lib_dirs().push_back(lib_dir);
-
- a.public_deps().push_back(LabelTargetPair(&b));
- b.public_deps().push_back(LabelTargetPair(&c));
-
- ASSERT_TRUE(c.OnResolved(&err));
- ASSERT_TRUE(b.OnResolved(&err));
- ASSERT_TRUE(a.OnResolved(&err));
-
- // B should have C in its inherited libs.
- std::vector<const Target*> b_inherited = b.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, b_inherited.size());
- EXPECT_EQ(&c, b_inherited[0]);
-
- // A should have B in its inherited libs, but not any others (the complete
- // static library will include the source set).
- std::vector<const Target*> a_inherited = a.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, a_inherited.size());
- EXPECT_EQ(&b, a_inherited[0]);
-
- // A should inherit the libs and lib_dirs from the C.
- ResolvedTargetData resolved;
- const auto& a_all_libs = resolved.GetLinkedLibraries(&a);
- ASSERT_EQ(1u, a_all_libs.size());
- EXPECT_EQ(lib, a_all_libs[0]);
-
- const auto& a_all_lib_dirs = resolved.GetLinkedLibraryDirs(&a);
- ASSERT_EQ(1u, a_all_lib_dirs.size());
- EXPECT_EQ(lib_dir, a_all_lib_dirs[0]);
-}
-
-TEST_F(TargetTest, InheritCompleteStaticLibStaticLibDeps) {
- TestWithScope setup;
- Err err;
-
- // Create a dependency chain:
- // A (executable) -> B (complete static lib) -> C (static lib)
- TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
- TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
- b.set_complete_static_lib(true);
- TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
- a.public_deps().push_back(LabelTargetPair(&b));
- b.public_deps().push_back(LabelTargetPair(&c));
-
- ASSERT_TRUE(c.OnResolved(&err));
- ASSERT_TRUE(b.OnResolved(&err));
- ASSERT_TRUE(a.OnResolved(&err));
-
- // B should have C in its inherited libs.
- std::vector<const Target*> b_inherited = b.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, b_inherited.size());
- EXPECT_EQ(&c, b_inherited[0]);
-
- // A should have B in its inherited libs, but not any others (the complete
- // static library will include the static library).
- std::vector<const Target*> a_inherited = a.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, a_inherited.size());
- EXPECT_EQ(&b, a_inherited[0]);
-}
-
-TEST_F(TargetTest, InheritCompleteStaticLibInheritedCompleteStaticLibDeps) {
- TestWithScope setup;
- Err err;
-
- // Create a dependency chain:
- // A (executable) -> B (complete static lib) -> C (complete static lib)
- TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
- TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
- b.set_complete_static_lib(true);
- TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
- c.set_complete_static_lib(true);
-
- a.private_deps().push_back(LabelTargetPair(&b));
- b.private_deps().push_back(LabelTargetPair(&c));
-
- ASSERT_TRUE(c.OnResolved(&err));
- ASSERT_TRUE(b.OnResolved(&err));
- ASSERT_TRUE(a.OnResolved(&err));
-
- // B should have C in its inherited libs.
- std::vector<const Target*> b_inherited = b.inherited_libraries().GetOrdered();
- ASSERT_EQ(1u, b_inherited.size());
- EXPECT_EQ(&c, b_inherited[0]);
-
- // A should have B and C in its inherited libs.
- std::vector<const Target*> a_inherited = a.inherited_libraries().GetOrdered();
- ASSERT_EQ(2u, a_inherited.size());
- EXPECT_EQ(&b, a_inherited[0]);
- EXPECT_EQ(&c, a_inherited[1]);
-}
-
-TEST_F(TargetTest, NoActionDepPropgation) {
- TestWithScope setup;
- Err err;
-
- // Create a dependency chain:
- // A (exe) -> B (action) -> C (source_set)
- {
- TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
- TestTarget b(setup, "//foo:b", Target::ACTION);
- TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
-
- a.private_deps().push_back(LabelTargetPair(&b));
- b.private_deps().push_back(LabelTargetPair(&c));
-
- ASSERT_TRUE(c.OnResolved(&err));
- ASSERT_TRUE(b.OnResolved(&err));
- ASSERT_TRUE(a.OnResolved(&err));
-
- // The executable should not have inherited the source set across the
- // action.
- std::vector<const Target*> libs = a.inherited_libraries().GetOrdered();
- ASSERT_TRUE(libs.empty());
- }
-}
-
TEST_F(TargetTest, GetComputedOutputName) {
TestWithScope setup;
Err err;
@@ -934,48 +767,6 @@
EXPECT_EQ("//out/Debug/one", computed_outputs[0].value());
}
-// Shared libraries should be inherited across public shared library
-// boundaries.
-TEST_F(TargetTest, SharedInheritance) {
- TestWithScope setup;
- Err err;
-
- // Create two leaf shared libraries.
- TestTarget pub(setup, "//foo:pub", Target::SHARED_LIBRARY);
- ASSERT_TRUE(pub.OnResolved(&err));
-
- TestTarget priv(setup, "//foo:priv", Target::SHARED_LIBRARY);
- ASSERT_TRUE(priv.OnResolved(&err));
-
- // Intermediate shared library with the leaf shared libraries as
- // dependencies, one public, one private.
- TestTarget inter(setup, "//foo:inter", Target::SHARED_LIBRARY);
- inter.public_deps().push_back(LabelTargetPair(&pub));
- inter.private_deps().push_back(LabelTargetPair(&priv));
- ASSERT_TRUE(inter.OnResolved(&err));
-
- // The intermediate shared library should have both "pub" and "priv" in its
- // inherited libraries.
- std::vector<const Target*> inter_inherited =
- inter.inherited_libraries().GetOrdered();
- ASSERT_EQ(2u, inter_inherited.size());
- EXPECT_EQ(&pub, inter_inherited[0]);
- EXPECT_EQ(&priv, inter_inherited[1]);
-
- // Make a toplevel executable target depending on the intermediate one.
- TestTarget exe(setup, "//foo:exe", Target::SHARED_LIBRARY);
- exe.private_deps().push_back(LabelTargetPair(&inter));
- ASSERT_TRUE(exe.OnResolved(&err));
-
- // The exe's inherited libraries should be "inter" (because it depended
- // directly on it) and "pub" (because inter depended publicly on it).
- std::vector<const Target*> exe_inherited =
- exe.inherited_libraries().GetOrdered();
- ASSERT_EQ(2u, exe_inherited.size());
- EXPECT_EQ(&inter, exe_inherited[0]);
- EXPECT_EQ(&pub, exe_inherited[1]);
-}
-
TEST_F(TargetTest, GeneratedInputs) {
TestWithScope setup;
Err err;