请在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 源代码

EDIT 它确实编译了 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"。这个库被先期优化编译,它会递归地先期优化编译其依赖项,而这些依赖项是老版本的timbre库,它们反过来又依赖于旧版本的 tools.reader,因此 com.fzakaria/slf4j-timbre "0.2.2" 的jar包含了旧的 tools.reader 编译版本。org.clojure/tools.analyzer.jvm "0.6.9" 使用更新的版本 tools.reader 进行先期优化编译,所以一切都会崩溃:

0投票

评论者:alexmiller

发布包含先期优化编译依赖的jar一定是个问题。我意识到了由于 CLJ-322(我希望能在这方面取得一些进展)而导致的痛苦。

关于这个工单是否还有其他需要做的事情吗?

0投票

评论者:bronsa

我认为我们除了推进 CLJ-322 和不建议用户发布先期优化编译的库之外,别无他法。

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日志语句时,运行结果 still ensued when running the result。

但是,一个解决办法是在AOT编译的命名空间中_cols>将{{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投票
...