# JNI UnsatisfiedLinkError ... undefined symbol: __cxa_pure_virtual



## tdc (19. Sep 2012)

Hi,
ich habe (leider) wieder ein Problem bezüglich JNI. Ich möchte ein größeres C++-Programm (Bullet Physics Engine, ja, es gibt JBullet, ich bräuchte aber die aktuellste, vollständige Version) über JNI ausführen. Deshalb habe ich es als *.so kompiliert und eine weitere C-Klasse geschrieben, die die Engine verwendet (in diesem Fall ein Hello-World-Programm ausführt). Diese zweite *.so-Datei möchte ich nun über JNI aufrufen.
Zurzeit erhalte ich allerdings eine Fehlermeldung. (siehe unten)

Zuvor hatte ich das Problem, dass ich für gcc erst noch den Ort für die Header, zusätzlich zu den *.so-Dateien angeben musste (-I/home/pfad/bullet-2.80-rev2531/src). Muss ich für JNI ebenfalls zusätzliche Parameter für die Header angeben?
Eigentlich dürfte sich, im Gegensatz zu meinen vorigen Versuchen mit JNI, ja nicht viel verändert haben. Im Quellcode verweise ich jetzt nur zusätzlich auf einen Header, die Compilierung der C++-Klasse funktioniert durch die zusätzliche Pfadangabe aber reibungslos.
Warum erhalte ich dann später beim Ausführen durch Java eine Fehlermeldung?
Diesmal sollten auch die Bezeichnungen der *.so-Dateien stimmen.

C++-Klasse

```
#include <jni.h>
#include <iostream>
#include <btBulletDynamicsCommon.h>
 
JNIEXPORT void JNICALL Java_jni_callnative(JNIEnv *env,
                                                  jobject obj)
{

        return ;
}
```

Compile-Script:

```
javac jni.java
javah -jni jni
gcc -fPIC -shared -I/home/pfad/bullet-2.80-rev2531/src -I/usr/local/java/include -I/usr/local/java/include/genunix hello.cpp -o libhello.so -LBulletCollision -LBulletDynamics -LBulletMultiThreaded -LBulletSoftBody -LLinearMath -LMiniCL
export LD_LIBRARY_PATH="/home/pfad/JNIBulletHello"
java jni
```

Fehlermeldung:

```
Exception in thread "main" java.lang.UnsatisfiedLinkError: /home/pfad/JNIBulletHello/libhello.so: /home/pfad/JNIBulletHello/libhello.so: undefined symbol: __cxa_pure_virtual
	at java.lang.ClassLoader$NativeLibrary.load(Native Method)
	at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1939)
	at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1864)
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1854)
	at java.lang.Runtime.loadLibrary0(Runtime.java:845)
	at java.lang.System.loadLibrary(System.java:1084)
	at jni.<clinit>(jni.java:9)
```


----------



## tdc (20. Sep 2012)

Okay. Wenn ich ein (Hello-World-)Beispielprogramm als C-Programm kompiliere, funktioniert es. Als C++-Programm funktioniert es nicht und ich bekomme unterschiedliche UnsatisfiedLinkErrors. Warum?


----------



## jamesv (20. Sep 2012)

Vielleicht hilft dir das hier:
JNI (Java talks with C++) Einführung (haertfelder.com)

Mit Glück hast du dasselbe Problem wie er hier:
java - Another JNI, C++, DLL, UnsatisfiedLinkError <Native Method> - Stack Overflow

Hoffe, dass hat dir geholfen?

LG


----------



## Marco13 (20. Sep 2012)

Der UnsatisfieldLinkError ist eben so omnipräsent (er fliegt ja _immer_ wenn _irgendwas_ schiefgeht) dass man wohl spezifischer werden muss. Eine websuche nach
unsatisfiedlinkerror undefined symbol: __cxa_pure_virtual
liefert (diese Thread hier als erstes Ergebnis, aber auch noch) ein paar Ergebnisse von anderen Seiten, aber ich habe nocht nicht näher geschaut...


----------



## LordJaxom (21. Sep 2012)

Tipp: Zum Übersetzen und Binden von C++-Quelltexten nutzt man g++, nicht gcc.


----------



## tdc (21. Sep 2012)

Okay, ich habe scheinbar mehrere Fehler gemacht. Ich versuche zurzeit nur ein einfaches C++-Hello-World-Programm mit JNI auszuführen (mit C funktioniert es ja bereits).
Mit g++ bekomme ich jetzt nur wieder:

