Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Packager for Clojure based on deps.edn (AKA tools.deps). Supporting jar, uberjar and GraalVM's native-image.

License

NotificationsYou must be signed in to change notification settings

luchiniatwork/cambada

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clojars Project

Cambada is a packager for Clojure based ondeps.edn (AKAtools.deps). It isheavily inspired by Leiningen's jar and uberjar tasks and also supportsGraalVM's new native-image making it a one-stop shop for any packaging neededfor your Clojure project.

Motivation

Leiningen has laid the foundations of what many of us have come to accept as thestandard for Clojure projects. Clojure'stools.deps potentially brings newideas to the Clojure workflow. Cambada brings some of the great features ofLeiningen to thetools.deps workflow.

Cambada's sole focus is packaging. It doesn't have plugins, templates or Clojarsintegration. It packages yourdeps.edn progject as one - or all - of:

  1. jar
  2. uberjar
  3. GraalVM native image

On top of Phil Hagelberg's (and so many others') great Leiningen, many thanks toDominic Monroe and his work onpack as well as Taylor Wood and hisclj.native-image. These projects offered a lot of inspiration (and, in somecases, donor code too).

Table of Contents

Getting Started

Cambada is a simple set of main functions that can be called from adeps.ednalias. The simplest way to have it available in your project is to add an aliaswithextra-deps to yourdeps.edn file:

{:aliases {:cambada           {:extra-deps            {luchiniatwork/cambada             {:mvn/version"1.0.5"}}}}}

Cambada has three main entry points,cambada.jar,cambada.uberjar andcambada.native-image. Let's say you simply want to create an uberjar:

$ clj -R:cambada -m cambada.uberjarCleaning targetCreating target/classes  Compiling ...Creating target/project-name-1.0.0-SNAPSHOT.jarUpdating pom.xmlCreating target/project-name-1.0.0-SNAPSHOT-standalone.jar  Including ...Done!

Your files will be located attarget/ by default.

All entry points have a few extra configuration options you might be interestedin. For instance:

$ clj -R:cambada -m cambada.uberjar --helpPackage up the project files and all dependencies into a jar file.Usage: clj -m cambada.uberjar [options]Options:  -m, --main NS_NAME                            The namespace with the -main function      --app-group-id STRING     project-name    Application Maven group ID      --app-artifact-id STRING  project-name    Application Maven artifact ID      --app-version STRING      1.0.0-SNAPSHOT  Application version      --[no-]copy-source                        Copysource files by default  -a, --aot NS_NAMES            all             Namespaces to be AOT-compiled or`all` (default)  -d, --deps FILE_PATH          deps.edn        Location of deps.edn file  -o, --out PATH                target          Output directory  -h, --help                                    Shows thishelp

Do try--help forcambada.jar andcambada.native-image if you areinterested or refer to the sections below.

Easy Aliases

One of the powers-in-simplicity oftools.deps is the ability to define aliasesondeps.edn. When we used the aliascambada on the section above, we simplyspecified it as an dependency to be resolved (therefore the-R when callingclj).

You can also be a lot more prescriptive in your aliases by making them do morework for you. For instance, the alias below will create a versioned uberjar:

{:aliases {:uberjar           {:extra-deps            {luchiniatwork/cambada {:mvn/version"1.0.0"}}:main-opts ["-m""cambada.uberjar""--app-version""0.5.3"]}}}

By having an alias like thisuberjar one in yourdeps.edn you can simply runit by using$ clj -A:uberjar making it very familiar to those used with$ lein uberjar:

$ clj -A:uberjarCleaning targetCreating target/classes  Compiling ...Creating target/project-name-0.5.3.jarUpdating pom.xmlCreating target/project-name-0.5.3-standalone.jar  Including ...Done!

Packaging as a Jar

Let's start with an empty project folder:

$ mkdir -p myproj/src/myproj/$cd myproj

Create adeps.edn at the root of your project withcambada.jar as an alias:

{:aliases {:jar           {:extra-deps            {luchiniatwork/cambada {:mvn/version"1.0.2"}}:main-opts ["-m""cambada.jar""-m""myproj.core"]}}}

Create a simple hello world on a-main function atsrc/myproj/core.clj:

(nsmyproj.core  (:gen-class))(defn-main [& args]  (println"Hello World!"))

Of course, just for safe measure, let's run this hello world viaclj:

$ clj -m myproj.coreHello World!

Then just call the alias from the project's root:

$ clj -A:jarCleaning targetCreating target/classes  Compiling myproj.coreCreating target/myproj-1.0.0-SNAPSHOT.jarUpdating pom.xmlDone!

Once Cambada is done, you'll have a jar package attarget/. In order to runit, you'll need to add Clojure and spec to your class path. The paths will varyon your system:

$ java -cp target/myproj-1.0.0-SNAPSHOT.jar myproj.coreHello World!

For a standalone jar file see the uberjar option on the next section.

You can specify the following options forcambada.jar:

  -m, --main NS_NAME                            The namespace with the -main function      --app-group-id STRING     project-name    Application Maven group ID      --app-artifact-id STRING  project-name    Application Maven artifact ID      --app-version STRING      1.0.0-SNAPSHOT  Application version      --[no-]copy-source                        Copy source files by default  -a, --aot NS_NAMES            all             Namespaces to be AOT-compiled or `all` (default)  -d, --deps FILE_PATH          deps.edn        Location of deps.edn file  -o, --out PATH                target          Output directory  -h, --help                                    Shows this help

