Hello all, I'm trying to use into deps.edn in :deps with a local lib like my-lib\lib {:local/root "../../libs/my-lib"} . I have an alias build to make uberjar:
:build {:extra-deps {io.github.clojure/tools.build {:git/tag "v0.9.4" :git/sha "76b78fe"}
org.clojure/tools.deps.alpha {:mvn/version "0.15.1254"}}
:ns-default build}
but when I look at target/classes I didn't see any references of my-lib . What am I missing in this process? I could run it from repl but I could not generate a .jar that include it. Thank youWhatβs in your build.clj?
Thank you for your time. This is my build.clj
(ns build
(:require [clojure.tools.build.api :as b]))
(def lib 'myapp/myapp-api)
(def main 'myapp.main)
(def version-format "1.0.%s")
(def basis (b/create-basis {:project "deps.edn"}))
(def class-dir "target/classes")
(defn uberjar-name [mode lib]
(let [lib-name (name lib)
lib-name-with-mode (format "%s-%s" lib-name (name mode))]
(str "target/" lib-name-with-mode "." (format version-format (b/git-count-revs nil)) ".jar")))
(defn clean [system]
(println "\nCleaning target...")
(b/delete {:path "target"})
system)
(defn resources-env [mode]
(let [type (name mode)]
["src" "resources" "target/classes" (str "config/" type) (str "env/clj/modeling-api/" type)]))
(defn sources-env [mode]
(let [type (name mode)]
["src" (str "env/clj/modeling-api/" type)]))
(defn- uber-opts [{:keys [mode] :as opts}]
(assoc opts
:main main
:basis basis
:class-dir class-dir
:src-dirs (sources-env mode)
:ns-compile [main]))
(defn uber [{:keys [mode] :as system}]
(let [uber-file (uberjar-name mode lib)
opts (merge (uber-opts system) {:uber-file uber-file})]
(clean system)
(b/copy-dir {:src-dirs (resources-env mode)
:target-dir class-dir})
(println "Compiling...")
(b/compile-clj opts)
(println "Building uberjar" (str uber-file "..."))
(b/uber opts))
system)what is the dependency from deps.edn :local/root to build.clj? What should I consider into compile-clj ? Should I copy the sources from libs too?
to the last question, generally, no
the dependency comes in two ways - 1) the build.clj creates a basis using your project deps.edn - that's what specifies the dependencies of your uber jar
2) also, when you compile, it will be using the classpath of your dependencies per the basis to compile your code to classes
this is assuming that compiling your main loads and uses the code in my-lib/lib
if so, that load should compile and emit classes from my-lib
so I guess that's my first question - does main load and/or use code from my-lib?
Yes, because it execute some parts from my-lib before execute the main load
if I don't include the my-lib, it will not run
I tried to use :deps/prep but no lucky
that's a different purpose altogether (really for others using your project as a dep)
do you see any classes in target/classes?
Yes, but not that came from my-lib
maybe have I to include some dependency into code to tell the compiler to include the lib?
presumably your deps.edn has it in :deps ? if so, that's being included in the basis created in build.clj and used by compile-clj
Yes, it is in :deps
compilation is transitive based on loading the namespace you specify (which you have as main ). compilation is a side effect of loading, so whatever main loads (in it's ns form) will also be loaded and thus compiled. does main's ns load something from my-lib?
It loads dynamically from aero and integrant, not direct.
maybe should I force ns require the lib?
ah, you don't need to change your code, but you do need to tell the build what needs to be compiled if you are dynamically loading
so add any dynamically loaded namespaces to :ns-compile
oh, great Alex, I got it. I'll include it over there and give a try. I'll update the results. Thank you !
Hello Alex, it worked, thank you very much, I'd appreciate your help.
An alternative approach is to expand :src-dirs in copy-dir to also include any directories from the :classpath-roots of the basis -- essentially a "transitive" source inclusion -- which brings in every potential source file, so you don't have to catch every single dynamically loaded namespace in :ns-compile. I've used that approach with monorepos (and not necessarily doing AOT compilation).
I would not recommend that as a matter of course
I know, and it was never a default. But if you are not AOT'ing your uberjar for whatever reason, you do need it π
so, I was thinking why I had to include into :ns-compile 2 libs that it's not related to my-lib to work? :ns-compile [main 'malli.core 'malli.registry]
that's a .jar dependency?
doesn't matter if it's a jar or files. anything you want to compile has to be loaded.
most loading happens via namespace declarations and transitive loading is included. anything that's dynamically loaded will not be included so needs to be explicitly compiled.