Launch4j

Last updated Mar 14, 2003.

If you’re looking for more up-to-date information on this topic, please visit our Java article, podcast, and store pages.

I have often heard the question, "how can I run my Java program as a Windows executable?" If you search the Web on this topic, you'll find commercial and open source solutions as well as strong opinions on both sides of the "Java running native on Windows" polarity. On the pro-Windows side, the argument is that it can be too difficult for non-geeks to launch Java applications and on the anti-Windows side, the arguments are typically "why bother?" or a diatribe on the benefits of platform independence.

I called the argument a polarity for a reason: both poles have their merits and the optimal solution is a blending between the two. I am personally opposed to solutions that attempt to convert all classes and dependencies (libraries typically packaged as JAR files) as well as a JRE into a single executable file. There may be performance improvements (arguable), but there are too many things that can go wrong when writing applications from a pure Java perspective, such as when using dynamic class loading or other extendable architectures. So as not to discount the topic altogether, there are times when a native executable is desirable, such as when integrating a Java application into a native framework or simply providing Windows users a happy "EXE" file to click on.

The solution that I propose is the creation of a native process that finds a JRE and launches a Java class. With the strategy, both viewpoints can be satisfied: the Windows user has a familiar entry-point into the Java application, but without disrupting the integrity of the Java environment. In this article I discuss the creation of a native Windows executable using the open source project launch4j.

Introduction

While I have faced this problem in the past, my current motivation behind building a Windows launcher for my Java applications began with an exploration into "portable applications". Portable applications are applications designed to run on a portable device, such as on a USB thumb drive. The purpose of using portable applications is to enable you to move from computer to computer, with only your portable device, and bring your applications and data with you. For example, if you use Thunderbird as your email client, you not only want to bring the Thunderbird application with you, but you also want to bring all of your email. In this way you can work on a computer from your thumb drive without disrupting the computer and not worrying about leaving any of your data behind.

After purchasing an 8GB Patriot USB drive from eCOST.com, I downloaded a set of applications from PortableApps.com. The PortableApps Suite includes open source products such as Mozilla Firefox, Mozilla Thunderbird, GIMP, OpenOffice, VLC Media Player, Audacity, and more. As a user of all of these products I thought it was a great idea and began looking at how to integrate my Java applications into PortableApps and quickly learned that the PortableApps menu builds its menu dynamically by finding Windows executables in subdirectories below the "PortableApps" directory. That obviously presented a problem to me that could only be solved by creating a native Windows launcher file.

launch4j is an open source project available for download from SourceForge.net that presents itself as, "a cross-platform tool for wrapping Java applications distributed as jars in lightweight Windows native executables." It provides the capabilities to wrap a JAR file in an EXE or to simply create an EXE that finds a JRE and launches a Java application. It provides robust support for control over the CLASSPATH and environmental configuration options, such as heap settings and other JVM options, and it can be configured and run from a Swing GUI or it can be launched automatically by an Ant task. And as version 3.0 is being released and the project is almost four years old, it is a project that you can trust.

Building an executable with launch4j

As of this writing, the latest version is 3.0.0-pre2 and can be downloaded here. The easiest way to install launch4j is to download the win32 executable and launch it. Walk through the installation script and then launch the launch4j GUI. This presents the screen shown in figure 1.

The example that I am going to use in this article is my pure Java Music Player, named "JBox". JBox is packaged in a JAR named "JBox.jar" and has a slue of dependencies, such as JDOM, JoSQL, JLayer, an MP3 tag library reader, and so forth. Its icons are stored externally in JPG files and its configuration is maintained in an XML file, so it is simple in organization, but includes enough complexity to stretch the capabilities of launch4j. The deployment directory structure is defined as follows:

lib: this folder contains all application and dependency JAR files

icons: this folder contains all JPG images that the application uses for icons (at some point later they should be incorporated into another JAR file)

conf: this folder contains the XML configuration file for the application (held in a separate directory for later expansion)

Figure 1 shows the initial display when you launch launch4j, namely the basic tab. The first text box specifies the output file to generate. In this example, the JBox source code and build directories are contained in my "C:\projects\JBox" folder and then I build the aforementioned deployment directory structure in a "deploy" subdirectory. Therefore I set the target executable file to "C:\projects\JBox\deploy\JBox.exe".

The JAR file that contains the JBox class is located in the lib folder's JBox.jar file, hence the "Jar runtime path" is defined to be ".\lib\JBox.jar".

The "Don't wrap the jar, launch only" checkbox allows you to differentiate between the launching strategy I am proposing of a thin executable that launches a Java application and the conversion of your JAR file to an executable file. By checking this checkbox, you are telling launch4j to create a launcher only, not to include any Java classes in the executable.

