“multiple definition of `memcmp” error when linkin

2019-02-28 11:38发布

问题:

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.

回答1:

You have a bunch of duplicated symbols coming from your customized "standard library" liba and from generated builtin symbols inserted into librust.a:

memset, memcpy, memmove, ecc, ecc

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 before librust.a will resolve symbols from librust.a and files coming after librust.a will resolve the same symbols from liba 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:

RUST_LIB_DIR = <path_to_librust.a>

.SECONDARY: $(objs)
%.$(EXE):
    @echo "LD      $@"
    $(Q) $(LD) $^ $(LDFLAGS) -L$(RUST_LIB_DIR) -l:librust.a -o $@ 

This recipe links successfully on my side. My basic epsilon/apps/main.cpp instrumentation:

#include "global_preferences.h"
#include "apps_container_storage.h"

extern "C" int hello_world(int a, int b);

void ion_main(int argc, char * argv[]) {

  hello_world(1,2);
  ...