Discussion:
lein uberjar runs forever?
Brandon Harvey
2012-03-15 23:09:39 UTC
Permalink
I have a fairly small project (<500 lines of Clojure code) that takes an
extremely long time to generate an uberjar. (Lein 1.7, Clojure 1.3). Some
features of the project:

- The project uses one jar file that's locally installed, using leiningen
- I use a simple invocation of gen-class in both of the project's (two)
code files
- One code (main.clj) file simply contains -main.
- The other code file (core.clj) contains a bunch of functions, one of
which is -marked for gen-class
- I call out the core file for :aot. I want its function to be callable
from Java.

Here is my project.clj:

(defproject jamsession "1.0.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.3.0"]
[aleph "0.2.1-beta1"]
[jelly "0.1.2-SNAPSHOT"]]
:aot [jamsession.core]
:main jamsession.main)

Here's output from an uberjar run that never (perhaps someday...) completes.
lein uberjar
Copying 20 files to /Users/sandover/src/projects/jamsession/lib
Copying 7 files to /Users/sandover/src/projects/jamsession/lib/dev
Compiling jamsession.core
Warning: *html-compatible* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-tag-depth* or change the name.
Compiling jamsession.main

Can anyone help? Thanks! I've tried commenting out :aot/gen-class for
core.clj. Not sure what else to try.

Brandon
Brandon Harvey
2012-03-15 23:56:37 UTC
Permalink
A little more information; I've reduced the project to a single clojure
file, containing -main and everything else. lein uberjar completes the
first part of the operation more quickly now, but still never completes.
lein uberjar
Copying 20 files to /Users/sandover/src/projects/jamsession/lib
Copying 7 files to /Users/sandover/src/projects/jamsession/lib/dev
Compiling jamsession.core
Warning: *html-compatible* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-tag-depth* or change the name.
Softaddicts
2012-03-16 00:34:32 UTC
Permalink
You do not happen to have some runtime initialization in the AOT file(s) ?
You should bracket these with something like:

(when-not *compile-files
....)

Otherwise they get executed as part of the compilation process.
You want to avoid that at build time, certainly if
the external runtime resources that might get involved are not available :)))

Luc P
Post by Brandon Harvey
A little more information; I've reduced the project to a single clojure
file, containing -main and everything else. lein uberjar completes the
first part of the operation more quickly now, but still never completes.
lein uberjar
Copying 20 files to /Users/sandover/src/projects/jamsession/lib
Copying 7 files to /Users/sandover/src/projects/jamsession/lib/dev
Compiling jamsession.core
Warning: *html-compatible* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-tag-depth* or change the name.
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Brandon Harvey
2012-03-20 04:05:58 UTC
Permalink
Post by Softaddicts
You do not happen to have some runtime initialization in the AOT file(s) ?
(when-not *compile-files
....)
Otherwise they get executed as part of the compilation process.
You want to avoid that at build time, certainly if
the external runtime resources that might get involved are not available :)))
That's an interesting question -- what would qualify as runtime
initialization? I def and defn a lot of things that are not exposed
through AOT with the '-' prefix; some of those defs things that need to be
evaluated in order for the program to work. An example:

(def pool-tcp-preamble
"The 88 byte preamble, represented as a seq of bytes"
(doall (map unchecked-byte
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50...

It's not yet entirely clear to me what the lifetime of code like this
actually is in Clojure.

Brandon
Softaddicts
2012-03-20 15:45:16 UTC
Permalink
A) Any code in a def (and variants, defonce, ..)is called immediately after compilation.
if you happen to connect to a database
to fetch a value in a def form, fetch property values from an external file,...
these would be done on the spot, after a successful compilation.

B) Anything done in a defn will get executed only when the defined form is called.
It's de facto deferred at runtime if the form is not called indirectly in a) or c)

C) Any other form inlined in you file will get compiled/ executed like def forms.
If you call (println "hello") in you AOT file, you will see its output while creating the
Jar file.

I hit a similar problem a couple of years ago when calling Spring from Clojure
the minute I switched to AOT. I had to defer the creation of the Spring context
to avoid creating one at compile time. That was lengthy, it had to access a lot of
external resources.

