Mac + jni + java - java

A little background:
I have a java application that needs to talk to a third party hardware on mac. They have given me the sdk but it is not in Java. So I am trying to make jnilib that will act as a bridge between my java application and the SDK.
The issue:
I have made a small sample jnilib that talks to the SDK but when I try to use it in my java program I get the following error
Exception in thread "main" java.lang.UnsatisfiedLinkError: /Users/john.doe/Desktop/eclipse/workspace/Lesson13_Jni_Smart7/bin/libSmartTest7.jnilib: Library not loaded: build/Release/SMARTResponseSDK.framework/Versions/A/SMARTResponseSDK Referenced from: /Users/john.doe/Desktop/eclipse/workspace/Lesson13_Jni_Smart7/bin/libSmartTest7.jnilib
Reason: image not found
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1827)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1742)
at java.lang.Runtime.loadLibrary0(Runtime.java:823)
at java.lang.System.loadLibrary(System.java:1045)
at com.learning.lesson13.JniSmart7.<clinit>(JniSmart7.java:6)
From the error it looks like my libSmartTest7.jnilib is looking for the library SMARTResponseSDK.
What I have tried
I know where the library SMARTResponseSDK is on my Mac. I tried copying it over to my working folder in eclipse but I still get the error. I have tried using the -DJava.library.path but I still get the error.
Any ideas on what the best possible approach would be.

Once you are inside JNI code, it no longer matters what java.library.path points at.
Once you are inside JNI code, all you can do is to make sure library is visible to your code via LD_LIBRARY_PATH/DYLD_LIBRARY_PATH, or you can dynamically load your library file from any location you like.
So, for you, I suggest to take a look here:
dynamic loading of library in JNI - http://jnicookbook.owsiak.org/recipe-No-018/
Calling code from shared library (adapter pattern) - http://jnicookbook.owsiak.org/recipe-No-023/
You can also benefit from compilation flags while building your JNI library and use rpath.

Related

Is there a way to set up dependency for javacv's native part in maven, without manual installation and setting up java.library.path?

I have dependencies on org.bytedeco:opencv:4.1.2-1.5.2 that is in turn added to the project by
<groupId>org.datavec</groupId>
<artifactId>datavec-data-image</artifactId>
<version>${datavec.version}</version>
And for the needs of datavec-data-image the open-cv is loaded well and all the internal open-cv actions are executed.
Then, I'd like to do some open cv executions explicitly. I use a class from https://github.com/rostrovsky/pdf-table that does this stuff:
public class PdfTableReader {
private TableExtractor extractor;
private PdfTableSettings settings;
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
and it fails with
Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java412 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1864)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at pdftable.PdfTableReader.<clinit>(PdfTableReader.java:32)
at pdftable.ExtractSyzlekFromPdf.main(ExtractSyzlekFromPdf.java:12)
What I should to do to make this explicit javacv part to work with datavec image code without doing the double explicit open-cv installation to some location on my pc and setting up the java.library.path explicitly? At least the datavec image code obtains it somehow without this explicit set up.
I also tried to follow up this answer: https://stackoverflow.com/a/57515132/1759063 but with no success (if I understand right, they use the dependency that ships native libs in a cross-platform way, i.e. ships all platform binaries and the needed one is used on the right platform). I suppose there should be a way to make java.library.path to be dynamically updated if the open-cv native binaries packed to the maven dependencies are attached to the project. But how?
If DL4J guys can explain how to use the javacv part there correctly, that would be perfect.
The Java API of OpenCV found in the org.opencv package doesn't come with a loader, so the libraries need to be loaded by something else externally. In the case of the JavaCPP Presets for OpenCV, the libraries and wrappers are all bundled in JAR files and we can call Loader.load(opencv_java.class) to load everything as documented here:
https://github.com/bytedeco/javacpp-presets/tree/master/opencv#documentation
JavaCV, Deeplearning4j, and DataVec do not use that Java API of OpenCV, they use the API found in the org.bytedeco.opencv package, which loads everything automatically, so they do not need to call anything.

JNI "The specified procedure could not be found" when dependent library is linked

Following is the basic working structure:
MainProxy.dll ==> JNIClient.java
Using JNI, I have successfully loaded the MainProxy.dll and able to call the native functions. Following is the required structure:
Main.dll ==> MainProxy.dll ==> JNIClient.java
But when MainProxy.dll compiled and linked with another DLL Main.dll the System.loadLibrary("MainProxy"); call crashed with an exception
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: MainProxy.dll: The specified procedure could not be found
However, the MainProxy.dll is successfully compiled and linked against Main.lib and both DLLs are placed to gather with java.
Any idea what causes this issue and how it can be resolved?
Above is the snap from dependencywalker. The ISPVPLPR.dll is the Main.dll and LPRPROXY.DLL is the MainProxy.dll. And the linking between these two looks fine. The CreateNativeClass is exported along with other functions from ISPVPLPR.dll while only CreateNativeClass is imported in LPRPROXY.dll.
Above snap shows that exported native function from LPRProxy.dll
Finally, it turns out that OpenCV pre-compiled libraries was the issue. The ISPVPLPR.DLL was utilizing OpenCV and the copied DLLs were the default that came with setup and were compiled for WinXP Prof 64bit or Win2003 64bit. Since Opencv_Core241.dll requires RtlLookupFunctionEntry and RtlVirtualUnwind functions from Kernel32.dll and these functions were only provided for WinXP and Win2003 Kernel32.dll versions (MSDN Reference).
The solution was simple to recompile the OpenCV2.4.1 for Win7 and with GOD blessings it worked.
I recommend you to use Dependency Walker from microsoft. Use this utility to really check if MainProxy.dll is correctly linked with Main.dll.
If Dependency Walker shows you a problem, tell us how do you compiled and linked MainProxy.dll.
When Dependency Walker shows you no problem, you won't have anymore an java.lang.UnsatisfiedLinkError

Calling C++ from Java, but Java loads the wrong Glibc version

