Fixing Rust targets depending on C source sets.

Previously, such source sets were ignored. Rust targets now link them in
correctly.

Change-Id: I9d19eb872064b6a888ff5c1829d000e8773b8751
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/8220
Reviewed-by: Brett Wilson <brettw@chromium.org>
Reviewed-by: Petr Hosek <phosek@google.com>
Commit-Queue: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index abe903f..983d92f 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -108,8 +108,20 @@
 // TODO(juliehockett): add inherited library support? and IsLinkable support?
 // for c-cross-compat
 void NinjaRustBinaryTargetWriter::Run() {
+  DCHECK(target_->output_type() != Target::SOURCE_SET);
+
   OutputFile input_dep = WriteInputsStampAndGetDep();
 
+  WriteCompilerVars();
+
+  // Classify our dependencies.
+  UniqueVector<const Target*> linkable_deps;
+  UniqueVector<const Target*> non_linkable_deps;
+  UniqueVector<const Target*> framework_deps;
+  UniqueVector<OutputFile> extra_obj_files;
+  GetDeps(&extra_obj_files, &linkable_deps, &non_linkable_deps,
+          &framework_deps);
+
   // The input dependencies will be an order-only dependency. This will cause
   // Ninja to make sure the inputs are up to date before compiling this source,
   // but changes in the inputs deps won't cause the file to be recompiled. See
@@ -117,24 +129,21 @@
   size_t num_stamp_uses = target_->sources().size();
   std::vector<OutputFile> order_only_deps = WriteInputDepsStampAndGetDep(
       std::vector<const Target*>(), num_stamp_uses);
-
-  // Public rust_library deps go in a --extern rlibs, public non-rust deps go in
-  // -Ldependency rustdeps, and non-public source_sets get passed in as normal
-  // source files
-  UniqueVector<OutputFile> deps;
-  DCHECK(target_->output_type() != Target::SOURCE_SET);
-  WriteCompilerVars();
-  UniqueVector<const Target*> linkable_deps;
-  UniqueVector<const Target*> non_linkable_deps;
-  UniqueVector<const Target*> framework_deps;
-  GetDeps(&deps, &linkable_deps, &non_linkable_deps, &framework_deps);
-  AppendSourcesToImplicitDeps(&deps);
-
   if (!input_dep.value().empty())
     order_only_deps.push_back(input_dep);
 
+  // Build lists which will go into different bits of the rustc command line.
+  // Public rust_library deps go in a --extern rlibs, public non-rust deps go in
+  // -Ldependency. Also assemble a list of extra (i.e. implicit) deps
+  // for ninja dependency tracking.
+  UniqueVector<OutputFile> implicit_deps;
+  AppendSourcesToImplicitDeps(&implicit_deps);
+  implicit_deps.Append(extra_obj_files.begin(), extra_obj_files.end());
+
   std::vector<OutputFile> rustdeps;
   std::vector<OutputFile> nonrustdeps;
+  nonrustdeps.insert(nonrustdeps.end(), extra_obj_files.begin(),
+                     extra_obj_files.end());
   for (const auto* framework_dep : framework_deps) {
     order_only_deps.push_back(framework_dep->dependency_output_file());
   }
@@ -151,7 +160,7 @@
     } else {
       nonrustdeps.push_back(linkable_dep->link_output_file());
     }
-    deps.push_back(linkable_dep->dependency_output_file());
+    implicit_deps.push_back(linkable_dep->dependency_output_file());
   }
 
   // Rust libraries specified by paths.
@@ -159,12 +168,13 @@
     const ConfigValues& cur = iter.cur();
     for (const auto& e : cur.externs()) {
       if (e.second.is_source_file()) {
-        deps.push_back(
+        implicit_deps.push_back(
             OutputFile(settings_->build_settings(), e.second.source_file()));
       }
     }
   }
 
+  // Bubble up the full list of transitive rlib dependencies.
   std::vector<OutputFile> transitive_rustlibs;
   for (const auto* dep :
        target_->rust_values().transitive_libs().GetOrdered()) {
@@ -176,8 +186,9 @@
   std::vector<OutputFile> tool_outputs;
   SubstitutionWriter::ApplyListToLinkerAsOutputFile(
       target_, tool_, tool_->outputs(), &tool_outputs);
-  WriteCompilerBuildLine(target_->rust_values().crate_root(), deps.vector(),
-                         order_only_deps, tool_->name(), tool_outputs);
+  WriteCompilerBuildLine(target_->rust_values().crate_root(),
+                         implicit_deps.vector(), order_only_deps, tool_->name(),
+                         tool_outputs);
 
   std::vector<const Target*> extern_deps(linkable_deps.vector());
   std::copy(non_linkable_deps.begin(), non_linkable_deps.end(),
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index 70a7d00..7cfd63d 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -372,6 +372,14 @@
   sharedlib.SetToolchain(setup.toolchain());
   ASSERT_TRUE(sharedlib.OnResolved(&err));
 
+  Target csourceset(setup.settings(), Label(SourceDir("//baz/"), "sourceset"));
+  csourceset.set_output_type(Target::SOURCE_SET);
+  csourceset.visibility().SetPublic();
+  csourceset.sources().push_back(SourceFile("//baz/csourceset.cpp"));
+  csourceset.source_types_used().Set(SourceFile::SOURCE_CPP);
+  csourceset.SetToolchain(setup.toolchain());
+  ASSERT_TRUE(csourceset.OnResolved(&err));
+
   Toolchain toolchain_with_toc(
       setup.settings(), Label(SourceDir("//toolchain_with_toc/"), "with_toc"));
   TestWithScope::SetupToolchain(&toolchain_with_toc, true);
@@ -396,6 +404,7 @@
   nonrust.private_deps().push_back(LabelTargetPair(&rlib));
   nonrust.private_deps().push_back(LabelTargetPair(&staticlib));
   nonrust.private_deps().push_back(LabelTargetPair(&sharedlib));
+  nonrust.private_deps().push_back(LabelTargetPair(&csourceset));
   nonrust.private_deps().push_back(LabelTargetPair(&sharedlib_with_toc));
   nonrust.SetToolchain(setup.toolchain());
   ASSERT_TRUE(nonrust.OnResolved(&err));
@@ -417,11 +426,14 @@
         "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/foo/libstatic.a "
-        "./libshared.so ./libshared_with_toc.so.TOC\n"
+        "../../foo/main.rs obj/baz/sourceset.csourceset.o "
+        "obj/bar/libmylib.rlib "
+        "obj/foo/libstatic.a ./libshared.so ./libshared_with_toc.so.TOC "
+        "|| obj/baz/sourceset.stamp\n"
         "  externs = --extern mylib=obj/bar/libmylib.rlib\n"
-        "  rustdeps = -Ldependency=obj/bar -Lnative=obj/foo -Lnative=. "
-        "-lstatic -lshared -lshared_with_toc\n";
+        "  rustdeps = -Ldependency=obj/bar -Lnative=obj/baz -Lnative=obj/foo "
+        "-Lnative=. -Clink-arg=obj/baz/sourceset.csourceset.o -lstatic "
+        "-lshared -lshared_with_toc\n";
     std::string out_str = out.str();
     EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
   }