```
Exception in thread "main" java.lang.UnsatisfiedLinkError: jni.callnative()V
	at jni.callnative(Native Method)
	at jni.main(jni.java:5)
```
Programm:

```
#include <jni.h>
#include <stdio.h>
#include <iostream>
using namespace std;

JNIEXPORT void JNICALL Java_jni_callnative(JNIEnv *env,
                                                  jobject obj)
{
   cout << "Hello World!";
   return;
}
```
Compile-Script:

```
javac jni.java
javah -jni jni
g++ -fPIC -shared -I/usr/local/java/include -I/usr/local/java/include/genunix hello.cpp -o libhello.so
export LD_LIBRARY_PATH="/home/oliver/Arbeitsfläche/javaTest/JNITestpp"
java jni
```
Und die Java-Klasse:

```
class jni {
  private native void callnative();

  public static void main(String[] args) {
    new jni().callnative();
  }

  static {
    System.loadLibrary("hello");
  }
}
```

Sobald ich mit JNI das C++-Programm anstatt das C Hello World Programm verwenden möchte, bekomme ich den Error. Ändern tue ich dabei nur den C-Quellcode (C++ statt C) und ich verwende g++ anstatt gcc.
Muss ich noch mehr verändern? Sind die Parameter ok?


----------



## Marco13 (21. Sep 2012)

Ich würde ja wieder auf das kill-at verweisen (wie im letzten Thread) aber vermutlich habe ich mit dem GCC einfach zu wenig praktische Erfahrung, um sinnvolleres beitragen zu können...


----------



## tdc (21. Sep 2012)

Marco13 hat gesagt.:


> Ich würde ja wieder auf das kill-at verweisen (wie im letzten Thread) aber vermutlich habe ich mit dem GCC einfach zu wenig praktische Erfahrung, um sinnvolleres beitragen zu können...



Und wie schon im letzten Thread kann ich nur wieder sagen, dass mein gcc/g++ das nicht zu kenn en scheint.  (bzw. dass ich es bei mir nicht funktioniert...)


```
g++ -Wl,--kill-at -fPIC -shared -I/usr/local/java/include -I/usr/local/java/include/genunix hello.cpp -o libhello.so
```
statt

```
g++ -fPIC -shared -I/usr/local/java/include -I/usr/local/java/include/genunix hello.cpp -o libhello.so
```
ergibt

```
/usr/bin/ld: unrecognized option '--kill-at'
/usr/bin/ld: use the --help option for usage information
collect2: ld gab 1 als Ende-Status zurück
```
kann natürlich auch sein, dass ich irgendetwas total falsch mache...


----------



## jamesv (21. Sep 2012)

Hallo,
hier ist zu finden, dass du erst ein .o File erstellen musst und dann die --kill-at anweisung verwenden.

jni - MinGW's compiler option Wl,--kill-at does not work - Stack Overflow


Ich hoffe, dass dir das hilft.

Kommando: 

g++ -I"C:\Program Files\Java\jdk1.6.0_13\include" -I"C:\Program Files\Java\jdk1.6.0_13\include\win32" -O0 -Wall -c -oMain.o ..\Main.cpp


zweites Kommando, dass auf das O-File geht:

g++ -Wl,--kill-at -shared -olibJniCTest.dll Main.o


Müsstest halt noch die Pfade austauschen


----------



## tdc (22. Sep 2012)

Nein, auch das hilft nicht, mein Compiler kennt es einfach nicht.

Nach einigem Suchen scheint es wohl einfach unter Linux nicht nötig zu sein:


> Linker Flag hinzufügen : Trage unter "Project -> properties -> C/C++ Build -> Settings -> MinGW C Linker -> Miscellaneous -> Linker flags" den Wert ein:
> "-Wl,--kill-at"
> (Das ist nötig, weil sonst die DLL beim Kompillieren mit @-Zeichen angereichert wird, die Java nicht versteht. Unter Linux braucht es dieses Flag nicht)


Quelle: JNI Tutorial
(Außerdem kennt der Compiler unter Linux es scheinbar einfach nicht)

Was könnte ich denn sonst noch falsch gemacht haben?


----------



## tdc (30. Sep 2012)

Oooookay, es scheint ein:

```
extern "C"
```
gefehlt zu haben.
So funktioniert es jetzt:

```
#include <jni.h>
#include <stdio.h>
#include <iostream>
using namespace std;

extern "C"
JNIEXPORT void JNICALL Java_jni_callnative(JNIEnv *env,
                                                  jobject obj)
{
   cout << "Hello World!" << endl;
   return;
}
```


----------

