Linux上的共享库中的JNI“符号查找错误”

时间:2012-03-04 21:19:37

标签: java-native-interface

当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提供的代码来支持相机(我所能做的就是抱怨)。

  3. 我基本上处于困境,因为所有SDK函数都需要引用“Open”方法返回的相机句柄。如果我无法打开相机,我无法继续开发JNI接口到我需要的相机。

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

    其他一些细节:

    • Netbeans 6.9.1开发环境
    • JDK 1.7_0_03 64位服务器
    • 将源编译为64位(即应该没有32对64位问题)

2 个答案:

答案 0 :(得分:11)

您可以使用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没有任何影响,所以我从编译中删除了。

修改-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(或仅此谷歌图书搜索result,@ ch.41.10)

答案 1 :(得分:5)

我有类似的问题,后来我发现这是连接顺序的问题:

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