Je voulais vraiment utiliser les chevilles de Nim (PEG) de Java, j'ai donc étudié comment appeler les fonctions Nim via JNI.
Des faits étonnants se sont avérés ...
Avec jnim, il semble que vous puissiez créer une bibliothèque partagée avec uniquement des fichiers Nim. Après demain, j'organiserai un peu plus la procédure.
jnim_call.nim
import jnim
import dynlib
#Renvoie l'argument tel quel
proc Java_HelloJNI_hello*(env: JNIEnvPtr, me:jobject, arg:jstring ): jstring {.cdecl,exportc,dynlib.} =
return arg
Compiler et exécuter
$ nim c --app:lib --noMain -o:libHelloJNI.so jnim_call.nim
$ java -Djava.library.path=. HelloJNI "Peux-tu m'appeler"
Peux-tu m'appeler
~~ Donc, ce qui suit est un article poubelle. ~~
Dans la source Nim ci-dessus, lorsque j'ai converti l'argument de la méthode JNI en jstring-> cstring-> string, pour une raison quelconque, la JVM a craché un vidage de mémoire et s'est terminée anormalement.
Dans la version initiale, cela ne fonctionnait que si j'appelais d'abord NimMain et que je l'initialisais, il semble donc que ce soit la cause.
J'ai pensé que je devrais appeler NimMain moi-même, et quand j'ai écrit ce qui suit en utilisant le pragma emit, j'ai pu l'appeler avec succès sans cracher un vidage de mémoire! !!
jnim_call.nim
import jnim
import dynlib
#Renvoie l'argument tel quel
proc Java_HelloJNI_hello*(env: JNIEnvPtr, me:jobject, arg:jstring ): jstring {.cdecl,exportc,dynlib.} =
#Initialiser Nim
{.emit: """
NimMain();
""".}
#Argument String->conversion cstring
var argNim:cstring = env.GetStringUTFChars(env,arg,nil)
#Ouvert à la fin
defer:
env.ReleaseStringUTFChars(env,arg,argNim)
# cstring ->conversion de chaîne
var ss = "Hello " & $argNim
#Générer une chaîne et quitter
return env.NewStringUTF(env,ss)
Vous pouvez maintenant appeler peg depuis Java.
※※※※ Ajout encore plus ※※※※
Quand j'ai appelé la méthode JNI environ 10000 fois en boucle pour voir si je devais appeler NimMain à chaque fois, Il s'est terminé anormalement avec l'erreur "impossible d'enregistrer la variable globale; trop de variables globales". Il semble que je n'ai besoin d'appeler NimMain qu'une seule fois la première fois, j'ai donc décidé d'utiliser les variables globales définies dans jnim. Avec ce support, même si vous appelez la méthode JNI par Nim 100 000 fois, aucune erreur ne se produira! !! !!
jnim_call.nim
import jnim
import dynlib
#Renvoie l'argument tel quel
proc Java_HelloJNI_hello*(env: JNIEnvPtr, me:jobject, arg:jstring ): jstring {.cdecl,exportc,dynlib.} =
#Initialiser Nim
if theEnv == nil :
{.emit: """
NimMain();
""".}
theEnv = env
#Argument String->conversion cstring
var argNim:cstring = env.GetStringUTFChars(env,arg,nil)
#Ouvert à la fin
defer:
env.ReleaseStringUTFChars(env,arg,argNim)
# cstring ->conversion de chaîne
var ss = "Hello " & $argNim
#Générer une chaîne et quitter
return env.NewStringUTF(env,ss)
Dans le [Forum] de Nim (http://forum.nim-lang.org/t/2696/1), il y avait un message indiquant qu'une erreur de segmentation s'est produite lors d'un appel natif avec jnim. Le même phénomène s'est produit avec la méthode native que j'ai créée dans mon article. En guise de solution, j'ai pu contourner le problème en passant -d: noSignalHandler comme option du compilateur.
Décrit les options de compilation pour créer un fichier SO natif (DLL) avec jnim.
nim c --out:libHelloJNI.so \
--app:lib \
--nomain \
--threads:on \
-d:release \
-d:noSignalHandler \
hello.nim
Java->Nim J'ai lu [cet article] de @ shsnow23 (http://qiita.com/shsnow23/items/1696687cca61bfedb1cc) et j'ai senti que je pouvais appeler Java-> Nim, donc j'ai fait un échantillon.
Compte tenu de la libération de mémoire après le retour d'une chaîne de caractères de Nim, j'ai pensé qu'il serait plus sûr d'utiliser la création d'objets Java dans la méthode JNI, je l'ai donc implémentée dans JNI.
HelloJNI.java
//Classe de test JNI
public class HelloJNI {
//Charger la bibliothèque
static {
System.loadLibrary("HelloJNI");
}
//Méthode JNI
private native String hello(String str);
//Fonction principale pour les tests
public static void main(String[] args){
HelloJNI h = new HelloJNI();
System.out.println(h.hello(args[0]));
}
}
proc hello_nim(s:cstring) : cstring {.exportc.} =
#Retour par concaténation de chaînes de caractères
var ss:string = ""
ss = "hello " & $s
return ss
L'en-tête est automatiquement généré par javah, il n'est donc pas nécessaire de le modifier.
HelloJNI.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */
#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloJNI
* Method: hello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_HelloJNI_hello
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
Source C (JNI). Convertit les arguments passés en type natif avant d'appeler la fonction nim. Si vous n'appelez pas la fonction appelée NimMain, l'initialisation côté Nim ne sera pas effectuée, ce qui entraînera une erreur d'exécution. Pour savoir comment mettre en œuvre JNI, je me suis référé à ici.
HelloJNI.c
#include "HelloJNI.h"
//Définition de la fonction côté Nim
#include "nimcache/hello.h"
JNIEXPORT jstring JNICALL Java_HelloJNI_hello
(JNIEnv * env, jobject pThis, jstring arg)
{
//Appel requis
NimMain();
//Argument char*Conversion en
NCSTRING argNim = (*env)->GetStringUTFChars(env,arg,NULL);
//Appeler les fonctions Nim
NCSTRING ret = hello_nim(argNim);
//Libérez la mémoire réservée
(*env)->ReleaseStringUTFChars(env,arg,argNim);
//Construisez une chaîne de caractères à partir de la valeur de retour de Nim et renvoyez-la
return (*env)->NewStringUTF(env,ret);
}
Je ne peux pas faire un makefile parce que je suis si faible ... NIM_HOME est le répertoire dans lequel Nim est installé.
build.sh
sharedlib=libHelloJNI.so
#Supprimer le produit précédent pour le moment
rm -rf nimcache
rm ${sharedlib}
#Compilation Nim et sortie source C La source est sortie vers nimcache
nim c --noMain --noLinking --header:hello.h Hello.nim
#Nimcache avec source JNI C/*.c compile également
gcc -shared -fPIC \
-I ${JAVA_HOME}/include \
-I ${JAVA_HOME}/include/linux \
-I ${NIM_HOME}/lib \
-o ${sharedlib} \
HelloJNI.c nimcache/*.c
#Java est également compilé
javac HelloJNI.java
#Essai
java -Djava.library.path=. HelloJNI
Ce sera dans un tel état.
.
├── compile.sh
├── HelloJNI.java
├── HelloJNI.class
├── HelloJNI.h
├── HelloJNI.c
├── Hello.nim
├── libHelloJNI.so
└── nimcache
├── Hello.c
├── Hello.o
├── hello.h
├── stdlib_system.c
└── stdlib_system.o
Iyahoooooooooooo
$ java -Djava.library.path=. HelloJNI "Nim Nim Nim"
bonjour Nim Nim Nim
Recommended Posts