Always link dependencies into Rust static libraries Rust handling of static libraries differs from C/C++ where we always need to link all dependencies, but they are not considered final. Change-Id: I843b0d0b9db435560b5b6da75f0696852a11ace8 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/10500 Reviewed-by: Brett Wilson <brettw@chromium.org> Commit-Queue: Petr Hosek <phosek@google.com>
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc index 08e8c93..e4b0652 100644 --- a/src/gn/ninja_binary_target_writer.cc +++ b/src/gn/ninja_binary_target_writer.cc
@@ -159,14 +159,22 @@ if (can_link_libs && dep->swift_values().builds_module()) classified_deps->swiftmodule_deps.push_back(dep); - if (dep->output_type() == Target::SOURCE_SET || - // If a complete static library depends on an incomplete static library, - // manually link in the object files of the dependent library as if it - // were a source set. This avoids problems with braindead tools such as - // ar which don't properly link dependent static libraries. - (target_->complete_static_lib() && - (dep->output_type() == Target::STATIC_LIBRARY && - !dep->complete_static_lib()))) { + if (target_->source_types_used().RustSourceUsed() && + (target_->output_type() == Target::RUST_LIBRARY || + target_->output_type() == Target::STATIC_LIBRARY) && + dep->IsLinkable()) { + // Rust libraries and static libraries aren't final, but need to have the + // link lines of all transitive deps specified. + classified_deps->linkable_deps.push_back(dep); + } else if (dep->output_type() == Target::SOURCE_SET || + // If a complete static library depends on an incomplete static + // library, manually link in the object files of the dependent + // library as if it were a source set. This avoids problems with + // braindead tools such as ar which don't properly link dependent + // static libraries. + (target_->complete_static_lib() && + (dep->output_type() == Target::STATIC_LIBRARY && + !dep->complete_static_lib()))) { // Source sets have their object files linked into final targets // (shared libraries, executables, loadable modules, and complete static // libraries). Intermediate static libraries and other source sets @@ -182,11 +190,6 @@ // can be complete. Otherwise, these will be skipped since this target // will depend only on the source set's object files. classified_deps->non_linkable_deps.push_back(dep); - } else if (target_->output_type() == Target::RUST_LIBRARY && - dep->IsLinkable()) { - // Rust libraries aren't final, but need to have the link lines of all - // transitive deps specified. - classified_deps->linkable_deps.push_back(dep); } else if (target_->complete_static_lib() && dep->IsFinal()) { classified_deps->non_linkable_deps.push_back(dep); } else if (can_link_libs && dep->IsLinkable()) {
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc index 34d87f0..e58572b 100644 --- a/src/gn/ninja_rust_binary_target_writer_unittest.cc +++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -351,6 +351,14 @@ Err err; TestWithScope setup; + Target staticlib(setup.settings(), Label(SourceDir("//foo/"), "static")); + staticlib.set_output_type(Target::STATIC_LIBRARY); + staticlib.visibility().SetPublic(); + staticlib.sources().push_back(SourceFile("//foo/static.cpp")); + staticlib.source_types_used().Set(SourceFile::SOURCE_CPP); + staticlib.SetToolchain(setup.toolchain()); + ASSERT_TRUE(staticlib.OnResolved(&err)); + Target rlib(setup.settings(), Label(SourceDir("//bar/"), "mylib")); rlib.set_output_type(Target::RUST_LIBRARY); rlib.visibility().SetPublic(); @@ -363,14 +371,6 @@ rlib.SetToolchain(setup.toolchain()); ASSERT_TRUE(rlib.OnResolved(&err)); - Target staticlib(setup.settings(), Label(SourceDir("//foo/"), "static")); - staticlib.set_output_type(Target::STATIC_LIBRARY); - staticlib.visibility().SetPublic(); - staticlib.sources().push_back(SourceFile("//foo/static.cpp")); - staticlib.source_types_used().Set(SourceFile::SOURCE_CPP); - staticlib.SetToolchain(setup.toolchain()); - ASSERT_TRUE(staticlib.OnResolved(&err)); - Target sharedlib(setup.settings(), Label(SourceDir("//foo/"), "shared")); sharedlib.set_output_type(Target::SHARED_LIBRARY); sharedlib.visibility().SetPublic(); @@ -482,6 +482,43 @@ std::string out_str = out.str(); EXPECT_EQ(expected, out_str) << expected << "\n" << out_str; } + + Target rstaticlib(setup.settings(), Label(SourceDir("//baz/"), "baz")); + rstaticlib.set_output_type(Target::STATIC_LIBRARY); + rstaticlib.visibility().SetPublic(); + SourceFile bazlib("//baz/lib.rs"); + rstaticlib.sources().push_back(bazlib); + rstaticlib.source_types_used().Set(SourceFile::SOURCE_RS); + rstaticlib.rust_values().set_crate_root(bazlib); + rstaticlib.rust_values().crate_name() = "baz"; + rstaticlib.private_deps().push_back(LabelTargetPair(&staticlib)); + rstaticlib.SetToolchain(setup.toolchain()); + ASSERT_TRUE(rstaticlib.OnResolved(&err)); + + { + std::ostringstream out; + NinjaRustBinaryTargetWriter writer(&rstaticlib, out); + writer.Run(); + + const char expected[] = + "crate_name = baz\n" + "crate_type = staticlib\n" + "output_extension = .a\n" + "output_dir = \n" + "rustflags =\n" + "rustenv =\n" + "root_out_dir = .\n" + "target_out_dir = obj/baz\n" + "target_output_name = libbaz\n" + "\n" + "build obj/baz/libbaz.a: rust_staticlib ../../baz/lib.rs | ../../baz/lib.rs " + "obj/foo/libstatic.a\n" + " externs =\n" + " rustdeps = -Lnative=obj/foo -lstatic\n" + " sources = ../../baz/lib.rs\n"; + std::string out_str = out.str(); + EXPECT_EQ(expected, out_str) << expected << "\n" << out_str; + } } TEST_F(NinjaRustBinaryTargetWriterTest, RustOutputExtensionAndDir) {