Hey guys, I am building an uberjar with lein and later trying to run it, but I am getting an issue with “Could not find or load main class”. How is the main class determined? I have one namespace, and my profile sets it for :main
(defproject mal "0.1.0-SNAPSHOT"
:description "x"
:dependencies [[org.clojure/clojure "1.10.1"]
[net.n01se/clojure-jna "1.0.0"]]
:repl-options {:init-ns mal.core}
:profiles {:step0 {:main mal.step0-repl
:uberjar-name "step0_repl.jar"
:aot [mal.step0-repl]}})
You define your uberjar details in a custom profile
So you’d have to specify that lein with-profile step0 uberjar
Or use the built in automatically included profile :uberjar
I did invoke it that way
Do you have a '-main' function in that namespace?
Yes
and it runs as expected with lein with-profile step0 run
$ lein with-profile step0 run
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
user> test
user>$ lein with-profile step0 uberjar
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
Compiling mal.step0-repl
Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method, or the namespace has not been AOT-compiled.
Created /Users/g/code/mal/impls/myclj/target/mal-0.0.1-SNAPSHOT.jar
Created /Users/g/code/mal/impls/myclj/target/step0_repl.jar
$ java -jar ./target/step0_repl.jar
Error: Could not find or load main class mal.step0_repl
Caused by: java.lang.ClassNotFoundException: mal.step0_repl
It’s because my ns
didn’t have (:gen-class)
in it.
consider that you can skip :gen-class
or :aot
, and use clojure.main as your entry point
Sorry, I don’t understand what you mean. Do you mean in my invocation of the jar? What would that look like?
java -cp my.jar clojure.main -m my.ns
an advantage here is that you can also run a repl (leave out the -m arg) and any number of namespaces can have a runnable -main
(and you don't have a language feature that you use in prod but not during dev)
cool, I will want that, since each of my profiles have their own main. At work right now, but will try that out later. Thank you!
so is it that gen-class
means turn a namespace into a java cjass, and i don’t need that if i get the clojure.main class to instead load/invoke the namespace?
this also works by having gen-class / -main in multiple namespaces, but I think just using clojure.main is simpler over all
that's exactly it, cheers
🙏
Can you post your project.clj