Можно ли вызвать код clojure из C ++? - PullRequest
3 голосов
/ 28 декабря 2011

Я пишу плагин для программы, написанной на C ++.

Плагины помещаются в определенный каталог и вызываются основным приложением.Я хотел бы написать большую часть плагина в Clojure (графический интерфейс, расчеты и т. Д.), Однако фактический «плагин» должен быть написан на C ++.Различные данные должны быть переданы из C ++ в Clojure.

Как это сделать?

JNI / JNA, сокеты, системные вызовы?(ничего о чем я не знаю)

Ответы [ 2 ]

4 голосов
/ 25 февраля 2018

Я знаю, что этот вопрос старый, но, может быть, кто-то найдет это полезным.

#include <jni.h>       /* where everything is defined */
#include <cstring>

int main() {
    JavaVM *jvm;       /* denotes a Java VM */
    JNIEnv *env;       /* pointer to native method interface */
    JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = "-Djava.class.path=/home/raoof/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:/home/raoof/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;
    /* load and initialize a Java VM, return a JNI interface
     * pointer in env */
    JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    delete options;

    jclass Clojure = env->FindClass("clojure/java/api/Clojure");
    jmethodID var = env->GetStaticMethodID(Clojure, "var", "(Ljava/lang/Object;Ljava/lang/Object;)Lclojure/lang/IFn;");
    jobject load_string = env->CallStaticObjectMethod(Clojure, var, env->NewStringUTF("clojure.core"), env->NewStringUTF("load-string"));
    jmethodID load_string_invoke = env->GetMethodID(env->GetObjectClass(load_string), "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
    env->CallObjectMethod(load_string, load_string_invoke, env->NewStringUTF("(prn (+ 1 2 3 4 5))"));

    jvm->DestroyJavaVM();
}

, а затем

g++ -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/ -L/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server -ljvm clojurejvm.cpp
LD_LIBRARY_PATH=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server ./a.out
1 голос
/ 30 декабря 2011

JNI должен быть довольно простым для этого.

Я бы подошел к этому так:

  1. разработайте ваш код clojure с четко определенным внешним интерфейсом, т. Е. С любым набором методов/ functions, которые вам нужно вызвать.
  2. упакуйте его в виде отдельного uber-jar (также содержащего библиотеки clojure)
  3. напишите вашу обёртку для c ++, которая должна сделать следующее:
    • создайте jvm с вашим uberjar на пути к классам (см. Эту ссылку: http://java.sun.com/docs/books/jni/html/invoke.html)
    • загрузите свой класс clojure
    • предоставьте фасад, который отображает функции c ++ на базовый javaметоды (функции clojure)

Вы можете протестировать свой uber-jar, начиная с шага 2, с помощью простого автономного тестового набора java, который создает основной класс clojure и вызывает соответствующие методы;это даст вам знать, что у вас есть хороший java / clojure jar на случай, если вы столкнетесь с какими-либо проблемами в вызове jni на шаге 3.

При проверке ссылок jni обращайте особое внимание на легкий / тонкий вызовразличия между c и c ++ jni-связями.

Удачи.

...