Fix linking dynamic libraries in Rust binaries An earlier commit, 646a62e, changed how Rust links against native dependencies. Rather than a `-l...` argument to instruct rustc to link against the specified library, GN uses `-Clink-arg=` to bypass rustc and directly instruct the linker to link the native library. This has a few implications: normally, Rust uses the `-Bstatic` and `-Bdynamic` linker arguments to tell the linker whether or not to link dynamic binaries. These flags take effect for the rest of the arguments specified (or until another one of the flags changes the mode). rustc has logic to ensure that these flags are emitted correctly, switching the mode as necessary when it outputs linker arguments to link objects of each type. Bypassing rustc via `-Clink-arg` prevents this logic from being used, and so it may be the case that, when rustc is building up the linker arguments, it's already emitted a `-Bstatic` flag, causing the linker arguments to be in the wrong mode when we emit the arguments to link the native libraries. Specicially, we cannot pass a dynamic object when the linker is in static-only mode. This commit addresses this issue by emitting a `-Bdynamic` linker argument before emitting the `-Clink-arg` arguments for the native libraries, ensuring that the linker is always in a mode that allows linking dynamic libraries. Change-Id: I79c1f285e661dc7e4638b1374b718fbbc4f31049 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/12000 Reviewed-by: Tyler Mandry <tmandry@google.com> Commit-Queue: Tyler Mandry <tmandry@google.com>
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc index 73cc9e8..afdf5d9 100644 --- a/src/gn/ninja_rust_binary_target_writer.cc +++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -316,6 +316,12 @@ out_ << " -Lnative="; path_output_.WriteDir(out_, nonrustdep_dir, PathOutput::DIR_NO_LAST_SLASH); } + // Before outputting any libraries to link, ensure the linker is in a mode + // that allows dynamic linking, as rustc may have previously put it into + // static-only mode. + if (nonrustdeps.size() > 0) { + out_ << " -Clink-arg=-Bdynamic"; + } for (const auto& nonrustdep : nonrustdeps) { out_ << " -Clink-arg="; 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 d130abb..8d3f07e 100644 --- a/src/gn/ninja_rust_binary_target_writer_unittest.cc +++ b/src/gn/ninja_rust_binary_target_writer_unittest.cc
@@ -448,7 +448,7 @@ " externs = --extern mylib=obj/bar/libmylib.rlib\n" " rustdeps = -Ldependency=obj/bar " "-Lnative=obj/baz -Lnative=obj/foo -Lnative=. " - "-Clink-arg=obj/baz/sourceset.csourceset.o " + "-Clink-arg=-Bdynamic -Clink-arg=obj/baz/sourceset.csourceset.o " "-Clink-arg=obj/foo/libstatic.a -Clink-arg=./libshared.so " "-Clink-arg=./libshared_with_toc.so\n" " ldflags =\n" @@ -488,7 +488,8 @@ "build ./foo_bar: rust_bin ../../foo/main.rs | ../../foo/source.rs " "../../foo/main.rs obj/foo/libstatic.a\n" " externs =\n" - " rustdeps = -Lnative=obj/foo -Clink-arg=obj/foo/libstatic.a\n" + " rustdeps = -Lnative=obj/foo -Clink-arg=-Bdynamic " + "-Clink-arg=obj/foo/libstatic.a\n" " ldflags =\n" " sources = ../../foo/source.rs ../../foo/main.rs\n"; std::string out_str = out.str(); @@ -527,7 +528,8 @@ "../../baz/lib.rs " "obj/foo/libstatic.a\n" " externs =\n" - " rustdeps = -Lnative=obj/foo -Clink-arg=obj/foo/libstatic.a\n" + " rustdeps = -Lnative=obj/foo -Clink-arg=-Bdynamic " + "-Clink-arg=obj/foo/libstatic.a\n" " ldflags =\n" " sources = ../../baz/lib.rs\n"; std::string out_str = out.str(); @@ -981,7 +983,7 @@ "../../foo/main.rs obj/bar/libmylib.so\n" " externs =\n" " rustdeps = -Ldependency=obj/bar -Lnative=obj/bar " - "-Clink-arg=obj/bar/libmylib.so\n" + "-Clink-arg=-Bdynamic -Clink-arg=obj/bar/libmylib.so\n" " ldflags =\n" " sources = ../../foo/source.rs ../../foo/main.rs\n"; std::string out_str = out.str();