将 Rust staticlib 与嵌入式 C 程序链接时出现“`memcmp 的多重定义”错误

Fer*_*ogh 5 c embedded linker ffi rust

我有一个 Rust 函数,我想从在 STM32F412 MCU 上运行的C 项目调用,但是我收到了一系列“多重定义”链接器错误。

这是我的 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 {} }
Run Code Online (Sandbox Code Playgroud)

Building withcargo build --release --target=thumbv7em-none-eabihf会生成一个librust.a我作为对象添加到 C Makefile 的对象。

可以在此处找到链接器错误的完整列表。nm将所有冲突函数显示为全局文本符号 (T),此处为完整输出

C 项目没有普通的标准 C 库,而是使用自定义 libc,这是一个特定于设备的实现,涵盖了标准的一小部分。我可以告诉 Rust 库使用这些函数吗?

通读 Rust 功能列表,#![feature(compiler_builtins_lib)]但是这与我想要的完全相反,因为如果您收到“未定义的引用”链接器错误。

att*_*ona 4

您有一堆重复的符号来自您的自定义“标准库”liba和插入到的生成的内置librust.a符号:

memset, memcpy, memmove, ecc, ecc
Run Code Online (Sandbox Code Playgroud)

出现您的问题是因为链接时目标文件的顺序很重要。

如果您librust.a过早地将要链接的文件的有序序列放入其中,则之前的文件librust.a将解析其中的符号librust.a,而之后的文件librust.a将解析其中的相同符号liba,这会生成重复的符号错误。

为了避免这个问题,请将 Rust 库放在目标文件的末尾进行链接。

在 epsilon Makefile 中将链接命令更改为:

RUST_LIB_DIR = <path_to_librust.a>

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

这个食谱在我这边链接成功。我的基本epsilon/apps/main.cpp仪器:

memset, memcpy, memmove, ecc, ecc
Run Code Online (Sandbox Code Playgroud)