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 时得到的堆栈跟踪。

`
线程 "main" 出现异常: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 抛出

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

并无法编译所需的 Java 源代码

编辑它确实编译了 Java 源代码,但没有创建 clojure 的默认编译器输出目录,也未创建

0

评论由:hiredman 制作

使用从链接的 GitHub 项目的检出编译 lein compile,对我来说没有错误地完成了

0

评论由:hiredman 制作

稍微改动了一下,很多依赖项及其临时依赖项似乎被 AOT 编译了,这很可能是使用不同版本的 Clojure 完成的,但据我所知,并非如此。使用 Clojure 版本 A 编译的 AOT 代码将无法与使用 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" 是针对 tools.reader 的一个较新版本进行 aot 编译的,因此一切都会崩溃

0

评论者:alexmiller

发布带有 AOT 依赖项的 jar 当然是个问题。我知道这有点痛苦,因为 CLJ-322(我希望今年能在这方面有所进展)。

这张票上还有什么需要做的吗?

0

评论者:bronsa

我认为我们除了推动 CLJ-322 和劝阻用户发布 AOT 编译库外,没有其他办法

0

评论由:ryfow 发布

对我来说,问题是错误信息。虽然我无法依赖AOT编译的库,但这似乎并不好,当我在做这个操作时,错误信息是"java.lang.NoSuchFieldError: thunk0__"或"java.lang.RuntimeException: 方法代码过大!"

0

评论者:alexmiller

我明白了。不幸的是,我不确定是否有任何通用的方法可以检测这种情况,并提供更好的错误信息。当混合使用库版本时,Java中也可能发生类似的问题。

0

评论由:aroemers 发布

我不确定问题是否仅仅是由于有AOT编译的库引起的。我开始重写slf4j-timbre库的部分,以减少对AOT的需求(链接:1)。但我在这个版本中注意到了问题,当{{TimbreLoggerAdapter}}在编译过程中加载{{slf4j-timbre.adapter}}命名空间,而不是Clojure命名空间时,问题仍然存在。因此,一旦在编译过程中执行SLF4J日志语句,在运行结果时仍然会触发__thunk__问题。

但是,一种解决方案是在AOT编译的命名空间中将{{slf4j-timbre(adapter)}}作为第一个之一。这在当前的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报告)
...