Ensure dynamic library dependencies end up in the runfiles directory (#2671)
Right now the runfiles directory only contains "data" that is attached
to a rust_binary() or one of its dependencies. This is inconsistent with
cc_binary() and go_binary(), which also include an `_solib_*/` directory
containing shared library dependencies.
When doing a plain 'bazel run' against the resulting executable, this is
not a noticeable issue. The reason being that the runtime dynamic linker
will use `${execroot}/_solib_*`. However, it does become a problem when
`pkg_tar(include_runfiles = True)` is used to construct an archive of
the binary so that it can be placed in a container image.
This change extends the runfiles gathering logic to merge all
LibraryToLink.dynamic_library files in there as well.
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 98806f1..6dbb258 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -1444,8 +1444,18 @@
experimental_use_coverage_metadata_files = toolchain._experimental_use_coverage_metadata_files
+ dynamic_libraries = [
+ library_to_link.dynamic_library
+ for dep in getattr(ctx.attr, "deps", [])
+ if CcInfo in dep
+ for linker_input in dep[CcInfo].linking_context.linker_inputs.to_list()
+ for library_to_link in linker_input.libraries
+ if _is_dylib(library_to_link)
+ ]
runfiles = ctx.runfiles(
- files = getattr(ctx.files, "data", []) + ([] if experimental_use_coverage_metadata_files else coverage_runfiles),
+ files = getattr(ctx.files, "data", []) +
+ ([] if experimental_use_coverage_metadata_files else coverage_runfiles) +
+ dynamic_libraries,
collect_data = True,
)
if getattr(ctx.attr, "crate", None):
diff --git a/test/cc_shared_library/BUILD.bazel b/test/cc_shared_library/BUILD.bazel
index 82e1fb1..e5145d6 100644
--- a/test/cc_shared_library/BUILD.bazel
+++ b/test/cc_shared_library/BUILD.bazel
@@ -1,5 +1,5 @@
-load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
-load("@rules_rust//rust:defs.bzl", "rust_static_library")
+load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library", "cc_test")
+load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_static_library")
rust_static_library(
name = "rust_lib",
@@ -28,3 +28,30 @@
linkstatic = True,
deps = [":c_lib"],
)
+
+NOT_WINDOWS = select({
+ "@platforms//os:linux": [],
+ "@platforms//os:macos": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+})
+
+cc_import(
+ name = "shared_import",
+ shared_library = ":shared",
+ target_compatible_with = NOT_WINDOWS,
+)
+
+rust_binary(
+ name = "linked_against_shared",
+ srcs = ["linked_against_shared.rs"],
+ edition = "2018",
+ target_compatible_with = NOT_WINDOWS,
+ deps = [":shared_import"],
+)
+
+sh_test(
+ name = "runfiles_contains_shared",
+ srcs = ["runfiles_contains_shared.sh"],
+ data = [":linked_against_shared"],
+ target_compatible_with = NOT_WINDOWS,
+)
diff --git a/test/cc_shared_library/linked_against_shared.rs b/test/cc_shared_library/linked_against_shared.rs
new file mode 100644
index 0000000..57a2490
--- /dev/null
+++ b/test/cc_shared_library/linked_against_shared.rs
@@ -0,0 +1,6 @@
+extern "C" {
+ fn foo() -> i32;
+}
+fn main() {
+ println!("{}", unsafe { foo() })
+}
diff --git a/test/cc_shared_library/runfiles_contains_shared.sh b/test/cc_shared_library/runfiles_contains_shared.sh
new file mode 100755
index 0000000..612229f
--- /dev/null
+++ b/test/cc_shared_library/runfiles_contains_shared.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set -eux
+
+# Validate that the runfiles directory actually contains the shared
+# library against which the Rust binary is linked.
+test -n "$(find ${RUNFILES_DIR} -name 'libshared.*')"