请在2024年Clojure状态调查中分享您的看法!

欢迎!请参阅《关于》页面了解更多关于如何使用此功能的信息。

0
Clojure

我在尝试为 clojure 编写一个新的“文学作品模式”的过程中遇到了难题

我基本上只想在子模式中启动 clj,然后从代码块中输入代码。我试图利用 add-lib 在文学作品块中动态添加库(并避免整个 deps.edn 项目结构)。然而,我遇到了奇怪的问题

这是我的测试代码

(use 'clojure.tools.deps.alpha.repl)
(add-lib 'thi.ng/geom {:mvn/version "1.0.0-RC4"})
(require `thi.ng.geom.svg.core)
(thi.ng.geom.svg.core/circle [0 1] 6)

如果我用以下(repl)启动repl

clj -Sdeps '{:deps {org.clojure/tools.deps.alpha {:git/url "https://github.com/clojure/tools.deps.alpha.git" :sha "d492e97259c013ba401c5238842cd3445839d020"}}}'

hash 来自官方 Clojure 博客文章此处 ) 然后我可以复制粘贴测试代码并得到期望的结果 - 它打印:[:circle {:cx "0.00", :cy "1.00", :r 6}]

然而,如果我用相同的代码通过中间文件 add-lib-test.clj

clj -Sdeps '{:deps {org.clojure/tools.deps.alpha {:git/url "https://github.com/clojure/tools.deps.alpha.git" :sha "d492e97259c013ba401c5238842cd3445839d020"}}}'  add-lib-test.clj 

那么它就会崩溃

WARNING: When invoking clojure.main, use -M
Syntax error (IllegalAccessError) compiling at (add-lib-test.clj:2:1).
Context classloader is not a DynamicClassLoader

Full report at:
/tmp/clojure-1788839394237911817.edn

geokon@ux305-kde:~$ cat /tmp/clojure-1788839394237911817.edn
{:clojure.main/message
 "Syntax error (IllegalAccessError) compiling at (add-lib-test.clj:2:1).\nContext classloader is not a DynamicClassLoader\n",
 :clojure.main/triage
 {:clojure.error/phase :compile-syntax-check,
  :clojure.error/line 2,
  :clojure.error/column 1,
  :clojure.error/source "add-lib-test.clj",
  :clojure.error/path "add-lib-test.clj",
  :clojure.error/class java.lang.IllegalAccessError,
  :clojure.error/cause
  "Context classloader is not a DynamicClassLoader"},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.Compiler$CompilerException,
    :message
    "Syntax error compiling at (/home/geokon/add-lib-test.clj:2:1).",
    :data
    {:clojure.error/phase :compile-syntax-check,
     :clojure.error/line 2,
     :clojure.error/column 1,
     :clojure.error/source "/home/geokon/add-lib-test.clj"},
    :at [clojure.lang.Compiler load "Compiler.java" 7648]}
   {:type java.lang.IllegalAccessError,
    :message "Context classloader is not a DynamicClassLoader",
    :at
    [clojure.tools.deps.alpha.repl$add_loader_url
     invokeStatic
     "repl.clj"
     32]}],
  :trace
  [[clojure.tools.deps.alpha.repl$add_loader_url
    invokeStatic
    "repl.clj"
    32]
   [clojure.tools.deps.alpha.repl$add_loader_url invoke "repl.clj" 22]
   [clojure.core$run_BANG_$fn__8790 invoke "core.clj" 7715]
   [clojure.lang.ArrayChunk reduce "ArrayChunk.java" 58]
   [clojure.core.protocols$fn__8154 invokeStatic "protocols.clj" 136]
   [clojure.core.protocols$fn__8154 invoke "protocols.clj" 124]
   [clojure.core.protocols$fn__8114$G__8109__8123
    invoke
    "protocols.clj"
    19]
   [clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 31]
   [clojure.core.protocols$fn__8146 invokeStatic "protocols.clj" 75]
   [clojure.core.protocols$fn__8146 invoke "protocols.clj" 75]
   [clojure.core.protocols$fn__8088$G__8083__8101
    invoke
    "protocols.clj"
    13]
   [clojure.core$reduce invokeStatic "core.clj" 6828]
   [clojure.core$run_BANG_ invokeStatic "core.clj" 7710]
   [clojure.core$run_BANG_ invoke "core.clj" 7710]
   [clojure.tools.deps.alpha.repl$add_lib invokeStatic "repl.clj" 58]
   [clojure.tools.deps.alpha.repl$add_lib invoke "repl.clj" 35]
   [clojure.tools.deps.alpha.repl$add_lib invokeStatic "repl.clj" 48]
   [clojure.tools.deps.alpha.repl$add_lib invoke "repl.clj" 35]
   [user$eval796 invokeStatic "add-lib-test.clj" 2]
   [user$eval796 invoke "add-lib-test.clj" 2]
   [clojure.lang.Compiler eval "Compiler.java" 7177]
   [clojure.lang.Compiler load "Compiler.java" 7636]
   [clojure.lang.Compiler loadFile "Compiler.java" 7574]
   [clojure.main$load_script invokeStatic "main.clj" 475]
   [clojure.main$script_opt invokeStatic "main.clj" 535]
   [clojure.main$script_opt invoke "main.clj" 530]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.main main "main.java" 40]],
  :cause "Context classloader is not a DynamicClassLoader",
  :phase :compile-syntax-check}}

我对JVM的了解还不够,无法理解这个错误。它看起来像是在尝试编译文件 - 这与 add-lib 不相适应。有没有办法让 clj 评估而不编译?

1 答案

+1

顺便说一下,那个版本的 add-lib 现在已经很老了,并且不太可能很好地与当前的 clojure CLI 一起工作。你可能会从https://github.com/seancorfield/dot-clojure/blob/develop/deps.edn#L202-L228 中汲取最新内容。

这个技术的工作原理是沿着类加载器结构向上查找DynamicClassLoader,然后使用该类加载器提供的功能向类加载器中添加新的JAR包。要使这样做有效,实际上您必须能够访问到DynamicClassLoader,这在您加载和运行Clojure代码的每一种方法中并非总是存在的。您可以在上面的链接中看到Sean使用的技巧来安装它——如果您喜欢,您也可以在您自己的代码中实现类似的做法。

by
非常感谢你尝试帮助@alexmiller。你有没有推荐的地方可以去学习ClassLoader和相关JVM的背景知识?我很尴尬的是,我无法自己解决这个问题。

我已经修改了`add-test-lib.clj`,使其与`add-lib`的最新版本(现在已更名为`add-libs`)相兼容,并按照您提供的示例设置了`DynamicClassLoader`。

    (->>(Thread/currentThread)
        (.getContextClassLoader)
        (clojure.lang.DynamicClassLoader.)
        (.setContextClassLoader (Thread/currentThread)))

    (use 'clojure.tools.deps.alpha.repl)
    (add-libs {'thi.ng/geom {:mvn/version "1.0.0-RC4"}})
    (require `thi.ng.geom.svg.core)
    (thi.ng.geom.svg.core/circle [0 1] 6)

现在我已经用最新版本运行了

    clj -Sdeps '{:deps {org.clojure/tools.deps.alpha {:git/url "https://github.com/clojure/tools.deps.alpha.git :sha "241cd24c35ba770aea4773ea161d45276e5d3a73"}}}' add-lib-test.clj

同样,它在大纲中运行良好,但通过文件运行时却不行。不过情况已经有所改善 :) 我猜测类加载器仍然存在问题,或者文件的非REPL类路径(这是我稍微有些模糊的其他术语)存在错误。

    {:clojure.main/message
    "Syntax error (FileNotFoundException) compiling at (add-lib-test.clj:4:1).\nCould not locate thi/ng/geom/svg/core__init.class, thi/ng/geom/svg/core.clj or thi/ng/geom/svg/core.cljc on classpath.\n",
    :clojure.main/triage
    {:clojure.error/phase :compile-syntax-check,
    :clojure.error/line 4,
    :clojure.error/column 1,
    :clojure.error/source "add-lib-test.clj",
    :clojure.error/path "add-lib-test.clj",
    :clojure.error/class java.io.FileNotFoundException,
    :clojure.error/cause
    "Could not locate thi/ng/geom/svg/core__init.class, thi/ng/geom/svg/core.clj or thi/ng/geom/svg/core.cljc on classpath."},
    :clojure.main/trace
    {:via
    [{:type clojure.lang.Compiler$CompilerException,
        :message
        "Syntax error compiling at (/home/geokon/add-lib-test.clj:4:1).",
        :data
        {:clojure.error/phase :compile-syntax-check,
        :clojure.error/line 4,
        :clojure.error/column 1,
        :clojure.error/source "/home/geokon/add-lib-test.clj"},
        :at [clojure.lang.Compiler load "Compiler.java" 7648]}
    {:type java.io.FileNotFoundException,
        :message
        "Could not locate thi/ng/geom/svg/core__init.class, thi/ng/geom/svg/core.clj or thi/ng/geom/svg/core.cljc on classpath.",
        :at [clojure.lang.RT load "RT.java" 462]}],
    :trace
    [[clojure.lang.RT load "RT.java" 462]
    [clojure.lang.RT load "RT.java" 424]
    [clojure.core$load$fn__6839 invoke "core.clj" 6126]
    [clojure.core$load invokeStatic "core.clj" 6125]
    [clojure.core$load doInvoke "core.clj" 6109]
    [clojure.lang.RestFn invoke "RestFn.java" 408]
    [clojure.core$load_one invokeStatic "core.clj" 5908]
    [clojure.core$load_one invoke "core.clj" 5903]
    [clojure.core$load_lib$fn__6780 invoke "core.clj" 5948]
    [clojure.core$load_lib invokeStatic "core.clj" 5947]
    [clojure.core$load_lib doInvoke "core.clj" 5928]
    [clojure.lang.RestFn applyTo "RestFn.java" 142]
    [clojure.core$apply invokeStatic "core.clj" 667]
    [clojure.core$load_libs invokeStatic "core.clj" 5985]
    [clojure.core$load_libs doInvoke "core.clj" 5969]
    [clojure.lang.RestFn applyTo "RestFn.java" 137]
    [clojure.core$apply invokeStatic "core.clj" 667]
    [clojure.core$require invokeStatic "core.clj" 6007]
    [clojure.core$require doInvoke "core.clj" 6007]
    [clojure.lang.RestFn invoke "RestFn.java" 408]
    [用户$评估4834 invokeStatic "add-lib-test.clj" 4]
    [用户$评估4834 invoke "add-lib-test.clj" 4]
    [clojure.lang.Compiler eval "Compiler.java" 7177]
    [clojure.lang.Compiler load "Compiler.java" 7636]
    [clojure.lang.Compiler loadFile "Compiler.java" 7574]
    [clojure.main$load_script invokeStatic "main.clj" 475]
    [clojure.main$script_opt invokeStatic "main.clj" 535]
    [clojure.main$script_opt invoke "main.clj" 530]
    [clojure.main$main invokeStatic "main.clj" 664]
    [clojure.main$main doInvoke "main.clj" 616]
    [clojure.lang.RestFn applyTo "RestFn.java" 137]
    [clojure.lang Var applyTo "Var.java" 705]
    [clojure.main main "main.java" 40]],
    :cause
    "无法在类路径中找到 thi/ng/geom/svg/core__init.class, thi/ng/geom/svg/core.clj 或 thi/ng/geom/svg/core.cljc。",
    :phase :compile-syntax-check}}
...