I have a project where I want certain parts of the code to be able to run on a local environment, and other parts which depend on libraries that only run on a remote environment. E.g.
src/app/core.clj <- can run anywhere
src/app/sandbox/remote_only.clj <- depnds on libs that only function in remote environ
where src/app/core.clj
is
(ns app.core
(:gen-class))
(defn -main [] (println "Hello, World!"))
and src/app/sandbox/remote_only.clj
is
(ns app.sandbox.remote-only
(:require
[uncomplicate.commons.core :refer [with-release]]
[uncomplicate.neanderthal
[native :refer [dv dge]]
[core :refer [mv mv!]]]))
I want to be able to uberjar
and run the code located in core.clj
on my local machine without pulling in remote_only.clj
which will cause the program to fail locally. According to the docs, Leiningen should be able to accomplish this using profiles and uberjar exclusions e.g.:
(defproject app "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.10.1"]]
:profiles {:uberjar {:main app.core
:init-ns app.core
:aot :all}
:remote {:init-ns app.sandbox.remote_only
:dependencies [[uncomplicate/neanderthal "0.43.1"]]}} ; these deps will fail locally
:uberjar-exclusions [#".*sandbox.*"]
:repl-options {:init-ns app.core})
compiling the uberjar here will result in:
❯ lein uberjar
Compiling app.core
Compiling app.sandbox.remote-only
Syntax error macroexpanding at (remote_only.clj:1:1).
Execution error (FileNotFoundException) at app.sandbox.remote-only/loading (remote_only.clj:1).
Could not locate uncomplicate/commons/core__init.class, uncomplicate/commons/core.clj or uncomplicate/commons/core.cljc on classpath.
So, explicitly its trying to compile the class that was specifically excluded.
I thought that this kind of problem could be avoided by removing the :all
tag from :aot
compilation. E.g.:
(defproject app "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.10.1"]]
:profiles {:uberjar {:main app.core
:init-ns app.core
:aot [app.core]}
:remote {:init-ns app.sandbox.remote_only
:dependencies [[uncomplicate/neanderthal "0.43.1"]]}} ; these deps will fail locally
:uberjar-exclusions [#".*sandbox.*"]
:repl-options {:init-ns app.core})
which causes other problems:
❯ lein uberjar
Compiling app.core
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT.jar
Created /Users/warrenronsiek/Projects/app/target/app-0.1.0-SNAPSHOT-standalone.jar
~/Projects/app 5s 15:47:37
❯ java -jar ./target/app-0.1.0-SNAPSHOT.jar
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Var
I've tried playing around with all kinds of :exclusions
, :jar-exclusions
and regexes. Variations of this question have been asked multiple times (1, 2) Nothing works.
How do I get Leiningen to compile uberjars and ignore the specified file(s)?
You are on the right track with changing :aot :all
to :aot [app.core]
but when you tried to run the JAR, you are running the library version instead of the whole application version:
java -jar ./target/app-0.1.0-SNAPSHOT.jar
That doesn't include Clojure or any dependencies. You want:
java -jar ./target/app-0.1.0-SNAPSHOT-standalone.jar