Make library inheritance for consistent for Rust libraries

Previously C libraries, and CDYLIB libraries would be inherited for
linking through an rlib. But DYLIB libraries would not be. Proc macros
would be inherited through a group, but not through a Rust library. And
proc macros would be inherited for linking as a direct dependency but
not as a transitive one.

There was inconsistency of what Rust targets should be inherited (ie
collected) for linking by a C linking target.

We improve this by removing or consolidating conditionals, which helps
to make the system more consistent.

a) Don't inherit transitive libraries through a Rust Dylib or Rlib
   differently than other final or non-final targets respectively.
   For linking purposes they are the same.

b) Since inherited_libraries_ and rust_linkable_inherited_libs_ are now
   the same thing, we can remove the latter.

c) Consistently avoid adding proc macros, or their dependencies, to
   inherited_libraries_, as they are never linked into a final target.
   They are only passed to the Rust compiler with --extern.

The NinjaCBinaryTargetWriterTest.LinkingWithRustLibraryDepsOnDylib test
demonstrates the bug fix, which allows Rust Dylib targets to be
inherited into the linker through an rlib.

The NinjaCBinaryTargetWriterTest.LinkingWithRustLibraryDepsOnCdylib
test passed before this change, but provides a regression test.

The NinjaRustBinaryTargetWriterTest.DylibDeps test was inadvertently
demonstrating the bug as well, but for public deps through a Dylib. A
binary depended a dylib ("direct") which then transitively publicly-
depended on another dylib ("mylib"). Since the binary has access to
mylib and could make calls to it, the transitive shared library needs
to be included in the inherited libraries of the binary as well. That
way if the binary was linked by a C linker, it would know all the
required Rust libraries. This is now done. We augment the test to also
show that a private dependency from the middle dylib ("direct") onto
another dylib ("private_dylib") will not add the private-transitive
shared library into the linker for the binary.

The NinjaRustBinaryTargetWriterTest.RlibDepsAcrossGroups test
changes to not inherit implicit dependencies on proc macro libraries,
as they would not need to be linked with the Rust library by a C linker.
This more accurately represents to a C linker what the Rust linker would
implicitly do. While the proc-macro is given to rustc in a --extern flag
the Rust compiler would not add it to the linking line.

The NinjaRustBinaryTargetWriterTest.GroupDeps test has a binary that
depends on a group which publicly-depends on an rlib. Rlibs were not
normally inherited (by checking !RustValues::IsRustLibrary()) however
since it was through a group, it was being inherited for linking
incorrectly.

An example of a BUILD.gn which failed to link (missing symbols from the
dylib) before this change, but builds after:

shared_library("rust_so") {
  crate_type = "dylib"
  crate_root = "rust_so.rs"
  sources = [ "rust_so.rs" ]
}

rust_library("rust_stdlib") {
  crate_type = "staticlib"
  crate_root = "rust_lib.rs"
}

rust_library("rust_lib") {
  crate_root = "rust_lib.rs"
  sources = [ "rust_lib.rs" ]
  deps = [":rust_so"]
}

executable("exe") {
  sources = [ "exe.c" ]
  deps = [
    ":rust_lib",
  ]
}

This also fixes a bug in the RUST_LIBRARY branch that is no longer a
special case, and thus removes the bug. We were inheriting all
transitive dependencies from _ourselves_ when depending on an rlib,
which would incorrectly pull in transitive dependencies from previously
traversed dependencies. In particular if one of those was a shared
library, we'd pull in things that were private deps in the shared
library and linked into it, and which should not be visible/inherited
into the current target.

We add a test which brackets an rlib dependency with shared library
dependencies and verifies the static libs inside the shared libraries
do not get inherited (which they do before this CL).

