Running a JOGL app from a single JAR file

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Running a JOGL app from a single JAR file

sasq
This post was updated on .

Hello.

I wrote an application using JOGL, compiled it and run, and everything works fine.

Now I want to make a JAR file out of it, so that I could put it on my website for download, and it needs to run even if the user doesn't have JOGL libraries installed on his machine. Is there any way to supply the JOGL libraries within the JAR file itself to make it a self-contained app?

I tried to make a JAR file, but it doesn't seem to work: it prints an error about missing libraries:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/media/opengl/GLEventListener
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:643)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
Caused by: java.lang.ClassNotFoundException: javax.media.opengl.GLEventListener
        at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
        ... 11 more
Could not find the main class: Main. Program will exit.

How can I supply the JOGL libraries within my JAR file?

Edit: Oh, and I don't use any IDE, just plain old text editor and command line on Linux.

Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

sasq
gouessej wrote
I assume that you would like to create a fat JAR.
I don't know. Would I?
I see that this technique is "discouraged" at the website you provided.

What I want is to make a self-contained JAR file available for download and run by the user which doesn't have any JOGL libraries installed on his machine. If the "fat JAR" solution allows this, then yes, I would like to create one.

On that website they also say:

Furthermore, adding all native library files for all supported platforms will add-up to +3M of _compressed_ jar data!
Could this be avoided by providing a set of several self-contained JAR files, each for one supported platform? This way, they would together still be weighty, but the user could select the one compatible with his platform, which is a fraction of the whole set and less weighty to download, I guess?

Which files should I put into that JAR and in what structure to make it work? I'd like to put there only a minimal set of files which are actually used by my application. How can I figure out which are needed?

Oh, I forgot to add in my original post that I don't use Ant, Eclipse, NetBeans, nor any other IDE, just plain old text editor and a command line on Linux. I'll try to add it to my original post...

Hmm, but it turns out that I have the ant command on my system, so perhaps I could use it somehow... I'll need to dig into the post you linked, but for now it's black magic to me. Can you advice me any additional URLs I should check out to find more about what is this ant and how to use it?
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
sasq wrote
I don't know. Would I?
What you described in your first post made me think that you want to make a single fat JAR with everything in it, i.e a fat JAR (or any variant doing almost the same thing).

sasq wrote
I see that this technique is "discouraged" at the website you provided.
It's discouraged mainly because it mixes up everything (your code + third party libraries) together, making it hard to indicate that what was in a JAR came from a specific organization.

sasq wrote
What I want is to make a self-contained JAR file available for download and run by the user which doesn't have any JOGL libraries installed on his machine. If the "fat JAR" solution allows this, then yes, I would like to create one.
It's the most commonly used solution to achieve that even though I go a little further in my case.

sasq wrote
On that website they also say:

Furthermore, adding all native library files for all supported platforms will add-up to +3M of _compressed_ jar data!
Could this be avoided by providing a set of several self-contained JAR files, each for one supported platform? This way, they would together still be weighty, but the user could select the one compatible with his platform, which is a fraction of the whole set and less weighty to download, I guess?
It's possible but is it worth the effort? It depends on the size of your application.

sasq wrote
Which files should I put into that JAR and in what structure to make it work? I'd like to put there only a minimal set of files which are actually used by my application. How can I figure out which are needed?
I advise you to make it work first with the JARs mentioned in the second post. Then, you will be able to reduce the size of the JAR by using some atomic JARs but again is it worth the effort?

sasq wrote
Oh, I forgot to add in my original post that I don't use Ant, Eclipse, NetBeans, nor any other IDE, just plain old text editor and a command line on Linux. I'll try to add it to my original post...
You don't need an IDE to make a fat JAR. There are some softwares for that but they are a lot less flexible than the build tools like Ant.

sasq wrote
Hmm, but it turns out that I have the ant command on my system, so perhaps I could use it somehow... I'll need to dig into the post you linked, but for now it's black magic to me. Can you advice me any additional URLs I should check out to find more about what is this ant and how to use it?
I advise you to read this tutorial:
https://ant.apache.org/manual/tutorial-HelloWorldWithAnt.html

