Ich wollte unbedingt Nims Pegs (PEGs) aus Java verwenden, also habe ich untersucht, wie man Nim-Funktionen über JNI aufruft.
Es stellten sich erstaunliche Fakten heraus ...
Mit jnim können Sie anscheinend eine gemeinsam genutzte Bibliothek nur mit Nim-Dateien erstellen. Nach morgen werde ich das Verfahren etwas weiter organisieren.
jnim_call.nim
import jnim
import dynlib
#Geben Sie das Argument so zurück, wie es ist
proc Java_HelloJNI_hello*(env: JNIEnvPtr, me:jobject, arg:jstring ): jstring {.cdecl,exportc,dynlib.} =
return arg
Kompilieren und ausführen
$ nim c --app:lib --noMain -o:libHelloJNI.so jnim_call.nim
$ java -Djava.library.path=. HelloJNI "Kannst du mich anrufen"
Kannst du mich anrufen
~~ Das Folgende ist also ein Müllartikel. ~~
Als ich in der obigen Nim-Quelle das Argument der JNI-Methode in jstring-> cstring-> string konvertierte, spuckte die JVM aus irgendeinem Grund einen Core-Dump aus und wurde abnormal beendet.
In der ersten Version hat es nicht funktioniert, es sei denn, ich habe zuerst NimMain aufgerufen und es initialisiert. Es scheint also, dass dies die Ursache ist.
Ich dachte, ich sollte NimMain alleine aufrufen, und als ich das Folgende mit dem Emit-Pragma schrieb, konnte ich es erfolgreich aufrufen, ohne einen Core-Dump auszuspucken! !!
jnim_call.nim
import jnim
import dynlib
#Geben Sie das Argument so zurück, wie es ist
proc Java_HelloJNI_hello*(env: JNIEnvPtr, me:jobject, arg:jstring ): jstring {.cdecl,exportc,dynlib.} =
#Initialisiere Nim
{.emit: """
NimMain();
""".}
#Argument String->cstring-Konvertierung
var argNim:cstring = env.GetStringUTFChars(env,arg,nil)
#Am Ende öffnen
defer:
env.ReleaseStringUTFChars(env,arg,argNim)
# cstring ->String-Konvertierung
var ss = "Hello " & $argNim
#Generieren Sie einen String und beenden Sie ihn
return env.NewStringUTF(env,ss)
Jetzt können Sie peg von Java aus aufrufen.
※※※※ Zugabe noch mehr ※※※※
Als ich die JNI-Methode ungefähr 10.000 Mal in einer Schleife aufrief, um zu sehen, ob ich jedes Mal NimMain aufrufen musste, Es wurde abnormal mit dem Fehler "Globale Variable kann nicht registriert werden; zu viele globale Variablen" beendet. Es scheint, dass ich NimMain nur einmal beim ersten Mal aufrufen muss, also habe ich mich entschieden, die in jnim definierten globalen Variablen zu verwenden. Mit dieser Unterstützung tritt auch dann kein Fehler auf, wenn Sie die JNI-Methode 100.000 Mal von Nim aufrufen! !! !!
jnim_call.nim
import jnim
import dynlib
#Geben Sie das Argument so zurück, wie es ist
proc Java_HelloJNI_hello*(env: JNIEnvPtr, me:jobject, arg:jstring ): jstring {.cdecl,exportc,dynlib.} =
#Initialisiere Nim
if theEnv == nil :
{.emit: """
NimMain();
""".}
theEnv = env
#Argument String->cstring-Konvertierung
var argNim:cstring = env.GetStringUTFChars(env,arg,nil)
#Am Ende öffnen
defer:
env.ReleaseStringUTFChars(env,arg,argNim)
# cstring ->String-Konvertierung
var ss = "Hello " & $argNim
#Generieren Sie einen String und beenden Sie ihn
return env.NewStringUTF(env,ss)
In Nims Forum gab es einen Beitrag, in dem ein Segmentierungsfehler bei einem nativen Aufruf mit jnim aufgetreten ist. Das gleiche Phänomen trat bei der nativen Methode auf, die ich in meinem Artikel erstellt habe. Als Lösung konnte ich das Problem umgehen, indem ich -d: noSignalHandler als Compileroption übergab.
Beschreibt die Kompilierungsoptionen zum Erstellen einer nativen SO-Datei (DLL) mit jnim.
nim c --out:libHelloJNI.so \
--app:lib \
--nomain \
--threads:on \
-d:release \
-d:noSignalHandler \
hello.nim
Java->Nim Ich las @ shsnow23s diesen Artikel und hatte das Gefühl, Java-> Nim aufrufen zu können, also machte ich ein Beispiel.
In Anbetracht der Speicherfreigabe nach der Rückgabe einer Zeichenfolge von Nim hielt ich es für sicherer, die Java-Objekterstellung in der JNI-Methode zu verwenden, und implementierte sie daher in JNI.
HelloJNI.java
//JNI-Testklasse
public class HelloJNI {
//Bibliothek laden
static {
System.loadLibrary("HelloJNI");
}
//JNI-Methode
private native String hello(String str);
//Hauptfunktion zum Testen
public static void main(String[] args){
HelloJNI h = new HelloJNI();
System.out.println(h.hello(args[0]));
}
}
proc hello_nim(s:cstring) : cstring {.exportc.} =
#Rückkehr durch Verketten von Zeichenketten
var ss:string = ""
ss = "hello " & $s
return ss
Der Header wird automatisch von javah generiert, sodass er nicht geändert werden muss.
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
C (JNI) Quelle. Konvertieren Sie die übergebenen Argumente in den nativen Typ, bevor Sie die Funktion nim aufrufen. Wenn Sie die Funktion NimMain nicht aufrufen, wird die Initialisierung auf der Nim-Seite nicht ausgeführt, was zu einem Laufzeitfehler führt. Informationen zur Implementierung von JNI finden Sie unter hier.
HelloJNI.c
#include "HelloJNI.h"
//Funktionsdefinition auf der Nim-Seite
#include "nimcache/hello.h"
JNIEXPORT jstring JNICALL Java_HelloJNI_hello
(JNIEnv * env, jobject pThis, jstring arg)
{
//Anruf erforderlich
NimMain();
//Char Argument*Umstellung auf
NCSTRING argNim = (*env)->GetStringUTFChars(env,arg,NULL);
//Nim-Funktionen aufrufen
NCSTRING ret = hello_nim(argNim);
//Geben Sie den reservierten Speicher frei
(*env)->ReleaseStringUTFChars(env,arg,argNim);
//Konstruiert eine Zeichenfolge aus dem Rückgabewert von Nim und gibt sie zurück
return (*env)->NewStringUTF(env,ret);
}
Ich kann kein Makefile machen, weil ich so schwach bin ... NIM_HOME ist das Verzeichnis, in dem Nim installiert ist.
build.sh
sharedlib=libHelloJNI.so
#Löschen Sie das vorherige Produkt vorerst
rm -rf nimcache
rm ${sharedlib}
#Nim-Kompilierung & C-Quellausgabe Die Quelle wird in Nimcache ausgegeben
nim c --noMain --noLinking --header:hello.h Hello.nim
#Nimcache mit JNI C-Quelle/*.c auch kompilieren
gcc -shared -fPIC \
-I ${JAVA_HOME}/include \
-I ${JAVA_HOME}/include/linux \
-I ${NIM_HOME}/lib \
-o ${sharedlib} \
HelloJNI.c nimcache/*.c
#Java wird ebenfalls kompiliert
javac HelloJNI.java
#Testlauf
java -Djava.library.path=. HelloJNI
Es wird in einem solchen Zustand sein.
.
├── 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"
Hallo Nim Nim Nim
Recommended Posts