Der Lyx-Compiler lyxc ist in Free Pascal (FPC) implementiert. Das hat einen wesentlichen Vorteil: FPC ist selbst plattformübergreifend verfügbar und erzeugt native Binaries ohne externe Laufzeitabhängigkeiten — genau wie Lyx selbst.
Diese Anleitung beschreibt, wie lyxc aus dem Quellcode gebaut wird: für das eigene System (native Build), für andere Zielplattformen (Cross-Build) und im Debug-Modus für die Compiler-Entwicklung.
FPC ist die einzige zwingend notwendige Abhängigkeit. Version 3.2.2 oder neuer wird empfohlen.
# Ubuntu / Debian
sudo apt install fpc
# macOS (Homebrew)
brew install fpc
# Fedora / RHEL
sudo dnf install fpc
# Windows — Installer von fpc.freepascal.org
# Nach der Installation: fpc.exe im PATH
# Version prüfen
fpc -iV
Erwartete Ausgabe:
3.2.2
| Werkzeug | Zweck | Pflicht? |
|---|---|---|
make | Build-Automatisierung | Empfohlen |
git | Quellcode holen und aktualisieren | Empfohlen |
arm-linux-gnueabihf- Toolchain | Cross-Build für ARM64 | Nur bei Cross-Build |
riscv64-linux-gnu- Toolchain | Cross-Build für RISC-V | Nur bei Cross-Build |
xtensa-esp32-elf- Toolchain | Cross-Build für ESP32 | Nur bei Cross-Build |
| Lazarus IDE | Grafische Entwicklungsumgebung für FPC | Nein |
git clone https://github.com/seolizer/lyxc.git
cd lyxc
Oder als Tarball-Download ohne Git:
curl -L https://seolizer.de/lyx/releases/v0.8.5/lyxc-src.tar.gz | tar xz
cd lyxc-src/
lyxc/
├── lyxc.lpr Haupt-Projektdatei (FPC-Einstiegspunkt)
├── Makefile Build-Automatisierung
├── src/ Quellcode des Compilers
│ ├── frontend/ Lexer, Parser, AST-Aufbau
│ ├── ir/ Intermediate Representation, Optimierungspässe
│ ├── backend/ Codegenerator — ein Unterverzeichnis pro Ziel
│ │ ├── x86_64/ x86_64 ELF (Linux, macOS)
│ │ ├── arm64/ ARM64 ELF (Linux, Raspberry Pi)
│ │ ├── macosx64/ x86_64 Mach-O (macOS Intel)
│ │ ├── win_arm64/ ARM64 PE (Windows ARM)
│ │ ├── macho/ Mach-O gemeinsame Teile
│ │ ├── elf/ ELF gemeinsame Teile
│ │ ├── pe/ PE/COFF gemeinsame Teile
│ │ ├── riscv/ RISC-V 64 ELF
│ │ ├── xtensa/ Xtensa ELF (ESP32)
│ │ ├── esp32/ ESP32-spezifische Erweiterungen
│ │ └── arm_cm/ ARM Cortex-M (Bare-Metal)
│ └── util/ Gemeinsame Hilfsfunktionen
├── stdlib/ Lyx-Standardbibliothek (std/ und data/)
│ ├── std/ Standard-Units (.lyx-Quelldateien)
│ └── data/ Daten-Units (.lyx-Quelldateien)
├── tests/ Compiler-Testsuite
└── lib/ Vorkompilierte FPC-Units (Build-Artefakte)
make
Das Makefile erkennt das Host-System automatisch und wählt die passenden Flags. Das fertige Binary liegt danach unter ./lyxc.
Der vollständige Build-Befehl, wie ihn das Makefile intern verwendet:
mkdir -p lib && fpc \
-Mobjfpc \
-Sh \
-O2 \
-FUlib/ \
-Fusrc/util/ \
-Fusrc/frontend/ \
-Fusrc/ir/ \
-Fusrc/backend/ \
-Fusrc/backend/x86_64/ \
-Fusrc/backend/elf/ \
-Fusrc/backend/pe/ \
-Fusrc/backend/arm64/ \
-Fusrc/backend/macho/ \
-Fusrc/backend/xtensa/ \
-Fusrc/backend/esp32/ \
-Fusrc/backend/macosx64/ \
-Fusrc/backend/win_arm64/ \
-Fusrc/backend/riscv/ \
-Fusrc/backend/arm_cm/ \
lyxc.lpr -olyxc 2>&1
Erklärung der FPC-Parameter:
| Parameter | Bedeutung |
|---|---|
-Mobjfpc | Object Pascal-Dialekt (Klassen, generische Units) |
-Sh | Strings als AnsiString (nicht ShortString) — wichtig für Unicode-Handling |
-O2 | Compiler-Optimierung Stufe 2 — gutes Verhältnis Buildzeit/Performance |
-O3 | Maximale Optimierung — langsamerer Build, schnelleres lyxc-Binary |
-FUlib/ | Ausgabeverzeichnis für kompilierte .ppu-Dateien |
-Fu<pfad>/ | Suchpfad für FPC-Units (einmal pro Unterverzeichnis) |
-olyxc | Name des Ausgabe-Binaries |
-Tlinux | Zielbetriebssystem (linux, win64, darwin) |
-Px86_64 | Zielprozessor (x86_64, arm64, riscv64) |
-g | Debug-Symbole einbetten |
-gl | Zeilennummern in Stack-Traces |
-gh | Heap-Trace aktivieren (für Speicherleck-Diagnose) |
-dDEBUG | Conditional Compilation: Debug-Blöcke aktivieren |
-Xs | Strip Symbols — kleineres Binary, kein Debugging |
# Linux x86_64 → lyxc für Linux (Standard)
fpc -Tlinux -Px86_64 ... lyxc.lpr -olyxc
# macOS Intel → lyxc für macOS x86_64
fpc -Tdarwin -Px86_64 ... lyxc.lpr -olyxc
# macOS Apple Silicon → lyxc für ARM64
fpc -Tdarwin -Parm64 ... lyxc.lpr -olyxc
# Windows x86_64 → lyxc.exe
fpc -Twin64 -Px86_64 ... lyxc.lpr -olyxc.exe
Ein auf Linux x86_64 gebautes lyxc kann Code für alle Zielplattformen erzeugen — das ist gewöhnliche Cross-Compilation von Lyx-Programmen. Hier geht es um etwas anderes: Das lyxc-Binary selbst für eine andere Plattform bauen, z.B. um es auf einem Raspberry Pi auszuführen.
FPC unterstützt Cross-Compilation des Compilers direkt. Voraussetzung ist eine passende Binutils-Toolchain für die Zielplattform.
# Toolchain installieren
sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
# lyxc für ARM64 bauen
fpc -Tlinux -Parm64 \
-XPaarch64-linux-gnu- \
-Mobjfpc -Sh -O2 \
-FUlib_arm64/ \
-Fusrc/util/ -Fusrc/frontend/ -Fusrc/ir/ \
-Fusrc/backend/ -Fusrc/backend/arm64/ -Fusrc/backend/elf/ \
-Fusrc/backend/x86_64/ -Fusrc/backend/pe/ \
-Fusrc/backend/macho/ -Fusrc/backend/xtensa/ \
-Fusrc/backend/esp32/ -Fusrc/backend/riscv/ \
-Fusrc/backend/arm_cm/ -Fusrc/backend/macosx64/ \
-Fusrc/backend/win_arm64/ \
lyxc.lpr -olyxc-arm64
Das Binary lyxc-arm64 kann auf den Raspberry Pi übertragen und dort ausgeführt werden.
sudo apt install gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu
fpc -Tlinux -Priscv64 \
-XPriscv64-linux-gnu- \
-Mobjfpc -Sh -O2 \
-FUlib_riscv64/ \
-Fusrc/util/ -Fusrc/frontend/ -Fusrc/ir/ \
-Fusrc/backend/ -Fusrc/backend/riscv/ -Fusrc/backend/elf/ \
-Fusrc/backend/x86_64/ -Fusrc/backend/arm64/ -Fusrc/backend/pe/ \
-Fusrc/backend/macho/ -Fusrc/backend/xtensa/ \
-Fusrc/backend/esp32/ -Fusrc/backend/arm_cm/ \
-Fusrc/backend/macosx64/ -Fusrc/backend/win_arm64/ \
lyxc.lpr -olyxc-riscv64
sudo apt install mingw-w64
fpc -Twin64 -Px86_64 \
-Mobjfpc -Sh -O2 \
-FUlib_win64/ \
-Fusrc/util/ -Fusrc/frontend/ -Fusrc/ir/ \
-Fusrc/backend/ -Fusrc/backend/x86_64/ -Fusrc/backend/pe/ \
-Fusrc/backend/elf/ -Fusrc/backend/arm64/ \
-Fusrc/backend/macho/ -Fusrc/backend/xtensa/ \
-Fusrc/backend/esp32/ -Fusrc/backend/riscv/ \
-Fusrc/backend/arm_cm/ -Fusrc/backend/macosx64/ \
-Fusrc/backend/win_arm64/ \
lyxc.lpr -olyxc.exe
Das Makefile stellt fertige Targets bereit:
make cross-arm64 # lyxc-arm64
make cross-riscv64 # lyxc-riscv64
make cross-win64 # lyxc.exe
make all-targets # Alle Ziele auf einmal
Nach dem Build muss lyxc wissen, wo die Lyx-Units liegen. Es gibt drei Wege:
export LYX_PATH=/pfad/zu/lyxc/stdlib
./lyxc mein_programm.lyx -o mein_programm
# Binary installieren
sudo cp lyxc /usr/local/bin/lyxc
# Standard-Library installieren
sudo mkdir -p /usr/local/lib/lyx
sudo cp -r stdlib/std /usr/local/lib/lyx/std
sudo cp -r stdlib/data /usr/local/lib/lyx/data
# lyxc sucht /usr/local/lib/lyx/ standardmäßig — keine Variable nötig
lyxc mein_programm.lyx -o mein_programm
./lyxc mein_programm.lyx -I ./stdlib/ -o mein_programm
Vorkompilierte .lyu-Dateien beschleunigen den Build erheblich. Die Units werden einmalig kompiliert und dann wiederverwendet:
# Alle Standard-Units zu .lyu vorkompilieren
make stdlib
# Oder einzeln
./lyxc stdlib/std/io.lyx --compile-unit -o stdlib/std/io.lyu
./lyxc stdlib/std/math.lyx --compile-unit -o stdlib/std/math.lyu
Danach sucht lyxc bei import std.io automatisch nach io.lyu vor io.lyx.
Wer am Compiler selbst arbeitet, braucht einen Build mit Debug-Symbolen und Heap-Trace:
mkdir -p lib_debug && fpc \
-Mobjfpc -Sh \
-g -gl -gh \
-dDEBUG \
-FUlib_debug/ \
-Fusrc/util/ -Fusrc/frontend/ -Fusrc/ir/ \
-Fusrc/backend/ -Fusrc/backend/x86_64/ -Fusrc/backend/elf/ \
-Fusrc/backend/pe/ -Fusrc/backend/arm64/ -Fusrc/backend/macho/ \
-Fusrc/backend/xtensa/ -Fusrc/backend/esp32/ \
-Fusrc/backend/macosx64/ -Fusrc/backend/win_arm64/ \
-Fusrc/backend/riscv/ -Fusrc/backend/arm_cm/ \
lyxc.lpr -olyxc-debug 2>&1
make debug # Kurzform über Makefile
Mit dem Debug-Build erhält man bei einem Compiler-Absturz (Internal Compiler Error) einen vollständigen Stack-Trace:
An unhandled exception occurred at $00000000004A3B21:
EAccessViolation: Access violation
$00000000004A3B21 EMITMOVREG, line 847 of backend/x86_64/emit.pas
$000000000049F102 CODEGENEXPR, line 312 of backend/x86_64/codegen.pas
$000000000047E8CD COMPILEFN, line 198 of ir/lower.pas
$000000000043A012 MAIN, line 44 of lyxc.lpr
Der Debug-Build aktiviert außerdem alle {$IFDEF DEBUG}-Blöcke im Quellcode — das sind ausführliche Log-Ausgaben zu AST-Aufbau, IR-Generierung und Registerallokation:
./lyxc-debug test.lyx --trace-passes -o test 2>&1 | head -50
Im Verzeichnis tests/ liegen Lyx-Quelldateien, deren erwartetes Verhalten (Ausgabe, Fehlercode, Kompilierfehler) in Metadateien beschrieben ist.
# Alle Tests ausführen
make test
# Einzelne Testkategorie
make test-codegen # Codegenerator-Tests
make test-frontend # Lexer/Parser-Tests
make test-safety # DO-178C / Safety-Pragma-Tests
make test-cross # Cross-Compilation-Tests (langsam)
Beispielausgabe:
[PASS] tests/codegen/arith.lyx
[PASS] tests/codegen/structs.lyx
[PASS] tests/frontend/generics.lyx
[FAIL] tests/safety/stack_limit.lyx
Expected: "error: stack limit exceeded"
Got: "warning: stack limit exceeded"
[PASS] tests/cross/arm64_basic.lyx
...
Tests: 247 passed, 1 failed
Einzelnen Test manuell ausführen:
./lyxc tests/codegen/arith.lyx -o /tmp/test_arith && /tmp/test_arith
Typischer Ablauf beim Arbeiten am Compiler:
# 1. Änderung in einer Backend-Datei vornehmen
# z.B. src/backend/x86_64/emit.pas
# 2. Nur geänderte Units neu bauen (FPC inkrementell)
make
# 3. Einzelnen Test ausführen
./lyxc tests/codegen/mein_test.lyx -o /tmp/out && /tmp/out
# 4. Mit Debug-Ausgabe prüfen
./lyxc-debug tests/codegen/mein_test.lyx --trace-passes --emit-asm -o /tmp/out
# 5. Assembler-Ausgabe prüfen (was der Codegen erzeugt hat)
./lyxc tests/codegen/mein_test.lyx --emit-asm 2>&1 | less
# 6. Gesamte Testsuite grün machen
make test
# 7. Release-Build
make release # -O3, stripped, alle Targets
FPC baut inkrementell: Nur Units, deren Quelldatei neuer als die .ppu-Datei in lib/ ist, werden neu kompiliert. Ein Rebuild nach einer Änderung in emit.pas dauert typisch 3–8 Sekunden.
FPC findet eine Unit nicht. Ursachen und Lösungen:
# Fehlende -Fu-Option prüfen — jedes Unterverzeichnis braucht seinen eigenen -Fu
fpc ... -Fusrc/frontend/ -Fusrc/ir/ ...
# lib/-Verzeichnis fehlt
mkdir -p lib
# FPC-Unit-Cache löschen und neu bauen
rm -rf lib/
make clean && make
FPC läuft im falschen Modus. -Mobjfpc oder -Mobjfpc fehlt:
fpc -Mobjfpc -Sh ...
# Fehler: "ld: cannot find -lgcc"
# → Passende Binutils-Toolchain fehlt
# ARM64
sudo apt install binutils-aarch64-linux-gnu
# RISC-V
sudo apt install binutils-riscv64-linux-gnu
# Toolchain-Präfix prüfen
aarch64-linux-gnu-ld --version
FPC findet seine eigenen RTL-Units nicht — passiert nach einem FPC-Upgrade ohne Neuinstallation der RTL:
# FPC RTL-Pfad prüfen
fpc -iSP # System-Pfad anzeigen
# RTL neu bauen (aus FPC-Quellen)
cd /pfad/zu/fpc-source/rtl
make
# Oder FPC komplett neu installieren
brew reinstall fpc
FPC ist inkrementell, aber nur wenn das lib/-Verzeichnis erhalten bleibt:
# Falsch — löscht den Cache
make clean && make
# Richtig — inkrementell, nur Geänderte werden neu kompiliert
make
# Fehler: "error: unit 'std.io' not found"
# Prüfen welche Pfade lyxc durchsucht
./lyxc --version # gibt den konfigurierten Stdlib-Pfad aus
# Manuell setzen
export LYX_PATH=/pfad/zu/lyxc/stdlib
./lyxc mein_programm.lyx -o mein_programm
# Oder als Flag
./lyxc mein_programm.lyx -I ./stdlib/ -o mein_programm
Ein Bug im Compiler. Reproduzieren und melden:
# Minimales Testprogramm erstellen, das den Fehler auslöst
# Debug-Build für Stack-Trace
./lyxc-debug test_minimal.lyx -o /tmp/out 2>&1
# Stack-Trace + Lyx-Quellcode als Bug-Report einreichen
| Target | Aktion |
|---|---|
make | Native Debug-Build (schnell) |
make release | Optimierter Release-Build (-O3, stripped) |
make debug | Debug-Build mit Symbolen und Heap-Trace |
make stdlib | Standard-Library vorkompilieren |
make test | Gesamte Testsuite ausführen |
make test-codegen | Nur Codegen-Tests |
make test-safety | Nur Safety-Tests |
make cross-arm64 | lyxc-binary für ARM64 bauen |
make cross-riscv64 | lyxc-binary für RISC-V 64 bauen |
make cross-win64 | lyxc.exe für Windows bauen |
make all-targets | Alle Cross-Build-Targets |
make clean | Build-Artefakte löschen (lib/, lyxc, lyxc-debug) |
make install | Binary + Stdlib in /usr/local/ installieren |
make uninstall | Installation rückgängig machen |