Build Tool

1. Introduction

Together with the engine we include a tool to help with building and packaging your programs for various platforms (standalone, mobile, consoles…​).

Just download Castle Game Engine and the build tool is included inside.

In most cases, you will use Castle Game Engine Editor (bin/castle-editor executable) that automatically uses build tool described here, under the hood. Alternatively, you can execute the build tool directly, on the command-line, using bin/castle-engin executable.

2. Command-line Usage

Open a terminal (command-line), and enter the directory containing CastleEngineManifest.xml file. This is the main project directory.

Run this command to compile the project (for the current operating system and processor):

castle-engine compile

Run this to compile and also package (again, for the current operating system and processor):

castle-engine package

By default we compile in release mode. Use option --mode=debug to compile a debug version (slower, but more friendly for various debuggers).

That’s it, you can now use our "build tool" to easily compile and package your games for various platforms:) Read on to learn about more useful commands of the build tool.

3. Creating and using the manifest file for your projects

Create a CastleEngineManifest.xml file in your project’s directory. See the CastleEngineManifest.xml examples page for samples and documentation. You can create an trivial starting CastleEngineManifest.xml file by executing castle-engine create-manifest. The manifest file describes your project’s name, source code, what files to include in the package and such.

Then you call castle-engine from within your project’s directory (or any subdirectory, we automatically look for CastleEngineManifest.xml in parent directories) to quickly compile, package and clean the project. See the description of command-line parameters to castle-engine below. The tool is integrated with our engine, so it can automatically compile the code correctly, and package it following our usual conventions. The data for the game is automatically packaged. On Windows the required DLL files are automatically included (see also the description of <dependencies> in CastleEngineManifest.xml). On Android the required Java wrappers and libraries are automatically used.

4. Commands supported by the castle-engine tool

4.1. create-manifest

Create CastleEngineManifest.xml file if it does not exist yet, guessing the project name based on directory name. You can use this CastleEngineManifest.xml as a starting point.

4.2. compile

Compile the project, with the syntax options and optimizations suggested for programs using our engine.

By default we compile for your current OS (operating system) and processor, so if you’re on 32-bit Windows -> you will compile a 32-bit Windows binary, if you’re on 64-bit Linux -> you will compile a 64-bit Linux binary and so on. You can use --os and/or --cpu options to cross-compile. Underneath, proper cross-compilation options will be passed to FPC.

For example:

  • Call castle-engine compile --cpu=x86_64 to compile a 64-bit version for the current operating system.

  • Call castle-engine compile --os=linux --cpu=x86_64 to compile a 64-bit version for Linux.

  • Windows is a little weird (due to historical conventions beyond FPC), and you have to use castle-engine compile --os=win64 --cpu=x86_64 (thus, you request 64-bit "twice" in the command-line) to get a 64-bit version on Windows. Use castle-engine compile --os=win32 --cpu=i386 to get a 32-bit executable for Windows.

Instead of --os and/or --cpu options, you can also use --target. A target is a collection of OS and CPU combinations that typically are distributed together. Right now, these targets are available:

  1. custom (the default target), which means that we look at --os and/or --cpu options, and compile for this single OS/CPU.

  2. android, which consists of 2 combinations of OS/CPU: Android OS on ARM (32-bit) and Android on Aarch64 aka Arm64 (64-bit).

  3. ios. By default this consists of 2 combinations of OS/CPU, to include 32-bit and 64-bit iOS devices. Add the --ios-simulator option to include 2 more combinations of OS/CPU to include also support for the iOS simulator. See iOS to learn more.

  4. nintendo-switch, which builds an application for Nintendo Switch.

Use --mode=debug or --mode=release or --mode=valgrind for a specific compilation mode. By default, it is "release". The "valgrind" mode is for profiling (speed, memory usage) using the excellent Valgrind tool.

In all cases, your programs will be compiled with the same options as engine units. We turn the same optimizations as for the engine core. In FPC it which means that we use ObjFpc syntax mode by default.

By default we auto-detect the compiler: using the compiler indicated in CastleEngineManifest.xml by compiler="xxx" option, otherwise using FPC or Delphi (whichever first is found). You can use --compiler command-line option to override the compiler choice, like --compiler=fpc or --compiler=delphi.

You can customize what options we pass to the compiler by:

  1. Adding options to the <custom_options> in CastleEngineManifest.xml. This is the good place to define options specific to your project (that should be used by all developers working with this project).

  2. Using --compiler-option command-line option. For example, --compiler-option=-dMY_DEFINE or --compiler-option=-gl --compiler-option=-gh. This is the good place to pass options specific to your development system or preferences, that should not be shared by all developers working on this project.

