In the context of a monorepo containing several modules I have noticed an issue with clojure.tools.build.api/compile-clj
which is making difficult to compile files when the basis project root is not in the current directory.
Here is a minimal scenario demonstrating the problem.
I have a top-level monorepo deps.edn
using tools.build to prepare/package its modules
{:deps {monorepo/module-a {:local/root "modules/a"}}
:aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.8.2"
:git/sha "ba1a2bf"}}
:ns-default build}}}
Module A contains some clojure source files. Here is modules/a/deps.edn
{:paths ["src"]}
Those files require a compilation step. Here is the top-level build.clj
file expected to proccess those files.
(ns build
(:require [clojure.tools.build.api :as b]))
(def module-a (binding [b/*project-root* "modules/a"]
(b/create-basis {:project "deps.edn"})))
(defn compile-a [_]
(b/compile-clj
{:basis module-a
:src-dirs ["modules/a/src"]
:class-dir "target/module-a/classes"}))
However when invoking clojure -T:build compile-a
from top-level directory I encounter the following error
Execution error (FileNotFoundException) at user/eval136$fn (compile.clj:5).
Could not locate monorepo/module/a__init.class, monorepo/module/a.clj or monorepo/module/a.cljc on classpath.
The problem is that the "src" relative directory is not expanded in the :classpath-roots
which lead compile-clj
to search source files in the wrong location. It is possible to work around the issue by binding the *project-root*
again and adapting :src-dirs
and class-dir
relative to module A root directory like this
(defn compile-a [_]
(binding [b/*project-root* "modules/a"]
(b/compile-clj
{:basis module-a
:src-dirs ["src"]
:class-dir "../../target/module-a/classes"})))
However IMO it would be better if the computed classpath in the basis was fully expanded by transforming relative paths into absolute ones to avoid this extra ceremony.
What do you think?
Is there a reason why relative source path directories are currently kept relative ?