Developing Linux applications using Delphi

1. Introduction

You can create applications for Linux using Delphi and Castle Game Engine.

This page outlines some details specific to Delphi on Linux. See Delphi page for general Delphi usage notes.

play_animation example using TCastleWindow to display animated TCastleScene CastleFmx example with TCastleControl on FMX form

2. Setting up the Linux and Delphi environment

Note
This information is not specific to Castle Game Engine. You may find it useful for any Linux development with Delphi.

Delphi IDE runs on Windows. To build and run applications from Delphi for Linux, you need to:

  • Have a working network connection from Windows to Linux.

  • Install on Linux the PA Server (Platform Assistant Server).

  • Connect from Delphi IDE to Linux.

  • Install FMXLinux in Delphi.

2.1. Make sure your Delphi supports Linux

You need Delphi Enterprise to have a Linux support. Make sure you have checked the "Linux" platform during the installation process.

Note that C++ Builder does not support the Linux target.

2.2. Installing Linux, regular or in WSL

You can use any Linux distribution and install it on any system:

  • You can use a regular, separate computer with Linux. We advise this to new users — just get Ubuntu for Desktop and install it on a separate computer. This is the easiest way to get started with Linux.

    Note
    We recommend this option especially for people who are not experienced with using Linux. You may be tempted to use some virtualization solution, and they indeed rock (see below), but using them requires some experience to deal with extra steps (e.g. to make sure modern OpenGL works with decent speed — and you will need this to run CGE applications). If you’re new to Linux, it will really be a smoother experience if you just install Linux in a regular way, on a dedicated machine.
  • Or you can set up a virtual machine using "full" virtualization software like VirtualBox.

  • Or you can use Windows Subsystem for Linux (WSL) to setup a comfortable Linux environment on Windows. This is a great option if you know your way around Linux and can use it from the command-line. WSL gives a lightweight and comfortable Linux virtual machine within your Windows.

    For example set WSL machine with latest Ubuntu by executing this on Windows command-line:

    wsl --install # gets ubuntu latest

    Later, use just wsl command to enter the virtual Linux environment. If the machine doesn’t run yet (e.g. after Windows reboot) it will be automatically started.

    Within the machine, you have full Linux system. Inspect it, upgrade it and install additional software as usual, e.g.:

    lsb_release -a
    sudo apt update
    sudo apt dist-upgrade
    sudo apt install mesa-utils
    glxinfo -B
    glxgears # make sure OpenGL works

    Note to Nvidia users: You may need to use export MESA_D3D12_DEFAULT_ADAPTER_NAME=nvidia . You can add it to ~/.bashrc to make it permanent.

2.3. Libraries required (for both development and runtime)

  • OpenGL (essential, to be able to render)

  • GTK 3 (essential, to open a window using FMX or TCastleWindow)

  • EGL (essential, to be able to initialize rendering context, either by TCastleWindow or TCastleControl)

  • LibCurl (to be able to use HTTP(S) protocol with TCastleDownload; as of Delphi 11.3, these version are supported: libcurl3, libcurl4, libcurl5).

  • LibPng (to open png files more efficiently)

  • ZLib (to unpack gzip files; also used by LibPng)

  • OpenAL (to play sound)

  • FreeType (to load font files)

  • VorbisFile (to load OggVorbis files)

On Debian and derivatives (like Ubuntu or Raspberry Pi OS), this command should install them all:

sudo apt install mesa-utils libgtk-3-dev libegl1 libcurl4 libpng-dev libz1 libopenal1 libfreetype6 libvorbisfile3

Note that users do not need the -dev versions of these libraries.

Note
The above list already contains the relevant subset of libraries used by CGE when compiled with FPC for Linux.

All these libraries are common and should be available out-of-the-box on any modern Linux distribution with a graphical environment installed.

2.4. Installing PA Server

Follow the PA Server docs how to install and run it on Linux.

Note that it may report issues with libpython3.so version. Fix it by commands like this:

# The directory below may be different for you, depending on where you unpacked the PA Server
cd ~/PAServer/lldb/lib

# See if the symlink looks valid
ls -Flah libpython3.so

# If the symlink looks invalid, move it away (you could also "rm -f libpython3.so" if feeling brave)
mv libpython3.so libpython3.so.old

# Setup proper symlink.
# Check the actual libpython3.XXX version below on your system first!
ls /usr/lib/x86_64-linux-gnu/libpython3*
ln -s /usr/lib/x86_64-linux-gnu/libpython3.11.so.1 libpython3.so

