问题描述
我的项目有一些需要 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.build
:https://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]}))