Ale*_*ard 48
这个答案继续引起人们的兴趣,可能是作为Leiningen在StackOverflow中的参考,因此现在进行了大量编辑,以便在2014年更新它.
Leiningen和Cake于2011年合并.Leiningen(第2版)现在是事实上的Clojure自动化工具.
Leiningen是Clojure的构建工具和依赖管理器,它包括使用适当配置的类路径设置交互式REPL以及从maven存储库和/或基于社区的Clojars以自动方式获取的所有java和clojure依赖项的功能.
Cake与Leiningen非常相似(当时使用相同的project.clj文件格式)但是试图通过在后台保持持久的JVM来避免大量的启动开销.由于在基于REPL的迭代开发的典型过程中持久化过程中的累积状态(旧函数定义等),这更容易响应,但交易方便了.事实证明这是一个糟糕的交易.
Leiningen的经验以及对更快启动时间的持续渴望导致了许多建议和方法来加快速度:https://github.com/technomancy/leiningen/wiki/Faster
小智 24
主要区别在于任务的实施方式.
蛋糕的做法是"很难扩展功能,他们已经确定之后,让我们创造了任务的新机制,而不是使用的功能",这就造成了deftask宏.
Leiningen的做法是"很难,他们已经被定义后,延长的功能,所以我们应该做的方式轻松地做到这一点,这样我们就可以使用功能的任务,也能够延长事情是不是任务,"这让您将任务的所有可组合性优势应用于任务.
lan*_*ntz 20
正如亚历克斯所说,最显着的区别是来自命令行的速度.Cake使用持久性JVM,因此当您第一次在项目中运行任务时,您只会遇到jvm启动开销.如果你没有使用emacs + slime + clojure-test-mode,这可能会节省很多时间.例如,我的一个项目的一组相当大的测试在蛋糕中运行0.3秒,而在lein中运行11.2s.
除了性能之外,蛋糕背后的核心思想是依赖任务模型.每个任务仅在给定构建中运行一次,同时考虑依赖关系图中的所有传递先决条件.以下是Martin Fowler关于rake in cake语法的文章的示例,该文章直接在您的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...")
...)
Run Code Online (Sandbox Code Playgroud)
要在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..."))
Run Code Online (Sandbox Code Playgroud)
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..."))
Run Code Online (Sandbox Code Playgroud)
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..."))
Run Code Online (Sandbox Code Playgroud)
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..."))
Run Code Online (Sandbox Code Playgroud)
人们会期待......
generating code...
compiling...
loading test data...
running tests...
Run Code Online (Sandbox Code Playgroud)
但是数据加载和我的编译都依赖于代码生成,所以你的实际输出是......
generating code...
compiling...
generating code...
loading test data...
running tests...
Run Code Online (Sandbox Code Playgroud)
您必须记住代码生成以防止它多次运行:
(ns leiningen.code-gen
"This task generates code. It has no dependencies.")
(def code-gen (memoize (fn []
(println "generating code..."))))
Run Code Online (Sandbox Code Playgroud)
输出:
generating code...
compiling...
loading test data...
running tests...
Run Code Online (Sandbox Code Playgroud)
这就是我们想要的.
如果每个构建只运行一次任务,那么构建会更简单,更高效,因此我们将其作为蛋糕构建中的默认行为.这种理念已有数十年历史,并由一系列构建工具共享.您仍然可以使用功能,您仍然可以反复调用它们,并且您可以随时使用clojure的全部功能.
Lein只是给你一个简单的函数作为一个任务,但增加了约束,它必须在src中拥有它自己的命名空间.如果某个任务依赖于它,它将位于一个单独的命名空间中,并且必须在其ns
宏中使用/ require另一个.相比之下,蛋糕构建看起来更整洁,更简洁.
另一个关键区别是如何附加任务.假设我们想添加my-test
cake/lein内置jar
任务的先决条件.在蛋糕中,您可以使用deftask
宏附加到任务的表单和依赖项.
(deftask jar #{my-test})
Run Code Online (Sandbox Code Playgroud)
Lein使用Robert Hooke来执行任务.这是一个非常酷的图书馆,以每个人最喜欢的自然哲学家的名字命名,但它需要一个宏观的简洁deftask
.
(add-hook #'leiningen.jar/jar (fn [f & args]
(my-test)
(apply f args)))
Run Code Online (Sandbox Code Playgroud)
Cake也有全球项目的概念.您可以~/.cake/project.clj
在所有项目中添加特定于用户的开发依赖项(如swank)并将其包含在内.全局项目还用于在项目之外启动repl以进行实验.Lein通过支持每个用户的配置~/.lein/init.clj
和全局插件来实现类似的功能~/.lein/plugins
.一般来说,Lein目前拥有比蛋糕更丰富的插件生态系统,但蛋糕包含更多开箱即用的任务(war,deploy,java编译,本机依赖,clojars和swank).Cljr也值得一试,它本质上只是一个包管理器的全局项目,但没有构建功能(但我没有经验).
正如技术指出的那样,真正不可比拟的差异是任务定义.在我的(有偏见的)意见中,蛋糕处理任务要好得多.当我们在项目中使用lein开始使用协议缓冲区时,对任务依赖模型的需求变得明显.Protobufs是我们所有任务的先决条件,但编译它们的速度非常慢.我们还有很多相互依赖的任务,所以任何构建都很痛苦.对于我创建的每个任务,我也不喜欢单独命名空间的要求,因此也不喜欢另外的src文件.开发人员应该创建很多任务,lein的方法通过产生太多的摩擦来阻止这一点.使用cake,您可以在project.clj中使用deftask宏.
蛋糕还很年轻,正在进行中,但这是一个非常活跃的项目.