Remember the directory where you unpacked the PA Server. Delphi will automatically deploy Linux applications there, which means that it will copy the binaries and data into the directory like ~/PAServer/scratch-dir/<connection-name>/<project-name>/. If need be, you can later run the applications directly, on that Linux machine, without using Delphi, just from command-line entering the directory and running the binary, like

cd ~/PAServer/scratch-dir/<connection-name>/my_project/
./my_project

2.5. Connect from Delphi to Linux

In Delphi IDE, go to "Options" → "Deployment" → "Connection Profile Manager". Add a new connection to the Linux machine. You need to provide the IP address of the Linux machine. You can see the IP e.g. by

  • Running ip a from the terminal on Linux.

  • Using i command inside PAServer console on Linux.

You also need to provide the password to connect to the PA Server running on it.

When you add a new connection, Delphi will copy the libraries from the Linux machine to your Windows machine. This is necessary to link applications for Linux. It is critical that after you install or upgrade any library on that Linux box, in Delphi go to "Options" → "Deployment" → "SDK Manager" and run "Update Local File Cache". This will copy the new libraries to your Windows machine.

2.6. Get and install FMXLinux

To compile Castle Game Engine applications using Delphi for Linux, you need to have FireMonkey for Linux (FMXLinux) installed in the Delphi IDE and properly configured.

Use RAD Studio GetIt Package Manager to install FMXLinux. Follow the FireMonkey for Linux using GetIt instructions for details.

You can also download FMXLinux from Embarcadero "My Downloads" page. Then you can use GetIt "Load Local Package" feature.

Note
Local packages from Embarcadero "My Downloads" come with units precompiled for a specific Delphi version. Pay attention to download the version proper for your Delphi. E.g. "FMXLinux Package Download for RAD Studio 12.0" contains FMXLinux 1.76 with unis for Delphi 12.0. Installing it in Delphi 11.3 will result in problems — it will seem to install OK, but then compilation of any FMX application for Linux will fail with "Could not compile used unit 'FMX.Forms'". To work with Delphi 11.3, you need to download "FMXLinux Package Download for RAD Studio 11.3". If you mess things up, you may need to manually cleanup the directory like C:\Users\Public\Documents\Embarcadero\Studio\22.0\CatalogRepository\FmxLinux-1.76_Local , in case GetIt UI doesn’t allow to uninstall packages when the GetIt website is offline, which happens.
Note
With Delphi 11.2 (Enterprise), it seems GetIt cannot find "FMXLinux". Just upgrade to 11.3 if you experience this issue. Or use Embarcadero "My Downloads" to download FMXLinux for Delphi 11.2.
Note
You can also buy FMXLinux. There is also a free trial. See FMXLinux installation instructions. But, practically, if you already have Linux platform, then you should also have Delphi Enterprise, and then you should be able to install FMXLinux without any additional cost using GetIt.

Once you have FireMonkey for Linux installed, you should see that "Linux 64-bit" becomes a possible platform for FMX projects.

Be sure to also install required libraries on Linux. As usual after installing libraries on Linux, refresh the cache: enter Delphi "Options" dialog, inside find "Deployment → SDK Manager", select the Linux platform, and "Update Local Cache" (answer "Yes To All" in case it asks whether to override files).

Test FMXLinux by installing "FMX Linux Samples" using GetIt. Run some of them to test that FMX on Linux works.

Note
GtkWindow sample from FMXLinux has a bug, that prevents compilation due to permissions. Edit fhe project settings and change "Unit Output Directory" from $(fmxlinux)\Lib\$(ProductVersion)\$(Config) to .\$(Platform)\$(Config). Or try a different sample, like FontList.

More FMXLinux useful resources:

2.7. Optional: Add FMXLinux redistributables to "Library Paths"

Note
This step is optional. It’s not required to build CGE applications for Linux. It’s not required to use TCastleWindow or TCastleControl. It’s not required to install CGE packages in Delphi IDE.

If you want to build CGE packages that use FMX for the "Linux 64-bit" platform, to use them as run-time packages in Linux, do this:

  • Enter "Tools → Options" dialog

  • Go to "Language → Delphi → Library → Library Path"

  • Add the $(BDSCatalogRepositoryAllUsers)\FmxLinux-1.74\Redist path to the list. See the screenshot below.

