裸机MCU项目混合Rust与C时rust_begin_unwind重复符号问题求助
解决裸机Rust静态库链接时
rust_begin_unwind重复符号问题 在裸机微控制器项目中混合使用Rust与C,未采用Cargo,直接调用rustc配合自定义构建系统。编写了两个结构类似的Rust静态库,每个库都包含#[panic_handler]定义,示例代码如下:
#![no_std] #![no_main] #![crate_type="lib"] #[panic_handler] fn my_panic(_info: &core::panic::PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn rust_sample_lib_for_c(a: i8) -> i8 { return a+53; }
编译命令:
rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a
链接C源码与两个Rust库时出现错误:
ld.lld: error: duplicate symbol: rust_begin_unwind
经objdump检查,两个静态库中均存在rust_begin_unwind符号——原因是每个Rust库编译时都要求定义panic_handler,最终导致符号重复。
解决方案
1. 抽离公共panic处理库
将panic处理逻辑单独做成一个独立的Rust库,所有业务Rust库依赖这个公共库,不再各自定义panic_handler:
公共panic库代码(src/panic_common.rs)
#![no_std] #![crate_type="lib"] #[panic_handler] fn my_panic(_info: &core::panic::PanicInfo) -> ! { loop {} }
编译公共库
rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/panic_common.rs -o src/libpanic_common.a
修改业务库并编译
移除业务库中的panic_handler代码,编译时链接公共panic库:
#![no_std] #![no_main] #![crate_type="lib"] #[no_mangle] pub extern "C" fn rust_sample_lib_for_c(a: i8) -> i8 { return a+53; }
编译命令添加依赖参数:
rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a --extern panic_common=src/libpanic_common.a
最终链接时,只需将两个业务库、公共panic库与C代码一起链接即可,避免符号重复。
2. 用条件编译控制panic_handler
给业务库添加条件编译标记,仅在单独测试时启用panic_handler,实际项目中由全局代码提供统一的panic处理:
修改业务库代码
#![no_std] #![no_main] #![crate_type="lib"] // 仅在standalone特性启用时编译panic_handler #[cfg(feature = "standalone")] #[panic_handler] fn my_panic(_info: &core::panic::PanicInfo) -> ! { loop {} } #[no_mangle] pub extern "C" fn rust_sample_lib_for_c(a: i8) -> i8 { return a+53; }
编译业务库
编译时不启用standalone特性,这样不会生成rust_begin_unwind符号:
rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a
添加全局panic处理
创建单独的panic实现文件(src/panic_impl.rs):
#![no_std] #[panic_handler] fn global_panic(_info: &core::panic::PanicInfo) -> ! { loop {} }
编译成目标文件:
rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj src/panic_impl.rs -o src/panic_impl.o
链接时将这个目标文件、两个业务库和C代码一起链接即可。
3. 标记弱符号(应急方案,不推荐)
如果暂时无法修改代码,可尝试将其中一个库的rust_begin_unwind标记为弱符号,让链接器优先选择强符号:
rustc --target thumbv7em-none-eabihf -C panic=abort -C opt-level=3 --emit obj --crate-type staticlib src/rust_sample_lib_for_c.rs -o src/librust_sample_lib_for_c.a -Clink-args="-Wl,--defsym=rust_begin_unwind=__weak_rust_begin_unwind"
该方式依赖链接器特性,可能隐藏潜在问题,仅作为临时应急方案使用。
内容的提问来源于stack exchange,提问作者developer123
相关产品推荐
相关产品推荐

