为什么`lein uberjar`计算用`def`定义的变量?

为什么`lein uberjar`计算用`def`定义的变量?

问题描述:

我想要了解创建 uberjar 时的Lieningen行为。以下是重现行为的最小示例:

I'm trying to understand "Lieningen" behaviour when creating an uberjar. Following is the minimal example which reproduces the behaviour:

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

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

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



当使用 lein run 它明显失败与异常。但是,我不明白为什么执行 lein uberjar 也失败,从变量定义的异常?为什么执行 lein uberjar 尝试评估变量值?这是特定于 uberjar 任务或者我缺少一些更重要的Clojure或Leiningen的东西?

When this is executed with lein run it clearly fails with an Exception. However, I don't understand why executing lein uberjar also fails with an Exception from variable definition? Why executing lein uberjar attempts to evaluate the variable value? Is this speecific to uberjar task or am I missing something more substantial about Clojure or Leiningen?

为了编译uberjar的命名空间(如果你打开了AOT),clojure编译器必须加载你的命名空间。

In order to compile your namespace for the uberjar (if you have AOT turned on), the clojure compiler must load your namespace. This will always invoke all top-level side effects.

处理这个问题的最好办法是在*代码中不要有副作用(无论是内部还是外部) c $ c> def 表单),并且具有初始化函数来实现任何所需的启动副作用。

The best way to handle this is to never have side effects in top level code (whether inside or outside a def form), and have initialization functions to realize any start-up side effects needed.

一个解决方法可以是make一个小的命名空间,使用内省在运行时加载代码的其余部分,但是在编译时不使用这样的函数:

A workaround can be to make a small namespace that uses introspection to load the rest of your code at runtime but not while compiling - using a function like this:

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

如果编译的命名空间,jvm可以找到-main并运行它,尽管没有你的其他代码编译。运行时 require 将使Clojure编译器仅在运行时加载其余代码,需要 resolve -main 将编译干净 - 它返回var引用,然后在调用时调用您的函数。

if that namespace is compiled, the jvm can find -main and run it, despite none of your other code being compiled. The runtime require will cause the Clojure compiler to load the rest of your code at runtime only, and resolve is needed so that -main will compile cleanly - it returns the var referenced, which then invokes your function when called.