Problem

Clojure today exists at a balance point between performance and dynamic flexibility. Some users would be willing to sacrifice dynamic features to gain more performance. Other users would be willing to sacrifice performance to gain better development error messages or debugging. The problem we aim to solve is to alter the Clojure build such that we can produce alternate versions of Clojure that are useful to smaller audiences while retaining Clojure as it is today.

Example builds we may want to produce (examples):

Direct linking

Off - allows redefs, good for interactive dev tooling or modifying Clojure internals

On - better performance and optimization for long-running more static programs

Validation and error messages that can guide development at the expense of runtime performance

Build profiles

Below are some proposed build variants.

Profile

Description

Compiled?

Direct linking?

Lazy vars?

Metadata

Dev assistance?

dev

For development

Yes

Off

On

Full

On

dynamic

For dynamic production use

Yes

Off

Off

Minimal

Off

static

For static production use

Yes

On

Off

Minimal

Off

slim

Source only

No

n/a

n/a

n/a

n/a

1.8 clojure jar

For comparison

Yes

On

Off

Full

Off

OPEN: Are these the right profiles and the right settings?

OPEN: Which one is the default no-classifier?

Constraints

Clojure users:

Build profile artifacts should be available in public Maven repositories for use with existing build systems (Leiningen, Maven, Boot), alternatives include:

Different artifacts: [org.clojure/clojure-foo "1.8.0"]

Different qualifiers: [org.clojure/clojure "1.8.0-foo"]

Different classifiers: [org.clojure/clojure "1.8.0" :classifier "foo"] - seems like the best choice

Some features may require further compiler flags or metadata to activate even if using the specialized build

For example, you may need to supply special var metadata on a function to get access to a feature

Ideally, use of the special feature should be simply ignored if not using the specialized build (or a warning should direct you)

Build:

Produce multiple output jars each time we build a version (snapshot or release)

The jars will contain different versions of the classes

Specialized build flags or env variables will need to be set during the build for each variant

Testing should occur for each variant

Integration / release infrastructure:

CI must be able to build and test custom builds as part of the dependency matrix

CI must be able to perform releases for all of the variants

CI must be able to test contribs against custom builds

Compiler:

The compiler will need a standard way to determine which variant is active to make decisions during compilation

External builds

Builds that use Clojure may also need to make these kinds of compiler choices to produce their own build profiles.

It would be useful to produce a guide on how to enable combinations of compiler options to produce builds of different flavors for libraries with the common build tools.

Implementation options

Hardest part of this is getting the build to sign and release all of the artifacts together.

Full build would consist of:

javac Java source

jar slim jar (without class files)

filter resources - update version.properties

repeat for each variant

aot compile Clojure source (using Compiler we just built)

jar compiled clojure jar (with class files)

javac test Java

aot compile test Clojure

run clojure.test runner

run generative test runner

jar source files

javadoc generate

jar javadoc files

zip package of full distribution

install to local repo

deploy

sign all artifacts

push all artifacts to Maven central

git tag release

update version to next SNAPSHOT on prod deploy

OPEN: which implementation would be best?

Maven custom assembly

The Maven assembly plugin allows for arbitrary customization of the artifacts created by the build. However, creating multiple artifacts with different Maven coordinates will likely require multiple builds to produce each artifact for deployment. This has issues with signing and release.

Build profiles for stripped down builds, and dev builds sound great; but a batteries included repl environment with bundled contrib libs, sounds like something that Leiningen could do.

Bundling could be achieved with by creating a Maven or Leiningen artefact that just lists all approved contrib libs as dependencies, or by creating a Leiningen new project template, that creates a project listing all of the approved dependencies in the project.clj.