请在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__,编译:(私人文件夹/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 版本,这显然不是预期的行为。使用 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: 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编译命名空间中的第一个来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
by
参考: https://clojure.atlassian.net/browse/CLJ-1886(由ryfow报告)
...