Inhaltsverzeichnis

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.

Compiler-Parameter-Referenz · 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:

  1. Seed kompiliert lyxc.lyx/tmp/lyxc_s3
  2. S3 kompiliert lyxc.lyx/tmp/lyxc_s4
  3. sha256sum s3 == sha256sum s4SINGULAR

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:


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