请在 2024 年 Clojure 状态调查!分享您的想法。

欢迎!请访问关于页面了解更多关于如何使用本站的信息。

0
编译器

在某种我并不理解的非常具体的情况下,AOT 编译器可能会创建出对名为 thunk0__ 的字段理解不一致的类文件。

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

复现这个问题所需的要素似乎包括 slf4j-timbre、tools.analyzer 和 core.async。

我认为 slf4j-timbre 被 AOT 编译但未直接由 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

使用链接 GitHub 项目的 lein compile 命令对我而言会在无错误的情况下完成。

0

评论者:hiredman

稍作调整,许多依赖及其瞬时依赖似乎已被AOT编译,可能使用了Clojure的不同版本,这并不符合我的预期。使用Clojure版本A编译的代码可能会与使用Clojure版本B编译的代码链接失败

0

评论者:bronsa

我同意Kevin的观点。这个问题极可能是由依赖被分布式AOT和依赖冲突引起的。

0

评论者:hiredman

com.fzakaria/slf4j-timbre "0.2.2" 是问题所在。该库被AOT编译,并且递归地AOT编译了其依赖项,而这些依赖项是timbre库的旧版本,它们反过来又依赖于旧版本的 tools.reader,因此 com.fzakaria/slf4j-timbre "0.2.2" 的jar包包含 tools.reader 的旧编译版本。org.clojure/tools.analyzer.jvm "0.6.9" 是针对新的工具.reader版本进行AOT编译的,所以导致一切崩溃

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编译过程中的命名空间 increíblemente transitivo加载,而不是关于AOT编译库本身?

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

0
...