I made a crate that exposes some c-compatible #[no_mangle] functions in its public API. Is there a way to also include those symbols in another crate cdylib?
Crate a contains two no_mangle functions (make_world and print_world).
Crate b depends on a and re-exports those functions, and adds an additional function (goodbye_world). However, in the generated shared library, the functions from a don't show up.
$ objdump -T a/target/debug/liba.so | grep world
00000000000030c0 g DF .text 0000000000000303 Base print_world
0000000000002f20 g DF .text 000000000000019a Base make_world
$ objdump -T b/target/debug/libb.so | grep world
00000000000034a0 g DF .text 0000000000000086 Base goodbye_world
So I tried to create wrapper functions around every function from a (see b2 crate). They work like this:
However, with this approach the C code actually segfaults (see b2/test.c):
$ cd b2
$ cc test.c -L target/debug -l b2 -o test
$ LD_LIBRARY_PATH=target/debug ./test
Test start
From b2 crate:
Output: Goodbye, world!
From a crate:
Segmentation fault (core dumped)
Shouldn't this trigger a compile warning/error, if two #[no_mangle] functions have the same name? I guess it would be worth to open an issue in the rust repository...
Sometimes it is the right thing. For example if you want "hook" libc functions like malloc you can create shared library with function malloc and with LD_PRELOAD= insert it into executable address space.
For example in your case, in bX library you can write:
#[no_mangle]
pub extern "C" fn make_world() -> *mut world_pointer_t {
type MakeWorldFunction = extern "C" fn() -> *mut world_pointer_t;
let p = unsafe { dlsym(RTLD_NEXT, swig_c_str!("make_world")) };
assert!(!p.is_null());
let p: MakeWorldFunction = unsafe { mem::transmute(p) };
p()
}
and then run your test code with:
LD_PRELOAD=full/path/to/liba.so ./test
and at least call of make_world it should pass without crash.
Anyways, this problem would not even occur if I would find a way to expose 3rd party crate no_mangle functions into my .so file... @Dushistov do you know of a way to get that working?
In current approach, without fixing issue in rustc that you've mentioned in top post I don't see solution.
But may be you should change the way you are looking at problem.
For example, why you need reexport symbols, if you build liba.so,
you can just link it to test executable?
Or for example, why you need make_world to be extern "C" + no_mangle in crate a?
If you make make_world normal function in crate a,
and in crate b you create extern "C" + no_manglemake_world that call a::make_world, then optimizaer should take care about this.
And your code should be as effective as you reexport a::make_world without calling it.
I never try, but I think this should not be the problem.
All symbols that you not define as pub explicity should be hidden
and not visible outside of cdylib.