tools-build

pinealan 2025-04-15T22:33:56.691049Z

Hi all, I am running into an odd situation where some namespaces of local dependencies are not being compiled when building an uberjar. To illustrate: In project B there is a local source-only dependency on A, i.e.

;; deps.edn of Project B
{:paths ["src" "dev" "resources"] 
 :deps {project/A {:local/root "../project/A"} ...}}
along with a fairly standard minimal build.clj
(def basis (b/create-basis {:project "deps.edn"}))
(def class-dir "target/classes")
(defn uber
  [_]
  (b/delete {:path class-dir})
  (b/copy-dir {:src-dirs ["src" "resources"] :target-dir class-dir})
  (b/compile-clj {:basis basis :class-dir class-dir})
  (b/uber
    {:class-dir class-dir
     :uber-file "target/uber.jar"
     :basis     basis
     :main      'main})
Now this runs fine, but when I run the uber jar for project B, it errors out with ClassNotFound for functions that should come from A. Initially I thought that means tools.build doesn’t support compiling source from dependencies, but I haven’t found any docs indicating that. Even more odd is that upon inspection of the jar content (via jar -tf), I notice that it is exactly the set of project A ns that has been explicitly required by B which are not compiled, whilst the transitively required nses in project A are compiled. FYI I’m running tools.build :mvn/version "0.10.8" Any idea on what’s going wrong here? I would love to share more detail but I’m not even sure where to start

pinealan 2025-04-16T22:00:27.589289Z

I get the ClassNotFoundException when running the uberjar built by project B; say for instances in B there’s a namespace like so

(ns b.main
  (:require
    [a.lib.x]))
and in A there’s
(ns a.lib.x
  (:require
    [a.lib.y]))
then I’d get a compiled b.main and a.lib.y , but not a.lib.x

pinealan 2025-04-16T22:01:46.838869Z

I do have a user.clj, but that’s under the dev path which shouldn’t be included in my build basis, so I’m not sure if that should affect anything

2025-04-16T22:01:50.455559Z

but what kind of class is not found?

2025-04-16T22:02:35.198419Z

I would double check by at least temporarily getting rid of the user.clj

2025-04-16T22:04:16.003509Z

what you are describing sounds like what would happen if a.lib.x was required, then in the same clojure runtime call like (clojure.core/compile 'a.lib.x) happened

🤔 1
pinealan 2025-04-16T22:14:17.978739Z

hm looks like indeed it’s user.clj causing the issues, once I removed it (even though I’m sure its directory is not on the cp), I can see the rest of the classes in the jar

pinealan 2025-04-16T22:15:38.480719Z

rather odd that something not on cp would affect the build, or I might be wrong and it’s sneaking in somehow; anyway thanks a lot for the tip!

2025-04-16T22:16:17.693409Z

the fact that it was being loaded proves it was on the classpath, user.clj is a tricky thing

2025-04-15T22:46:13.478739Z

what do you mean by "ClassNotFound for functions that should come from A"?

2025-04-15T22:46:30.571489Z

when and where do you see a classnotfound error?

2025-04-15T22:50:34.947939Z

do you have a user.clj?

2025-04-15T22:52:07.687199Z

likely you have something that is causing the namespaces to be loaded before compiling loads them, user.clj being the main thing that causes this (the only?)

2025-04-15T22:53:30.668259Z

because of the way clojure.core/compile is written things that it is explicitly called on will get compiled regardless of if the namespace is already loaded or not, but for transitive namespaces, if they are already loaded, they don't get compiled