I have an application written in Java with Spring Boot. This application needs to load .so files that are bundled with the project, I am using JNA to accomplish this. However, the JNA loader doesn't seem to be able to pick up the .so files and the application fails to start.
I've tried running the application from within IntelliJ and by running the packaged .jar with "java -jar". The .so files are kept in src/main/resources/linux-x86-64 for now. I've tried keeping them in a different directory, e.g src/main/resources/libs/linux-x86-64 and set the property "jna.library.path", but JNA still fails to find the files.
This is the debug log for JNA:
Trying (via loadLibrary) jnidispatch
Looking in classpath from sun.misc.Launcher$AppClassLoader#18b4aac2 for /com/sun/jna/linux-x86-64/libjnidispatch.so
Found library resource at jar:file:/home/dalivi/.m2/repository/net/java/dev/jna/jna/4.5.0/jna-4.5.0.jar!/com/sun/jna/linux-x86-64/libjnidispatch.so
Trying /tmp/jna--1339148563/jna4246531844315283838.tmp
Found jnidispatch at /tmp/jna--1339148563/jna4246531844315283838.tmp
Looking for library 'GTransTF'
Adding paths from jna.library.path: null
Trying libGTransTF.so
Adding system paths: [/usr/lib/x86_64-linux-gnu, /lib/x86_64-linux-gnu, /lib64, /usr/lib, /lib, /lib/i386-linux-gnu, /usr/lib/i386-linux-gnu, /usr/lib/x86_64-linux-gnu/libfakeroot]
Trying libGTransTF.so
Looking for version variants
Looking in classpath from sun.misc.Launcher$AppClassLoader#18b4aac2 for GTransTF
Found library resource at file:/home/dalivi/Workspace/java/geotransboot/target/classes/linux-x86-64/libGTransTF.so
Looking in /home/dalivi/Workspace/java/geotransboot/target/classes/linux-x86-64/libGTransTF.so
2019-04-25 12:43:38.032 ERROR 25897 --- [o-auto-1-exec-1] s.l.g.c.TransformationRestController : Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: libCoreGTrans.so: cannot open shared object file: No such file or directory
I does seem to find one of the files in the directory: libGTransTF.so, but then immediately fails when trying to find the file libCoreGTrans.so which is present in the same directory as the previous file.
I should mention, on Windows, this works just fine. JNA finds the corresponding dll files in the directory specified with "jna.library.path".
The windows behaviour is to search for dependent libraries in the directory that the .dll comes from, so when jna loads the library into memory the dependent library is loaded from there as well.
If you fire up a terminal window and cd to the directory that the .so exists in and run the command:
ldd ./libGTransTF.so
and it indicates that it's unable to find the library libCoreGTrans.so then you can see that the search order won't find this location.
The run-time link-loader (ld.so) uses a set of decisions as to where to find libraries. The default behaviour doesn't include the directory that the library was found.
You can add an option to the library when building to search in specific locations to find libraries. When you're building the library, you can say to search in the directory that the .so comes from at run time by adding the line:
-Wl,-rpath,'$ORIGIN'
to the link line. It needs to populate with the constant value $ORIGIN or else this doesn't work, so this can be a bit tricky to get right in a makefile. This is a value that gets resolved at run-time.
This is all very fine and well if you're building the library yourself, but if you're getting libraries from somewhere else, or you've already built them and don't want to rebuild them, you can use a tool such as patchelf to edit the search path for an .so to add it's origin location:
patchelf --set-rpath '$ORIGIN' libGTransTF.so
Then when you run:
ldd ./libGTransTF.so
it should be able to successfully find the libCoreGTrans.so library.
Related
I'm trying to do some template matching with the Java binding of OpenCV 4.3.0 in Eclipse, but attempting to load the template image always results in this error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.imgcodecs.Imgcodecs.imread_0(Ljava/lang/String;I)J
The line of code where this exception is thrown is this:
flowerTemplate = Imgcodecs.imread("/templates/flowerpot_white.png", Imgcodecs.IMREAD_COLOR);
I have tried a number of solutions suggested on similar questions on StackOverflow and elsewhere on the internet, including:
Pointing at the native library folder with the "Native library location" variable in the user library definition in Eclipse.
Adding the native library folder location to my PATH variable.
Adding the native library .dll location to my PATH variable.
Setting up the Eclipse run configuration to add the native library folder & .dll locations to the PATH and CLASSPATH variables.
Loading the library with the appropriate Java code, in each of the three ways I saw it suggested, in three different places which all run before the code that throws the exception.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.load(<path_to_the_dll>);
File opencvLibrary = new File(System.mapLibraryName(Core.NATIVE_LIBRARY_NAME));
System.load(opencvLibrary.getAbsolutePath());
Placing the .dll in question into my source folder and every subfolder. I am running it from within Eclipse, so this is also the program's working directory.
UnsatisfiedLinkError is a runtime exception that happens when running your Java program. So placing your file in the source folder will not work.
You need it to be available in a place that your program can find it.
See this article for example:
https://www.javaworld.com/article/2077520/java-tip-23--write-native-methods.html
In it they place the library in Linux's library path. In windows you'd similarly place it in the current directory (where you're running from) or in some shared location.
This article explains Window's dll search order: https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
You shouldn't need to explicitly call System.loadLibrary() yourself. That's the library's responsibility.
Your problem is that OpenCV is improperly installed on your machine or inaccessible from Eclipse.
For instructions on how to make in work in Eclipse see:
Add .dll to java.library.path in Eclipse/PyDev Jython project
After removing every load method and then adding them back one-by-one, I determined that the issue was most likely caused by Eclipse loading the native library folder twice.
I'm trying to work with a third-party SDK on RHEL. Running this vendor's sample code (using their own provided run.sh) throws what I'll call Error 1: java.lang.UnsatisfiedLinkError: Unable to load library 'redacted': Native library (linux-x86-64/libredacted.so) not found in resource path. I add the library location to the class path, and that error disappears.
It is replaced with Error 2: Java.lang.UnsatisfiedLinkError: libodbc.so: cannot open shared object file: No such file or directory, where I obviously am missing a dependency. I install the appropriate MySQL package (which puts the .so in /lib64) and it's happy.
Now both .so files are in /lib64, which is on the Java library path, so I would assume it should find them the same. Even pointing LD_LIBRARY_PATH to the library (which the vendor had done in their script) doesn't resolve Error 1.
Why is the first library required to be on the class path when Java uses java.library.path to find shared objects?
It's worth noting that the vendor's script didn't run correctly out of the box, which makes me wonder if it's an issue with my particular RHEL installation.
Im trying to use GStreamer in eclipse via jna.
Processing provides a library for that and all is fine if i try to run the code by running the sketch as an applet from eclipse, but when i try to execute the whole application i get a list of warnings(on Camera first call) like this one
(javaw.exe:3840): GStreamer-WARNING **: Failed to load plugin 'C:/Users/aaa/Desktop/bbb/ccc/video/library/\windows64\plugins\libgstvorbis.dll': `C:/Users/aaa/Desktop/bbb/ccc/video/library/\windows64\plugins\libgstvorbis.dll': Impossibile trovare il modulo specificato.
on 30+ of 140 plugins (probably the ones needed by my library for the camera managment)
the jna jar and the libraries are in the project folder C:/Users/aaa/Desktop/bbb/ccc/video/library/
and included in the build path
and the native code is in C:/Users/aaa/Desktop/bbb/ccc/video/library/windows64/plugins/
the path doesnt seem correct...
i never wrote libraries that need jna and i was trying to use this library as is if possible, any suggestions?
You can set the system property jna.library.path to the path to your primary library that is being loaded. All of that library's dependencies must either be in that directory or on %PATH%.
You can find the dependent libraries using dependency walker.
I'm trying to run a piece of sample code to connect to a specific DVR. I've got the SDK from the DVR manufacturer. The code tries to call a native library like this:
DHNetSDKLib INSTANCE = (DHNetSDKLib)Native.loadLibrary("dhnetsdk", DHNetSDKLib.class);
But, no matter where I put the dll file, I always get this error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'dhnetsdk': Specified module could not be found.
This being a piece of demo code, I feel this should work. The dll files are placed in the root folder as standard. I've tried copying them to the windows dll folders, gave them a folder of their own (C:\dll), adding this folder to the PATH variable, editing project properties to include the various folders to the build path, pointing to it like this:
DHNetSDKLib INSTANCE = (DHNetSDKLib)Native.loadLibrary("C:\\dll\\dhnetsdk.dll", DHNetSDKLib.class);
But nothing works. I've searched a lot but I have yet to find a solution. Most threads I come across however usually don't have the module bit in the error. Perhaps there is something wrong with the dll?
I'm trying to do this in java because I want to build an Android application using this dll, but now I'm wondering if that is even possible. The only search results I find are related to native Android code (I think). This project is being run as a standard application for testing purposes however.
I'm a little confused by this error. I'm new to Java and the error seems pretty self explanatory, but I've checked my paths (even defined my own) and it still fails to find this library. Is there something I'm doing wrong? See directory screenshot and error screenshot below:
UPDATE
UPDATE 2
If I create a new NetBeans project this works fine. Same code and everything. If I create new IntelliJ project I get this error above. I must be missing something in IntelliJ
UPDATE 3
Found the solution. Adding dependencies is a bit different in IntelliJ. Thanks all for the help.
http://www.jetbrains.com/idea/webhelp/configuring-module-dependencies-and-libraries.html
Obidisc4j is a .jar file. You just dont see its extension in the explorer.
Regular jar files are not loaded by System.loadLibrary. They are automatically loaded by the JVM's classLoader.
You are using a native library. It doen't matter if that library is in the classpath. There are 4 ways you can make the Java runtime load your shared library at runtime:
Call System.load to load the .so from an explicitly specified absolute path.
Copy the shared library to one of the paths already listed in java.library.path
Modify the LD_LIBRARY_PATH environment variable to include the directory where the shared library is located.
Specify the java.library.path on the command line by using the -D option.
Seems like your application is trying to find out a obidisc4j.dll (for Windows) or obidisc4j.so (for Linux). The file must be present on the PATH (but not the classpath). If you are not sure what PATH is your Java application searching in, you can write the following statement, before the point where the exception takes place, to find out the PATH.
System.out.println(System.getProperty("java.library.path"));
This will tell you about the paths where your DLL or SO file should be placed. You just need to place the file in ONE of those N-paths.