我能否从C++中调用Clojure代码?

6
我正在为一个 C++ 程序编写插件。
插件放置在特定目录中,并由主应用程序调用。我希望在 Clojure 中编写插件的大部分内容(图形界面、计算等),但实际的“插件”需要用 C++ 编写。需要将各种数据从 C++ 传递给 Clojure。
如何实现呢?
可以采用 JNI/JNA、套接字、系统调用等方式(这些都不是我非常了解的)。

我从未使用过Clojure,因为我不是Lisp或宏的粉丝。简短查看维基百科,它似乎在Java VM中运行,同时支持CLR并可以编译为JavaScript。无论如何,它都不是本地语言,因此要从C ++ 中调用它,您需要一些包装器DLL、Web服务或两者兼备。 - AJG85
5
这个问题分为两部分:1)如何从C++调用Java,2)如何从Java调用Clojure。后者并不难,http://clojure.org/java_interop 是一个起点。第一个问题取决于您的要求和环境。在我很久以前的一个项目中,我们使用了sockets:http://sourceforge.net/projects/jradius/。 - Gert
2个回答

8
我知道这个问题很老,但或许会有人发现这很有用。
#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

2
JNI对于这个问题应该很直观易懂。我会按照以下方式进行:
1. 使用明确定义的外部接口开发你的Clojure代码,即你需要调用的任何一组方法/函数。 2. 将其打包为一个独立的uber-jar文件(包含Clojure库)。 3. 编写C++包装器,必须执行以下操作: - 用类路径上的uberjar创建JVM(请参阅此链接:http://java.sun.com/docs/books/jni/html/invoke.html) - 加载你的Clojure类 - 提供一个门面,将C++函数映射到底层Java方法(Clojure函数)
你可以通过一个简单的独立Java测试工具来测试第2步中的uber-jar,该工具创建主要的Clojure类并调用适当的方法;这将让你知道你是否有一个良好的Java/Clojure jar文件,以防在第3步JNI调用时遇到任何问题。
在检查JNI引用时,特别注意C和C++ JNI链接之间微妙的调用差异。
祝你好运。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接