请在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" 是针对 tools.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投票
by

评论由:alexmiller

我理解你的意思。不幸的是,我不确定有没有办法以通用方式检测这种情况,并生成更好的错误消息。当使用不同版本的库混合时,在Java中也可能发生类似的问题。

0投票
by

评论者:aroemers

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

然而,一种解决方案是将{{slf4j-timbre.adapter}}命名空间作为AOT编译命名空间中第一个要求的之一。这也适用于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投票
by
...