bazelbuild / rules_rust

Rust rules for Bazel
https://bazelbuild.github.io/rules_rust/
Apache License 2.0
666 stars 428 forks source link

Cannot link rust_static_library in a rust_binary target #1063

Closed boxdot closed 2 years ago

boxdot commented 2 years ago

The symbols from rust_static_library are not found when linking it to the rust_binary target via deps. In the invocation of the linker the path to the library directory is added via -L, however there is not library parameter with -l. Also note that the library has a numeric suffix generated from its name.

A workaround is possible via defining a cc_library target, linking the rust_static_library to it, and then using it in the rust_binary target.

Example BUILD file and repository to reproduce:

https://github.com/boxdot/bazel-rust-linking-issue/blob/fc92fb2b6384c78f9a5df95035c5dd882ad11694/BUILD.bazel

UebelAndre commented 2 years ago

@hlopko curious what your thoughts are on this interaction. Not quite sure how to triage this.

hlopko commented 2 years ago

Hey @boxdot thank you for the repro, it was super helpful. There are indeed various bugs that I think I hacked out in https://github.com/bazelbuild/rules_rust/pull/1219 (however that draft is not ready for submission, it needs tests and potentially polishing - feel free to take over :). See the draft description for details.

On a different level though a question begs to be asked - why are you using rust_static_library if you are using rust_binary for linking? I believe that rustc doesn't support this scenario. Why not use rust_library?

boxdot commented 2 years ago

Thank you for providing a possible fix.

why are you using rust_static_library

As in my example, the dependency is on the C-level. It is not a usual Rust crate dependency. The rust lib implements a C-API. The final rust binary uses the C-API loosely via linking the needed symbols. So, we need to link the library as static library into the Rust binary. C-API is important here, because in a real-world scenario, the rust binary might link different implementations of the C-API. Or, the Rust implementation of the C-API can be linked into different binaries (Rust or not).

hlopko commented 2 years ago

I see, then I'm afraid rustc doesn't really support your use case right now. The staticlib crate output contains allocators shims generated, and bin crate output also generates them. The linking fails with duplicated symbols (on linux, I haven't tested on mac, but even if it passed there it wouldn't be a robust solution). There is nothing we can do on rules_rust side to fix it.

Is it an option to use cc_binary instead of rust_binary? That is fully supported by rules_rust and by rustc.

scentini commented 2 years ago

https://github.com/bazelbuild/rules_rust/pull/1298 and https://github.com/bazelbuild/rules_rust/pull/1222 took care of rules_rust issues uncovered here, however as @hlopko notes in https://github.com/bazelbuild/rules_rust/pull/1219:

it is actually not supported to link rust_static_library into a rust_binary. From rustc docs:

--crate-type=staticlib, #[crate_type = "staticlib"] - A static system library will be produced. This is different from other library outputs in that the compiler will never attempt to link to staticlib outputs. The purpose of this output type is to create a static library containing all of the local crate's code along with all upstream dependencies. This output type will create .a files on Linux, macOS and Windows (MinGW), and .lib files on Windows (MSVC). This format is recommended for use in situations such as linking Rust code into an existing non-Rust application because it will not have dynamic dependencies on other Rust code.

https://doc.rust-lang.org/reference/linkage.html#linkage.

At HEAD, bazel-rust-linking-issue now fails with duplicate symbols:

note: duplicate symbol '___rust_alloc_error_handler' in:
              bazel-out/darwin-fastbuild/bin/rust_binary.46d3zwq56yl4ofng.rcgu.o
              bazel-out/darwin-fastbuild/bin/librust_c_lib.a(rust_c_lib.46voediov2mf69ue.rcgu.o)
...
ld: 5 duplicate symbols for architecture x86_64

As there's nothing we can do about this, should we close this issue?

keith commented 2 years ago

In other rule sets with rules that are explicitly only used for archiving targets to use outside of bazel, they sometimes don't propagate the right providers to be included up the dependency tree. rules_apple has a few of these. Maybe rust_static_library should do the same? and just propagate the files via DefaultInfo?

hlopko commented 2 years ago

Hi Keith, yeah this is exactly what @scentini did in https://github.com/bazelbuild/rules_rust/pull/1298.

hlopko commented 2 years ago

I believe we can close this issue now. Please let me know if there's something I missed.