`rust_test(crate = ...)` does not stage the crate's transitive dynamic libraries into runfiles
Maintainer thường phản hồi trong vòng 2 ngày
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 88/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- rust
- Lĩnh vực
- build-system
Hướng nghiên cứu
Bắt đầu trong rust/private/rustc.bzl tại rustc_compile_action và so sánh vòng lặp runfiles của dynamic library với _compute_rpaths và dep_info.transitive_noncrates. Chạy bản tái hiện Bazel được cung cấp bằng bazel test //repro:all --cache_test_results=no; hoàn tất khi bài kiểm thử dựa trên crate stage libfoo.so và không thay đổi hành vi của bài kiểm thử dựa trên deps.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
rustc_compile_action stages a binary's CcInfo dynamic libraries into its runfiles by walking only the rule's own deps attribute, while _compute_rpaths walks the full transitive linker-input set. A rust_test that reaches a dynamic library only through its crate attribute therefore links against it, has DT_NEEDED for it and a RUNPATH into the _solib_<cpu> directory where Bazel would stage it, but the file is never put in the runfiles. The test then fails at loader time on any host that has no copy of the library on the system search path (a sandbox, a remote executor, CI).
The same crate exposed through a rust_library listed in deps works, because establish_cc_info merges the transitive CcInfo into the library's own provider, so the deps-only walk happens to see it.
Reproduction
# BUILD.bazel
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
cc_binary(
name = "libfoo.so",
srcs = ["foo.c"],
linkshared = True,
)
cc_import(
name = "foo",
shared_library = ":libfoo.so",
)
rust_library(
name = "uses_foo",
srcs = ["lib.rs"],
deps = [":foo"],
)
# Reaches libfoo.so only through `crate`.
rust_test(
name = "uses_foo_crate_test",
crate = ":uses_foo",
)
# Reaches libfoo.so through a rust_library in `deps`.
rust_test(
name = "uses_foo_deps_test",
srcs = ["test.rs"],
deps = [":uses_foo"],
)
// foo.c
int foo_answer(void) { return 42; }
// lib.rs
unsafe extern "C" {
fn foo_answer() -> i32;
}
pub fn answer() -> i32 {
unsafe { foo_answer() }
}
#[cfg(test)]
mod tests {
#[test]
fn answers() {
assert_eq!(super::answer(), 42);
}
}
// test.rs
#[test]
fn answers() {
assert_eq!(uses_foo::answer(), 42);
}
$ bazel test //repro:all --cache_test_results=no
//repro:uses_foo_deps_test PASSED in 0.0s
//repro:uses_foo_crate_test FAILED in 0.0s
$ cat bazel-testlogs/repro/uses_foo_crate_test/test.log
.../uses_foo_crate_test: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
Observed
Both binaries link identically. readelf -d on each shows the same entries:
(RUNPATH) Library runpath: [$ORIGIN/../../../_solib_k8/_U_S_Srepro_Cfoo___Urepro]
(NEEDED) Shared library: [libfoo.so]
Only the runfiles differ. From bazel cquery --output=starlark over providers(target)["DefaultInfo"].default_runfiles.files:
//repro:uses_foo_crate_test: uses_foo_crate_test
//repro:uses_foo_deps_test: libfoo.so, uses_foo_deps_test
Expected
A binary's runfiles contain every dynamic library its link consumed, i.e. the same set the rpath computation already walks. Whether a dylib is reached via deps or via crate should not change what is shipped.
Cause
rust/private/rustc.bzl, in rustc_compile_action (0.70.0, lines 1753–1762; main has the same loop plus link_deps):
if crate_info.type in ["bin", "cdylib", "staticlib"]:
dynamic_libraries = ctx.runfiles(files = [
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) and library_to_link.dynamic_library
])
transitive_runfiles.append(dynamic_libraries)
ctx.attr.crate is not in ctx.attr.deps, and the crate's own DefaultInfo.default_runfiles (merged a few lines above) carry no dylibs because an rlib is not in the ["bin", "cdylib", "staticlib"] set. _compute_rpaths, by contrast, iterates dep_info.transitive_noncrates, which collect_deps builds from crate_info.deps and therefore does include the crate's dependencies.
Proposed fix
Iterate the same transitive set the rpath computation uses. dep_info is already in scope. This cannot add anything the binary does not need: _is_dylib keeps only libraries that were linked dynamically, which are exactly the ones the binary has as DT_NEEDED.
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -1751,11 +1751,15 @@
for target in runfiles_attr:
transitive_runfiles.append(target[DefaultInfo].default_runfiles)
if crate_info.type in ["bin", "cdylib", "staticlib"]:
+ # Stage every dynamic library the link consumed, walking the same
+ # transitive set `_compute_rpaths` does. Walking only `ctx.attr.deps`
+ # misses a dylib reached solely through a `rust_test(crate = ...)`'s
+ # crate: the binary NEEDs it and its rpath points at the solib dir, but
+ # the file is never shipped, so it fails at loader time wherever the
+ # host has no copy.
dynamic_libraries = ctx.runfiles(files = [
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 linker_input in dep_info.transitive_noncrates.to_list()
for library_to_link in linker_input.libraries
if _is_dylib(library_to_link) and library_to_link.dynamic_library
])
With this applied, the crate = test above stages libfoo.so and passes. In a larger repository, diffing default_runfiles for 16 rust_test/rust_binary targets before and after the change altered only the one target that used crate =; every other target's runfiles were byte-identical, as expected from the establish_cc_info merge.
Environment
- rules_rust 0.70.0 (bzlmod); the loop is unchanged on
mainas of 0.74.0 - Bazel 9.2.0, Linux x86_64
- Reproduces locally under sandboxing and on remote execution; passes on a host that happens to have the library on the default loader path, which is why it is easy to miss
- Ngôn ngữ chính
- Starlark
- Star
- 854
- Fork
- 684
- Merge trung bình
- 2 ngày 22 giờ
- Pull request đã merge (30 ngày)
- 21
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của bazelbuild/rules_rust
-
MSVC stdlib_linkflags miss kernel32.lib and ntdll.libCó thể đã có người làm @TrapsterDK đã nhận 4 ngày trước. Đang mởneeds-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
bazelbuild/rules_rust#4375 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
bazelbuild/rules_rust#4266 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
bazelbuild/rules_rust#4223 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 90/100
bazelbuild/rules_rust#4152 · 1 reaction ·
Maintainer thường phản hồi trong vòng 2 ngày
-
awaiting-response
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
bazelbuild/rules_rust#3599 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của bazelbuild/rules_rust
Issue tương tự
-
complexity: trivial help wanted
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
dunia-hub/stellar-402-live#45 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
JustAResearcher/gpu-unlock-ada#145 · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 89/100
jotaijs/jotai-babel#10 ·
-
flac's CMake config is brokenĐang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
msys2/MINGW-packages#33356 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày