I've got a Java project that uses several native DLLs but only uses System.load() to load one of them, and it's dependent on the others. I'm not allowed to modify that code. System.load() looks in java.library.path, which I can set via a command line parameter, but according to the top answer in Java JNI and dependent libraries on Windows the loading of dependent DLLs is done by Windows, which only cares about PATH, not java.library.path. So I'd need to add the directory that has the DLLs to PATH, and it'd be lovely to do that via command line parameters as well. Can it be done this way?
Edit for clarification: I'm running my code from Eclipse as a jUnit plug-in test, and I'm trying to figure out how to change the run configuration to get this effect. I changed java.library.path by adding the following to the VM arguments box in the Arguments tab:
-Djava.library.path="D:/prototype/resources/nativelib/x64;${system_property:java.library.path}"
D:/prototype/resources/nativelib/x64 is, of course, the directory where the DLLs are stored.
I tried adding
-Dpath "D:/prototype/resources/nativelib/x64;${system_property:path}"
or
-DPATH "D:/prototype/resources/nativelib/x64;${system_property:PATH}"
in the same place, but neither of them got the desired result.
On the command line enter the following command.
set PATH=%PATH%;C:\path_to_ur_dlls
And yes, you can do it inside java code as following.
Process proc = Runtime.getRuntime().exec("cmd set PATH=%PATH%;C:\\path_to_ur_dlls");
proc.waitFor();
Related
This has really got me baffled.
In my Eclipse workspace I have a project called "Java scratchpad". In "Package Explorer" you see "src" (Source Folder) under this and then "root" (Package). Under "root" is a .java file called "LoggingTest.java".
So the path to this java file is "G:\My Documents\software projects\workspace\Java scratchpad\src\root\LoggingTest.java".
When I run the following code in Eclipse:
Path currentRelativePath = Paths.get("");
String s_currRelPath = currentRelativePath.toAbsolutePath().toString();
String pathWithForwardSlashes = s_currRelPath.replace( "\\", "/" );
System.out.println( "path " + pathWithForwardSlashes );
The result is
path G:/My Documents/software projects/workspace/Java scratchpad
But... when I am running the same piece of code at the Command Prompt I have to start in the following directory:
G:\My Documents\software projects\workspace\Java scratchpad\bin
... and then go > java root.LoggingTest at the prompt.
The output from the above bit of code is then:
path G:/My Documents/software projects/workspace/Java scratchpad/bin
In other words, when you run the thing at the Command Prompt you are running a .class file under the \bin directory, but when you run in Eclipse, the Eclipse framework "pretends" that the bin directory doesn't exist.
And the upshot is that I get different values for the "current relative path" (CWD) depending on whether I'm running in Eclipse or at the Command Prompt. If I want to make or use a directory relative to the CWD I'm going to get different values depending on whether I'm running in Eclipse or at the Command Prompt.
I'm feeling quite slow tonight. What should I do? Is there a way of detecting whether a project is being run in Eclipse or at the Command Prompt? Or should I simply try to detect whether the path ends in "\bin" and remove those four characters to make the paths equivalent?
later
Just adding a note in reply to the comment from E-Riz:
It's a simple thing: I want to create logs and I want to create Lucene indices... and to keep things in one location (at this stage anyway) I just want to put this output in a location such as ...\Java scratchpad\output\indices\[name of index] or, respectively, ...\Java scratchpad\output\logging\[name of log].
And, yes, of course at present I do know the absolute path involved here... however, as the name suggests, this is a "scratchpad" or test area... so then this code which uses the CWD to determine where to put or find logs or indices can be used more generically, without having to know the absolute paths involved.
But it has to work either in Eclipse or at the command prompt...!
NB my current workaround is indeed to check whether pathWithForwardSlashes ends in "\bin", and if so to delete these last 4 chars. I can't be the only person to have encountered this oddity. Bet there are cleverer solutions!
There's a couple of facts that you should know or keep in mind:
At runtime, Java can (should) be given a classpath to work with; the default application classpath is just . (the current directory where java was invoked from). That's why it seems to you that you must run your program from the \bin directory of your project; because you haven't told the JVM anywhere else to look for classes. You should be setting the runtime classpath when running your application, which can be done a variety of ways but for simple programs is often done via a batch file or shell script. Note that using -cp to specify the classpath will be crucial when you depend on any JARs.
In Eclipse, since applications aren't run via a command-line, Eclipse has Launch Configurations that encapsulate all the details necessary for launching a program (in "run" or "debug" mode). Here's a decent tutorial (although a bit dated; you can find lots more info about Launch Configurations out there on the Interwebs. The key piece of configuration you're looking for is on the Arguments tab, where you can specify the working directory for a program launch config. The default is the project's root directory. See how that's different than when you've been running your on command line? That explains the difference you're seeing in output. You could change the working directory in the Eclipse Launch Configuration, but I tend to prefer to keep it as the project root.
So, you have a couple of options to make things consistent: use a script/batch to run your app on the command-line, specifying -cp so the JVM knows where your class files are (and any other JARs it might need down the road, too); or, reconfigure your Eclipse launch to match where you run from on the command line. I think the (by far) preferable option is the first one.
Having said all that, you should usually not need to do any path manipulation at all when it comes to files/resources in Java. Everything is relative to either the current working directory where Java was run from, or the classpath.
I am using ClearTK along with SVM-Light programmatically within Java. I have downloaded the package both for ClearTK integration as well as for SVM-Light itself. Whether I run via Eclipse or the command line, I keep getting
Cannot find file "svm_learn"
I try putting it in the current directory. I try putting including its location using "-cp" on the command line or add the folder in Eclipse to the runtime classpath. What must I do to get my Java code to recognize where the two executables reside?
You need to adjust the $PATH variable for your system to include the location for the two executables. Only then will eclipse or command line execution pick up these tools. It is not good enough to do -cp or add it to your Eclipse runtime classpath.
Examples include:
export PATH=$PATH:{svm light path}
for Linux or
set PATH=%PATH%;{svm light path}
for windows
In addition, if using Eclipse, you may have to go to your environment tab and make sure you reference the system path variable by pushing Select and then selecting Path
Hi I have a java program which has to invoke a native program, and this native program are given by two so files. So I create my so file in order to use this native program APIs to do something for my java program. I was trying to merge two so files with my created so file into single one, and run my java program. However, it seems that it failed this way. To be more concrete, here is my example.
I have a java program A which has to invoke some native code. Therefore I've written some native code and built it as a shared library (called: C.so).
Unfortunately, the native code I've written have to use other code which is in other so files. (A.so, B.so)
Thus, any ideas how to compile my so file with A.so and B.so in order to make my java program work?
I'm assuming the following:
When you link c.so, you are listing a.so and b.so on the command line.
When you run ldd on c.so, you see a.so and b.so.
When you run, you set -Djava.library.path to include the directory containing all three.
When you run, you do NOT set LD_LIBRARY_PATH to include the directory containing all three.
You will get the desired results if you set the LD_LIBRARY_PATH environment variable to include the directory with the libraries in it.
For more explanation, and an alternative, see https://github.com/bimargulies/jni-origin-testbed.
Currently I am starting my Slick 2D application via this batch file-
java -Djava.library.path=lib -Xms512m -Xmx512m -jar myapp.jar %1
Where lib is the folder that contains the LWJGL/Slick libraries and myapp.jar is my application.
Although this is easy and effective I want to be able not to have to run a script all the time and actually create a java .jar to do this.
So my question is, how would I 'convert' this batch script into Java code?
Why you would want Java code for this is beyond me as that creates exactly the same problem for you again – namely running your startup Java program that then starts another Java program; you'd be at the same point as before.
However, you don't need to create a JAR in any case. You can stuff all your compiled .class files somewhere and set that as the classpath. A JAR is little more than a main class and a classpath bundled into one.
So instead of your invocation above you can then use
java ... -cp %USERPROFILE%\Java\MyApp myapp.gui.Main
or something like that. Set the classpath with -cp and give the main class on the command line instead of the JAR.
Any -D command line arguments can be set via java.lang.System.setProperty. But the memory parameters can't be set from inside a JVM as far as I know. Therefore, there is no way to do what you want.
Instead you could generate e.g. a Windows executable with JSmooth. Such a wrapper should be able to set all JVM arguments. But in the end the situation is similar to the script. You have some kind of wrapper.
The easiest way is to use a program like JarSplice (http://ninjacave.com/jarsplice)
You can easily create a jar executable with all needed lib. it works very well
I have a Java program that is calling C code through JNI that I'm attempting to run on Linux. The external code consists of two .so files: one for the JNI bindings (built with swig) and the other with the actual functions. I have the two libraries in the same directory and LD_LIBRARY_PATH is set correctly. ldd reports no problems when running from the command line, but when I set the LD_LIBRARY_PATH to the same value in the "run configurations" dialog in the Eclipse editor and attempt to execute the program, it gets the following error:
java.lang.UnsatisfiedLinkError: [path to libraries]/[JNI binding library].so: [actual code library].so: cannot open shared object file: No such file or directory
This leads me to believe that the JNI wrapper library is loaded successfully, but there is a failure when that library attempts to load the library containing the actual code. Is there any way to debug this further?
I will further note that this problem is happening in the eclipse editor itself and that I haven't attempted to package the code into a jar and run it within a free-standing jvm instance.
I think the issue is with the call to System.loadLibrary(String) and using LD_LIBRARY_PATH. Using loadLibrary("foo") will look in your java.library.path for something named libfoo.so. If nothing named libfoo.so is found you will get this error.
Now if you just set up the LD_LIBRARY_PATH, the native symbols you want will automatically be picked up by the linker, so you don't need to set up -Djava.library.path.
In my experience with swig in the gdal project, this error is actually harmless and since the LD_LIBRARY_PATH is set up, this will work fine.
I would recommend using -Djava.library.path and calling loadLibrary explitly, the reason being that if you ever decide to deploy your app with webstart, you will explicitly need to call loadLibrary to get your native libs picked up.
When I use eclipse I follow the instructions that Daff gave where you edit the native library under the jar in the Libraries tab in the Build Path. Just to mention again, this just sets java.library.path under the covers.
It may be that you just have to find the right place on the run config dialog to put the -Djava.library.path=... option. Offhand I think you want -D defines in the "vm arguments" on the arguments tab, whereas if you want to define LD_LIBRARY_PATH that goes on the environment tab. Eclipse will merrily let you put things in places where they won't mean what you think they mean. Anyway, I've used libraries this way before and if I get a chance I will look up what I did and edit my answer here.
Another thing to try is to play with LD_DEBUG. You can set the environment variable LD_DEBUG to various things (try ALL), and then the linux loader will divulge all sorts of useful information about what an application is trying to load, where it's looking for things, etc. Of course, this pre-supposes you launch eclipse from a command line, so you can both set the env vars and see the loader diagnostics; but as far as the system is concerned, when you run your app from inside eclipse, your app is just something eclipse is doing, so any library loading behavior can be seen in this way.
You could try -Djava.library.path=actual.so in command line parameters perhaps?
On windows, I had similar problems with a 3rd party library, which used a JNI wrapper DLL for its DLLs. My project had the DLL in the lib directory so I added lib to the PATH (e.g. PATH=%PATH%;./lib environment variable and everything started working.
As far as I know the Eclipse doesn't use the LD_LIBRARY_PATH.
The easiest way to set up the right native library path is to go to
Project properties -> Java Build Path -> Libraries
Then expand either the JRE System Library entry or (if available) the
Jar File that uses you native Library,
choose "Native Library Location" then click "Edit..." and choose the folder your libraries are in. Actually it does set the -Djava.library.path variable so you have to include this in your command line if you start your program from outside eclipse.
Are there any other libraries that your two libraries depend on? If so, you need to make sure they are also accessible to the JVM.
Be aware, manually setting "-Djava.library.path" seems to erase the default library path.
So with the following code:
public class LibTest {
public static void main(String[] args) {
String property = System.getProperty("java.library.path");
StringTokenizer parser = new StringTokenizer(property, ":");
while (parser.hasMoreTokens()) {
System.err.println(parser.nextToken());
}
}
}
Launched from eclipse with Java 1.6.0_14 outputs:
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/opt/java/jre/../lib/i386
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/usr/lib/xulrunner-devel-1.9.0.11
/usr/lib/xulrunner-devel-1.9.0.11
/usr/java/packages/lib/i386
/lib
/usr/lib
But when I set the JVM arg "-Djava.library.path=/tmp/" I only get:
/tmp/
If you are manually setting java.library.path this may explain why ldd works from the command line but your .so does not from eclipse/java.
You can try not setting java.library.path and use System.load with the absolute path to your library instead of calling System.loadLibrary. This may allow the JVM to find your .so and still use the default path when searching for its dependencies.
Of course, if this is no use then you can also try turning on jni debug output with "-verbose:jni" on the command line. This may give you some clues to the problem.
Yes the LD_LIBRARY_PATH worked for me
Adding this answer may be it can be useful In AIX Machines we need to setup LIBPATH environment variable instead of LD_LIBRARY_PATH.