编译含libc依赖的Rust项目到Wasm时遇函数签名不匹配问题求助
解决c2rust转换代码编译WASM时的libc函数签名不匹配问题
问题场景
用c2rust将C代码转换为Rust后,执行cargo build --target=wasm32-wasi编译时,链接器抛出函数签名不匹配错误,相关代码和错误信息如下:
转换后的Rust代码
extern "C" { fn printf(_: *const libc::c_char, _: ...) -> libc::c_int; fn time(__timer: *mut time_t) -> time_t; fn ctime(__timer: *const time_t) -> *mut libc::c_char; fn memcpy( _: *mut libc::c_void, _: *const libc::c_void, _: libc::c_ulong, ) -> *mut libc::c_void; fn strlen(_: *const libc::c_char) -> libc::c_ulong; } pub type __time_t = libc::c_long; pub type time_t = __time_t; unsafe fn main_0() -> libc::c_int { let mut src: [libc::c_char; 14] = *::core::mem::transmute::< &[u8; 14], &mut [libc::c_char; 14], >(b"Hello, world!\0"); let mut dest: [libc::c_char; 20] = [0; 20]; memcpy( dest.as_mut_ptr() as *mut libc::c_void, src.as_mut_ptr() as *const libc::c_void, (strlen(src.as_mut_ptr())).wrapping_add(1 as libc::c_int as libc::c_ulong), ); printf(b"src: %s\n\0" as *const u8 as *const libc::c_char, src.as_mut_ptr()); printf(b"dest: %s\n\0" as *const u8 as *const libc::c_char, dest.as_mut_ptr()); let mut cur_time: time_t = 0; time(&mut cur_time); printf( b"Current local time: %s\0" as *const u8 as *const libc::c_char, ctime(&mut cur_time), ); return 0 as libc::c_int; } pub fn main() { unsafe { ::std::process::exit(main_0() as i32) } }
编译错误信息
= note: rust-lld: error: function signature mismatch: time >>> defined as (i32) -> i32 in /home/ubuntu/demo/demo_rust/target/wasm32-wasi/debug/deps/main-975cb877ac86c0d4.3vi6reg7dgepzj1h.rcgu.o >>> defined as (i32) -> i64 in /home/ubuntu/.rustup/toolchains/nightly-2022-08-08-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-wasi/lib/self-contained/libc.a(time.o)
怀疑是Wasm的libc与Rust的libc不一致导致,求可行解决办法。
解决办法
直接复用libc crate的标准定义
c2rust生成的代码手动声明了time_t和C函数,这和libccrate针对wasm32-wasi目标的内置定义冲突。修改代码,移除手动声明的类型和函数,直接引用libc的导出:use libc::{c_char, c_int, c_ulong, c_void, time_t, printf, time, ctime, memcpy, strlen}; unsafe fn main_0() -> c_int { let mut src: [c_char; 14] = *::core::mem::transmute::< &[u8; 14], &mut [c_char; 14], >(b"Hello, world!\0"); let mut dest: [c_char; 20] = [0; 20]; memcpy( dest.as_mut_ptr() as *mut c_void, src.as_mut_ptr() as *const c_void, (strlen(src.as_mut_ptr())).wrapping_add(1 as c_int as c_ulong), ); printf(b"src: %s\n\0" as *const u8 as *const c_char, src.as_mut_ptr()); printf(b"dest: %s\n\0" as *const u8 as *const c_char, dest.as_mut_ptr()); let mut cur_time: time_t = 0; time(&mut cur_time); printf( b"Current local time: %s\0" as *const u8 as *const c_char, ctime(&cur_time), ); return 0 as c_int; } pub fn main() { unsafe { ::std::process::exit(main_0() as i32) } }避免手动定义libc相关类型
wasm32-wasi目标下,libccrate已经适配了WASI的libc实现,不要自行定义__time_t、time_t这类和系统libc强相关的类型,防止和目标平台实际定义不匹配。优化c2rust转换参数
后续用c2rust转换时,添加--extern-libc参数,让生成的代码直接依赖libccrate的类型定义,减少手动适配的工作量。升级工具链版本
你使用的是2022年的nightly版本,较旧的工具链可能存在WASI目标的libc适配缺陷。可以升级到最新的稳定版或nightly版,确保工具链对WASI的支持更完善。
内容的提问来源于stack exchange,提问作者Effy
相关产品推荐
相关产品推荐

