Just came across an issue with the latest lein release v2.9.0:
─$ git clone <https://github.com/quil/quil.git>
# with lein 2.9.0
─$ lein do clean, compile
Compiling quil.applet
java.lang.ClassNotFoundException: quil.helpers.AppletListener, compiling:(quil/applet.clj:256:22)
Exception in thread "main" java.lang.ClassNotFoundException: quil.helpers.AppletListener, compiling:(quil/applet.clj:256:22)
...
Caused by: java.lang.ClassNotFoundException: quil.helpers.AppletListener
# after downgrading to lein 2.8.3:
─$ lein do clean, compile
Compiling quil.helpers.applet-listener
Compiling quil.applet
─$ java -version
java version "1.8.0_202"
Has anyone seen anything similar?Is there a race condition in the compilation?
are you using :aot :all ?
looks like, no (there was a possible change in compilation order with that in lein 2.9.0)
https://github.com/technomancy/leiningen/commit/76dbf7c3ce6f8ea79e4e20014fe757048ccf9c45
?
oh wait, you are seeing a difference in order there
project.clj has :aot [quil.helpers.applet-listener quil.applet]
- but you are seeing quil.applet
compiled first
that sort was supposed to only occur for :aot :all based on what I was told. if not, then I'd say that's a regression and you should file a bug
ok will do, thanks @alexmiller
Yeah, looks like it sorts all forms of :aot
from that commit above.
ref: https://www.reddit.com/r/Clojure/comments/aplq3x/leiningen_29_released/egaayfp/
However, isn’t it not really a good impl in quil.applet to not require the namespace that the class is defined in?
Not saying lein should resort your list, just thinking, that’d break with :aot :all
if you chose to go that route instead later
I mean, quil.applet refers to the class quil.helpers.AppletListener, without adding a :require
for quil.helpers.applet-listener
I tend to consider that a faulty ns
it's loading a gen-class though?
if I'm reading it right, AppletListener is a genclass. aot is being used to compile it. applet is just using it purely as a java class.
that all seems sane to me
@alexmiller It’s loading a gen-class’ed class
but if you did AOT :all
and is “started” with the ns quil.applet, it’d fail I think
due to the missing :require
so it wouldn’t know to first compile that ns
Well, I did learn now that lein :aot :all
calls repeated compile
on each ns. Not a big fan of that due to duplicated loading concerns. Yikes
I wish it would just take a “single entry point” ns that transitively requires all else - so only one compile
goes
well, yes. that's why you sometimes need to order your aot calls
but seems like you wouldn’t have the ordering problem if you have a single top-level ns that causes the transitive (one time load) of everything it depends on
but thanks for the reddit pointer. all stuff I was unaware of and good to know about now.
I still think if I use a gen-class class from another ns, I always make taht explicit with a (:require [quil.helpers.applet-listener])
<- the ns that defines the gen-class
I don't think there is any reason to in this case
@mikerod fyi just tried :aot :all
with lein 2.8.3. Without the require I get a ClassNotFoundException
for AppletListener
and with the require I don’t as you expected. Order of compilation:
...
Compiling quil.applet
...
Compiling quil.helpers.applet-listener
...
@anthony-galea @alexmiller
Yeah, the general rule I’m getting at is that if a ns requires another ns to be pre-loaded - for any reason, including side effects like gen-class - then it should explicitly ensure that other ns is loaded - typically via adding it to :require
(or something that loads appropriately).
So this quil ns, assumes the gen-class class exists, but never ensures the ns that creates it is loaded. That violates my “general rule” here. I think it’s a brittle pattern when you don’t make your direct dependencies explicitly called out.
ie. I’d expect to be able to do (compile 'quil.applet)
and have success with no prior compile
calls to ns’s it depends on.
All that aside though, I didn’t realize that (1) :aot :all
in lein calls compile
multiple times for possibly inter-related ns’s and (2) now there is this sorting happening both for all and what looks like the explicit ns vector way.
That’s how aot works in all tools
1 that is