See Ant as a cross-platform make :)

I advise you to read carefully my post, it mentions tons of fat JAR limitations.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

sasq
gouessej wrote
It's discouraged mainly because it mixes up everything (your code + third party libraries) together, making it hard to indicate that what was in a JAR came from a specific organization.

Couldn't I just make separate directories in the JAR file, one for my package, and one for the libraries?

gouessej wrote
It's possible but is it worth the effort? It depends on the size of your application.

For the production version, I guess it might be worth the effort (smaller downloads, less traffic for the server etc.). Expecially if generating of these files could be automated through some makefiles.

gouessej wrote
I advise you to make it work first with the JARs mentioned in the second post.
That's why I'm trying to do by now.
gouessej wrote
You don't need an IDE to make a fat JAR. There are some softwares for that but they are a lot less flexible than the build tools like Ant.
OK, so I decided to go with ant, since I already have it on my system. (Thanks for the tutorial! It was very helpful). Here's my first attempt at writing the build file:
<project name="TextureQuads" basedir="." default="main">
	
	<property name="src.dir"     value="src"/>
	<property name="lib.dir"     value="lib"/>
	<property name="assets.dir"  value="assets"/>
	
	<property name="build.dir"   value="build"/>
	<property name="classes.dir" value="${build.dir}/classes"/>
	<property name="jar.dir"     value="${build.dir}/jar"/>
	
	<property name="main-class"  value="texQuads.Main"/>
	
	<path id="classpath">
		<fileset dir="/usr/share/gluegen-2/lib" includes="gluegen-rt.jar"/>
		<fileset dir="/usr/share/jogl-2/lib"    includes="jogl.all.jar jogl.test.jar"/>
		<fileset dir="${lib.dir}" includes="**/*.jar"/>
	</path>
	
	<presetdef name="javac">
		<javac includeantruntime="false"/>
	</presetdef>
	
	
	<target name="clean">
		<delete dir="${build.dir}"/>
	</target>
	
	<target name="compile">
		<mkdir dir="${classes.dir}"/>
		<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
	</target>
	
	<target name="jar" depends="compile">
		<mkdir dir="${jar.dir}"/>
		<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
			<manifest>
				<attribute name="Main-Class" value="${main-class}"/>
				<attribute name="Class-Path" value="/usr/share/gluegen-2/lib /usr/share/jogl-2/lib"/>
			</manifest>
		</jar>
	</target>
	
	<target name="run" depends="compile">
		<java classname="${main-class}" classpath="${classes.dir}" classpathref="classpath" fork="true"/>
	</target>
	
	<target name="run-jar" depends="jar">
		<java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/>
	</target>
	
	<target name="clean-build" depends="clean,jar"/>
	
	<target name="main" depends="clean,jar"/>
	
</project>

Note that I deliberately set the Class-Path field in the manifest file to point to my system libs, because I wanted to test if it will run from the JAR at all before trying to package them into the JAR file itself.

Compilation goes without any errors. I can run the final app from the command line by using java -cp {path to the JOGL libs} texQuads/main and it runs fine. So it seems to work. But...

When I try to run the JAR file, it throws up:

run-jar:
     [java] Exception in thread "main" java.lang.NoClassDefFoundError: javax/media/opengl/GLEventListener
     [java]     at java.lang.ClassLoader.defineClass1(Native Method)
     [java]     at java.lang.ClassLoader.defineClass(ClassLoader.java:643)
     [java]     at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
     [java]     at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
     [java]     at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
     [java]     at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
     [java]     at java.security.AccessController.doPrivileged(Native Method)
     [java]     at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
     [java]     at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
     [java]     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
     [java]     at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
     [java] Caused by: java.lang.ClassNotFoundException: javax.media.opengl.GLEventListener
     [java]     at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
     [java]     at java.security.AccessController.doPrivileged(Native Method)
     [java]     at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
     [java]     at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
     [java]     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
     [java]     at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
     [java]     ... 11 more
     [java] Could not find the main class: texQuads.Main. Program will exit.
     [java] Java Result: 1

