2024年 Clojure 状态调查!中分享你的想法。

欢迎!请查阅关于页面以了解有关此功能的更多信息。

0
编译器

在不了解的一些非常具体的场景下,AOT 编译器可能会创建一个有关于名为 thunk0__ 的字段的矛盾观点的类文件。

我在 https://github.com/ryfow/weird-aot 上创建了一个项目,该项目通过执行 lein run 来复现问题。

复现问题的要素似乎是 slf4j-timbre、tools.analyzer 和 core.async。

我怀疑 slf4j-timbre 虽然进行了ATT编译但没有由clojure代码直接加载可能是影响因素。

请注意,weird-aot 中的 timbre 版本与 slf4j-timbre 中编译的版本不同。

我不清楚为什么需要 tools.analyzer 和 core.async 来表现出这个问题。

以下是我在 weird-aot 项目上执行 lein run 时得到的堆栈跟踪。

`
主线程抛出异常 java.lang.NoSuchFieldError: thunk0__,编译:(/private/var/folders/2q/tk7cywk93217_d4pxn_5kft40000gn/T/form-init7490372454812250103.clj:1:125)

    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)

原因:java.lang.NoSuchFieldError: thunk0__

    at clojure.tools.analyzer.jvm.utils__init.load(Unknown Source)
    at clojure.tools.analyzer.jvm.utils__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:340)
    at clojure.lang.RT.classForName(RT.java:2154)
    at clojure.lang.RT.classForName(RT.java:2163)
    at clojure.lang.RT.loadClassForName(RT.java:2182)
    at clojure.lang.RT.load(RT.java:436)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:703)
    at clojure.tools.analyzer.jvm$loading__5340__auto____1677.invoke(jvm.clj:9)
    at clojure.tools.analyzer.jvm__init.load(Unknown Source)
    at clojure.tools.analyzer.jvm__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:340)
    at clojure.lang.RT.classForName(RT.java:2154)
    at clojure.lang.RT.classForName(RT.java:2163)
    at clojure.lang.RT.loadClassForName(RT.java:2182)
    at clojure.lang.RT.load(RT.java:436)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at weird_aot.core$loading__5340__auto____81.invoke(core.clj:1)
    at weird_aot.core__init.load(Unknown Source)
    at weird_aot.core__init.<clinit>(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:340)
    at clojure.lang.RT.classForName(RT.java:2154)
    at clojure.lang.RT.classForName(RT.java:2163)
    at clojure.lang.RT.loadClassForName(RT.java:2182)
    at clojure.lang.RT.load(RT.java:436)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at user$eval65$fn__67.invoke(form-init7490372454812250103.clj:1)
    at user$eval65.invoke(form-init7490372454812250103.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    ... 11 more

`

11 个答案

0

评论由:hiredman 提出

链接github仓库中的 run.sh 抛出

主线程抛出异常 java.lang.RuntimeException: 方法代码过大!,编译:(weird_aot/jetty.clj:4:1)

并无法编译所需的Java源文件

编辑它能够编译Java源文件,但不会为Clojure创建默认编译器输出目录或创建它

0

评论由:hiredman 提出

lein compile 对链接的 github 项目进行检出时,对我的编译过程没有出错。

0

评论由:hiredman 提出

稍微调整一下,许多依赖及其瞬时依赖似乎都被 AOT 编译了,这与我所知的预期不符。使用 Clojure 版本 A 编译的 aot 代码将无法与使用 Clojure 版本 B 编译的代码链接。

0

评论者:bronsa

我同意 Kevin 的说法。这个问题很可能是由于依赖项以 AOT 的形式分发并存在依赖冲突所引起的。

0

评论由:hiredman 提出

问题出在 com.fzakaria/slf4j-timbre "0.2.2" 上。这是一个 aot 编译的库,它间接地将其依赖项(老版本的很多 timbre 库)也进行了 aot 编译,这些依赖项反过来又依赖于旧版本的 tools.reader,因此 com.fzakaria/slf4j-timbre "0.2.2" 的 jar 包中含有 tools.reader 的旧编译版本。org.clojure/tools.analyzer.jvm "0.6.9" 是针对 tools.reader 的较新版本进行 aot 编译的,所以 everything explodes( všichni explodují)。

0

评论者:alexmiller

发布带有 AOT 依赖项的 jar 确实是一个问题。我明白这很痛苦,因为 CLJ-322(我希望在今年实际取得一些进展)。

这个条目需要做些什么其他的事情吗?

0

评论者:bronsa

我认为我们除了推动 CLJ-322 和不鼓励用户发布 AOT 编译的库之外没有其他可以做的事情。

0

评论者:ryfow

对我而言,问题出在错误信息上。虽然我不能依赖AOT编译的库,但这似乎并不合适。当我这样做时,错误信息是 "java.lang.NoSuchFieldError: thunk0__" 或 "java.lang.RuntimeException: Method code too large!"

0

评论者:alexmiller

我理解你的观点。不幸的是,我不确定有没有一种通用的方法可以检测这种情况,并生成更好的错误信息。在使用不同版本的库混合使用时,Java也会出现类似的问题。

0

评论者:aroemers

我不确定这个问题是由于拥有AOT编译库导致的(只)。我开始重新编写slf4j-timbre库的部分内容,以消除对AOT的需求(链接:1)。但我注意到,在编译期间,当 {{TimbreLoggerAdapter}} 加载 {{slf4j-timbre.adapter}} 命名空间(而不是 Clojure 命名空间)时,该问题仍然存在。因此,在编译期间执行任何 SLF4J 日志语句时,在运行结果时仍然会出现 __thunk__ 问题。

然而,一个解决方案是将 {{slf4j-timbre.adapter}} 命名空间作为 AOT 编译命名空间中的第一个之一来 {{require}}。这也适用于 slf4j-timbre 库的当前 AOT 编译版本。因此,解决这个问题的方法可能更多地与 AOT 编译期间通过 Java 类进行传输加载命名空间有关,而不是与 AOT 编译库本身有关?

(链接:1) https://github.com/hellodata-org/slf4j-timbre/blob/f9a2f4469fd92063c261276479593de39fffbee3/src-java/com/github/fzakaria/slf4j/TimbreLoggerAdapter.java

0
参考:https://clojure.atlassian.net/browse/CLJ-1886(由 ryfow 报告)
...