Leiningen为什么不能总是使用我的:gen-class呢?

Sam*_*tep 5 clojure gen-class leiningen

假设我创建了一个新的Leiningen项目(lein new app example)并添加了一些代码,example/src/example/core.clj其中使用了:gen-class:

(ns example.core
  (:gen-class :extends javafx.application.Application))

(defn -start [this stage]
  (.show stage))

(defn -main [& args]
  (javafx.application.Application/launch example.core args))
Run Code Online (Sandbox Code Playgroud)

如果我然后创建一个JAR(lein uberjar)并运行它,一切正常.但是,如果我试着直接运行我的应用程序(lein run),我会得到一个ClassNotFoundException.另外,如果我打开一个REPL(lein repl),我首先得到与以前相同的错误,但在运行此代码后:

(compile 'example.core)
Run Code Online (Sandbox Code Playgroud)

错误不再出现在lein run 或中 lein repl.

有人可以向我解释这里到底发生了什么,以及如何直接运行我的应用程序而无需从REPL手动编译我的代码?

编辑:在多了一点之后,我发现这个问题的解决方案是添加

:aot [example.core]
Run Code Online (Sandbox Code Playgroud)

project.clj.(感谢@Mars!)我仍然感到困惑,因为我之前尝试过简单地删除^:skip-aot,(根据文档)应该工作:

这将是AOT默认编译; 要禁用此功能,请将^:skip-aot元数据附加 到命名空间符号.

但事实并非如此.为什么?

另一个编辑(如果我将其中任何一个分成一个单独的问题,让我知道,我会这样做):我一直在玩连字符(lein new app my-example),并且发生了奇怪的事情.这不起作用:

(ns my-example.core
  (:gen-class :extends javafx.application.Application))
;; ...
(defn -main [& args]
  (javafx.application.Application/launch my-example.core args))
Run Code Online (Sandbox Code Playgroud)

但这样做:

(ns my-example.core
  (:gen-class
    :name my-example.Core
    :extends javafx.application.Application))
;; ...
(defn -main [& args]
  (javafx.application.Application/launch my-example.Core args))
Run Code Online (Sandbox Code Playgroud)

所以我的类名可以以小写字母(example.core)开头,也可以包含连字符(my-example.Core),但不能同时包含?我真的不明白.

最后,lein uberjar失败的最后一个例子(显式:name),因为

Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method.
Run Code Online (Sandbox Code Playgroud)

据我所知,解决这个问题的唯一方法是将Application子类拆分为一个单独的命名空间.还有另外一种方法吗?

tun*_*ngd 3

同意@Mars,问题是lein run不AOTexample.core命名空间。默认的 Leiningen 模板成为example.core非 AOT:

(defproject example "0.1.0-SNAPSHOT"
  ...
  :main ^:skip-aot example.core
  ...)
Run Code Online (Sandbox Code Playgroud)

我最好的猜测是,您可以使用它来定义您的应用程序defrecord并将其用作类而不是命名空间。

  • 摘自[这些注释](https://github.com/mars0i/majure/blob/master/doc/ClojureMASONinteropTips.md):“在 Clojure 中创建类有五种方法:`defrecord`、`deftype`、` reify`、`proxy`、`gen-class`...所有五个类创建宏都允许实现接口。但只有 `proxy` 和 `gen-class` 允许您扩展类...`proxy ` 可能是五种方法中最慢的,因为它使用额外的间接级别来执行方法,并且在很多方面比 `gen-class` 受到更多限制。” 尝试弄乱 project.clj 中的 `:aot` 规范。 (3认同)