JNA can't find shared library on Mac OS - java

I am writing an interface in Java which uses underneath library in "C".
Now, when I try to load the library specifying relative path, it cannot find the library.
If I give the absolute path, it works fine.
I want to know, is there something to do with relative and absolute path on MAc OS. Because same code works well on linux(even though I specify relative path on that).
Please Help.

Defining the system property jna.debug_load (pass -Djna.debug_load=true to your JVM) will result in console output indicating where JNA is looking for your native library.
Keep in mind you need to define jna.library.path to be the directory where JNA can find your library. That value should be an absolute path. If you're using something like myapp/libs then your operation is going to be dependent on whatever the process's current directory is set to.

Related

Why 2 Path for load Library JNA

Hello This is my code :
if (isWindows()) {
//System.setProperty("jna.library.path", getClass().getResource("/resources/win32-x86").getPath());//netbeans WinOs
System.setProperty("jna.library.path", System.getProperty("user.dir").toString()+File.separator+"Desktop");//compiler WinOs
} else if (isMac()) {
//System.setProperty("jna.library.path", getClass().getResource("/resources").getPath());//netbeans MacOs
System.setProperty("jna.library.path", System.getProperty("user.dir").toString()+File.separator+"Desktop");//compiler MacOs
} else {
System.out.println("Your OS is not support!!");
}
Why I have 2 PATH (don't understand because for add an image i have only one Path) by OS, one for use with IDE and another for use with .JAR ?
I just realized, that when I'm use windows and I run the project (from netbeans) the "Library" load and I get the information, but when I compile and I launch my .jar I get error :
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: %1 is not a valid Win32 application.
My Structure
It is correct?
On mac only work with this command : java -jar "/System/Volumes/Data/Users/hugoclo/NetBeansProjects/Prezauto/dist/Prezauto.jar"since Terminal. If click on jar i have message error : Not Found .....
Sorry about my English,
There can be two reasons for the "why". While Java is cross-platform, JNA (which relies on some native code) must necessarily behave differently on different operating systems. Particularly in the case of loading DLLs (Windows) or dynamic libraries (OSX), you don't want to mix and match. Because it might be possible to have a dll with the same name compiled for different operating systems, JNA's Getting Started page identifies standard locations for these libraries:
Make your target library available to your Java program. There are several ways to do this:
The preferred method is to set the jna.library.path system property to the path to your target library. This property is similar to java.library.path, but only applies to libraries loaded by JNA.
Change the appropriate library access environment variable before launching the VM. This is PATH on Windows, LD_LIBRARY_PATH on Linux, and DYLD_LIBRARY_PATH on OSX.
Make your native library available on your classpath, under the path {OS}-{ARCH}/{LIBRARY}, where {OS}-{ARCH} is JNA's canonical prefix for native libraries (e.g. win32-x86, linux-amd64, or darwin). If the resource is within a jar file it will be automatically extracted when loaded.
In your code, you appear to be trying to do the first option (setting the jna.library.path) to include the user's desktop. That's fine for testing, not good for production, and likely the reason your compiled jar can't find it. Furthermore, by setting this variable, you are overwriting any previous (default) location for it. If you want to go this route, you should copy the saved location and then append your own additional path to it.
However, for code you'll distribute to users, you don't want to have to rely on an absolute file path. It's far better to put the library in a standard relative path location: a resources path (src/main/resources if using Maven) that will be available on your (or any user's) classpath when executing. This seems to align with the commented-out Windows branch of your code, which will look in the win32-x86 subdirectory of your resources folder.
You may have told your IDE to add something to the classpath (so it works there) but if it's not in a standard location, it may fail in a jar.
I'm not sure why the macOS branch of your code does not put the resources in the darwin subdirectory but it probably should.

How to change / to \\ in the path to jvm.dll

I thought which title to choose for 30 minutes, because my problem is rather strange.
Suppose we have a C++ native dll (C.dll). I want to load this dll with the help of JNA into my java project. Now what's important: in C.dll there is widely used a file path, from where this dll was called. And there is literally an if-statement like this:
if (filepath[2] != _T('\\'))
{
//throw an arror and close dll loading
}
If I try to load this dll via JNA, it throws an internal dll error with the following message: "There is missing a certain sign '\' in: "C:/Program Files/AdoptOpenJDK/jdk-14.0.0.36-hotspot/bin/client" on position: 3"
I know the nature of that error and I also understand, that this if-statement is really silly, because it is absolutely anti-crossplatform, but I couldn't change C.dll, because it has come from 3rd party, well, you know that story.
What is also problematic - I couldn't just replace this file path parameter somewhere (f.e. via some other wrapper.dll or so), call then this wrapper via JNA and be happy, because all that file path checking inside C.dll is harcoded with the help of multiple macros and it is implied, that all the routines of receiveing and checking this file path are occured fully automatically (this is actually provided by other dlls, which C.dll have to use, and for which I don't have a source code, yes, it is that bad). So it is not so easy to find a concrete value which I could directly replace.
So, my question is: is it somehow possible to replace those (/) to double (\) backslashes in file path of jvm.dll in runtime or so? Is it possible to write a wrapper.dll, that will do it for my C.dll, either in C++ or java? I need to run this finally in JNA, that's actually why the file path is exactly JAVA_HOME or so - because as far as I understood java virtual machine is exactly the process, who loads C.dll in that situation, that's why I got the path to jvm.dll as a wrong file path. AFAIK all the java paths are harcoded with (/) in JDK, so from the JNA's side it is not directly possible in my opinion. But is it possible generally without changing original .dll? Maybe there exist something like path-replacers tools for java in Windows or so?

Java, Load native library inside classpath

I have the following distribution
.__bin
| |__start.sh
|
|__lib
|__Main.jar
|__Utility.jar
|__lib.so
Main.jar contains main method, in which I would like to access native functions provided by the lib.so bundled in the distribution. start.sh simply sets the classpath and bootstraps java.
What is the best approach to load the lib.so library inside the application? I am aware of two methods:
System.load(absolute path)
System.loadLibrary(name)
Former requires the absolute path of the library in the file system, latter requires setting the application specific java.library.path JVM argument. Which is better solution in this case? Would setting the library path in the start.sh script possibly break something? How could I get the absolute file system path of the library for the former solution?
Assuming I am not missing anything, isn't setting System.load the best approach? Your lib.so is not going to change since you have it in your structure. If you would want to give control to the end user to load the native/shared library from elsewhere have an optional parameter in start.sh. Else use the System.load().Just make sure to check the type of OS, since you will be having the different formats for file paths.
The load() method requires the complete path name of the library as an argument. For example, on a Solaris system you might write:
System.load("/home/me/libs/libmylib.so");
to load the libmylib.so library in the /home/me/libs directory.
Using the load() method is system-dependent because it uses a pathname to load the library and pathnames are usually system-dependent. Thus, loadLibrary() is sometimes a better choice. However, dynamically loadable libraries are system-dependent in nature so the use of load() may not compromise system-independence any more than the act of loading the library itself.
The loadLibrary() method requires just the name of a to load:
System.loadLibrary("mylib");
The loadLibrary() method searches for the library. The search performed by loadLibrary() depends on the system you are running on, but typically, it searches the directories listed in one of your environment variables set up to that purpose.
You can explicitly specify your absolute path.
Apart from system independence, there are no real differences security wise.
References :
1) https://security.stackexchange.com/questions/35724/security-implications-of-javas-system-load-vs-system-loadlibrary
2) https://www.chilkatsoft.com/java-loadLibrary-Linux.asp

How to use a JNI lib, with associated libs, at an arbitrary location?

We have an app that sometimes is installed with an associated app. Both may be installed separately, at different times, and neither is usually in the OS Path environment setting.
IF both apps are installed, the one I'm working on needs to use a JNI library from the other app. This library uses a dozen or so other native libs. While I can FIND the JNI lib, I can't seem to find a way to use it without requiring the user to change their system setup.
I've found the (hacky) technique to add the JNI lib to the java.library.path, I've been unable to find any way of updating the native Path so the JNI lib can find it's associated libs.
The only things that have worked so far are to:
Add the folder that the JNI and associated files are in to the OS path before launching our app.
Launch our app so the Current Working Directory is the JNI lib folder.
Neither of which makes for a hassle-free user experience.
So, is there any way for a Java app to modify it's own environment Path so the JNI lib can find it's associated native libs? (currently testing on Win7, will also need to support OS/X)
This can not be done with an unknown location at run time. According to jni documentation
"To load your shared native library module in Java, simply use Java's System.loadLibrary method in a Java class:"
as well as
"Another common reason for the native library not loading is because it is not in your path. On Windows make sure the path environment variable contains the path to the native library. On Unix make sure that your LD_LIBRARY_PATH contains the path to the native library. Adding paths to LD_LIBRARY_PATH can slow down other programs on your system so you may want to consider alternative approaches. For example you could recompile your native library with extra path information using -rpath if you're using GNU, see the GNU linker documentation (ld man page). You could use a command such as ldconfig (Linux) or crle (Solaris) to add additional search paths to the default system configuration (this requires root access and you will need to read the man pages)."
So thus you need to know the location and must be in a path to be able to load the file. If the location is not known it can not be done due to how jni works and the jvm works.
One way to load a JNI lib with dependent libraries is to load each of the dependents then load the JNI library.
For example, if bar.so is dependent on foo.so and both libraries exist in /some/dir, do the following:
System.load("/some/dir/foo.so");
System.load("/some/dir/bar.so");
Use System.load() instead of System.loadLibrary() so you can specify the absolute path to the library.
You'll have to load all dependents of all loaded libraries unless they can be found in the java.library.path path.
Hope this helps.

How automatically set Native Library Path and JAR's path through code

I was trying to automatically set the native library path and the JAR's path automatically during the runtime of a program of mine (in other words, I would like to perform the settings' definition through code.
I tried to execute the following in the beginning of my program flow:
System.setProperty("java.library.path", "\\some_folder");
apparently this should set up the native library path, but the application could not load the dlls in the folder. I've also tried some variations (like "jni.library.path") but none of them seemed to work. Is there another way to solve this?
The java.library.path is read only once when the JVM starts up. If you change this property using System.setProperty, it won't make any difference. the following blog provides options to load dlls in runtime.
http://fahdshariff.blogspot.jp/2011/08/changing-java-library-path-at-runtime.html

Categories