bootstrap resolves and fetches the JARs of one or more dependencies. Like the
launch command, it tries to find a main class in those JARs (unless
-M specifies one already). But unlike
bootstrap command doesn't launch this main class straightaway. Instead, it generates a (usually tiny) JAR, that can be renamed, copied, moved to another machine or OS, and is able to download and launch the corresponding application.
$ coursier bootstrap org.scalameta:scalafmt-cli_2.13:2.3.2 -o scalafmt $ ./scalafmt --version scalafmt 2.3.2
$ coursier bootstrap scalafmt -o scalafmt $ coursier bootstrap scalafmt:2.3.2 -o scalafmt # explicit version
The generated bootstraps are tiny Java apps, that upon launch, successively
- read a list of URLs for one of their resource files,
- read a main class name from another of their resource files,
- download the URLs missing from the coursier cache,
- get all the files corresponding to these URLs from the coursier cache,
- load those files in a class loader,
- find the main class by reflection,
- call the main method of the main class, which actually runs the application.
Overall, this "bootstraps" the application, hence the name.
All of that logic is handled by a small Java application, which currently corresponds to the
bootstrap-launcher module of the coursier sources. A bootstrap consists of that module classes, along with resource files (for the artifact URLs and main class to load) that are specific to each application to launch.
The generated bootstraps automatically pass their arguments starting with
-J to Java, stripping the leading
$ coursier bootstrap com.lihaoyi:ammonite_2.12.8:1.6.0 -M ammonite.Main -o amm $ ./amm -J-Dfoo=bar Loading... Welcome to the Ammonite Repl 1.6.0 (Scala 2.12.8 Java 1.8.0_121) @ sys.props("foo") res0: String = "bar"
Alternatively, one can hard-code Java options when generating the bootstrap, by passing
--java-opt options, like
$ coursier bootstrap com.lihaoyi:ammonite_2.12.8:1.6.0 -M ammonite.Main -o amm \ --java-opt -Dfoo=bar $ ./amm Loading... Welcome to the Ammonite Repl 1.6.0 (Scala 2.12.8 Java 1.8.0_121) @ sys.props("foo") res0: String = "bar"
The launchers generated by the
bootstrap command contain a shell preamble, and are made executable, so that even though they are JARs, they can be run straightaway on Linux and OS X. On Windows, the
bootstrap command also generates a
.bat file along with the launcher (simply appending
.bat to the launcher file name). This
.bat file allows one to run the launcher on Windows nonetheless, almost as on Linux / OS X.
To generate this
.bat file on Linux or OS X (to offer to download it for example), pass
--bat to the bootstrap command, like
$ coursier bootstrap com.geirsson:scalafmt-cli_2.12:1.5.1 -o scalafmt --bat $ ls -lh scalafmt* -rwxr-xr-x 1 user group 18K 8 jan 15:24 scalafmt -rw-r--r-- 1 user group 2,0K 8 jan 15:24 scalafmt.bat
Inversely, to disable generating it on Windows, pass
--bat=false to the
Rather than having the launcher download its JARs upon first launch, one may prefer to ship those JARs along with the launcher. The
--standalone option allows just that. This options adds the application JARs as resources in the launcher. This inflates the launcher size, but that allows it to run without relying on the coursier cache or downloading things.
$ coursier bootstrap com.geirsson:scalafmt-cli_2.12:1.5.1 -o scalafmt --standalone $ ls -lh scalafmt -rwxr-xr-x 1 alexandre staff 15M 8 jan 15:31 scalafmt $ ./scalafmt --version scalafmt 1.5.1
Standalone bootstraps should be similar to JARs generated by One-JAR. Note that although they ship with all their dependencies like so-called uber JARs or assemblies, they differ from them in the sense that:
- dependencies are still kept separate (each dependency stays in its own JAR, themselves added as JARs to the launcher - these are JARs in JARs), so that no conflict has to be resolved,
- the launchers can't be added as is to a classpath, like standard JARs, or assemblies / uber JARs. This prevents using them as is to package spark jobs in particular.
bootstrap command of coursier can generate Scala Native-based native launchers.
This requires the application you want a launcher for to be cross-compiled to Scala Native, and its Scala Native artifacts to be published to Maven or Ivy repositories. The echo project of coursier has such a module, currently published as
In order to generate a launcher for such a published application, you'll need to have your environment set up for Scala Native. You can then generate native launchers by passing the
-S option to the
bootstrap command, like
$ coursier bootstrap \ --native \ io.get-coursier:echo_native0.3_2.11:1.0.2 \ -o echo [info] Linking (2354 ms) [info] Discovered 1291 classes and 9538 methods …
and run them, like
$ ./echo hey hey
Linking flags during the linking phase can be adjusted via
LDFLAGS in the environment.
GraalVM native image
bootstrap command can generate native executables via GraalVM native image.
$ coursier bootstrap --native-image \ io.get-coursier:echo:1.0.3 \ -o echo
This command automatically fetches and extracts a GraalVM Community edition archive, like the
java command of coursier does, then uses it to call
You can pass an explicit GraalVM version via
$ coursier bootstrap --native-image \ --graalvm 19.3 \ io.get-coursier:echo:1.0.3 \ -o echo
Note that this option accepts short versions. So as of writing this,
19.3 gets automatically expanded to
You can pass custom options to native-image via
--graalvm-opt, or after a
$ coursier bootstrap --native-image \ --graalvm 19.3 \ io.get-coursier:echo:1.0.3 \ -o echo \ --graalvm-opt --no-fallback \ -- \ --enable-all-security-services \ --initialize-at-build-time
Note that it can be more convenient to pass arguments to native-image via a native-image.properties resource rather than on the command-line.
Some of the JARs of the dependencies passed to the
bootstrap command may correspond to local files (e.g. from the local
~/.ivy2/local repository) rather than files from remote repositories. In that case, these local files are going to be included as resources, rather than via a URL, in the generated launchers. That allows these launchers to be copied to other machines, and work fine even without the original local repositories. To disable that behavior, pass
--embed-files=false to the
bootstrap command. Note that this only applies when the
--standalone option is not passed - if it is, JARs are added as resources to the launcher nevertheless.