How to make a JAR file Linux executable (Example) (original) (raw)
Every Java programmer knows - or should known - that it is possible to create a runnable Java package archive (JAR), so that in order to launch an application it is enough to specify the jar file name on the Java interpreter command line along with the -jar
parameter. For example:
$ java -jar helloworld.jar
There are plenty of tutorials showing how to implement this feature using Ant, Maven, Eclipse, Netbens, etc.
Anyway in its basic form, it just requires to add a MANIFEST.MF
file to the jar package. The manifest must contain an entry Main-Class
that specifies which is the class defining the main method for your application. For example:
$ javac HelloWorld.java
$ echo Main-Class: HelloWorld > MANIFEST.MF
$ jar -cvmf MANIFEST.MF helloworld.jar HelloWorld.class
But this still requires your users to invoke the Java interpreter with the -jar
option. There are many reasons why it would be preferable to have your app runnable by simply invoking it on the terminal shell like any other command.
Here comes the protip!
This technique it is based on the ability to append a generic binary payload to a Linux shell script. Read more about this here: http://www.linuxjournal.com/content/add-binary-payload-your-shell-scripts
Taking advantage of this possibility the trick is just to embed a runnable jar file into a Bash script file. The script when executed will launch the Java interpreter specifying itself as the jar to run. Too complex? Much more easier to do in practice, than to explain!
Let's say that you have a runnable jar named helloworld.jar
Copy the Bash script below to a file named stub.sh
#!/bin/sh
MYSELF=`which "$0" 2>/dev/null`
[ <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">?</mo><mo>−</mo><mi>g</mi><mi>t</mi><mn>0</mn><mo>−</mo><mi>a</mi><mo>−</mo><mi>f</mi><mi mathvariant="normal">"</mi></mrow><annotation encoding="application/x-tex">? -gt 0 -a -f "</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mclose">?</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8389em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">t</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6667em;vertical-align:-0.0833em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mord">"</span></span></span></span>0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mi>a</mi><mi>v</mi><msub><mi>a</mi><mi>a</mi></msub><mi>r</mi><mi>g</mi><mi>s</mi><mo>−</mo><mi>j</mi><mi>a</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">java_args -jar </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">ja</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">a</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.854em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">ja</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span></span>MYSELF "$@"
exit 1
Than append the jar file to the saved script and grant the execute permission to the file resulting with the following command:
cat stub.sh helloworld.jar > hello.run && chmod +x helloworld.run
That's all!
Now you can execute the app just typing helloworld.run
on your shell terminal.
The script is smart enough to pass any command line parameters to the Java application transparently. Cool! Isn't it ?!
In the case your are a Windows guy, obviously this will not work (except you will run a Linux compatibility layer like Cygwin).
Anyway exist tools that are able to wrap a Java application into a native Windows .exe
binary file, producing a result similar to the one explained in this tutorial. See for example http://launch4j.sourceforge.net/