io7m | single-page | multi-page | epub | Montarre User Manual 0.0.3
2. Installation
Front Matter
4. Maven Plugin
1
This section of the documentation describes how to use the montarre package whilst attempting to explain as little as possible of exactly how the package works. The specification section, on the other hand, goes into detail on exactly how everything works internally.
1
In a similar manner to how a jar file is simply a zip file containing the Java bytecode of an application along with some metadata, a montarre package is simply a zip file containing the jar files that comprise an application along with detailed metadata that provides enough information to allow for easily transforming that package to any number of platform-specific package formats. A montarre package is platform-independent and thus contains the superset of all code that the application might use on all of the platforms upon which it might run. Assuming that one has a suitable Java VM installed, a montarre package can simply be unzipped and then run using the java command [1]. This, obviously, is not particularly interesting in itself, and isn't really the way montarre packages are intended to be used. The interesting aspect of a montarre package is that, with no other configuration required, the package can be used to produce a range of native packages and/or executables relevant to the current platform. For example, a user examining the package on Linux can use a single invocation of the montarre native create command to produce a Debian .deb package, a Flatpak, and/or a simple application image executable.
2
The first step in using montarre is to have your build system produce a montarre package as one of the outputs. In general, this will be accomplished with a single invocation of the Maven Plugin, but it is also possible to use the command-line tools.
1
Every montarre package contains a package declaration. A package declaration is an XML file with an extremely strict schema, with almost no optional elements [2]. The package declaration serves two purposes:

3.3.2. Package Declaration Purposes

  • It provides all of the metadata that is used by the tools to produce native packages. For example, the metadata contains Category elements that are used to categorize applications when converting them to Flatpaks.
  • It provides a list of all of the files included in the package, along with their cryptographic hashes for integrity checks, and type information such as "this file is an icon", "this file is a platform-dependent library that is only used on Linux x86_64", and etc.
3
In a montarre package, the package declaration is always stored in the zip file entry named META-INF/MONTARRE/PACKAGE.XML, which is also expected to be the first entry in the file. As a concrete example, this is the package declaration taken from the montarre package itself:

3.3.4. Montarre Package Declaration

$ unzip -p com.io7m.montarre.distribution/target/com.io7m.montarre.distribution-0.0.1-SNAPSHOT.mpk META-INF/MONTARRE/PACKAGE.XML

