Reputation: 2922
I have a project setup at the moment that works like a charm when I use lein run
.
The minimal case that causes the problem is the following. I have two files, shown below. The core.clj
file is supposed to throw an error and then stop. The error is simply an error that extends the standard Error
of Java. However, when I open up this file in emacs and open up cider I can't get it to compile properly.
(ns meta-clojure.core
(:import (org.jsoup Jsoup)
(java.lang String)
(meta_clojure.stm RetryEx)))
(defn -main
[& args]
(println "Throwing exception now..")
(throw (RetryEx. "this is broken"))
(println "End of main")
nil)
(ns meta-clojure.stm.RetryEx
(:gen-class :extends java.lang.Error))
Now, as I said, when I run the lein run
command it executes just fine. However, in emacs I get the following stack trace:
clojure.lang.Compiler$CompilerException: java.lang.ClassNotFoundException: meta_clojure.stm.RetryEx, compiling:(/home/christophe/bitbucket/meta-clojure/src/meta_clojure/core.clj:1:1)
Compiler.java:7142 clojure.lang.Compiler.load
NO_SOURCE_FILE:1 user/eval931
Compiler.java:6703 clojure.lang.Compiler.eval
Compiler.java:6666 clojure.lang.Compiler.eval
core.clj:2927 clojure.core/eval
main.clj:239 clojure.main/repl[fn]
main.clj:239 clojure.main/repl[fn]
main.clj:257 clojure.main/repl[fn]
main.clj:257 clojure.main/repl
RestFn.java:1523 clojure.lang.RestFn.invoke
interruptible_eval.clj:67 clojure.tools.nrepl.middleware.interruptible-eval/evaluate[fn]
AFn.java:152 clojure.lang.AFn.applyToHelper
AFn.java:144 clojure.lang.AFn.applyTo
core.clj:624 clojure.core/apply
core.clj:1862 clojure.core/with-bindings*
RestFn.java:425 clojure.lang.RestFn.invoke
interruptible_eval.clj:51 clojure.tools.nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj:183 clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval[fn]
interruptible_eval.clj:152 clojure.tools.nrepl.middleware.interruptible-eval/run-next[fn]
AFn.java:22 clojure.lang.AFn.run
ThreadPoolExecutor.java:1145 java.util.concurrent.ThreadPoolExecutor.runWorker
ThreadPoolExecutor.java:615 java.util.concurrent.ThreadPoolExecutor$Worker.run
Thread.java:745 java.lang.Thread.run
Caused by: java.lang.ClassNotFoundException: meta_clojure.stm.RetryEx
URLClassLoader.java:366 java.net.URLClassLoader$1.run
URLClassLoader.java:355 java.net.URLClassLoader$1.run
(Unknown Source) java.security.AccessController.doPrivileged
URLClassLoader.java:354 java.net.URLClassLoader.findClass
DynamicClassLoader.java:61 clojure.lang.DynamicClassLoader.findClass
ClassLoader.java:425 java.lang.ClassLoader.loadClass
ClassLoader.java:358 java.lang.ClassLoader.loadClass
(Unknown Source) java.lang.Class.forName0
Class.java:191 java.lang.Class.forName
core.clj:1 meta-clojure.core/eval935[fn]
core.clj:1 meta-clojure.core/eval935
Compiler.java:6703 clojure.lang.Compiler.eval
Compiler.java:6692 clojure.lang.Compiler.eval
Compiler.java:7130 clojure.lang.Compiler.load
Could anyone help me out please? I think I need to tell Cider/Emacs to compile ahead of time or something. Perhaps leiningen compiles to different directories than emacs?
Upvotes: 3
Views: 475
Reputation: 91534
You are correct that you need to compile the meta-clojure.stm.RetryEx namespace to produce the class files before you can include it. This is sometimes useful if you are writing a class for consumption by a Java library and core.clj is only a test harness for developing, though it's not the easy or typical way to go about it. It is a bit more common to use require instead of include to refer to a clojure namespace from with a Clojure project.
You can check what is actually been compiled by looking in the target/classes
directory of the project. before compiling I see:
arthur@a:~/meta-clojure$ ls target/classes/
META-INF
Then after compiling it from the repl:
user> (compile 'meta-clojure.stm.RetryEx)
meta-clojure.stm.RetryEx
user>
meta-clojure.core> (-main )
Throwing exception now..
RetryEx this is broken meta-clojure.core/-main (core.clj:6)
meta-clojure.core>
And checking the same directory:
arthur@a:~/meta-clojure$ ls -R target/classes/
target/classes/:
meta_clojure META-INF
target/classes/meta_clojure:
stm
target/classes/meta_clojure/stm:
RetryEx.class RetryEx$fn__3333.class RetryEx$fn__3351.class RetryEx__init.class RetryEx$loading__4958__auto__.class
target/classes/META-INF:
maven
target/classes/META-INF/maven:
meta-clojure
target/classes/META-INF/maven/meta-clojure:
meta-clojure
target/classes/META-INF/maven/meta-clojure/meta-clojure:
pom.properties
Leiningen is happy to do the AOT compiling for you, if you specify which namespaces require it:
project.clj:
(defproject meta-clojure "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.6.0"]]
:aot [meta-clojure.stm.RetryEx])
and then run lein compile
:
arthur@a:~/meta-clojure$ lein compile
Compiling meta-clojure.stm.RetryEx
arthur@a:~/meta-clojure$ ls target/classes/
meta_clojure/ META-INF/
arthur@a:~/meta-clojure$ ls target/classes/meta_clojure/stm/
PS: you also don't need to include java.lang.String
it's included by default.
Upvotes: 1