Use --plugin to compile a web browser plugin.

Use --output DIR to place the output files (executable, temporary castle-engine-output subdirectory) in a specified directory. When not given, they are placed in the current project directory. This option is also available for other commands, like package, install and run.

Compiling on Windows will also copy the necessary .dll files from the engine to be alongside your .exe file. This allows to run the executable afterwards, in any way.

Note
This is not the only possible way to compile programs using our engine (for example, you can also compile and run using Lazarus, which is OK for desktop applications).

4.3. package

Create an installable package with your application.

Use --cpu, --os or --target options to specify target operating system/processor. By default, we package for current standalone platform.

Use --compiler to override compiler for building, just as for compile command.

What exactly is produced by this command depends on the target platform and the --package-format option used.

  • --package-format=default (used also when no --package-format=... was specified):

    • For the standalone platforms, we package to a simple zip / tar.gz archive containing the executable, libraries and data. For Windows, we create zip, otherwise tar.gz.

    • For the Android (when --target=android or --os=android --cpu=arm/aarch64), we create a complete apk with your application, ready to be installed and uploaded to Google Play!

    • For iOS (when --target=ios), we create an Xcode project, that you can run and publish using Xcode.

  • --package-format=zip: Pack files into a zip file.

  • --package-format=tar.gz: Pack files into a tar.gz file.

  • --package-format=deb: Pack files into a Debian Package (deb).

  • --package-format=directory: Put files into a directory. This is useful if you plan to further process this directory, e.g. pack it with your own scripts.

  • Android formats:

    • --package-format=android-apk: Create an APK file. This is right now the equivalent to --package-format=default and it is just the default behavior when target/OS is Android. It’s the standard way to build applications for Android. It also allows you to manually install the app on your Android device.

    • --package-format=android-app-bundle: Create an Android App Bundle (AAB). This is a new format recommended for submitting a release to Google Play Store. Android App Bundle may contain multiple precompiled versions of the app and assets, and Google Play Store internally generates an installable APK for every specific user depending on user device configuration (such as Android version or screen resolution). AAB format is strictly required to upload a project larger than 100Mb to Play Store.

  • iOS formats:

    • --package-format=ios-xcode-project: Create the Xcode project. This is the default package method for iOS. You can open the resulting project in Xcode and build/deploy the application for iOS device or AppStore.

    • --package-format=ios-archive-ad-hoc: Archive and export using the ad-hoc method, which results in an IPA file of the application. To install on designated devices, upload to TestFairy etc.

    • --package-format=ios-archive-development: Archive and export using the development method. See the Xcode documentation (and try these options from Xcode interactively) for details.

    • --package-format=ios-archive-app-store: Archive and export for the TestFlight and the AppStore. See the Xcode documentation (and try these options from Xcode interactively) for details. Note that this does not upload to the TestFlight / AppStore (although we’d like to extend this someday to do it).

  • macOS formats:

    • --package-format=mac-app-bundle-zip: Application bundle on macOS, packed into zip. Default format for macOS.

    • --package-format=mac-app-bundle: Application bundle on macOS, not packed (so it is just a directory like MyApplication.app).

  • Nintendo Switch format: --package-format=nintendo-switch.

When target is iOS you can also use --ios-simulator option to include iOS simulator support (see iOS).

By default output filename contains a version number. Sometimes this is not comfortable, use --package-name-no-version to avoid it.

You can use --mode=xxx option when packaging, just like when compiling. Use --mode=debug or --mode=release for a specific compilation mode. By default, it is "release". You can use --mode=debug to package a debug release, which may be useful to distribute to users interested in beta-testing.

In some cases, the --mode also affects the packaging wrapper. For example, on Android, a debug apk is generated. Also, only a debug apk may use a debug signing key (our build tool will automatically fallback from release apk to debug apk if you did not provide a release key in AndroidSigningProperties.txt).

To make sure that we recompile everything in the current mode (e.g. a release mode), this does clean, and then compile, and only then actually packages the result. You can change this behavior:

  • Use --fast to make the compilation step faster — we will recompile only what changed.

    By default, without --fast, the package command first cleans all the compilation results, and then builds from scratch (engine and your code). This is safest (makes sure that everything is rebuild with latest compilation options) but slow, and usually not necessary (Pascal compilers are generally excellent at detecting what needs to be recompiled, FPC even handles changes to include files reliably). For the final release builds, we advise to not use this option.

    Using --fast is suitable during the development, if you call the package command often.

  • Use --assume-compiled to say that you already compiled the application in proper mode before calling the package action. We will not do clean and compile in this case at all. This is obviously much faster, but you need to make sure to call compile beforehand yourself.

