I have a Rust function I would like to call from a C project that runs on an STM32F412 MCU, but I am getting a series of "multiple definition of" linker errors.
Here is my lib.rs:
#![crate_type = "staticlib"]
#![feature(lang_items)]
#![no_std]
#![no_builtins]
#[no_mangle]
pub extern "C" fn hello_world(a: i32, b: i32) -> i32 {
a + b
}
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
Building with cargo build --release --target=thumbv7em-none-eabihf
produces a librust.a
which I added as an object to the C Makefile.
The complete list of linker errors can be found here. nm
shows all the conflicting functions as global text symbols (T), full output here.
The C project does not have a normal standard C library, instead it uses a custom libc a device-specific implementation that covers a small portion of the standard. Can I tell the Rust library to use those functions?
Reading through the Rust features list, there is #![feature(compiler_builtins_lib)]
but this does the exact opposite of what I want, for if you are getting "undefined reference to" linker errors.
You have a bunch of duplicated symbols coming from your customized "standard library"
liba
and from generated builtin symbols inserted intolibrust.a
:Your problem arises because the order of object files matters when linking.
If you put
librust.a
too early in the ordered sequence of files to link, then files beforelibrust.a
will resolve symbols fromlibrust.a
and files coming afterlibrust.a
will resolve the same symbols fromliba
and this generates duplicate symbol errors.To avoid this problem, put the Rust library at the end of object files to link.
In epsilon Makefile change the link commands as:
This recipe links successfully on my side. My basic
epsilon/apps/main.cpp
instrumentation: