# Maven und Native-Libs



## Siassei (3. Nov 2010)

Hallo,

wahrscheinlich zum x-ten mal, aber trotz allem finde ich keine vernünftige Lösung.

Ich habe einen Ordner mit nativen Bibliotheken. Ich erstelle in der Super-POM Profile für die verschiedene OS (Win, Linux, Mac, ...). So, nun möchte ich noch folgendes erledigen
1) Beim build-Vorgang sollen die Bibliotheken in den Ordner buildDir/lib kopiert werden. 
2) Beim Ausführen oder Testen (z.B. aus einer IDE) soll Maven die Classpath-Variablen entsprechend erweitern.

zu 1)
Bei einer einzigen Datei kein Problem. z.B. für jocl von jogamp

```
<profiles>
        <profile>
            <id>Linux_64</id>
            <activation>
                <os>
                    <arch>amd64</arch>
                    <name>Linux</name>
                </os>
            </activation>
            
            <dependencyManagement>
                <dependency>
                    <groupId>org.jogamp</groupId>
                    <artifactId>jocl-natives-linux-amd64</artifactId>
                    <version>2.0-pre</version>
                    <scope>system</scope>

                    <systemPath>${basedir}/lib/localRepository/com/jogamp/opencl/jocl/2.0-pre/jocl-natives-linux-amd64.jar</systemPath>
                </dependency>
            </dependencyManagement>
        </profile>
    </profiles>
```

Aber was ist, wenn es sich um mehrere Dateien handelt. z.B. bei jocl sind es 8x *.so Dateien. Muss ich hier acht Einträge erstellen?
Edit: Und wie mache ich das mit dem Kopieren?

zu 2)
Da ist mir noch gar nichts eingefallen 

Ich würde mich um ein wenig Unterstützung sehr freuen. Wie ihr an der Uhrzeit sehen könnt handelt es sich um ein privates Vorhaben.

Gruß,
  Thomas


----------



## Siassei (4. Nov 2010)

Keiner eine Idee?


----------



## kama (4. Nov 2010)

Hallo,

das Profile definiert ja dependencyManagement...das bedeutet, dass die POM die das verwenden sollen auch einen entsprechenden Eintrag wie den folgenden haben müssen:

```
<dependency>
  <groupId>org.jogamp</groupId>
  <artifactId>jocl-natives-linux-amd64</artifactId>
</dependency>
```

Danach sollte der Classpath auch entsprechend gesetzt sein.....wichtig ist, dass das Profile auch aktiviert ist...

Mir ist nicht so ganz klar was Du mit dem "kopieren" erreichen möchtest ? Grundsätzlich Kopieren von dependencies kann man mit dem dependency-plugin....aber ich denke dass das hier nicht das Problem ist...

Weiterhin musst Du für jede Abhängigkeit einen eigenen Eintrag machen....Die Frage ist für die .so Dateien weiß ich nicht wirklich ob das so funktioniert (Schau mal in das Projekt was Du benutzt rein, ob die eventuell schon eine POM haben)...

Eventuell wäre auch ein Blick in das Maven-Nar-Plugin hilfreich, da es ja hier um Shared-Libraries geht ...

Gruß
Karl Heinz Marbaise


----------



## Siassei (4. Nov 2010)

kama hat gesagt.:


> Mir ist nicht so ganz klar was Du mit dem "kopieren" erreichen möchtest ? Grundsätzlich Kopieren von dependencies kann man mit dem dependency-plugin....aber ich denke dass das hier nicht das Problem ist...


Ich möchte gerne eine POM erstellen, die mir alles was z.B. für eine Client-Ausführung nötig ist, zusammenhollt und es entsprechend verpackt.
Danach würde ich gerne folgende Struktur haben
Build-Dir := Readme.txt, Lizenz, ....
Build-Dir/lib := alle .jar's
Build-Dir/native := alle nativen Bibliotheken
Build-Dir/resource := Icons, Bilder, ....
Build-Dir/bin := Shell-Skripte & Co.


----------



## kama (4. Nov 2010)

Hallo,



Siassei hat gesagt.:


> Ich möchte gerne eine POM erstellen, die mir alles was z.B. für eine Client-Ausführung nötig ist, zusammenhollt und es entsprechend verpackt.
> Danach würde ich gerne folgende Struktur haben
> Build-Dir := Readme.txt, Lizenz, ....
> Build-Dir/lib := alle .jar's
> ...


Ah...jetzt wirds klar...Dafür ist das Assembly Plugin genau richtig...damit kann man das machen...

Ich vermute, dass das in Form einer zip (.tar.gz) Datei geschehen soll ? Genau dafür ist das Assembly plugin gedacht...

Gruß
Karl Heinz Marbaise


----------



## Siassei (5. Nov 2010)

Hmm, ich weiss nicht ob das Assembly-Plugin das wahre ist.

O.k. Nehmen wir als Beispiel mal folgende Situation:
- Es gibt ein "jar" nur Java-Code enthält
- Mehrere .so Dateien z.b 4x pro Betriebssystem liefern den Maschinencode

Jetzt kann man ja über Profile das ganze OS-abhängig steuern. Wie binde ich nun am elegantesten die .so-Dateien in mehreren Sub-Modulen ein?

Würde eine zusätzliche .jar das Problem lösen? Also z.B. eine native-Linux.jar, die eben alle .so-Dateien enthält. Findet der Classloader in einer jar die nötigen native Bibliotheken? z.B. für das Kommand System.loadLibrary("")


----------



## Siassei (6. Nov 2010)

Ich habe nun alle Library's in eine .jar gepackt und diese als Abhängigkeit in maven hinzugefügt. So weit so gut. Nun möchte ich einen kleinen Test aus Netbeans heraus starten. Die .jar wird im Bibliotheken-Reiter des Maven-Projekts angezeigt. Beim starten der Anwendung meckert java mit "java.lang.UnsatisfiedLinkError" :-(

Der Befehl der Zeile lautet System.load("libAbc") oder System.loadLibrary("libAbc"). Beides führt zum gleichen Ergebnis. 
System.getProperty("java.library.path") liefert folgendes
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/../lib/amd64
/usr/lib64/mpich2/lib
/usr/local/cuda/lib64
/usr/local/cuda
/usr/java/packages/lib/amd64
/usr/lib64
/lib64
/lib
/usr/lib


Wie bekomme ich nun java dazu, die nativen Bibliotheken aus der Jar zu laden?


----------



## Siassei (6. Nov 2010)

Irgendwie funktionieren Projekte mit nativen Abhängigkeiten bei mir nicht. Schade. Mit einem "normalen" Projekt in Netbeans funktioniert alles einwandfrei.

Wenn sich dennoch jemand findet, der mir folgendes beantworten kann, wäre ich sehr sehr glücklich.

"Was muss ich einstellen bzw. was benötige ich, damit Maven-Projekte mit einer Nativen-Abhängigkeit z.B. .so einwandfrei funktionieren?"
Egal, ob ich die .so Datei in einen der Ordner von "java.library.path" lege, oder in das Hauptverzeichnis der JRE er findet sie nicht.

Edit: Lässt sich der LD_Library_Path mit Maven anpassen?

Gruß,
  Thomas


----------



## Siassei (8. Nov 2010)

Keiner eine Idee?


----------



## Guest2 (8. Nov 2010)

Moin,

Maven ist im Schwerpunkt ein Werkzeug um den Buildprozess eines Projektes zu verwallten. Das Laden der nativen Bibliotheken ist aber etwas das zur Laufzeit des Programms passiert. Der Zeitpunkt an den Maven wirkt, ist also ein anderer, als der an dem das Problem mit den Bibliotheken auftritt.

Zwar kannst Du Maven "missbrauchen" um den java.library.path anzupassen. Ich habe (vor langer Zeit) mal ein Maven plugin geschrieben, das in der Lage war den java.library.path in den Einstellungen eines des Eclipse Projektes einzufügen, ähnliches sollte wohl auch mit Netbeans möglich sein, Sinn macht das aber eigentlich nicht. Spätestens nach dem Release tritt das Problem dann beim eigentlichen Nutzer des Projektes auf. Und der hat weder Maven noch Netbeans.

Ich löse das seit dem meistens im Programm selber, indem das Programm sich selbst um die Handhabung der nativen Bibliotheken kümmert. Etwa so.



Siassei hat gesagt.:


> Egal, ob ich die .so Datei in einen der Ordner von "java.library.path" lege, oder in das Hauptverzeichnis der JRE er findet sie nicht.



Wenn sie im java.library.path liegt, muss sie gefunden werden. Bist Du sicher, dass es die für Dein Betriebssystem passende ist? Das es keine evtl. abhängigen Bibliotheken gibt, die ggf. vorher geladen werden müssen? Bist Du sicher das der Zeitpunkt der Richtige ist (main kann schon zu spät sein...)? Wie lädst Du die natives?

Gruß,
Fancy


----------



## Siassei (8. Nov 2010)

Guest2 hat gesagt.:


> Wenn sie im java.library.path liegt, muss sie gefunden werden. Bist Du sicher, dass es die für Dein Betriebssystem passende ist? Das es keine evtl. abhängigen Bibliotheken gibt, die ggf. vorher geladen werden müssen? Bist Du sicher das der Zeitpunkt der Richtige ist (main kann schon zu spät sein...)? Wie lädst Du die natives?


Die native Bibliotheken liegen zur Zeit in einem Ordner und liegem im "java.library.path" Ordner. Das funktioniert auch so weit. Leider muss man das erst manuell anpassen. Das möchte ich eigentlich verhindern.

Netbeans bietet ja eine sehr gute Maven-Integration. Eclipse auch. Nun möchte ich gerne folgendes erreichen.
Auf einem Computer XYZ
 - laden das Projekt vom GIT-Server
 - bevorzugte IDE mit Maven-Unterstützung starten
 - Compilieren und Testen aus der IDE
 - keine manuelle Anpassung von ....



> Spätestens nach dem Release tritt das Problem dann beim eigentlichen Nutzer des Projektes auf


Dafür gibt es doch das Assembly-Plugin und ein Shell-Skript zum starten der Anwendung.



> Maven ist im Schwerpunkt ein Werkzeug um den Buildprozess eines Projektes zu verwallten. Das Laden der nativen Bibliotheken ist aber etwas das zur Laufzeit des Programms passiert.


Gehört hier nicht auch Test (z.B. JUnit), Optimierung und das Ausführen zu testzwecken?


Wie kama bereist angedeutet hat, liegt die Lösung im nar-Plugin. Es lassen sich native-Abhängigkeiten definieren, die in einer Jar-File mit der Endung .nar liegen. Diese werden beim install-Vorgang auch entpackt falls erwünscht.
maven-nar-plugin - Maven NAR Plugin

Problem gelöst  Danke.


----------



## Guest2 (9. Nov 2010)

Siassei hat gesagt.:


> Netbeans bietet ja eine sehr gute Maven-Integration. Eclipse auch. Nun möchte ich gerne folgendes erreichen.
> Auf einem Computer XYZ
> - laden das Projekt vom GIT-Server
> - bevorzugte IDE mit Maven-Unterstützung starten
> ...



Wobei Maven den Ton angeben sollte. Maven ist das Buildwerkzeug und ein "mvn install" sollte auf der Kommandozeile fehlerfrei durchlaufen, sonnst gibt es später Probleme. Z.B. der continuous integration Server sollte schließlich auch in der Lage sein das Projekt zu bauen, testen, packen und ggf. den release anzustoßen. Und dieser läuft schließlich auch ohne IDE. Die IDE sollte sich also nach Maven richten.

Und genau da ist das Problem, Maven hat den Buildzyklus im Schwerpunkt. Das Starten der Anwendung ist aber erst nach dem Build.




Siassei hat gesagt.:


> Dafür gibt es doch das Assembly-Plugin und ein Shell-Skript zum starten der Anwendung.



Ja natürlich, das kann man so machen. Imho ist das auch Geschmackssache, einige liefern lieber ein .tar.gz aus, das alle Dateien und ein Shell-Skript für jede unterstützte Plattform enthält, andere lieber ein direkt startfähiges jar File. Beides hat Vor- und Nachteile. Hängt letztendlich auch davon, ab was der zukünftige Nutzer erwartet.




Siassei hat gesagt.:


> Gehört hier nicht auch Test (z.B. JUnit), Optimierung und das Ausführen zu testzwecken?



Unit Tests gehört auf jeden Fall mit in den Buildzyklus. Da ist der java.library.path aber auch kein Problem, da dieser über das surefire plugin gesetzt werden kann:


```
<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <systemProperties>
            <property>
              <name>java.library.path</name>
              <value>target/lib/</value>
            </property>
          </systemProperties>
        </configuration>
      </plugin>
```


Das Ausführen zu Testzwecken gehört imho aber nicht mehr zum Buildprozess. Das Setzen der dazu notwendigen Parameter / Umgebung würde ehr in den Bereich "Materialisierung eines existierenden Projektes in die IDE" fallen. Eclipse Buckminster wäre da wohl ein Stichwort. 




Siassei hat gesagt.:


> Wie kama bereist angedeutet hat, liegt die Lösung im nar-Plugin. Es lassen sich native-Abhängigkeiten definieren, die in einer Jar-File mit der Endung .nar liegen. Diese werden beim install-Vorgang auch entpackt falls erwünscht.
> maven-nar-plugin - Maven NAR Plugin