Another (independent) way to make packaging faster is to use --update-only-code. For now this is meaningful only for iOS. If specified, it means that the build tool can assume that only the Pascal code have changed (so you did not change e.g. data/ directory, or project settings in CastleEngineManifest.xml). We can then recompile the code (and update the relevant file in the project, like libxxx.a) without changing anything else. This means that the package command will finish much faster. It will also be more comfortable — e.g. no need to close and reopen the project in Xcode, Visual Studio or whatever other software is used to handle the final project.

4.4. install

Install the application created by previous "package" call.

  • This is useful when OS is "android", it installs and runs the apk package created by previous "package" call for Android. Useful for quick testing of your app on a device connected through USB. Note: it’s best to first test do you see your device using SDK tools, for example execute adb devices and see is your device listed.

  • Use --plugin to install a web browser plugin. We install the compiled plugin such that it should be visible by all web browsers supporting NPAPI. (On Windows, this means installing proper registry entries. On Unix, it means copying the library to special directory.)

Pass also additional options reflecting the OS/architecture, mode and package name format. In general, pass to install exactly the same values as you used for package, so that we know which package to install:

  • Use --os, --cpu or --target to specify target operating system/processor (by default, we install for the current standalone platform).

  • Use --mode=xxx to specify debug or release package.

  • Use --package-format, --package-name-no-version to determine the package name.

4.5. run

Run the application.

The log of the application (whatever you write using WritelnLog, WritelnWarning) will be the output of this command. On some platforms, you can also use regular Writeln, but to be cross-platform better stick to CGE WritelnLog / WritelnWarning, they will work in all cases (Android, iOS, Windows GUI applications etc.).

As usual, use --os, --cpu or --target options to specify target operating system/processor. By default, we run the normal (exe) application on the current platform.

On some platforms, it requires packaging and installing the application first. This applies to Android: we install and run on a device connected through USB. Use the "package" and "install" commands before this. For example, on Android you can package and install and run your application like this:

castle-engine package --target=android
castle-engine install --target=android
castle-engine run --target=android

On other platforms (e.g. standalone Windows, Linux, macOS…​), this simply runs the last compiled application. So just "compile" the application first, like this:

castle-engine compile
castle-engine run

You can specify parameters to pass to the application after the special "--" parameter. For example,

castle-engine run -- --fullscreen

This will run your application with command-line parameters --fullscreen. In your application, you can read command-line parameters with the help of CastleParameters unit. (The --fullscreen option, used as an example here, is actually handled automatically, if only your program calls Application.ParseStandardParameters.) The command-line parameters are not supported in non-desktop environments (e.g. there’s no way to pass them to an Android or iOS application).

On Unix desktop platforms (like Linux, FreeBSD..), we can run your game through a "wrapper script". This is useful e.g. to set LD_LIBRARY_PATH before running the application. The build tool simply looks for run.sh or <application_name>_run.sh script in the project directory, and executes it if found (instead of executing the compiled binary directly).

4.6. package-source

Package source code, which means just to package whole project directory (cleaned up first).

It creates xxx-VERSION-src.tar.gz archive, with VERSION obtained following the <version> element in the CastleEngineManifest.xml.

It accepts the --package-format and --package-name-no-version options, just like the package command. By default we just pack to zip (that is, --package-format=zip is equivalent to --package-format=zip).

4.7. clean

Clean compilation and packaging temporary stuff. This does not remove final packaging files.

4.8. simple-compile

Compile the Object Pascal file (unit/program/library) given as a parameter. This does not search for the Castle Game Engine project’s manifest in the CastleEngineManifest.xml file. It merely calls "fpc" with proper command-line options for units/programs/libraries using our engine.

Use this instead of "compile" only if there’s some good reason you don’t want to use CastleEngineManifest.xml to manage your project.

4.9. auto-generate-textures

Create GPU-compressed versions of textures, and downscaled textures, for the textures mentioned in <auto_generated_textures> inside the file data/material_properties.xml. Such GPU-compressed and downscaled textures can then be automatically used in your application. See instructions how to use it and example data/material_properties.xml.

If the output textures are already created, they are updated only if the output timestamp is earlier than input. This usually allows to automatically do only the necessary work, similar to how Makefiles operate. To force recreating all textures, just call castle-engine auto-generate-clean --all first.

