Allow Rust targets to link against Rust cdylibs
There was previously a deficiency in the Rust binary target
generator that caused GN to fail to emit a link argument for
Rust cdylib dependencies.
This fixes the issue by linking against Rust cdylibs the same way
that other non-Rust native dependencies are handled. This also
fixes an issue in the unit test toolchain that prevented Rust
cdylib/dylib outputs from being set.
Fixes https://bugs.chromium.org/p/gn/issues/detail?id=233 .
Change-Id: Ief9c5f0dd652c0430ada756cbe09b5800d069962
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/11320
Reviewed-by: Brett Wilson <brettw@chromium.org>
Reviewed-by: Tyler Mandry <tmandry@google.com>
Commit-Queue: Brett Wilson <brettw@chromium.org>
diff --git a/src/gn/json_project_writer_unittest.cc b/src/gn/json_project_writer_unittest.cc
index a22511b..1915c30 100644
--- a/src/gn/json_project_writer_unittest.cc
+++ b/src/gn/json_project_writer_unittest.cc
@@ -172,7 +172,7 @@
"lib_switch": "-l",
"linker_arg": "-Clink-arg=",
"output_prefix": "lib",
- "outputs": [ "" ]
+ "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
},
"rust_dylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -182,7 +182,7 @@
"lib_switch": "-l",
"linker_arg": "-Clink-arg=",
"output_prefix": "lib",
- "outputs": [ "" ]
+ "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
},
"rust_macro": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -391,7 +391,7 @@
"lib_switch": "-l",
"linker_arg": "-Clink-arg=",
"output_prefix": "lib",
- "outputs": [ "" ]
+ "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
},
"rust_dylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -401,7 +401,7 @@
"lib_switch": "-l",
"linker_arg": "-Clink-arg=",
"output_prefix": "lib",
- "outputs": [ "" ]
+ "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
},
"rust_macro": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -634,7 +634,7 @@
"lib_switch": "-l",
"linker_arg": "-Clink-arg=",
"output_prefix": "lib",
- "outputs": [ "" ]
+ "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
},
"rust_dylib": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
@@ -644,7 +644,7 @@
"lib_switch": "-l",
"linker_arg": "-Clink-arg=",
"output_prefix": "lib",
- "outputs": [ "" ]
+ "outputs": [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
},
"rust_macro": {
"command": "{{rustenv}} rustc --crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}} -o {{output}} {{rustdeps}} {{externs}}",
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index 38f4686..568c2b4 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -154,7 +154,9 @@
order_only_deps.push_back(non_linkable_dep->dependency_output_file());
}
for (const auto* linkable_dep : classified_deps.linkable_deps) {
- if (linkable_dep->source_types_used().RustSourceUsed()) {
+ // Rust cdylibs are treated as non-Rust dependencies for linking purposes.
+ if (linkable_dep->source_types_used().RustSourceUsed() &&
+ linkable_dep->rust_values().crate_type() != RustValues::CRATE_CDYLIB) {
rustdeps.push_back(linkable_dep->link_output_file());
} else {
nonrustdeps.push_back(linkable_dep->link_output_file());
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index 6840b72..a65a961 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -890,3 +890,80 @@
EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
}
}
+
+TEST_F(NinjaRustBinaryTargetWriterTest, CdylibDeps) {
+ Err err;
+ TestWithScope setup;
+ Target cdylib(setup.settings(), Label(SourceDir("//bar/"), "mylib"));
+ cdylib.set_output_type(Target::SHARED_LIBRARY);
+ cdylib.visibility().SetPublic();
+ SourceFile barlib("//bar/lib.rs");
+ cdylib.sources().push_back(barlib);
+ cdylib.source_types_used().Set(SourceFile::SOURCE_RS);
+ cdylib.rust_values().set_crate_type(RustValues::CRATE_CDYLIB);
+ cdylib.rust_values().set_crate_root(barlib);
+ cdylib.rust_values().crate_name() = "mylib";
+ cdylib.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(cdylib.OnResolved(&err));
+ {
+ std::ostringstream out;
+ NinjaRustBinaryTargetWriter writer(&cdylib, out);
+ writer.Run();
+ const char expected[] =
+ "crate_name = mylib\n"
+ "crate_type = cdylib\n"
+ "output_extension = .so\n"
+ "output_dir = \n"
+ "rustflags =\n"
+ "rustenv =\n"
+ "root_out_dir = .\n"
+ "target_out_dir = obj/bar\n"
+ "target_output_name = libmylib\n"
+ "\n"
+ "build obj/bar/libmylib.so: rust_cdylib ../../bar/lib.rs | "
+ "../../bar/lib.rs\n"
+ " externs =\n"
+ " rustdeps =\n"
+ " sources = ../../bar/lib.rs\n";
+ std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+
+ Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+ target.set_output_type(Target::EXECUTABLE);
+ target.visibility().SetPublic();
+ SourceFile main("//foo/main.rs");
+ target.sources().push_back(SourceFile("//foo/source.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() = "foo_bar";
+ target.private_deps().push_back(LabelTargetPair(&cdylib));
+ target.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(target.OnResolved(&err));
+ {
+ std::ostringstream out;
+ NinjaRustBinaryTargetWriter writer(&target, out);
+ writer.Run();
+
+ const char expected[] =
+ "crate_name = foo_bar\n"
+ "crate_type = bin\n"
+ "output_extension = \n"
+ "output_dir = \n"
+ "rustflags =\n"
+ "rustenv =\n"
+ "root_out_dir = .\n"
+ "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.so\n"
+ " externs =\n"
+ " rustdeps = -Ldependency=obj/bar -Lnative=obj/bar "
+ "-Clink-arg=obj/bar/libmylib.so\n"
+ " sources = ../../foo/source.rs ../../foo/main.rs\n";
+ std::string out_str = out.str();
+ EXPECT_EQ(expected, out_str) << expected << "\n" << out_str;
+ }
+}
diff --git a/src/gn/test_with_scope.cc b/src/gn/test_with_scope.cc
index 583eebb..757dd34 100644
--- a/src/gn/test_with_scope.cc
+++ b/src/gn/test_with_scope.cc
@@ -252,7 +252,7 @@
cdylib_tool->set_output_prefix("lib");
cdylib_tool->set_default_output_extension(".so");
cdylib_tool->set_outputs(SubstitutionList::MakeForTest(
- "{{root_output_dir}}/{{target_output_name}}{{output_extension}}"));
+ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
toolchain->SetTool(std::move(cdylib_tool));
// DYLIB
@@ -265,7 +265,7 @@
dylib_tool->set_output_prefix("lib");
dylib_tool->set_default_output_extension(".so");
dylib_tool->set_outputs(SubstitutionList::MakeForTest(
- "{{root_output_dir}}/{{target_output_name}}{{output_extension}}"));
+ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"));
toolchain->SetTool(std::move(dylib_tool));
// RUST_PROC_MACRO