views:

77

answers:

1

When you create a Clojure project with leiningen all the *.clj-files are compiled AOT. Normally the AOT compilation is not necessary and I would like to minimize it.

This is necessary for me to raise acceptance of Clojure as a complement in a Java-dominated environment. It is easier to "sell" a single class-file as the glue together with a couple of kB clj-files against the alternative of having 250+ kB class-files with strange names and hidden amongst them a little clj-file (which isn't even read any more during execution).

Ideally the result of "lein compile" would be only a single small class file which (together with the clj-files and the clojure-library) implements the needed class-instance.

What is the easiest way to achieve this? I would prefer not to write a single line of Java (of course).

Update after feedback from technomancy

I do not suspect this being a leiningen problem. Let me explain what I am after with an example. Please forgive the length of the example. I am using leiningen 1.3.1 but I think 1.4.0-SNAPSHOOT behaves the same way.

$ lein new dummy
Created new project in: dummy
$ cd dummy

Now change project.clj to (added ":main dummy.core"):

(defproject dummy "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.2.0"]
                 [org.clojure/clojure-contrib "1.2.0"]]
  :main dummy.core)

and src/dummy/core.clj to:

(ns dummy.core
  (:gen-class))
(defn -main [& args]
  (println "This is Clojure code, args=" args))

Now compile it:

$ lein compile
Compiling dummy.core

This generates the following files in classes/dummy:

core.class
core__init.class
core$loading__4410__auto__.class
core$_main.class

This is all correct, I can execute the result:

$ java -cp lib/*:classes dummy.core Hello
This is Clojure code, args= (Hello)

Now comes what I want to have instead, but I do it manually: I can delete all class-files except core.class and copy the core.clj into classes/dummy which now looks very empty:

$ ls classes/dummy/
core.class
core.clj

The core.class contains code to load the core.clj at runtime and the result is still the same, I still can do:

$ java -cp lib/*:classes dummy.core Hello
This is Clojure code, args= (Hello)

I can also modify core.clj (note: in classes/dummy!) and of course changes do not need to be recompiled.

Now my question boils down to this: Is there an easier way to get just this core.class?

+3  A: 

Leiningen has done no AOT by default for quite some time now; perhaps you have an older version? But there is a new feature (in 1.4.0-SNAPSHOT) that ensures .class files created due to transitive AOT get deleted before jar creation, (see Clojure assembla #322) which may also interest you.

technomancy
I am using 1.3.1. and leiningen is not to blame, of course. However when I do "lein new dummy", fill the dummy/core.clj with some "defn" and add a ":main dummy.core" to the project.clj then "lein compile" produces loads of class files. Again, this is probably correct (lein is never wrong!), but I would like to know how to prevent this.
jramb
Yeah, you're getting bitten by Clojure bug #322: https://www.assembla.com/spaces/clojure/tickets/322-enhance-aot-compilation-process-to-emit-classfiles-only-for-explicitly-specified-namespaces Leiningen 1.4 will contain a workaround for this problem. It should be released in a week or so; if you need it sooner you can run from git.
technomancy
Thanks for the feedback, technomancy! I look forward to the new release. Above I tried to explain in more detail what I wish to accomplish. Although I understand the relationship of bug #322 to my problem I hope mine is much easier to solve. :-)
jramb
I see. The fix in 1.4 makes it so if you require a contrib lib or something in your ns then those class files will be deleted, but it sounds like you want everything except core.class deleted. This could be added fairly easily, but it's a much less serious problem. If you really need this I'd take a patch to the leiningen.compile/has-corresponding-src? function (perhaps the :keep-non-project-classes key in project.clj could support a special value for your use case); otherwise this will have to wait for another release beyond 1.4.
technomancy
If this could be done in leiningen (now or some future version) I think there would be more than me who would find it a useful feature. I am starting to think this might a feature to wish from Clojure rather than from leiningen...
jramb