我是 Clojure 新手,正开始尝试构建应用程序。
到目前为止,我所看到的有关编译 Clojure 程序的教程的所有内容都涉及交互性。例如,“加载 REPL 并键入 (load-file "this-or-that") 以运行。这很好,但还不够。
我已经习惯了 C 或 Delphi 等语言的编辑-编译-运行习惯用法,以至于我本能地被驱使进行编辑,然后点击“M-x 编译”。
问题是“lein uberjar”,据我所知等同于“make”,即使对于 hello world,执行起来也非常缓慢。所以我将不得不弄清楚这个“交互式开发”的东西是如何工作的,停止使用 uberjar 就像它是快速制作的一样,并且只在一天结束时保存它。
我在构建(使用 lein uberjar)时注意到的另一件事是我正在处理的小型 GUI 应用程序在编译过程中弹出框架,就好像它们在编译时正在执行一样。这对我来说似乎有点违反直觉;它不像我想象的那样类似于“make”。
我知道 Lisp 的开发方式是在 REPL 中交互工作,我不想改变它:我想适应这种生活方式。不幸的是,我几乎没有看到关于如何这样做的文档形式。例如,如何重置机器的当前状态。在无法进行某种重置的情况下不断编译单个片段似乎有点困惑。
我看到的大多数关于 Clojure(和 Lisp)的教程似乎都集中在 REPL 中的黑客攻击。应用程序部署的最佳实践对我来说仍然是个谜。我的用户将成为用户;他们不会成为将文件加载到 REPL 中的开发人员。
所以这是我的问题:关于构建 Clojure 应用程序(包括部署)的整个过程的有用信息或教程的任何资源?
(注意:我已经安装并运行了所有先决条件(例如 Emacs、Slime、Leiningen 等),所以这不是问题)。
最佳答案
几个快速提示,然后是一些链接:
在开发过程中不要使用lein uberjar
;更喜欢 lein jar
。不同之处在于 lein uberjar
将所有依赖项放入生成的 jar
中(包括 Clojure 本身),因此您的单个 jar 是一个完全独立的包,其中包含您的应用程序; lein jar
只打包你自己的代码。 uberjar
方法对于部署有明显的好处,但对于开发,您应该能够在运行应用程序时使用适当的类路径,从而节省准备 uberjar 所需的时间。如果您不想手动管理测试运行的类路径,请查看 lein run
plugin .
此外,您的大部分代码很可能实际上不应该进行 AOT 编译。在某些 Java 互操作场景中,AOT 是必需的,但大多数情况下,它会略微提高启动速度和与不同版本的 Clojure 二进制兼容性的恼人问题。我想后一个问题与 uberjar
编辑的独立应用程序类型的项目无关,但如果可能的话,任何库代码至少应该保留为 JIT 编辑。使用 Leiningen,您可以在 project.clj
的 defproject
形式中放置一个 :namespaces
子句来确定要编译哪些 namespace ;默认情况下,您遗漏的任何内容目前都将进行 JIT 处理。旧版本的 Leiningen 过去默认编译所有内容,这实际上是升级的好理由!
至于在编译期间弹出的窗口,我猜测您要么在宏扩展期间运行弹出窗口的代码,要么在任何函数定义或类似构造之外运行。 (类似于顶层的 (println "Foo!")
。)我想这只是你不应该做的事情——除非你打算将你的代码作为脚本运行,无论如何.为避免该问题,将有副作用的代码包装在函数定义中,并使用 project.clj
中的 :main
子句为您的应用程序提供入口点。 (如果你说 :main foo
,那么来自 foo
命名空间的 -main
函数将被用作你的应用程序的入口点。那是无论如何,默认值,至少上面提到的 lein run
似乎有硬编码的名称——不确定 lein 本身。)
至于重置 REPL 的状态——你可以重启它。使用 SLIME,M-x slime-restart-inferior-lisp 将在保持 Emacs session 的所有其他状态的同时做到这一点。
另请参阅 Clojure Google 群组中的这些讨论:
关于deployment - 构建和部署 Clojure 应用程序的最佳实践 : good tutorials?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2391711/