These options should be quite self-explanatory and the defaults arehopefully sensible enough for most of the basic cases. By defaulteverything gets AOT-compiled and sources are copied to the resulting jar.

For those used to Leiningen, the application's group ID, artifact IDand version are not extracted fromproject.clj (since it's assumedyou don't have aproject.clj in adeps.edn workflow). Therefore,you must specify these expressively as options.

Packaging as an Uberjar

Let's start with an empty project folder:

$ mkdir -p myproj/src/myproj/$cd myproj

Create adeps.edn at the root of your project withcambada.jar as an alias:

{:aliases {:uberjar           {:extra-deps            {luchiniatwork/cambada {:mvn/version"1.0.0"}}:main-opts ["-m""cambada.uberjar""-m""myproj.core"]}}}

Create a simple hello world on a-main function atsrc/myproj/core.clj:

(nsmyproj.core  (:gen-class))(defn-main [& args]  (println"Hello World!"))

Of course, just for safe measure, let's run this hello world viaclj:

$ clj -m myproj.coreHello World!

Then just call the alias from the project's root:

$ clj -A:uberjarCleaning targetCreating target/classes  Compiling myproj.coreCreating target/myproj-1.0.0-SNAPSHOT.jarUpdating pom.xmlCreating target/myproj-1.0.0-SNAPSHOT-standalone.jar  Including myproj-1.0.0-SNAPSHOT.jar  Including clojure-1.9.0.jar  Including spec.alpha-0.1.143.jar  Including core.specs.alpha-0.1.24.jarDone!

Once Cambada is done, you'll have two jar packages attarget/. One for a basicjar and one standalone with all dependencies in it. In order to run it, simplycall it:

$ java -jar target/myproj-1.0.0-SNAPSHOT-standalone.jarHello World!

cambada.uberjar has exactly the same options and defaults ascambada.jar (see above for more details).

Caveats

If any of your transitive dependencies has a Maven Central dependency,cambada may fail on you (investigations under way). Therefore, it isrecommended that you explicitly add your repos (Central included) toyourdeps.edn file i.e.:

{:deps {...}:mvn/repos {"central" {:url"https://repo1.maven.org/maven2/"}"clojars" {:url"https://repo.clojars.org/"}}}

Packaging as a Native Image

By using GraalVM we now have the option of packaging everything AOTcompiled as a native image.

If you want to use this feature, make sure todownload and installGraalVM.

If you are a MacOS user, GraalVM CE is available as a brew cask:

$ brew cask install graalvm/tap/graalvm-ce

GraalVM'snative-image is a package that needs to be installedmanually with the following command (attention thatgu is at$GRAALVM_HOME/bin/ if it is not on yourPATH):

$ gu install native-image

You will need to set yourGRAALVM_HOME environment variable to pointto where GraalVM is installed. Alternatevely you can callcambada.native-image with the argument--graalvm-home pointing to it.

The entry point for native image packaging iscambada.native-image. Let's assume yourGRAALVM_HOME variable isset (if you don't, use--graalvm-home).

Let's start with an empty project folder:

$ mkdir -p myproj/src/myproj/$cd myproj

Create adeps.edn at the root of your project withcambada.jar as an alias:

{:aliases {:native-image           {:extra-deps            {luchiniatwork/cambada {:mvn/version"1.0.0"}}:main-opts ["-m""cambada.native-image""-m""myproj.core"]}}}

Create a simple hello world on a-main function atsrc/myproj/core.clj:

(nsmyproj.core  (:gen-class))(defn-main [& args]  (println"Hello World!"))

Of course, just for safe measure, let's run this hello world viaclj:

$ clj -m myproj.native-imageHello World!

Then just call the alias from the project's root:

$ clj -A:native-imageCleaning targetCreating target/classes  Compiling myproj.coreCreating target/myproj   classlist:   2,810.07 ms       (cap):   1,469.31 ms       setup:   2,561.28 ms  (typeflow):   5,802.45 ms   (objects):   2,644.17 ms  (features):      40.54 ms    analysis:   8,609.18 ms    universe:     314.28 ms     (parse):   1,834.84 ms    (inline):   2,338.45 ms   (compile):  16,824.24 ms     compile:  21,435.77 ms       image:   1,862.44 ms       write:   1,276.55 ms     [total]:  38,942.48 msDone!

Once Cambada is done, you'll have an executable package attarget/:

$ ./target/myprojHello World!

Extra options can be sent to GraalVM's packager by using Cambada's--graalvm-opt option i.e., to includeFILE as a resource, simplyuse--graalvm-opt H:IncludeResources=FILE.

Performance Comparison

A quick comparison of themyproj hello world as described previously and ranacross different packaging options:

Straight withclj:

$time clj -m myproj.coreHello World!1.160 secs

As a standalone uberjar:

$time java -jar target/myproj-1.0.0-SNAPSHOT-standalone.jarHello World!0.850 secs

As a native image:

$time ./target/myprojHello World!0.054 secs

Comparing withclj as a baseline:

MethodSpeed in secsSpeed relative toclj
clj1.160 secs1x
uberjar0.850 secs1.36x
native-image0.054 secs21.48x

Bugs

If you find a bug, submit aGithub issue.

Help

This project is looking for team members who can help this project succeed!If you are interested in becoming a team member please open an issue.

License

Copyright © 2018 Tiago Luchini

Distributed under the MIT License. See LICENSE

About

Packager for Clojure based on deps.edn (AKA tools.deps). Supporting jar, uberjar and GraalVM's native-image.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp