Standalone Java programs on Unix systems (now with C code!)

Standalone Java programs on Unix systems (now with C code!)

Have you ever wanted to package up your Java code and have it look like an executable? Here is an easy way to do it.

First make an executable jar file of your java program. The easiest way to do this is to make a new directory, unjar all of your classes into it. I’ll use groovy as an example:

/Users/sam/tmp/groovyshell/classes:> jar xf /Users/sam/Projects/groovy-dev/target/install/lib/groovy-1.0-beta-3-snapshot.jar 
/Users/sam/tmp/groovyshell/classes:> jar xf /Users/sam/Projects/groovy-dev/target/install/lib/asm-1.4.1.jar 
/Users/sam/tmp/groovyshell/classes:> cd ..

Now we need a manifest with the main class that we want to run:

/Users/sam/tmp/groovyshell:> cat > manifest
Main-Class: groovy.lang.GroovyShell

Then jar up this new concoction so that you have an executable jar file:

/Users/sam/tmp/groovyshell:> jar cmf manifest groovy.jar -C classes .

You can check it with:

/Users/sam/tmp/groovyshell:> java -jar groovy.jar 
Usage: Groovy groovyScript [arguments]

Now that we see that it works, we make a simple shell script I will call

/Users/sam/tmp/groovyshell:> cat >
java -jar $0 $*

Now here is the magic that you may not have seen before. As it turns out, jar always uses the end of the file for the index. It is legal to put it at the beginning, but not needed. So what we do is we just append the executable jar onto our script:

/Users/sam/tmp/groovyshell:> cat > groovy groovy.jar 

That gives us a new file, groovy , that we can make executable:

/Users/sam/tmp/groovyshell:> chmod +x groovy

And now we can execute this:

/Users/sam/tmp/groovyshell:> echo > hello.groovy ‘println(“Hello, world”)’
/Users/sam/tmp/groovyshell:> groovy hello.groovy
“Hello, world”

This should work, in general, for any script that you want to attack java classes to. It doesn’t really have to be executable, but that makes the script more generic. This was all done on Mac OS X but I copied it to my Linux box and verified it works there as well. Not sure if it works on bash on Windows.


One of the things I noticed about using a script instead of an executable is that you can’t reference them in other scripts. For instance, if you use the script above, you can’t put it in your /bin directory and make a groovy script like:

println(“Hello, world!”)

It will give you archaic shell error that I won’t repeat here for decency’s sake. Instead you will need a C program:

#include <errno.h>

int main(int argc, char* argv[]) {
 int i;
 char* argv2[argc+3];
 argv2[0] = “java”;
 argv2[1] = “-jar”;
 argv2[2] = argv[0];
 for (i = 1;i < argc; i ++) {
 argv2[i+2] = argv[i];
 argv2[argc+2] = 0;
 execvp(“java”, argv2);
 printf(“Cannot execute ‘”);
 for (i = 0;i < argc+2; i ++) { printf(“%s “, argv2[i]); }
 printf(“’, caused by error: %d\n”, errno);

Compile this with ‘gcc -o base base.c’ use cat to append the .jar file to it, voila, you have your own groovy executable that you can use in scripts:

/Users/sam/tmp/groovyshell:> ./test
“Hello, world!”

Pretty convenient! I’m sure there is some Windows equivalent that someone could throw together.