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)

如果我通过

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

(hash来自官方Clojure博客文章这里 )启动REPL,然后我可以复制粘贴测试代码并得到预期的结果 - 它打印:[: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演示的一个技巧来安装它——如果你喜欢,你可以在自己的代码中也做类似的事情。

非常感谢您帮助 @alexmiller。您能推荐一个学习ClassLoaders和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
        "语法错误在/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]
    [user$eval4834 invokeStatic "add-lib-test.clj" 4]
    [user$eval4834 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}}
...