# LWJGL -> Runnable .jar



## tdc (29. Mai 2011)

Hi,
ich habe vor einigen Tagen angefangen, mich in LWJGL einzuarbeiten. Jetzt habe ich zur Übung ein kleines Spiel geschrieben und möchte es nun in eine ausführbare .jar exportieren.
Dafür gibt es bei eclipse 3 Optionen (in die .jar packen, in einen Ordner daneben und noch eine dritte), allerdings kommt bei allen 3 Optionen die Fehlermeldung, dass die nativen Dateien nicht gefunden werden.
Ich habe schon im Internet danach gesucht, wie man die nativen Dateien jetzt einfügen muss, aber ich habe keine funktionierende Lösung gefunden.
Mein Ziel wäre es, am Ende eine ausführbare .jar-Datei zu haben.
Aber wie macht man das am besten? Und wie muss man die nativen Dateien einbinden?

mfg tdc


----------



## freak_007 (29. Mai 2011)

Versuch mal die Native librarys in lwjgl.jar reinzustecken.


----------



## tdc (29. Mai 2011)

Also wenn ich die Linux-Natives in die lwjgl.jar (die sich in meiner erzeugten .jar befindet) direkt reinkopiere, kommt immer noch die gleiche Fehlermeldung:


```
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
Caused by: java.lang.UnsatisfiedLinkError: no lwjgl in java.library.path
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)
	at java.lang.Runtime.loadLibrary0(Runtime.java:823)
	at java.lang.System.loadLibrary(System.java:1028)
	at org.lwjgl.Sys$1.run(Sys.java:73)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.lwjgl.Sys.doLoadLibrary(Sys.java:66)
	at org.lwjgl.Sys.loadLibrary(Sys.java:82)
	at org.lwjgl.Sys.<clinit>(Sys.java:99)
	at org.lwjgl.opengl.Display.<clinit>(Display.java:130)
	at game.Game.start(Game.java:46)
	at game.Start.main(Start.java:11)
	... 5 more
```


Das:

```
Caused by: java.lang.UnsatisfiedLinkError: no lwjgl in java.library.path
```
scheint ja der Grund zu sein. Aber wie bekomme ich die lwjgl-libs zu java.library.path? Muss ich das automatisch beim Programmstart dorthin kopieren?


----------



## the GINI the M (29. Mai 2011)

Wenn Du Dein Spiel in Eclipse startest, musst Du ja den Ordner mit den Natives als "working directory" setzen. Kannst das nicht auch im Manifest machen?

EDIT: Achtung, das lwjgl.jar enthält die natives NICHT.


----------



## tdc (29. Mai 2011)

Das Problem ist nicht das Ausführen in Eclipse, das funktioniert einwandfrei, sondern das Exportieren. Die Fehlermeldung oben erhalte ich, wenn ich die exportierte .jar-Datei über die Konsole starte.

Du hast noch das Manifest erwähnt. Eigentlich dürfte es da kein Problem geben, denn das Manifest in der .jar-Datei (/META-INF/MANIFEST.MF) sieht folgendermaßen aus:

```
Manifest-Version: 1.0

Rsrc-Class-Path: ./ lwjgl.jar lwjgl_util.jar

Class-Path: .

Rsrc-Main-Class: game.Start

Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
```
Dort sind ja bereits lwjgl.jar und lwjgl_util.jar erwähnt.


----------



## Kr0e (31. Mai 2011)

Bau dir einen Extraktor der aus der internen Jar die native Libraries je nach Betriebsystem in den Ausführungsordner kopiert.
Ist sogar einfacher als es sich anhört... Machen alle guten Engines so...


----------



## the GINI the M (31. Mai 2011)

Oder, TDC, mach's als Webstart, das erspart Dir viel Liebesmüh!


----------



## Cottonwood (31. Mai 2011)

Bei mir hat das erst geklappt, als ich das ...\lwjgl\native\windows-Verzeichnis bei Eclipse als Working directory eingestellt hatte.


----------



## Spacerat (1. Jun 2011)

Also die natives gehören definitiv nicht ins Jar-Archiv. Ein vorläufig guter Platz dafür ist das Verzeichnis aus welchem man das Archiv starten will. Zum Starten benötigt man nun allerdings eine Batch-Datei bzw. ein Shellscript. Dieses hat die Aufgabe der JVM das aktuelle Verzeichnis dem "java.library.path" hinzuzufügen.

für Windows: java -Djava.library.path=.;%PATH% -jar myJar.jar

für Linux geht's ähnlich, aber mir ist grad' die Path-Variable nicht geläufig.

Will man die lwjgl-Jars auch mit publizieren muss so noch mit "java.ext.dirs" verfahren werden.


----------



## Cottonwood (1. Jun 2011)

Ich seh's einfach so, dass sich ein .jar mit Doppelklick starten lassen sollte. Ohne Rücksicht darauf, in welchem Verzeichnis ich mich gerade befinde.

Und wenn das aus irgend welchen Gründen nicht direkt möglich ist, dann sollte man sich dafür ein Setup bauen, mit dem der Desktop Icon mit den erforderlichen Parametern versorgt wird. Ich verwende dafür Inno-Setup.


