请在2024年Clojure状况调查中分享您的想法!

欢迎!请参阅关于页面了解更多该工作的相关信息。

+1
tools.build

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

  • :compile 编译所需的依赖和类的类路径。

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

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

考虑以下简化的依赖图

dep graph

我们只需要将蓝色的依赖放到jar中。白色的"provided"依赖需要在编译时使用,但不应该包含在最终的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
by
被选中 by
 
最佳回答

使用多个调用create-basis是正确的做法 - 一个用于编译,一个用于uberjar。

by
知道了就好。有没有文档记录了这种方法?或者有没有使用这种模式的开源项目,我可以从中阅读呢?

此代码段包含我尝试使用多个bases的尝试,但它抛出了我无法解释的异常。
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? 不存在
    在 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? 不存在
    在 clojure.core$refer.invokeStatic(core.clj:4237)
    在 clojure.core$refer.doInvoke(core.clj:4205)
```
by
这是代码加载上的竞态条件。

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

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