Delphi-compatible Pascal toolchain for Win64 and Linux x86-64
compiler, Unicode RTL, memory manager, and qualification as one integrated whole
What it is for · Quick start · Diagnostics · Build profile · What changed · Performance · Qualification · Lazarus · Documentation
MoonCompiler is a self-contained environment for building modern Delphi code on Win64 and Linux x86-64. It grew out of a specific need: moving the core of a high-load cryptocurrency-scalping trading terminal, written in and still being developed with Delphi 12.2, to Linux.
The starting point was Unleashed, an FPC fork with support for modern Delphi syntax. Working against a complete production application required substantial work on its compiler, RTL, and memory manager.
MoonCompiler brings the modified compiler, Unicode RTL, packages, memory manager, and runtime units together as one supported x86-64 configuration. We validate and optimize that configuration as a whole.
The supported surface and intentionally retained boundaries are listed in Known Issues; future improvements are in the Backlog. Supported targets are Win64 and Linux x86-64. 32-bit targets, other CPU architectures, and macOS are neither supported nor planned.
MoonCompiler lets supported Delphi 12.2 code run on Linux without an application rewrite. The same toolchain builds native Win64 applications. Compiler and runtime optimizations target ordinary text, collection and server workloads.
In practice, this means:
- the same source continues to build with Delphi 12.2 and MoonCompiler;
- the Linux version uses the same types, algorithms, and application architecture rather than a port with different semantics;
- Unicode, threading, RTTI, exceptions, and the memory manager come from one ready-made profile instead of being configured anew for each project;
- the result is validated beyond “it compiled”: tests compare calculations, lifetime, ABI, and behaviour at different optimization levels;
- optional diagnostic reports preserve the original exception context and source locations, helping investigate failures in deployed Windows and Linux services;
- compiler, RTL, and MM performance is measured together on application hot paths, and bottlenecks are fixed where they originate—in the compiler, RTL, or MM.
Download the archive for your platform from
GitHub Releases,
unpack it into a directory named toolchain, and clone MoonORMot next to it.
No bootstrap compiler, no clone of this repository and no Python are needed.
Then build a program - this one, or examples/hello.dpr:
program hello;
begin
Writeln('Hello from MoonCompiler');
end.Linux:
mkdir -p ~/moon/toolchain && cd ~/moon
tar -xzf ~/Downloads/mooncompiler-toolchain-v2.4.5-linux-x86-64.tar.gz -C toolchain
git clone https://github.com/Moonbot-Tech/MoonORMot mormot
toolchain/bin/fpc hello.dpr
toolchain/bin/fpc -dRELEASE hello.dprWin64 PowerShell:
New-Item -ItemType Directory -Force C:\Moon | Set-Location
Expand-Archive $HOME\Downloads\mooncompiler-toolchain-v2.4.5-win64.zip -DestinationPath toolchain
git clone https://github.com/Moonbot-Tech/MoonORMot mormot
toolchain\bin\x86_64-win64\fpc.exe hello.dpr
toolchain\bin\x86_64-win64\fpc.exe -dRELEASE hello.dprfpc is the product: it reads only the configuration next to its own binary,
so the two commands are the same on both platforms and from any directory.
Without -dRELEASE the program is a Debug build. MoonORMot is not inside the
archive on purpose: the runtime units over mORMot (System.Zip,
System.Net.HttpClient, Moon.Diagnostics, ...) compile against the clone in
mormot, and git pull there is how it is updated.
Alternatively, build the same toolchain from source with the FPC 3.2.2 bootstrap compiler; this also clones MoonORMot next to the toolchain:
git clone https://github.com/Moonbot-Tech/MoonCompiler.git
cd MoonCompiler
./build compilergit clone https://github.com/Moonbot-Tech/MoonCompiler.git
Set-Location MoonCompiler
.\build.ps1 compilerThe source-build dependencies and the exact bootstrap commands are in Setup.
That is enough for a normal project. The toolchain's configuration adds the
Unicode RTL, Delphi namespaces, the runtime units and the bundled MM itself.
For a larger project, add a <Project>.mooncompiler file next to the .dpr
once - a file of compiler options: source trees (-Fu./** for a whole tree),
aliases and defines; the daily command stays the same. The format is described
in Project Build.
Heavy MM diagnostics can be enabled separately without changing Debug/Release semantics:
toolchain/bin/fpc -dFPCX64MM_DIAGNOSTIC hello.dprMoon.Diagnostics helps explain a failed request, crashed worker or stalled
service from a report produced by the application itself. It runs on Win64 and
Linux x86-64, including optimized Release builds.
- Find the failing code: exception reports retain the original call stack, function names and available source lines. Symbols travel inside the executable; deployment needs no separate map file, debugger or crash-handler process.
- Understand hardware faults: reports save registers, readable Intel ASM around the failing instruction, bounded memory fragments and memory-access information captured before exception unwinding.
- Investigate hangs: a manual report requested from a responsive thread samples all OS thread stacks, helping locate blocked workers and their callers.
- Keep application context: attach operation IDs, relevant state and log files. Reports are saved locally; ZIP delivery to an HTTP(S) endpoint is optional.
Enable reporting once, before starting application work and worker threads:
uses Moon.Diagnostics;
begin
InitializeReports;
// Start the application here.
end.Unhandled main-thread and TThread.Execute exceptions are reported automatically.
For a caught exception, call WriteExceptionReport inside except; use
WriteManualReport for an on-demand thread snapshot. The default output directory
is BugReports beside the executable. Linux requires libunwind.so.8; keep the
executable's embedded debug information when deploying either profile.
See the diagnostic guide for settings, capture costs and supported failure cases, or try the working example.
Users should not have to enumerate internal units or remember their ordering.
The product compiler automatically adds the required prefix before the user's
uses clause:
- Win64: bundled MM →
fpwinmonitor; - Linux x86-64: bundled MM →
cthreads→cwstring→fpmonitor.
Plain String always means UnicodeString. The byte domain is declared
explicitly with AnsiString, RawByteString, or TBytes. Debug and Release
use one validated runtime-check profile: I/O checking is enabled, while
overflow, range, and stack checking are disabled. Release uses -O3 and
AUTOINLINE; the presence of line information does not change program semantics.
The installed Unicode RTL and the application-facing packages are built with
the same -O3 (scripts/rtl-profile.txt, one definition for both drivers):
an application spends much of its time inside RTL code, and that code is
optimized and aligned like the application's own. At -O3 the compiler puts
procedure entries and loop heads on 32 bytes (CODEALIGN); the hand-laid
assembler routines of the RTL and of the bundled MM carry their own layout in
their source - the entry on a 64-byte line, the short form of a forward jump
written out as bytes where the assembler's single sizing pass would take the
long one (ASM layout rules). The code placement
draft of the internal assembler is off; MOONCOMPILER_PLACEMENT=1 in the
environment switches it on
(Optimizer, Code placement). The toolchain
records the exact profile, and qualification/build-driver/rtl_profile_gate.py
proves the installed RTL and package witness objects against it.
The product runtime can be explicitly disabled with
-dMOONCOMPILER_VANILLA_RUNTIME; Valgrind and ASan builds use cmem instead
of the bundled MM.
For the full layout of profiles and dependencies, see Setup and Project Build.
The repository contains more than 120 individual correctness, compatibility,
and performance fixes across the compiler and RTL. The supported Delphi surface
includes inline variables, anonymous methods and reference to, generics,
advanced and managed records, attributes, extended RTTI, and namespaces. For
example:
- after loop unrolling, the optimizer reused a stale table address, causing AES to diverge from FIPS-197 starting with the second round;
- Win64 code generation for
Currency * Currencytruncated an intermediate result to 64 bits and corrupted exact financial arithmetic; - an exception from
InitializeorAssignon a managed record or array left leaks or caused repeated finalization of a partially constructed value; - Linux exception unwinding could restore the wrong nonvolatile register and
corrupt a live exception object inside
finally.
For the full catalogue of symptoms, causes, and regression tests, see Compiler Fixes.
inline; forward; is accepted, and a unit's own {$MODE Delphi} is a no-op
under the product profile instead of a reset of the driver's switches. A
Delphi Win64 assembler body used on Linux is declared ms_abi_default (see
Project Build).
The product RTL uses UnicodeString as the normal String and provides the
Delphi surface applications need on both platforms. We fixed managed-value
lifetime, strings and encodings, collections, streams, tasks and threads, RTTI
invocation, file and network helpers, and the platform ABI. Win64 and Linux
build from one source contract; platform differences remain inside the RTL.
Delphi surface that Unleashed lacked and MoonBot/Arbitrage needed on Linux is written from behavioural contracts and standards, not from Embarcadero sources:
- text reader/writer classes in
System.Classes, with peeking, line/block reads, rewind, short-read handling and compatibleStreamExaliases; Classes.TBufferedFileStream, aTFileStreamwith one read/write window that is observably identical to the plain stream (thebufstreampage cache, which corrupted seek-back write patterns, is repaired as well);SyncObjs.TLightweightMREW, the readers/writer lock over the OS primitive (SRW lock, pthread rwlock): records initialize automatically, with the Linux-only timedTryBeginRead/TryBeginWriteas in Delphi;SyncObjs.TLightweightEventandTLightweightSemaphoreprovide manual-reset signaling and counted permits, with immediate acquisition when already ready;Generics.Collections.TThreadedQueue<T>andSyncObjs.TCountdownEventfor bounded producer/consumer queues and completion of parallel batches, including timeouts and shutdown (thread coordination);- historical time-zone conversion, Unicode custom-Variant dispatch and collection growth callbacks; Win64 delayed DLL imports and record-helper lookup;
- completed
System.JSON.Buildersbuilder/iterator operations with managed ownership, typed values, reset and exact quoted property paths; - direct Windows SDK bindings with consistent Unicode overloads and a documented
Linux
Posix.*surface; shared task callbacks, signed comparer hashes andTThread.Started(platform and runtime contracts); System.RegularExpressionsover a privately linked PCRE2 engine: no PCRE2 DLL or shared library to deploy, and no regex engine in programs that do not use it;Sockets.sockaddr_storage(TSockAddrStorage,PSockAddrStorage) andsocklen_t: the 128-byte,sockaddr_in6-aligned peer buffer forfprecvfrom/fpacceptof any family;System.Masks(TMask,MatchesMask,EMaskException) with the Delphi wildcard syntax and its quirks (*?, ASCII-only case folding, byte sets);System.ZLib: the zlib.h functions,TZCompressionStream/TZDecompressionStreamand theZCompress*/ZDecompress*helpers over zlib 1.3.1, linked as private objects on Win64 and Linux (no DLL, nolibz.so; no C runtime on Win64, the C library'smemcpy/memseton Linux); MoonORMot compresses through it too (System.Zip, mORMot's HTTP compression), so a program carries one zlib;System.Net.URLClient(TNetHeaders,TURLHeaders,TURLRequest,TCertificate,ENet*) without mORMot;- in
runtime/mormot, compiled into each project over its own mORMot:System.Zip(TZipFile,TZipHeader,EZip*overmormot.core.zip: entry streams inflated on demand from the mapped archive with CRC checking, ZIP64, UTF-8 names,ExtractAllthat refuses escaping names before writing anything),System.Net.Mime(TMultipartFormDataoverTHttpMultiPartStream, a flat RFC 7578 body that streams its files and reads more than once) andSystem.Net.HttpClient(THTTPClient,IHTTPResponse,IAsyncResult,TCookieManager,ENetHTTP*: keep-alive, the redirect table with method changes, cookies with domain/path/expiry rules, Basic authentication and proxy credentials, gzip/deflate throughContentAsStringorAutomaticDecompression, optional Brotli viaMoon.HttpClient.Brotli, upload/download progress, TLS validation, the standard asynchronous request family, cancellation and connection deadlines);
The accepted branch includes more than local peephole fixes; it also contains a dedicated optimization block:
- safe LICM with an explicit effects model;
- ADDRESSGVN and reuse of proven-stable addresses;
- precise register allocation and liveness around Windows SEH and Linux EH;
- shorter FP live ranges and register preservation through exception paths;
- CODEALIGN (entries and loop heads on 32 bytes; the code placement draft of the internal assembler is off by default) and x86-64 machine facts checked by dedicated gates.
The architecture, safety boundaries, and measured results are described in Optimizer.
The bundled MM is based on the mORMot FPC x86-64 MM and is part of the product profile. It is included before any user unit and has multithreaded arenas, validated small and medium size classes, and a separate diagnostic mode with an allocation registry, poison, structural checks, and a leak report. For details and licensing, see Memory Manager.
Performance is measured by Pulse, the benchmark system included in the repository. It combines compiler, RTL, and MM microbenchmarks with compact models of server and trading hot paths. Each case is built with both compilers from the same Pascal source; speed is considered only after their calculation results agree.
The second release reduces repeated work in string search, UTF-8 decoding,
dictionaries, loops and resource cleanup. It also speeds up compilation of large
programs with many generated classes and provides a portable direct fpc build.
Read what changed in MoonCompiler 2.0 for the practical
results, the measured workloads and upgrading instructions.
Selected confirmed examples from the 5 October release measurements:
| Useful operation | CPU cost removed vs Delphi 12.2, Win64 | CPU cost removed vs first Moon release, Win64 / Linux |
|---|---|---|
| UTF-16 substring search in a 64-character string | 24% | 52% / 56% |
| Decode 32 Cyrillic characters from UTF-8 | 60% | 83% / 79% |
| Add or update a numeric dictionary entry | 70% | 70% / 68% |
| Fill a reserved dictionary with numeric keys and string values | 13% | 51% / 50% |
| Scan a mixed JSON byte buffer | 32% | 36% / 34% |
Loop with a short try/finally |
37% | 29% / 63% |
These are reductions in the cost of the named work, not whole-application speedups or a complete-matrix average. Linux comparisons use the previous Moon release; Delphi comparisons are Windows-only. The measurement record identifies the tested source, machines, semantic checks and individual ratios. The bundled-MM comparison with the standard FPC allocator is a separate test using the same compiler; it is not a comparison of two compiler products.
To reproduce the complete current-versus-release comparison, configure the two hosts and their installed toolchains, then run:
python qualification/performance/tools/pulse_both.py --config <hosts.json>
For one host, use pulse_full.py; both commands use the fixed-work method,
identical-program controls and independent confirmation described in
Performance Qualification.
Earlier measurements remain in the Pulse history
and dated snapshots.
A green build of one project is not considered evidence of compatibility. Qualification is split into independent layers:
| System | What it validates |
|---|---|
| Focused regressions | The exact defect and the neighbouring boundaries of each fix |
| Mega and Omni | Broad language forms, their combinations, and optimization modes |
| Devil | Generated expression classes, ABI, managed lifetime, and a differential oracle |
| Chimera | Whole and split compositions transferred from MoonBot, Arbitrage, mORMot, and other Pascal projects |
| Resident | A multithreaded mix of runtime, collections, crypto, hashing, compression, numerical algorithms, and long-lived managed values |
| Project checks | Both mORMot lines, Lazarus, upstream regressions, and complete forms from other Pascal projects |
| RTL-test | RTL API, boundaries, ownership, exception cleanup, and multithreading |
| Pulse and Heartbeat | A semantic digest plus comparative performance |
Win64 and Linux run Debug/O2/O3 wherever the optimization level is part of the risk being checked. Light and impact-scoped gates are for the short fix cycle; full qualification is for a release exact HEAD. See Testing for commands and a map of the layers.
The pinned Lazarus version builds and launches with one command:
./lazarus.\lazarus.ps1On its first run, the driver builds the compiler, checks out the supported Lazarus commit, and creates an isolated IDE configuration. Lazarus sources are not patched. The toolchain contains two non-overlapping profiles: a normal FPC ABI for the IDE/LCL itself, and a Unicode product profile for Delphi-compatible applications.
Lazarus provides the editor, navigation, debugger, and designer. The product
build of a larger .dpr is the toolchain's fpc with the project's
.mooncompiler file next to it, so the IDE does not create a second set of
hidden settings. For details, see Lazarus setup.
compiler,rtl,packages,utils— toolchain;runtime/mm— the sole product memory manager;runtime/reporting— optional in-process exception and all-thread reports;runtime/mormot—System.Zip,System.Net.Mime,System.Net.HttpClientover the mORMot next to the toolchain, andMoonORMot.Need, the MoonORMot version these units require;examples— minimal Delphi-compatible projects for a quick start;tests— upstream tests and minimal compiler regressions;RTL-test— a separate matrix for RTL semantics and lifetime;qualification/suite— Mega, Omni, Devil, Chimera, corpora, and integration;qualification/performance— Pulse, Heartbeat, and versioned evidence;.qualification/deps/moonormot— the ignored, on-demand checkout of the exact MoonORMot commit used only by qualification; the pin must equal MoonORMotmain, andscripts/sync-moonormot.pykeeps it, the runtime units' version floor and the bundled MM on that tip together;mormot— the ignored clone of MoonORMot next totoolchainthat applications build against (build compilercreates it when it is missing);doc— public documentation.
A clone and normal build require only the repository contents and the bootstrap
tools from Setup; build compiler fetches MoonORMot once for
the applications, and qualification fetches its own pinned checkout.
- Release notes — current changes and upgrade requirements;
- Setup — a clean Linux and Win64 installation;
- Project Build — simple and multi-repository projects;
- Testing — Light/full qualification and the role of each layer;
- Compiler Fixes — catalogue of correctness, API, and ABI fixes;
- Performance Qualification — Pulse methodology;
- Optimizer — LICM, ADDRESSGVN, RA, and CODEALIGN;
- Memory Manager — MM, diagnostic mode, and limitations;
- Diagnostic Reports — opt-in file reports and embedded stack symbols;
- Known Issues — accepted observable boundaries;
- Backlog — intentionally deferred improvements;
- Development — rules for the next fix;
- Licensing — licenses, notices, and the linking exception.
The compiler is distributed under GPLv2 or later. The RTL and packages retain the modified LGPL and FPC static-link exception. The bundled MM retains its original disjunctive MPL-1.1/GPL/LGPL header and FPC linking exception. For the complete component map, see Licensing.
The memory manager is based on open-source Synopse mORMot;
the modified source and original notices are in runtime/mm.
Moonbot · MoonCompiler — Delphi-compatible Pascal toolchain · moonbot.pro