Package ⚡️
The Package command is restricted and requires setting the --power
option to be used.
You can pass it explicitly or set it globally by running:
scala-cli config power true
The package
command can package your Scala code in various formats, such as:
- lightweight launcher JARs
- standard library JARs
- so called "assemblies" or "fat JARs"
- docker container
- JavaScript files for Scala.js code
- GraalVM native image executables
- native executables for Scala Native code
- OS-specific formats, such as deb or rpm (Linux), pkg (macOS), or MSI (Windows)
Default package format
The default package format writes a lightweight launcher JAR, like the "bootstrap" JAR files generated by coursier. These JARs tend to have a small size (mostly containing only the byte code from your own sources), can be generated fast, and download their dependencies upon first launch via coursier.
Such JARs can be copied to other machines, and will run fine there.
Their only requirement is that the java
command needs to be available in the PATH
:
object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package Hello.scala -o hello
./hello
Hello
Library JARs
Library JARs are suitable if you plan to put the resulting JAR in a class path, rather than running it as is. These follow the same format as the JARs of libraries published to Maven Central:
package mylib
class MyLibrary {
def message = "Hello"
}
scala-cli --power package MyLibrary.scala -o my-library.jar --library
javap -cp my-library.jar mylib.MyLibrary
Compiled from "MyLibrary.scala"
public class mylib.MyLibrary {
public java.lang.String message();
public mylib.MyLibrary();
}
Assemblies
Assemblies blend your dependencies and your sources' byte code together in a single JAR file. As a result, assemblies can be run as is, just like bootstraps, but don't need to download anything upon first launch. Because of that, assemblies also tend to be bigger, and somewhat slower to generate:
object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package Hello.scala -o hello --assembly
./hello
Hello
By default assemblies are self-executable, just like the default package format. With the --preamble=false
option, you can build an assembly that just contains the JAR and does not contain any built-in Bash code, and therefore can be launched directly with Java and is more portable:
scala-cli --power package Hello.scala -o hello.jar --assembly --preamble=false
java -jar hello.jar
Hello
Docker container
Scala CLI can create an executable application and package it into a docker image.
For example, here’s an application that will be executed in a docker container:
object HelloDocker extends App {
println("Hello from Docker")
}
Passing --docker
to the package
sub-command generates a docker image.
The docker image name parameter --docker-image-repository
is mandatory.
The following command generates a hello-docker
image with the latest
tag:
scala-cli --power package --docker HelloDocker.scala --docker-image-repository hello-docker
docker run hello-docker
Hello from Docker
You can also create Docker images for Scala.js and Scala Native applications.
The following command shows how to create a Docker image (--docker
) for a Scala.js (--js
) application:
scala-cli --power package --js --docker HelloDocker.scala --docker-image-repository hello-docker
Packaging Scala Native applications to a Docker image is only supported on Linux.
The following command shows how to do that:
scala-cli --power package --native --docker HelloDocker.scala --docker-image-repository hello-docker
Building Docker container from base image
--docker-from
lets you specify your base docker image.
The following command generate a hello-docker
image using base image openjdk:11
scala-cli --power package --docker HelloDocker.scala --docker-from openjdk:11 --docker-image-repository hello-docker
Scala.js
Packaging Scala.js applications results in a .js
file, which can be run with node
:
object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package --js HelloJs.scala -o hello.js
node hello.js
Hello
Note that Scala CLI doesn't offer the ability to link the resulting JavaScript with linkers, such as Webpack (yet).
Native image
GraalVM native image makes it possible to build native executables out of JVM applications. It can be used from Scala CLI to build native executables for Scala applications.
object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package Hello.scala -o hello --native-image
./hello
Hello
Note that Scala CLI automatically downloads and unpacks a GraalVM distribution using the JVM management capabilities of coursier.
Several options can be passed to adjust the GraalVM version used by Scala CLI:
--graalvm-jvm-id
accepts a JVM identifier, such asgraalvm-java17:22.0.0
orgraalvm-java17:21
(short versions accepted).--graalvm-java-version
makes it possible to specify only a target Java version, such as11
or17
(note that only specific Java versions may be supported by the default GraalVM version that Scala CLI picks)--graalvm-version
makes it possible to specify only a GraalVM version, such as22.0.0
or21
(short versions accepted)--graalvm-args
makes it possible to pass args to GraalVM version
Scala Native
Packaging a Scala Native application results in a native executable:
object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package --native HelloNative.scala -S 2.13 -o hello
file hello
hello: Mach-O 64-bit executable x86_64
./hello
Hello
OS-specific packages
Scala CLI also lets you package Scala code as OS-specific packages. This feature is somewhat experimental, and supports the following formats, provided they're compatible with the operating system you're running Scala CLI on:
object Hello {
def main(args: Array[String]): Unit =
println("Hello")
}
scala-cli --power package --deb Hello.scala -o hello.deb
file hello
hello: Mach-O 64-bit executable x86_64
./hello
Hello
Debian
DEB is the package format for the Debian Linux distribution.
To build a Debian package, you will need to have dpkg-deb
installed.
Example:
scala-cli --power package --deb --output 'path.deb' Hello.scala
Mandatory arguments
- version
- maintainer
- description
- output-path
Optional arguments
- force
- launcher-app
- debian-conflicts
- debian-dependencies
- architecture
RedHat
RPM is the software package format for RedHat distributions.
To build a RedHat Package, you will need to have rpmbuild
installed.
Example:
scala-cli --power package --rpm --output 'path.rpm' Hello.scala
Mandatory arguments
- version
- description
- license
- output-path
Optional arguments
- force
- launcher-app
- release
- rpm-architecture
macOS (PKG)
PKG is a software package format for macOS.
To build a PKG you will need to have pkgbuild
installed.
Example:
`scala-cli --power package --pkg --output 'path.pkg` Hello.scala
Mandatory arguments
- version
- identifier
- output-path
Optional arguments
- force
- launcher-app
Windows
MSI is a software package format for Windows.
To build an MSI installer, you will need to have WIX Toolset
installed.
Example:
scala-cli --power package --msi --output path.msi Hello.scala
Mandatory arguments
- version
- maintainer
- licence-path
- product-name
- output-path
Optional arguments
- force
- launcher-app
- exit-dialog
- logo-path
Using directives
Instead of passing the package
options directly from bash, it is possible to pass some of them with using directives.
packaging.packageType
This using directive makes it possible to define the type of the package generated by the package
command. For example:
//> using packaging.packageType assembly
Available types: assembly
, raw-assembly
, bootstrap
, library
, source
, doc
, spark
, js
, native
, docker
, graalvm
, deb
, dmg
, pkg
, rpm
, msi
.
packaging.output
This using directive makes it possible to define the destination path of the package generated by the package
command. For example:
//> using packaging.output foo
The using directive above makes it possible to create a package named foo
inside the current directory.
packaging.graalvmArgs
This using directive makes it possible to pass args to GraalVM:
//> using packaging.graalvmArgs --no-fallback --enable-url-protocols=http,https
Docker
packaging.dockerFrom
The using directive allows you to define the base Docker image that is used to run your application.
//> using packaging.dockerFrom openjdk:11
packaging.dockerFrom
The using directive allows you to define the generated Docker image tag.
//> using packaging.dockerImageTag 1.0.0
packaging.dockerImageRegistry
The using directive allows you to define the image registry.
//> using packaging.dockerImageRegistry virtuslab
packaging.dockerImageRepository
The using directive allows you to define the image repository.
//> using packaging.dockerImageRepository scala-cli