Android平台下如何向Rust编译的cdylib暴露C函数?
解决Android端Rust cdylib调用本地C函数的UnsatisfiedLinkError问题
出现java.lang.UnsatisfiedLinkError找不到符号foo的核心原因是:Rust编译的动态库(.so)加载时,依赖的符号需要在当前进程的全局符号表中可见。你当前将foo编译为静态库,若未将其链接到Rust库或提前加载的动态库中,Rust库无法找到该符号。以下是三种可行的解决方式:
方式一:将C++实现编译为动态库并提前加载
- 修改Android模块的CMake配置,把静态库改为动态库:
# 原配置 # add_library(foo STATIC foo.cpp) # 修改后 add_library(foo SHARED foo.cpp) - 确保
foo函数暴露C接口(避免C++名字修饰),头文件需添加:#ifdef __cplusplus extern "C" { #endif void foo(); #ifdef __cplusplus } #endif - 在Java代码中先加载foo的动态库,再加载Rust库:
// 加载顺序不能颠倒 System.loadLibrary("foo"); System.loadLibrary("rust_lib"); // 替换为你的Rust库名称
方式二:将静态库直接链接到Rust cdylib
- 在Rust项目的
build.rs中,指定链接静态库的路径和名称:fn main() { // 替换为你的静态库所在目录路径,需匹配对应ABI(如arm64-v8a) println!("cargo:rustc-link-search=native=/path/to/android/static/lib"); println!("cargo:rustc-link-lib=static=foo"); } - 同样要保证
foo是C接口(extern "C"声明),且静态库与Rust库的编译ABI完全一致(如均为arm64-v8a)。
方式三:将C++代码纳入Rust构建流程
- 把实现
foo的C++文件放到Rust项目中,通过build.rs调用编译器生成静态库并链接:use std::process::Command; use std::env; fn main() { let target = env::var("TARGET").unwrap(); let out_dir = env::var("OUT_DIR").unwrap(); // 编译C++文件为目标文件 Command::new("clang++") .args(&[ "-c", "src/foo.cpp", "-o", &format!("{}/foo.o", out_dir), "--target", &target, "-fPIC" ]) .status().unwrap(); // 打包为静态库 Command::new("ar") .args(&["rcs", &format!("{}/libfoo.a", out_dir), &format!("{}/foo.o", out_dir)]) .status().unwrap(); // 告知Rust链接该静态库 println!("cargo:rustc-link-lib=static=foo"); println!("cargo:rustc-link-search=native={}", out_dir); } - Rust代码中通过
extern "C"声明调用foo:extern "C" { fn foo(); } // 调用示例 pub fn call_foo() { unsafe { foo(); } }
内容的提问来源于stack exchange,提问作者Oscar Franco
相关产品推荐
相关产品推荐

