I'm working with a Rust library that contains many extern "C" functions. Building the crate works fine but the generated static library (.a) does not contain any of the exported symbols (i.e. extern "C" functions). However, the generated dynamic library (.dylib) file contains all exported symbols.
Any ideas why I'm not getting the exported symbols in the static library build?
I don't see anything wrong in the code, but I don't have any experience with apple platforms, so I can only guess. how do you link against the static library exactly, like what command line flags are used, etc.? what's the actual linker error message you see when you try to link the library?
I then inspect the .a file using nm but it does not contain the functions I expect and when using the library I get the error <function_name> undefined symbol, not found in image.
The output of --print native-static-libs is not to be added as RUSTFLAGS, but when linking against the staticlib that was produced. You likely need to change the XCode configuration to add these linker flags.
that's strange. did you check what other symbols are missing? what's the output if you run objdump -a /path/to/library? is the correct object file archived correctly?
also, I see there's cbindgen.toml, did you check the output of cbindgen? is the function present in the generated header file?
Understood, but am I right in thinking that the symbols should be in the .a library output by the build command (targer/aarch64-apple-ios/debug/libxxx.a) or will they only appear post linking?
The #[no_mangle] functions you define should already be in the .a static library. So in your case example_function should be present. What is the linker error and what does nm target/aarch64-apple-ios/debug/libxxx.a show?
--print native-static-libs shows which dynamic libraries the .a static library depends on. Static libraries don't have a way to tell the linker what libraries they depend on unlike with dynamic libraries. This is why we have --print native-static-libs to still be able to know the dependencies.
After adding the dynamic library dependencies in XCode and running a sample app I get the error:
Failed to lookup symbol 'example_function': symbol not found.
The output of nm is:
radix_engine_toolkit.2g106qn3ufjfrmjj.rcgu.o:
U ___rdl_alloc
U ___rdl_alloc_zeroed
U ___rdl_dealloc
U ___rdl_realloc
U ___rg_oom
---------------- T ___rust_alloc
---------------- T ___rust_alloc_error_handler
---------------- D ___rust_alloc_error_handler_should_panic
---------------- T ___rust_alloc_zeroed
---------------- T ___rust_dealloc
---------------- D ___rust_no_alloc_shim_is_unstable
---------------- T ___rust_realloc
...
can you call the function within rust code? is there any chance the function is not compiled into the library, like guarded by a #[cfg(feature = "foo")] attribute or something?
I created a new lib project, imported the crate (which I have locally) and successfully called one of its methods.
Cargo.toml
[package]
name = "example"
version = "0.1.0"
edition = "2021"
[dependencies]
radix-engine-toolkit = { path = "../radix-engine-toolkit" }
main.rs
use std::ffi::CString;
use radix_engine_toolkit::prelude::build_information;
fn main() {
// JSON string to c pointer.
let s = String::from("{}");
let cs = CString::new(s).unwrap();
let mut cv: Vec<u8> = cs.into_bytes_with_nul();
let cptr: *mut i8 = cv.as_mut_ptr() as *mut i8;
// Call exported function.
let result = build_information(cptr);
// Pointer to result.
println!("{:?}", result);
}
An .a library is "just" a container for a bunch of .o files. If all else fails, you should be able to add the missing object files to the library manually, with a shell command like
ar rs target/.../your_crate.a missing_c_object_1.o missing_c_object_2.o ...
If OSX ar objects to rs, then instead do
ar r target/.../your_crate.a missing_c_object_1.o missing_c_object_2.o ...
ranlib target/.../your_crate.a
Regretfully, I cannot tell you how to glue this into your larger build.