Don't link Rust libraries and proc macros to C targets

These are incompatible, so just ignore them.

Change-Id: Iae0db6221fd1238efbc21ee981557fee32db99e5
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/5940
Commit-Queue: Petr Hosek <phosek@google.com>
Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/tools/gn/ninja_c_binary_target_writer.cc b/tools/gn/ninja_c_binary_target_writer.cc
index 594fec5..a777cbf 100644
--- a/tools/gn/ninja_c_binary_target_writer.cc
+++ b/tools/gn/ninja_c_binary_target_writer.cc
@@ -458,6 +458,10 @@
         << "No link output file for "
         << target_->label().GetUserVisibleName(false);
 
+    if (cur->output_type() == Target::RUST_LIBRARY ||
+        cur->rust_values().crate_type() == RustValues::CRATE_PROC_MACRO)
+      continue;
+
     if (cur->dependency_output_file().value() !=
         cur->link_output_file().value()) {
       // This is a shared library with separate link and deps files. Save for
diff --git a/tools/gn/ninja_c_binary_target_writer_unittest.cc b/tools/gn/ninja_c_binary_target_writer_unittest.cc
index 3281176..874616f 100644
--- a/tools/gn/ninja_c_binary_target_writer_unittest.cc
+++ b/tools/gn/ninja_c_binary_target_writer_unittest.cc
@@ -1185,3 +1185,172 @@
     EXPECT_EQ(expected, out.str());
   }
 }
+
+// Test linking of Rust dependencies into C targets.
+TEST_F(NinjaCBinaryTargetWriterTest, RustDeps) {
+  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 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"
+        "\n"
+        "build ./bar: link obj/bar/bar.bar.o obj/foo/foo.a\n"
+        "  ldflags =\n"
+        "  libs =\n"
+        "  output_extension = \n"
+        "  output_dir = \n";
+
+    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));
+
+    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));
+
+    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"
+        "\n"
+        "build ./bar: link obj/bar/bar.bar.o obj/foo/foo.a\n"
+        "  ldflags =\n"
+        "  libs =\n"
+        "  output_extension = \n"
+        "  output_dir = \n";
+
+    std::string out_str = out.str();
+    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  }
+
+  {
+    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"
+        "\n"
+        "build ./bar: link obj/bar/bar.bar.o obj/foo/foo.a\n"
+        "  ldflags =\n"
+        "  libs =\n"
+        "  output_extension = \n"
+        "  output_dir = \n";
+
+    std::string out_str = out.str();
+    EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+  }
+}