The Shell Script Launcher, In Detail
I recently re-worked the shell script launcher for Big Block Engine, so I wanted to share it and explain what it does in general. You'll find the complete file at the end of this post, in a code block. The script itself is released as public domain, so if it's useful to you, do as you please with it. There's no need to give credit, but a link to Big Block Engine would make me happy.
As any Java developer knows, getting your application to run the way you want on multiple platforms can sometimes be a pain, especially when you factor in users that don't know what they're doing. I've seen a great many solutions to this problem, including shell scripts for Linux, batch files on Windows and custom EXE launchers, also for Windows. I find that many fall short of the actual goal of starting their bundled application in some way or another. Just the other day, I spent roughly an hour or two fighting to get a very old java program running on a modern system, because it's shell script just didn't work and it's main jar file wasn't built to be runnable.
The shell script here is the one I made for this onerous job.
What this script does:
- Detecting a Java Virtual Machine (JVM)
- Bundled JVM is checked for first
- JVM found via 'JAVA_HOME' environment variable
- JVM found via the 'PATH' environment variable, if all else fails
- Checking the version of the JVM, for compatibility's sake
- Checking for an X Server 'DISPLAY' environment variable
- Does one of the following:
- Launch the game via it's main jar file
- Inform the user of any failures
- Via the terminal, if there is one
- Via a simple dialog box, if there is no terminal and an X Server is available
Optionally, you can modify the script slightly and use the 'cat' command to combine the script together with the main jar, to make a runnable jar file into a executable! This is described in the script itself as using the jar as a binary payload.
It also determines if the script is running on a terminal and sets a property that my game engine pays attention to to determine whether it should displays it's log via a window or not, but this is specific to my game engine.
What this script DOES NOT do:
- Prepare and use a 'CLASSPATH' variable for launching an application
- Launch an application via unpackaged, naked class files
- Launch an application by knowing the name of it's main class
All of the above things it doesn't do are the job of the application's main Jar file and should be setup via it's manifest file, by the developer. Most of the troubles I've seen people have with launching Java applications were because the developer that wrote the application didn't understand that a jar file does all this work, if properly prepared. Heck, if a jar file is properly prepared, under Windows, you can double click the jar file and it will just start! The manifest is just a text file dropped into the Jar file along with the class files! It tells Java the name of the main class and can even be used to setup the class-path for the application. Library Jar files also have a manifest, which can add additional Jar files to the class-path. There really is nothing special about a Jar manifest, aside from correct formatting, which is easy.
Sorry if that last paragraph was a bit of a rant. It's been an annoyance to me for about 18 years and sadly, I don't see it changing any time soon.
In conclusion, I hope this script will make the job of other Java developers easier. I hope it will also make the lives of end-users easier.
This takes care of the Linux side of things, providing an easy and reliable script to launch a java application. If you want a simple approach to launching Java applications for Windows, I suggest Launch4j, which is what I've used for this project to provide EXE launchers, since that's what the average Windows user will be expecting.
I am looking for something similar to make a launcher for the Mac OS, but I've never owned a Mac and couldn't test it even if I knew what to do. If you have some idea of how this kind of thing is done on a Mac, please comment and let me know.
#!/bin/bash # This shell script is released into the Public Domain; if it does you any good, # feel free to use and/or modify it # This script does a bunch of sanity checking and then launches the target JAR # file for a Java application # If the environment is not sane, it gives some useful feedback on the problem, # using Zenity to display a dialog box, if available and not run from a terminal # The main purpose of this is to notify a user when Java isn't installed or # likely isn't installed correctly; there's also a check for an X server, for # GUI applications to fail early on with a decent error message, instead of # throwing an ugly HeadlessException # Change directory to the location of this script, to avoid issues with relative # paths to files referenced here cd "${0%/*}" # Some constants and variables for later # Version Integer 4 = Java 1.4, 5 = Java 5, 6 = Java 6, etc. TARGET_VER=8 # The JAR file to launch, relative to the directory of this script # make this "$0" to execute a binary payload (on this script) as a JAR TARGET_JAR="bigblockengine.jar" #TARGET_JAR="$0" # Name of the application to display in error dialog TARGET_NAME="Big Block Engine" # This is a directory to search for a JVM, for the sake of bundling one with the # application JAVA_DIR="jvm" # Any required options for the JVM itself go here JAVA_OPTIONS="" #JAVA_OPTIONS="-Xmx1024M" # Any options you want passed to the application, before command-line parameters # are passed APPLICATION_OPTIONS="" # Some strings to display for various error conditions TOO_OLD="Java is installed, but is too old." NO_JAVA_PATH="The Java executable has not been found on directories indicated by the 'PATH' variable.\nThis may indicate that Java isn't installed, or it may indicate that your 'PATH' variable does not include it." PLEASE_INSTALL="Please install Java 8 or higher." NO_X="No 'DISPLAY' variable set.\nThis application uses a GUI and cannot run without an X server." DOWNLOAD_URL=" https://adoptopenjdk.net/\n https://www.azul.com/downloads/zulu-community/\n http://java.com/en/download/" DOWNLOAD_MESSAGE="You can download Java from any of the following:\n$DOWNLOAD_URL" ERROR_TITLE="Unable to Start '${TARGET_NAME}'" # This checks the supplied 'java' command, to see if it exists, then checks it's # version against the required version, displaying 'good' if all is correct, # 'bad' if the file doesn't exist or isn't executaable and 'old' if the java # version is too old # Argument 1: Path to the target 'java' executable # Argument 2: Integer version number, as matching the comment for the # TARGET_VER variable, above function check-java() { if ! which "$1" >/dev/null ; then echo 'bad' elif [ $("$1" -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1) -lt "$2" ]; then echo 'old' else echo 'good' fi } # Any of the checks below may switch this to false, forcing the script to # terminate with an error message RUN_TARGET=true # If this becomes true, this indicates that we found at least one JVM that was # too old and if we never find a good JVM at all, then this should be reported # to the user JAVA_OLD=false # Check if we're running from a terminal of some kind ON_TERMINAL=true if ! [ -t 0 ] ; then # This one is specific to Big Block Engine # Optionally add the command-line switch to turn on the property for the GUI # log JAVA_OPTIONS="$JAVA_OPTIONS -Dnet.sf.simulatoralive.blockgame.GUIConsole=true" # We need this information later, for displaying dialog boxes instead of # unhelpfully displaying messages to Standard Out ON_TERMINAL=false fi # Check for Zenity; don't bother with dialog boxes without it if ! which zenity >/dev/null ; then ON_TERMINAL=true fi # Check for a proper DISPLAY variable, to avoid using zenity if no X ON_X=true if ! [ -n "$DISPLAY" ]; then ON_TERMINAL=true ON_X=false fi # Check for java in a directory specifically set aside for a JVM if [ -d "$JAVA_DIR" ]; then JAVA_LAUNCHER="$JAVA_DIR/bin/java" JAVA_GOOD=$( check-java "$JAVA_LAUNCHER" $TARGET_VER ) # echo $JAVA_GOOD : $JAVA_LAUNCHER if ! [ "$JAVA_GOOD" = 'good' ]; then RUN_TARGET=false fi if [ "$JAVA_GOOD" = 'old' ]; then JAVA_OLD=true fi else RUN_TARGET=false fi # Check for java, based on JAVA_HOME environment variable, which is a sort of # de-facto standard for locating java on some systems if [ "$RUN_TARGET" = false ] && [ -d "$JAVA_HOME" ]; then JAVA_LAUNCHER="$JAVA_HOME/bin/java" JAVA_GOOD=$( check-java "$JAVA_LAUNCHER" $TARGET_VER ) # echo $JAVA_GOOD : $JAVA_LAUNCHER if ! [ "$JAVA_GOOD" = 'good' ]; then RUN_TARGET=false fi if [ "$JAVA_GOOD" = 'old' ]; then JAVA_OLD=true fi else RUN_TARGET=false fi # Check for java on the PATH, but only if the above failed to find a good JVM if [ "$RUN_TARGET" = false ]; then JAVA_LAUNCHER="java" JAVA_GOOD=$( check-java "$JAVA_LAUNCHER" $TARGET_VER ) # echo $JAVA_GOOD : $JAVA_LAUNCHER if [ "$JAVA_GOOD" = 'good' ]; then RUN_TARGET=true else RUN_TARGET=false fi if [ "$JAVA_GOOD" = 'old' ]; then JAVA_OLD=true fi fi # Some debug code #echo "JAVA_LAUNCHER=$JAVA_LAUNCHER" #echo "RUN_TARGET=$RUN_TARGET" #echo "JAVA_OLD=$JAVA_OLD" # This final check is for GUI applications that need an X server # Comment out if you don't need this # Check for a running X server if ! [ "$ON_X" = true ]; then echo -e "$NO_X" >&2 RUN_TARGET=false fi # Finally, all sanity checks are done: Start the program, using passed # command-line arguments! if [ "$RUN_TARGET" = true ]; then "$JAVA_LAUNCHER" $JAVA_OPTIONS -jar "$TARGET_JAR" $APPLICATION_OPTIONS "$@" # Or time to call Zenity to display the error dialog and exit with error code else # Construct the final error message piece by piece ERROR_TEXT="The following error(s) have occured:" if [ "$JAVA_OLD" = true ]; then ERROR_TEXT="$ERROR_TEXT\n$TOO_OLD" else ERROR_TEXT="$ERROR_TEXT\n$NO_JAVA_PATH" fi ERROR_TEXT="$ERROR_TEXT\n$PLEASE_INSTALL\n$DOWNLOAD_MESSAGE" if [ "$ON_TERMINAL" = true ]; then echo -e "$ERROR_TITLE\n" echo -e "$ERROR_TEXT" else zenity --error --width=400 --title="$ERROR_TITLE" --text="$ERROR_TEXT" fi # Exit with error code exit 1 fi # Prevent a binary payload from being executed as part of this script # Also, a couple blank lines to make sure the payload doesn't interfere with the # exit command; I made that mistake the first time I tested a payload exit # And this will ensure editors don't snip off the trailing blank lines
Get Big Block Engine
Big Block Engine
2D block-based mod-friendly sandbox game/game engine
Status | In development |
Category | Tool |
Author | simulatoralive |
Tags | blocks, Game engine, Moddable, Physics, Pixel Art, Sandbox |
Languages | English |
More posts
- Sandboxing Java Code, a Modern ApproachFeb 22, 2023
- Logic Components (0.27.0 Alpha)Feb 10, 2023
- Parallel Block-Based PhysicsOct 19, 2020
- GUI Overhaul (0.26.1-3 Alpha)Oct 11, 2020
- Placing Painted Blocks (0.26.0 Alpha)Sep 26, 2020
- General UI Improvements (0.25.1 Alpha)Sep 19, 2020
- Better Error Reporting (0.25.0 Alpha)Sep 11, 2020
- Better Exit Cleanup (0.24.0 Alpha)Sep 01, 2020
- Fix for Floating Actors (0.23.2 Alpha)Jun 28, 2020
- Actor Physics Fixes (0.23.1 Alpha)Jun 27, 2020
Leave a comment
Log in with itch.io to leave a comment.