The information about created textures is stored in data/CastleAutoGenerated.xml file. If you use version control, you should either:

  • ignore the data/CastleAutoGenerated.xml file and ignore all auto_generated directories.

  • or commit both the data/CastleAutoGenerated.xml file and all auto_generated directories.

4.10. auto-generate-clean

Clear auto_generated subdirectories. They should contain only the output created by castle-engine auto-generate-textures target. In the future, it is possible that more things will be placed there (for example, modern GPUs allow mesh data compression).

Run without any arguments to only clean the unused files in auto_generated subdirectories. This may be useful after moving/renaming some subdirectories, as the castle-engine auto-generate-textures command never removes previous files, it only adds new files. Having unused files is not a problem — but they waste disk space, and can be safely removed.

Run with --all argument to clean all files from the auto_generated subdirectories. This is useful e.g. if you want to force regenerating them all by next castle-engine auto-generate-textures command.

4.11. generate-program

Generates:

  1. standalone (desktop) Pascal program code in the file xxx_standalone.dpr. It uses the game_units defined in the CastleEngineManifest.xml to determine the correct uses clause of the program file.

    You can use this program code to compile the project using any tool you want, not necessarily our build tool. E.g. maybe you like using Lazarus or fpmake. You can use it as a standalone_source in the CastleEngineManifest.xml to make sure build tool also uses it (in case you will modify it), although build tool can also generate such source code automatically.

    If the standalone_source is specified in CastleEngineManifest.xml, then we overwrite it, regardless if it is called xxx_standalone.dpr or not.

  2. Lazarus project information in the file xxx_standalone.lpi.

    Together with xxx_standalone.dpr, this allows you to open this project in Lazarus to edit, compile, debug and run it from Lazarus. You can also compile it using lazbuild.

    If the standalone_source is specified in CastleEngineManifest.xml, then we overwrite the respective LPI file, regardless if it is called xxx_standalone.lpi or not.

  3. Delphi project information in the file xxx_standalone.dproj.

    Together with xxx_standalone.dpr, this allows you to open this project in Delphi to edit, compile, debug and run it from Delphi.

    If the standalone_source is specified in CastleEngineManifest.xml, then we overwrite the respective DPROJ file, regardless if it is called xxx_standalone.dproj or not.

  4. CastleAutoGenerated unit in castleautogenerated.pas unit. It is used by the program file created above (xxx_standalone.dpr) and also by all program or library files created automatically by the build tool to build project on all platforms. It defines some project properties, to parse standard command-line properties, to initialize logging.

4.12. editor

Run the Castle Game Engine Editor within this project. The executed editor will include possible project-specific components.

  • In simple cases, this is just a shortcut for running castle-editor and opening the current project, which can also be done by calling castle-editor ../path-to-project/CastleEngineManifest.xml.

  • If your CastleEngineManifest.xml contains editor_units attribute, then this automatically builds and runs a custom CGE editor (a fork of the CGE editor, for use in your project), with your custom components included.

    The custom editor is compiled and present inside castle-engine-output/editor/, so it is tied to your project, cleared with castle-engine clean and so on. You should always execute it using castle-engine editor command. Or using the "Project -> Restart Editor (may rebuild editor with custom controls)" menu from the CGE editor (vanilla build or custom build, doesn’t matter, the "Restart editor" will always build custom editor if project uses editor_units).

4.13. cache

Precompile CGE units, to speed up future compilation of all projects (with the current compiler and engine version).

By default we prepare cache for compilation on the current platform. The options --os, --cpu, --target switch the platform, as usual. E.g. you can use castle-engine cache --target android to speedup future Android compilations.

The precompiled units are stored in user files, and will be reused by all subsequent compilations of any CGE project for matching platform. The precompiled units from cache are simply copied over (as a starting point) to your project’s compilation directory. The precompiled units do not overwrite the existing ones, moreover the compiler will overwrite them (in the project) if e.g. you have changed CGE since making the cache. So the cache tries hard not to conflict with what you’re doing.

The cache is always prepared for all possible modes: debug, release, valgrind. This command ignores the --mode option.

The --compiler option is taken into account, but for now for Delphi we merely answer with an error. The code to use cache is now only for FPC. In the future we plan to extend this to Delphi.

The --ios-simulator option is honored, it changes what castle-engine cache --target=iOS does (for what platforms does it prepare cache).

4.14. cache-clean

Remove all the cached files created by cache (for all platforms).

This reclaims the disk space used by cache and it implies that future compilations will be done without using the cache.


To improve this documentation just edit this page and create a pull request to cge-www repository.