当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的发布版本,但我遇到了同样的问题。
我有两个基本问题
这可能是C ++名称错误的问题吗?我尝试用gcc而不是g ++编译我的相机测试程序,我遇到了大量的编译错误。我读过C ++名称修改可能会导致问题。
这是制造商提供的libatdevsimcam.so库中的问题吗?我无法控制Andor提供的代码来支持相机(我所能做的就是抱怨)。
我基本上处于困境,因为所有SDK函数都需要引用“Open”方法返回的相机句柄。如果我无法打开相机,我无法继续开发JNI接口到我需要的相机。
我已经广泛研究了这个问题,但我没有找到任何直接解决问题的答案。这不是JNI帖子中常见的标准“不满意链接”错误,基本的JNI功能似乎有效(即您可以初始化和完成库或调用任何不直接访问摄像头的功能)。这似乎是Java VM遇到本机代码问题的情况,只是直接运行代码不会产生。你是如何处理这类问题的?这是我需要带到制造商的问题还是有配置/编译/链接方法处理这个问题?
其他一些细节:
答案 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
详细参考
答案 1 :(得分:5)
我有类似的问题,后来我发现这是连接顺序的问题:
您需要在-L/usr/local/lib -lnetsnmp
之后放置-o libmytest.so
才能使其正常工作。