JNI UnsatisfiedLinkError ... undefined symbol: __cxa_pure_virtual

tdc

Bekanntes Mitglied
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
Code:
#include <jni.h>
#include <iostream>
#include <btBulletDynamicsCommon.h>
 
JNIEXPORT void JNICALL Java_jni_callnative(JNIEnv *env,
                                                  jobject obj)
{

        return ;
}

Compile-Script:
Code:
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:
Code:
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)
 
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?
 
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... 😳
 
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:
Code:
Exception in thread "main" java.lang.UnsatisfiedLinkError: jni.callnative()V
	at jni.callnative(Native Method)
	at jni.main(jni.java:5)
Programm:
Code:
#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:
Code:
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:
Java:
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?
 
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...😳
 
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...)

Code:
g++ -Wl,--kill-at -fPIC -shared -I/usr/local/java/include -I/usr/local/java/include/genunix hello.cpp -o libhello.so
statt
Code:
g++ -fPIC -shared -I/usr/local/java/include -I/usr/local/java/include/genunix hello.cpp -o libhello.so
ergibt
Code:
/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... 😳
 
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 🙂
 
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?
 
Oooookay, es scheint ein:
Code:
extern "C"
gefehlt zu haben.
So funktioniert es jetzt:
Code:
#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;
}
 

Zurück
Oben