我有一个Java程序通过JNI调用C代码,我试图在Linux上运行。外部代码由两个.so文件组成:一个用于JNI绑定(用swig构建),另一个用于实际功能。我在同一目录中有两个库,并且正确设置了LD_LIBRARY_PATH。从命令行运行时ldd报告没有问题,但是当我在Eclipse编辑器的“运行配置”对话框中将LD_LIBRARY_PATH设置为相同的值并尝试执行该程序时,它会收到以下错误:
java.lang.UnsatisfiedLinkError:[库的路径] / [JNI绑定库] .so:[实际代码库] .so:无法打开共享对象文件:没有这样的文件或目录
这让我相信JNI包装器库已成功加载,但是当该库尝试加载包含实际代码的库时,会出现故障。有没有办法进一步调试?
我将进一步注意到这个问题发生在eclipse编辑器本身,并且我没有尝试将代码打包到jar中并在一个独立的jvm实例中运行它。
答案 0 :(得分:2)
我认为问题在于调用System.loadLibrary(String)并使用LD_LIBRARY_PATH。使用loadLibrary(“foo”)将在java.library.path中查找名为libfoo.so的内容。如果找不到任何名为libfoo.so的内容,您将收到此错误。
现在,如果您只是设置LD_LIBRARY_PATH,链接器将自动拾取您想要的本机符号,因此您无需设置-Djava.library.path。
根据我在gdal项目中使用swig的经验,这个错误实际上是无害的,因为设置了LD_LIBRARY_PATH,这将正常工作。
我建议使用-Djava.library.path并在explitly中调用loadLibrary,原因是如果您决定使用webstart部署应用程序,那么您将明确需要调用loadLibrary来获取本机库。
当我使用eclipse时,我按照Daff提供的说明,在编辑路径的Libraries选项卡中的jar下编辑本机库。再说一遍,这只是设置java.library.path。
答案 1 :(得分:1)
可能您必须在运行配置对话框中找到正确的位置以放置-Djava.library.path = ...选项。我认为您希望-D在参数选项卡上的“vm arguments”中定义,而如果您想要定义环境选项卡上的LD_LIBRARY_PATH。 Eclipse会很乐意让你把东西放在他们认为不是你想要的地方。无论如何,我以前用这种方式使用过库,如果有机会我会查看我做了什么并在这里编辑我的答案。
要尝试的另一件事是使用LD_DEBUG。您可以将环境变量LD_DEBUG设置为各种东西(尝试ALL),然后linux加载器将泄露有关应用程序尝试加载的各种有用信息, 它正在寻找的东西等等当然,这预先假设您从命令行启动eclipse,因此您可以设置env变量并查看加载程序诊断;但就系统而言,当您从eclipse中运行应用程序时,您的应用程序只是eclipse所做的事情,因此可以通过这种方式看到任何库加载行为。
答案 2 :(得分:0)
您可以在命令行参数中尝试-Djava.library.path=actual.so
吗?
在Windows上,我遇到了与第三方库类似的问题,第三方库为其DLL使用了JNI包装器DLL。我的项目在lib目录中有DLL,所以我将lib添加到PATH(例如PATH=%PATH%;./lib
环境变量,一切都开始工作了。
答案 3 :(得分:0)
据我所知,Eclipse不使用LD_LIBRARY_PATH。 设置正确的本机库路径的最简单方法是转到 项目属性 - > Java构建路径 - >图书馆 然后展开JRE系统库条目或(如果可用) 使用本机库的Jar文件, 选择“Native Library Location”然后单击“Edit ...”并选择库所在的文件夹。实际上它确实设置了-Djava.library.path变量,因此如果启动程序,必须在命令行中包含它来自日食之外。
答案 4 :(得分:0)
您的两个库是否还有其他库?如果是这样,您需要确保JVM也可以访问它们。
请注意,手动设置“-Djava.library.path”似乎会删除默认的库路径。
所以使用以下代码:
public class LibTest {
public static void main(String[] args) {
String property = System.getProperty("java.library.path");
StringTokenizer parser = new StringTokenizer(property, ":");
while (parser.hasMoreTokens()) {
System.err.println(parser.nextToken());
}
}
}
使用Java 1.6.0_14输出从eclipse启动:
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/opt/java/jre/../lib/i386
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/usr/lib/xulrunner-devel-1.9.0.11
/usr/lib/xulrunner-devel-1.9.0.11
/usr/java/packages/lib/i386
/lib
/usr/lib
但是当我设置JVM arg“-Djava.library.path = / tmp /”时,我只得到:
/tmp/
如果你手动设置java.library.path,这可以解释为什么ldd可以从命令行运行,但你的.so不是来自eclipse / java。
您可以尝试不设置java.library.path并使用System.load和库的绝对路径,而不是调用System.loadLibrary。这可能允许JVM在搜索其依赖项时找到您的.so并仍然使用默认路径。
当然,如果没用,那么您也可以尝试在命令行上使用“-verbose:jni”打开jni调试输出。这可能会为您提供一些问题的线索。
答案 5 :(得分:0)
是的,LD_LIBRARY_PATH为我工作
答案 6 :(得分:0)
添加此答案可能有用在AIX机器人中,我们需要设置LIBPATH环境变量而不是LD_LIBRARY_PATH。