HarmonyOS 鸿蒙Next中native多so依赖查找符号表出错
HarmonyOS 鸿蒙Next中native多so依赖查找符号表出错 项目有多so模块,napi的so是access,c++核心主入口是platform.so
运行时候总是找不到so的符号表,但是命令行查看符号表是存在的?不知道是什么原因?而且为什么总是在platform中找符号表呢?
更多关于HarmonyOS 鸿蒙Next中native多so依赖查找符号表出错的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【背景知识】
HarmonyOS上使用CMake构建系统来编译NDK库,其核心编译过程如下: 根据CMake配置脚本以及build-profile.json5中配置的externalNativeOptions构建参数,与缓存中的配置比对后,生成CMake命令并执行CMake,按照makefile执行编译和链接,将生成的.so以及运行时依赖的.so同步到输出目录,完成构建过程。
【问题定位】
当遇到编译找不到SO文件的时候,需要做以下几个方向的排查:
- 通过错误日志锁定问题SO的名字,并在CMakeLists.txt文件中找到对应的配置项;
- 如果配置项语法没有问题,则检查是否存在工程对应的SO存放路径;
- 查看是否有编译缓存文件;
- 检查预编译SO的SONAME,文件拷贝是否正确;
- 检查该预编译的SO中依赖的其他库是否都存在。
【分析结论】
- 可能是CMake配置里,对应的SO关联的选项未打开,或者未配置库的搜索路径;
- 可能对应的SO文件未拷贝或者未生成到对应的路径下;
- 可能之前的编译缓存影响,编译使用了缓存,未刷新成正确的配置;
- 应用在引用动态库的时候是通过SONAME来查找的,开发者需要将SONAME对应的库文件拷贝到entry/libs/${OHOS_ARCH}/目录下。
查询命令:llvm-readelf -d xxx.so
$ llvm-readelf -d xxx.so
Dynamic section at offset 0xad00a0 contains 31 entries:
Tag Type Name/Value
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../../../mapi/shared-glapi:/xxx/ohos-sdk/thirdparty/libxxx:/xxx/ohos-sdk/hiviewdfx/hilog]
0x0000000000000001 (NEEDED) Shared library: [libglapi.so.0]
0x0000000000000001 (NEEDED) Shared library: [libz.so]
0x0000000000000001 (NEEDED) Shared library: [libhilog.so]
0x0000000000000001 (NEEDED) Shared library: [libc++_shared.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so]
0x000000000000000e (SONAME) Library soname: [libaaa.so]
- 使用上述命令查看依赖的SO(NEEDED)。需要把依赖的SO添加到工程中并在CMakeLists.txt链接。
【修改建议】
- 检查并更正对应的配置选项;
- 拷贝SO到对应的路径下;
- 删除缓存的.CXX文件夹,重新执行编译;
- Native工程引入SO库时需要SONAME对应的库文件拷贝到entry/libs/${OHOS_ARCH}/目录下;
- Native工程引入SO库时要将其依赖项同步链接到工程中。
更多关于HarmonyOS 鸿蒙Next中native多so依赖查找符号表出错的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,native多so依赖查找符号表出错通常是由于符号可见性或加载顺序问题导致。需检查依赖so是否在CMakeLists.txt或build-profile.json中正确定义,并确保符号在导出so中已通过__attribute__((visibility("default")))
显式声明。动态链接时需注意so加载顺序,被依赖库应优先加载。可通过nm工具验证符号是否存在,或使用链接器参数--no-undefined
在编译阶段检测未定义符号。
在HarmonyOS Next中,多个so模块依赖时出现符号表查找失败,通常是由于动态链接器在解析符号时的搜索路径问题。根据你的描述,符号表在命令行中存在,但运行时找不到,这可能是以下原因导致的:
-
符号可见性设置问题:确保依赖的so在编译时正确导出符号。检查CMakeLists.txt或编译脚本中是否使用
-fvisibility=default
或显式声明__attribute__((visibility("default")))
。如果符号被隐藏,动态链接器将无法在运行时解析。 -
依赖加载顺序:动态链接器按加载顺序解析符号。如果
platform.so
依赖其他so的符号,但依赖的so未先加载,会导致查找失败。在代码中通过dlopen
显式加载依赖so时,需使用RTLD_GLOBAL
标志,确保符号全局可见。例如:dlopen("libdependency.so", RTLD_NOW | RTLD_GLOBAL);
-
so路径配置:检查应用程序的
config.json
中nativeLibraryPath
是否包含所有so的正确路径。如果so未放置在标准目录(如libs/arm64-v8a
),需确保路径配置正确。 -
符号冲突或版本问题:如果多个so定义了相同符号,链接器可能优先绑定到错误模块。使用
nm -D
验证符号实际所在模块,并确保无重复定义。
关于“总是在platform中找符号表”,这是因为动态链接器默认从当前模块(如platform.so
)开始解析符号。若依赖未正确加载,链接器会局限在该模块内查找,导致失败。建议:
- 在加载
platform.so
前,通过dlopen
预加载所有依赖so,并设置RTLD_GLOBAL
。 - 检查编译链接参数,确保依赖so被正确链接(如使用
-l
指定库)。
通过调整加载顺序和符号导出设置,可解决此问题。