5

Is it legitimate to compile Clojure from Java using clojure.lang.Compiler.compile?

Our Java application used to create instances of Clojure objects by using clojure.lang.Compiler.load on a .clj source which had a proxy macro. Now we want to AOT compile these objects using gen-class rather than proxy. This is so the .class files can be moved around and we instantiate the objects later on.

The best I’ve managed so far is to convince clojure.lang.Compiler.compile to produce me the loader classfile (“my/domain/lib__init.class”). But I didn’t seem to get the accompanying .class files, one per function in the namespace (“my/domain/lib$fnname__1234.class”) and a stub class file for each gen-class. This is in a sandbox using the very simple first example at http://clojure.org/compilation. I thought I’d correctly set compile-path, and set it to something in the classpath, but maybe there’s still an issue there.

In any case, our actual application is RCP (Eclipse) based, which probably means they'll be more to figure out in terms of OSGI classloader classpath. In the meantime I’m just wondering if using clojure.lang.Compiler.compile directly is even a valid approach?

Edit: So I've now got it producing all the .class files, but it needed various bits of undocumented initializing which suggests to me that methods on clojure.lang.Compiler are meant to be internal. I had to set *compile-path* appropriately and *compile-files* to true, e.g.

RT.var("clojure.core", "*compile-files*").bindRoot(true);

2 Answers 2

2

You should try to use clojure.core/compile function. Also you can check out how lein handles the :aot param to do aot compilation.

Sign up to request clarification or add additional context in comments.

2 Comments

I believe Ankur's suggestion is to call clojure.core/compile directly from Java: RT.var("clojure.core", "compile").invoke(...). Grabbing vars and executing them from Java is far less error-prone and less confusing than trying to use the Java internals of clojure. If I recall correctly, this is how the Datomic Java API is implemented.
@DaveRay: Yup, thats what I meant by calling this from java
1

Here is an example of driving the Clojure compiler directly from Java.

        String clojureScript = "(ns user) (def hello (fn [] \"Hello world\"))";
        String notionalScriptFileName="hello.clj";
        String outputDirectory="/my/output/dir";

        Var compilePath = RT.var("clojure.core", "*compile-path*");            
        Var compileFiles = RT.var("clojure.core", "*compile-files*");

        Var.pushThreadBindings(RT.map(compilePath, outputDirectory, compileFiles, Boolean.TRUE));                        
        Compiler.compile(new StringReader(clojureScript), notionalScriptFileName, notionalScriptFileName);
        Var.popThreadBindings();

I've tested this with Clojure 1.4.0... your mileage may vary with other versions.

As the API stands you need to provide a "notional" file name. This only seems to be used to generate the .class file names. The class files it generates are written to the outputDirectory.

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.