【问题标题】:JNI "symbol lookup error" in shared library on LinuxLinux 上共享库中的 JNI“符号查找错误”
【发布时间】:2012-03-04 21:19:37
【问题描述】:

Java VM 在执行 JNI 函数时出现“符号查找错误”怎么办?符号查找错误不在支持 JNI 接口的主共享库中,也不是直接在链接到主库的库中,而是在链接到链接到 JNI 共享库的库中? (多么尴尬的一句话☺)特别是,当你不控制包含违规符号的库的代码时,你会怎么做?

我在使用 JNI 访问科学相机 (Andor NEO CMOS) 的 SDK 时遇到问题。我在 RHEL 6 上使用 Netbeans C/C++ 插件来创建一个共享库 (AndorC.so),它基本上围绕相机 SDK 提供的方法创建 JNI 包装器。摄像头 SDK 提供了一组访问摄像头的方法,这些方法封装在一个共享对象库 (libatcore.so) 中。 libatcore.so 库使用了一系列附加库,libatdevregcam.so(用于真实相机)、libatdevsimcam.so(用于模拟相机)、libatcl_bitflow.so(低级视频板驱动程序)等。

我已经对相机 SDK 进行了广泛的测试,我可以通过 C/C++ 轻松访问相机。我已经链接到从测试 C 程序(使用单独的头文件)实现 JNI 函数的共享库(AndorC)并且一切运行正常(即我可以读取图像并且程序正常完成)。

我的 Java 代码可以通过 JNI 接口从 SDK 执行“InitializeLibrary”和“FinalizeLibrary”函数,因此找到主 libatcore.so 库或我的 AndorC.so 库没有问题。 JNI 的基本设置似乎没有任何问题。但是,当我尝试为相机执行“打开”功能(即实际连接到真实和/或模拟相机的功能)时,我在 libatcore.so 库使用的库之一中遇到未定义符号错误运行时(libdevsimcam.so)。

/usr/local/java/jdk1.7.0_03/jre/bin/java: symbol lookup error: /usr/local/lib/libatdevsimcam.so: undefined symbol: _ZN20TAndorLibDebugOutput6OutputEPKciS1_xx24TAndorDebugFunctionLevel16TAndorDebugLevelS1_z
Java Result: 127

基本上,Java VM 的 libatcore.so(即主库文件)没有问题,定位相关的运行时库(/usr/local/lib/libatdevsimcam.so)也没有问题)但是当它试图打开相机时它会在该库中遇到一个未定义的符号(注意我实际上是在打开真实的相机而不是模拟的相机)。

当我检查每个库(libAndorC.so、libatcore.so、libatdevsimcam.so)的依赖关系时,我没有找到任何未定义的符号。显然,当程序直接从 C/C++ 运行时,libatdevsimcam.so 库中的未定义符号不是问题,但当 Java VM 尝试加载 libatdevsimcam.so 时会导致问题。

 libAndorC.so
linux-vdso.so.1 =>  (0x00007fff507ff000)
libatcore.so.3 => /usr/local/lib/libatcore.so.3 (0x00007fe23a278000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fe239f4a000)
libm.so.6 => /lib64/libm.so.6 (0x00007fe239cc6000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fe239ab0000)
libc.so.6 => /lib64/libc.so.6 (0x00007fe239730000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe239513000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fe23930f000)
librt.so.1 => /lib64/librt.so.1 (0x00007fe239106000)
/lib64/ld-linux-x86-64.so.2 (0x0000003f07000000)
libatcore.so
linux-vdso.so.1 =>  (0x00007fffd53ff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7e6b645000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f7e6b440000)
librt.so.1 => /lib64/librt.so.1 (0x00007f7e6b238000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f7e6af31000)
libm.so.6 => /lib64/libm.so.6 (0x00007f7e6acac000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7e6aa96000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7e6a717000)
/lib64/ld-linux-x86-64.so.2 (0x0000003f07000000)
ldd libatdevsimcam.so
linux-vdso.so.1 =>  (0x00007fff247ef000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f5219dc4000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f5219bbf000)
librt.so.1 => /lib64/librt.so.1 (0x00007f52199b7000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f52196b0000)
libm.so.6 => /lib64/libm.so.6 (0x00007f521942b000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f5219215000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5218e96000)
/lib64/ld-linux-x86-64.so.2 (0x0000003f07000000)

当我专门检查 Java VM 有问题的符号时,很明显该符号是未定义的。

nm libatdevsimcam.so | grep _ZN20TAndor
             U _ZN20TAndorLibDebugOutput6OutputEPKciS1_xx24TAndorDebugFunctionLevel16TAndorDebugLevelS1_z

我认为该符号可能未在 libatdevsimcam.so 库的发行版与调试版中定义,因此我尝试构建 libAndorC.so 的发行版,但遇到了同样的问题。

