2024 Clojure 状态调查!中分享您的想法。

欢迎!请查看关于页面,获取更多关于这一过程的信息。

0 投票
tools.build

在一个包含多个模块的 monorepo 环境中,我遇到了一个关于 clojure.tools.build.api/compile-clj 的问题,使得在基础项目根不在当前目录时难以编译文件。

下面是一个演示问题的最小场景。

我有一个顶级 monorepo deps.edn,使用 tools.build 准备/包装其模块

 {: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}}}

模块 A 包含一些 Clojure 源文件。这里是 modules/a/deps.edn

{:paths ["src"]}

这些文件需要编译步骤。这里是处理这些文件的最高级 build.clj 文件。

(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"}))

然而,当我从顶级目录调用 clojure -T:build compile-a 时,遇到了以下错误

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.

问题是 "src" 相对目录没有在 :classpath-roots 中展开,导致 compile-clj 在错误的位置搜索源文件。可以通过再次绑定 *project-root* 并将 :src-dirsclass-dir 相对于模块 A 的根目录进行调整来解决这个问题。

(defn compile-a [_]
  (binding [b/*project-root* "modules/a"]
    (b/compile-clj
     {:basis module-a
      :src-dirs ["src"]
      :class-dir "../../target/module-a/classes"})))

然而,在我看来,最好是让 basis 中的计算出的类路径完全展开,将相对路径转换为绝对路径,以避免这种额外的仪式。

您怎么看?
为什么目前保留相对源路径目录为相对路径?

1 个答案

0 投票

您应该绑定 *project-root,以便正确解析项目和任何递归局部依赖项中的相对路径。由于这个目的存在 *project-root*。我认为最好不在创建 basis 和 compile-clj 等构建任务之前将 basis 放到变量中。

是的,我明白当前 *tools.build* 在调用任何依赖于路径解析的构建任务时,需要绑定 `*project-root*`。

我想表达的是,这在一个单仓模式(monorepo)下略显不便,在这种模式下,你可以操作多个基于不同目录的模块,这些目录都包含你希望统一处理的 `deps.edn` 文件。

一个可能会简化问题的建议是放松绑定 `*project-root*` 的要求,将其作为对应于构建基础 `deps.edn` 文件的基本目录的静态属性。

    (binding [b/*project-root* "modules/a"]
                (b/create-basis {:project "deps.edn"}))

可以简单地替换为

    (b/create-basis {:project "modules/a/deps.edn"})

然后调用 `compile-clj` 就不需要再设置项目根目录了,因为作为参数传递的基将会已经知道它。要实现这种设计,可以将 `deps.edn` 的相对路径转换为绝对路径,根据 `deps.edn` 的基本目录,这将允许额外的相对路径参数依然可以根据 `build.clj` 的基本目录进行解析。

这讲得通吗?
是的,我会考虑的。
...