如何调试linux中的java system.loadlibrary错误?

时间:2009-06-18 02:38:58

标签: java eclipse java-native-interface

我有一个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实例中运行它。

7 个答案:

答案 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。