How to re-export symbols from a static lib

When I link a rust lib to a static lib archive (libfoo.a), I'd like to re-export the symbols defined in the static lib,
e.g.
#[no_mangle]
pub extern "C" fn version() -> c_int;

Compiler warn on the no_mangle attribute here and does not export symbol version when I build the rust dylib, if this is possible, what is the correctly way? If not possible, is it valid to make a feature request? Thanks!

extern "C" {
    pub fn version() -> c_int;
}

This directly re-exports that symbol (it is thus analogous to a .h file in the C world). If you want to change the ABI and/or the safety, you can insted write:

#[inline]
pub fn version() -> c_int {
    #![deny(unconditional_recursion)]

    extern "C" { fn version() -> c_int; }
    unsafe { version() }
}

Note too that you can use #[link_name] if you want to re-export it as a different name:

extern "C" {
    #[link_name = "version"]
    pub fn rust_name () -> c_int;
}

And you can use the #[link attribute on the whole extern "C" { … } block to specify the expected library (so that if the library happens to be missing at compile-time, you get a nicer error message :slightly_smiling_face:)

See the reference for more info.

3 Likes

Awesome, thank you so much!

Sorry but I cannot get it working. I check with objdump but the symbol is not exported with the same name from static lib. Then I try to add #[no_mangle] to outter rust function I got error LNK2005: <symbol> already defined in <staticlib>.o. When I give outter rust function a different name 'version1' (and keep #[no_mangle]), I can see symbol version1 exported from the dylib, could not figure out what I was doing wrong here.

Oh, maybe that annotation only declares the item to be usable from within Rust, and it won't re-export the symbol? :thinking: Sorry I don't know if there is a flag to achieve this (I imagine there must be!).

I have personally tried the following and it worked, but maybe on Windows it is different:

asciicast

Yeah, I have no problem using the C function in rust, I just want to re-export the same C symbol name when I build a dylib from rust. When using cc-rs, cargo just works like a makefile, and the produced dylib has the same symbol names as if it's directly compiled from C source code.

If you look at my cc command, you will notice I am linking the final C test against the Rust library (I called it inner) and not against the original C library (foo).

I guess in your case it may not work because the final artifact is a dynamic library and not a static one


EDIT: yes, if I change inner to be a cdylib, the symbol is no longer found

EDIT 2: It looks like whole-archive semantics are what we need here; those were suggested within this RFC.

Yes, whole-archive looks like what I'm looking for, looking forward to its approval. Thanks!