Cible inexplorée Nous utilisons Qulacs, qui est un simulateur d'ordinateur quantique écrit principalement en C ++ pour le développement de l'ordinateur quantique gated 2018. Qulacs a déjà des liaisons Python, mais j'ai toujours voulu développer en Scala, qui est également un langage de programmation plus familier. J'ai donc utilisé Java CPP pour faire beaucoup de recherches pour appeler une bibliothèque native comme Qulacs de Scala via Java, et enfin le plug-in sbt. J'ai pu faire.
En fait, il existe un plug-in sbt dans l'organisation GitHub de JavaCPP, mais j'ai découvert que c'était pour faciliter l'utilisation d'OpenCV, etc. qui sont déjà disponibles dans JavaCPP de Scala, afin qu'une nouvelle bibliothèque native puisse être utilisée à partir de Scala. J'ai décidé d'en créer un nouveau cette fois car ce n'était pas quelque chose à faire. Cet article décrit comment utiliser ce plugin sbt et certaines implémentations internes. Si vous avez des questions ou des améliorations après avoir lu cet article, n'hésitez pas à nous le faire savoir dans les commentaires.
Ce plug-in sbt fait trois choses:
g ++
pour créer une bibliothèque native utilisable depuis Java.Tout d'abord, (1) semble être créé différemment selon la bibliothèque (en utilisant make
, etc.), donc la commande OS est passée en tant que settingKey
de sbt. Et (2) démarre également un nouveau processus Java à partir de sbt. Cela aurait dû être fait avec les modifications appropriées des options passées à la JVM, et aurait pu être réalisé avec les modifications appropriées de la commande run
et de javaOptions
de sbt, mais c'était un gros effort. Je l'ai fait parce qu'il n'y avait pas de changement. Ensuite, Java CPP fonctionnera (3) et deviendra une bibliothèque de liens dynamiques pouvant être appelée depuis Java.
De là, j'expliquerai basé sur Sample Project. Maintenant, le code source C ++ et le fichier d'en-tête existent comme suit.
cpp_src/HelloWorld.hpp
class HelloWorld {
public:
int printN(int n);
};
cpp_src/HelloWorld.cpp
#include <iostream>
#include <string>
#include "HelloWorld.hpp"
using namespace std;
int HelloWorld::printN(int n) {
for (int i = 0; i < n; i++) {
cout << "Hello World!\n";
}
return n;
}
Tout d'abord, écrivez les paramètres de compilation dans build.sbt
.
build.sbt
includePath := (baseDirectory in Compile).value / "cpp_src"
libraryName := "libHelloWorld"
makeLibraryCommands := Seq(
gppCompilerPath.value,
"-I", includePath.value.toString,
currentLibraryMeta.value.option,
"-o",
(libraryDestinationPath.value / s"${libraryName.value}.${currentLibraryMeta.value.extension}").toString,
((baseDirectory in Compile).value / "cpp_src" / "HelloWorld.cpp").toString
)
Ici, makeLibraryCommands
est la commande du système d'exploitation utilisée pour créer libHelloWorld
. Je vais expliquer dans l'ordre.
Premièrement, gppCompilerPath
utilise clang ++
par défaut.
Ensuite, currentLibraryMeta
stocke les options de traitement telles que clang ++
par le système d'exploitation, et la structure de donnéesDynamicLibraryMeta
pour absorber l'extension de la bibliothèque native générée.
DynamicLibraryMeta.scala
sealed abstract class DynamicLibraryMeta(
val option: String,
val extension: String
)
object DynamicLibraryMeta {
case object Mac extends DynamicLibraryMeta("-dynamiclib", "dylib")
case object Linux extends DynamicLibraryMeta("-shared", "so")
}
Et currentLibraryMeta
est automatiquement sélectionné dans la propriété Java System.getProperty (" os.name ")
par défaut. Par défaut, libraryDestinationPath
utilise également un répertoire dédié sous le répertoire target
.
Ensuite, créez du code Java qui utilise la bibliothèque native.
src/main/java/javacpp/sbt/HelloWorld.java
package javacpp.sbt;
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include = {"HelloWorld.hpp"}, link = "HelloWorld")
public class HelloWorld extends Pointer {
static {
Loader.load();
}
public HelloWorld() {
allocate();
}
public native void allocate();
public native int printN(int n);
}
Revenez à build.sbt
et indiquez la bibliothèque native et le chemin de classe Java correspondant.
build.sbt
nativeJavaClassPath := "javacpp.sbt.*"
enablePlugins(SbtJavaCPP4S)
Vous pouvez également utiliser des caractères génériques comme celui-ci. De plus, avec ce plug-in activé, le travail dans build.sbt
est terminé.
Enfin, créez le code d'appel de pièce Java à partir de Scala.
src/main/scala/javacpp/HelloWorld.scala
object HelloWorld {
def main(args: Array[String]): Unit = {
val instance = new HelloWorld()
instance.printN(5)
}
}
Après cela, si vous sbt run
ceci, ce sera comme suit.
$ sbt run
[info] Loading settings for project example from build.sbt ...
[info] Set current project to example (in build file:/Users/yyu/Desktop/javacpp-sbt/example/)
[info] Compiling 1 Scala source to /Users/yyu/Desktop/javacpp-sbt/example/target/scala-2.12/classes ...
[info] Success!
[info] running (fork) org.bytedeco.javacpp.tools.Builder -cp /Users/yyu/Desktop/javacpp-sbt/example/target/scala-2.12/classes:/Users/yyu/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/bytedeco/javacpp/1.5.1/javacpp-1.5.1.jar:/Users/yyu/.sbt/boot/scala-2.12.10/lib/scala-library.jar -Dplatform.compiler=clang++ -Dplatform.includepath=/Users/yyu/Desktop/javacpp-sbt/example/cpp_src -Dplatform.linkpath=/Users/yyu/Desktop/javacpp-sbt/example/target/libjni -d /Users/yyu/Desktop/javacpp-sbt/example/target/libjni javacpp.sbt.*mple / Compile / generateJNILibrary 0s
[info] Generating /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/jnijavacpp.cpp
[info] Generating /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/jniHelloWorld.cpp
[info] Compiling /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/libjniHelloWorld.dylib
[info] clang++ -I/Users/yyu/Desktop/javacpp-sbt/example/cpp_src -I/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home/include/darwin /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/jniHelloWorld.cpp /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/jnijavacpp.cpp -march=x86-64 -m64 -O3 -Wl,-rpath,@loader_path/. -Wall -fPIC -dynamiclib -undefined dynamic_lookup -o libjniHelloWorld.dylib -L/Users/yyu/Desktop/javacpp-sbt/example/target/libjni -Wl,-rpath,/Users/yyu/Desktop/javacpp-sbt/example/target/libjni -lHelloWorld -framework JavaVM
[info] Deleting /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/jniHelloWorld.cpp
[info] Deleting /Users/yyu/Desktop/javacpp-sbt/example/target/libjni/jnijavacpp.cpp
[info] running (fork) javacpp.HelloWorld
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[success] Total time: 6 s, completed 2019/11/09 4:57:50
Cela fonctionne bien comme ça.
Le petit exemple a fonctionné, donc maintenant je veux pouvoir travailler avec de grandes bibliothèques C ++ comme Qulacs. Ce développement demande beaucoup d'efforts pour la quantité de code. Après tout, j'ai eu beaucoup de problèmes, comme ne pas bien connaître l'erreur native et ne pas connaître les liens dynamiques. En passant, je pense que la complexité des liens dynamiques est l'une des raisons pour lesquelles le langage Go est un seul binaire.
Recommended Posts