Skip to content

Latest commit

 

History

History
75 lines (58 loc) · 2.84 KB

8-01_aot-compilation.asciidoc

File metadata and controls

75 lines (58 loc) · 2.84 KB

AOT Compilation

by Luke VanderHart

Problem

You want to deliver your code as precompiled JVM bytecode in .class files, rather than as Clojure source code.

Solution

Use the :aot (ahead of time) compilation key in your project’s project.clj file to specify which namespaces should be compiled to .class files. The value of the :aot key is a vector of either symbols indicating specific namespaces to be compiled, or regular expression literals specifying that any namespace with a matching name should be compiled. Alternatively, instead of a vector, you can use the keyword :all as a value, which will AOT-compile every namespace in the project:

:aot [foo.bar foo.baz]

;; or...
:aot [#"foo\.b.+"] ; Compile all namespaces starting with "foo.b"

;; or...
:aot :all

Note that if your project has specified a :main namespace, Leiningen will AOT-compile it by default, regardless of whether it is present in an :aot directive.

Once your project is configured for AOT compilation, you can compile it by invoking lein compile at the command line. All emitted classes will be placed in the target/classes directory, unless you’ve overridden the output directory with the :target-path or :compile-path options.

Discussion

It’s important to understand that AOT compilation does not change how the code actually runs. It’s no faster or different. All Clojure code is compiled to the same bytecode before execution; AOT compilation merely means that it happens at a singular, defined point in time instead of on demand as the program loads and runs.

However, although it isn’t any faster, it can be a great tool in the following situations:

  • You want to deliver the application binary, but you don’t want to include the original source code with it.

  • To marginally speed up an application’s start time (since the Clojure code won’t have to be compiled on the fly).

  • You need to generate classes loadable directly from Java for interop purposes.

  • For platforms (such as Android) that do not support custom class loaders for running new bytecode at runtime.

You may observe that there is more than one emitted class file for each AOT-compiled namespace. In fact, there will be separate Java classes for each function, the namespace itself, and any additional gen-class, deftype, or defrecord forms. This is actually not dissimilar from Java itself; it has always been the case that inner classes are compiled to separate class files, and Clojure functions are effectively anonymous inner classes from the JVM’s point of view.

See Also