So it seems that I cannot even run it with the class path set to my system libs :-/ What did I do wrong?

Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
The value of the attribute Class-Path is probably wrong. Please read the documentation:
http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Main_Attributes

It uses relative URLs, not absolute URLs. You should write "jogl.all.jar,jogl.test.jar" instead of "jogl.all.jar jogl.test.jar" (even though both should work).

Using the packages provided with various GNU Linux distributions is a bad idea, they are often obsolete and they don't contain the JARs containing the native libraries. If you use them, you'll have to modify a lot the example I gave you.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

sasq
gouessej wrote
Using the packages provided with various GNU Linux distributions is a bad idea, they are often obsolete and they don't contain the JARs containing the native libraries.
I know. I just set it that way to test if the JAR file would run on my machine at the very least.

As the next step I planned to put the libraries into the JAR file itself, as my original requirement is.

I just need to know which of these JOGL library files need to be packed in the JAR for it to work on other machines, too.

gouessej wrote
The value of the attribute Class-Path is probably wrong.
Thanks for the suggestion, I'll try with the relative paths too.
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
Actually, using the packages provided with various GNU Linux distributions is a bad idea even for development purposes.

Maybe you can simply copy the JOGL JARs into the same directory than the JAR you created (modify the Class-Path attribute too) and you will need to set the Java library path for the native libraries.

The example I gave you shows which JARs are necessary. If you create one JAR per platform, you'll have to hope that the end user won't pick the wrong one and actually, it will occupy much more space on your server than a single JAR. Moreover, some people install the 32-bit JVM on a 64-bit system which is another source of confusion...
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

sasq
gouessej wrote
Actually, using the packages provided with various GNU Linux distributions is a bad idea even for development purposes.

Perhaps, but it's not the issue right now, as long as the non-JAR version of my test app runs fine.
I'm on Gentoo Linux which compiles everything from sources and usually has everything up to date.
But if they stop running from some reason, I'll upgrade these libs from the JOGL website.

gouessej wrote
Maybe you can simply copy the JOGL JARs into the same directory than the JAR you created (modify the Class-Path attribute too) and you will need to set the Java library path for the native libraries.

Yeah, this way it works fine. Now how to make it run with these JARs embedded into my app's JAR file? When I put the library JARs inside the app's JAR, they are not seen by the class loader.

gouessej wrote
The example I gave you shows which JARs are necessary.

OK, I pretty much learned how to find out which JARs are needed by opening them and looking through them for the class from the error message. Maybe later I'll figure out how to repackage them. But for now, the main issue is how to run the app with all the libraries supplied in the JARs packed inside the main single stand-alone JAR file instead of supplying them separately and having the user copy it into the same directory with my app's main JAR.

Unfortunately, this quote from the Java docs doesn't seem very promising :-/

Note: The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's manifest to load classes in MyUtils.jar into the class path.

Unfortunately, they don't explain much about how such "custom code" should look like and how to do it.

gouessej wrote
If you create one JAR per platform, you'll have to hope that the end user won't pick the wrong one

Perhaps I could pre-select it for him by detecting the platform supplied by his browser. That's how many corporate websites do it (such as Oracle with Java, Adobe with Flash etc.). This is not an issue right now. So let's not get into unnecessary details for now, OK? The main issue right now is how to make the JAR self-contained.

Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
sasq wrote
<p>Perhaps, but it's not the issue right now, as long as the non-JAR version of my test app runs fine.<br/>
I'm on Gentoo Linux which compiles everything from sources and usually has everything up to date.<br/>
But if they stop running from some reason, I'll upgrade these libs from the JOGL website.</p>
Which version of JOGL does Gentoo provide? As far as I know, only Debian (thanks to Sylvestre) provides JOGL 2.2.4 right now, other distros provide only JOGL 2.0.2 and JOGL 1.1.1. If something goes wrong, we'll be able to help you only if you use the very latest version.

