lyxc ist vollständig self-hosted: Der Compiler ist in Lyx selbst geschrieben (src/lyxc.lyx) und kompiliert sich seit Version 0.9 eigenständig. FPC wird nicht mehr benötigt.
Diese Anleitung beschreibt den Bootstrap-Prozess, die Selbstkompilierung, die Singularitätsprüfung und den Entwicklungsworkflow.
→ Compiler-Parameter-Referenz · Cross-Compilation-Guide
Da ein Compiler seine eigene Quelle nicht aus dem Nichts übersetzen kann, gibt es ein Seed-Binary:
src/lyxc_bootstrap ← singularitätsverifiziertes Seed-Binary
│
│ kompiliert
▼
src/lyxc.lyx → ./lyxc (Stufe 3: Seed → Quelle)
│
│ kompiliert sich selbst
▼
./lyxc.new (Stufe 4: Stufe-3 → Quelle)
Die Singularitätsprüfung (make singularity) stellt sicher, dass Stufe 3 und Stufe 4 bitidentisch sind — ein Nachweis, dass der Compiler keine Backdoor in seinen eigenen Output einschleust (Ken Thompsons „Trusting Trust“-Problem).
| Werkzeug | Zweck | Pflicht? |
|---|---|---|
make | Build-Automatisierung | Empfohlen |
git | Quellcode holen und aktualisieren | Empfohlen |
sha256sum | Singularitätsprüfung | Nur für make singularity |
Keine externen Toolchains, kein FPC, kein LLVM. lyxc schreibt ELF/PE/Mach-O direkt und ist vollständig self-contained.
git clone https://github.com/seolizer/lyxc.git
cd lyxc
lyxc/
├── src/
│ ├── lyxc.lyx Haupt-Quelldatei des Compilers (Lyx)
│ ├── lyxc_bootstrap Seed-Binary (verifiziert, kein Quellcode)
│ ├── frontend/ Lexer, Parser, AST-Aufbau
│ ├── ir/ Intermediate Representation, Optimierungspässe
│ ├── backend/ Codegeneratoren — ein Unterverzeichnis pro Ziel
│ │ ├── x86_64/ x86_64 ELF (Linux)
│ │ ├── arm64/ ARM64 ELF (Linux, Raspberry Pi)
│ │ ├── macho/ Mach-O (macOS)
│ │ ├── elf/ ELF gemeinsame Teile
│ │ ├── pe/ PE/COFF gemeinsame Teile
│ │ ├── riscv/ RISC-V 64 ELF
│ │ ├── xtensa/ Xtensa ELF (ESP32)
│ │ └── arm_cm/ ARM Cortex-M (Bare-Metal)
│ └── util/ Gemeinsame Hilfsfunktionen
├── std/ Lyx-Standardbibliothek (Standard-Units)
├── data/ Daten-Units
├── tests/ Compiler-Testsuite (Snapshot-Tests)
├── examples/ Beispielprogramme
└── Makefile
Beim ersten Mal — oder wenn kein aktuelles ./lyxc vorhanden ist:
make build
Das Seed-Binary src/lyxc_bootstrap kompiliert src/lyxc.lyx und erzeugt ./lyxc.
Sobald ein ./lyxc vorhanden ist, kann es sich selbst neu übersetzen:
make bootstrap
Intern wird ./lyxc src/lyxc.lyx -o lyxc.new ausgeführt, danach lyxc.new nach lyxc verschoben.
# Schritt 1: Aus Seed bauen
src/lyxc_bootstrap src/lyxc.lyx -o lyxc
# Schritt 2: Selbstkompilieren
./lyxc src/lyxc.lyx -o lyxc.new && mv lyxc.new lyxc
Stellt sicher, dass der Compiler deterministisch und backdoor-frei kompiliert:
make singularity
Ablauf:
lyxc.lyx → /tmp/lyxc_s3lyxc.lyx → /tmp/lyxc_s4sha256sum s3 == sha256sum s4 → SINGULARErwartete Ausgabe:
=== Singularitätsprüfung ===
abc123... /tmp/lyxc_s3
abc123... /tmp/lyxc_s4
SINGULAR: S3 == S4
Schlägt die Prüfung fehl, ist der Compiler nicht deterministisch oder der Seed wurde verändert.
Da lyxc self-contained ist, braucht man keine externe Toolchain. Ein lyxc-Binary für eine andere Plattform entsteht mit –target:
# lyxc für ARM64 (z.B. Raspberry Pi 4):
./lyxc src/lyxc.lyx --target=linux-arm64 -o lyxc-arm64
# lyxc für RISC-V 64:
./lyxc src/lyxc.lyx --target=linux-riscv64 -o lyxc-riscv64
# lyxc für Windows x86_64:
./lyxc src/lyxc.lyx --target=win64 -o lyxc.exe
# lyxc für macOS ARM64 (Apple Silicon):
./lyxc src/lyxc.lyx --target=macos-arm64 -o lyxc-macos-arm64
Das erzeugte Binary kann auf die Zielplattform übertragen und dort direkt ausgeführt werden.
Nach dem Build muss lyxc wissen, wo die Lyx-Units liegen:
export LYX_PATH=/pfad/zu/lyxc/std
./lyxc mein_programm.lyx -o mein_programm
sudo cp lyxc /usr/local/bin/lyxc
sudo mkdir -p /usr/local/lib/lyx
sudo cp -r std /usr/local/lib/lyx/std
sudo cp -r 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 ./std/ -o mein_programm
Vorkompilierte .lyu-Dateien beschleunigen spätere Builds erheblich:
make precompile-units
Oder einzeln:
./lyxc --compile-unit std/io.lyx -o std/io.lyu
lyxc sucht bei import std.io automatisch nach io.lyu vor io.lyx.
lyxc kennt eigene Diagnose-Flags — kein separater Build-Typ nötig:
# Debug-Symbole in das erzeugte Binary einbetten (DWARF):
./lyxc src/lyxc.lyx --debug -o lyxc-debug
# Beim Übersetzen eines Lyx-Programms IR als Pseudo-Assembler ausgeben:
./lyxc mein_programm.lyx --emit-asm -o /dev/null
# Import-Auflösung verfolgen:
./lyxc mein_programm.lyx --trace-imports -o /tmp/out
# Transformations-Pässe mit Timing ausgeben:
./lyxc mein_programm.lyx --trace-passes -o /tmp/out
| Flag | Bedeutung |
|---|---|
–debug | DWARF-Debug-Symbole in das Binary einbetten |
–debug-symbols | Debug-Symbole in .lyu-Units einbetten |
–emit-asm | IR als Pseudo-Assembler auf stderr ausgeben |
–trace-imports | Import-Auflösung Schritt für Schritt ausgeben |
–trace-passes | Optimierungspässe mit Laufzeit messen |
# Basis-Integrationstest (hello.lyx):
make test
# Snapshot-Testsuite (Regressionstest):
make snapshot
# Snapshot-Erwartungswerte aktualisieren (nach bewusstem Verhalten-Änderung):
make snapshot-update
Einzelnen Test manuell ausführen:
./lyxc examples/basics/hello.lyx -o /tmp/test_hello && /tmp/test_hello
make package
Erzeugt lyxc-0.9.3A.deb mit:
lyxc-Binary unter /usr/local/bin/lyxc/usr/include/lyx/units/Typischer Ablauf beim Arbeiten am Compiler:
# 1. Änderung in einer Backend-Datei vornehmen
# z.B. src/backend/x86_64/emit_x86.lyx
# 2. Compiler neu bauen (lyxc kompiliert sich selbst)
make bootstrap
# 3. Einzelnen Test ausführen
./lyxc examples/basics/hello.lyx -o /tmp/out && /tmp/out
# 4. IR-Ausgabe prüfen (was der Codegen erzeugt hat)
./lyxc examples/basics/hello.lyx --emit-asm -o /dev/null 2>&1 | less
# 5. Gesamt-Testsuite grün machen
make snapshot
# 6. Singularität sicherstellen
make singularity
lyxc baut inkrementell, sofern das lyxc-Binary aktuell ist. Ein Rebuild nach einer einzelnen Backend-Änderung dauert typisch wenige Sekunden.
Der Bootstrap-Lauf kann bei großen Adressräumen (ASLR) viel Speicher beanspruchen. Das Makefile begrenzt den virtuellen Speicher automatisch:
ulimit -v $(( 8 * 1024 * 1024 )) && src/lyxc_bootstrap src/lyxc.lyx -o lyxc
# Fehler: "error: unit 'std.io' not found"
# Pfade prüfen:
./lyxc --version # gibt den konfigurierten Stdlib-Pfad aus
# Manuell setzen:
export LYX_PATH=/pfad/zu/lyxc/std
./lyxc mein_programm.lyx -o mein_programm
# NICHT SINGULAR: S3 != S4
# → nicht-deterministisches Verhalten im Codegen (z.B. Zeigerarithmetik-Reihenfolge)
# Kandidaten prüfen:
./lyxc src/lyxc.lyx --trace-passes -o /dev/null 2>&1 | grep -i "order\|sort\|map"
# Minimales Testprogramm isolieren, das den Fehler auslöst
./lyxc test_minimal.lyx --trace-passes --emit-asm -o /dev/null 2>&1
# Stack-Trace + Lyx-Quellcode als Bug-Report einreichen
| Target | Aktion |
|---|---|
make build | Seed → ./lyxc (erster Bootstrap-Schritt) |
make bootstrap | ./lyxc kompiliert sich selbst neu |
make singularity | S3 == S4 prüfen (Backdoor-Nachweis) |
make test | Basis-Integrationstest (hello.lyx) |
make snapshot | Snapshot-Regressionstest |
make snapshot-update | Snapshot-Erwartungswerte aktualisieren |
make precompile-units | Standard-Units zu .lyu vorkompilieren |
make package | .deb-Paket bauen |
make keygen | Schlüssel-Generator bauen (nur intern) |
make clean | lyxc, lyxc.new, lyxc-keygen löschen |
Letzte Aktualisierung: 2026-06-08