6

I'm writing a plugin for a program written in C++.

Plugins are placed in a specific dir and get called by the main application. I would like to write most of the plugin in Clojure (gui, calculations, etc) however the actual "plugin" needs to be written in C++. Various data needs to be passed from C++ to Clojure.

How can I do this?

JNI/JNA, sockets, system calls? (nothing I know much about)

2
  • Never used Clojure as I'm not a fan of lisp or macros. Brief scan of wikipedia it looks like it runs in a Java VM but also supports CLR and can compile down to JavaScript. Either way it's not native so to call it from C++ you'll need some kind of wrapper DLL, webservice, or both. Commented Dec 28, 2011 at 0:06
  • 5
    There are two parts to this question: 1) how do you call Java from C++, and 2) how do you call Clojure from Java. The latter is not that hard, clojure.org/java_interop is a starting point. The first question depends on your requirements and your environment. For a project I worked on long, long ago, we used sockets: sourceforge.net/projects/jradius Commented Dec 28, 2011 at 0:15

2 Answers 2

8

I know this question is old but maybe somebody find this useful.

#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();
}

and then

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
Sign up to request clarification or add additional context in comments.

Comments

2

JNI should be pretty straightforward for this.

I would approach it this way:

  1. develop your clojure code with a well defined external interface, ie, whatever set of methods/functions you need to invoke.
  2. package it as a standalone uber-jar (containing the clojure libs as well)
  3. write your c++ wrapper, which must do the following:

You can test your uber-jar from step 2 via a simple standalone java test harness that creates the main clojure class and invokes the appropriate methods; this will let you know that you have a good java/clojure jar in case you run into any issues in the jni invocation in step 3.

As you check the jni references pay particular attention to the slight/subtle calling differences between the c and c++ jni linkages.

Good luck.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.