La bibliothèque native peut être chargée par loadLibrary avec un nom valide. Par exemple, libXXXX .so pour la famille linux, votre hellolib.so devrait se renommer en libhello.so. Au fait, je développe java avec jni, je vais séparer l'implémentation et l'interface native (.c ou .cpp).
static {
System.loadLibrary("hello"); // will load libhello.so
}
L'en-tête d'implémentation (HelloImpl.h):
#ifndef _HELLO_IMPL_H
#define _HELLO_IMPL_H
#ifdef __cplusplus
extern "C" {
#endif
void sayHello ();
#ifdef __cplusplus
}
#endif
#endif
BonjourImpl.cpp :
#include "HelloImpl.h"
#include <iostream>
using namespace std;
void sayHello () {
cout << "Hello World!" << endl;
return;
}
Hello.c (je préfère compiler jni en c) :
#include <jni.h>
#include "Hello.h"
#include "HelloImpl.h"
JNIEXPORT void JNICALL Java_Hello_sayHello (JNIEnv *env, jobject obj) {
sayHello();
return;
}
Enfin, nous pouvons les compiler en quelques étapes :
- compiler obj (générer HelloImpl.o)
g++ -c -I"/opt/java/include"-I"/opt/java/include/linux" HelloImpl.cpp
- compiler jni avec .o
g++ -I"/opt/java/include"-I"/opt/java/include/linux" -o libhello.so -shared-Wl,-soname,hello.so Hello.c HelloImpl.o -static -lc
à l'étape 2, nous utilisons g++ pour le compiler. C'est très important. vous pouvez voir comment mélanger C et C++
Après compilation, vous pouvez vérifier le nommage de la fonction avec nm :
$ nm libhello.so |grep say
00000708 T Java_Hello_sayHello
00000784 t _GLOBAL__I_sayHello
00000718 T sayHello
Il existe un Java_Hello_sayHello marqué T. Il doit être exactement égal au nom de votre méthode native. Si tout va bien. vous pouvez l'exécuter :
$ java -Djava.library.path=. Hello
Hello World!
Enfin mon code fonctionne. C'est hello.java
public class hello {
public native void sayHello(int length) ;
public static void main (String args[]) {
String str = "I am a good boy" ;
hello h = new hello () ;
h.sayHello (str.length() ) ;
}
static {
System.loadLibrary ( "hello" ) ;
}
}
Vous devriez le compiler comme :
$ javac hello.java
Pour créer un fichier .h, vous devez exécuter cette commande :
$ javah -jni hello
C'est hello.h
:
JNIEXPORT void JNICALL Java_hello_sayHello
(JNIEnv *, jobject, jint);
Voici hello.c
:
#include<stdio.h>
#include<jni.h>
#include "hello.h"
JNIEXPORT void JNICALL Java_hello_sayHello
(JNIEnv *env, jobject object, jint len) {
printf ( "\nLength is %d", len ); }
Pour compiler cela et créer une bibliothèque partagée, nous devons exécuter cette commande :
$ gcc -I/usr/lib/jvm/java-6-openjdk/include -o libhello.so -shared hello.c
Puis lancez enfin celui-ci :
$ java -Djava.library.path=. hello
Cela se plaint que les symboles C++ ne sont pas disponibles. Il me semble me souvenir, quand j'avais l'habitude de faire des trucs JNI tout le temps qu'il y avait des problèmes de liaison dans les bibliothèques C++ et que nous nous en tenions toujours au bon vieux C
Si vous modifiez votre code pour qu'il soit en C standard (et renommez le fichier) :
#include <jni.h>
#include "Hello.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_Hello_sayHello (JNIEnv *env, jobject obj) {
printf("Hello World");
return;
}
Et compilez-le
gcc -I/usr/lib/jvm/java-6-openjdk/include -o libhellolib.so -shared Hello.c
Ça marche
java -Djava.library.path=`pwd` Hello
Hello World