Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:加载具有依赖项的共享库_Java_Shared Libraries_Jna - Fatal编程技术网

Java:加载具有依赖项的共享库

Java:加载具有依赖项的共享库,java,shared-libraries,jna,Java,Shared Libraries,Jna,我正在使用JNA用Java包装一个共享库(用C编写)。共享库是在内部编写的,但该库使用来自另一个外部库的函数,而另一个外部库又依赖于另一个外部库。所以情况是这样的: ext1试试这个,将这个函数添加到代码中。在加载DLL之前调用它。对于参数,请使用DLL的位置 public boolean addDllLocationToPath(String dllLocation) { try { System.setProperty

我正在使用JNA用Java包装一个共享库(用C编写)。共享库是在内部编写的,但该库使用来自另一个外部库的函数,而另一个外部库又依赖于另一个外部库。所以情况是这样的:


ext1试试这个,将这个函数添加到代码中。在加载DLL之前调用它。对于参数,请使用DLL的位置


    public boolean addDllLocationToPath(String dllLocation)
    {
        try
        {
            System.setProperty("java.library.path", System.getProperty("java.library.path") + ";" + dllLocation);
            Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
            fieldSysPath.setAccessible(true);
            fieldSysPath.set(null, null);
        }
        catch (Exception e)
        {
            System.err.println("Could not modify path");
            return false;
        }
        return true;
    }
}
嗯,

我最终找到了一个可以接受的解决方案,但不是没有大量的限制。我所做的是

  • 使用普通的JNA机制从动态链接库(libdl.so)映射dlopen()函数
  • 使用JNA中映射的dlopen()函数加载带有选项RTLD_GLOBAL set的外部库“ext1”和“ext2”

  • 这似乎真的很有效:-)

    这是一个老问题,但我找到了一个可以接受的解决方案,它也应该是可移植的,我想我应该发布一个答案。解决方案是使用的,因为在Linux上这将传递到
    RTLD\u GLOBAL
    dlopen()
    (在Windows上这是不需要的)

    现在,如果使用此库实现Java
    native
    方法,则在调用
    nativellibrary\getInstance()
    之后,还需要在同一个库上调用
    System.load()
    (或
    Sysem.loadLibrary()

    首先,一个指向JNA bug的链接:

    其中的一条评论说,基本上应该在从JNA中使用实际库之前加载依赖项,而不是以标准Java方式。我将复制粘贴我的代码,这是一个典型的场景:

    String libPath =
            "/path/to/my/lib:" + // My library file
            "/usr/local/lib:" +  // Libraries lept and tesseract
            System.getProperty("java.library.path");
    
    System.setProperty("jna.library.path", libPath);
    
    NativeLibrary.getInstance("lept");
    NativeLibrary.getInstance("tesseract");
    OcrTesseractInterf ocrInstance = (OcrTesseractInterf)
            Native.loadLibrary(OcrTesseractInterf.JNA_LIBRARY_NAME, OcrTesseractInterf.class);
    
    我编写了一个小型库,使用Tesseract为我的Java应用程序提供OCR功能。Tesseract依赖于Leptonica,所以要使用我的库,我需要先加载lept和Tesseract库。使用标准方法(System.load()和System.loadLibrary())加载库不会起作用,设置属性jna.library.path或java.library.path也不会起作用。显然,JNA喜欢以自己的方式加载库


    这对我来说在Linux中是可行的,我想如果设置了正确的库路径,这在其他操作系统中也应该可行。

    还有另一种解决方案。您可以直接在JNI代码中dlopen,如下所示:

    void loadLibrary() {
      if(handle == NULL) {
        handle = dlopen("libname.so", RTLD_LAZY | RTLD_GLOBAL);
        if (!handle) {
          fprintf(stderr, "%s\n", dlerror());
          exit(EXIT_FAILURE);
        }
      }
    }
    
    ...
    ...
    
    loadLibrary();
    
    这样,您将使用RTLD_GLOBAL打开库

    您可以在此处找到详细说明:

    如中所述,Linux上的一个简单但粗糙的解决方案是使用
    LD\u PRELOAD


    如果这是不可接受的,那么我建议Oo.Oo给出答案:
    dlopen
    JNI代码中带有
    RTLD\u GLOBAL
    的库。

    为了解决您的问题,您可以使用此包:。它使用RTLD_全局标志直接加载库

    以下是一个例子:

    import com.globalload.LibraryLoaderJNI;
    
    public class HelloWorldJNI {
     
        static {
            // Loaded with RTLD_GLOBAL flag
            try {
                LibraryLoaderJNI.loadLibrary("/path/to/my_native_lib_A");
            } catch (UnsatisfiedLinkError e) {
                System.Println("Couldn't load my_native_lib_A");
                System.Println(e.getMessage());
                e.printStackTrace();
            }
    
            // Not loaded with RTLD_GLOBAL flag
            try {
                System.load("/path/to/my_native_lib_B");
            } catch (UnsatisfiedLinkError e) {
                System.Println("Couldn't load my_native_lib_B");
                System.Println(e.getMessage());
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            new HelloWorldJNI().sayHello();
        }
     
        private native void sayHello();
    }
    

    它使用了与前面答案相同的dlopen()技巧,但它打包在一个独立的代码中。

    是Java属性
    Java.library.path中定义的库的路径。
    ?很好地定位库实际上是另一个抱怨,我求助于使用System.load(完整路径到共享库)-但我认为这个问题主要是netbeans的问题。加载库“ext”时的例外情况是在符号解析阶段,即库已正确定位等。我认为/担心这与运行时底层dlopen()调用中的RTLD_全局标志(或缺少)有关。感谢您的努力-您的建议在定位库时效果很好。但不幸的是,这不是我的问题,问题是库“ext2”中的符号对“ext1”中的函数不可用-当直接使用dlopen()库调用时(可能这就是我必须做的吗?),此行为由整数标志控制,而我正在寻找的行为是通过RTLD_全局标志实现的。这似乎比我想象的要难?!谢谢你,我已经研究这个问题好几个小时了,上面的解决方案都不起作用。谢谢。当我用LibraryLoaderJNI.loadLibrary()加载时,我从java中得到一个不满意的链接错误。我发现我需要两次“加载”库,一次是使用LibraryLoader。。。一次使用System.load。这是意料之中的事吗?
    void loadLibrary() {
      if(handle == NULL) {
        handle = dlopen("libname.so", RTLD_LAZY | RTLD_GLOBAL);
        if (!handle) {
          fprintf(stderr, "%s\n", dlerror());
          exit(EXIT_FAILURE);
        }
      }
    }
    
    ...
    ...
    
    loadLibrary();
    
    import com.globalload.LibraryLoaderJNI;
    
    public class HelloWorldJNI {
     
        static {
            // Loaded with RTLD_GLOBAL flag
            try {
                LibraryLoaderJNI.loadLibrary("/path/to/my_native_lib_A");
            } catch (UnsatisfiedLinkError e) {
                System.Println("Couldn't load my_native_lib_A");
                System.Println(e.getMessage());
                e.printStackTrace();
            }
    
            // Not loaded with RTLD_GLOBAL flag
            try {
                System.load("/path/to/my_native_lib_B");
            } catch (UnsatisfiedLinkError e) {
                System.Println("Couldn't load my_native_lib_B");
                System.Println(e.getMessage());
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            new HelloWorldJNI().sayHello();
        }
     
        private native void sayHello();
    }