====== Lyx – Compiler selbst kompilieren ======
''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.
→ [[lyx_-_programmiersprache:tools:compiler-parameter|Compiler-Parameter-Referenz]] · [[lyx_-_programmiersprache:guides:crosscompiling|Cross-Compilation-Guide]]
----
===== 1. Konzept: Seed → Stufe 3 → Stufe 4 =====
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).
----
===== 2. Voraussetzungen =====
^ 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.
----
===== 3. Quellcode beziehen =====
git clone https://github.com/seolizer/lyxc.git
cd lyxc
----
===== 4. Verzeichnisstruktur =====
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
----
===== 5. Build =====
==== Normaler Build (Seed → lyxc) ====
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''.
==== Selbstkompilierung (lyxc → 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.
==== Manuell (ohne Make) ====
# 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
----
===== 6. Singularitätsprüfung =====
Stellt sicher, dass der Compiler deterministisch und backdoor-frei kompiliert:
make singularity
Ablauf:
- Seed kompiliert ''lyxc.lyx'' → ''/tmp/lyxc_s3''
- S3 kompiliert ''lyxc.lyx'' → ''/tmp/lyxc_s4''
- ''sha256sum s3 == sha256sum s4'' → **SINGULAR**
Erwartete 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.
----
===== 7. Cross-Compilation des lyxc-Binaries =====
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.
----
===== 8. Standard-Library einrichten =====
Nach dem Build muss ''lyxc'' wissen, wo die Lyx-Units liegen:
==== Option A: Umgebungsvariable (Entwicklung) ====
export LYX_PATH=/pfad/zu/lyxc/std
./lyxc mein_programm.lyx -o mein_programm
==== Option B: Systemweite Installation ====
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
==== Option C: Suchpfad per Flag ====
./lyxc mein_programm.lyx -I ./std/ -o mein_programm
==== Standard-Units vorkompilieren ====
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''.
----
===== 9. Debug-Build für Compiler-Entwicklung =====
''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 |
----
===== 10. Tests ausführen =====
# 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
----
===== 11. Paket bauen (.deb) =====
make package
Erzeugt ''lyxc-0.9.3A.deb'' mit:
* ''lyxc''-Binary unter ''/usr/local/bin/lyxc''
* Vorkompilierte Units unter ''/usr/include/lyx/units/''
----
===== 12. Entwicklungsworkflow =====
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.
----
===== 13. Troubleshooting =====
==== OOM-Kill beim Bootstrap ====
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
==== lyxc findet Standard-Units nicht ====
# 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
==== Singularität schlägt fehl ====
# 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"
==== Internal Compiler Error (ICE) ====
# 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
----
===== Kurzreferenz: Make-Targets =====
^ 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