What's the difference between Cake and Leiningen?
相关问题
- Better Sequence Duplicate Remover
- Installation of Leiningen 2.X in Mac OS X
- Questions about Lists and other stuff in Clojure
- How do I add CORS to a compojure-api app?
- How do I use Clojure in Android Studio using Gracl
相关文章
- Factor Clojure code setting many different fields
- Does learning one Lisp help in learning the other?
- Better way to nest if-let in clojure
- Idiomatic approach for structuring Clojure source
- Is a “transparent” macrolet possible?
- Detect operating system in Clojure
- Using quote in Clojure
- Enums and Clojure
The main difference is in the way tasks are implemented.
Cake's approach is "it's hard to extend functions after they've been defined, so let's invent a new mechanism for tasks rather than use functions", which resulted in the deftask macro.
Leiningen's approach is "it's hard to extend functions after they've been defined, so we should make a way to do this easily; that way we can use functions for tasks and also be able to extend things that aren't tasks," which lets you apply all the composability advantages of functions with tasks.
This answer continues to get interest, presumably as a reference for Leiningen in StackOverflow so it is now significantly edited to update it for 2014.
Leiningen and Cake merged back in 2011. Leiningen (version 2) is now the de facto Clojure automation tool.
Leiningenis a build tool and dependency manager for Clojure which includes the ability to set up an interactive REPL with the appropriately configured classpath and with all java and clojure dependencies acquired in an automated manner from maven repositories and/or the community based Clojars.
Cake was very similar to Leiningen (down to using the same project.clj file format at the time) but attempted to avoid a lot of startup overhead by keeping persistent JVMs around in the background. This was more responsive but traded convenience for bugs due to accumulated state in the persistent processes (old function definitions hanging around etc.) over the typical course of iterative REPL based development. This turned out to be a bad bargain.
Experience with Leiningen and a continued desire for faster startup times have lead to an number of recommendations and approaches for speeding things up: https://github.com/technomancy/leiningen/wiki/Faster
As Alex mentioned, the most striking difference is speed from the command line. Cake uses a persistent JVM, so you only encounter the jvm startup overhead when you run a task within your project for the first time. If you are not using emacs + slime + clojure-test-mode, this can be a huge timesaver. For example, a reasonably large set of tests on one of my projects runs in 0.3 seconds in cake, vs 11.2s in lein.
Aside from performance, the core idea behind cake is the dependency task model. Each task is only run once in a given build, taking into account all transitive prerequisites in the dependency graph. Here's an example from Martin Fowler's article on rake in cake syntax, which goes directly in your project.clj.
To do the same in Leiningen, you would first have to create a leiningen directory in your project with 4 files: code_gen.clj, compile.clj, data_load.clj, and my_test.clj.
src/leiningen/code_gen.clj
src/leiningen/my_compile.clj
src/leiningen/data_load.clj
src/leiningen/my_test.clj
One would expect...
But both data-load and my-compile depend on code-gen, so your actual ouput is...
You would have to memoize code-gen to prevent it from being run multiple times:
output:
Which is what we want.
Builds are simpler and more efficient if a task is only ran once per build, so we made it the default behavior in cake builds. The philosophy is decades old and shared by a lineage of build tools. You can still use functions, you can still call them repeatedly, and you always have the full power of clojure at your disposal.
Lein just gives you a plain function as a task, but with the added constraint that it must have it's own namespace in src. If a task depends on it, it will be in a separate namespace, and must use/require the other in it's
ns
macro. Cake builds look much neater and concise in comparison.Another key difference is how tasks are appended to. Let's say we wanted to add
my-test
as prerequisite to cake/lein's built injar
task. In cake, you can use thedeftask
macro to append to a task's forms and dependencies.Lein uses Robert Hooke to append to tasks. It's a really cool library, named after everyone's favorite natural philospher, but it would require a macro for the conciseness of
deftask
.Cake also has the notion of a global project. You can add user specific dev-dependencies, like swank, to
~/.cake/project.clj
and have it across all of your projects. The global project is also used to start a repl outside of a project for experimentation. Lein implements similar features by supporting per-user configuration in~/.lein/init.clj
, and global plugins in~/.lein/plugins
. In general, Lein currently has a much richer plugin ecosystem than cake, but cake includes more tasks out of the box (war, deploy, java compilation, native dependencies, clojars, and swank). Cljr may also be worth checking out, it's essentially just a global project with a package manager, but without build capabilities (i have no experience with it however).The real irreconcible difference is task defintions, as technomancy pointed out. In my (biased) opinion, cake handles tasks much better. The need for a task dependency model became evident when we started using protocol buffers in our project with lein. Protobufs were pre-requisites for all of our tasks, yet compiling them is really slow. We also have alot of inter-dependent tasks, so any build was painful. I also don't like the requirement of a seperate namespace, and therefore an additional src file, for every task I create. Developers should create a lot tasks, lein's approach discourages this by creating too much friction. With cake, you can just use the deftask macro within project.clj.
Cake is still young, and a work in progress, but it's a very active project.
As 2011-11-15, the announcement of cake and lein merge