如何在从 deps.edn 运行 -M 或 -X 之前编译所有源代码和测试?

问题描述

我的项目有一些需要 AOT 编译的代码

以下是我的 deps.edn 的缩短版本。我发现在每次测试运行之前编译一些代码的唯一方法是将 -e (compile,'my.project.namespace)添加:main-opts。这需要了解需要编译的确切命名空间,这些命名空间在开发过程中会定期更改。即使是单元测试中的简单实验,也可能需要临时更改 deps.edn,这很烦人。

{:paths   ["src" "classes"]
 :deps    {}
 :aliases {:test           {:extra-paths ["test"]}
           :test/cognitect {:extra-deps {com.cognitect/test-runner {:git/url "..." :sha "..."}}
                            :main-opts  ["-e" "(compile,'my.project.namespace1)"
                                         "-e" "(compile,'my.project.namespace2)"
                                         "-e" "(compile,'my.project.namespace3)"
                                         "-m" "cognitect.test-runner"]
                            :exec-fn    cognitect.test-runner.api/test}}

这将使用 clj -M:test:test/cognitect 调用

当使用某个别名调用 -M(或 -X)时,是否有一种简单的方法来编译整个项目(包括测试)?

我知道 -e 可以处理任何 Clojure 表达式,因此一种选择是编写一个完整的小程序,该程序将枚举所有命名空间并对其调用 compile。只要代码简单,我就可以接受。这是个好主意吗?

一般来说,如何设置一个 deps.edn 来 AOT 编译整个项目?

解决方法

看看tools.buildhttps://clojure.org/guides/tools_build

这是核心团队对这个问题的回答。

,

Sean Corfield's answer 似乎是最好的方向。鉴于 tools.build 是多么的新,我认为扩展一些内容可能会有所帮助,让其他人了解如何做到这一点并突出显示我遇到的问题。

(def class-dir "target/classes")

(def basis (b/create-basis {:project "deps.edn"
                            ;; Include any aliases that will bring deps required for 
                            ;; compilation onto the classpath.
                            :aliases [:spark-deps :test]}))

(defn compile-for-tests
  []
  (b/compile-clj {:basis basis
                  :src-dirs ["src" "test"]
                  :class-dir class-dir
                  ;; Filters which classes get written into `class-dir` by their namespace prefix.
                  :filter-nses ['my.project]})`)

我相信上述内容通常是您所需要的,但是我的项目需要 2 个编译阶段。一个编译一些 :gen-class 命名空间,第二个编译代码库的其余部分(其中一些将这些 :gen-class 类导入为 Java 类)。

此外,那些 :gen-class 命名空间似乎需要一次编译一个(即使它们不相互引用),以免获得 ClassNotFoundException。我无法解释这是为什么,但如果我弄清楚了,我会更新这个答案。以下是我目前正在使用的确切功能。

(defn ns-under-prefix
  [prefix paths]
  (let [all-ns (mapcat #(-> % b/resolve-path jio/file find/find-namespaces-in-dir) paths)]
    (filter #(str/starts-with? (name %) (name prefix)) all-ns)))


(defn compile-for-tests
  [_]
  ;; Compiling one at a time is required... for some reason.
  (doseq [nmspc (ns-under-prefix 'erp12.clark.core.aot ["src"])]
    (println "Compiling" nmspc)
    (b/compile-clj {:basis basis
                    :src-dirs ["src"]
                    :class-dir class-dir
                    :ns-compile [nmspc]}))
  (println "Compiled AOT namespaces.")
  ;; Compile everything else. Relies on the AOT classes already existing.
  (b/compile-clj {:basis basis
                  :src-dirs ["src" "test"]
                  :class-dir class-dir
                  :filter-nses ['erp12.clark.core]}))