<Package xmlns="urn:com.io7m.montarre.package:1">
    <Metadata ApplicationKind="CONSOLE">
        <Category Name="Building"></Category>
        <Category Name="Development"></Category>
        <Copying Copyright="Copyright © 2024 Mark Raynsford &lt;code@io7m.com> https://www.io7m.com" License="ISC"></Copying>
        <Description>
            <Text Language="en">Package Java applications</Text>
        </Description>
        <Flatpak>
            <FlatpakPermission Value="--share=network"></FlatpakPermission>
            <FlatpakPermission Value="--filesystem=home:rw"></FlatpakPermission>
            <FlatpakRuntime Name="org.freedesktop.Sdk" Role="SDK" Version="24.08"></FlatpakRuntime>
            <FlatpakRuntime Name="org.freedesktop.Platform" Role="PLATFORM" Version="24.08"></FlatpakRuntime>
        </Flatpak>
        <JavaInfo MainModule="com.io7m.montarre.cmdline/com.io7m.montarre.cmdline.MMain" RequiredJDKVersion="21"></JavaInfo>
        <Link Role="SCM" Target="https://www.github.com/io7m-com/montarre"></Link>
        <Link Role="ISSUES" Target="https://www.github.com/io7m-com/montarre/issues"></Link>
        <Link Role="HOME_PAGE" Target="https://www.io7m.com/software/montarre"></Link>
        <LongDescription Language="en">
            <Paragraph>The Montarre package provides a set of tools for producing native platform artifacts from platform-independent Java packages.</Paragraph>
            <Feature>A rich, strictly-defined, and well-specified packaging format that remains platform-independent whilst allowing straightforward zero-configuration transformations to a wide range of platform-specific package formats.</Feature>
            <Feature>Extensive, type-driven, ahead-of-time checking; if your package validates, you should get working native packages on all platforms.</Feature>
            <Feature>Reproducible builds by default.</Feature>
            <Feature>Support for producing simple jpackage "app-image" executables on any platform.</Feature>
            <Feature>Support for producing Debian .deb packages.</Feature>
            <Feature>Support for producing Windows MSI installers.</Feature>
            <Feature>Support for producing Flatpaks.</Feature>
            <Feature>A carefully-engineered Java API for creating, manipulating, and transforming packages.</Feature>
            <Feature>A full command-line interface built on top of the Java API.</Feature>
            <Feature>A Maven plugin for producing packages from any Maven module.</Feature>
        </LongDescription>
        <Names HumanName="Montarre" Name="com.io7m.montarre" ShortName="montarre"></Names>
        <Vendor ID="com.io7m" Name="io7m"></Vendor>
        <Version Date="2024-01-01" Number="0.0.1-SNAPSHOT"></Version>
    </Metadata>
    <Manifest>
        <Module File="lib/com.io7m.anethum.api-1.1.1.jar" HashAlgorithm="SHA-256" HashValue="bef5e82eeac406d93b993858e575ba304366ad333d54134969951d1223ff2ce8"></Module>
        <Module File="lib/com.io7m.blackthorne.core-2.0.2.jar" HashAlgorithm="SHA-256" HashValue="48b994b273dddd8a2a410c43db3efcd0d91a71910fc27189a24736313fb2bb23"></Module>
        <Module File="lib/com.io7m.blackthorne.jxe-2.0.2.jar" HashAlgorithm="SHA-256" HashValue="bfcf0e162aa3b636f29f933de5d80f01a1ee1ebb32780f1ff8ca96d56a75ecdf"></Module>
        <Module File="lib/com.io7m.jaffirm.core-4.0.1.jar" HashAlgorithm="SHA-256" HashValue="dc02592647284de9b985a3852e3ad967e9ee561d44772d3e4ecd99afbbc22f18"></Module>
        <Module File="lib/com.io7m.jcip-2.0.1.jar" HashAlgorithm="SHA-256" HashValue="f103daf09059c6969efb7e87dbd427da9dd2b9088224f3aca36e76865edd8ba2"></Module>
        <Module File="lib/com.io7m.jdownload.core-1.0.0.jar" HashAlgorithm="SHA-256" HashValue="807ec26e9b987dd7e5e475f64494501582af0a89375ec106a8307102a269095d"></Module>
        <Module File="lib/com.io7m.jlexing.core-3.2.0.jar" HashAlgorithm="SHA-256" HashValue="e26c6046de6cf41819fe2ed15e38279ce3447cf45430166b0f25a3f589d55c93"></Module>
        <Module File="lib/com.io7m.jmulticlose.core-1.1.3.jar" HashAlgorithm="SHA-256" HashValue="c0e5164f515e530dc210772d98120bbf8f60c9933b9e178e3ad4dbbf4ef43b92"></Module>
        <Module File="lib/com.io7m.junreachable.core-4.0.2.jar" HashAlgorithm="SHA-256" HashValue="979cb909924e8ea64e17b03340c601a8e6b6e1620c4e751a0bd74a34ffb9d5e9"></Module>
        <Module File="lib/com.io7m.jxe.core-2.0.0.jar" HashAlgorithm="SHA-256" HashValue="3520d03a2606787c4e88625f151c9dbbc853bd4987e752c509e6030a83238b67"></Module>
        <Module File="lib/com.io7m.jxtrand.api-2.1.0.jar" HashAlgorithm="SHA-256" HashValue="53c1a2cc739b6359441ba7aacc2aee74166ea416060b197ef6530e8a60052b27"></Module>
        <Module File="lib/com.io7m.jxtrand.vanilla-2.1.0.jar" HashAlgorithm="SHA-256" HashValue="c1bbcea8b4ec0a99093e1ec745036e7849f98687158ad3b777179618052ce9b2"></Module>
        <Module File="lib/com.io7m.lanark.core-1.2.0.jar" HashAlgorithm="SHA-256" HashValue="c725d2de4b82b9632cc2d72219b27f5d4c4700dde3dd2905f965f06894f04503"></Module>
        <Module File="lib/com.io7m.montarre.api-0.0.1-SNAPSHOT.jar" HashAlgorithm="SHA-256" HashValue="57cd2bf03e9b80f1ee78011d4a1ee45a5a6051ef8652917b89c5e368ea1d538f"></Module>
        <Module File="lib/com.io7m.montarre.cmdline-0.0.1-SNAPSHOT.jar" HashAlgorithm="SHA-256" HashValue="6e8b6e26827c9d46a678742aa5981cb9060d0ea68a295466a173481a7b0cf441"></Module>
        <Module File="lib/com.io7m.montarre.io-0.0.1-SNAPSHOT.jar" HashAlgorithm="SHA-256" HashValue="61bf500d463fac19cbe595bb6e3612936ba2f68aedf1ec9107ebd7addf37eeda"></Module>
        <Module File="lib/com.io7m.montarre.nativepack-0.0.1-SNAPSHOT.jar" HashAlgorithm="SHA-256" HashValue="f2d9ffcd1080036d47f2759a6bc174818d7fd73bbe4188141889d895f630deb1"></Module>
        <Module File="lib/com.io7m.montarre.schema-0.0.1-SNAPSHOT.jar" HashAlgorithm="SHA-256" HashValue="1027ae156398734ee4124839189361255b58b98bdd7dab2036dbfde231eaf3af"></Module>
        <Module File="lib/com.io7m.montarre.xml-0.0.1-SNAPSHOT.jar" HashAlgorithm="SHA-256" HashValue="9c614cda97071bef22da7fdcaeb446ccf6f4f5e29f654eab874b99725d01c124"></Module>
        <Module File="lib/com.io7m.quarrel.core-1.6.1.jar" HashAlgorithm="SHA-256" HashValue="20047834fc6d68a57ea251bccc52822de8bac068c4a13dcb6ae99111e542be90"></Module>
        <Module File="lib/com.io7m.quarrel.ext.logback-1.6.1.jar" HashAlgorithm="SHA-256" HashValue="48827e4267a6e85c5900649381bf73ddfb0ccee9e4e181834d3c17bd12e4fb48"></Module>
        <Module File="lib/com.io7m.seltzer.api-1.1.0.jar" HashAlgorithm="SHA-256" HashValue="1097d2d28fcf12e6a9699fc9b527712f954ebe8d25467ccfa8201e445eeadf96"></Module>
        <Module File="lib/com.io7m.streamtime.core-1.0.0.jar" HashAlgorithm="SHA-256" HashValue="d062c6142754e507c51a3e127b449ae2d95cf30afb65b4cfd6fffa7f7717a0c8"></Module>
        <Module File="lib/com.io7m.verona.core-1.0.1.jar" HashAlgorithm="SHA-256" HashValue="b6c2fb9858a9736c32e05513f0c0801ebcf38d7226d5c70f62dd7ba4dbd311e2"></Module>
        <Module File="lib/commons-codec-1.17.1.jar" HashAlgorithm="SHA-256" HashValue="f9f6cb103f2ddc3c99a9d80ada2ae7bf0685111fd6bffccb72033d1da4e6ff23"></Module>
        <Module File="lib/commons-compress-1.27.1.jar" HashAlgorithm="SHA-256" HashValue="293d80f54b536b74095dcd7ea3cf0a29bbfc3402519281332495f4420d370d16"></Module>
        <Module File="lib/commons-io-2.17.0.jar" HashAlgorithm="SHA-256" HashValue="4aa4ca48f3dfd30b78220b7881d8cb93eac4093ec94361b6befa9487998a550b"></Module>
        <Module File="lib/commons-lang3-3.17.0.jar" HashAlgorithm="SHA-256" HashValue="6ee731df5c8e5a2976a1ca023b6bb320ea8d3539fbe64c8a1d5cb765127c33b4"></Module>
        <Module File="lib/logback-classic-1.5.8.jar" HashAlgorithm="SHA-256" HashValue="89b0f7bec5fa8a9c9246acd1e99f0e84d6cb3bbadaa5b095a14c2cd0f4732d05"></Module>
        <Module File="lib/logback-core-1.5.8.jar" HashAlgorithm="SHA-256" HashValue="a698e4cff3eac45eec9b2755df93bb7a9725d853f7938030654ce5430b37c41d"></Module>
        <Module File="lib/slf4j-api-2.0.16.jar" HashAlgorithm="SHA-256" HashValue="a12578dde1ba00bd9b816d388a0b879928d00bab3c83c240f7013bf4196c579a"></Module>
        <Resource File="meta/bom.xml" HashAlgorithm="SHA-256" HashValue="822512da044a72e5e851f73347027c802e90f21468235266b32fca6cd7193bcc" Role="BOM"></Resource>
        <Resource File="meta/icon.ico" HashAlgorithm="SHA-256" HashValue="a36ce859182d76a764bfdb2260b05e0c00580a191e7bc36155a00062ccd06b0e" Role="ICO_WINDOWS"></Resource>
        <Resource File="meta/icon128.png" HashAlgorithm="SHA-256" HashValue="404b0d848df4c98a02804b6e7566b4c4bf27430f7c584381d32cf43a0b3e4028" Role="ICON_128"></Resource>
        <Resource File="meta/icon16.png" HashAlgorithm="SHA-256" HashValue="47734e7530a565bca0d8b3c2015600441b31fe151c59855b4f0af535360e1cf9" Role="ICON_16"></Resource>
        <Resource File="meta/icon24.png" HashAlgorithm="SHA-256" HashValue="7597832ef6ebff7f4fa8ac0c8774552f54b47391f8db8479ea96e395556c7da0" Role="ICON_24"></Resource>
        <Resource File="meta/icon32.png" HashAlgorithm="SHA-256" HashValue="e3ea34ef4296b538d7ef5d58ad511ab5bd4b4b078a30f1910e9789143c98776a" Role="ICON_32"></Resource>
        <Resource File="meta/icon48.png" HashAlgorithm="SHA-256" HashValue="35d5ada26910c3f707f9b8cfb016b1dca9a575c940018fa5048d71258581b0fc" Role="ICON_48"></Resource>
        <Resource File="meta/icon64.png" HashAlgorithm="SHA-256" HashValue="c30a14e51ade414a6110daa447e8d44cfa10808fa9ce06b4bb67f37def7fd04e" Role="ICON_64"></Resource>
        <Resource File="meta/license.txt" HashAlgorithm="SHA-256" HashValue="cb2db7e26966764c369e6fb4ca08a989e752d926016dd132661a8c64b25149f4" Role="LICENSE"></Resource>
        <Resource File="meta/screenshot.png" HashAlgorithm="SHA-256" HashValue="8341f4b229fea93885c52d7ad3797da8803d4e291b3a9e6f8c2c4d4d641637aa" Role="SCREENSHOT">
            <Caption>
                <Text Language="en">The main command-line entry point.</Text>
            </Caption>
        </Resource>
    </Manifest>
