ARM架构Mac加载libfingerprints.dylib遇UnsatisfiedLinkError求助
问题描述
运行以下Java代码时,第一个动态库加载正常,但第二个库始终加载失败:
public class Main { public static void main(String[] args) { System.out.println("Hello world!"); System.load("/Users/orlando/libbinaryen.dylib"); System.load("/Users/orlando/libfingerprints.dylib"); } }
执行输出:
Hello world! Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load library: /Users/orlando/libfingerprints.dylib at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2393) at java.base/java.lang.Runtime.load0(Runtime.java:755) at java.base/java.lang.System.load(System.java:1953) at Main.main(Main.java:9)
已尝试过自行编译的库、他人在ARM Mac上编译且可正常运行的库,均无法解决。同时已确认文件权限、路径、处理器架构匹配,使用java -Djava.library.path=/Users/orlando/Git/lib -verbose:jni -classpath /Users/orlando/Git/HelloWorld/out/production/HelloWorld Main调试,输出仍显示相同错误。
额外验证信息
# 库架构验证 >> file libfingerprints.dylib libfingerprints.dylib: Mach-O 64-bit dynamically linked shared library arm64 # 库依赖检查 >> otool -L libfingerprints.dylib libfingerprints.dylib: @rpath/libfingerprints.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1500.65.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3) # 系统架构 >> uname -m arm64 # Java版本 >> java --version openjdk version "17.0.4.1" 2022-08-12 LTS OpenJDK Runtime Environment Corretto-17.0.4.9.1 (build 17.0.4.1+9-LTS) OpenJDK 64-Bit Server VM Corretto-17.0.4.9.1 (build 17.0.4.1+9-LTS, mixed mode, sharing)
非常规排查方向与验证方法
用系统工具直接加载库,排除Java层面问题
写个简单的C程序调用dlopen加载库,看系统动态链接器能否正常加载:// test_dlopen.c #include <dlfcn.h> #include <stdio.h> int main() { void* handle = dlopen("/Users/orlando/libfingerprints.dylib", RTLD_NOW); if (!handle) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); return 1; } printf("Library loaded successfully\n"); dlclose(handle); return 0; }编译运行:
clang test_dlopen.c -o test_dlopen && ./test_dlopen如果这里也失败,问题出在系统层面,和Java无关;如果成功,再聚焦Java加载逻辑。
追踪动态库加载的完整依赖链
用DYLD_PRINT_LIBRARIES环境变量打印加载过程的详细日志,看动态链接器寻找依赖时的行为:# 先在C测试程序中追踪 DYLD_PRINT_LIBRARIES=1 ./test_dlopen # 再在Java进程中追踪 DYLD_PRINT_LIBRARIES=1 java -classpath /Users/orlando/Git/HelloWorld/out/production/HelloWorld Main重点看加载
libfingerprints.dylib时,是否有依赖找不到、版本不匹配的情况。检查Java进程的环境变量与系统权限限制
查看Java进程的环境变量,确认DYLD相关路径是否被修改:java -classpath /Users/orlando/Git/HelloWorld/out/production/HelloWorld -XshowSettings:properties Main | grep dyld另外检查系统完整性保护(SIP)状态,SIP可能限制某些路径的库加载:
csrutil status若SIP开启,可临时关闭测试(测试后务必恢复):
# 重启进入恢复模式后执行 csrutil disable # 测试完成后重启恢复模式执行 csrutil enable验证库的代码签名与公证状态
ARM Mac对代码签名要求更严格,检查库的签名:codesign -vvv /Users/orlando/libfingerprints.dylib如果签名无效,尝试重新签名:
codesign -f -s - /Users/orlando/libfingerprints.dylib注意:自签名库在SIP开启时可能仍无法加载,需用开发者证书签名或添加到系统允许列表。
排查两个库之间的符号/依赖冲突
尝试单独加载libfingerprints.dylib,不加载libbinaryen.dylib,看是否能成功:public class Main { public static void main(String[] args) { System.out.println("Hello world!"); System.load("/Users/orlando/libfingerprints.dylib"); } }如果单独加载成功,说明两个库存在冲突,用
nm导出符号对比:nm -gU /Users/orlando/libbinaryen.dylib > binaryen_syms.txt nm -gU /Users/orlando/libfingerprints.dylib > fingerprints_syms.txt comm -12 binaryen_syms.txt fingerprints_syms.txt输出的内容就是两个库共有的导出符号,可能存在冲突。
内容的提问来源于stack exchange,提问作者Orlando