sasq wrote
<p>Yeah, this way it works fine. Now how to make it run with these JARs embedded into my app's JAR file? When I put the library JARs inside the app's JAR, they are not seen by the class loader.</p>
Then, you're not creating a fat JAR, you're trying to apply the method called "Jar-in-Jar", it's doable with or without Eclipse:
http://jogamp.org/wiki/index.php/JogAmp_JAR_File_Handling#Eclipse

However, I haven't tested it, I can't help you and if you have a very old version of JOGL 2, it won't work. Please look at the bottom of the page above, it shows how to set the classpath in this case.

sasq wrote
<p>OK, I pretty much learned how to find out which JARs are needed by opening them and looking through them for the class from the error message. Maybe later I'll figure out how to repackage them. But for now, the main issue is how to run the app with all the libraries supplied in the JARs packed inside the main single stand-alone JAR file instead of supplying them separately and having the user copy it into the same directory with my app's main JAR.</p>

<p>Unfortunately, this quote from the Java docs doesn't seem very promising :-/</p>

Note: The <code>Class-Path</code> header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if <code>MyJar.jar</code> contains another JAR file called <code>MyUtils.jar</code>, you cannot use the <code>Class-Path</code> header in <code>MyJar.jar</code>'s manifest to load classes in <code>MyUtils.jar</code> into the class path.
<p>Unfortunately, they don't explain much about how such "custom code" should look like and how to do it.</p>
This problem is already solved in JOGL but please use the example I gave you as is first. If you complicate things now, you will never succeed in making it work.

sasq wrote
<p>Perhaps I could pre-select it for him by detecting the platform supplied by his browser. That's how many corporate websites do it (such as Oracle with Java, Adobe with Flash etc.). This is not an issue right now. So let's not get into unnecessary details for now, OK? The main issue right now is how to make the JAR self-contained.</p>
Don't get into unnecessary complications and you'll make your self-contained JAR very soon. The very first example I gave you is rudimentary, it makes a single JAR from GlueGen, JOGL and your application JAR:
http://forum.jogamp.org/Fat-jar-deployment-method-ant-recipe-tp4032213p4032229.html
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

sasq
gouessej wrote
Which version of JOGL does Gentoo provide? As far as I know, only Debian (thanks to Sylvestre) provides JOGL 2.2.4 right now, other distros provide only JOGL 2.0.2 and JOGL 1.1.1.

You're right. The version I installed a couple of days ago (which I thought will be the most recent), is jogl-2.0_rc8-r1

gouessej wrote
If something goes wrong, we'll be able to help you only if you use the very latest version.

OK, so I downloaded the 2.2.4, branch "origin/b22x" commit "78f641de80d1c37cd61e5300eeba369c6aa9b1a1" version from the JOGL website and put the selected JAR libs into my project's lib directory.

sasq wrote
Then, you're not creating a fat JAR, you're trying to apply the method called "Jar-in-Jar"

So that's where we misunderstood each other: when you were speaking about "fat JAR", I thought it means putting the library JARs into my app's JAR and loading them from there. Now I see that I was supposed to repack all the particular files into a directory structure into my app's JAR.

So I did, and it seems to work now.
Well, almost:
It works on Linux and MacOS X, but on Windows I get:

Starting up the application.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\drott_000\Documents\gluegen-rt.dll
        at java.lang.ClassLoader.loadLibrary(Unknown Source)
        at java.lang.Runtime.load0(Unknown Source)
        at java.lang.System.load(Unknown Source)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibraryInternal(JNILibLoaderBase.java:596)
        at com.jogamp.common.jvm.JNILibLoaderBase.access$000(JNILibLoaderBase.java:64)
        at com.jogamp.common.jvm.JNILibLoaderBase$DefaultAction.loadLibrary(JNILibLoaderBase.java:96)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibrary(JNILibLoaderBase.java:459)
        at com.jogamp.common.os.DynamicLibraryBundle$GlueJNILibLoader.loadLibrary(DynamicLibraryBundle.java:388)
        at com.jogamp.common.os.Platform$1.run(Platform.java:209)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.jogamp.common.os.Platform.(Platform.java:179)
        at javax.media.opengl.GLProfile.(GLProfile.java:120)
        at texQuads.Main.main(Unknown Source)