</Package>
5
You are not usually expected to write a package declaration by hand. Instead, the Maven plugin can be used to collect all of the (transitive) dependencies of a project, generate an appropriate manifest, and fill in all of the package declaration information that can be inferred from the Maven POM alone. Anything that cannot be inferred from the POM must be included as configuration parameters to the plugin.
1
To use the Maven plugin, simply add a plugin execution to the main module in your project:

3.4.2. Maven Plugin Execution

<plugin>
  <groupId>com.io7m.montarre</groupId>
  <artifactId>com.io7m.montarre.maven_plugin</artifactId>
  <version>...</version>
  <executions>
    <execution>
      <id>make-distribution</id>
      <goals>
        <goal>package</goal>
      </goals>
      <phase>package</phase>
      <configuration>
        <validationWarningsAreErrors>true</validationWarningsAreErrors>

        <applicationKind>CONSOLE</applicationKind>

        <categories>
          <category>Development</category>
          <category>Building</category>
        </categories>

        <copyright>Copyright © 2024 Mark Raynsford &lt;code@io7m.com> https://www.io7m.com</copyright>

        <humanName>Montarre</humanName>
        <packageName>com.io7m.montarre</packageName>
        <shortName>montarre</shortName>

        <description>Package Java applications</description>

        <version>
          <number>${project.version}</number>
          <date>2024-10-06</date>
        </version>

        <vendor>
          <id>com.io7m</id>
          <name>io7m</name>
        </vendor>

        <longDescriptions>
          <longDescription>${project.basedir}/src/main/meta/description-en.xml</longDescription>
        </longDescriptions>

        <mainModule>com.io7m.montarre.cmdline/com.io7m.montarre.cmdline.MMain</mainModule>

        <requiredJDKVersion>21</requiredJDKVersion>

        <flatpak>
          <runtimes>
            <runtime>
              <name>org.freedesktop.Sdk</name>
              <version>24.08</version>
              <role>SDK</role>
            </runtime>
            <runtime>
              <name>org.freedesktop.Platform</name>
              <version>24.08</version>
              <role>PLATFORM</role>
            </runtime>
          </runtimes>
          <permissions>
            <permission>--share=network</permission>
            <permission>--filesystem=home:rw</permission>
          </permissions>
        </flatpak>

        <libraries>
          <excludes>
            <exclude>com\.io7m\.montarre\.cmdline-.*-main\.jar</exclude>
            <exclude>com\.io7m\.montarre\.distribution-.*</exclude>
            <exclude>maven-.*</exclude>
            <exclude>com\.io7m\.montarre\.maven_plugin-.*</exclude>
          </excludes>
        </libraries>

        <resources>
          <resource>
            <role>BOM</role>
            <file>${project.build.directory}/bom.xml</file>
            <entryName>bom.xml</entryName>
          </resource>
          <resource>
            <role>ICON_16</role>
            <file>${project.basedir}/src/main/meta/icon16.png</file>
            <entryName>icon16.png</entryName>
          </resource>
          <resource>
            <role>ICON_24</role>
            <file>${project.basedir}/src/main/meta/icon24.png</file>
            <entryName>icon24.png</entryName>
          </resource>
          <resource>
            <role>ICON_32</role>
            <file>${project.basedir}/src/main/meta/icon32.png</file>
            <entryName>icon32.png</entryName>
          </resource>
          <resource>
            <role>ICON_48</role>
            <file>${project.basedir}/src/main/meta/icon48.png</file>
            <entryName>icon48.png</entryName>
          </resource>
          <resource>
            <role>ICON_64</role>
            <file>${project.basedir}/src/main/meta/icon64.png</file>
            <entryName>icon64.png</entryName>
          </resource>
          <resource>
            <role>ICON_128</role>
            <file>${project.basedir}/src/main/meta/icon128.png</file>
            <entryName>icon128.png</entryName>
          </resource>
          <resource>
            <role>SCREENSHOT</role>
            <file>${project.basedir}/src/main/meta/screenshot.png</file>
            <entryName>screenshot.png</entryName>
            <captions>
              <caption>
                <language>en</language>
                <text>The main command-line entry point.</text>
              </caption>
            </captions>
          </resource>
          <resource>
            <role>ICO_WINDOWS</role>
            <file>${project.basedir}/src/main/meta/icon.ico</file>
            <entryName>icon.ico</entryName>
          </resource>
          <resource>
            <role>LICENSE</role>
            <file>${project.basedir}/../README-LICENSE.txt</file>
            <entryName>license.txt</entryName>
          </resource>
        </resources>
      </configuration>
    </execution>
  </executions>
