Building the App
This page covers how to build Terrarum for distribution — from preparing custom JVM runtimes and the asset archive, to packaging platform-specific executables.
All five platform builds (Linux x86, Linux ARM, Windows x86, macOS Apple Silicon, macOS Intel) can be produced from a single x86 Linux workstation. The build scripts live in the buildapp/ directory.
Quick Start
1. Build the Project JAR
Build the project from your IDE (IntelliJ IDEA). The output JAR should be at out/TerrarumBuild.jar.
2. Run Prebuild
Run Prebuild.kt's main() from the IDE. This generates platform-specific metadata files in out/:
build_autogen_buildinfo.properties— Version number and build datebuild_autogen_linux.desktop— Linux.desktopentrybuild_autogen_macos_Info.plist— macOSInfo.plistbuild_autogen_windows.rc— Windows resource file (icon, version info)
It also regenerates assets/mods/basegame/metadata.properties with the current version and date.
3. Prepare JVM Runtimes
Download JDK 21.0.2 for each target platform from jdk.java.net/archive and unzip them to ~/Documents/openjdk/ with these filenames:
| Target | Filename |
|---|---|
| Linux AMD64 | jdk-21.0.2-x86 |
| Linux Aarch64 | jdk-21.0.2-arm |
| Windows AMD64 | jdk-21.0.2-windows |
| macOS Apple Silicon | jdk-21.0.2.jdk-arm |
| macOS Intel | jdk-21.0.2.jdk-x86 |
Then create stripped-down runtimes using jlink:
# Linux x86
jlink --module-path ~/Documents/openjdk/jdk-21.0.2-x86/jmods:mods \
--add-modules java.base,java.desktop,java.net.http,jdk.crypto.ec,java.logging,java.scripting,jdk.unsupported \
--output ~/Documents/Terrarum/out/runtime-linux-x86 \
--no-header-files --no-man-pages --strip-debug --compress=2
# Linux ARM
jlink --module-path ~/Documents/openjdk/jdk-21.0.2-arm/jmods:mods \
--add-modules java.base,java.desktop,java.net.http,jdk.crypto.ec,java.logging,java.scripting,jdk.unsupported \
--output ~/Documents/Terrarum/out/runtime-linux-arm \
--no-header-files --no-man-pages --strip-debug --compress=2
# Windows x86
jlink --module-path ~/Documents/openjdk/jdk-21.0.2-windows/jmods:mods \
--add-modules java.base,java.desktop,java.net.http,jdk.crypto.ec,java.logging,java.scripting,jdk.unsupported \
--output ~/Documents/Terrarum/out/runtime-windows-x86 \
--no-header-files --no-man-pages --strip-debug --compress=2
# macOS Apple Silicon
jlink --module-path ~/Documents/openjdk/jdk-21.0.2.jdk-arm/Contents/Home/jmods:mods \
--add-modules java.base,java.desktop,java.net.http,jdk.crypto.ec,java.logging,java.scripting,jdk.unsupported \
--output ~/Documents/Terrarum/out/runtime-osx-arm \
--no-header-files --no-man-pages --strip-debug --compress=2
# macOS Intel
jlink --module-path ~/Documents/openjdk/jdk-21.0.2.jdk-x86/Contents/Home/jmods:mods \
--add-modules java.base,java.desktop,java.net.http,jdk.crypto.ec,java.logging,java.scripting,jdk.unsupported \
--output ~/Documents/Terrarum/out/runtime-osx-x86 \
--no-header-files --no-man-pages --strip-debug --compress=2
The jlink runtimes include only the Java modules the game actually needs, significantly reducing the distribution size.
Note: The Linux Aarch64 runtime must be prepared on an actual ARM Linux system, then copied to your workstation.
4. Build the Asset Archive
cd buildapp/
make assets
This runs two scripts in sequence:
make_assets_release.sh— Copiesassets/toassets_release/, stripping development-only filesmake_assets_archive.sh— Packsassets_release/intobuildapp/out/assets.tevdusing the TEVD Clustered format
See Asset Archiving for details on the archive format and runtime loading.
5. Package for All Platforms
cd buildapp/
make all
Or build individual targets:
make linux_x86 # Linux AMD64 AppImage
make linux_arm # Linux Aarch64 AppImage
make mac # macOS Apple Silicon .app (alias: make mac_arm)
make mac_x86 # macOS Intel .app
make windows # Windows .exe + .zip
Output files appear in buildapp/out/.
Makefile Targets
| Target | Output | Script |
|---|---|---|
what (default) |
Prints usage help | make_print_description_then_exit.sh |
assets |
out/assets.tevd |
make_assets_release.sh then make_assets_archive.sh |
linux_x86 |
out/TerrarumLinux.x86.AppImage |
build_app_linux_x86.sh |
linux_arm |
out/TerrarumLinux.arm.AppImage |
build_app_linux_arm.sh |
mac / mac_arm |
out/TerrarumMac.arm.app.zip |
build_app_mac_arm.sh |
mac_x86 |
out/TerrarumMac.x86.app.zip |
build_app_mac_x86.sh |
windows |
out/TerrarumWindows.x86.zip |
build_app_windows_x86.sh |
all |
All five of the above | build_app_all.sh |
Asset Preparation
make_assets_release.sh
Creates assets_release/ from assets/ by removing files that should not ship:
- Test files (
loopey.wav,batchtest.txt,test_texture.tga, etc.) - Development modules (
dwarventech,myawesomemod) - Source/working files (
*.gz,*.txt,*.md,*.krain mod directories) - OS junk (
.DS_Store,Thumbs.db,.directory)
make_assets_archive.sh
Invokes AssetArchiveBuilderKt to pack assets_release/ into a TEVD archive:
# Builds classpath from the project JAR and all library JARs
CP="../out/TerrarumBuild.jar"
for jar in ../lib/*.jar; do CP="$CP:$jar"; done
java -cp "$CP" net.torvald.terrarum.AssetArchiveBuilderKt "$SRCDIR" "$OUTDIR/assets.tevd"
Requires out/TerrarumBuild.jar and lib/TerranVirtualDisk.jar to exist.
Prebuild (Autogenerated Files)
Prebuild.kt (src/net/torvald/terrarum/Prebuild.kt) reads the version number from App.VERSION_RAW and generates platform-specific files. Run it before packaging.
| Generated File | Purpose | Used By |
|---|---|---|
out/build_autogen_buildinfo.properties |
Version number and UTC build date | Runtime version display |
out/build_autogen_linux.desktop |
FreeDesktop .desktop entry |
Linux AppImage |
out/build_autogen_macos_Info.plist |
macOS application bundle metadata | macOS .app |
out/build_autogen_windows.rc |
Windows resource script (icon, version) | Windows .exe |
assets/mods/basegame/metadata.properties |
Base game module metadata with current version | Module loader |
Platform-Specific Packaging
Each platform build script creates a self-contained application bundle with the game JAR, the asset archive, and a custom JVM runtime. All scripts refuse to run as root.
Linux (AppImage)
Script: build_app_linux_x86.sh (and build_app_linux_arm.sh)
Packages the game as an AppImage — a single executable file that runs on most Linux distributions without installation.
Structure:
TerrarumLinux.x86/
├── AppRun ← Entry point (shell script)
├── icns.png ← Application icon
├── build_autogen_linux.desktop
├── assets.tevd ← Game assets archive
└── out/
├── TerrarumBuild.jar
└── runtime-linux-x86/
└── bin/java ← Custom JVM
AppRun is a shell script that launches the JVM:
./out/runtime-linux-x86/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
The directory is then packed into an AppImage using appimagetool-x86_64.AppImage.
Requirements: appimagetool must be present in buildapp/.
Windows (EXE + ZIP)
Script: build_app_windows_x86.sh
Cross-compiles a native Windows launcher using x86_64-w64-mingw32-gcc, then zips the entire package.
Launcher (Terrarum.c): A small C program that uses CreateProcessA to launch the JVM with the console window hidden (SW_HIDE). This gives users a clean double-click experience without a visible command prompt.
Build steps:
- Compile the Windows resource file (
.rc→.res) withx86_64-w64-mingw32-windresfor icon and version metadata - Compile
Terrarum.cwithx86_64-w64-mingw32-gcc, linking the resource file - Copy runtime, JAR, and assets into the output directory
- Zip into
out/TerrarumWindows.x86.zip
Structure (inside zip):
TerrarumWindows.x86/
├── Terrarum.exe ← Native launcher
├── assets.tevd
└── out/
├── TerrarumBuild.jar
└── runtime-windows-x86/
└── bin/java.exe
Requirements: mingw-w64 cross-compiler (x86_64-w64-mingw32-gcc and x86_64-w64-mingw32-windres).
macOS (.app Bundle)
Script: build_app_mac_arm.sh (and build_app_mac_x86.sh)
Creates a standard macOS .app bundle and compresses it with 7z.
Structure:
TerrarumMac.arm.app/
└── Contents/
├── Info.plist ← Application metadata
├── Resources/
│ └── AppIcon.icns ← macOS icon
└── MacOS/
├── Terrarum.sh ← Entry point (shell script)
├── assets.tevd
└── out/
├── TerrarumBuild.jar
└── runtime-osx-arm/
└── bin/java
Terrarum.sh launches the JVM:
./out/runtime-osx-arm/bin/java -jar ./out/TerrarumBuild.jar
Requirements: 7z for creating the zip archive.
Directory Layout
buildapp/
buildapp/
├── Makefile
├── make_print_description_then_exit.sh
├── make_assets_release.sh
├── make_assets_archive.sh
├── build_app_all.sh
├── build_app_linux_x86.sh
├── build_app_linux_arm.sh
├── build_app_mac_arm.sh
├── build_app_mac_x86.sh
├── build_app_windows_x86.sh
├── appimagetool-x86_64.AppImage ← Linux AppImage packer
├── icns.png ← Linux/generic icon
├── icns.ico ← Windows icon
├── AppIcon.icns ← macOS icon
├── terrarum.manifest ← Windows application manifest
├── terrarumlinux_x86/ ← Linux x86 template
│ └── AppRun
├── terrarumlinux_arm/ ← Linux ARM template
│ └── AppRun
├── terrarumwindows_x86/ ← Windows template
│ └── Terrarum.c
├── terrarummac_arm/ ← macOS ARM template
│ └── Terrarum.sh
├── terrarummac_x86/ ← macOS Intel template
│ └── Terrarum.sh
└── out/ ← Build output
├── assets.tevd
├── TerrarumLinux.x86.AppImage
├── TerrarumLinux.arm.AppImage
├── TerrarumWindows.x86.zip
├── TerrarumMac.arm.app.zip
└── TerrarumMac.x86.app.zip
out/ (Project Root)
out/
├── TerrarumBuild.jar ← Compiled game (fat JAR)
├── build_autogen_buildinfo.properties ← Generated by Prebuild.kt
├── build_autogen_linux.desktop
├── build_autogen_macos_Info.plist
├── build_autogen_windows.rc
├── build_autogen_windows.rc.res ← Compiled by mingw windres
├── runtime-linux-x86/ ← jlink runtimes
├── runtime-linux-arm/
├── runtime-windows-x86/
├── runtime-osx-arm/
└── runtime-osx-x86/
Icon Creation
macOS .icns
On a real macOS system:
- Create a folder called
icon.iconset - Copy the PNG icon as
icon_512x512.pnginto that folder - Run:
iconutil -c icns icon.iconset
Windows .ico
- Open the PNG icon in GIMP
- Export As
.ico, selecting 24 bpp (1-bit alpha) or 32 bpp (8-bit alpha)
Notes
- The game does not use Java 9+ modules — all dependencies are fat-jar'd into
TerrarumBuild.jar - The
jlinkruntimes contain only the modules listed in the--add-modulesflag, keeping them small - All five executables can be built on a single x86 Linux workstation, but the ARM Linux runtime must be prepared on an actual ARM system
- Build scripts all refuse to run as root as a safety measure