The exact path may differ based on FMXLinux version.

Add FMXLinux redistributables to "Library Paths"

2.8. Test blank FMX application

We advise to test everything above by creating a blank FMX application ("File → New → Multi-Device Application"), and compiling and running it on Linux. If this works, you know you have everything set up correctly.

3. Test Castle Game Engine on Delphi/Linux

Simply open in Delphi any example, switch the platform on top to Linux 64-bit, and hit F9 (compile and run) from Delphi.

All our examples are compatible with Delphi on Linux. This includes

4. Special things to watch out for when using Delphi for Linux with CGE

4.1. Data files deployment (applies to all non-Windows platforms with Delphi)

When "deploying" your application (e.g. when you hit F9 in Delphi to run on Linux), Delphi needs to know which data files to copy to the target (Linux). This is particularly important for the data directory of your project, it needs to be available on target. Unfortunately, we cannot tell Delphi to just "copy whole data directory recursively" in the project deployment settings.

To make it work, our editor and build tool can generate in the DPROJ (project settings) the list of files to copy, by listing all current files in the data directory.

So we highly advise to manage your project files (DPROJ) automatically, and just use "Code →Regenerate Project" menu item from the editor whenever you add / remove some files in your data directory.

See at Delphi window "Project → Deployment" to confirm that Delphi is aware of all your data files.

4.2. Use TCastleControl.ApplicationRun (instead of Application.Run) in FireMonkey applications

Note
This section only matters if you create applications using FMX. If you use TCastleWindow, you don’t need to worry about this (even if TCastleWindow internally uses FMX).

Due to technical limitations, you cannot just use Application.Run in FMX (FireMonkey) applications that you want to run on Linux if you want to have reliable TCastleControl. You need to replace it (usually in the main program file) with

TCastleControl.ApplicationRun;

Add to the uses clause the Fmx.CastleControl unit where it is defined. Like this.

On Windows, this is equivalent to just doing Application.Run. On Linux, this does the event loop in more special way, to ensure engine updates and rendering can happen reliably.

All our FMX examples (like examples/delphi/fmx and examples/delphi/fmx_play_animation) already do this. Remember to do this in your own FMX applications too.

Moreover, if you ever call Application.ProcessMessages; to perform manual loop control in your FMX application, you should extend it to call CGE processing too:

while Something do
begin
  Application.ProcessMessages;
  TCastleControl.ProcessTasks; // additional CGE processing
end;

Additional notes:

  • The TCastleControl.ApplicationRun (and TCastleControl.ProcessTasks) work even if your application does not use TCastleControl. Or if your application doesn’t use it on all forms or all the time.

  • We have tried to avoid this non-standard need and make just Application.Run work for CGE applications. But it really seems unavoidable with current FMXLinux. See USE_TIMER comments in castlewindow_form.inc and fmx.castlecontrol.pas. With Application.Run, there seems to be no reliable way to perform some work independent of user input (like update animations) many times per second, on FMXLinux.

  • As a consequence of this workaround, FMX applications (using TCastleControl.ApplicationRun) will always report this GTK error on exit:

    ...: Gtk-CRITICAL **: ...: gtk_main_quit: assertion 'main_loops != NULL' failed

    You have to simply ignore this GTK error. It doesn’t break the execution flow, in particular code after TCastleControl.ApplicationRun executes normally.

    The reason is that FMXLinux Application.Terminate uses gtk_main_quit, but it should not be used when gtk_main is not called. And indeed gtk_main is not called when we don’t call Application.Run. When you use TCastleWindow, we can adjust to it, by not using Application.Terminate at all. But when using TCastleControl, we cannot avoid it being called when last window gets closed.

4.3. For CI (Continuous Integration): Command-line compilation using Delphi for Linux requires additional options

If you own a Delphi version with a command-line compiler (this means: not a Community Edition), then you can compile from the command-line. This means that CGE build tool and CGE editor can both invoke Delphi compiler from the command-line. This is also useful for CI (Continuous Integration) systems. For example, to compile a project for Windows, you can use the following command:

castle-engine compile --compiler=delphi --verbose

The default target OS/CPU corresponds to your current (source) OS/CPU, which is pretty much guaranteed to be Win64/x86_64 since Delphi runs on Windows and all Windows installations are now 64-bit (it doesn’t matter that Delphi IDE is 32-bit here). So this is equivalent to