----------



## Spacerat (1. Jun 2011)

@Cottonwood: Sicher ist das eleganter und auch professioneller. Aber bevor man so etwas macht, sollte man seine Software zumindest einmal ohne Eclipse oder sonst einer IDE zumindest einmal gestartet bekommen und ggf. ausgiebig testen, bevor man immer wieder eine Setup-Exe o.Ä. erstellt, feststellt, dass es immer noch nicht läuft und wieder von vorne anfängt. Da ist das Editieren eines Shell-Scriptes doch zunächst angenehmer oder seh' ich das falsch? Im übrigen lassen sich diese Pfade auch noch zur Laufzeit in der Main-Methode ändern, aber dann müsste man in Eclipse ewig das Jar neu erstellen und es hätte den selben Effekt wie der mit dem Setup.


----------



## Cottonwood (1. Jun 2011)

Spacerat hat gesagt.:


> Sicher ist das eleganter und auch professioneller. Aber bevor man so etwas macht, sollte man seine Software zumindest einmal ohne Eclipse oder sonst einer IDE zumindest einmal gestartet bekommen und ggf. ausgiebig testen, bevor man immer wieder eine Setup-Exe o.Ä. erstellt, feststellt, dass es immer noch nicht läuft und wieder von vorne anfängt. Da ist das Editieren eines Shell-Scriptes doch zunächst angenehmer oder seh' ich das falsch?



Das Setup erstellt man auch nur einmal.



Spacerat hat gesagt.:


> Im übrigen lassen sich diese Pfade auch noch zur Laufzeit in der Main-Methode ändern, aber dann müsste man in Eclipse ewig das Jar neu erstellen und es hätte den selben Effekt wie der mit dem Setup.



Das ist wohl weniger trivial. Man kann sie zwar setzen, aber das wirkt sich nicht aus.
Wenn es dir gelungen ist, solltest du das mal ganz detailliert beschreiben.


----------



## freak_007 (3. Jun 2011)

Ich hab ein self extractor für libs gefunden. moioli.net: sito di Silvio Moioli, programmatore Web e Open Source


----------



## Spacerat (3. Jun 2011)

@Cottonwood: Aber gerne 

```
public final class Distributable
{
	public static void main(String[] args)
	{
		try {
			System.loadLibrary("jogl");
			System.out.println("jogl found in java.library.path");
		} catch(Throwable e) {
			System.out.println("jogl not found in java.library.path");
		}
		AccessController.doPrivileged(new PrivilegedAction<Void>()
		{
			public Void run()
			{
				try {
					Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
					usrPathsField.setAccessible(true);
					String[] user_paths = (String[]) usrPathsField.get(null);
					String[] new_user_paths = new String[user_paths.length + 1];
					System.arraycopy(user_paths, 0, new_user_paths, 0, user_paths.length);
					new_user_paths[user_paths.length] = new File("").getAbsoluteFile().toString() + File.separator;
					usrPathsField.set(null, new_user_paths);
					usrPathsField.setAccessible(false);
					System.out.println("System ok");
				} catch(Throwable e) {
					System.out.println("System ****ed");
				}
				return null;
			}
		});
		try {
			System.loadLibrary("jogl");
			System.out.println("jogl found in java.library.path");
		} catch(Throwable e) {
			System.out.println("jogl not found in java.library.path");
			e.printStackTrace();
		}
	}
}
```
Sofern sich eine ladbare (32/64Bit beachten ) jogl.dll bzw. .so mit all ihren Abhängigkeiten im Verzeichnis des Jar-Archivs befindet, erhält man folgende Ausgabe:

```
jogl not found in java.library.path
System ok
jogl found in java.library.path
```
Okay... des funzt so jetzt scheinbar nur in der Konsole aber ich kann euch versichern, dass es auch mit GUIs per Doppelklick auf das Jar-Archiv geht 

@Edit: Auf Anhieb hab' ich nun auch eine Idee, wie man seine DLLs mit ins Jar-Archiv packen kann. Mit getResource() die URL besorgen, als Datei laden, in ein temporäres Verzeichnis kopieren und dieses wie oben dem "java.library.path" hinzufügen. 

@Edit2: Also ich bin nun ehrlich gesagt ein wenig verwirrt. Nach einem Update der JVM zeigt die Ausgabe in beiden Fällen (vor und nach diesem äh nennen wir es Patch) an, dass die Bibliothek gefunden wurde. Heisst das, dass das aktuelle Verzeichnis erst vor kurzem dem Standard-Suchpfad der JVM hinzugefügt wurde? Naja... zumindest lassen sich auf die Art auch noch weitere Verzeichnisse, diesem Suchpfad anhängen, z.B. die Trennung von 32- und 64 Bit.


----------



## tdc (4. Jun 2011)

Danke für die vielen Antworten!

Ich habs jetzt erstmal mit nem Shell-Script gelöst.


```
export LD_LIBRARY_PATH=PFAD/native/linux/
cd PFAD
java -jar JARNAME.jar
```


----------



## Empire Phoenix (5. Jun 2011)

Sauber ist wennde die natives inne jar packst und automatisch beim start der runtime die benötigten entpackst.


----------