The "Icon" text box allows you to associate an icon with your executable. If you do not have the facilities to create an ".ico" file, GIMP (available as a portable application) can convert a JPEG file to a Windows icon file for you (using the "File" -> "Save As" functionality).

Finally, I found it necessary in my tests to set the "Change dir" text field to the current directory, ".". This may be a bug in launch4j because the default behavior, if a "Change dir" value is not specified, is to set the working directory to that of the executable file. The real purpose of this text box is for the executable to change directories to a relative directory within your application to act as the "current working directory" for your application. Adding a "." to this field is an easy workaround, so I won't complain too loudly.

Hovering over the different text boxes will display usage information about each text box, so fill in values as appropriate for your application. When you're finished, click on the "Classpath" tab, which I have shown in figure 2.

The main class to execute in your application. In this example, the JBox class is contained in the com.javasrc.jbox.JBox class.

A list of CLASSPATH elements

If your application is not self-contained within a single JAR file, meaning that it needs additional JAR files or directories in its CLASSPATH, then click on the "Custom classpath" check box and define the CLASSPATH. The CLASSPATH elements are defined either in absolute directories or in relative directories to the "current working directory". In the sample application, all of the application and dependency JAR files are contained within the lib folder. You can click on the "New" button to create a new entry, type its path in the "Edit item" text box, and press "Enter" to add it to the CLASSPATH. If you need to change the order of the CLASSPATH elements, click on an item in the list and press the up or down arrow buttons.

The header tab contains a list of Windows components used during the linking phase of the executable file (recall that native applications require compilation and then linking with system libraries before constructing an executable.) You typically do not need to change anything on this tab, so we'll skip it and move on to the "JRE" tab, shown in figure 3.

The "Emb. JRE Path" defines the JRE path relative to the executable, or an absolute path. For now we'll leave this blank and rely on the underlying environment to already have an appropriate JRE installed. The "Min JRE version" text box defines the minimum requirements for the JRE required to launch the application and must be defined in the form:

X.X.X[_xx]

You are likewise permitted to define a maximum JRE version if there are known incompatibilities with your application and later JREs.

The initial and maximum heap sizes define the JVM options "-Xms" and "-Xmx", respectively. Remember that if you do not specify a maximum heap size, then your heap can only grow to the maximum size supported by the operating system (which in the case of Windows is a maximum heap size of 64 megabytes), so if you need more memory, this is the place to specify it. In the example I defined an initial heap of 16 megabytes that can climb up to 256 megabytes.

The "JVM Options" text box allows you to define any number of JVM options. For example, in this case I defined that the default look and feel for the application should be the "Windows look-and-feel", by defining the system property (-D) "swing.defaultlaf".

The "Set env. variables" tab, shown in figure 4, allows you to define any operating system environment variables that your application may need.

I am somewhat opposed to specifying a splash screen here and delegating that responsibility to the Windows executable file because that behavior would need to be somehow replicated in non-Windows environments. Instead I would suggest that you build the splash screen functionality into your Java applications directly. I covered building splash screens in my first book, Java 2 From Scratch (QUE, 1999), but if there is interest I can publish similar content here in the Java Reference Guide.

Windows executables can optionally display a set of versioning information, which can be specified in the "Version Info" tab, shown in figure 6.

When you are finished, click on the save button (the third icon on the toolbar that looks like a 3.5" floppy disk.) If you have any errors, they will be displayed at this point, and you need to resolve them before you are permitted save your file. Finally, click on the "Build wrapper" toolbar icon (right next to the save icon, it looks like a gear.) The "Log" message at the bottom of launch4j shows the status of the build (which is very fast) and will include "Successfully created: " on success.

Test your executable and enjoy!

Integrating launch4j into Ant

In the last installment we used the launch4j GUI to build an executable file
to launch a Java-based MP3 player. While the GUI was helpful in configuring the
options we wanted to incorporate into the executable, integration of the
launch4j functionality into an automated build is more desirable. Otherwise,
after routine builds complete, we would need to manually open launch4j and
generate our executable.

Luckily launch4j can be executed in an Ant build script using a custom
launch4j Ant task. It takes as input an XML file describing how to build the
executable file, which, not coincidentally, is the format of the file generated
by the launch4j GUI application. Thus we can use the launch4j user interface to
generate an XML file that can be used in our automated build script.

The GUI provides a nice wrapper around the XML file, but before continuing,
let's review the components of the XML file. Listing 1 shows the contents
to my launch4j.xml file.

The things that I changed between the previous section and this one are the
destination EXE file to ".\dist\JBox.exe" and the source JAR file to
".\dist\lib\JBox.jar" to match my build script and I changed the
location of the embedded JRE to "..\..\java\jre", but more on that
later. This XML file is divided into the following sections:

Header: I am grouping the first several entries into a header category
because they do not have too much in common. This section includes our option to
not wrap our JAR file inside an EXE (<dontWrapJar>), the header type is
GUI, the location of the source JAR file and destination EXE, the icon file for
the EXE, and so forth.

Classpath: this section lists all of the JAR files or directories to add to
your CLASSPATH at run time. Note that launch4j is not compiling your source
code, so this is not a list of JAR files for compilation. This list includes the
locations of all JAR files when the application launches. In this example, all
JAR files will be located in a lib directory located directly under the
resultant EXE file. This section also includes the name of the main class for
the EXE to launch.

JRE: this section specifies information about the location and
characteristics (such as minimum and maximum JRE versions) of the JRE that will
be used to launch the main class of the application. If you leave the path blank
then the EXE will pick up the first JRE that it can find that meets your
criteria (the version is between the minimum and maximum specifications), but in
this case I have specified that there will be a specific JRE located two
directories above the EXE in the java/jre directory. I will discuss this more
next week, but as a sneak preview, this is part of my portable application
integration.

Version Info: this section defines the version and copyright information
that will be embedded into the EXE

With this XML file built, Ant integration is a very straightforward
procedure. Ant integration is typically performed in two steps:

Import an Ant task

Call the Ant task inside of one of your targets

Launch4j includes an Ant task that is implemented by its
net.sf.launch4j.ant.Launch4jTask class. In order to import this Ant
task, you need to include two of its JAR files: launch4j.jar and
xstream.jar, which are located in the launch4j installation directory
hierarchy. If you installed launch4j from the installation file on Windows then
the default installation location is: "C:\Program Files\Launch4j".
Therefore, to import the launch4j Ant task, add the following snippet to your
Ant build script:

The taskdef Ant command defines a new task that is implemented by
the specified "classname". In this case we included the two
required JAR files in the CLASSPATH to satisfy the task definition. All that is
left is to execute the launch4j Ant task inside one of our targets. In
its simplest form, the launch4j task accepts a sole "configFile"
attribute that references the launch4j.xml file that we created earlier. Thus
the following snippet creates a new "exe" target that exercises the
launch4j task:

In this example, my launch4j.xml is in the same directory as my
build.xml file. Again, the instructions on how to build the executable
are all contained in the launch4j.xml file. The Ant task allows you to
embed the entire contents of the launch4j.xml file, but doing so precludes you
from using the GUI to edit it. On the other hand, there are a handful of common
options that you can override in the task itself. Namely when building an EXE
you might want to change versioning information to match your build. Thus the
following attributes can be added to the launch4j task:

jar

jarPath

outfile

fileVersion

txtFileVersion

productVersion

txtProductVersion

bindir

tmpdir

The majority of these attributes allow you to change the version information
to be embedded in your executable for your build. This is a good place to add
the specific build number, which may already be in your build script.

Portable Java Applications

I have spent a considerable amount of time in the past few articles
discussing the process of building a Windows executable to launch your Java
applications. While this is a good feature in and of itself, there is a specific
application of this technology that inspired me to dedicate time to it: portable
applications.

A portable application, simply put, is an application that runs on a portable
device, such as a USB drive. The challenge in converting a standard application
to a portable application is in both removing its environmental dependencies as
well as redirecting its own resource requests to the portable device. For
example, a Windows application may need libraries that may not be available on
the host system or the application may store information in the user's home
directory. The application needs to be packaged with its dependencies and then
configured to store its stateful information on the portable device.

The premier source for open source applications configured to run on a
portable device is
PortableApps.com.
PortableApps combines the best in open source applications, including Mozilla
Firefox and Thunderbird, GIMP, FileZilla, Audacity, MPlayer, VLC Player,
OpenOffice, and a dozen other titles that you can
review here.
The benefits to installing PortableApp's suite of products are two-fold:
the applications have been preconfigured to run on a portable device and it
includes a menu application that automatically discovers portable applications
and adds "start menu"-like functionality that can be launched from
your Windows system tray.

Java applications provide a distinct advantage, which is also its greatest
limitation in providing support for portable applications. Because Java
applications run inside a Java Virtual Machine, the only system dependency that
a Java application has is the Java Virtual Machine itself (you can easily
include dependent JAR files on the portable device.) Thus, as long as you can
bundle a Java Runtime Engine with your application, you do not need to be
concerned with Windows system dependencies. The challenge is that the Java
Runtime Engine is large, the JRE that I extracted from Java SE 6 was almost 80
megabytes.

The good news is that USB drives are becoming more and more affordable. If
you search
eCOST.com for
"USB Flash Drive" and review the "Storage" results, you will
find a 4GB or 8GB flash drive for well under $100. At the time of this writing I
bought a Patriot Memory 8GB drive that, after rebates, was less than $70. In
order to run Java applications from a USB drive you will need plenty of space,
and I would not recommend using anything under one gigabyte of storage, although
it is technically possible.

In this article I demonstrate how to integrate a Java application into
PortableApps using launch4j and then propose a strategy to help you deploy
multiple Java applications to a portable device while minimizing their overall
footprint on the drive.

Before we begin, you will need to obtain a portable device and install the
PortableApps suite on it. You can download PortableApps from the following
URL:

[lb] Standard Edition: this installation includes the PortableApps menu as
well as the most common portable applications, including Firefox, Thunderbird,
and OpenOffice. They claim it runs comfortably on a 512MB flash drive.

[lb] Lite Edition: for the more conservative flash drive, this edition
substitutes AbiWord in place of OpenOffice and runes comfortably on a 256MB
flash drive.

[lb] Base Edition: the version includes the PortableApps menu application
as well as the directory hierarchies so that you can customize the applications
you want installed

Depending on the applications you use and the size of the flash drive you
have choose the most appropriate installation. Launch the installation file and
point it to your portable device. You can add additional applications to
PortableApps by downloading the installation file from the PortableApps web site
and then clicking on the "Options" button (on the right) and choosing
"Install a New App". You can manually install it, but this method
ensures that everything is installed in the correct location and it causes the
PortableApps menu to refresh itself automatically.

After you've had time to peruse your portable applications, let's
review the requirements for building an application compatible with
PortableApps. The directory structure that PortableApps creates on your portable
device is as follows:

In order to add a new application to the PortableApps menu, you need to
create a new directory in the "PortableApps" directory and include an
executable file for the PortableApps menu to launch (it only launches EXE files,
which is why we need launch4j to create an EXE for us.) But before building an
EXE as we did in the last couple articles, we need to consider the footprint of
a JRE on our portable device. Although portable devices are becoming cheaper and
storage space is increasing, it does not mean that we should abuse it by using
unnecessary space. As mentioned previously, the JRE included with the Java SE 6
is approximately 80MB, so it would be in our best interest to reuse a single JRE
for all of our applications.

Fortunately, one of the features of launch4j is that you can specify the
absolute or relative directory of the JRE to use to launch your application.
Thus I propose the following solution: create a "java" folder in the
root of your portable device and create a "jre" subfolder that
contains the JRE to use when launching your application. Furthermore, I propose
that we include a "lib" folder to contain commonly used JAR files. So
the final directory structure will look like this:

By now I am sure that you have a JRE installed somewhere on your computer,
but if not then download one from java.sun.com. The default installation
location for both JREs as well as JDKs (which you can use in this case too) is
"C:\Program Files\java\jdk|jre version number", for example:

C:\Program Files\java\jre1.6.0_01

Copy the contents of this folder, which will include a "bin" and a
"lib" folder to the jre folder of your portable device. In the end you
should have the following directory on your portable device:

java \jre
\lib
\bin
LICENSE
LICENSE...

Now we need to build an EXE that uses this JRE. Recall from the last article
that the script that controls how an EXE is built is contained in an XML, named
launch4j.xml by default. My launch4j.xml file for the JBox Music Player is shown
in listing 2.

The important thing to notice in this script is that the path of the JRE is
defined to be "..\..\java\jre", or looking at our directory structure
again:

PortableApps \JBox
JBoxPortable.exe
java \jre

The path goes from JBoxPortable.exe to the JRE that we just copied to
"java\jre". Now when we execute this script (see the two previous
articles in this series), the resultant EXE is configured to use this specific
JRE. Create a directory in the PortableApps directory and copy this EXE to it,
including the required JAR files, and then either restart the PortableApps menu
or choose "Options" and then "Refresh App Icons" and you
should see your executable file. Figure 1 shows a screenshot of the PortableApps
menu with my "JBox Music Player Portable" running in it.

Summary

Launch4j allows you to create Windows executables that launch your Java
applications. In the first article I presented a step-by-step example that
created an executable using the launch4j graphical user interface. In the next
article I reviewed the underlying XML file that drives launch4j and look at how
to integrate launch4j into an Ant script for the automated generation of a
Windows executable. And in this article, I demonstrated how to deploy your Java
applications to a portable device using the PortableApps.com, including a shared
JRE to conserve precious space on a portable device.