[JAVA] J'ai utilisé jnr-ffi (facilité d'utilisation, etc.)

Glossaire

JNR (Java Native Runtime) Mécanisme pour appeler du code natif depuis Java Contenu principal du Projet Panama JEP 191: Foreign Function Interface a été proposé

FFI (Foreign Function Interface) L'interface est définie en Java ~~ (pas) ~~, excellente chose qui peut être implémentée en C ou C ++ Créer et appeler un objet à partir d'une bibliothèque de liens dynamiques (.dll ou .so) en utilisant un gars appelé LibraryLoader

Essayez d'utiliser FFI

Création de projet

Spécifiez la version JDK à 12 (je ne sais pas si cela a du sens)

Ajouter une bibliothèque

Ajoutez la bibliothèque aux dépendances dans build.gradle.

version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

//Partie supplémentaire
dependencies {
    //Corps FFI
    compile group: 'com.github.jnr', name: 'jnr-ffi', version: '2.1.9'
    //Bibliothèques dont dépend FFI
    compile group: 'org.ow2.asm', name: 'asm', version: '7.0'
}

Créer une interface pour la définition de fonction

Puisque la bibliothèque créée en C est appelée, la spécification est définie dans Interface. La définition de méthode dans Interface est alignée sur la déclaration de fonction dans le fichier d'en-tête (.h).

Cette fois, nous avons implémenté la Méthode euclidienne de division mutuelle pour trouver l'engagement maximum.

Créer une interface

Décrivez le même contenu que euclid.h dans Interface.

fact.java


public interface test {
    int euclid(int m, int n);
}

Créer une classe principale

Créez un fichier Java pour l'appelant.

Test.java


import jnr.ffi.LibraryLoader;

public class Test {
    public static void main(String[] args) {
        System.out.println(
            /*Charger un objet de type fact
Lors de la création, passez la classe de l'interface spécifiée
Dans l'argument load, le nom de fichier du fichier dll sous forme de chaîne de caractères(Hors extensions)donner*/
            LibraryLoader.create(test.class).load("test")
                //Exécuter euclid
                .euclid(2,4)
        );
    }
}

Implémenter le traitement en 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);
}

Oui, j'ai normalement implémenté des fichiers d'en-tête et des programmes en C.

Générer un fichier .dll

L'interface de fonction étrangère utilise la bibliothèque de liens dynamiques, donc il génère un fichier .dll. Lors de la création d'une dll, créons-en une qui correspond au nombre de bits du système d'exploitation. À propos, si vous l'exécutez dans un état où le système d'exploitation et le nombre de bits sont différents, ou il n'y a pas de dll en premier lieu, java.lang.UnsatisfiedLinkError: unknown J'obtiens l'erreur.

J'ai utilisé gcc de MinGW.

gcc -shared -o test.dll test.cpp

Spécification des propriétés du système

Vous devez transmettre le chemin d'accès aux propriétés système java.library.path afin d'inclure le fichier .dll que vous avez créé dans votre projet. En Java, vous pouvez définir les propriétés système comme suit lors de l'exécution de commandes java.

java -D<Nom de la propriété>=<Propriété>

Dans ce cas, vous pouvez inclure le fichier .dll en l'exécutant comme ceci.

java -Djava.library.path=C:\\test.dll Test

Spécification des propriétés système dans Gradle

Lorsque vous l'exécutez dans Gradle, vous ne vous souciez pas de taper la commande java, non? Ainsi, en ajoutant un peu à build.gradle, vous pouvez passer les propriétés du système lorsque vous l'exécutez avec le bouton d'exécution.

//Le nom de la tâche est-il arbitraire?
task launch(type: JavaExec) {
    //Spécifiez le nom de la classe principale pour laquelle vous souhaitez spécifier systemProperty
    main = "Test"
    //C'est magique
    classpath sourceSets.main.runtimeClasspath
    systemProperty "java.library.path", "<.chemin du fichier dll>"
}

Automatisation de la génération d'interface

jextract Un outil qui génère automatiquement un fichier jar (avec interface) à partir d'un fichier .h

Système d'Exploitation pris en charge

jextract n'est actuellement inclus que dans Project Panama Early Access Edition. Le problème est qu'actuellement (14 janvier 2019) seules les versions Linux et Mac sont disponibles. Je ne pouvais pas m'en empêcher, alors j'ai Introduit Bash sur Ubuntu sous Windows.

Installer l'accès anticipé au Panama

J'ai généralement un binaire avec wget. Il semble que make install etc. est ** inutile **. Vous pouvez l'utiliser immédiatement en le décompressant avec la commande tar. Au fait, passons le chemin.

wget https://download.java.net/java/early_access/panama/archive/0/binaries/jdk-12-foreign+0_linux-x64_bin.tar.gz

Exécutez jextract

Spécifiez simplement le fichier .h.

jextract test.h

Ajoutez le fichier jar généré (test.h.jar dans ce cas) à votre projet. (Spécifiez dans la bibliothèque avec Edition-> Structure du projet.)

Vous n'avez plus besoin d'écrire la même description dans l'interface et l'en-tête un par un.

Sujet principal

Donc, je n'aimais pas mettre le nom du fichier dans la propriété un par un lors de la mise en place de ce fichier jar et de cette dll, et je ne savais pas comment définir la propriété système lorsque je mettais la dll dans le jar, donc à la place J'ai fait un gars pour le faire.

Le programme est conservé sur github, donc si vous voulez l'utiliser, prenez-le et utilisez-le. Javakky/UseC4ffi4Windows

Comment utiliser

Placez la dll dans le dossier de ressources. Passez simplement le chemin du fichier .dll (ci-dessous / resource) et la classe Interface à loadDll et l'objet sera renvoyé.

LoadDllTest.java


public class LoadDllTest {
    public static void main(String[] args) {
        //Vous pouvez obtenir un objet avec juste ça
        IClassA func = LoadDll.loadDll("<.nom dll>", <interface>.class));
    }
}

Utilisé avec gradle

Publié dans bintry afin qu'il puisse être utilisé à partir du projet gradle.

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 des articles auxquels il est fait référence

Liens pour les articles liés à jnr-ffi

Recommended Posts

J'ai utilisé jnr-ffi (facilité d'utilisation, etc.)
J'ai essayé de résumer les méthodes utilisées
Je souhaite utiliser DBViewer avec Eclipse 2018-12! !!
Je veux utiliser @Autowired dans Servlet
[Rails] Enum est plus facile à utiliser! Énumélisez!
J'ai essayé d'utiliser Selenium comme JQuery
Comme la commande du utilisée lorsque la capacité est pleine est difficile à utiliser, j'ai essayé de l'envelopper avec du rubis
Je veux utiliser java8 forEach avec index
Code utilisé pour connecter Rails 3 à PostgreSQL 10
J'ai créé un conteneur Docker pour exécuter Maven
[Java] J'ai étudié le polymorphisme, je vais donc résumer comment l'utiliser et ses mérites.