</plugin>
3
Many of the parameters are optional and are inferred from the hosting Maven project if not specified. All parameters are documented in the Maven Plugin documentation.
4
Upon running the build, a montarre package will be produced and attached to the build. Look for a file with the suffix .mpk:

3.4.5. mpk File

$ ls com.io7m.montarre.distribution/target/*.mpk
com.io7m.montarre.distribution/target/com.io7m.montarre.distribution-0.0.1-SNAPSHOT.mpk
1
Assuming that you have an existing montarre package (we'll pretend that it's called montarre.mpk), it's possible to produce every type of native package supported by the current system with a single command. Assuming that the current system is Linux, and we're running on the x86_64 hardware architecture, we need to tell the command-line where to get a suitable Java runtime that can be used as the basis for a native package. At the time of writing, there seems to be little reason to use anything other than Eclipse Adoptium as they produce TCK certified runtimes for the widest range of platforms. We call the native create subcommand of the command-line montarre tool, passing it a couple of temporary directories that will be used for temporary files and the outputs of packaging, and a link to a suitable Temurin JRE:

3.5.2. Native Creation

$ montarre native create \
  --package montarre.mpk \
  --work-directory /tmp/work0 \
  --output-directory /tmp/work0-output \
  --java-runtime-download-uri https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.4%2B7/OpenJDK21U-jdk_x64_linux_hotspot_21.0.4_7.tar.gz \
  --java-runtime-sha256 51fb4d03a4429c39d397d3a03a779077159317616550e4e71624c9843083e7b9 \
  --java-runtime-format TAR_GZ
3
The output of the command is a set of packages in various formats:

3.5.4. Native Creation Outputs

$ ls -alF /tmp/work0-output
total 187632
drwxr-xr-x  2 montarre   montarre        120 Oct 15 12:13 ./
drwxrwxrwt 30 root       root            880 Oct 16 17:37 ../
-rw-r--r--  1 montarre   montarre    4138851 Oct 15 12:13 com.io7m.montarre-0.0.1-SNAPSHOT-any.tgz
-rw-r--r--  1 montarre   montarre   81923503 Oct 15 12:11 com.io7m.montarre-0.0.1-SNAPSHOT-x86_64-linux.tgz
-rw-r--r--  1 montarre   montarre   52665048 Oct 15 12:13 com.io7m.montarre.flatpak
-rw-r--r--  1 montarre   montarre   53400220 Oct 15 12:11 montarre-0.0.1-SNAPSHOT-x86_64-linux.deb
5
We can see that the process produced a Debian package named montarre-0.0.1-SNAPSHOT-x86_64-linux.deb, an app-image named com.io7m.montarre-0.0.1-SNAPSHOT-x86_64-linux.tgz, a shell distribution named com.io7m.montarre-0.0.1-SNAPSHOT-any.tgz, and a Flatpak named com.io7m.montarre.flatpak.
6
Had this command been run on Windows, the output would likely have included an MSI installer.

Footnotes

1
It might be necessary to adjust the module path to account for the fact that the package might have included, for example, native libraries that should not be placed on the module path on some platforms. The included package metadata contains all of the information required to make these decisions. Most applications do not include native libraries, so the point generally stands.
References to this footnote: 1
2
The schema is so strict, in fact, that simply creating a Package element in the correct urn:com.io7m.montarre.package:1 namespace in any modern IDE will automatically create and fill in most of the elements!
References to this footnote: 1
2. Installation
Front Matter
4. Maven Plugin
io7m | single-page | multi-page | epub | Montarre User Manual 0.0.3