Knowledge Base

Notice Information in this article applies to Excelsior JET version 11.3 and above.


This document explains by example the process of creating a Debian package (.deb file) for a Java application that was compiled to a native Linux binary with the help of Excelsior JET.


Debian Linux and its derivatives support the so called Debian packages (.deb files). Debian packages are more powerful and flexible than the Linux version of Excelsior Installer. More importantly, .deb is the standard format of many popular Linux distributions, such as Ubuntu.

Notice: Plugins for Debian package creation exist for both Maven and Gradle. You may want to utilize if you are already using the respective Excelsior JET plugin.

A .deb file is actually an ar archive containing exactly three files in the following order:

  1. debian-binary contains the file format descriptor.
  2. control.tar contains the control files. At a minimum, it should contain the so called master control file with package metadata. Optional files are a list of MD5 sums for integriry checks, scripts to run before and after package installation and removal, a template file for those scripts to prompt the user for input, and so on.
  3. data.tar contains the files that need to be copied to the target system.

Both .tar files can be compressed with gzip or xz.


Here is how you would make a barebones Debian package for the "Hello, World!" Java application compiled with Excelsior JET.

File Format Descriptor

As of the current version of .deb file format, the debian-binary file should contain just the format version number, namely string "2.0":

echo 2.0 > debian-binary

Control Files

The master control file of a Debian package, appropriately named control, is a plain text file that contains a number of fields. A field starts with a tag followed by a colon and the body of the field, which can span multiple lines. The Description field is special in that regard: the first line is interpreted as the short description and the rest as the long description. The only required fields are Package, Version, Maintainer, and Description. Adding the Architecture field to a package containing native binaries is a good idea. You may also want to add some other metadata such as the URL of your home page:

Package: hello
Version: 1.0.0
Architecture: amd64
Section: java
Maintainer: Joe Schmoe <>
Installed-Size: 27024
Description: Natively compiled Java "Hello, World!".
  The Java implemenation of a classic "Hello, World!" program,
  used here to illustrate the process of compiling a Java
  application to native code and packaging it as a standalone
  Debian package.


  • If you are using the 32-bit version of Excelsior JET or Excelsior JET Embedded for Linux/ARM, make sure to change Architecture: to "i386" or "armhf" respectively.
  • Maintainer: has format "name <email-address>.
  • Installed-Size: expects size in kilobytes.

Data Files

During installation, the root directory of the data.tar archive maps onto the root of the target filesystem. For example, a file stored as foo/bar/baz would install into /foo/bar. The Linux File System Hierarchy Standard (FHS) dictates an add-on application software package to install in a separate /opt/package directory tree. Therefore all files in data.tar shall be placed in the opt/package subdirectory as follows:

Using JetPackII, create a directory /opt at the root of your project, and a subdirectory /opt/hello in it. Add or move the native executable to /opt/hello, and also move the /rt directory there from the root of the project. Then proceed to create a self-contained directory.

You can also achieve the same result using the xpack utility. Assuming the native executable is located in the current directory and called hello, issue the following command.

xpack -add-file hello /opt/hello  \
      -move-file /rt /opt/hello   \
      -profile auto               \
      -target ./data              \

Here, -profile auto selects the smallest suitable Java SE 8 Compact Profile (compact1 for "Hello, World"), -target specifies the pathname of the resulting self-contained directory, and -clean-target ensures that it contains no extra files.

At this point, you may wish to use the du command to obtain the right value for the Installed-Size: field in the master control file:

du -sk data

Putting It All Together

The self-contained directory produced by Excelsior JET (here ./data) goes into data.tar. However, the files and directories inside data.tar will have the same owner and group and the same permissions on target systems as they had during packaging. Fortunately, these are easy to normalize using tar flags:

tar cvfz data.tar.gz \
    --owner=root --group=root --mode=go=rX,u+rw,a-s \ 
    -C data .

control.tar contains just the file control. It is also a good idea to use the same tar flags so as to make builds reproducible on other systems:

tar cvfz control.tar.gz \
    --owner=root --group=root --mode=go=rX,u+rw,a-s \ 

Finally, run ar to create a Debian package:

ar rcDv hello_1.0.0_amd64.deb debian-binary control.tar.gz data.tar.gz

Here, r denotes the replace operation (if the archive does not exist, it gets created), c suppresses the warning that ar normally issues in case of archive absence, D makes the operation deterministic with regard to file timestamps, ownership and permissions, and v stands for "verbose".

To install the newly created package from the command line, run the command

sudo dpkg -i hello_1.0.0_amd64.deb

On systems with GUI, you can also double-click the .deb file.

To remove the package, issue the command:

sudo dpkg -r hello

or use the graphical software installation management tools, if available.


  1. The Linux File System Hierarchy Standard.
  2. deb-control(5) man page.
  3. Excelsior JET User’s Guide.

Article ID: 41
Last Revised On: 08-Aug-2018