You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android NDK链接器无法在两个共享库间找到符号问题求助

问题:Android加载依赖BZip2的原生库失败

调用System.loadLibrary("contribtests")加载依赖动态编译BZip2库libbz2.so的原生库contribtests.so时始终失败,报错:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "BZ2_bzlibVersion" referenced by "/data/app/~~aTgFU-pNoDjbLJvJTuDiiQ==/com.microcaet.contribtests"

已排查信息:

  • 解压APK后用readelf检查,两个库动态节信息正常:libbz2.so中存在BZ2_bzlibVersion符号,contribtests.so中该符号标记为UND(未定义)
  • 编译生成的libbz2.so带有语义版本号libbz2.so.1.0.9,为让Gradle打包进APK,使用patchelf修改其SONAME并移除版本号后重命名
  • 将contribtests改为简单main.c生成命令行程序,设置LD_LIBRARY_PATH后通过adb运行正常,但APP内加载仍失败
调试与修复方法

一、调整库加载顺序

Android原生库加载时依赖库需优先加载,在调用System.loadLibrary("contribtests")前,先显式加载libbz2.so:

System.loadLibrary("bz2");
System.loadLibrary("contribtests");

注意:加载名称需去掉lib前缀和.so后缀,若libbz2.so放在jniLibs/[abi]/目录下,Gradle会自动打包。

二、验证patchelf修改有效性

重新检查libbz2.so的SONAME设置,执行命令确认SONAME为libbz2.so:

readelf -d libbz2.so | grep SONAME

若SONAME仍带版本号,重新执行修改命令:

patchelf --set-soname libbz2.so libbz2.so.1.0.9
mv libbz2.so.1.0.9 libbz2.so

三、检查APK内库的路径与ABI匹配

  • 确保libbz2.so和contribtests.so都放在APK的lib/[abi]/目录下(对应项目src/main/jniLibs/[abi]/路径)
  • 确认两个库的ABI架构完全一致(如均为arm64-v8a或armeabi-v7a),避免因架构不匹配导致加载失败

四、通过日志定位链接器问题

使用adb过滤链接器日志,获取更详细的加载失败原因:

adb logcat | grep linker

日志会显示是否找不到libbz2.so,或符号解析的具体异常细节。

五、检查编译链接参数

编译contribtests.so时,确保正确链接libbz2.so:

  • 原生编译命令需包含-lbz2参数并指定库路径:
gcc -shared -o contribtests.so contribtests.c -L/path/to/bz2/lib -lbz2
  • 若使用CMake,在CMakeLists.txt中添加依赖:
target_link_libraries(contribtests bz2)

六、尝试静态链接替代动态链接

若动态依赖问题难以解决,可将BZip2静态库编译进contribtests.so:

  1. 编译BZip2生成静态库libbz2.a
  2. 编译contribtests.so时链接静态库:
gcc -shared -o contribtests.so contribtests.c /path/to/libbz2.a

内容的提问来源于stack exchange,提问作者Lothar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 04:26:08