-
Notifications
You must be signed in to change notification settings - Fork 466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recommendation for allocators when linking with C* binary #1238
Comments
Does the same program link on x86_64 (Mac or Linux)? It could just be a bogus platform name, we've hit that before: https://github.com/bazelbuild/rules_rust/pull/806/files |
Ah sorry I meant to attach my repro case too rustrepro.zip, this + |
So also interestingly, this is avoided if you use |
Thinking more about the rust_static_library workaround, maybe it would make sense to include a single rust_static_library in your build graph, to get the allocator infra, and then use everything else as a rust_library, similar to how you would inject a single cc_library in the build graph |
@hlopko wondering if you have any thoughts here. |
Hi folks, You're right, 802bcf9 was created so we have a way to provide those allocator shims to the linker somehow. Internally we use pretty much exactly what you found in chromium. Ideally we would get a supported solution upstream. rust-lang/rust#73632 is the tracking bug. In the meantime we will probably continue with the workaround like chromium does. FTR, we don't expect to support custom allocators in our Bazel setup, we will use the allocator configured for C++ through |
I think |
It is still valid, but I'm not sure if we want it to be 😛? |
Yes, there is a benefit to propagating a |
If it helps, I added a full working example in #1350. It takes a bit to set up, but I think it will work somewhat robustly this way. Rust toolchain changes may break it, but I don't think any recent ones would. A setup based on that PR works with all my toolchains, which include cross compiling with both GCC and Clang, and linking with llvm-ld and GNU ld. |
Nice, I also have a demo with mobile in https://github.com/keith/bazel-rust-mobile-demo/ |
I suspect your approach will fail when building a cc_test with more complex codebases keith. It's definitely simpler, and if the caveats are acceptable then it looks nice, but I'd like to lay out some things for you or others who try using it. Also reasons why this is not a good approach for rules_rust to adopt. If you use llvm-ld or another linker which ignores the traditional Unix linker search algorithm and just searches all objects, then none of this applies, it'll work great. If I'm understanding it correctly, you only have a dependency from one rust_library to the allocator shim implementation, which means the shared objects built for each library in test mode (at least for cc_library, not sure what rust_library currently does) won't have those symbols, so they won't link. You could add that to the deps of each rust_library manually, but that gets pretty tedious, especially if you use external dependencies with rust_libraries you don't write (either cargo-raze or Bazel external repositories with pre-written BUILD files). Also, if no rust_library with a dependency on alloc uses a certain function, but something else without that dependency does, then Bazel's arbitrary choice of link order determines whether those symbols get linked in or linking fails. |
I hit this without a custom allocator using GCC (on clang it works fine ala 802bcf9). An alternative workaround to the one posted in #1350, is to do a stub of a rust binary that essentially calls into C++. I made the C++ have a use std::ffi::{CString};
use std::os::raw::{c_char, c_int};
extern "C" {
fn app_main(num_args: c_int, args: *const *const c_char) -> c_int;
}
fn main() {
let args = std::env::args_os()
.map(|arg| arg.to_string_lossy().to_string())
.map(|arg| arg.into_bytes())
.map(|arg| unsafe { CString::from_vec_unchecked(arg) })
.collect::<Vec<_>>();
let rc = unsafe { app_main(args.len() as c_int, args.as_ptr() as *const *const c_char) };
std::process::exit(rc);
} This is untested on anything other than linux and is IMHO a hack, but might be useful for people who need to tweak a binary here or there. Of interest, this seems to only happen to me for some link targets of the form |
Previous work has made `rust_library` operate as a `CcInfo` provider. As far as I can tell this lets the compiler directly consume an rlib rather than a formal static or shared library crate type. This is a fine experiment but is a poor recommendation in the documentation, I would suggest that until rust-lang/rust#73632 is in a better place we dont recommend people use a `rust_library` target directly where `CcInfo` is expected. I found that this failed for me in ways similar to bazelbuild#1238 even without stating a custom allocator. After fixing this for Linux + GCC this then failed in macos *and* windows. It seems that we are jumping the gun slightly and encouraging a behavior that only works with a specific configuration as the default, rather than as something to trial.
Alas this failed for me on macos, I think recommending |
Update on this: #1490 added the |
For anybody looking to use a non-default global allocator with //! Hand-written allocator shims to use `my_allocator` with Bazel. This is used instead of
//! `#[global_allocator]`.
use std::alloc::{GlobalAlloc, Layout};
use my_allocator::MyAllocator;
static ALLOC: MyAllocator = MyAllocator;
#[no_mangle]
extern "C" fn __rust_alloc(size: usize, align: usize) -> *mut u8 {
unsafe { ALLOC.alloc(Layout::from_size_align_unchecked(size, align)) }
}
#[no_mangle]
extern "C" fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize) {
unsafe { ALLOC.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
}
#[no_mangle]
extern "C" fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8 {
unsafe { ALLOC.realloc(ptr, Layout::from_size_align_unchecked(old_size, align), new_size) }
}
#[no_mangle]
extern "C" fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
unsafe { ALLOC.alloc_zeroed(Layout::from_size_align_unchecked(size, align)) }
} |
When using rules_rust to link a rust library into a final C / C++ binary, you end up hitting some linker issues around missing allocator symbols:
After reading some various issues it sounds like the core issue is that rust mostly expects to handle linking itself, and provides these manually during the final link, but when linking it into a C binary with bazel, we don't go through that logic and therefore end up missing these symbols.
This change 802bcf9 potentially improves this by allowing you to add a global
allocator_library
which can provide these symbols and solve this. But as far as I can tell that would currently require reproducing a lot of toolchain setup boilerplate, as well as a library containing the necessary symbols (one of which can be found here https://github.com/chromium/chromium/blob/42bd3d0802e90ca093450a2683ff2a104e10e48a/build/rust/std/remap_alloc.cc)I'm hoping for some input on the best way to solve this, ideally for everyone, and ideally in rules_rust. One potential thing I could see working is defaulting the allocator library to a library in rules_rust containing something like chromium's solution. If that would be too invasive we could potentially expose the allocator_library attribute and pipe that through all the toolchain setup so users could specify one globally in their WORKSPACE without having to add too much boilerplate.
Please let me know what you think!
The text was updated successfully, but these errors were encountered: