====== 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