from one user, and the following from another user:

c:\> java -jar TextureQuads.jar
Starting up the application.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load library: c:\\gluegen-rt.dll
        at java.lang.ClassLoader.loadLibrary(Unknown Source)
        at java.lang.Runtime.load0(Unknown Source)
        at java.lang.System.load(Unknown Source)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibraryInternal(JNILibLoaderBase.java:596)
        at com.jogamp.common.jvm.JNILibLoaderBase.access$000(JNILibLoaderBase.java:64)
        at com.jogamp.common.jvm.JNILibLoaderBase$DefaultAction.loadLibrary(JNILibLoaderBase.java:96)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibrary(JNILibLoaderBase.java:459)
        at com.jogamp.common.os.DynamicLibraryBundle$GlueJNILibLoader.loadLibrary(DynamicLibraryBundle.java:388)
        at com.jogamp.common.os.Platform$1.run(Platform.java:209)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.jogamp.common.os.Platform.(Platform.java:179)
        at javax.media.opengl.GLProfile.(GLProfile.java:120)
        at texQuads.Main.main(Unknown Source)

The "Starting up the application." piece comes from my app's main function, so it seems that at least the Java libs are properly being loaded and the application runs. But there is some problem with loading the native libs on Windows (gluegen-rt.dll in particular). On other platforms (Linux and MacOS X) it runs fine.

I have the Windows native libs in my JAR, I checked. Here's how it looks like:

$ jar  tf  build/jar/TextureQuads.jar  natives
natives/
natives/linux-amd64/
natives/linux-amd64/libjogl_desktop.so
natives/linux-amd64/libjogl_mobile.so
natives/linux-amd64/libnativewindow_awt.so
natives/linux-amd64/libnativewindow_x11.so
natives/linux-amd64/libnewt.so
natives/linux-amd64/libgluegen-rt.so
natives/windows-amd64/
natives/windows-amd64/jogl_desktop.dll
natives/windows-amd64/jogl_mobile.dll
natives/windows-amd64/nativewindow_awt.dll
natives/windows-amd64/nativewindow_win32.dll
natives/windows-amd64/newt.dll
natives/windows-amd64/gluegen-rt.dll
natives/macosx-universal/
natives/macosx-universal/libjogl_desktop.jnilib
natives/macosx-universal/libjogl_mobile.jnilib
natives/macosx-universal/libnativewindow_awt.jnilib
natives/macosx-universal/libnativewindow_macosx.jnilib
natives/macosx-universal/libnewt.jnilib
natives/macosx-universal/libgluegen-rt.jnilib

so everything seems to be in place. But Windows says otherwise...

gouessej wrote
This problem is already solved in JOGL but please use the example I gave you as is first. If you complicate things now, you will never succeed in making it work.

Well, though I'm an experienced programmer in C++ and a bunch of other languages, I'm still a noob when it comes to Java. I learn how to use JOGL since a week so far, and it's still hard to me to grasp some of these things. I already wasted a couple of days trying to make it compile, and then run, by setting up all these classpaths & stuff and testing lots of different combinations. Then I wasted another couple of days trying to figure out how to make those JARs according to your directions. Although I appreciate your help, I must admit that the information you provide is very scarce and enigmatic, it is all very poorly documented (otherwise I would figure it out myself from reading the docs & wikis). I know that you have a clear picture in your head of how it all works, but I don't, and I have a hard time having to actively dig these informations out from your head, and figuring out what question should I ask next to get another important piece you forgot to tell me.

gouessej wrote
Don't get into unnecessary complications and you'll make your self-contained JAR very soon.

