JNR (Java Native Runtime) Mechanismus zum Aufrufen von nativem Code aus Java Hauptinhalt von Project Panama JEP 191: Foreign Function Interface wurde vorgeschlagen
FFI (Foreign Function Interface) Die Schnittstelle ist in Java ~~ (nicht) ~~ definiert, eine hervorragende Sache, die in C oder C ++ implementiert werden kann Erstellen und rufen Sie ein Objekt aus einer dynamischen Linkbibliothek (.dll oder .so) mit einem Typ namens LibraryLoader auf
Geben Sie die JDK-Version auf 12 an (nicht sicher, ob dies sinnvoll ist).
Fügen Sie die Bibliothek zu Abhängigkeiten in build.gradle hinzu.
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
//Zusätzlicher Teil
dependencies {
//FFI Körper
compile group: 'com.github.jnr', name: 'jnr-ffi', version: '2.1.9'
//Bibliotheken, von denen FFI abhängt
compile group: 'org.ow2.asm', name: 'asm', version: '7.0'
}
Da die in C erstellte Bibliothek aufgerufen wird, wird die Spezifikation in Interface definiert. Die Methodendefinition in Interface ist an der Funktionsdeklaration in der Header-Datei (.h) ausgerichtet.
Dieses Mal haben wir die euklidische Methode der gegenseitigen Teilung implementiert, um das maximale Versprechen zu finden.
Beschreiben Sie den gleichen Inhalt wie euclid.h in der Benutzeroberfläche.
fact.java
public interface test {
int euclid(int m, int n);
}
Erstellen Sie eine Java-Datei für den Anrufer.
Test.java
import jnr.ffi.LibraryLoader;
public class Test {
public static void main(String[] args) {
System.out.println(
/*Laden Sie ein Objekt vom Typ fact
Übergeben Sie beim Erstellen die Klasse der angegebenen Schnittstelle
Im Ladeargument der Dateiname der DLL-Datei als Zeichenfolge(Erweiterungen ausschließen)geben*/
LibraryLoader.create(test.class).load("test")
//Führen Sie euclid aus
.euclid(2,4)
);
}
}
euclid.h
int euclid(int i, int j);
euclid.c
int euclid(int m, int n){
int tmp, r;
if(n > m){
tmp = m;
m = n;
n = tmp;
}
r = m % n;
if(r == 0) return n;
return euclid(n, r);
}
Ja, ich habe normalerweise Header-Dateien und -Programme in C implementiert.
Die Fremdfunktionsschnittstelle verwendet die dynamische Linkbibliothek und generiert daher eine DLL-Datei. Wenn Sie eine DLL erstellen, erstellen wir eine, die der Anzahl der Bits des Betriebssystems entspricht. Übrigens, wenn Sie es in einem Zustand ausführen, in dem das Betriebssystem und die Anzahl der Bits unterschiedlich sind oder es überhaupt keine DLL gibt, java.lang.UnsatisfiedLinkError: unknown Ich bekomme den Fehler.
Ich habe gcc von [MinGW] verwendet (https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/rubenvb/).
gcc -shared -o test.dll test.cpp
Sie müssen den Pfad an die Systemeigenschaften java.library.path übergeben, um die von Ihnen erstellte DLL-Datei in Ihr Projekt aufzunehmen. In Java können Sie die Systemeigenschaften wie folgt festlegen, wenn Sie Java-Befehle ausführen.
java -D<Name des Anwesens>=<Eigentum>
In diesem Fall können Sie die DLL-Datei einschließen, indem Sie sie wie folgt ausführen.
java -Djava.library.path=C:\\test.dll Test
Wenn Sie es in Gradle ausführen, müssen Sie den Java-Befehl nicht eingeben, oder? Wenn Sie build.gradle ein wenig hinzufügen, können Sie Systemeigenschaften übergeben, wenn Sie es mit der Schaltfläche run ausführen.
//Ist der Aufgabenname beliebig?
task launch(type: JavaExec) {
//Geben Sie den Hauptklassennamen an, für den Sie systemProperty angeben möchten
main = "Test"
//Das ist Magie
classpath sourceSets.main.runtimeClasspath
systemProperty "java.library.path", "<.DLL-Dateipfad>"
}
jextract Ein Tool, das automatisch ein JAR (mit Schnittstelle) aus einer .h-Datei generiert
jextract ist derzeit nur in Project Panama Early Access Edition enthalten. Das Problem ist, dass derzeit (14. Januar 2019) nur Linux- und Mac-Versionen verfügbar sind. Ich konnte nicht anders, also habe ich Bash unter Ubuntu unter Windows eingeführt.
Normalerweise habe ich eine Binärdatei mit wget. Es scheint, dass make install etc. ** unnötig ** ist. Sie können es sofort verwenden, indem Sie es mit dem Befehl tar dekomprimieren. Übrigens lassen Sie uns den Pfad passieren.
wget https://download.java.net/java/early_access/panama/archive/0/binaries/jdk-12-foreign+0_linux-x64_bin.tar.gz
Geben Sie einfach die .h-Datei an.
jextract test.h
Fügen Sie die generierte JAR-Datei (in diesem Fall test.h.jar) zu Ihrem Projekt hinzu. (Geben Sie in der Bibliothek mit Bearbeiten-> Projektstruktur an.)
Jetzt müssen Sie nicht mehr dieselbe Beschreibung in Interface und Header einzeln schreiben.
Daher wollte ich den Dateinamen nicht einzeln in die Eigenschaft einfügen, wenn ich diese JAR und DLL einfügte, und ich wusste nicht, wie ich die Systemeigenschaft festlegen sollte, wenn ich die DLL in die JAR einfügte Ich habe einen Mann dazu gebracht.
Das Programm wird auf Github gehalten. Wenn Sie es also verwenden möchten, nehmen Sie es auf und verwenden Sie es. Javakky/UseC4ffi4Windows
Platzieren Sie die DLL im Ressourcenordner. Übergeben Sie einfach den DLL-Dateipfad (unten / resource) und die Interface-Klasse an loadDll, und das Objekt wird zurückgegeben.
LoadDllTest.java
public class LoadDllTest {
public static void main(String[] args) {
//Mit genau diesem können Sie ein Objekt erhalten
IClassA func = LoadDll.loadDll("<.DLL-Name>", <Schnittstelle>.class));
}
}
Wird in bintry veröffentlicht, damit es aus dem gradle-Projekt verwendet werden kann.
build.gradle
repositories {
maven {
url 'https://dl.bintray.com/javakky/maven'
}
}
dependencies{
compile group: 'com.github.javakky', name: 'jnr-load-dill', version: '1.0.1'
}
・ Links für Artikel zu jnr-ffi
Recommended Posts