As a general rule, AOT code execution that references external resource has to be
deferred at buld time, either by wrapping it in a form or by testing the
compilation state flag.

Check your def forms and try to isolate the one that stalls. Tracing might be helpful
here.

Luc
Post by Brandon Harvey
Post by Softaddicts
You do not happen to have some runtime initialization in the AOT file(s) ?
(when-not *compile-files
....)
Otherwise they get executed as part of the compilation process.
You want to avoid that at build time, certainly if
the external runtime resources that might get involved are not available :)))
That's an interesting question -- what would qualify as runtime
initialization? I def and defn a lot of things that are not exposed
through AOT with the '-' prefix; some of those defs things that need to be
(def pool-tcp-preamble
"The 88 byte preamble, represented as a seq of bytes"
(doall (map unchecked-byte
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50...
It's not yet entirely clear to me what the lifetime of code like this
actually is in Clojure.
Brandon
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Sam Ritchie
2012-03-20 15:50:06 UTC
Permalink
I want to note that the exact same project that takes forever to "lein uberjar" will speed up immediately if you destroy the classes directory. This is on OS X Lion. The issues you raise are definitely relevant, but I think that Leiningen has a bug in OS X Lion that's not explained by any long-running def.

This comes up for me on projects with a fairly large net size of dependencies
 maybe 20MB or so.

--
Sam Ritchie
Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
Post by Softaddicts
A) Any code in a def (and variants, defonce, ..)is called immediately after compilation.
if you happen to connect to a database
to fetch a value in a def form, fetch property values from an external file,...
these would be done on the spot, after a successful compilation.
B) Anything done in a defn will get executed only when the defined form is called.
It's de facto deferred at runtime if the form is not called indirectly in a) or c)
C) Any other form inlined in you file will get compiled/ executed like def forms.
If you call (println "hello") in you AOT file, you will see its output while creating the
Jar file.
I hit a similar problem a couple of years ago when calling Spring from Clojure
the minute I switched to AOT. I had to defer the creation of the Spring context
to avoid creating one at compile time. That was lengthy, it had to access a lot of
external resources.
As a general rule, AOT code execution that references external resource has to be
deferred at buld time, either by wrapping it in a form or by testing the
compilation state flag.
Check your def forms and try to isolate the one that stalls. Tracing might be helpful
here.
Luc
Post by Brandon Harvey
Post by Softaddicts
You do not happen to have some runtime initialization in the AOT file(s) ?
(when-not *compile-files
....)
Otherwise they get executed as part of the compilation process.
You want to avoid that at build time, certainly if
the external runtime resources that might get involved are not available :)))
That's an interesting question -- what would qualify as runtime
initialization? I def and defn a lot of things that are not exposed
through AOT with the '-' prefix; some of those defs things that need to be
(def pool-tcp-preamble
"The 88 byte preamble, represented as a seq of bytes"
(doall (map unchecked-byte
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50...
It's not yet entirely clear to me what the lifetime of code like this
actually is in Clojure.
Brandon
--
Softaddicts
2012-03-20 16:12:48 UTC
Permalink
Brandon, are you running under OS X ? If yes did you try this fix ?

If you run lei jar, do you face the same issue ?
Luc
Post by Sam Ritchie
I want to note that the exact same project that takes forever to "lein uberjar" will speed up immediately if you destroy the classes directory. This is on OS X Lion. The issues you raise are definitely relevant, but I think that Leiningen has a bug in OS X Lion that's not explained by any long-running def.
This comes up for me on projects with a fairly large net size of dependencies… maybe 20MB or so. > > -- > Sam Ritchie
Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
Post by Softaddicts
A) Any code in a def (and variants, defonce, ..)is called immediately after compilation.
if you happen to connect to a database
to fetch a value in a def form, fetch property values from an external file,...
these would be done on the spot, after a successful compilation.
Post by Softaddicts
Post by Softaddicts
B) Anything done in a defn will get executed only when the defined form is called.
It's de facto deferred at runtime if the form is not called indirectly in a) or c)
Post by Softaddicts
Post by Softaddicts
C) Any other form inlined in you file will get compiled/ executed like def forms.
If you call (println "hello") in you AOT file, you will see its output while creating the > > Jar file.
Post by Softaddicts
Post by Softaddicts
I hit a similar problem a couple of years ago when calling Spring from Clojure
the minute I switched to AOT. I had to defer the creation of the Spring context
to avoid creating one at compile time. That was lengthy, it had to access a lot of
external resources.
Post by Softaddicts
Post by Softaddicts
As a general rule, AOT code execution that references external resource has to be > > deferred at buld time, either by wrapping it in a form or by testing the
compilation state flag.
Post by Softaddicts
Post by Softaddicts
Check your def forms and try to isolate the one that stalls. Tracing might be helpful
here.
Post by Softaddicts
Post by Softaddicts
Luc
Post by Brandon Harvey
Post by Softaddicts
You do not happen to have some runtime initialization in the AOT file(s) ?
(when-not *compile-files
....)
Post by Brandon Harvey
Post by Softaddicts
Otherwise they get executed as part of the compilation process.
You want to avoid that at build time, certainly if
the external runtime resources that might get involved are not available > > > > :)))
Post by Brandon Harvey
(def pool-tcp-preamble
"The 88 byte preamble, represented as a seq of bytes"
(doall (map unchecked-byte
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50...
Post by Softaddicts
Post by Brandon Harvey
It's not yet entirely clear to me what the lifetime of code like this > > > actually is in Clojure.
Brandon
--
Post by Softaddicts
Post by Softaddicts
Post by Brandon Harvey
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Brandon Harvey
2012-03-21 17:59:45 UTC
Permalink
Post by Softaddicts
Brandon, are you running under OS X ? If yes did you try this fix ?
If you run lei jar, do you face the same issue ?
Yes, I regularly blow away the lib and classes directories, and sometimes I
go nuke ~/.m2/repository for good measure.
Softaddicts
2012-03-21 20:45:42 UTC
Permalink
Can you post your minimal source file somewhere or send it to me privately
if you do not want to expose your code to all of us ?


Luc
Post by Brandon Harvey
Post by Softaddicts
Brandon, are you running under OS X ? If yes did you try this fix ?
If you run lei jar, do you face the same issue ?
Yes, I regularly blow away the lib and classes directories, and sometimes I
go nuke ~/.m2/repository for good measure.
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Brandon Harvey
2012-03-22 17:37:47 UTC
Permalink
OK, I've winnowed it down to a couple of files and it's reproducible for
me. (I found that I need to completely delete the 'classes' and 'lib'
directories to ensure repro.)

Here is project.clj:

(defproject jamsession "1.0.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.3.0"]
[aleph "0.2.1-SNAPSHOT"]]
:disable-deps-clean false
:omit-source true
:main jamsession.main)

And here is main.clj:

(ns jamsession.main
(:use [jamsession.binaryproteins])
(:require [aleph tcp])
(:gen-class))

(defn start-jam-session [port]
(println "hello world! port was " port))

(defn -startjamsession
"Java-callable wrapper function for start-jam-session"
([port] (start-jam-session port)))

(defn -main [& args]
(start-jam-session 65456))
rm -rf classes/
rm -rf lib
lein uberjar
Copying 16 files to /Users/demo/src/projects/jamsession/lib
Copying 16 files to /Users/demo/src/projects/jamsession/lib
Compiling jamsession.main
Warning: *html-compatible* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-tag-depth* or change the name.
**** never finishes ****

Here's the one-line change that fixes it: comment out the 'require aleph'
statement.
lein uberjar
Copying 16 files to /Users/demo/src/projects/jamsession/lib
Compiling jamsession.main
Compilation succeeded.
Created /Users/demo/src/projects/jamsession/jamsession-1.0.0-SNAPSHOT.jar
Including jamsession-1.0.0-SNAPSHOT.jar
Including aleph-0.2.1-20120321.005702-11.jar
Including clj-http-0.1.3.jar
Including clojure-1.3.0.jar
Including commons-codec-1.4.jar
Including commons-io-1.4.jar
Including commons-logging-1.1.1.jar
Including data.json-0.1.1.jar
Including gloss-0.2.1-beta1.jar
Including httpclient-4.0.3.jar
Including httpcore-4.0.1.jar
Including lamina-0.4.1-beta1.jar
Including netty-3.3.1.Final.jar
Including potemkin-0.1.2.jar
Including prxml-1.3.0-alpha4.jar
Including tools.logging-0.2.3.jar
Including user-agent-utils-1.2.3.jar
Created
/Users/demo/src/projects/jamsession/jamsession-1.0.0-SNAPSHOT-standalone.jar
Softaddicts
2012-03-22 18:35:18 UTC
Permalink
Most probably Aleph does something at compile time that needs to be deferred at run time. It could be in Aleph or one of its dependencies.

I'll look at this tonight, should give some feedback this week-end.

Any reason why you stick with the latest snapshot ? Did you try with the last
stable release ? (0.2.0 I believe)

Luc
Post by Brandon Harvey
OK, I've winnowed it down to a couple of files and it's reproducible for
me. (I found that I need to completely delete the 'classes' and 'lib'
directories to ensure repro.)
(defproject jamsession "1.0.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.3.0"]
[aleph "0.2.1-SNAPSHOT"]]
:disable-deps-clean false
:omit-source true
:main jamsession.main)
(ns jamsession.main
(:use [jamsession.binaryproteins])
(:require [aleph tcp])
(:gen-class))
(defn start-jam-session [port]
(println "hello world! port was " port))
(defn -startjamsession
"Java-callable wrapper function for start-jam-session"
([port] (start-jam-session port)))
(defn -main [& args]
(start-jam-session 65456))
rm -rf classes/
rm -rf lib
lein uberjar
Copying 16 files to /Users/demo/src/projects/jamsession/lib
Copying 16 files to /Users/demo/src/projects/jamsession/lib
Compiling jamsession.main
Warning: *html-compatible* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-tag-depth* or change the name.
**** never finishes ****
Here's the one-line change that fixes it: comment out the 'require aleph'
statement.
lein uberjar
Copying 16 files to /Users/demo/src/projects/jamsession/lib
Compiling jamsession.main
Compilation succeeded.
Created /Users/demo/src/projects/jamsession/jamsession-1.0.0-SNAPSHOT.jar
Including jamsession-1.0.0-SNAPSHOT.jar
Including aleph-0.2.1-20120321.005702-11.jar
Including clj-http-0.1.3.jar
Including clojure-1.3.0.jar
Including commons-codec-1.4.jar
Including commons-io-1.4.jar
Including commons-logging-1.1.1.jar
Including data.json-0.1.1.jar
Including gloss-0.2.1-beta1.jar
Including httpclient-4.0.3.jar
Including httpcore-4.0.1.jar
Including lamina-0.4.1-beta1.jar
Including netty-3.3.1.Final.jar
Including potemkin-0.1.2.jar
Including prxml-1.3.0-alpha4.jar
Including tools.logging-0.2.3.jar
Including user-agent-utils-1.2.3.jar
Created
/Users/demo/src/projects/jamsession/jamsession-1.0.0-SNAPSHOT-standalone.jar
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Brandon Harvey
2012-03-22 23:17:09 UTC
Permalink
I haven't seen a release under that version number, at least by doing 'lein
search aleph'.

