我试图了解创建uberjar时的“ Lieningen”行为。以下是再现行为的最小示例:

(ns my-stuff.core
  (:gen-class))

(def some-var (throw (Exception. "boom!")))

(defn -main [& args]
  (println some-var))


当使用lein run执行此操作时,显然会失败,并显示Exception。但是,我不明白为什么执行lein uberjar也会因变量定义的异常而失败?为什么执行lein uberjar会尝试评估变量值?这对uberjar任务是否特定,或者我是否缺少有关Clojure或Leiningen的实质性内容?

最佳答案

为了为uberjar编译名称空间(如果已打开AOT),clojure编译器必须加载名称空间。这将始终调用所有顶级副作用。

解决此问题的最佳方法是永远不要在顶级代码中产生副作用(无论是在def表单内还是在外部),并具有初始化功能以实现所需的任何启动副作用。

一种解决方法是创建一个小的自定义名称空间,该名称空间使用自省功能在运行时而不是在编译时加载其余代码-使用如下函数:

(defn -main
  []
  (require 'my.primary.ns)
  ((resolve 'my.primary.ns/start)))


如果该名称空间已编译,则jvm可以找到-main并运行它,尽管您的其他代码均未编译。运行时require将导致Clojure编译器仅在运行时加载其余代码,并且需要resolve以便-main可以干净地编译-它返回引用的var,然后在调用时调用您的函数。

10-01 17:15