That's the point: I don't know which solutions are "unnecessary complications" as long as I don't have a clear picture of how it all works internally. I must do a lot of experimenting in a trial-and-error approach and waste a lot of time – a time which could be saved if you state all these little details clearly from the very beginning instead of waiting for me to dig them up from your head. I'm not clairvoyant yet.

One of these important details I missed was the fact that JOGL has its own fancy mechanism for loading these native libraries from the JAR file, and that they have to be put in special locations with hard-coded names to make it work. Not knowing that, I must have to go through several failed attempts with different combinations of these paths before it finally worked. I did read the links you provided, and I did use the <zipfileset> trick, just in a wrong way, with wrong paths.

But that was only after you enlightened me that you didn't mean putting entire JARs into my app's JAR under the "fat JAR" name, but repacking them as plain files in a particular directory structure. You could tell me that a couple of posts ago, when I first asked about putting these JARs into my app's JAR, and you would save me some random erring then.

So is it me who makes unnecessary complications? Or is it the whole jumping through hoops I experience here which actually makes it harder?

Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
sasq wrote
<p>You're right. The version I installed a couple of days ago (which I thought will be the most recent), is jogl-2.0_rc8-r1</p>
Oh my .... Both Jar-in-Jar, multi-Jar and fat JARs aren't supported by JOGL 2.0.

sasq wrote
<p>OK, so I downloaded the 2.2.4, branch "origin/b22x" commit "78f641de80d1c37cd61e5300eeba369c6aa9b1a1" version from the JOGL website and put the selected JAR libs into my project's <code>lib</code> directory.</p>
It's far better.

sasq wrote
<p>So that's where we misunderstood each other: when you were speaking about "fat JAR", I thought it means putting the library JARs into my app's JAR and loading them from there. Now I see that I was supposed to repack all the particular files into a directory structure into my app's JAR.</p>

<p>So I did, and it seems to work now.<br/>
Well, almost:<br/>
It works on Linux and MacOS X, but on Windows I get:</p>

<pre>Starting up the application.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load library: C:\Users\drott_000\Documents\gluegen-rt.dll
        at java.lang.ClassLoader.loadLibrary(Unknown Source)
        at java.lang.Runtime.load0(Unknown Source)
        at java.lang.System.load(Unknown Source)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibraryInternal(JNILibLoaderBase.java:596)
        at com.jogamp.common.jvm.JNILibLoaderBase.access$000(JNILibLoaderBase.java:64)
        at com.jogamp.common.jvm.JNILibLoaderBase$DefaultAction.loadLibrary(JNILibLoaderBase.java:96)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibrary(JNILibLoaderBase.java:459)
        at com.jogamp.common.os.DynamicLibraryBundle$GlueJNILibLoader.loadLibrary(DynamicLibraryBundle.java:388)
        at com.jogamp.common.os.Platform$1.run(Platform.java:209)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.jogamp.common.os.Platform.<clinit>(Platform.java:179)
        at javax.media.opengl.GLProfile.<clinit>(GLProfile.java:120)
        at texQuads.Main.main(Unknown Source)
</pre>

<p>from one user, and the following from another user:</p>

<pre>c:\> java -jar TextureQuads.jar
Starting up the application.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Can't load library: c:\\gluegen-rt.dll
        at java.lang.ClassLoader.loadLibrary(Unknown Source)
        at java.lang.Runtime.load0(Unknown Source)
        at java.lang.System.load(Unknown Source)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibraryInternal(JNILibLoaderBase.java:596)
        at com.jogamp.common.jvm.JNILibLoaderBase.access$000(JNILibLoaderBase.java:64)
        at com.jogamp.common.jvm.JNILibLoaderBase$DefaultAction.loadLibrary(JNILibLoaderBase.java:96)
        at com.jogamp.common.jvm.JNILibLoaderBase.loadLibrary(JNILibLoaderBase.java:459)
        at com.jogamp.common.os.DynamicLibraryBundle$GlueJNILibLoader.loadLibrary(DynamicLibraryBundle.java:388)
        at com.jogamp.common.os.Platform$1.run(Platform.java:209)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.jogamp.common.os.Platform.<clinit>(Platform.java:179)
        at javax.media.opengl.GLProfile.<clinit>(GLProfile.java:120)
        at texQuads.Main.main(Unknown Source)