Das Einbinden der dependency aus dem repo und ggf. entpacken in ein gewünschtes Verzeichnis ist dabei ja auch das kleinere Problem. Das geht z.B. mit dem dependency plugin und passend gesetzten classifier auch. Problematischer ist, dass es immer und überall gestartet werden kann. 

Gruß,
Fancy


----------



## Siassei (12. Nov 2010)

@guest3

Intressant. Was würdest du dann für

Build-Prozess, Test, Ausführung, Ausliefung

empfehlen, dass

IDE- und Plattform-Unabhängig ist?


----------



## Guest2 (16. Nov 2010)

Maven 

Worauf ich hinaus will, ist das der Entwicklungsprozess von Software wesentlich mehr Aufgaben umfast, als nur der reine Buildzyklus. Und aus jeder dieser Aufgaben ergeben sich unterschiedliche Anforderungen, aus denen sich dann wiederum unterschiedliche Werkzeuge ergeben.

Ich halte Maven für das beste Tool, um den Buildprozess zu organisieren. Auflösen der Abhängigkeiten, kompilieren, Unittests, packen, Integrationstests und ggf. der Release lassen sich mit Maven imho in einer sehr schlanken und übersichtlichen Weise organisieren. Das Schöne dabei ist, Maven ist dabei unabhängig von der IDE. Die IDE ist nur noch ein Werkzeug für den Entwickler, nicht mehr für den Build. 

Das bedeutet aber auch, das Maven nichts kann (und imho auch nicht können sollte), was sich nicht aus dem Buildprozess ergibt. Weitere Einstellungen an der IDE vorzunehmen würden imho so nicht in das Konzept von Maven passen. 

Das Setzen des java.library.path wäre dabei auch noch das kleinste Problem. Wenn z.B. in einem Projekt einige "höhere" Frameworks Verwendung finden, so lassen sich diese Projekte auch nur noch effektiv bearbeiten, wenn die IDE entsprechende Tool Unterstützung bietet. Hier würde z.B. ein Auschecken aus dem git alleine auch nicht mehr reichen, um das Projekt innerhalb der IDE bearbeiten zu können. Der Entwickler müsste dann auch erst, die zum Framework passenden Plugins installieren und entsprechend einrichten. Daraus ergibt sich dann aber auch, dass dieser Schritt nicht IDE unabhängig sein kann.

Es gab (gibt?) auch einige Entwickler, die aus diesem Grund ihre komplette Entwicklungsumgebung mit in die Quellcodeverwaltung eingepflegt haben.

Ein modernerer Ansatz wäre eben z.B. Eclipse Buckminster. Buckminister geht im Bereich Materialisierung viel weiter als Maven. Erzeugt aber auch eine starke Koppelung zwischen Eclipse und dem Buildprozess (da ist mir das Konzept von Maven wesentlich sympathischer). Ein entsprechender Ansatz für Netbeans ist mir nicht bekannt.

Es gibt dazu auch gerade einen interessanten Nachbarthread. Aber wie bereits angedeutet, Einstellungen in der IDE Vornehmen (wie z.B. den java.library.path) und unabhängig von der IDE bleiben, beißt sich.





Siassei hat gesagt.:


> Intressant. Was würdest du dann für
> 
> Build-Prozess, Test, Ausführung, Ausliefung
> 
> ...



Ich selbst nutze auch Maven. Wobei ich bei Projekten, die besondere Einstellungen innerhalb der IDE benötigen, auch die entsprechenden (Eclipse-) Konfigurationsdateien mit in die Quellcodeverwaltung einpflege. (Z.B. der java.library.path ist ein Parameter der .classpath)

Bei Projekten, die native Bibliotheken benötigen, baue ich diese so, dass die jars die natives "aus sich heraus" handhaben können (wie im obigen Link angedeutet). Das hat den Vorteil das die Anwendung immer, also z.B. in der IDE, per Doppelklick, per Shell-Skript, per Webstart und per Applet läuft, ohne das der Nutzer (oder der Entwickler) sich Gedanken darum machen muss, das intern irgendwo native Bibliotheken genutzt werden. Auch stellt dann das von Maven erzeugte jar ein ganz normales Artifact dar, welches in anderen Projekten als ganz normale Dependency genutzt werden kann, ohne das der native Part eine Rolle spielt.

Gruß,
Fancy


----------



## Marco13 (23. Dez 2010)

Vielleicht hätte ich mit diesen Thread für die Beantwortung von SCM and Maven - Seite 4 - Byte-Welt Forum schon früher mal ansehen sollen ....


----------

