51

蛋糕和莱宁根有什么区别?

4

4 回答 4

48

这个答案继续引起人们的兴趣,大概是作为 StackOverflow 中 Leiningen 的参考,因此现在对其进行了重大编辑以在 2014 年对其进行更新。

Leiningen 和 Cake 于 2011 年合并。Leiningen(第 2 版)现在是事实上的 Clojure 自动化工具。

Leiningen是 Clojure 的构建工具和依赖项管理器,其中包括使用适当配置的类路径以及从 maven 存储库和/或基于社区的Clojars以自动方式获取的所有 java 和 clojure 依赖项设置交互式 REPL 的能力。

Cake 与 Leiningen 非常相似(当时使用相同的 project.clj 文件格式),但试图通过在后台保留持久性 JVM 来避免大量启动开销。在基于 REPL 的迭代开发的典型过程中,由于持久过程中的累积状态(旧的函数定义等),这反应更快,但以方便换取错误。事实证明这是一笔糟糕的交易。

Leiningen 的经验和对更快启动时间的持续渴望导致了许多加快速度的建议和方法:https ://github.com/technomancy/leiningen/wiki/Faster

于 2010-10-11T14:27:53.813 回答
24

主要区别在于执行任务的方式。

Cake 的方法是“函数定义后很难扩展,所以让我们为任务发明一种新机制而不是使用函数”,这导致了 deftask 宏。

Leiningen 的方法是“函数定义后很难扩展,所以我们应该找到一种方法来轻松地做到这一点;这样我们就可以将函数用于任务,也可以扩展非任务的东西”,让您可以将函数的所有可组合性优势应用于任务。

于 2010-10-11T16:30:18.637 回答
20

正如亚历克斯所提到的,最显着的区别是命令行的速度。Cake 使用持久的 JVM,因此只有在您第一次在项目中运行任务时才会遇到 jvm 启动开销。如果您不使用 emacs + slime + clojure-test-mode,这可以节省大量时间。例如,我的一个项目的一组相当大的测试在 cake 中运行时间为 0.3 秒,而在 lein 中为 11.2 秒。

除了性能,cake 背后的核心思想是依赖任务模型。每个任务在给定的构建中只运行一次,考虑到依赖图中的所有传递先决条件。这是Martin Fowler 关于蛋糕语法 rake 的文章中的一个示例,该示例直接位于您的 project.clj 中。

(deftask code-gen
  "This task generates code. It has no dependencies."
  (println "generating code...")
  ...)

(deftask compile #{code-gen}
  "This task does the compilation. It depends on code-gen."
  (println "compiling...")
  ...)

(deftask data-load #{code-gen}
  "This task loads the test data. It depends on code-gen."
  (println "loading test data...")
  ...)

(deftask test #{compile data-load}
  "This task runs the tests. It depends on compile and data-load."
  (println "running tests...")
  ...)

要在 Leiningen 中执行相同操作,您首先必须在项目中创建一个包含 4 个文件的 leiningen 目录:code_gen.clj、compile.clj、data_load.clj 和 my_test.clj。

src/leiningen/code_gen.clj

(ns leiningen.code-gen
   "This task generates code. It has no dependencies.")

(defn code-gen []
  (println "generating code..."))

src/leiningen/my_compile.clj

(ns leiningen.my-compile
  "This task does the compilation. It depends on code-gen."
  (:use [leiningen.code-gen]))

(defn my-compile []
  (code-gen)
  (println "compiling..."))

src/leiningen/data_load.clj

(ns leiningen.data-load
  "This task loads the test data. It depends on code-gen."
  (:use [leiningen.code-gen]))

(defn data-load []
  (code-gen)
  (println "loading test data..."))

src/leiningen/my_test.clj

(ns leiningen.my-test
  "This task runs the tests. It depends on compile and data-load."
  (:use [leiningen.my-compile]
        [leiningen.data-load]))

(defn my-test []
  (my-compile)
  (data-load)
  (println "running tests..."))

人们会期望...

generating code...
compiling...
loading test data...
running tests...

但是数据加载和我的编译都依赖于代码生成,所以你的实际输出是......

generating code...
compiling...
generating code...
loading test data...
running tests...

您必须记住 code-gen 以防止它被多次运行:

(ns leiningen.code-gen
   "This task generates code. It has no dependencies.")

(def code-gen (memoize (fn []
                         (println "generating code..."))))

输出:

generating code...
compiling...
loading test data...
running tests...

这就是我们想要的。

如果每次构建只运行一次任务,构建会更简单、更高效,因此我们将其设置为蛋糕构建中的默认行为。这一理念已有数十年的历史,并为一系列构建工具所共有。您仍然可以使用函数,仍然可以重复调用它们,并且您始终拥有 clojure 的全部功能。

Lein 只是为您提供了一个简单的函数作为任务,但附加的约束是它必须在 src 中有自己的命名空间。如果一个任务依赖于它,它将在一个单独的命名空间中,并且必须在它的ns宏中使用/要求另一个。相比之下,Cake 的造型看起来更加整洁简洁。

另一个关键区别是如何附加任务。假设我们想将my-test作为先决条件添加到 cake/lein 的内置jar任务中。在 cake 中,您可以使用deftask宏附加到任务的表单和依赖项。

(deftask jar #{my-test})

Lein 使用 Robert Hooke 附加到任务。这是一个非常酷的库,以每个人最喜欢的自然哲学家的名字命名,但它需要一个宏来简化deftask.

(add-hook #'leiningen.jar/jar (fn [f & args]
                                (my-test)
                                (apply f args)))

Cake 还有一个全球项目的概念。您可以将用户特定的开发依赖项(如 swank)添加到~/.cake/project.clj您的所有项目中并使用它。全局项目还用于在项目之外启动 repl 以进行实验。Lein 通过支持 中的每个用户配置和 中的~/.lein/init.clj全局插件来实现类似的功能~/.lein/plugins。总的来说,Lein 目前拥有比 cake 更丰富的插件生态系统,但 cake 包含更多开箱即用的任务(war、deploy、java 编译、native dependencies、clojars 和 swank)。Cljr 也可能值得一试,它本质上只是一个带有包管理器的全球项目,但没有构建功能(但是我没有使用它的经验)。

正如技术专家指出的那样,真正不可调和的区别是任务定义。在我(有偏见的)看来,蛋糕处理任务要好得多。当我们开始在 lein 项目中使用协议缓冲区时,对任务依赖模型的需求变得很明显。Protobufs 是我们所有任务的先决条件,但编译它们真的很慢。我们还有很多相互依赖的任务,所以任何构建都是痛苦的。我也不喜欢我创建的每个任务都需要一个单独的命名空间,因此需要一个额外的 src 文件。开发人员应该创建很多任务,lein 的方法通过创建太多摩擦来阻止这种情况。使用 cake,您可以只使用 project.clj 中的 deftask 宏。

Cake 还很年轻,还在进行中,但它是一个非常活跃的项目。

于 2010-10-15T06:21:40.437 回答
7

2011-11-15, cake与lein合并的公告

于 2011-11-30T10:35:23.467 回答