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
Spécifiez la version JDK à 12 (je ne sais pas si cela a du sens)
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'
}
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.
Décrivez le même contenu que euclid.h dans Interface.
fact.java
public interface test {
int euclid(int m, int n);
}
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)
);
}
}
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.
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
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
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>"
}
jextract Un outil qui génère automatiquement un fichier jar (avec interface) à partir d'un fichier .h
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.
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
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.
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
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));
}
}
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'
}
・ Liens pour les articles liés à jnr-ffi
Recommended Posts