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

Android原生库.so中JNI_OnLoad等符号缺失问题排查

问题原因分析

链接器构建动态库时,默认会丢弃未被直接引用的目标文件和符号。你的Lib1静态库中仅包含JNI_OnLoad和JNI_OnUnload,而动态库的入口文件native-lib.cpp没有直接引用这两个函数,链接器会判定这些符号属于“无用代码”,因此在生成.so时将它们剔除。

当你添加静态变量并在JNI_OnLoad中使用时,链接器会认为该目标文件存在被依赖的代码,从而保留整个目标文件的所有符号,这就是为什么此时符号会出现在.so中。

-E(--export-dynamic)参数无效的原因是:它的作用是将已被链接器包含的全局符号加入动态符号表,但如果链接器已经丢弃了包含JNI_OnLoad的目标文件,这个参数就起不到任何作用。

解决方案

1. 使用链接器-u参数强制保留符号

-u参数可以指定某个符号为“未定义”,迫使链接器将包含该符号的目标文件纳入链接流程,即使没有其他代码引用它。针对你的场景,需要强制保留JNI_OnLoad和JNI_OnUnload。

修改CMake脚本,给动态库目标添加链接选项:

add_library(${CMAKE_PROJECT_NAME} SHARED native-lib.cpp) 

# 强制链接器保留JNI_OnLoad和JNI_OnUnload符号
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
    -u JNI_OnLoad
    -u JNI_OnUnload
)

target_link_libraries (${CMAKE_PROJECT_NAME} PUBLIC Lib1 Lib2 log android)  

2. 备选方案:手动添加符号引用

在native-lib.cpp中添加对JNI_OnLoad的空引用,让链接器认为该符号被使用:

extern "C" jint JNI_OnLoad(JavaVM*, void*);
// 强制编译器标记该符号为被使用
static void __attribute__((used)) dummy_ref() {
    (void)JNI_OnLoad;
}

这种方式不如-u参数简洁,但同样能解决问题。

验证方法

编译完成后,使用nm命令检查.so文件的符号表:

nm -D libMyProject.so | grep JNI_

如果输出包含JNI_OnLoad和JNI_OnUnload,说明问题已解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 02:28:23