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;