[JAVA] Ich habe jnr-ffi verwendet (einfacher zu bedienen usw.)

Glossar

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

Versuchen Sie es mit FFI

Projekterstellung

Geben Sie die JDK-Version auf 12 an (nicht sicher, ob dies sinnvoll ist).

Bibliothek hinzufügen

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'
}

Erstellen Sie eine Schnittstelle zur Funktionsdefinition

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.

Erstellen Sie eine Schnittstelle

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 Hauptklasse

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)
        );
    }
}

Implementieren Sie die Verarbeitung in C.

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.

Generieren Sie eine DLL-Datei

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

Angeben von Systemeigenschaften

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

Angeben von Systemeigenschaften in Gradle

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>"
}

Automatisierung der Schnittstellengenerierung

jextract Ein Tool, das automatisch ein JAR (mit Schnittstelle) aus einer .h-Datei generiert

Unterstütztes Betriebssystem

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.

Installieren Sie Panama Early Access

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

Jextract ausführen

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.

Hauptthema

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

Wie benutzt man

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 mit Gradle verwendet

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'
}

Liste der Artikel, auf die verwiesen wird

Links für Artikel zu jnr-ffi

Recommended Posts

Ich habe jnr-ffi verwendet (einfacher zu bedienen usw.)
Ich habe versucht, die verwendeten Methoden zusammenzufassen
Ich möchte DBViewer mit Eclipse 2018-12 verwenden! !!
Ich möchte @Autowired in Servlet verwenden
[Rails] Enum ist einfacher zu bedienen! Enumelize!
Ich habe versucht, Selen wie JQuery zu verwenden
Da der Befehl du, der bei voller Kapazität verwendet wird, schwierig zu verwenden ist, habe ich versucht, ihn mit Rubin zu umwickeln
Ich möchte Java8 für jeden mit Index verwenden
Code zum Verbinden von Rails 3 mit PostgreSQL 10
Ich habe einen Docker-Container erstellt, um Maven auszuführen
[Java] Ich habe Polymorphismus studiert, daher werde ich zusammenfassen, wie man ihn verwendet und welche Vorzüge er hat.