Fix Rust linking -lfoo.so not -lfoo due to TOC
Some toolchains generate a .so.TOC as well as a .so file when creating
shared libraries; they did not previously link correctly into downstream
Rust targets because the generated Ninja rules asked to link to -lfoo.so
rather than -lfoo.
The unit test code here is a bit verbose. It seemed desirable to test
with a toolchain that generates TOC files and one that does not.
However, that may be overkill.
Bug: crbug.com/gn/137
Change-Id: I30918957f8da187c5a1fc3e8f76d91fe5fda494f
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/7020
Reviewed-by: Adrian Taylor <adetaylor@chromium.org>
Reviewed-by: Brett Wilson <brettw@chromium.org>
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 729bfc7..2ac1978 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -87,8 +87,8 @@
WriteVar(kRustSubstitutionCrateType.ninja_name, crate_type, opts, out);
WriteVar(SubstitutionOutputExtension.ninja_name,
- SubstitutionWriter::GetLinkerSubstitution(target, tool,
- &SubstitutionOutputExtension),
+ SubstitutionWriter::GetLinkerSubstitution(
+ target, tool, &SubstitutionOutputExtension),
opts, out);
WriteVar(SubstitutionOutputDir.ninja_name,
SubstitutionWriter::GetLinkerSubstitution(target, tool,
@@ -146,9 +146,9 @@
}
for (const auto* linkable_dep : linkable_deps) {
if (linkable_dep->source_types_used().RustSourceUsed()) {
- rustdeps.push_back(linkable_dep->dependency_output_file());
+ rustdeps.push_back(linkable_dep->link_output_file());
} else {
- nonrustdeps.push_back(linkable_dep->dependency_output_file());
+ nonrustdeps.push_back(linkable_dep->link_output_file());
}
deps.push_back(linkable_dep->dependency_output_file());
}
@@ -184,13 +184,11 @@
EscapeOptions opts = GetFlagOptions();
WriteCrateVars(target_, tool_, opts, out_);
- WriteOneFlag(target_, &kRustSubstitutionRustFlags, false,
- Tool::kToolNone, &ConfigValues::rustflags, opts,
- path_output_, out_);
+ WriteOneFlag(target_, &kRustSubstitutionRustFlags, false, Tool::kToolNone,
+ &ConfigValues::rustflags, opts, path_output_, out_);
- WriteOneFlag(target_, &kRustSubstitutionRustEnv, false,
- Tool::kToolNone, &ConfigValues::rustenv, opts,
- path_output_, out_);
+ WriteOneFlag(target_, &kRustSubstitutionRustEnv, false, Tool::kToolNone,
+ &ConfigValues::rustenv, opts, path_output_, out_);
WriteSharedVars(subst);
}
@@ -250,18 +248,19 @@
const std::string_view lib_prefix("lib");
// Non-Rust native dependencies.
- for (const auto& rustdep : nonrustdeps) {
+ for (const auto& nonrustdep : nonrustdeps) {
out_ << " -Lnative=";
path_output_.WriteDir(
- out_, rustdep.AsSourceFile(settings_->build_settings()).GetDir(),
+ out_, nonrustdep.AsSourceFile(settings_->build_settings()).GetDir(),
PathOutput::DIR_NO_LAST_SLASH);
- std::string_view file = FindFilenameNoExtension(&rustdep.value());
+ std::string_view file = FindFilenameNoExtension(&nonrustdep.value());
if (!file.compare(0, lib_prefix.size(), lib_prefix)) {
out_ << " -l";
- EscapeStringToStream(out_, file.substr(lib_prefix.size()), lib_escape_opts);
+ EscapeStringToStream(out_, file.substr(lib_prefix.size()),
+ lib_escape_opts);
} else {
out_ << " -Clink-arg=";
- path_output_.WriteFile(out_, rustdep);
+ path_output_.WriteFile(out_, nonrustdep);
}
}
diff --git a/src/gn/ninja_rust_binary_target_writer_unittest.cc b/src/gn/ninja_rust_binary_target_writer_unittest.cc
index d581b21..44ff61c 100644
--- a/src/gn/ninja_rust_binary_target_writer_unittest.cc
+++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -269,6 +269,26 @@
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();
+ sharedlib.sources().push_back(SourceFile("//foo/static.cpp"));
+ sharedlib.source_types_used().Set(SourceFile::SOURCE_CPP);
+ sharedlib.SetToolchain(setup.toolchain());
+ ASSERT_TRUE(sharedlib.OnResolved(&err));
+
+ Toolchain toolchain_with_toc(
+ setup.settings(), Label(SourceDir("//toolchain_with_toc/"), "with_toc"));
+ TestWithScope::SetupToolchain(&toolchain_with_toc, true);
+ Target sharedlib_with_toc(setup.settings(),
+ Label(SourceDir("//foo/"), "shared_with_toc"));
+ sharedlib_with_toc.set_output_type(Target::SHARED_LIBRARY);
+ sharedlib_with_toc.visibility().SetPublic();
+ sharedlib_with_toc.sources().push_back(SourceFile("//foo/static.cpp"));
+ sharedlib_with_toc.source_types_used().Set(SourceFile::SOURCE_CPP);
+ sharedlib_with_toc.SetToolchain(&toolchain_with_toc);
+ ASSERT_TRUE(sharedlib_with_toc.OnResolved(&err));
+
Target nonrust(setup.settings(), Label(SourceDir("//foo/"), "bar"));
nonrust.set_output_type(Target::EXECUTABLE);
nonrust.visibility().SetPublic();
@@ -280,6 +300,8 @@
nonrust.rust_values().crate_name() = "foo_bar";
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(&sharedlib_with_toc));
nonrust.SetToolchain(setup.toolchain());
ASSERT_TRUE(nonrust.OnResolved(&err));
@@ -300,9 +322,11 @@
"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\n"
+ "../../foo/main.rs obj/bar/libmylib.rlib obj/foo/libstatic.a "
+ "./libshared.so ./libshared_with_toc.so.TOC\n"
" externs = --extern mylib=obj/bar/libmylib.rlib\n"
- " rustdeps = -Ldependency=obj/bar -Lnative=obj/foo -lstatic\n";
+ " rustdeps = -Ldependency=obj/bar -Lnative=obj/foo -lstatic "
+ "-Lnative=. -lshared -Lnative=. -lshared_with_toc\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 06a8772..dda4b2a 100644
--- a/src/gn/test_with_scope.cc
+++ b/src/gn/test_with_scope.cc
@@ -69,7 +69,7 @@
}
// static
-void TestWithScope::SetupToolchain(Toolchain* toolchain) {
+void TestWithScope::SetupToolchain(Toolchain* toolchain, bool use_toc) {
Err err;
// CC
@@ -137,8 +137,18 @@
solink_tool->set_lib_dir_switch("-L");
solink_tool->set_output_prefix("lib");
solink_tool->set_default_output_extension(".so");
- solink_tool->set_outputs(SubstitutionList::MakeForTest(
- "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
+ if (use_toc) {
+ solink_tool->set_outputs(SubstitutionList::MakeForTest(
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC",
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
+ solink_tool->set_link_output(SubstitutionPattern::MakeForTest(
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
+ solink_tool->set_depend_output(SubstitutionPattern::MakeForTest(
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.TOC"));
+ } else {
+ solink_tool->set_outputs(SubstitutionList::MakeForTest(
+ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"));
+ }
toolchain->SetTool(std::move(solink));
// SOLINK_MODULE
@@ -232,7 +242,8 @@
toolchain->SetTool(std::move(dylib_tool));
// RUST_PROC_MACRO
- std::unique_ptr<Tool> rust_proc_macro_tool = Tool::CreateTool(RustTool::kRsToolMacro);
+ std::unique_ptr<Tool> rust_proc_macro_tool =
+ Tool::CreateTool(RustTool::kRsToolMacro);
SetCommandForTool(
"{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
"--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
@@ -258,7 +269,8 @@
toolchain->SetTool(std::move(rlib_tool));
// STATICLIB
- std::unique_ptr<Tool> staticlib_tool = Tool::CreateTool(RustTool::kRsToolStaticlib);
+ std::unique_ptr<Tool> staticlib_tool =
+ Tool::CreateTool(RustTool::kRsToolStaticlib);
SetCommandForTool(
"{{rustenv}} rustc --crate-name {{crate_name}} {{source}} "
"--crate-type {{crate_type}} {{rustflags}} -o {{output}} "
diff --git a/src/gn/test_with_scope.h b/src/gn/test_with_scope.h
index de1f967..6292b6c 100644
--- a/src/gn/test_with_scope.h
+++ b/src/gn/test_with_scope.h
@@ -57,7 +57,10 @@
// The toolchain in this object will be automatically set up with this
// function, it is exposed to allow tests to get the same functionality for
// other toolchains they make.
- static void SetupToolchain(Toolchain* toolchain);
+ // Two slightly different toolchains can be generated by this function,
+ // based on the use_toc argument. This is only currently required by
+ // one test.
+ static void SetupToolchain(Toolchain* toolchain, bool use_toc = false);
// Sets the given text command on the given tool, parsing it as a
// substitution pattern. This will assert if the input is malformed. This is