【问题标题】:JNA loading librariesJNA 加载库
【发布时间】:2011-09-02 00:25:49
【问题描述】:

我有两个库,一个带有 Ada 对象,一个带有 C++ 对象(我没有太多控制权)

Ada 的东西引用了 C 的东西,反之亦然...

这个符号在 libIPCAda.so 中:ipc_manager_shutdown_c

这个符号在 libIPCC.so 中:stream_buffer_header_size

当我进行这些 JNA 调用时:

   CLibrary INSTANCE8 = (CLibrary)
   Native.loadLibrary("IPCAda", //  <<< our library goes here
                      CLibrary.class);

   CLibrary INSTANCE9 = (CLibrary)
   Native.loadLibrary("IPCC", //  <<< our library goes here
                      CLibrary.class);

我明白了:

ld.so.1: java: fatal: relocation error: file <<my directory>>/lib/libIPCAda.so: symbol stream_buffer_header_size: referenced symbol not found

当我进行这些 JNA 调用时:

   CLibrary INSTANCE9 = (CLibrary)
   Native.loadLibrary("IPCC", //  <<< our library goes here
                      CLibrary.class);

   CLibrary INSTANCE8 = (CLibrary)
   Native.loadLibrary("IPCAda", //  <<< our library goes here
                      CLibrary.class);

我明白了:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'IPCC': ld.so.1: java: fatal: relocation error: file <<my directory>>/lib/libIPCC.so: symbol ipc_manager_shutdown_c: referenced symbol not found
    at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:163)
    at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:236)
    at com.sun.jna.Library$Handler.<init>(Library.java:140)
    at com.sun.jna.Native.loadLibrary(Native.java:379)
    at com.sun.jna.Native.loadLibrary(Native.java:364)
    at Test2$CLibrary.<clinit>(Test2.java:55)
    at Test2.main(Test2.java:74)

显然它不喜欢交叉依赖符号...有什么办法可以在 JNA 中实现这一点?

*EDIT 示例编译 *

gcc -c -fPIC -g -O0 -fstack-check -pipe -gnatE -gnatU -gnatwl -gnatf -gnatE -gnat05 -lIPCC -I- -gnatA <<my directory>>src/ndds_c.adb

【问题讨论】:

    标签: java c++ java-native-interface shared-libraries jna


    【解决方案1】:

    交叉链接将发生在本机代码领域,而不是 Java 内部。据 JNA 所知,它正在加载两个完全独立的本机库。

    您需要为库本身提供彼此的位置。有几种方法可以做到这一点;在编译共享库时设置 rpath,或者在运行时设置 LD_LIBRARY_PATH 环境变量。

    Rpath 可以说是更好的方法,因为它特定于需要它的二进制文件,并且不会污染运行时环境。您可以使用以下编译器标志在 gcc 中设置它:

    -Lpath-to-your-library -Wl,-rpath,path-to-your-library

    【讨论】:

    • 此目录在我的 LD_LIBRARY_PATH 上:>/lib/ 这是 .SO 文件所在的位置...这还不够吗?
    • 不,这应该使它们正确交叉链接......也许编译器没有包括所有符号。您是否尝试过从本机应用程序链接到它们?你在编译库时使用了哪些编译器标志?
    • 是的,我有一个 C++ 应用程序正在调用相同的函数并且它可以工作...当我尝试从 Java 中执行它时它就死了...请参阅上面的编辑以获取编译器标志
    • 尝试将-shared -Wl,-soname,your-library-name.so.1 添加到编译标志。这应该确保链接器知道它是一个共享库。
    【解决方案2】:

    您是否将所有原生关键字都放在一个“CLibrary”中?因此,当它执行第一个 Native.loadLibrary 时,它会尝试将所有符号从第一次加载映射到所有 Native 定义的方法。

    尝试将其分解为 CLibrary1 和 CLibrary2,它们与将由 Ada 和 C 库加载的符号完全对应。我相信 Java 会尝试映射您所有的本机方法,并且会在第一个 Native.loadLibrary 中缺少的一半上失败。

    CLibrary INSTANCE9 = (CLibrary)
    Native.loadLibrary("IPCC", //  <<< our library goes here
                      CLibrary.class);
    
    AdaLibrary INSTANCE8 = (AdaLibrary)
    Native.loadLibrary("IPCAda", //  <<< our library goes here
                      AdaLibrary.class);
    

    您还提到了 C++。 Java JNI 无法加载 C++ 错位符号。如果您可能强制实现导出为 C 符号,那么您会没事的。在谈论本机实现时不要交换 C 和 C++。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-17
      • 2015-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-09
      • 2018-05-29
      • 1970-01-01
      相关资源
      最近更新 更多