4

我有一个 Java 程序,它通过我试图在 Linux 上运行的 JNI 调用 C 代码。外部代码由两个 .so 文件组成:一个用于 JNI 绑定(使用 swig 构建),另一个用于实际功能。我在同一个目录中有两个库,并且 LD_LIBRARY_PATH 设置正确。ldd 从命令行运行时没有报告任何问题,但是当我在 Eclipse 编辑器的“运行配置”对话框中将 LD_LIBRARY_PATH 设置为相同的值并尝试执行程序时,会出现以下错误:

java.lang.UnsatisfiedLinkError: [path to libraries]/[JNI binding library].so: [actual code library].so: cannot open shared object file: No such file or directory

这使我相信 JNI 包装器库已成功加载,但是当该库尝试加载包含实际代码的库时会失败。有什么办法可以进一步调试吗?

我将进一步指出,这个问题发生在 eclipse 编辑器本身中,并且我没有尝试将代码打包到 jar 中并在独立的 jvm 实例中运行它。

4

7 回答 7

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 并显式调用 loadLibrary,原因是如果您决定使用 webstart 部署您的应用程序,您将明确需要调用 loadLibrary 来获取您的本机库。

当我使用 eclipse 时,我按照 Daff 给出的说明在构建路径中的库选项卡中的 jar 下编辑本机库。再说一遍,这只是将 java.library.path 设置在幕后。

于 2009-06-24T06:26:22.917 回答
1

可能您只需要在运行配置对话框中找到正确的位置即可放置 -Djava.library.path=... 选项。我认为你想 -D 在参数选项卡上的“vm参数”中定义,而如果你想定义环境选项卡上的 LD_LIBRARY_PATH 。Eclipse 会很高兴地让你把东西放在它们不代表你认为它们的意思的地方。无论如何,我以前以这种方式使用过库,如果有机会,我会查看我所做的并在此处编辑我的答案。

另一件要尝试的事情是使用 LD_DEBUG。您可以将环境变量 LD_DEBUG 设置为各种事物(尝试 ALL),然后 linux 加载器将泄露有关应用程序试图加载什么、它在哪里寻找事物等的各种有用信息。当然,这个预先假设您从命令行启动 eclipse,因此您既可以设置环境变量并查看加载程序诊断;但就系统而言,当您从 eclipse 内部运行您的应用程序时,您的应用程序只是 eclipse 正在做的事情,因此可以通过这种方式看到任何库加载行为。

于 2009-06-24T23:39:52.243 回答
0

据我所知,Eclipse 不使用 LD_LIBRARY_PATH。设置正确的本地库路径的最简单方法是转到 Project properties -> Java Build Path -> Libraries 然后展开 JRE System Library 条目或(如果可用)使用您的本地库的 Jar 文件,选择“Native库位置”然后单击“编辑...”并选择您的库所在的文件夹。实际上它确实设置了 -Djava.library.path 变量,因此如果您从 Eclipse 外部启动程序,则必须将其包含在命令行中.

于 2009-06-18T12:33:36.997 回答
0

你可以试试-Djava.library.path=actual.so命令行参数吗?

在 Windows 上,我在使用 JNI 包装器 DLL 作为其 DLL 的 3rd 方库时遇到了类似的问题。我的项目在 lib 目录中有 DLL,所以我将 lib 添加到 PATH(例如PATH=%PATH%;./lib环境变量,一切都开始工作了。

于 2009-06-18T06:17:49.793 回答
0

是的 LD_LIBRARY_PATH 为我工作

于 2010-11-10T06:28:32.360 回答
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());
        }
    }
}

从 eclipse 启动,带有 Java 1.6.0_14 输出:

/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 调试输出。这可能会给你一些问题的线索。

于 2009-06-29T21:21:04.900 回答
0

添加这个答案可能很有用在 AIX 机器中,我们需要设置 LIBPATH 环境变量而不是 LD_LIBRARY_PATH。

于 2012-11-20T06:59:18.490 回答