On Zach's advice, over in the Aleph google group, I have just tried
version 0.2.1-alpha1. (A version that is also not discoverable by 'lein
search aleph'.) But I can report that it does fix my issue. So at least I
can stick with that version for now.

Brandon
Phil Hagelberg
2012-03-22 23:25:21 UTC
Permalink
Post by Brandon Harvey
On Zach's advice, over in the Aleph google group, I have just tried
version 0.2.1-alpha1. (A version that is also not discoverable by
'lein search aleph'.)
The indices used by lein search are downloaded on-demand, but they
aren't updated automatically. So that version probably didn't exist when
you first fetched them. You can use "lein search --update" to force a
refresh, but you probably don't want to do that because the Maven
Central ones take like twenty minutes to download; try "rm -rf
~/.lein/indices/http___clojars.org_repo_/" instead.

-Phil
Softaddicts
2012-03-25 03:46:20 UTC
Permalink
Hi,

I downloaded the beta1 jar of aleph and I tried to AOT it with lein 1.7.0,
I invoked the separate steps (deps, compile,...)
The compilation phase freezes after compiling the last file (udp.clj)

The last class files generated successfully before the freeze belong to the aleph trace.clj source file.

This one refers to components of lamina and at that point, I decided to stop...

Basically, compilation stalls somewhere down that path.

With AOT you may trigger a chain of compilations that
ends up very far from your source code because you are requiring components
that have not been built using AOT so the compiler adds stuff you refer to to its initial
scope as it discovers them.

Any AOT related problems that these component may have become then your problems.
Investigation can be a pain in the ass, each component needs to be investigated
in turn to find which ones can't take it.

You were unlucky :))

