我有java程序Client.class,它通过JNI使用cpp共享库libclient.so。 libclient.so构建为共享并使用cpp共享库libhttp.so。
libclient.so和libhttp.so放在文件夹/home/client/lib64
中
Client.class放在/home/client/bin
客户端可以使用
加载库第一种方式正常。
export LD_LIBRARY_PATH = /home/client/lib64
java -classpath ./bin Client
secon方式失败。
java -classpath ./bin -Djava.library.path=./../lib64 Client
java.lang.UnsatisfiedLinkError: /home/client/lib64/libclient.so: libhttp.so: cannot open shared object file: No such file or directory
当我将libhttp.so放入/ usr / lib64时,第二种方式正常。
如果我使用System.loadLibrary,为什么libclient.so在/ usr / lib64中寻找libhttp.so? 如何在不将libhttp.so复制到/ usr / lib64的情况下修复它?
我的加载代码:
//Try load from -Djava.library.path
boolean found = false;
String lib = "client";
try {
System.loadLibrary(lib);
found = true;
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}
//Try load from LD_LIBRARY_PATH
if (!found) {
lib = "libclient.so";
String ld_lib_path = System.getenv("LD_LIBRARY_PATH");
String[] paths = ld_lib_path.split(":");
for(int i=0; i<paths.length; i++) {
String p = paths[i];
File x = new File(p, lib);
if (x.exists()) {
System.load(x.getAbsolutePath());
found = true;
break;
}
}
}
其他信息。
如果我用ldd测试libclient.so,那么我看到:libhttp.so =&gt;未找到 如果我设置export LD_LIBRARY_PATH = / home / client / lib64,那么我看到:libhttp.so =&gt; /home/client/lib64/libhttp.so
答案 0 :(得分:10)
原因是libclient.so是从您的JVM加载的,它在java.library.path
中查找。但是,当libclient.so尝试加载libhttp.so时,它对Java一无所知,只是使用常规的Linux方式加载共享库(动态链接器ld.so
),它查找LD_LIBRARY_PATH
和一些常见目录,如/usr/lib64
。
我可能会从Java应用程序的启动脚本中使用LD_LIBRARY_PATH
set。如果您不想使用启动脚本,理论上可以在流程本身内设置LD_LIBRARY_PATH
。但是,Java不允许这样做(只有System.getenv()
,而不是System.setenv()
),因此您需要编写一个从Java调用的小型C库并调用putenv()
设置LD_LIBRARY_PATH
。
如果您自己构建libclient.so
,则可以使用-rpath
链接器标志指定动态链接器应查找其他所需库的路径。如果在此处指定相对路径,请小心,它将被解释为相对于正在运行的应用程序的当前工作目录,而不是相对于libclient.so
的位置。要实现这一点,您需要使用$ORIGIN
作为-rpath
的参数,并注意您的shell不会扩展它。
因此,如果您想在同一目录中拥有libclient.so
和libhttp.so
,则需要使用
-rpath '$ORIGIN'
作为构建libclient.so
时链接器的参数。如果不直接调用链接器但让编译器调用它,则需要将以下内容添加到编译器的命令行中:
-Wl,-rpath,'$ORIGIN'
有关此内容的更多信息,请参阅man page for ld.so
。
答案 1 :(得分:2)
我对这个问题没有好的答案。
但我发现了几个好方法。
答案 2 :(得分:0)
为了正确查找不同操作系统的库(来自 java.library.path ),必须有不同的名称:
你可以从Java打电话:
System.loadLibrary( "http" );