Bug: 276
Change-Id: Ie50ea2ae21fc6da7dcdbb7259726f67f74c61beb
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/13180
Reviewed-by: Tyler Mandry <tmandry@google.com>
Reviewed-by: David Turner <digit@google.com>
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index 213505e..5f3afcb 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -780,8 +780,7 @@
   // rlibs only depended on inside a shared library dependency).
   std::vector<OutputFile> transitive_rustlibs;
   if (target_->IsFinal()) {
-    for (const auto* dep :
-         target_->rust_linkable_inherited_libs().GetOrdered()) {
+    for (const auto* dep : target_->inherited_libraries().GetOrdered()) {
       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/ninja_c_binary_target_writer_unittest.cc b/src/gn/ninja_c_binary_target_writer_unittest.cc
index 630ba28..2aafe92 100644
--- a/src/gn/ninja_c_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_c_binary_target_writer_unittest.cc
@@ -1340,238 +1340,477 @@
 }
 
 // Test linking of Rust dependencies into C targets.
-TEST_F(NinjaCBinaryTargetWriterTest, RustDeps) {
+TEST_F(NinjaCBinaryTargetWriterTest, RustStaticLib) {
   Err err;
   TestWithScope setup;
 
-  {
-    Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
-    library_target.set_output_type(Target::STATIC_LIBRARY);
-    library_target.visibility().SetPublic();
-    SourceFile lib("//foo/lib.rs");
-    library_target.sources().push_back(lib);
-    library_target.source_types_used().Set(SourceFile::SOURCE_RS);
-    library_target.rust_values().set_crate_root(lib);
-    library_target.rust_values().crate_name() = "foo";
-    library_target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(library_target.OnResolved(&err));
+  Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
+  library_target.set_output_type(Target::STATIC_LIBRARY);
+  library_target.visibility().SetPublic();
+  SourceFile lib("//foo/lib.rs");
+  library_target.sources().push_back(lib);
+  library_target.source_types_used().Set(SourceFile::SOURCE_RS);
+  library_target.rust_values().set_crate_root(lib);
+  library_target.rust_values().crate_name() = "foo";
+  library_target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(library_target.OnResolved(&err));
 
-    Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
-    target.set_output_type(Target::EXECUTABLE);
-    target.visibility().SetPublic();
-    target.sources().push_back(SourceFile("//bar/bar.cc"));
-    target.source_types_used().Set(SourceFile::SOURCE_CPP);
-    target.private_deps().push_back(LabelTargetPair(&library_target));
-    target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(target.OnResolved(&err));
+  Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//bar/bar.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&library_target));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
 
-    std::ostringstream out;
-    NinjaCBinaryTargetWriter writer(&target, out);
-    writer.Run();
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
 
-    const char expected[] =
-        "defines =\n"
-        "include_dirs =\n"
-        "cflags =\n"
-        "cflags_cc =\n"
-        "root_out_dir = .\n"
-        "target_out_dir = obj/bar\n"
-        "target_output_name = bar\n"
-        "\n"
-        "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
-        "  source_file_part = bar.cc\n"
-        "  source_name_part = bar\n"
-        "\n"
-        "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a\n"
-        "  ldflags =\n"
-        "  libs =\n"
-        "  frameworks =\n"
-        "  swiftmodules =\n"
-        "  output_extension = \n"
-        "  output_dir = \n";
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/bar\n"
+      "target_output_name = bar\n"
+      "\n"
+      "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
+      "  source_file_part = bar.cc\n"
+      "  source_name_part = bar\n"
+      "\n"
+      "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n";
 
-    std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
-  }
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
 
-  {
-    Target rlib_target(setup.settings(), Label(SourceDir("//baz/"), "lib"));
-    rlib_target.set_output_type(Target::RUST_LIBRARY);
-    rlib_target.visibility().SetPublic();
-    SourceFile bazlib("//baz/lib.rs");
-    rlib_target.sources().push_back(bazlib);
-    rlib_target.source_types_used().Set(SourceFile::SOURCE_RS);
-    rlib_target.rust_values().set_crate_root(bazlib);
-    rlib_target.rust_values().crate_name() = "lib";
-    rlib_target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(rlib_target.OnResolved(&err));
+// Test linking of Rust dependencies into C targets.
+TEST_F(NinjaCBinaryTargetWriterTest, RlibInLibrary) {
+  Err err;
+  TestWithScope setup;
 
-    Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
-    library_target.set_output_type(Target::STATIC_LIBRARY);
-    library_target.visibility().SetPublic();
-    SourceFile lib("//foo/lib.rs");
-    library_target.sources().push_back(lib);
-    library_target.source_types_used().Set(SourceFile::SOURCE_RS);
-    library_target.rust_values().set_crate_root(lib);
-    library_target.rust_values().crate_name() = "foo";
-    library_target.public_deps().push_back(LabelTargetPair(&rlib_target));
-    library_target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(library_target.OnResolved(&err));
+  // This source_set() is depended on by an rlib, which is a private dep of a
+  // static lib.
+  Target priv_sset_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//priv_sset_in_staticlib/"), "priv_sset_in_staticlib"));
+  priv_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
+  priv_sset_in_staticlib.visibility().SetPublic();
+  priv_sset_in_staticlib.sources().push_back(
+      SourceFile("//priv_sset_in_staticlib/lib.cc"));
+  priv_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  priv_sset_in_staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(priv_sset_in_staticlib.OnResolved(&err));
 
-    Target rlib_target2(setup.settings(), Label(SourceDir("//qux/"), "lib2"));
-    rlib_target2.set_output_type(Target::RUST_LIBRARY);
-    rlib_target2.visibility().SetPublic();
-    SourceFile quxlib("//qux/lib.rs");
-    rlib_target2.sources().push_back(quxlib);
-    rlib_target2.source_types_used().Set(SourceFile::SOURCE_RS);
-    rlib_target2.rust_values().set_crate_root(quxlib);
-    rlib_target2.rust_values().crate_name() = "lib2";
-    rlib_target2.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(rlib_target2.OnResolved(&err));
+  // This source_set() is depended on by an rlib, which is a public dep of a
+  // static lib.
+  Target pub_sset_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//pub_sset_in_staticlib/"), "pub_sset_in_staticlib"));
+  pub_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
+  pub_sset_in_staticlib.visibility().SetPublic();
+  pub_sset_in_staticlib.sources().push_back(
+      SourceFile("//pub_sset_in_staticlib/lib.cc"));
+  pub_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  pub_sset_in_staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_sset_in_staticlib.OnResolved(&err));
 
-    Target rlib_target3(setup.settings(), Label(SourceDir("//quxqux/"), "lib3"));
-    rlib_target3.set_output_type(Target::RUST_LIBRARY);
-    rlib_target3.visibility().SetPublic();
-    SourceFile quxquxlib("//quxqux/lib.rs");
-    rlib_target3.sources().push_back(quxquxlib);
-    rlib_target3.source_types_used().Set(SourceFile::SOURCE_RS);
-    rlib_target3.rust_values().set_crate_root(quxlib);
-    rlib_target3.rust_values().crate_name() = "lib3";
-    rlib_target3.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(rlib_target3.OnResolved(&err));
+  // This source_set() is depended on by an rlib, which is a private dep of a
+  // shared lib.
+  Target priv_sset_in_dylib(
+      setup.settings(),
+      Label(SourceDir("//priv_sset_in_dylib/"), "priv_sset_in_dylib"));
+  priv_sset_in_dylib.set_output_type(Target::SOURCE_SET);
+  priv_sset_in_dylib.visibility().SetPublic();
+  priv_sset_in_dylib.sources().push_back(
+      SourceFile("//priv_sset_in_dylib/lib.cc"));
+  priv_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  priv_sset_in_dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(priv_sset_in_dylib.OnResolved(&err));
 
-    Target procmacro(setup.settings(),
-                     Label(SourceDir("//quuxmacro/"), "procmacro"));
-    procmacro.set_output_type(Target::RUST_PROC_MACRO);
-    procmacro.visibility().SetPublic();
-    SourceFile procmacrolib("//procmacro/lib.rs");
-    procmacro.sources().push_back(procmacrolib);
-    procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
-    procmacro.public_deps().push_back(LabelTargetPair(&rlib_target2));
-    procmacro.public_deps().push_back(LabelTargetPair(&rlib_target3));
-    procmacro.rust_values().set_crate_root(procmacrolib);
-    procmacro.rust_values().crate_name() = "procmacro";
-    procmacro.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(procmacro.OnResolved(&err));
+  // This source_set() is depended on by an rlib, which is a public dep of a
+  // shared lib.
+  Target pub_sset_in_dylib(
+      setup.settings(),
+      Label(SourceDir("//pub_sset_in_dylib"), "pub_sset_in_dylib"));
+  pub_sset_in_dylib.set_output_type(Target::SOURCE_SET);
+  pub_sset_in_dylib.visibility().SetPublic();
+  pub_sset_in_dylib.sources().push_back(
+      SourceFile("//pub_sset_in_dylib/lib.cc"));
+  pub_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  pub_sset_in_dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_sset_in_dylib.OnResolved(&err));
 
-    Target rlib_target4(setup.settings(), Label(SourceDir("//quux/"), "lib4"));
-    rlib_target4.set_output_type(Target::RUST_LIBRARY);
-    rlib_target4.visibility().SetPublic();
-    SourceFile quuxlib("//quux/lib.rs");
-    rlib_target4.sources().push_back(quuxlib);
-    rlib_target4.source_types_used().Set(SourceFile::SOURCE_RS);
-    rlib_target4.public_deps().push_back(LabelTargetPair(&rlib_target2));
-    // Transitive proc macros should not impact C++ targets; we're
-    // adding one to ensure the ninja instructions below are unaffected.
-    rlib_target4.public_deps().push_back(LabelTargetPair(&procmacro));
-    rlib_target4.rust_values().set_crate_root(quuxlib);
-    rlib_target4.rust_values().crate_name() = "lib4";
-    rlib_target4.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(rlib_target4.OnResolved(&err));
+  Target priv_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//priv_in_staticlib/"), "priv_in_staticlib"));
+  priv_in_staticlib.set_output_type(Target::RUST_LIBRARY);
+  priv_in_staticlib.visibility().SetPublic();
+  SourceFile priv_in_staticlib_root("//priv_in_staticlib/lib.rs");
+  priv_in_staticlib.sources().push_back(priv_in_staticlib_root);
+  priv_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  priv_in_staticlib.rust_values().set_crate_root(priv_in_staticlib_root);
+  priv_in_staticlib.rust_values().crate_name() = "priv_in_staticlib";
+  priv_in_staticlib.SetToolchain(setup.toolchain());
+  priv_in_staticlib.private_deps().push_back(
+      LabelTargetPair(&priv_sset_in_staticlib));
+  ASSERT_TRUE(priv_in_staticlib.OnResolved(&err));
 
-    Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
-    target.set_output_type(Target::EXECUTABLE);
-    target.visibility().SetPublic();
-    target.sources().push_back(SourceFile("//bar/bar.cc"));
-    target.source_types_used().Set(SourceFile::SOURCE_CPP);
-    target.private_deps().push_back(LabelTargetPair(&library_target));
-    target.private_deps().push_back(LabelTargetPair(&rlib_target4));
-    target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(target.OnResolved(&err));
+  Target pub_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//pub_in_staticlib/"), "pub_in_staticlib"));
+  pub_in_staticlib.set_output_type(Target::RUST_LIBRARY);
+  pub_in_staticlib.visibility().SetPublic();
+  SourceFile pub_in_staticlib_root("//pub_in_staticlib/lib.rs");
+  pub_in_staticlib.sources().push_back(pub_in_staticlib_root);
+  pub_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_staticlib.rust_values().set_crate_root(pub_in_staticlib_root);
+  pub_in_staticlib.rust_values().crate_name() = "pub_in_staticlib";
+  pub_in_staticlib.SetToolchain(setup.toolchain());
+  pub_in_staticlib.private_deps().push_back(
+      LabelTargetPair(&pub_sset_in_staticlib));
+  ASSERT_TRUE(pub_in_staticlib.OnResolved(&err));
 
-    std::ostringstream out;
-    NinjaCBinaryTargetWriter writer(&target, out);
-    writer.Run();
+  Target priv_in_dylib(setup.settings(),
+                       Label(SourceDir("//priv_in_dylib/"), "priv_in_dylib"));
+  priv_in_dylib.set_output_type(Target::RUST_LIBRARY);
+  priv_in_dylib.visibility().SetPublic();
+  SourceFile priv_in_dylib_root("//priv_in_dylib/lib.rs");
+  priv_in_dylib.sources().push_back(priv_in_dylib_root);
+  priv_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  priv_in_dylib.rust_values().set_crate_root(priv_in_dylib_root);
+  priv_in_dylib.rust_values().crate_name() = "priv_in_dylib";
+  priv_in_dylib.SetToolchain(setup.toolchain());
+  priv_in_dylib.private_deps().push_back(LabelTargetPair(&priv_sset_in_dylib));
+  ASSERT_TRUE(priv_in_dylib.OnResolved(&err));
 
-    const char expected[] =
-        "defines =\n"
-        "include_dirs =\n"
-        "cflags =\n"
-        "cflags_cc =\n"
-        "root_out_dir = .\n"
-        "target_out_dir = obj/bar\n"
-        "target_output_name = bar\n"
-        "\n"
-        "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
-        "  source_file_part = bar.cc\n"
-        "  source_name_part = bar\n"
-        "\n"
-        "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a | "
-        "obj/baz/lib.rlib obj/quux/lib4.rlib obj/qux/lib2.rlib\n"
-        "  ldflags =\n"
-        "  libs =\n"
-        "  frameworks =\n"
-        "  swiftmodules =\n"
-        "  output_extension = \n"
-        "  output_dir = \n"
-        "  rlibs = obj/baz/lib.rlib obj/quux/lib4.rlib obj/qux/lib2.rlib\n";
+  Target pub_in_dylib(setup.settings(),
+                      Label(SourceDir("//pub_in_dylib/"), "pub_in_dylib"));
+  pub_in_dylib.set_output_type(Target::RUST_LIBRARY);
+  pub_in_dylib.visibility().SetPublic();
+  SourceFile pub_in_dylib_root("//pub_in_dylib/lib.rs");
+  pub_in_dylib.sources().push_back(pub_in_dylib_root);
+  pub_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_dylib.rust_values().set_crate_root(pub_in_dylib_root);
+  pub_in_dylib.rust_values().crate_name() = "pub_in_dylib";
+  pub_in_dylib.SetToolchain(setup.toolchain());
+  pub_in_dylib.private_deps().push_back(LabelTargetPair(&pub_sset_in_dylib));
+  ASSERT_TRUE(pub_in_dylib.OnResolved(&err));
 
-    std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
-  }
+  Target staticlib(setup.settings(),
+                   Label(SourceDir("//staticlib/"), "staticlib"));
+  staticlib.set_output_type(Target::STATIC_LIBRARY);
+  staticlib.visibility().SetPublic();
+  staticlib.sources().push_back(SourceFile("//staticlib/lib.cc"));
+  staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  staticlib.public_deps().push_back(LabelTargetPair(&pub_in_staticlib));
+  staticlib.private_deps().push_back(LabelTargetPair(&priv_in_staticlib));
+  staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(staticlib.OnResolved(&err));
 
-  {
-    Target procmacro(setup.settings(), Label(SourceDir("//baz/"), "macro"));
-    procmacro.set_output_type(Target::LOADABLE_MODULE);
-    procmacro.visibility().SetPublic();
-    SourceFile bazlib("//baz/lib.rs");
-    procmacro.sources().push_back(bazlib);
-    procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
-    procmacro.rust_values().set_crate_root(bazlib);
-    procmacro.rust_values().crate_name() = "macro";
-    procmacro.rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
-    procmacro.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(procmacro.OnResolved(&err));
+  Target dylib(setup.settings(), Label(SourceDir("//dylib/"), "dylib"));
+  dylib.set_output_type(Target::SHARED_LIBRARY);
+  dylib.visibility().SetPublic();
+  SourceFile dylib_root("//dylib/lib.rs");
+  dylib.sources().push_back(dylib_root);
+  dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  dylib.rust_values().set_crate_root(dylib_root);
+  dylib.rust_values().crate_name() = "dylib";
+  dylib.public_deps().push_back(LabelTargetPair(&pub_in_dylib));
+  dylib.private_deps().push_back(LabelTargetPair(&priv_in_dylib));
+  dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(dylib.OnResolved(&err));
 
-    Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
-    library_target.set_output_type(Target::STATIC_LIBRARY);
-    library_target.visibility().SetPublic();
-    SourceFile lib("//foo/lib.rs");
-    library_target.sources().push_back(lib);
-    library_target.source_types_used().Set(SourceFile::SOURCE_RS);
-    library_target.rust_values().set_crate_root(lib);
-    library_target.rust_values().crate_name() = "foo";
-    library_target.public_deps().push_back(LabelTargetPair(&procmacro));
-    library_target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(library_target.OnResolved(&err));
+  Target target(setup.settings(), Label(SourceDir("//exe/"), "exe"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//exe/main.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&staticlib));
+  target.private_deps().push_back(LabelTargetPair(&dylib));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
 
-    Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
-    target.set_output_type(Target::EXECUTABLE);
-    target.visibility().SetPublic();
-    target.sources().push_back(SourceFile("//bar/bar.cc"));
-    target.source_types_used().Set(SourceFile::SOURCE_CPP);
-    target.private_deps().push_back(LabelTargetPair(&library_target));
-    target.SetToolchain(setup.toolchain());
-    ASSERT_TRUE(target.OnResolved(&err));
 
-    std::ostringstream out;
-    NinjaCBinaryTargetWriter writer(&target, out);
-    writer.Run();
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
 
-    const char expected[] =
-        "defines =\n"
-        "include_dirs =\n"
-        "cflags =\n"
-        "cflags_cc =\n"
-        "root_out_dir = .\n"
-        "target_out_dir = obj/bar\n"
-        "target_output_name = bar\n"
-        "\n"
-        "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
-        "  source_file_part = bar.cc\n"
-        "  source_name_part = bar\n"
-        "\n"
-        "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a\n"
-        "  ldflags =\n"
-        "  libs =\n"
-        "  frameworks =\n"
-        "  swiftmodules =\n"
-        "  output_extension = \n"
-        "  output_dir = \n";
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/exe\n"
+      "target_output_name = exe\n"
+      "\n"
+      "build obj/exe/exe.main.o: cxx ../../exe/main.cc\n"
+      "  source_file_part = main.cc\n"
+      "  source_name_part = main\n"
+      "\n"
+      "build ./exe: link obj/exe/exe.main.o "
+      "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o "
+      "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.lib.o "
+      "obj/staticlib/libstaticlib.a "
+      "obj/dylib/libdylib.so | "
+      "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
+      "obj/priv_in_staticlib/libpriv_in_staticlib.rlib || "
+      "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.stamp "
+      "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.stamp\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n"
+      "  rlibs = obj/pub_in_staticlib/libpub_in_staticlib.rlib "
+      "obj/priv_in_staticlib/libpriv_in_staticlib.rlib\n";
 
-    std::string out_str = out.str();
-    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
-  }
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
+// Test linking of Rust dependencies into C targets. Proc-macro dependencies are
+// not inherited by the targets that depend on them, even from public_deps,
+// since they are not built into those targets, but instead used to build them.
+TEST_F(NinjaCBinaryTargetWriterTest, RlibsWithProcMacros) {
+  Err err;
+  TestWithScope setup;
+
+  Target pub_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//pub_in_staticlib/"), "pub_in_staticlib"));
+  pub_in_staticlib.set_output_type(Target::RUST_LIBRARY);
+  pub_in_staticlib.visibility().SetPublic();
+  SourceFile pub_in_staticlib_root("//pub_in_staticlib/lib.rs");
+  pub_in_staticlib.sources().push_back(pub_in_staticlib_root);
+  pub_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_staticlib.rust_values().set_crate_root(pub_in_staticlib_root);
+  pub_in_staticlib.rust_values().crate_name() = "pub_in_staticlib";
+  pub_in_staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_in_staticlib.OnResolved(&err));
+
+  Target priv_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//priv_in_staticlib/"), "priv_in_staticlib"));
+  priv_in_staticlib.set_output_type(Target::RUST_LIBRARY);
+  priv_in_staticlib.visibility().SetPublic();
+  SourceFile priv_in_staticlib_root("//priv_in_staticlib/lib.rs");
+  priv_in_staticlib.sources().push_back(priv_in_staticlib_root);
+  priv_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  priv_in_staticlib.rust_values().set_crate_root(priv_in_staticlib_root);
+  priv_in_staticlib.rust_values().crate_name() = "priv_in_staticlib";
+  priv_in_staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(priv_in_staticlib.OnResolved(&err));
+
+  Target staticlib(setup.settings(),
+                   Label(SourceDir("//staticlib/"), "staticlib"));
+  staticlib.set_output_type(Target::STATIC_LIBRARY);
+  staticlib.visibility().SetPublic();
+  staticlib.sources().push_back(SourceFile("//staticlib/lib.cc"));
+  staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  staticlib.public_deps().push_back(LabelTargetPair(&pub_in_staticlib));
+  staticlib.private_deps().push_back(LabelTargetPair(&priv_in_staticlib));
+  staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(staticlib.OnResolved(&err));
+
+  Target priv_in_procmacro(
+      setup.settings(),
+      Label(SourceDir("//priv_in_procmacro/"), "priv_in_procmacro"));
+  priv_in_procmacro.set_output_type(Target::RUST_LIBRARY);
+  priv_in_procmacro.visibility().SetPublic();
+  SourceFile priv_in_procmacro_root("//priv_in_procmacro/lib.rs");
+  priv_in_procmacro.sources().push_back(priv_in_procmacro_root);
+  priv_in_procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
+  priv_in_procmacro.rust_values().set_crate_root(priv_in_procmacro_root);
+  priv_in_procmacro.rust_values().crate_name() = "priv_in_procmacro";
+  priv_in_procmacro.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(priv_in_procmacro.OnResolved(&err));
+
+  // Public deps in a proc-macro are not inherited, since the proc-macro is not
+  // compiled into targets that depend on it.
+  Target pub_in_procmacro(
+      setup.settings(),
+      Label(SourceDir("//pub_in_procmacro/"), "pub_in_procmacro"));
+  pub_in_procmacro.set_output_type(Target::RUST_LIBRARY);
+  pub_in_procmacro.visibility().SetPublic();
+  SourceFile pub_in_procmacro_root("//pub_in_procmacro/lib.rs");
+  pub_in_procmacro.sources().push_back(pub_in_procmacro_root);
+  pub_in_procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_procmacro.rust_values().set_crate_root(pub_in_procmacro_root);
+  pub_in_procmacro.rust_values().crate_name() = "pub_in_procmacro";
+  pub_in_procmacro.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_in_procmacro.OnResolved(&err));
+
+  Target pub_in_procmacro_and_rlib(
+      setup.settings(), Label(SourceDir("//pub_in_procmacro_and_rlib/"),
+                              "pub_in_procmacro_and_rlib"));
+  pub_in_procmacro_and_rlib.set_output_type(Target::RUST_LIBRARY);
+  pub_in_procmacro_and_rlib.visibility().SetPublic();
+  SourceFile pub_in_procmacro_and_rlib_root(
+      "//pub_in_procmacro_and_rlib/lib.rs");
+  pub_in_procmacro_and_rlib.sources().push_back(pub_in_procmacro_and_rlib_root);
+  pub_in_procmacro_and_rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_procmacro_and_rlib.rust_values().set_crate_root(
+      pub_in_procmacro_and_rlib_root);
+  pub_in_procmacro_and_rlib.rust_values().crate_name() = "lib2";
+  pub_in_procmacro_and_rlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_in_procmacro_and_rlib.OnResolved(&err));
+
+  Target procmacro(setup.settings(),
+                   Label(SourceDir("//procmacro/"), "procmacro"));
+  procmacro.set_output_type(Target::RUST_PROC_MACRO);
+  procmacro.visibility().SetPublic();
+  SourceFile procmacrolib("//procmacro/lib.rs");
+  procmacro.sources().push_back(procmacrolib);
+  procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
+  procmacro.public_deps().push_back(LabelTargetPair(&pub_in_procmacro));
+  procmacro.public_deps().push_back(LabelTargetPair(&priv_in_procmacro));
+  procmacro.public_deps().push_back(
+      LabelTargetPair(&pub_in_procmacro_and_rlib));
+  procmacro.rust_values().set_crate_root(procmacrolib);
+  procmacro.rust_values().crate_name() = "procmacro";
+  procmacro.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(procmacro.OnResolved(&err));
+
+  Target rlib(setup.settings(), Label(SourceDir("//rlib/"), "rlib"));
+  rlib.set_output_type(Target::RUST_LIBRARY);
+  rlib.visibility().SetPublic();
+  SourceFile rlib_root("//rlib/lib.rs");
+  rlib.sources().push_back(rlib_root);
+  rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  rlib.public_deps().push_back(LabelTargetPair(&pub_in_procmacro_and_rlib));
+  // Transitive proc macros should not impact C++ targets; we're
+  // adding one to ensure the ninja instructions below are unaffected.
+  rlib.public_deps().push_back(LabelTargetPair(&procmacro));
+  rlib.rust_values().set_crate_root(rlib_root);
+  rlib.rust_values().crate_name() = "rlib";
+  rlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(rlib.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//exe/"), "exe"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//exe/main.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&staticlib));
+  target.private_deps().push_back(LabelTargetPair(&rlib));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/exe\n"
+      "target_output_name = exe\n"
+      "\n"
+      "build obj/exe/exe.main.o: cxx ../../exe/main.cc\n"
+      "  source_file_part = main.cc\n"
+      "  source_name_part = main\n"
+      "\n"
+      "build ./exe: link obj/exe/exe.main.o "
+      "obj/staticlib/libstaticlib.a | "
+      "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
+      "obj/priv_in_staticlib/libpriv_in_staticlib.rlib "
+      "obj/rlib/librlib.rlib "
+      "obj/pub_in_procmacro_and_rlib/libpub_in_procmacro_and_rlib.rlib\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n"
+      "  rlibs = obj/pub_in_staticlib/libpub_in_staticlib.rlib "
+      "obj/priv_in_staticlib/libpriv_in_staticlib.rlib "
+      "obj/rlib/librlib.rlib "
+      "obj/pub_in_procmacro_and_rlib/libpub_in_procmacro_and_rlib.rlib\n";
+
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
+// Test linking of Rust dependencies into C targets.
+TEST_F(NinjaCBinaryTargetWriterTest, ProcMacroInRustStaticLib) {
+  Err err;
+  TestWithScope setup;
+
+  Target procmacro(setup.settings(), Label(SourceDir("//baz/"), "macro"));
+  procmacro.set_output_type(Target::LOADABLE_MODULE);
+  procmacro.visibility().SetPublic();
+  SourceFile bazlib("//baz/lib.rs");
+  procmacro.sources().push_back(bazlib);
+  procmacro.source_types_used().Set(SourceFile::SOURCE_RS);
+  procmacro.rust_values().set_crate_root(bazlib);
+  procmacro.rust_values().crate_name() = "macro";
+  procmacro.rust_values().set_crate_type(RustValues::CRATE_PROC_MACRO);
+  procmacro.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(procmacro.OnResolved(&err));
+
+  Target library_target(setup.settings(), Label(SourceDir("//foo/"), "foo"));
+  library_target.set_output_type(Target::STATIC_LIBRARY);
+  library_target.visibility().SetPublic();
+  SourceFile lib("//foo/lib.rs");
+  library_target.sources().push_back(lib);
+  library_target.source_types_used().Set(SourceFile::SOURCE_RS);
+  library_target.rust_values().set_crate_root(lib);
+  library_target.rust_values().crate_name() = "foo";
+  library_target.public_deps().push_back(LabelTargetPair(&procmacro));
+  library_target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(library_target.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//bar/"), "bar"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//bar/bar.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&library_target));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/bar\n"
+      "target_output_name = bar\n"
+      "\n"
+      "build obj/bar/bar.bar.o: cxx ../../bar/bar.cc\n"
+      "  source_file_part = bar.cc\n"
+      "  source_name_part = bar\n"
+      "\n"
+      "build ./bar: link obj/bar/bar.bar.o obj/foo/libfoo.a\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n";
+
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
 }
 
 TEST_F(NinjaCBinaryTargetWriterTest, RustDepsOverDynamicLinking) {
@@ -1680,6 +1919,308 @@
   EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
 }
 
+TEST_F(NinjaCBinaryTargetWriterTest, LinkingWithRustLibraryDepsOnCdylib) {
+  Err err;
+  TestWithScope setup;
+
+  // A non-rust shared library.
+  Target cc_shlib(setup.settings(), Label(SourceDir("//cc_shlib"), "cc_shlib"));
+  cc_shlib.set_output_type(Target::SHARED_LIBRARY);
+  cc_shlib.set_output_name("cc_shlib");
+  cc_shlib.SetToolchain(setup.toolchain());
+  cc_shlib.visibility().SetPublic();
+  ASSERT_TRUE(cc_shlib.OnResolved(&err));
+
+  // A Rust CDYLIB shared library that will be in deps.
+  Target rust_shlib(setup.settings(),
+                    Label(SourceDir("//rust_shlib/"), "rust_shlib"));
+  rust_shlib.set_output_type(Target::SHARED_LIBRARY);
+  rust_shlib.visibility().SetPublic();
+  SourceFile rust_shlib_rs("//rust_shlib/lib.rs");
+  rust_shlib.sources().push_back(rust_shlib_rs);
+  rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  rust_shlib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
+  rust_shlib.rust_values().set_crate_root(rust_shlib_rs);
+  rust_shlib.rust_values().crate_name() = "rust_shlib";
+  rust_shlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(rust_shlib.OnResolved(&err));
+
+  // A Rust DYLIB shared library that will be in public_deps.
+  Target pub_rust_shlib(setup.settings(), Label(SourceDir("//pub_rust_shlib/"),
+                                                "pub_rust_shlib"));
+  pub_rust_shlib.set_output_type(Target::SHARED_LIBRARY);
+  pub_rust_shlib.visibility().SetPublic();
+  SourceFile pub_rust_shlib_rs("//pub_rust_shlib/lib.rs");
+  pub_rust_shlib.sources().push_back(pub_rust_shlib_rs);
+  pub_rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_rust_shlib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
+  pub_rust_shlib.rust_values().set_crate_root(pub_rust_shlib_rs);
+  pub_rust_shlib.rust_values().crate_name() = "pub_rust_shlib";
+  pub_rust_shlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_rust_shlib.OnResolved(&err));
+
+  // An rlib that depends on both shared libraries.
+  Target rlib(setup.settings(), Label(SourceDir("//rlib/"), "rlib"));
+  rlib.set_output_type(Target::RUST_LIBRARY);
+  rlib.visibility().SetPublic();
+  SourceFile rlib_rs("//rlib/lib.rs");
+  rlib.sources().push_back(rlib_rs);
+  rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  rlib.rust_values().set_crate_root(rlib_rs);
+  rlib.rust_values().crate_name() = "rlib";
+  rlib.private_deps().push_back(LabelTargetPair(&rust_shlib));
+  rlib.private_deps().push_back(LabelTargetPair(&cc_shlib));
+  rlib.public_deps().push_back(LabelTargetPair(&pub_rust_shlib));
+  rlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(rlib.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//exe/main.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&rlib));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/exe\n"
+      "target_output_name = binary\n"
+      "\n"
+      "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
+      "  source_file_part = main.cc\n"
+      "  source_name_part = main\n"
+      "\n"
+      "build ./binary: link obj/exe/binary.main.o "
+      "obj/pub_rust_shlib/libpub_rust_shlib.so obj/rust_shlib/librust_shlib.so "
+      "./libcc_shlib.so | "
+      "obj/rlib/librlib.rlib\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n"
+      "  rlibs = obj/rlib/librlib.rlib\n";
+
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
+TEST_F(NinjaCBinaryTargetWriterTest, LinkingWithRustLibraryDepsOnDylib) {
+  Err err;
+  TestWithScope setup;
+
+  // A non-rust shared library.
+  Target cc_shlib(setup.settings(), Label(SourceDir("//cc_shlib"), "cc_shlib"));
+  cc_shlib.set_output_type(Target::SHARED_LIBRARY);
+  cc_shlib.set_output_name("cc_shlib");
+  cc_shlib.SetToolchain(setup.toolchain());
+  cc_shlib.visibility().SetPublic();
+  ASSERT_TRUE(cc_shlib.OnResolved(&err));
+
+  // A Rust DYLIB shared library that will be in deps.
+  Target rust_shlib(setup.settings(),
+                    Label(SourceDir("//rust_shlib/"), "rust_shlib"));
+  rust_shlib.set_output_type(Target::SHARED_LIBRARY);
+  rust_shlib.visibility().SetPublic();
+  SourceFile rust_shlib_rs("//rust_shlib/lib.rs");
+  rust_shlib.sources().push_back(rust_shlib_rs);
+  rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  rust_shlib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
+  rust_shlib.rust_values().set_crate_root(rust_shlib_rs);
+  rust_shlib.rust_values().crate_name() = "rust_shlib";
+  rust_shlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(rust_shlib.OnResolved(&err));
+
+  // A Rust DYLIB shared library that will be in public_deps.
+  Target pub_rust_shlib(setup.settings(), Label(SourceDir("//pub_rust_shlib/"),
+                                                "pub_rust_shlib"));
+  pub_rust_shlib.set_output_type(Target::SHARED_LIBRARY);
+  pub_rust_shlib.visibility().SetPublic();
+  SourceFile pub_rust_shlib_rs("//pub_rust_shlib/lib.rs");
+  pub_rust_shlib.sources().push_back(pub_rust_shlib_rs);
+  pub_rust_shlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_rust_shlib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
+  pub_rust_shlib.rust_values().set_crate_root(pub_rust_shlib_rs);
+  pub_rust_shlib.rust_values().crate_name() = "pub_rust_shlib";
+  pub_rust_shlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_rust_shlib.OnResolved(&err));
+
+  // An rlib that depends on both shared libraries.
+  Target rlib(setup.settings(), Label(SourceDir("//rlib/"), "rlib"));
+  rlib.set_output_type(Target::RUST_LIBRARY);
+  rlib.visibility().SetPublic();
+  SourceFile rlib_rs("//rlib/lib.rs");
+  rlib.sources().push_back(rlib_rs);
+  rlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  rlib.rust_values().set_crate_root(rlib_rs);
+  rlib.rust_values().crate_name() = "rlib";
+  rlib.private_deps().push_back(LabelTargetPair(&rust_shlib));
+  rlib.private_deps().push_back(LabelTargetPair(&cc_shlib));
+  rlib.public_deps().push_back(LabelTargetPair(&pub_rust_shlib));
+  rlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(rlib.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//exe/main.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&rlib));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/exe\n"
+      "target_output_name = binary\n"
+      "\n"
+      "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
+      "  source_file_part = main.cc\n"
+      "  source_name_part = main\n"
+      "\n"
+      "build ./binary: link obj/exe/binary.main.o "
+      "obj/pub_rust_shlib/libpub_rust_shlib.so obj/rust_shlib/librust_shlib.so "
+      "./libcc_shlib.so | "
+      "obj/rlib/librlib.rlib\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n"
+      "  rlibs = obj/rlib/librlib.rlib\n";
+
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
+// Verify dependencies of a shared library and a rust library are inherited
+// independently.
+TEST_F(NinjaCBinaryTargetWriterTest, RustLibAfterSharedLib) {
+  Err err;
+  TestWithScope setup;
+
+  Target static1(setup.settings(),
+                Label(SourceDir("//static1/"), "staticlib1"));
+  static1.set_output_type(Target::STATIC_LIBRARY);
+  static1.visibility().SetPublic();
+  static1.sources().push_back(SourceFile("//static1/c.cc"));
+  static1.source_types_used().Set(SourceFile::SOURCE_CPP);
+  static1.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(static1.OnResolved(&err));
+
+  Target static2(setup.settings(),
+                Label(SourceDir("//static2/"), "staticlib2"));
+  static2.set_output_type(Target::STATIC_LIBRARY);
+  static2.visibility().SetPublic();
+  static2.sources().push_back(SourceFile("//static2/c.cc"));
+  static2.source_types_used().Set(SourceFile::SOURCE_CPP);
+  static2.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(static2.OnResolved(&err));
+
+  Target static3(setup.settings(),
+                Label(SourceDir("//static3/"), "staticlib3"));
+  static3.set_output_type(Target::STATIC_LIBRARY);
+  static3.visibility().SetPublic();
+  static3.sources().push_back(SourceFile("//static3/c.cc"));
+  static3.source_types_used().Set(SourceFile::SOURCE_CPP);
+  static3.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(static3.OnResolved(&err));
+
+  Target shared1(setup.settings(),
+                    Label(SourceDir("//shared1"), "mysharedlib1"));
+  shared1.set_output_type(Target::SHARED_LIBRARY);
+  shared1.set_output_name("mysharedlib1");
+  shared1.set_output_prefix_override("");
+  shared1.SetToolchain(setup.toolchain());
+  shared1.visibility().SetPublic();
+  shared1.private_deps().push_back(LabelTargetPair(&static1));
+  ASSERT_TRUE(shared1.OnResolved(&err));
+
+  Target rlib2(setup.settings(), Label(SourceDir("//rlib2/"), "myrlib2"));
+  rlib2.set_output_type(Target::RUST_LIBRARY);
+  rlib2.visibility().SetPublic();
+  SourceFile lib2("//rlib2/lib.rs");
+  rlib2.sources().push_back(lib2);
+  rlib2.source_types_used().Set(SourceFile::SOURCE_RS);
+  rlib2.rust_values().set_crate_root(lib2);
+  rlib2.rust_values().crate_name() = "foo";
+  rlib2.private_deps().push_back(LabelTargetPair(&static2));
+  rlib2.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(rlib2.OnResolved(&err));
+
+  Target shared3(setup.settings(),
+                    Label(SourceDir("//shared3"), "mysharedlib3"));
+  shared3.set_output_type(Target::SHARED_LIBRARY);
+  shared3.set_output_name("mysharedlib3");
+  shared3.set_output_prefix_override("");
+  shared3.SetToolchain(setup.toolchain());
+  shared3.visibility().SetPublic();
+  shared3.private_deps().push_back(LabelTargetPair(&static3));
+  ASSERT_TRUE(shared3.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//exe/"), "binary"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  target.sources().push_back(SourceFile("//exe/main.cc"));
+  target.source_types_used().Set(SourceFile::SOURCE_CPP);
+  target.private_deps().push_back(LabelTargetPair(&shared1));
+  target.private_deps().push_back(LabelTargetPair(&rlib2));
+  target.private_deps().push_back(LabelTargetPair(&shared3));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+  std::ostringstream out;
+  NinjaCBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "defines =\n"
+      "include_dirs =\n"
+      "cflags =\n"
+      "cflags_cc =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/exe\n"
+      "target_output_name = binary\n"
+      "\n"
+      "build obj/exe/binary.main.o: cxx ../../exe/main.cc\n"
+      "  source_file_part = main.cc\n"
+      "  source_name_part = main\n"
+      "\n"
+      "build ./binary: link obj/exe/binary.main.o "
+      "./mysharedlib1.so ./mysharedlib3.so "
+      "obj/static2/libstaticlib2.a | obj/rlib2/libmyrlib2.rlib\n"
+      "  ldflags =\n"
+      "  libs =\n"
+      "  frameworks =\n"
+      "  swiftmodules =\n"
+      "  output_extension = \n"
+      "  output_dir = \n"
+      "  rlibs = obj/rlib2/libmyrlib2.rlib\n";
+
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
 TEST_F(NinjaCBinaryTargetWriterTest, ModuleMapInStaticLibrary) {
   TestWithScope setup;
   Err err;
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index cc77bfc..308e742 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -253,7 +253,9 @@
         "target_output_name = main\n"
         "\n"
         "build ./main_crate: rust_bin ../../main/main.rs | "
-        "../../main/source.rs ../../main/main.rs obj/foo/libdirect.rlib\n"
+        "../../main/source.rs ../../main/main.rs obj/foo/libdirect.rlib "
+        "obj/bar/libpubliclib.rlib obj/far/libfarlib.rlib "
+        "obj/baz/libprivatelib.rlib\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern direct=obj/foo/libdirect.rlib "
@@ -359,7 +361,7 @@
   dylib.sources().push_back(SourceFile("//bar/mylib.rs"));
   dylib.sources().push_back(barlib);
   dylib.source_types_used().Set(SourceFile::SOURCE_RS);
-  dylib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);  // TODO
+  dylib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
   dylib.rust_values().set_crate_root(barlib);
   dylib.rust_values().crate_name() = "mylib";
   dylib.public_deps().push_back(LabelTargetPair(&inside_dylib));
@@ -397,6 +399,19 @@
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
   }
 
+  Target private_dylib(setup.settings(), Label(SourceDir("//private_dylib/"), "private_dylib"));
+  private_dylib.set_output_type(Target::SHARED_LIBRARY);
+  private_dylib.visibility().SetPublic();
+  SourceFile private_dyliblib("//private_dylib/lib.rs");
+  private_dylib.sources().push_back(SourceFile("//private_dylib/mylib.rs"));
+  private_dylib.sources().push_back(private_dyliblib);
+  private_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  private_dylib.rust_values().set_crate_type(RustValues::CRATE_DYLIB);
+  private_dylib.rust_values().set_crate_root(private_dyliblib);
+  private_dylib.rust_values().crate_name() = "private_dylib";
+  private_dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(private_dylib.OnResolved(&err));
+
   Target another_dylib(setup.settings(), Label(SourceDir("//foo/"), "direct"));
   another_dylib.set_output_type(Target::SHARED_LIBRARY);
   another_dylib.visibility().SetPublic();
@@ -409,6 +424,7 @@
   another_dylib.rust_values().crate_name() = "direct";
   another_dylib.SetToolchain(setup.toolchain());
   another_dylib.public_deps().push_back(LabelTargetPair(&dylib));
+  another_dylib.private_deps().push_back(LabelTargetPair(&private_dylib));
   ASSERT_TRUE(another_dylib.OnResolved(&err));
 
   Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
@@ -441,14 +457,15 @@
         "target_output_name = bar\n"
         "\n"
         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
-        "../../foo/main.rs obj/foo/libdirect.so\n"
+        "../../foo/main.rs obj/foo/libdirect.so obj/bar/libmylib.so\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern direct=obj/foo/libdirect.so "
         "--extern mylib=obj/bar/libmylib.so "
         "--extern inside=obj/baz/libinside.rlib\n"
         "  rustdeps = -Ldependency=obj/foo -Ldependency=obj/bar "
-        "-Ldependency=obj/baz -Ldependency=obj/faz\n"
+        "-Ldependency=obj/baz -Ldependency=obj/faz "
+        "-Ldependency=obj/private_dylib\n"
         "  ldflags =\n"
         "  sources = ../../foo/source.rs ../../foo/main.rs\n";
     std::string out_str = out.str();
@@ -538,7 +555,7 @@
         "target_output_name = libmylib\n"
         "\n"
         "build obj/bar/libmylib.rlib: rust_rlib ../../bar/lib.rs | "
-        "../../bar/mylib.rs ../../bar/lib.rs obj/bar/libmymacro.so || "
+        "../../bar/mylib.rs ../../bar/lib.rs || "
         "obj/baz/group.stamp\n"
         "  source_file_part = lib.rs\n"
         "  source_name_part = lib\n"
@@ -580,8 +597,7 @@
         "target_output_name = bar\n"
         "\n"
         "build ./foo_bar: rust_bin ../../foo/main.rs | "
-        "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib || "
-        "obj/baz/group.stamp\n"
+        "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern mylib=obj/bar/libmylib.rlib "
@@ -671,7 +687,8 @@
         "target_output_name = bar\n"
         "\n"
         "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
-        "../../foo/main.rs obj/bar/libdirect.rlib obj/baz/libmylib.rlib\n"
+        "../../foo/main.rs obj/bar/libdirect.rlib obj/baz/libmylib.rlib "
+        "obj/faz/libtransitive.rlib\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern direct_renamed=obj/bar/libdirect.rlib "
@@ -874,6 +891,195 @@
   }
 }
 
+TEST_F(NinjaRustBinaryTargetWriterTest, RlibInLibrary) {
+  Err err;
+  TestWithScope setup;
+
+  Target priv_sset_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//priv_sset_in_staticlib/"), "priv_sset_in_staticlib"));
+  priv_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
+  priv_sset_in_staticlib.visibility().SetPublic();
+  priv_sset_in_staticlib.sources().push_back(
+      SourceFile("//priv_sset_in_staticlib/lib.cc"));
+  priv_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  priv_sset_in_staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(priv_sset_in_staticlib.OnResolved(&err));
+
+  Target pub_sset_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//pub_sset_in_staticlib/"), "pub_sset_in_staticlib"));
+  pub_sset_in_staticlib.set_output_type(Target::SOURCE_SET);
+  pub_sset_in_staticlib.visibility().SetPublic();
+  pub_sset_in_staticlib.sources().push_back(
+      SourceFile("//pub_sset_in_staticlib/lib.cc"));
+  pub_sset_in_staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  pub_sset_in_staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_sset_in_staticlib.OnResolved(&err));
+
+  Target priv_sset_in_dylib(
+      setup.settings(),
+      Label(SourceDir("//priv_sset_in_dylib/"), "priv_sset_in_dylib"));
+  priv_sset_in_dylib.set_output_type(Target::SOURCE_SET);
+  priv_sset_in_dylib.visibility().SetPublic();
+  priv_sset_in_dylib.sources().push_back(
+      SourceFile("//priv_sset_in_dylib/lib.cc"));
+  priv_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  priv_sset_in_dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(priv_sset_in_dylib.OnResolved(&err));
+
+  Target pub_sset_in_dylib(
+      setup.settings(),
+      Label(SourceDir("//pub_sset_in_dylib"), "pub_sset_in_dylib"));
+  pub_sset_in_dylib.set_output_type(Target::SOURCE_SET);
+  pub_sset_in_dylib.visibility().SetPublic();
+  pub_sset_in_dylib.sources().push_back(
+      SourceFile("//pub_sset_in_dylib/lib.cc"));
+  pub_sset_in_dylib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  pub_sset_in_dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(pub_sset_in_dylib.OnResolved(&err));
+
+  Target priv_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//priv_in_staticlib/"), "priv_in_staticlib"));
+  priv_in_staticlib.set_output_type(Target::RUST_LIBRARY);
+  priv_in_staticlib.visibility().SetPublic();
+  SourceFile priv_in_staticlib_root("//priv_in_staticlib/lib.rs");
+  priv_in_staticlib.sources().push_back(priv_in_staticlib_root);
+  priv_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  priv_in_staticlib.rust_values().set_crate_root(priv_in_staticlib_root);
+  priv_in_staticlib.rust_values().crate_name() = "priv_in_staticlib";
+  priv_in_staticlib.SetToolchain(setup.toolchain());
+  priv_in_staticlib.private_deps().push_back(
+      LabelTargetPair(&priv_sset_in_staticlib));
+  ASSERT_TRUE(priv_in_staticlib.OnResolved(&err));
+
+  Target pub_in_staticlib(
+      setup.settings(),
+      Label(SourceDir("//pub_in_staticlib/"), "pub_in_staticlib"));
+  pub_in_staticlib.set_output_type(Target::RUST_LIBRARY);
+  pub_in_staticlib.visibility().SetPublic();
+  SourceFile pub_in_staticlib_root("//pub_in_staticlib/lib.rs");
+  pub_in_staticlib.sources().push_back(pub_in_staticlib_root);
+  pub_in_staticlib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_staticlib.rust_values().set_crate_root(pub_in_staticlib_root);
+  pub_in_staticlib.rust_values().crate_name() = "pub_in_staticlib";
+  pub_in_staticlib.SetToolchain(setup.toolchain());
+  pub_in_staticlib.private_deps().push_back(
+      LabelTargetPair(&pub_sset_in_staticlib));
+  ASSERT_TRUE(pub_in_staticlib.OnResolved(&err));
+
+  Target priv_in_dylib(setup.settings(),
+                       Label(SourceDir("//priv_in_dylib/"), "priv_in_dylib"));
+  priv_in_dylib.set_output_type(Target::RUST_LIBRARY);
+  priv_in_dylib.visibility().SetPublic();
+  SourceFile priv_in_dylib_root("//priv_in_dylib/lib.rs");
+  priv_in_dylib.sources().push_back(priv_in_dylib_root);
+  priv_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  priv_in_dylib.rust_values().set_crate_root(priv_in_dylib_root);
+  priv_in_dylib.rust_values().crate_name() = "priv_in_dylib";
+  priv_in_dylib.SetToolchain(setup.toolchain());
+  priv_in_dylib.private_deps().push_back(LabelTargetPair(&priv_sset_in_dylib));
+  ASSERT_TRUE(priv_in_dylib.OnResolved(&err));
+
+  Target pub_in_dylib(setup.settings(),
+                      Label(SourceDir("//pub_in_dylib/"), "pub_in_dylib"));
+  pub_in_dylib.set_output_type(Target::RUST_LIBRARY);
+  pub_in_dylib.visibility().SetPublic();
+  SourceFile pub_in_dylib_root("//pub_in_dylib/lib.rs");
+  pub_in_dylib.sources().push_back(pub_in_dylib_root);
+  pub_in_dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  pub_in_dylib.rust_values().set_crate_root(pub_in_dylib_root);
+  pub_in_dylib.rust_values().crate_name() = "pub_in_dylib";
+  pub_in_dylib.SetToolchain(setup.toolchain());
+  pub_in_dylib.private_deps().push_back(LabelTargetPair(&pub_sset_in_dylib));
+  ASSERT_TRUE(pub_in_dylib.OnResolved(&err));
+
+  Target staticlib(setup.settings(),
+                   Label(SourceDir("//staticlib/"), "staticlib"));
+  staticlib.set_output_type(Target::STATIC_LIBRARY);
+  staticlib.visibility().SetPublic();
+  staticlib.sources().push_back(SourceFile("//staticlib/lib.cc"));
+  staticlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+  staticlib.public_deps().push_back(LabelTargetPair(&pub_in_staticlib));
+  staticlib.private_deps().push_back(LabelTargetPair(&priv_in_staticlib));
+  staticlib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(staticlib.OnResolved(&err));
+
+  Target dylib(setup.settings(), Label(SourceDir("//dylib/"), "dylib"));
+  dylib.set_output_type(Target::SHARED_LIBRARY);
+  dylib.visibility().SetPublic();
+  SourceFile dylib_root("//dylib/lib.rs");
+  dylib.sources().push_back(dylib_root);
+  dylib.source_types_used().Set(SourceFile::SOURCE_RS);
+  dylib.rust_values().set_crate_root(dylib_root);
+  dylib.rust_values().crate_name() = "dylib";
+  dylib.public_deps().push_back(LabelTargetPair(&pub_in_dylib));
+  dylib.private_deps().push_back(LabelTargetPair(&priv_in_dylib));
+  dylib.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(dylib.OnResolved(&err));
+
+  Target target(setup.settings(), Label(SourceDir("//exe/"), "exe"));
+  target.set_output_type(Target::EXECUTABLE);
+  target.visibility().SetPublic();
+  SourceFile main("//exe/main.rs");
+  target.sources().push_back(main);
+  target.source_types_used().Set(SourceFile::SOURCE_RS);
+  target.rust_values().set_crate_root(main);
+  target.rust_values().crate_name() = "exe";
+  target.private_deps().push_back(LabelTargetPair(&staticlib));
+  target.private_deps().push_back(LabelTargetPair(&dylib));
+  target.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(target.OnResolved(&err));
+
+
+  std::ostringstream out;
+  NinjaRustBinaryTargetWriter writer(&target, out);
+  writer.Run();
+
+  const char expected[] =
+      "crate_name = exe\n"
+      "crate_type = bin\n"
+      "output_extension = \n"
+      "output_dir = \n"
+      "rustflags =\n"
+      "rustenv =\n"
+      "root_out_dir = .\n"
+      "target_out_dir = obj/exe\n"
+      "target_output_name = exe\n"
+      "\n"
+      "build ./exe: rust_bin ../../exe/main.rs | "
+      "../../exe/main.rs "
+      "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o "
+      "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.lib.o "
+      "obj/staticlib/libstaticlib.a "
+      "obj/dylib/libdylib.so "
+      "obj/pub_in_staticlib/libpub_in_staticlib.rlib "
+      "obj/priv_in_staticlib/libpriv_in_staticlib.rlib || "
+      "obj/pub_sset_in_staticlib/pub_sset_in_staticlib.stamp "
+      "obj/priv_sset_in_staticlib/priv_sset_in_staticlib.stamp\n"
+      "  source_file_part = main.rs\n"
+      "  source_name_part = main\n"
+      "  externs = "
+      "--extern pub_in_staticlib=obj/pub_in_staticlib/libpub_in_staticlib.rlib "
+      "--extern dylib=obj/dylib/libdylib.so "
+      "--extern pub_in_dylib=obj/pub_in_dylib/libpub_in_dylib.rlib\n"
+      "  rustdeps = -Ldependency=obj/pub_in_staticlib "
+      "-Ldependency=obj/priv_in_staticlib -Ldependency=obj/dylib "
+      "-Ldependency=obj/pub_in_dylib -Ldependency=obj/priv_in_dylib "
+      "-Lnative=obj/pub_sset_in_staticlib "
+      "-Lnative=obj/priv_sset_in_staticlib "
+      "-Lnative=obj/staticlib -Clink-arg=-Bdynamic "
+      "-Clink-arg=obj/pub_sset_in_staticlib/pub_sset_in_staticlib.lib.o "
+      "-Clink-arg=obj/priv_sset_in_staticlib/priv_sset_in_staticlib.lib.o "
+      "-Clink-arg=obj/staticlib/libstaticlib.a\n"
+      "  ldflags =\n"
+      "  sources = ../../exe/main.rs\n";
+
+  std::string out_str = out.str();
+  EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+}
+
 TEST_F(NinjaRustBinaryTargetWriterTest, RustOutputExtensionAndDir) {
   Err err;
   TestWithScope setup;
@@ -1175,8 +1381,9 @@
         "target_out_dir = obj/foo\n"
         "target_output_name = bar\n"
         "\n"
-        "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs "
-        "../../foo/main.rs obj/bar/libmylib.rlib || obj/baz/group.stamp\n"
+        "build ./foo_bar: rust_bin ../../foo/main.rs | "
+        "../../foo/source.rs ../../foo/main.rs obj/bar/libmylib.rlib || "
+        "obj/baz/group.stamp\n"
         "  source_file_part = main.rs\n"
         "  source_name_part = main\n"
         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 53c6510..55649d4 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -760,13 +760,14 @@
   if (dep->output_type() == STATIC_LIBRARY ||
       dep->output_type() == SHARED_LIBRARY ||
       dep->output_type() == RUST_LIBRARY ||
-      dep->output_type() == RUST_PROC_MACRO ||
       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 ||
       dep->output_type() == SHARED_LIBRARY ||
       dep->output_type() == RUST_LIBRARY || dep->output_type() == GROUP) {
@@ -775,8 +776,12 @@
     // The `this` target has direct access to `dep` since its a direct
     // dependency, regardless of the edge being a public_dep or not, so we pass
     // true for public-ness. Whereas, anything depending on `this` can only gain
-    // direct access to `dep` if the edge between `this` and `dep` is public,
-    // so we pass `is_public`.
+    // direct access to `dep` if the edge between `this` and `dep` is public, so
+    // we pass `is_public`.
+    //
+    // TODO(danakj): We should only need to track Rust rlibs or dylibs here, as
+    // it's used for passing to rustc with --extern. We currently track
+    // everything then drop non-Rust libs in ninja_rust_binary_target_writer.cc.
     rust_transitive_inherited_libs_.Append(dep, true);
     rust_transitive_inheritable_libs_.Append(dep, is_public);
 
@@ -791,32 +796,8 @@
     rust_transitive_inherited_libs_.Append(dep, true);
     rust_transitive_inheritable_libs_.Append(dep, is_public);
   }
-  if (!dep->IsFinal()) {
-    // A "final" dependency is not an rlib, so while a final dependency would be
-    // part of another linking target, we don't inherit it here. Example:
-    //
-    //   [bin E] -> [rlib A] -> [so D] -> [rlib B]
-    //
-    // The [so D] is linked into [bin E] along with [rlib A]. But we didn't add
-    // the edge to [so D] as an inherited rlib.
-    rust_linkable_inherited_libs_.Append(dep, true);
-    // Gathers the set of rlibs that are part of the current target's final
-    // linking target.
-    rust_linkable_inherited_libs_.AppendInherited(
-        dep->rust_linkable_inherited_libs(), true);
-  }
 
-  if (dep->output_type() == RUST_LIBRARY ||
-      RustValues::InferredCrateType(dep) == RustValues::CRATE_DYLIB) {
-    // Transitive dependencies behind a library (shared or static), that would
-    // be consumed by rustc, gets bumped up to this target.
-    for (const auto& [inherited, inherited_is_public] :
-         rust_transitive_inheritable_libs_.GetOrderedAndPublicFlag()) {
-      if (!RustValues::IsRustLibrary(inherited)) {
-        inherited_libraries_.Append(inherited, inherited_is_public);
-      }
-    }
-  } else if (dep->output_type() == SHARED_LIBRARY) {
+  if (dep->output_type() == SHARED_LIBRARY) {
     // Shared library dependendencies are inherited across public shared
     // library boundaries.
     //
@@ -839,22 +820,37 @@
     // resolved by the compiler.
     inherited_libraries_.AppendPublicSharedLibraries(dep->inherited_libraries(),
                                                      is_public);
-  } else if (!dep->IsFinal()) {
-    // The current target isn't linked, so propagate linked deps and
-    // libraries up the dependency tree.
-    inherited_libraries_.AppendInherited(dep->inherited_libraries(), 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 :
-         dep->inherited_libraries().GetOrderedAndPublicFlag()) {
-      if (inherited.first->IsFinal()) {
-        inherited_libraries_.Append(inherited.first,
-                                    is_public && inherited.second);
+  } 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);
       }
     }
   }
diff --git a/src/gn/target.h b/src/gn/target.h
index 31d4e3a..de076a8 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -322,12 +322,6 @@
   const InheritedLibraries& rust_transitive_inheritable_libs() const {
     return rust_transitive_inheritable_libs_;
   }
-  // The transitive closure of libraries that are depended on by this target
-  // and are part of the current linking step. Previously-linked libraries are
-  // not included.
-  const InheritedLibraries& rust_linkable_inherited_libs() const {
-    return rust_linkable_inherited_libs_;
-  }
 
   const UniqueVector<SourceDir>& all_lib_dirs() const { return all_lib_dirs_; }
   const UniqueVector<LibFile>& all_libs() const { return all_libs_; }
@@ -540,10 +534,6 @@
   // For each library marked public: "If you depend on me, you get access to
   // these targets."
   InheritedLibraries rust_transitive_inheritable_libs_;
-  // Lists all transitive libraries in the current linking target. Unlike the
-  // two sets above, this does not include libraries that have already been
-  // linked into a dependency. The public bit is ignored.
-  InheritedLibraries rust_linkable_inherited_libs_;
 
   // User for Swift targets.
   std::unique_ptr<SwiftValues> swift_values_;