I am trying to call a C++ library from java side and have written necessary jni code. However, when my java code tries to load my C++ library via System.loadLibrary, it complains the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: libmylib.so: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by libmylib.so)
I later found that it is because I have two different GLIBC versions on my system, and the default one is the older one, while libmylib.so is required to built from the newer GLIBC. As a result, java links to the wrong GLIBC.
I tried the following things, but it does not work :(.
The first one is to try to load correct library manually via System.load in my java code. Specifically, I added the following codes before it loads my library:
static {
System.load("/usr/local/gcc-4.8.1-glibc-2.17/lib/libc.so.6");
System.load("/usr/local/gcc-4.8.1-glibc-2.17/lib/libstdc++.so.6.0.18");
System.loadLibrary(mylib);
}
The libc.so.6 is also added because libstdc++ depends on it (otherwise java will load the wrong libc and complains another error). However, this time java complains the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError:
/usr/local/gcc-4.8.1-glibc2.17/lib/libc-2.17.so:
__vdso_time: invalid mode for dlopen(): Invalid argument
And this error is caused by mixing two versions of GLIBC as described in this question.
The solution to that question is for building C++ program with -Wl,--dynamic-linker set properly (also described here). However, I don't know how to do that in Java.
I tried to set LD_LIBRARY_PATH to the newer version, but the situation is just the same :(.
Can I know how to make java link to the correct library?
(PS: a solution without make install newer version of glibc is preferred, since many other applications in my machine rely on the current default glibc)
I have been searching and trying solutions to my problem for days, but none of them succeed :(
Stackoverflow, you're my only hope :~.
System.load("/usr/local/gcc-4.8.1-glibc-2.17/lib/libc.so.6");
As I explained here, this can not possibly work.
By the time you reach above statement, the system libc.so.6 has already been loaded (at process startup), and you absolutely can not have two versions of libc.so.6 loaded into the same process.
Try using LD_PRELOAD=new_c_library.so java -javastuff

JNI lib crash, with a change in a .c file which is not included in the Makefile

We are facing an unusual problem, our JNI lib crashes at load time.
we use CentOS 5.4/G++ and VS2005 for development.
scenario:
we are currently working on an enhancement in our product and wanted to pass the new information back to the Java server code using JNI.
our C/C++ code works fine and we have tested it by running for around 6 hours or so in our dev environment. we have updated two result structure(which were already present) with one long value each to pass on the result of our new enhancement.
when we updated the JNI code to pass on the result to Java code, we found that Java server is crashing while loading JNI, we did debugging and found that JNI lib crashes, even, when we do not have our changes in JNI lib code base.
in our further debugging we found that, JNI Makefile includes a .c file(aa.c), which has a couple of our changes for the new enhancement; we started with commenting our changes in this aa.c file one by one and found that the crash happens only when we have BBB.cpp::method1() call(which we have added, as part of our new enhancement).
The unusual part is, this .c file(aa.c) is not needed in the JNI lib and we do not have any methods of aa.c called from JNI lib;
Now we have removed aa.c from the JNI Makefile and compile just fine, but still crashes when we have BBB.cpp::method1() call, if we remove this method1() call then it works fine.
we are not sure, why/how it is linking to a file which is not included, in the Makefile and crashing.
this is the error log we see
AgentServer#0 started: OK
12750 [Connection#Cnx:#0.0.1026:0 - Session#c0s1] ERROR com.xx.xxx.xxxx - Unable to load JNI BBBController Library
java.lang.UnsatisfiedLinkError: /opt/XXXXX/lib/libjnixxx.so: Can't load IA 32-bit .so on a IA 32-bit platform
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1751)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1676)
at java.lang.Runtime.loadLibrary0(Runtime.java:822)
at java.lang.System.loadLibrary(System.java:993)
Please suggest, any idea's would be appreciated.
Thanks in advance,
Aqura
I'd suggest you try turning on debugging in ld.so.1 when you start your application up and see if that gives you any clues. See LD_DEBUG in http://linux.die.net/man/8/ld-linux
finally, we are able to solve this issue.
We were seeing this issue because the Makefile we used to build the JNI lib had a lot of .o files which were not needed by the build.
one of the file happened to be the one, we were modifying, but other dependent files were not included in the Makefile and this was causing the crash at load time as it was not able to resolve the references.
to find and fix the issue, we created a simple Java class which just loads the libjni.so, this gave us undefined references to method, which we searched and started fixing the ones not needed.
I know this was a crude method and it will take some time to find and fix the original issue.
This worked for us, so I thought I would share this with others.
Aqura

What is the cause of an UnsatisfiedLinkError?

When i am trying to run my program it is giving the following error
Exception in thread "main" java.lang.UnsatisfiedLinkError: no jacob-1.14.3-x86 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)
at java.lang.Runtime.loadLibrary0(Runtime.java:823)
at java.lang.System.loadLibrary(System.java:1030)
at com.jacob.com.LibraryLoader.loadJacobLibrary(LibraryLoader.java:184)
at com.jacob.com.JacobObject.<clinit>(JacobObject.java:108)
at javaSMSTest.main(javaSMSTest.java:18)
please help
From the Javadoc:
Thrown if the Java Virtual Machine cannot find an appropriate native-language definition of a method declared native.
It is an error related to JNI. loadJacobLibrary is trying to load the native library called jacob-1.14.3-x86 and it is not found on the path defined by java.library.path. This path should be defined as a system property when you start the JVM. e.g.
-Djava.library.path=<dir where jacob library is>
On Windows, the actual native library file will be called jacob-1.14.3-x86.dll while on Linux it would be called libjacob-1.14.3-x86.so
You need the jacob-1.14.3-x86 library on your java library path.
On windows, this would be jacob-1.14.3-x86.dll.
This is a binary file which is used by java to run native methods. It's probably required by some library (jar) you're using.
In here you can see not only a jar, but also the binary required by the jar. Pick the one for your platform.
To quote http://www.velocityreviews.com/forums/t143642-jni-unsatisfied-link-error-but-the-method-name-is-correct.html:
There are two things that cause UnsatisfiedLinkError. One is when
System.loadLibrary() fails to load the library, the other is when the
JVM fails to find a specific method in the library. The text of the
error message itself will indicate which is the case...
The error which you describe clearly cannot find the library at all. As the others have said, include it in your Java library path.
The other error—when the library can be found but the method within the library is not found—looks as follows:
java.lang.UnsatisfiedLinkError: myObject.method([Ljava/lang/Object;)V
In this case you either have the wrong method name, or will have to go back and add the method and recompile the code...

Categories

Resources