castle-engine compile --compiler=delphi --verbose --os=win64 --cpu=x86_64

Alas, to compile for Linux (on x86_64 CPU), this is not enough:

castle-engine compile --compiler=delphi --verbose --os=linux --cpu=x86_64

That’s because:

  • It will not find FMXLinux units.

  • Moreover, it cannot find Linux libraries to link to.

So you need to add them on the command-line. Below is an example using typical paths for Delphi 11.3:

castle-engine compile --compiler=delphi --verbose --os=linux \
  '--compiler-option=-UC:\Users\Public\Documents\Embarcadero\Studio\22.0\CatalogRepository\FmxLinux-1.74\source' \
  '--compiler-option=-UC:\Users\Public\Documents\Embarcadero\Studio\22.0\CatalogRepository\FmxLinux-1.74\lib\Release' \
  '--compiler-option=--syslibroot:C:\Users\michalis\Documents\Embarcadero\Studio\SDKs\ubuntu23.10.sdk\' \
  '--compiler-option=--libpath:C:\Users\michalis\Documents\Embarcadero\Studio\SDKs\ubuntu23.10.sdk\usr\lib\gcc\x86_64-linux-gnu\10;C:\Users\michalis\Documents\Embarcadero\Studio\SDKs\ubuntu23.10.sdk\usr\lib\x86_64-linux-gnu;C:\Users\michalis\Documents\Embarcadero\Studio\SDKs\ubuntu23.10.sdk\lib\x86_64-linux-gnu;C:\Users\michalis\Documents\Embarcadero\Studio\SDKs\ubuntu23.10.sdk\lib64;C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\linux64\release'

You can find these paths in Delphi IDE:

  • FMXLinux is in "Tools → Options → Language → Delphi → Library Path".

  • Libraries are in "Tools → Options → Deployment → SDK Manager → <your Linux connection> → Local root directory".

    They may use environment variables, also defined locally in Delphi IDE, you’ll have to expand them. You can also just take a look at the dcclinux64…​ command-line used by Delphi IDE when you compile a project for Linux from Delphi: it will contain also the correct --syslibroot etc.

  • Add one additional library location inside Delphi installation, C:\Program Files (x86)\Embarcadero\Studio\22.0\lib\linux64\release above.

5. Known Limitations

5.1. optirun doesn’t affect Delphi applications

optirun is a useful utility on some laptops with 2 GPUs. It allows to force an application to use the dedicated, faster GPU (like Nvidia), instead of the integrated, slower GPU (like Intel).

For unknown reason, using optirun, like optirun ./play_animation, doesn’t affect Delphi applications. They continue to run on integrated GPU.

Reason is unknown at this point. Notes about things we considered:

  • We use the same OpenGL header (CastleGL based on dglOpenGL) and even load OpenGL library in the same way (CastleDynLib) on FPC and Delphi. And optirun works on FPC applications.

  • Exporting NvOptimusEnablement on Delphi/Linux doesn’t change anything. It is possible, see this answer, but doesn’t affect anything on Linux (doesn’t change the default GPU, doesn’t change whether optirun works). This is similar to FPC (where NvOptimusEnablement needs to be exported differently, but it also doesn’t actually change anything on Linux, in our tests).

  • We tested changing CastleDynLib to handle shared libraries using directly dlopen / dlsym / dlclose, with and without RTLD_GLOBAL. (In case Delphi’s LoadLibrary did something non-standard on Linux.) It didn’t change anything — that is the resulting applications worked OK, but remained "invulnerable" to optirun.

5.2. "Loading" text is not displayed during Application.OnInitialize work

On other platforms (like Windows) or other compilers (like FPC), if you use TCastleWindow and put some work in Application.OnInitialize, then we display a simple screen with "Loading" text when it happens. Its look is configurable by adjusting colors or images.

Unfortunately, on Delphi/Linux, the "Loading" is not visible. Instead the application shows either a completely black window, or the window is not even visible before we finish Application.OnInitialize callback.

There’s no solution for now, it’s just a consequence of how FMXLinux works. Presumably, the same problem with happen if you put some work in Form.OnCreate in any FMX application, regardless of CGE, regardless of using TCastleControl or TCastleWindow. The FMX window is not drawn soon enough to show some UI.

Eventually, once we adjust GTK backend of TCastleWindow to Delphi, we will avoid using FMX in this case, and then we will control the window initialization completely — and the problem will be solved.


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