</pre>

<p>The "Starting up the application." piece comes from my app's <code>main</code> function, so it seems that at least the Java libs are properly being loaded and the application runs. But there is some problem with loading the native libs on Windows (<code>gluegen-rt.dll</code> in particular). On other platforms (Linux and MacOS X) it runs fine.</p>

<p>I have the Windows native libs in my JAR, I checked. Here's how it looks like:</p>

<pre>$ jar  tf  build/jar/TextureQuads.jar  natives
natives/
natives/linux-amd64/
natives/linux-amd64/libjogl_desktop.so
natives/linux-amd64/libjogl_mobile.so
natives/linux-amd64/libnativewindow_awt.so
natives/linux-amd64/libnativewindow_x11.so
natives/linux-amd64/libnewt.so
natives/linux-amd64/libgluegen-rt.so
natives/windows-amd64/
natives/windows-amd64/jogl_desktop.dll
natives/windows-amd64/jogl_mobile.dll
natives/windows-amd64/nativewindow_awt.dll
natives/windows-amd64/nativewindow_win32.dll
natives/windows-amd64/newt.dll
natives/windows-amd64/gluegen-rt.dll
natives/macosx-universal/
natives/macosx-universal/libjogl_desktop.jnilib
natives/macosx-universal/libjogl_mobile.jnilib
natives/macosx-universal/libnativewindow_awt.jnilib
natives/macosx-universal/libnativewindow_macosx.jnilib
natives/macosx-universal/libnewt.jnilib
natives/macosx-universal/libgluegen-rt.jnilib
</pre>

<p>so everything seems to be in place. But Windows says otherwise...</p>
You forgot to put the 32-bit native libraries into your fat JAR. Keep in mind that it is possible to use a 32-bit JRE on a 64-bit operating system. A 32-bit JRE on a 64-bit machine requires 32-bit binaries.

sasq wrote
<p>Well, though I'm an experienced programmer in C++ and a bunch of other languages, I'm still a noob when it comes to Java. I learn how to use JOGL since a week so far, and it's still hard to me to grasp some of these things. I already wasted a couple of days trying to make it compile, and then run, by setting up all these classpaths & stuff and testing lots of different combinations. Then I wasted another couple of days trying to figure out how to make those JARs according to your directions. Although I appreciate your help, I must admit that the information you provide is very scarce and enigmatic, it is all very poorly documented (otherwise I would figure it out myself from reading the docs & wikis). I know that you have a clear picture in your head of how it all works, but I don't, and I have a hard time having to actively dig these informations out from your head, and figuring out what question should I ask next to get another important piece you forgot to tell me.</p>

<p>That's the point: I don't know which solutions are "unnecessary complications" as long as I don't have a clear picture of how it all works internally. I must do a lot of experimenting in a trial-and-error approach and waste a lot of time – a time which could be saved if you state all these little details clearly from the very beginning instead of waiting for me to dig them up from your head. I'm not clairvoyant yet.</p>

<p>One of these important details I missed was the fact that JOGL has its own fancy mechanism for loading these native libraries from the JAR file, and that they have to be put in special locations with hard-coded names to make it work. Not knowing that, I must have to go through several failed attempts with different combinations of these paths before it finally worked. I did read the links you provided, and I did use the <zipfileset> trick, just in a wrong way, with wrong paths.</p>

<p>But that was only after you enlightened me that you didn't mean putting entire JARs into my app's JAR under the "fat JAR" name, but repacking them as plain files in a particular directory structure. You could tell me that a couple of posts ago, when I first asked about putting these JARs into my app's JAR, and you would save me some random erring then.</p>

