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

How to compile all source and tests before running -M or -X from deps.edn?

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

以下是我的 deps.edn 的简化版本。我发现在每次测试 运行 之前编译一些代码的唯一方法是向 :main-opts 添加一个 -e (compile,'my.project.namespace) 对。这需要了解需要编译的确切名称空间,这些名称空间在开发过程中会定期更改。即使是单元测试中的简单实验也可能需要对 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

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

似乎是最好的方向。考虑到 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 classes 作为 Java class 导入) .

此外,那些 :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]}))