Time to go to bed...

Luc
Post by Brandon Harvey
I haven't seen a release under that version number, at least by doing 'lein
search aleph'.
On Zach's advice, over in the Aleph google group, I have just tried
version 0.2.1-alpha1. (A version that is also not discoverable by 'lein
search aleph'.) But I can report that it does fix my issue. So at least I
can stick with that version for now.
Brandon
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Brandon Harvey
2012-04-03 23:17:21 UTC
Permalink
For the record, this has been resolved. It was an issue in a library I was
using (aleph). Zach Tellman reported that "a non-daemon thread was being
started in Lamina during the compilation process. Targeting 0.2.1-beta2
will allow compilation/uberjar creation.".
And he's right!

Brandon
Softaddicts
2012-04-04 01:37:02 UTC
Permalink
Hé, hé, having more time and less need for sleep hours, I would have nailed it...

Luc P.
For the record, this has been resolved. It was an issue in a library I was > using (aleph). Zach Tellman reported that "a non-daemon thread was being > started in Lamina during the compilation process. Targeting 0.2.1-beta2 > will allow compilation/uberjar creation.". > And he's right!
Post by Brandon Harvey
Brandon
--
Softaddicts<lprefontaine-***@public.gmane.org> sent by ibisMail!
Phil Hagelberg
2012-03-20 17:07:02 UTC
Permalink
Post by Sam Ritchie
I want to note that the exact same project that takes forever to
"lein uberjar" will speed up immediately if you destroy the classes
directory. This is on OS X Lion. The issues you raise are definitely
relevant, but I think that Leiningen has a bug in OS X Lion that's
not explained by any long-running def.
The clean bug (which is triggered by uberjar) is fixed in the 1.x
branch. We are waiting on one more bug before releasing 1.7.1:

https://github.com/technomancy/leiningen/issues/455

-Phil
octopusgrabbus
2012-04-10 14:30:29 UTC
Permalink
Where would I put this code that you mentioned?
(when-not *compile-files
....)

Thanks.
cmn
Post by Softaddicts
You do not happen to have some runtime initialization in the AOT file(s) ?
(when-not *compile-files
....)
Otherwise they get executed as part of the compilation process.
You want to avoid that at build time, certainly if
the external runtime resources that might get involved are not available :)))
Luc P
Post by Brandon Harvey
A little more information; I've reduced the project to a single clojure
file, containing -main and everything else. lein uberjar completes the
first part of the operation more quickly now, but still never completes.
lein uberjar
Copying 20 files to /Users/sandover/src/projects/jamsession/lib
Copying 7 files to /Users/sandover/src/projects/jamsession/lib/dev
Compiling jamsession.core
Warning: *html-compatible* not declared dynamic and thus is not
dynamically
Post by Brandon Harvey
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not
dynamically
Post by Brandon Harvey
rebindable, but its name suggests otherwise. Please either indicate
^:dynamic *prxml-tag-depth* or change the name.
--
Sam Ritchie
2012-03-16 00:36:49 UTC
Permalink
Not sure why this happens, but the secret fix is:

rm -rf classes

It seems that this is only an issue on OS X Lion. I've been running into this myself on a number of projects.
--
Sam Ritchie
Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
Post by Brandon Harvey
lein uberjar
Copying 20 files to /Users/sandover/src/projects/jamsession/lib
Copying 7 files to /Users/sandover/src/projects/jamsession/lib/dev
Compiling jamsession.core
Warning: *html-compatible* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *html-compatible* or change the name.
Warning: *prxml-indent* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *prxml-indent* or change the name.
Warning: *prxml-tag-depth* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *prxml-tag-depth* or change the name.
Loading...