请在 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

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

(哈希来自官方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 投票

FYI,那个版本的add-lib现在相当老了,可能不会与当前的clojure CLI很好地工作。您可能可以从https://github.com/seancorfield/dot-clojure/blob/develop/deps.edn#L202-L228 中改编最新版本。

这种东西的工作原理是沿着类加载器结构向上查找动态类加载器,然后使用其中的设施将新的jar包添加到类加载器中。要实现这一点,您实际上需要拥有可用的DynamicClassLoader,这在您能加载和运行Clojure代码的任何方式中并不一定成立。您可以通过上面的链接看到Sean使用的技巧来安装它——如果您愿意,在自己的代码中也可以使用类似的技巧。

by
非常感谢您尝试帮助@alexmiller。您能推荐一些地方来学习关于类加载器和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中使用时能正常工作,但通过文件则不行。尽管如此,它现在已经前进了一步 :) 我猜ClassLoader仍存在问题,或者非REPL的类路径有问题(另一个我不是很清楚的概念)。

    {:clojure.main/message
    "语法错误(FileNotFoundException)编译时出错于(add-lib-test.clj:4:1)。\n无法在类路径上找到thi/ng/geom/svg/core__init.class,thi/ng/geom/svg/core.clj 或 thi/ng/geom/svg/core.cljc,\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 加载 "RT.java" 424]
    [clojure.core$load$fn__6839 调用 "core.clj" 6126]
    [clojure.core$load invokeStatic "core.clj" 6125]
    [clojure.core$load doInvoke "core.clj" 6109]
    [clojure.lang.RestFn 调用 "RestFn.java" 408]
    [clojure.core$load_one invokeStatic "core.clj" 5908]
    [clojure.core$load_one 调用 "core.clj" 5903]
    [clojure.core$load_lib$fn__6780 调用 "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 调用 "RestFn.java" 408]
    [user$eval4834 invokeStatic "add-lib-test.clj" 4]
    [user$eval4834 调用 "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 调用 "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}}
...