How do I just use AOT compiled class files over clj(c) source with a leiningen uberjar?

351 views
Skip to first unread message

lvh ‌

unread,
Apr 1, 2017, 2:49:22 PM4/1/17
to Clojure
Hi,


Context: I'm using Proguard to try to minimize an uberjar produced with lein uberjar. This is failing, because when I run the resulting jar with java -jar minimized.jar, I get errors about missing classes while trying to load/compile .clj files.  proguard is renaming classes and removing unused ones. In this case, the class is still in the jar, but under another name. As long as the _class_ files are loaded, this should be fine (it's proguard's job to rename all references). But proguard doesn't know about Clojure, so the Clojure files don't get the same treatment. I understand that Clojure generally imports source files as resources, but I was hoping with an :aot :all uberjar, that wouldn't be the (primary) case. Removing clj[csx]? files from the jar (via :uberjar-exclusions) (which I was hoping would force it to try the class files), breaks:

Caused by: java.io.FileNotFoundException: Could not locate clojure/core_instant18__init.class or clojure/core_instant18.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.

This appears to be due to this source file: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core_instant18.clj ; and the lack of matching class file can be explained because it is in the clojure.core namespace.

Do I misunderstand how :aot :all works? Are clj files always going to exist in the resulting uberjar if I want Clojure to work?
 

lvh

Daniel Compton

unread,
Apr 1, 2017, 3:24:30 PM4/1/17
to Clojure
Zach Tellman talked about making Clojure work better with Proguard in August 2016. I couldn’t find any open JIRA tickets about this though.

https://www.deepbluelambda.org/programming/clojure/creating-android-applications-with-clojure--slimming-things-down-with-proguard and https://github.com/sattvik/Clojure-Android-Examples/blob/master/slimmed/proguard.cfg are from an old post about Proguard on Android which looks like it might have what you need to get started, though I’m not sure about core_instant18.clj. Possibly something like this might help?

-keep class clojure.core_instant18__init { public static void load(); }

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--

Daniel

lvh

unread,
Apr 1, 2017, 3:42:03 PM4/1/17
to clo...@googlegroups.com
Hi Daniel,


Thanks, I didn't know about Zach's talk. FWIW: that instant18 clj does not occur in the _uberjar_ (before proguard gets its grubby mitts on it).


lvh

Alex Miller

unread,
Apr 3, 2017, 10:24:57 AM4/3/17
to Clojure
core_instant18.clj is conditionally loaded if you are using >= Java 1.8 to extend the Inst protocol to java.time.Instant (which didn't exist in prior JDKs). This is set up at:


There is some similar conditional loading for clojure.core.reducers (dealing with whether using JDK 1.6 with jsr-166 jar or JDK 1.7+) in:


Those are the two things like that that I know of in Clojure. There are a handful of other namespaces that are not AOT compiled - clojure.parallel (deprecated, also has forkjoin dependencies), clojure.instant, and clojure.uuid. I think the last two may just be an oversight.

Alex Miller

unread,
Apr 3, 2017, 10:26:14 AM4/3/17
to Clojure

On Saturday, April 1, 2017 at 2:24:30 PM UTC-5, Daniel Compton wrote:
Zach Tellman talked about making Clojure work better with Proguard in August 2016. I couldn’t find any open JIRA tickets about this though.

Zach and I actually talked about this again at Clojure/west this week and I think he's going to do some work on it. I can't really comment as I don't know what is being requested.


lvh

unread,
Apr 3, 2017, 3:45:56 PM4/3/17
to clo...@googlegroups.com
Thanks, Alex! That helps a lot.

Is my understanding of how uberjars with aot complication work otherwise correct? I.e. apart from the dynamically loaded 

One thing I particularly care about is compile-time precomputation. My app uses source JSON data (that I don't control) that's pretty big, but the stuff it produces from that data is pretty small. In ClojureScript, I did this by just using macros, since ClojureScript conveniently guarantees those will be evaluated on the JVM and compile time. So, for example, when I was using ClojureScript to write a GreaseMonkey script/WebExtension (where there are good reasons to keep everything in a single file) and i wanted to include e.g. some literal CSS in the source, I'd just use a macro.

Does a similar trick work with Clojure and AOT compilation + uberjar, or should I use a resource as an intermediate? I'm fine with it loading e.g. instant18.clj (although it'd certainly be neater if I didn't have to :)))

thanks in advance,
lvh


--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages