Convert Java to EXE
Why, When, When Not and How
By Dmitry LESKOV
CONTENTS
Introduction
Simplify Java Application Deployment
Executable Jars
Java Web Start
Custom Java Launchers And Wrappers
Java-Aware Setup Authoring Tools
Ahead-Of-Time Compilers
"How do I make an .EXE file from my Java application?", "Need help converting jar to exe", "Is it possible to create a Windows executable using Java?" --- these and similar questions are among the most popular topics on Java developer forums. Should you start such a topic today, you are likely to encounter the following three types of replies:
- "You cannot"
- "You should not, because that would kill the very purpose of Java"
- "You can do that with third party software X and Y"
The truth is that there exist two completely different approaches to the creation of native executables from Java applications, addressing different sets of problems. Moreover, under certain conditions some of those problems may be solved without making an EXE. So the most correct way to reply to such a post would be a request for more information, namely what is the goal of conversion to EXE. And the most frequent answer would be
Simplify Java Application Deployment
Java compiles to platform-independent bytecode (.class files), which is not directly supported by PC hardware. So a Java program needs a Java Runtime Environment (JRE) to run, which would either interpret the bytecode instructions or compile them to native code on the fly. This in turn means that the author of that program has to ensure somehow that the proper version of the JRE is installed on an end user system.
In a general case you may not expect that your end users will know what a JRE is, how to check its version, and how to download and install it. This is especially true for consumer applications, such as games or multimedia. And those who already have a JRE installed may not like the idea about installing a different version, because it may break their existing Java applications and favorite applets.
Then, even if you can make sure the right version of the JRE is properly installed on enduser systems, which is quite possible in a classroom or enterprise environment, the command line required to launch your Java application can be quite long:
java -Xmx200m -cp whatever.jar -Dsome.property MyApp
Yes, you may put that line into a batch file and call it runme.bat, but it looks so much easier to give your program to a friend, teacher or colleague as a single file that can be run by a double-click. Or, even better, enable it to be installed and uninstalled in a native manner without affecting other applications.
So it comes as no surprise that the primary motivation for seeking a way to convert a Java application into an EXE file is to make its deployment and use simpler and safer for an average user, that is, a Windows user. What surprises newbie Java developers is that the JDK does not offer such functionality. Before J2SE 1.4, all you could make with JDK tools were
Executable Jars
Pros
No need to use any third-party tools
Single distribution for all Java-enabled platforms
Cons
Application will not start on systems that do not have a JRE (properly) installed
Application will not work if it uses APIs absent in the default JRE
Need to teach users that .JAR files are clickable
Resources
The Java Archive (JAR) File Format
Tools
One-JAR
Autojar
Fat Jar
Java Launcher
You can make your Java application runnable via a double-click by packaging it into a so called
executable jar. You do that by specifying the main class of your application, any extra jar files it may require and so on in the jar's
manifest file
Main-Class: MyAppMain
Class-Path: mylib.jar
Then you use the jar utility from the Java SDK to package your classes and resource files, specifying the m option and the name of your manifest file:
jar cvfm MyApp.jar MyApp.mf *.class *.gif
This will result in the creation of MyApp.jar. Now, if you type
java -jar MyApp.jar
the Java launcher will read the manifest from MyApp.jar and invoke the main method from the class
MyAppMain. Moreover, if you double-click that jar file on a system that has JRE installed, the java launcher will be invoked automatically.
Note: As of J2SE 5.0, jar files are associated with the javaw launcher on Windows, which does not open a console on startup. If your application needs a console, write a batch file which would start it using the java launcher
.
If your application consists of more than one jar file, there is an open source tool called
One-JAR that claims to correctly
repackage multiple jars into one.
The major problem with executable jars is compatibility. The default JRE may be of an older version than is required by your application or may not have the necessary Java Optional Packages (previously known as Standard Extensions) installed. For instance, if your app uses the java.nio package introduced in Java 2 version 1.4, it will not work on JRE 1.3.x. Similarly, if it uses JavaMail 1.3, and the default JRE has JavaMail 1.2 or JavaMail is not present at all, the double-clicked jar will not run.
Fortunately, Sun has created a Java application deployment technology that eliminates this compatibility problem and adds some nice features. It is part of the Java 2 platform since version 1.4 and is called
Java Web Start
Pros
Available for all major desktop platforms
Single distribution for all JWS-enabled platforms
Code-signing and sandboxing
Versioning and incremental updates
Automatic installation of JREs and optional packages
Use of third-party tools is optional
Cons
Internet connectivity required if JWS, JRE, and/or an Optional Package is not present on the system
Support for jnlp MIME type required on both Web server and browser
Limited desktop integration capabilities
Resources
JWS Technology Home
Deploying Software with JNLP and JavaT Web Start
Java Web Start
(Roedy Green's Java Glossary)
Tools
Xito Application Manager
DeployDirector
Java Web Start (JWS) and the underlying
Java Network Launch Protocol (JNLP) enable Java application delivery from a standard Web server. The end user initiates application installation by clicking on an URL. If the Java Web Start engine is not present on the system, the user is prompted to download and install it. Once Java Web Start is in place, clicking on the same URL will initiate the application download and installation procedures. It may involve download and installation of the required version of the JRE and Optional Packages. Upon their successful completion, the application is launched. The application will be cached on the user's system so next time the user clicks on the same URL, the JWS engine will launch the local copy of the application from the cache, if it detects that the computer is offline or the application was not updated on the Web site
.
Another important feature of JWS is its ability to run your application in a
sandbox - a restricted container based on Java security architecture. But, unlike an applet, your application can gain access to local system resources like the filesystem, printer and system clipboard using the JNLP API even if it comes from an untrusted environment, after prompting the user for confirmation.
Java Web Start is available for Windows, Linux, and Solaris, and is part of MacOS X since v10.1. There are also third-party implementations of the JNLP protocol, some of them also include tools that assist you in the creation and maintenance of JNLP packages.
That was the bright side. Now, what is not so good about JNLP? First off, for seamless operation both the browser and the Web server that hosts the JNLP-enabled application must support application/x-java-jnlp-file MIME type. Some hosting providers do not support it. Moreover, versioning and incremental updates require additional support from the Web server, which has to be implemented using servlets, cgi-bin scripts, etc.
On the client side, a major browser would be configured to recognize the above MIME type during installation of the JWS engine, but users of less popular browsers, such as Opera, may have to do that manually.
JNLP-enabling an application may involve minor changes in its code and (re)packaging it into a set of jar files.
Before J2SE 5.0, JWS had very little to offer in terms of desktop integration - all it could do was create a desktop icon and/or a Start Menu entry for the application. On Windows, the application will not show up in Add/Remove Programs, so end users would have to run the Java Web Start application manager in order to remove your application.
Finally, JWS user interface needs much polishing. As of J2SE 5.0, users still complain about ugly windows with incomprehensible messages.
To sum it up, JWS can be a viable option in a controlled environment, such as corporate intranet, but it is not ready for the consumer market, where you may be better off using
Custom Java Launchers And Wrappers
Pros
JRE version check
JRE download or bundling
Unique process name and icon
No end-user training
Cons
Platform specific
Desktop integration capabilities absent or very limited
Resources
JNI 5.0 Specification
JNI Tutorial
Tools
Commercial:
JEXECreator
exe4J
NativeJ
execJava
Executor
JExePack
Jlaunch
Free:
JSmooth
Launch4j
jstart32
exeJ
Java Launcher
Janel
jstart
Roxes Ant Tasks
Marner Java Launcher
jelude
When a Java program is invoked using one of the methods discussed above (batch file, executable jar, or Java Web Start/JNLP), the operating system runs a Java launcher from the JRE. The Windows version of the JRE has separate launchers for command-line and GUI apps, called java.exe and javaw.exe respectively.
As a result, all running Java applications have the same Taskbar/Alt-Tab icons and appear in the Windows Task Manager as either java.exe or javaw.exe. If you have two or more Java apps running, you have no means to distinguish between multiple instances of the standard Java launcher in the Task Manager.
In fact, those launchers are just small native programs that load the Java Virtual Machine from a DLL/shared library and then feed your program to that JVM using the Invocation API. That API is part of the
Java Native Interface (JNI), so it is standardized, and it is also very simple. This makes it relatively easy to write your own launcher with a unique name and icon. What it has to do is find a suitable JRE on the end user's system (unless you bundle the JRE with your application), load and initialize the JVM, and run your application on it.
If you do not have the right tools, skills, or time to develop a custom launcher for your Java application, there are quite a few third-party Java launcher generators listed in the Tools section of the frame. Some of them provide additional features such as instant splash screen, stdout and stderr redirection, and so on, the most notable being
wrapping.
A Java wrapper in essentially a custom Java launcher that is also a self-extracting archive containing all the application's classes, jars and auxiliary files. The wrapper unpacks those files on startup and removes on termination. This way, your application is distributed as a single executable.
A wrapper normally looks up the JRE upon startup. If the JRE is not present or its version does not match the application's compatibility requirements, some wrappers may install the JRE (if you have included it when wrapping your application) and/or download and install the required version of the JRE.
The most sophisticated wrappers may also setup file associations and create shortcuts on first run. But if you need something more complex, such as support for automatic updates or uniform cross-platform deployment, have a look at
Java-Aware Setup Authoring Tools
Pros
Complete desktop integration
Can be platform-specific or cross-platform
Localization support
Flexibility
Cons
Requires third-party tools which may be too pricey and/or complex
Resources
AppDeploy.com
Tools
install4j
IzPack
InstallAnywhere
InstallShield
Advanced Installer for Java
JExpress
If all you need is install a private copy of the JRE alongside your application and create shortcuts that run your application on that JRE, you may use any setup generator. However, using a Java-aware tool may give you the following benefits:
- Install-time JRE detection and download
- Generation of native launchers
- User-editable JVM parameter files
- Redirection of stderr and stdout for saving logs and exception stack traces.
- Registration of Java applications as Windows services and Unix daemons
This category is the most diversified in terms of tool pricing and functionality. The differences are explained below by example.
Windows-centric tools, such as
Advanced Installer for Java enable you to build MSI (Windows Installer) packages.
Multi-platform tools can generate native installers for multiple platforms - Windows, Linux, Mac OS X, as well as RPMs and tarballs.
install4j is one such tool.
There exist also Java-based setup authoring tools enabling you to create
cross-platform installations, Those installations are essentially
executable jars with platform-specific logic selected at run time.
InstallAnywhere is perhaps the most well known tool of this type, but if its pricing is beyond your budget, consider the cheaper
JExpress or the open source
IzPack.
Finally, there is One Tool to Rule Them All -
InstallShield, which can create both
Windows desktop (MSI) and cross-platform installations, plus
server and
mobile ones, for any type of application and for a multitude of platforms. And yes, it does support JRE lookup and bundling, native launchers, and so on.
For straightforward installations, however, InstallShield is an overkill. Also note that InstallAnywhere and InstallShield are aimed at the enterprise developer and are priced accordingly.
All the above solutions do not change the fundamental principle mentioned in the first section of this article. Whether you make an executable jar or create a sophisitacted installer, your Java program is still deployed as platform-independent bytecode. In the early days of Java, the only way to execute a Java program on a common PC hardware was to interpret that bytecode. Today, any decent J2SE implementation contains a Just-In-Time (JIT) compiler that compiles frequently executed methods to native code. So it sounds quite natural to take one step further and compile the entire application down to native code
before it is deployed. Such tools exist and they are called
Ahead-Of-Time Compilers
Pros
Performance increase
IP protection
Better user perception
Native deployment
Cons
Limited applicability
Misconceptions
Disk footprint increase
Portability loss
Resources
Improving Swing Performance: JIT vs AOT Compilation
Cracking Java byte-code encryption
Tools
Excelsior JET
GCJ
NewMonics PERC
AOT compilers are known also as "static compilers" and "native code compilers". The latter term is the most used and, as it often happens, the least correct from the technical standpoint, because JIT compilers also produce native code.
An Ahead-Of-Time (AOT) compiler takes as input your jars and class files and produces a conventional native executable for the target platform, such as Windows EXE or Linux ELF binary. Just like any other technical solution, this has its advantages and drawbacks.
Advantages
- Performance. A JIT compiler works at application's runtime and shares CPU and memory resources with the application it compiles and possibly other applications. An AOT compiler runs on the developer's system with no resource or compilation time constraints. Therefore it can potentially use more powerful resource-intensive optimizations, yielding better code.
- Intellectual Property Protection. Java bytecode is very easy to decompile - just google for "download java decompiler" and you will get your source code back in 5 minutes. Yes, you may obfuscate names of public classes and methods not accessed via reflection, but control flow obfuscation can render your bytecode unverifiable on future JVMs and hinders optimizations implemented in JIT compilers. Finally, encrypting your Java bytecode does not protect it at all regardless of the encryption algorithm you use. In contrast, native code produced by an optimizing AOT Java compiler is about as hard to reverse engineer as if you have coded the original program in C++. Needless to say, there is no performance loss. If you are concerned about protecting your intellectual property, have a closer look at native compilation.
- User Perception. Java client applications often suffer from the so called warm-up cycle syndrome. Starting up a Java application involves bytecode interpretation, profiling and JIT-compilation. So Java programs tend to start much longer than their native counterparts and the initial response time of a Java app GUI element is much worse than after it has been used several times, which are the two major reasons for Java is still perceived as slow by many users. A native executable runs directly on hardware, without the interpret-profile-compile overhead, so it may start faster and immediately demonstrates the best response times.
- Native deployment. Even the most sophisticated Java-aware setup tools have to generate native launchers for better desktop integration, and may need to take care of the JRE download and installation. Executables produced by an AOT Java compiler do not depend on the JRE and can be deployed using any setup authoring tool available for the target platform. Moreover, AOT compilers may come with specifically tailored setup generators that create compact, professional installers.
Drawbacks
- Dynamic applications. Classes that the application loads dynamically at runtime may be unavailable to the application developer. These can be third-party plug-ins, dynamic proxies and other classes generated at runtime and so on. So the runtime system has to include a Java bytecode interpreter and/or a JIT compiler. Moreover, in the general case only classes that are loaded by either system or application classloader may be precompiled to native code. So applications that use custom classloaders extensively may only be partially precompiled.
- Hardware-specific optimizations. A JIT compiler has a potential advantage over AOT compilers in that it can select code generation patterns according to the actual hardware on which the application is executing. For instance, it may use Intel MMX/SSE/SSE2 extensions to speedup floating point calculations. An AOT compiler must either produce code for the lowest common denominator or apply versioning to the most CPU-intensive methods, which may result in code size increase.
Misconceptions
Java bytecode had been originally designed for compactness, so it has a much higher level than a typical CPU instruction set and takes less space than the equivalent machine code for a real-world general purpose processor, such as Intel x86. But Java class files contain not only code. The amount of symbolic information in Java class files has grown dramatically over the years due to the development of numerous APIs and their package structure. So now there is not much difference in disk footprint between the original and AOT-compiled forms of an application, and the download size can be even
smaller than the size of the JRE.
There is also a common misconception that AOT compilation kills Java portability. This is not the case, because the source code need not be changed, so you can always deploy your application as bytecode to a platform for which you do not have an AOT compiler. (This would of course blow the advantage of IP protection away.)
Tools
There used to be half a dozen AOT Java compilers on the market in the year 2000, but the only two that have survived are
Excelsior JET and
GCJ (GNU Compiler for Java). (If you are in the embedded field, check out
NewMonics PERC, which targets J2ME CDC and also has limited support for J2SE 1.3.)
Disclaimer:
I work for the company that makes Excelsior JET, so skip the rest of the article if you believe it is going to be a shameless plug.
Product Comparison
Target Platforms. As of July 2006, the official
GCJ Status page lists 15 supported targets, from "bare metal" ARM and XScale to IBM s390x mainframes. Some of the targets, most notably Windows, are not fully supported, though. Excelsior JET supports Windows and Linux on Intel x86 at the moment. The Windows version has been on the market since the year 2000, so it is more mature than the Linux version, introduced in 2004.
Standard Compliance. GCJ has not passed the Sun's official Java Compatibility Kit (JCK) test suite and is quite far from even attempting to do that. The major reason is that the GCJ runtime library, libgcj, is an open source clean-room implementation of the core Java API classes, and thus is way behind Sun developments. At the moment GCJ may only compile graphical applications built using third-party AWT-independent GUI toolkits, such as
SWT.
libgcj is being slowly merged with
GNU Classpath. The
unofficial compatibility testing results for GNU Classpath claim that it includes most, but not all of the JDK 1.4 API features as of July 2006. Note however that the data used to back that claim is
not being produced by running the JCK, so they can only confirm
availability, not
compatibility of the respective APIs.
Excelsior is a
Java Authorized Licensee, and its product uses the licensed Sun's implementation of the Java SE 5.0 API. Excelsior JET is
certified Java Compatible on a number of Windows and Linux platforms.
Dynamic Class Loading. Both products support dynamic class loading. The GCJ runtime runs dynamically loaded clases on an interpreter, whereas the Excelsior JET runtime features a JIT compiler. The latter may cache compilation results to disk and reuse them on subsequent application launches.
Deployment facilities. GCJ is just a compiler; you are responsible for choosing a third-party deployment tool and setting it up for packaging of the executables GCJ produces.
Excelsior JET includes a toolkit that enables you to create
compact Windows and Linux installers, or integrate easily with third-party setup generators. You may also compile your Java applications into Windows services.
Price. GCJ and libgcj are open source (GPL) and therefore can be freely downloaded, modified and distributed. Note that 'libgcc exception' applies to libgcj, so linking with it does not by itself cause your program to fall under the GPL.
Commercial use Excelsior JET licenses start from $1,200 per developer. Deployment to general purpose desktops and servers is royalty-free, but runtime fees apply if you deploy your application to embedded systems.
Academic Licenses are available for education and non-commercial research use. A single-platform, single-seat Academic License is priced at $100;
Academic Site Licenses are also available.
This concludes the article. I update it regularly, so if you have any comments or know of resource/tools URLs which I should have added, please send them to me. (
dleskov@excelsior-usa.com)