我有两个基本问题

  1. 这可能是 C++ 名称修改的问题吗?我尝试使用 gcc 而不是 g++ 编译我的相机测试程序,但遇到了大量编译错误。我读过 C++ 名称修改会导致问题。

  2. 这是不是厂家提供的libatdevsimcam.so库有问题?我无法控制 Andor 提供的支持相机的代码(我所能做的就是抱怨)。

我基本上被困在这一点上,因为所有 SDK 函数都需要对“Open”方法返回的相机句柄的引用。如果我无法打开相机,我将无法继续为我需要的相机开发 JNI 接口。

我对这个问题进行了广泛的研究,但没有找到任何直接解决该问题的答案。这不是 JNI 帖子中常见的标准“不满意的链接”错误,基本的 JNI 功能似乎可以工作(即您可以初始化和完成库或调用任何不直接访问相机的函数)。这似乎是 Java VM 遇到原生代码问题的情况,直接运行代码不会产生问题。您如何处理此类问题?这是我需要向制造商提出的问题,还是有处理此问题的配置/编译/链接方法?

一些额外的细节:

  • Netbeans 6.9.1 开发环境
  • JDK 1.7_0_03 64 位服务器
  • 将源代码编译为 64 位(即不应存在 32 位与 64 位的问题)

【问题讨论】:

    标签: java-native-interface


    【解决方案1】:

    您可以使用 LD_PRELOAD 摆脱它(但我认为这不是一个合适的解决方案)

    故事

    我遇到了同样的问题,我的情况是......

    *javaHelloWorldApp.java --> JNI_Hello_world.c --> 这个原生 c 函数调用 snmp 库*

    java: symbol lookup error: /home/source/bin/libmytest.so: undefined symbol: init_snmp

    我使用了 LD_PRELOAD,如 here 所示,现在解决了这个问题。 export LD_PRELOAD=/usr/local/lib/libnetsnmp.so.30

    未决问题

    ldd 给出,(注意,没有引用 snmp 库)

    ldd ../libmytest/bin/libmytest.so linux-gate.so.1 => (0xb7777000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75a3000) /lib/ld-linux.so.2 (0xb7778000)

    export LD_PRELOAD=/usr/local/lib/libnetsnmp.so.30 我看到了对 snmp 的引用,

    snmp$ldd ../libredsnmp/bin/libredsnmp.so

    linux-gate.so.1 =>  (0xb770c000)
        /usr/local/lib/libnetsnmp.so.30 (0xb763a000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb746c000)
        librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xb7462000)
        libcrypto.so.1.0.0 => /lib/i386-linux-gnu/libcrypto.so.1.0.0 (0xb72b7000)
        /lib/ld-linux.so.2 (0xb770d000)
        libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb729c000)
        libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb7297000)
        libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb7281000)
    

    我的编译行,

    gcc -fPIC -shared -o ./bin/libmytest.so -I/usr/lib/jvm/java-6-openjdk-i386/include/ -I/usr/lib/jvm/java-6-openjdk-i386/include/linux -static -lc JNI_Hello_world.c

    我尝试过的其他选项 -L/usr/local/lib -lnetsnmp 没有任何效果,所以我从编译中删除了。

    EDIT-1

    可以使用这两个命令并且没有其他环境变量, 一、编译源码

    gcc -c -fPIC ./mytest.c -o mytest.o -I$(JAVA_INC_PATH) -I$(JAVA_INC_PATH)linux
    

    现在,在构建共享库时使用 -rpath 链接器选项。

    gcc -shared -o ./bin/libmytest.so  mytest.o -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lnetsnmp
    

    详细参考

    有关详细说明,请参阅此 book(或仅此 Google 图书搜索 result,@ ch.41.10)

    【讨论】:

    • 链接期间的 -l 对我有用!惊人的!如果您在 Linux 上使用 Eclipse,请将其添加到 Miscellaneous 部分 GCC C Linker 下的 Linker Flags
    • 唯一有帮助的是 -Wl,-rpath,/usr/local/lib -L/usr/local/lib ...不需要 LD_PRELOAD。非常感谢
    【解决方案2】:

    我也遇到过类似的问题,后来发现是链接顺序的问题:

    您需要将-L/usr/local/lib -lnetsnmp 放在-o libmytest.so 之后才能正常工作。

    【讨论】:

    • 真的是这样。如果有人使用nar-maven-plugin,请使用链接器的<libs> 标签,而不是在<options> 中指定库。这使它们按正确的顺序排列。
    • 知道为什么标志的顺序很重要吗?
    猜你喜欢
    • 2018-06-14
    • 2017-08-02
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 2011-02-28
    • 1970-01-01
    相关资源
    最近更新 更多