请在 2024 Clojure 状态调查! 中分享您的看法。

欢迎!请参阅关于页面了解有关此内容的更多信息。

+1
tools.build

我在使用 tools.build 控制uberjar的构成内容时遇到了麻烦。在这种情况下,运行时环境(一个Spark集群)提供了一些依赖项,因此这些依赖项不应包含在uberjar中。假设我有两个类路径(用别名表示)

  • :compile 用于编译所需的全部依赖/类的类路径。

  • :uber 仅包含应包含在最终jar中依赖/类的类路径。

理论上,如果您从 :compile 类路径中减去 :uber 类路径,我们应该得到由运行时环境提供的类集。

考虑以下简化的依赖图

dep graph

我们只需要将蓝色的依赖项放入jar中。白颜色的“提供”依赖项在编译期间需要使用,但不应该包含在最终的uberjar中。

我查看了使用 compile-clj:filter-nses 选项,但它在临时依赖项上引起了一些问题。

  • 如果我们仅过滤 my.project,我们将失去 some.other/depsome.transient/dep 中的重要依赖项。
  • 如果我们过滤排除 org.apache(无法使用 :filter-nses 实现,但理论上可以),我们仍然会有 org.scala-lang/scala-library

我还尝试了在编译和jar构建过程中使用不同的 create-basis 调用。我不确定这是否合理。

是否能利用依赖图来控制1)被编译的内容或2)哪些类将被放入uberjar?非常感谢任何建议。

1 答案

+2

被选中
 
最佳答案

使用多次调用create-basis完全正确 —— 一个用于编译,另一个用于uberjar。

知道了这一点很好。有没有哪里记录了这样的例子?或许有一个知名的开源项目使用这个模式,我可以从中学习?

这个gist包含了我在使用多个基础时的尝试,但它抛出了我无法解释的异常
https://gist.github.com/erp12/7ea123fe4d623f61dcda94e3cbd03845#file-build-clj

有趣的是,根原因异常并不一致。以下是两个例子。
甚至更奇怪的是,即使`jar-basis`从未在任何入口函数中引用,这些异常也会发生。这似乎只是多次调用`create-basis`就导致了这些异常。

```
线程 "Thread-7" 中发生异常 java.lang.ExceptionInInitializerError
    在 clojure.tools.deps.alpha.util.S3TransporterFactory.triggerLoad(S3TransporterFactory.java:44)
    在 clojure.tools.deps.alpha.util.S3TransporterFactory.access$100(S3TransporterFactory.java:29)
    在 clojure.tools.deps.alpha.util.S3TransporterFactory$1.run(S3TransporterFactory.java:49)
    在 java.lang.Thread.run(Thread.java:748)
原因是:在 (clojure/tools/reader.clj:1:1) 处编译时出现语法错误。
    在 clojure.lang.Compiler.load(Compiler.java:7652)
    在 clojure.lang.RT.loadResourceScript(RT.java:381)
    ...
原因是:java.lang.IllegalAccessError: indexing-reader? does not exist
    在 clojure.core$refer.invokeStatic(core.clj:4237)
    在 clojure.core$refer.doInvoke(core.clj:4205)
```

另一个错误版本。

```
线程 "Thread-7" 中发生异常 java.lang.ExceptionInInitializerError
    在 clojure.tools.deps.alpha.util.S3TransporterFactory.triggerLoad(S3TransporterFactory.java:44)
    在 clojure.tools.deps.alpha.util.S3TransporterFactory.access$100(S3TransporterFactory.java:29)
    在 clojure.tools.deps.alpha.util.S3TransporterFactory$1.run(S3TransporterFactory.java:49)
    在 java.lang.Thread.run(Thread.java:748)
原因是:在 (clojure/tools/reader/reader_types.clj:1:1) 处编译时出现语法错误。
    在 clojure.lang.Compiler.load(Compiler.java:7652)
    在 clojure.lang.RT.loadResourceScript(RT.java:381)
    ...
原因是:java.lang.IllegalAccessError: whitespace? does not exist
    在 clojure.core$refer.invokeStatic(core.clj:4237)
    在 clojure.core$refer.doInvoke(core.clj:4205)
```
这是代码加载上的竞争条件。

调用 create-basis 最终会导致 Maven 代码孵化另一个线程,如果尚未加载,则最终会加载一些代码。这种代码加载与其他在 build.clj 中发生的代码加载竞争,导致这些错误。

如果您在 build.clj 的顶部要求命名空间 clojure.tools.deps.alpha.util.s3-transporter,它应该预加载代码并消除竞争。但这会使您的脚本启动变慢。
by
感谢对问题的解释!这对我的帮助非常大。
by
还遇到了与 https://github.com/clj-easy/graal-build-time 的竞争条件。
by
在这里的加载竞争条件应该在 tools.build 的最新版本中得到修复。
...