Die wachsenden Anforderungen an ein Pascal-basiertes Tool führten zu einer innovativen Lösung: zwei Ausführungsmodi aus einer einzigen Codebasis. Diese Strategie verbindet die Vorteile schneller Iteration mit der Effizienz nativer Kompilierung. Entwickelt parallel zum Designkapitel der Architektur, wurde das Konzept in Sprint 9 mit der Version 2.17.0 als stabiler Ausgangspunkt etabliert.
Ein Tool, zwei Wege: Interpretiert oder nativ
Das Tool crab-pascal bietet zwei Ausführungspfade für Pascal-Quellcode, die denselben Frontend-Prozess nutzen – Lexer, Parser, Präprozessor und semantische Analyse laufen in beiden Fällen identisch ab. Die Unterschiede zeigen sich erst in der Codegenerierung:
- Der Interpretiermodus (
crab-pascal run) führt den Code direkt aus, ohne vorherige Kompilierung. Ideal für schnelle Tests und Entwicklungszyklen. - Der Native-Modus (
crab-pascal build-exe) generiert C-Code, der anschließend mit gcc oder clang zu einem ausführbaren Binary kompiliert wird. Perfekt für Performance-kritische Anwendungen oder die Verteilung an Nutzer ohne Entwicklungsumgebung.
| Modus | Geschwindigkeit | Ausgabe | Compiler erforderlich | |-------|--------------|---------|-----------------------| | run | Schnellste Iteration | Ausgabe in Terminal | Nein | | build-exe | Langsamer durch Kompilierung | Binärdatei | Ja (gcc/clang) |
Im täglichen Entwicklungsprozess wird standardmäßig der Interpretiermodus genutzt. Für Releases oder Benchmarks kommt der Native-Modus zum Einsatz.
Interpretiermodus: Schnelligkeit ohne Kompromisse bei der Fehlerdiagnose
Der Befehl crab-pascal run examples/crud/crud.dpr startet die Ausführung direkt über einen integrierten Runtime-Interpreter. Dieser durchläuft den abstrakten Syntaxbaum (AST), verwaltet Speicherbereiche (Heap) und virtuelle Methodentabellen (VMT) – genau wie in den vorherigen Architektur-Dokumentationen beschrieben.
Besonders vorteilhaft ist die umfassende Fehleranalyse: Der Interpreter liefert präzise Fehlermeldungen mit Kontext, die den Debugging-Prozess deutlich verkürzen. Zudem entfällt die Abhängigkeit von externen C-Compilern, was die Einrichtung vereinfacht. Die Entwicklungszyklen in den Sprints profitieren von dieser Stabilität, da die meisten Testfälle (QA-Fixtures) direkt im Interpretiermodus validiert werden können.
Ein Nachteil besteht darin, dass das generierte Programm kein eigenständiges Binary ist. Ohne die Installation von CrabPascal kann der Code nicht an Dritte weitergegeben werden – ein wichtiger Punkt für die Planung von Deployment-Strategien.
Native Kompilierung: Maximale Performance und Unabhängigkeit
Mit dem Befehl crab-pascal build-exe examples/hello.dpr wird der Pascal-Code zunächst in C übersetzt. Anschließend kommt ein externer Compiler (gcc oder clang) zum Einsatz, um daraus eine ausführbare Datei zu erstellen. Der Prozess umfasst mehrere Schritte:
- Der Codegenerator übersetzt den Pascal-Code in C unter Verwendung von Runtime-Hilfsfunktionen aus der Datei
stubs.c. Diese enthält Implementierungen für grundlegende Datentypen wie Strings, Objekte und Systemfunktionen. - Der C-Compiler generiert das finale Binary (z. B.
hello.exeunter Windows oder eine ELF-Datei unter Linux).
Vorteile des Native-Modus:
- Echte native Performance: Die Ausführung erfolgt ohne den Overhead eines Interpreters, was besonders bei rechenintensiven Aufgaben spürbar ist.
- Einfache Distribution: Die generierte Binärdatei kann ohne zusätzliche Laufzeitumgebungen an Nutzer verteilt werden.
Herausforderungen zeigen sich vor allem bei fortschrittlichen Sprachfeatures:
- Einige Sprachkonstrukte wie Ausnahmen (
try/except) oder komplexe Generics-Fälle werden erst in späteren Sprints vollständig unterstützt. - Die Paritätsprüfung zwischen Interpretier- und Native-Modus ist entscheidend, um Inkonsistenzen früh zu erkennen.
Version 2.17.0: Transparenz als Grundprinzip
Bis zur Version 2.17.0 führte das Fehlen eines C-Compilers gelegentlich zu falsch positiven Build-Ergebnissen. Seitdem gelten strengere Regeln:
- Der Codegenerator erzeugt weiterhin C-Dateien, auch wenn kein Compiler verfügbar ist. Diese können in Pull Requests überprüft werden.
- Der Link-Schritt scheitert explizit, wenn kein Compiler gefunden wird – ein klares Signal für Entwickler.
- Fehler wie undefinierte Variablen werden nun konsistent in beiden Modi erkannt und gemeldet.
Um die Parität zwischen den Modi zu gewährleisten, stehen automatisierte Tests zur Verfügung:
cargo test --test run_build_parity
cargo test --libDiese Tests vergleichen nicht nur die Ausgaben, sondern auch die Exit-Codes, um sicherzustellen, dass beide Ausführungswege identische Ergebnisse liefern.
Entscheidungshilfe: Welcher Modus für welchen Einsatzzweck?
Nutzen Sie run für:
- Die Entwicklung von Horse-Webservices und API-Tests (siehe Post 036).
- Testgetriebene Entwicklung (TDD) für Parser- und semantische Prüfungen.
- Lehrzwecke, da Studierende das Verhalten von Pascal unmittelbar erleben.
Setzen Sie build-exe ein für:
- Die Verteilung von CLI-Tools an Maschinen ohne CrabPascal-Installation.
- Performance-Benchmarks gegen etablierte Pascal-Compiler wie Free Pascal oder Delphi.
- Die Validierung von Codegenerierungsfunktionen, z. B. für Strings (Sprint 10) oder Ausnahmen (Sprint 13).
Der Modus check ist ideal für:
- Integrationen in IDEs, die keine Ausführung erfordern (siehe Post 034). Der Fokus liegt hier auf statischer Analyse und Syntaxprüfung.
Konfiguration: Zentrale Steuerung beider Modi
Die Datei crabpascal.toml ermöglicht die zentrale Konfiguration beider Ausführungswege. Hier können Standard-Backends, Suchpfade und Präprozessor-Definitionen festgelegt werden. Wichtig: Die präprozessorbasierte bedingte Kompilierung gilt für beide Modi gleichermaßen, nachdem der Präprozessor durchlaufen wurde.
Auf Windows-Systemen unterstützt das Tool mehrere Compiler-Ketten:
- Microsoft Visual C++ (MSVC)
- MinGW
- Clang
Die Reihenfolge der Erkennung ist konfigurierbar. In CI-Umgebungen sollte die verwendete Toolchain dokumentiert werden.
Aktueller Stand der Parität: Was funktioniert – und was nicht
Die folgende Matrix gibt einen Überblick über den aktuellen Implementierungsstand (Stand: Sprint 9). Grüne Einträge sind stabil, gelbe Bereiche erfordern weitere Arbeit:
- Grün: Einfache Beispiele wie „Hello World“, arithmetische Operationen, Records.
- Grün (meistens): Generische Kollektionen (seit Sprint 7).
- Gelb: Behandlung von Ausnahmen (
try/except) im Native-Modus – geplant für Sprint 13. - Rot/Gelb: Langlaufende Horse-Anwendungen werden primär im Interpretiermodus getestet, da der Native-Modus hier variableres Verhalten zeigen kann.
Vor der Zusage an Kunden für native Builds sollte stets der Projektstatus geprüft werden.
CI-Pipeline: Automatisierte Validierung beider Modi
Ein minimalistisches Beispiel für eine Bitbucket-Pipeline, die beide Ausführungswege testet:
pipelines:
default:
- step:
script:
- cargo test
- ./target/release/crab-pascal check examples/hello.dpr
- ./target/release/crab-pascal run examples/hello.dpr
- ./target/release/crab-pascal build-exe examples/hello.dpr # erfordert gccEmpfehlung: Falls der gcc-Compiler die Pipeline deutlich verlangsamt, können die Schritte in separate Jobs aufgeteilt werden. Allerdings sollte der Schritt check nie ausgelassen werden, da er die Grundlage für alle weiteren Validierungen bildet. Die Version 2.17.0 dokumentiert eindrücklich, warum falsch-positive Build-Ergebnisse langfristig mehr Schaden anrichten als ein fehlgeschlagener Test.
Ausblick: Die Zukunft der dualen Ausführung
In Post 041 – Sprint 1 Review: Präzise Diagnoseinformationen – wird die Architektur weiterentwickelt. Der Fokus liegt auf der Verbesserung der Fehlermeldungen im check-Modus, die als Grundlage für IDE-Integrationen, CI-Pipelines und transparente Fehlerbehebung dienen. Diese Optimierungen sind der Schlüssel, um die Parität zwischen Interpretier- und Native-Modus weiter zu erhöhen und die Entwicklererfahrung zu verbessern.
KI-Zusammenfassung
Learn how CrabPascal’s dual-mode build system delivers faster development with interpreted execution and optimized native binaries from the same Pascal source code.