<p>So is it me who makes unnecessary complications? Or is it the whole jumping through hoops I experience here which actually makes it harder?</p>
I just put a link to 20 lines of XML (Ant script) that you could simply copy/paste/modify to do the job. I think that our misunderstanding (fat JAR vs Jar-in-Jar) made us waste some time. Be patient, you're close to the aim. I warned you several times but you'll probably have some other troubles even with a fat JAR. For example, imagine that an end user tries to use an old Apple JRE 1.6 whereas your code uses Java 1.7... I hope that the extraction of the native libraries doesn't fail in some cases under Windows.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

sasq
gouessej wrote
Oh my .... Both Jar-in-Jar, multi-Jar and fat JARs aren't supported by JOGL 2.0.
Then again, this is an important piece of information, so it should be documented. If I saw it in the documentation, I would upgrade my libs right away, because then I'd have a reason for doing it and going around my distro's package manager.

gouessej wrote
You forgot to put the 32-bit native libraries into your fat JAR. Keep in mind that it is possible to use a 32-bit JRE on a 64-bit operating system. A 32-bit JRE on a 64-bit machine requires 32-bit binaries.
Good point. And it actually solved the problem! :)
Now my phat JAR runs correctly on all platforms I planned supporting.
But I'll need to think on a way to make it somewhat less phat, since it already weighs nearly 5 MB

There's a strange bug on one of my friend's Macs, though: It starts correctly with all the libs, it loads a texture, but then it doesn't display on the color background. The background quad with just some colors is rendering fine, just not the textured quad. I wonder why, since it doesn't print any errors nor throws any exceptions, so I guess the image is loaded correctly, and it is probably something on the side of OpenGL.

But it's not related to JAR files, so I should perhaps save it for another day, another thread, unless I figure out the cause myself...

gouessej wrote
I just put a link to 20 lines of XML (Ant script) that you could simply copy/paste/modify to do the job.
Yeah, and that's what I did, and it pretty much worked.
But only after I understood that this is what I actually need to do.

gouessej wrote
I warned you several times but you'll probably have some other troubles even with a fat JAR.
Yes, I keep your warnings in mind. I just decided to save it for later, until the problems will actually occur. For now, after the last correction with win32 libs, it seems to work as I expected. So thanks for all your help.
Reply | Threaded
Open this post in threaded view
|

Re: Running a JOGL app from a single JAR file

gouessej
Administrator
sasq wrote
Then again, this is an important piece of information, so it should be documented. If I saw it in the documentation, I would upgrade my libs right away, because then I'd have a reason for doing it and going around my distro's package manager.
Keep in mind that the JogAmp community is NOT responsible for the GNU Linux distros packaging management. I always ask the developers to use our very latest version, always. This is one of the first things I asked you to do.

sasq wrote
Good point. And it actually solved the problem! :)
Now my phat JAR runs correctly on all platforms I planned supporting.
But I'll need to think on a way to make it somewhat less phat, since it already weighs nearly 5 MB
Maybe we should fix your other problems first, shouldn't we?

sasq wrote
There's a strange bug on one of my friend's Macs, though: It starts correctly with all the libs, it loads a texture, but then it doesn't display on the color background. The background quad with just some colors is rendering fine, just not the textured quad. I wonder why, since it doesn't print any errors nor throws any exceptions, so I guess the image is loaded correctly, and it is probably something on the side of OpenGL.

But it's not related to JAR files, so I should perhaps save it for another day, another thread, unless I figure out the cause myself...
Look at how you generate the identifiers of your textures. It's just a guess.

sasq wrote
Yeah, and that's what I did, and it pretty much worked.
But only after I understood that this is what I actually need to do.
That's why I'm here, I'm here to transmit you some of my knowledge so that you get more and more autonomous. I have nothing to sell.

sasq wrote
Yes, I keep your warnings in mind. I just decided to save it for later, until the problems will actually occur. For now, after the last correction with win32 libs, it seems to work as I expected. So thanks for all your help.
You're welcome and I'll be there to help you. If you aim only recent Macs and if your user base isn't very silly, it should be ok.
Julien Gouesse | Personal blog | Website