====== Aerospace Tutorial: Von der Anforderung zum Nachweis ====== Dieses Tutorial führt Schritt für Schritt durch den vollständigen Entwicklungszyklus eines sicherheitskritischen Lyx-Programms — von der Projektstruktur über das Schreiben von Safety-konformem Code bis hin zur Erzeugung aller Zertifizierungsnachweise nach DO-178C. Als durchgehendes Beispiel dient ein **Altitude Monitor**: eine Komponente, die Druckrohdaten in Höhenmeter umrechnet, Grenzwerte überwacht und einen Warnung-Status ausgibt. Einfach genug, um den Fokus auf den Prozess zu legen — komplex genug, um alle relevanten Safety-Features zu zeigen. > **Zielgruppe:** Entwickler, die erstmals ein DO-178C-konformes Programm mit Lyx erstellen oder den gesamten Toolchain-Workflow kennenlernen wollen. ---- ===== 1. Projektstruktur anlegen ===== Eine klare Verzeichnisstruktur ist die Grundlage für nachvollziehbare, auditierbare Builds. DO-178C verlangt, dass Quellcode, Tests und Nachweise klar voneinander getrennt sind. mkdir -p altitude_monitor/{src,tests,build,evidence} cd altitude_monitor ^ Verzeichnis ^ Inhalt ^ | ''src/'' | Produktiver Quellcode (.lyx-Dateien) | | ''tests/'' | Testfälle und Testprogramme | | ''build/'' | Compiler-Ausgaben (Binaries, .lyu-Units) | | ''evidence/'' | Zertifizierungsnachweise (Reports, Logs, Graphs) | Struktur nach dem Tutorial: altitude_monitor/ ├── src/ │ ├── types.lyx # Gemeinsame Typdefinitionen │ └── altitude.lyx # Hauptkomponente ├── tests/ │ └── altitude_test.lyx # Testprogramm ├── build/ │ ├── altitude.elf │ └── altitude_test.elf └── evidence/ ├── call_graph.dot ├── coverage.html ├── static_analysis.log ├── stack_report.log └── provenance.log ---- ===== 2. Typdefinitionen schreiben ===== Alle gemeinsamen Typen kommen in eine eigene Datei. Range-Typen sind das erste Sicherheitsnetz — sie machen ungültige Zustände auf Typebene unmöglich. Datei: ''src/types.lyx'' unit AltitudeMonitor.Types; // Physikalische Wertebereiche — Compile-Zeit- und Laufzeit-geprüft type Altitude = int64 range -1000..15000; // Meter über MSL type Pressure = int64 range 10000..115000; // Pascal (10–1150 hPa) type Temperature = int64 range -90..60; // Grad Celsius type Confidence = int64 range 0..100; // Prozent // Warnstatus — geschlossene Menge, kein ungültiger Wert möglich type WarningLevel = enum { NOMINAL, CAUTION, // Annäherung an Grenzwert WARNING, // Grenzwert überschritten CRITICAL // Zweiter Grenzwert überschritten — sofortiger Handlungsbedarf }; // Sensor-Rohdaten vom ADC type SensorFrame = struct { pressure_raw: int64; temperature_raw: int64; valid: bool; sequence_id: int64; }; // Ausgabe der Altitude-Monitor-Komponente type AltitudeResult = struct { altitude: Altitude; warning: WarningLevel; confidence: Confidence; valid: bool; }; ---- ===== 3. Hauptkomponente schreiben ===== Die Hauptkomponente enthält die eigentliche Berechnungslogik. Jede Funktion, die im Regelzyklus aufgerufen wird, bekommt die entsprechenden Safety-Pragmas. Datei: ''src/altitude.lyx'' unit AltitudeMonitor; import AltitudeMonitor.Types; import std.math; // ── Grenzwerte ──────────────────────────────────────────────────────────────── con CAUTION_ALTITUDE: Altitude := 12000; // Meter — Vorsichtsgrenze con WARNING_ALTITUDE: Altitude := 13500; // Meter — Warngrenze con CRITICAL_ALTITUDE: Altitude := 14500; // Meter — Kritische Grenze con SEA_LEVEL_PRESSURE: f64 := 101325.0; // Pascal con SCALE_HEIGHT: f64 := 8434.0; // Meter (barometrische Formel) con MIN_CONFIDENCE: Confidence := 70; // Unter diesem Wert: Ergebnis ungültig // ── Interne Hilfsfunktionen ─────────────────────────────────────────────────── // Berechnet Höhe aus Luftdruck nach barometrischer Höhenformel // Kein @flight_crit — wird nur aus validierten Funktionen aufgerufen @stack_limit(128) fn PressureToAltitude(pressure_pa: f64): f64 { con EXPONENT: f64 := 0.190263; var ratio: f64 := pressure_pa / SEA_LEVEL_PRESSURE; return SCALE_HEIGHT * (1.0 - math.Pow(ratio, EXPONENT)); } // Berechnet Konfidenzwert aus Sensorkonsistenz (vereinfacht) @stack_limit(128) fn ComputeConfidence(frame: SensorFrame): Confidence { if (!frame.valid) { return 0; } // Plausibilitätsprüfung Druck vs. Temperatur (vereinfacht) var p_ok: bool := (frame.pressure_raw >= 10000) && (frame.pressure_raw <= 115000); var t_ok: bool := (frame.temperature_raw >= -90) && (frame.temperature_raw <= 60); if (!p_ok || !t_ok) { return 40; } return 95; } // Bestimmt Warnstufe aus berechneter Höhe @stack_limit(128) fn ClassifyAltitude(alt: Altitude): WarningLevel { if (alt >= CRITICAL_ALTITUDE) { return WarningLevel.CRITICAL; } if (alt >= WARNING_ALTITUDE) { return WarningLevel.WARNING; } if (alt >= CAUTION_ALTITUDE) { return WarningLevel.CAUTION; } return WarningLevel.NOMINAL; } // ── Hauptfunktion ───────────────────────────────────────────────────────────── @dal(B) @flight_crit @stack_limit(512) @wcet(800) pub fn ProcessSensorFrame(frame: SensorFrame): AltitudeResult { // Ungültige oder nicht plausible Frames sicher ablehnen if (!frame.valid) { return AltitudeResult { altitude: 0, warning: WarningLevel.NOMINAL, confidence: 0, valid: false }; } // TMR-Schutz für den berechneten Höhenwert @redundant var altitude_raw: f64 := PressureToAltitude(frame.pressure_raw as f64); // Clamping in den gültigen Range-Typ — Range-Typ übernimmt weitere Prüfung var alt_clamped: int64 := altitude_raw as int64; if (alt_clamped < -1000) { alt_clamped := -1000; } if (alt_clamped > 15000) { alt_clamped := 15000; } @redundant var altitude: Altitude := alt_clamped; var conf: Confidence := ComputeConfidence(frame); var warning: WarningLevel := ClassifyAltitude(altitude); // Ergebnis als ungültig markieren, wenn Konfidenz zu niedrig var result_valid: bool := (conf >= MIN_CONFIDENCE); return AltitudeResult { altitude: altitude, warning: warning, confidence: conf, valid: result_valid }; } ---- ===== 4. Tests schreiben ===== Tests in Lyx sind gewöhnliche Programme, die die zu testende Unit importieren. Für MC/DC müssen alle atomaren Bedingungen unabhängig voneinander den Gesamtausdruck beeinflussen — die Testfälle müssen diese Kombinationen explizit abdecken. Datei: ''tests/altitude_test.lyx'' unit AltitudeMonitor.Tests; import AltitudeMonitor; import AltitudeMonitor.Types; import std.test; // ── Hilfsfunktion ───────────────────────────────────────────────────────────── fn MakeFrame(pressure: int64, temp: int64, valid: bool): SensorFrame { return SensorFrame { pressure_raw: pressure, temperature_raw: temp, valid: valid, sequence_id: 1 }; } // ── Testfälle für ProcessSensorFrame ───────────────────────────────────────── // TC-01: Ungültiger Frame → result.valid = false, warning = NOMINAL fn TC01_InvalidFrame(): void { var frame := MakeFrame(101325, 15, false); var result := ProcessSensorFrame(frame); test.Assert(!result.valid, "TC-01: result.valid soll false sein"); test.Assert(result.warning == WarningLevel.NOMINAL, "TC-01: warning soll NOMINAL sein"); test.Assert(result.confidence == 0, "TC-01: confidence soll 0 sein"); } // TC-02: Normalbetrieb, Meeresspiegel — NOMINAL fn TC02_NominalSealevel(): void { var frame := MakeFrame(101325, 15, true); var result := ProcessSensorFrame(frame); test.Assert(result.valid, "TC-02: result.valid soll true sein"); test.Assert(result.warning == WarningLevel.NOMINAL, "TC-02: warning soll NOMINAL sein"); test.Assert(result.confidence >= 70, "TC-02: confidence soll >= 70 sein"); } // TC-03: Reiseflug ~10.000 m — NOMINAL (unterhalb CAUTION-Grenze) fn TC03_CruiseAltitude(): void { var frame := MakeFrame(26436, -45, true); // ~10.000 m var result := ProcessSensorFrame(frame); test.Assert(result.valid, "TC-03: result soll valid sein"); test.Assert(result.warning == WarningLevel.NOMINAL, "TC-03: 10.000m soll NOMINAL sein"); } // TC-04: CAUTION-Bereich (~12.500 m) fn TC04_CautionAltitude(): void { var frame := MakeFrame(19000, -55, true); // ~12.500 m var result := ProcessSensorFrame(frame); test.Assert(result.valid, "TC-04: result soll valid sein"); test.Assert(result.warning == WarningLevel.CAUTION, "TC-04: soll CAUTION sein"); } // TC-05: WARNING-Bereich (~13.800 m) fn TC05_WarningAltitude(): void { var frame := MakeFrame(16000, -60, true); // ~13.800 m var result := ProcessSensorFrame(frame); test.Assert(result.valid, "TC-05: result soll valid sein"); test.Assert(result.warning == WarningLevel.WARNING, "TC-05: soll WARNING sein"); } // TC-06: CRITICAL-Bereich (~14.700 m) fn TC06_CriticalAltitude(): void { var frame := MakeFrame(14000, -62, true); // ~14.700 m var result := ProcessSensorFrame(frame); test.Assert(result.valid, "TC-06: result soll valid sein"); test.Assert(result.warning == WarningLevel.CRITICAL, "TC-06: soll CRITICAL sein"); } // TC-07: Druck außerhalb Plausibilitätsbereich → confidence < MIN → result.valid = false fn TC07_ImplausiblePressure(): void { var frame := MakeFrame(5000, 15, true); // Druck zu niedrig (< 10000 Pa) var result := ProcessSensorFrame(frame); test.Assert(!result.valid, "TC-07: implausible pressure soll result.valid = false ergeben"); } // TC-08: Temperatur außerhalb Plausibilitätsbereich fn TC08_ImplausibleTemperature(): void { var frame := MakeFrame(101325, 80, true); // Temperatur zu hoch (> 60°C) var result := ProcessSensorFrame(frame); test.Assert(!result.valid, "TC-08: implausible temperature soll result.valid = false ergeben"); } // TC-09: Grenzwert genau an CAUTION-Grenze (Boundary Value) fn TC09_BoundaryCAUTION(): void { // Druck der ~12.000 m entspricht (Boundary Value Analysis) var frame := MakeFrame(19330, -56, true); var result := ProcessSensorFrame(frame); test.Assert(result.valid, "TC-09: Boundary-Frame soll valid sein"); // Warning ist CAUTION oder NOMINAL je nach exaktem Rundungsverhalten } // TC-10: MC/DC — frame.valid=false dominiert, Pressure/Temp irrelevant fn TC10_MCDC_InvalidOverrides(): void { var frame := MakeFrame(5000, 80, false); // Beide Werte außerhalb + invalid var result := ProcessSensorFrame(frame); test.Assert(!result.valid, "TC-10: MCDC: invalid-Flag dominiert"); test.Assert(result.confidence == 0, "TC-10: MCDC: confidence soll 0 sein"); } // ── Einstiegspunkt ──────────────────────────────────────────────────────────── fn main(): int64 { test.Begin("AltitudeMonitor — Testlauf"); TC01_InvalidFrame(); TC02_NominalSealevel(); TC03_CruiseAltitude(); TC04_CautionAltitude(); TC05_WarningAltitude(); TC06_CriticalAltitude(); TC07_ImplausiblePressure(); TC08_ImplausibleTemperature(); TC09_BoundaryCAUTION(); TC10_MCDC_InvalidOverrides(); test.End(); return 0; } ---- ===== 5. Safety-Build durchführen ===== Der erste Build dient der Überprüfung: Sind alle Safety-Regeln eingehalten? Compiliert der Code ohne Warnungen? # Typen kompilieren (vorkompilierte Unit erzeugen) lyxc src/types.lyx \ --compile-unit \ --lint \ -o build/types.lyu # Hauptkomponente kompilieren — vollständige Safety-Prüfung lyxc src/altitude.lyx \ -I build/ \ --lint \ --static-analysis \ --stack-check \ --target=arm64 \ -o build/altitude.elf Erwartete Ausgabe bei korrektem Code: [lint] AltitudeMonitor — OK (0 warnings, 0 errors) [stack] ProcessSensorFrame: 312 bytes / 512 limit — OK [stack] PressureToAltitude: 96 bytes / 128 limit — OK [stack] ComputeConfidence: 80 bytes / 128 limit — OK [stack] ClassifyAltitude: 64 bytes / 128 limit — OK [build] build/altitude.elf — OK Häufige Lint-Fehler und ihre Bedeutung: ^ Fehlermeldung ^ Bedeutung ^ Lösung ^ | ''heap allocation in @flight_crit function'' | ''new'' innerhalb einer @flight_crit-Funktion | ''new'' in die Initialisierungsphase verschieben | | ''unbounded loop in @flight_crit context'' | Schleife ohne ''limit(N)'' | ''limit(N)'' hinzufügen | | ''missing @stack_limit on @flight_crit function'' | Kein Stack-Budget definiert | ''@stack_limit(N)'' ergänzen | | ''range violation: value 16000 exceeds Altitude range'' | Konstante verletzt Range-Typ | Konstante oder Typ korrigieren | | ''@wcet annotation missing for DAL-B function'' | DAL-B verlangt WCET-Budget | ''@wcet(N)'' ergänzen | ---- ===== 6. Tests bauen und ausführen ===== # Testprogramm kompilieren lyxc tests/altitude_test.lyx \ -I build/ \ --lint \ -o build/altitude_test.elf # Tests ausführen ./build/altitude_test.elf Erwartete Ausgabe: === AltitudeMonitor — Testlauf === [PASS] TC-01: result.valid soll false sein [PASS] TC-01: warning soll NOMINAL sein [PASS] TC-01: confidence soll 0 sein [PASS] TC-02: result.valid soll true sein [PASS] TC-02: warning soll NOMINAL sein [PASS] TC-02: confidence soll >= 70 sein [PASS] TC-03: result soll valid sein [PASS] TC-03: 10.000m soll NOMINAL sein [PASS] TC-04: result soll valid sein [PASS] TC-04: soll CAUTION sein [PASS] TC-05: result soll valid sein [PASS] TC-05: soll WARNING sein [PASS] TC-06: result soll valid sein [PASS] TC-06: soll CRITICAL sein [PASS] TC-07: implausible pressure soll result.valid = false ergeben [PASS] TC-08: implausible temperature soll result.valid = false ergeben [PASS] TC-09: Boundary-Frame soll valid sein [PASS] TC-10: MCDC: invalid-Flag dominiert [PASS] TC-10: MCDC: confidence soll 0 sein === ALLE TESTS BESTANDEN (19/19) === ---- ===== 7. Statische Analyse und Call-Graph ===== Die statische Analyse sucht nach Problemen, die Compiler und Tests allein nicht finden — unerreichbarer Code, potenzielle Null-Pointer, nicht initialisierte Variablen, Division durch null. lyxc src/altitude.lyx \ -I build/ \ --static-analysis \ 2>&1 | tee evidence/static_analysis.log Beispielausgabe: [analysis] AltitudeMonitor — ProcessSensorFrame [OK] No unreachable code detected [OK] No null-pointer dereferences detected [OK] No uninitialized variables [OK] No division-by-zero paths [OK] All enum cases handled in ClassifyAltitude [analysis] Completed — 0 issues Call-Graph erzeugen (zeigt, welche Funktion welche aufruft — Pflichtnachweis für DO-178C): lyxc src/altitude.lyx \ -I build/ \ --call-graph \ -o evidence/call_graph.dot # Visualisierung als PNG (benötigt Graphviz) dot -Tpng evidence/call_graph.dot -o evidence/call_graph.png Der Call-Graph zeigt u.a., dass ''ProcessSensorFrame'' genau drei interne Funktionen aufruft (''PressureToAltitude'', ''ComputeConfidence'', ''ClassifyAltitude'') und keine externen oder nicht validierten Funktionen — das ist für DAL-B eine Anforderung. ---- ===== 8. Stack-Report erstellen ===== Der Stack-Report dokumentiert den maximalen Stack-Verbrauch jeder Funktion auf dem gesamten Call-Graph. Er ist der Nachweis, dass kein Stack-Overflow auftreten kann. lyxc src/altitude.lyx \ -I build/ \ --stack-check \ 2>&1 | tee evidence/stack_report.log Beispielausgabe: [stack-check] AltitudeMonitor ProcessSensorFrame 312 / 512 bytes OK PressureToAltitude 96 / 128 bytes OK ComputeConfidence 80 / 128 bytes OK ClassifyAltitude 64 / 128 bytes OK Worst-case call depth: ProcessSensorFrame → PressureToAltitude Worst-case stack total: 408 bytes [stack-check] All limits satisfied — PASS ---- ===== 9. MC/DC-Coverage messen ===== MC/DC (Modified Condition/Decision Coverage) ist für DAL-A und DAL-B vorgeschrieben. Jede atomare Bedingung in einem booleschen Ausdruck muss nachweislich unabhängig voneinander den Gesamtausdruck beeinflussen. Schritt 1 — Instrumentiertes Binary erzeugen: lyxc src/altitude.lyx \ -I build/ \ --mcdc-instrument \ -o build/altitude_instrumented.elf Schritt 2 — Tests mit dem instrumentierten Binary laufen lassen: lyxc tests/altitude_test.lyx \ -I build/ \ --link build/altitude_instrumented.elf \ -o build/altitude_test_cov.elf ./build/altitude_test_cov.elf # Coverage-Daten werden automatisch in altitude_monitor.coverage geschrieben Schritt 3 — Coverage-Report erzeugen: lyxc --coverage-report altitude_monitor.coverage \ -o evidence/coverage.html Beispiel-Report-Ausgabe (Konsolenübersicht): Coverage Report — AltitudeMonitor ══════════════════════════════════════════════════════════════ Function Line Branch MC/DC ────────────────────────────────────────────────────────────── ProcessSensorFrame 100% 100% 100% ✓ PressureToAltitude 100% 100% 100% ✓ ComputeConfidence 100% 100% 88% ✗ ← DAL-B: OK, DAL-A: nicht ausreichend ClassifyAltitude 100% 100% 100% ✓ ────────────────────────────────────────────────────────────── GESAMT 100% 100% 97% ══════════════════════════════════════════════════════════════ DAL-B Anforderung: 100% MC/DC für alle @dal(B)-Funktionen — PASS Was das Ergebnis bedeutet: ''ComputeConfidence'' hat 88 % MC/DC. Für DAL-B ist das kein Problem — die Funktion ist nicht mit ''@dal(B)'' annotiert. Wäre das Projekt DAL-A, müsste ein weiterer Testfall ergänzt werden, der die fehlende Kombination abdeckt. ==== MC/DC-Lücke schließen (DAL-A Beispiel) ==== Der Report zeigt, welche Bedingung fehlt: [mcdc-gap] ComputeConfidence — Bedingung 'frame.valid' hat keinen Test, bei dem 'p_ok && t_ok = true' aber 'frame.valid' allein das Ergebnis bestimmt. Fehlende Kombination: valid=true, p_ok=true, t_ok=true → nur valid=false dreht Ergebnis. Zusätzlichen Testfall ergänzen: // TC-11: MC/DC — valid=false bei sonst gültigen Werten fn TC11_MCDC_ValidAlone(): void { var frame_valid := MakeFrame(101325, 15, true); var frame_invalid := MakeFrame(101325, 15, false); var r_valid := ProcessSensorFrame(frame_valid); var r_invalid := ProcessSensorFrame(frame_invalid); // Nur 'valid' unterscheidet sich — MC/DC-Nachweis für diese Bedingung test.Assert( r_valid.valid, "TC-11: valid=true → result.valid = true"); test.Assert(!r_invalid.valid, "TC-11: valid=false → result.valid = false"); } ---- ===== 10. Provenance und Audit-Log ===== Für die Zertifizierung muss nachweisbar sein, dass der gelieferte Maschinencode aus dem geprüften Quellcode entstanden ist — bit-identisch, reproduzierbar. # Reproduzierbaren Final-Build mit vollständigem Audit-Log erzeugen lyxc src/altitude.lyx \ -I build/ \ --lint \ --static-analysis \ --stack-check \ --provenance \ --trace-passes \ --target=arm64 \ -o build/altitude_final.elf \ 2>&1 | tee evidence/provenance.log ''--provenance'' schreibt für jede IR-Transformation einen signierten Eintrag ins Log: [provenance] Source: src/altitude.lyx SHA256: a3f8...c291 [provenance] Unit: build/types.lyu SHA256: 7b21...e04a [provenance] Pass 01: parse → AST [provenance] Pass 02: type-check → typed AST [provenance] Pass 03: range-check → annotated AST [provenance] Pass 04: lower → IR [provenance] Pass 05: mcdc-instrument → instrumented IR [provenance] Pass 06: codegen arm64 → ELF [provenance] Output: build/altitude_final.elf SHA256: 19d4...f7a2 [provenance] Compiler: lyxc v0.8.5-aerospace [provenance] Flags: --lint --static-analysis --stack-check --provenance --trace-passes --target=arm64 [provenance] Timestamp: 2026-05-22T14:30:00Z ''--build-info'' zeigt die Compiler-Version und Build-Konfiguration, die im Abnahmedokument festgehalten wird: lyxc --build-info lyxc version: 0.8.5-aerospace Target: arm64-linux-elf Build date: 2026-05-22 Reproducible: yes FIPS: no ---- ===== 11. Nachweis-Checkliste nach DAL-Level ===== Die folgende Tabelle zeigt, welche Schritte aus diesem Tutorial für welches DAL-Level verpflichtend sind. ^ Nachweis ^ DAL-A ^ DAL-B ^ DAL-C ^ DAL-D ^ | ''--lint'' (DO-178C-Konformitätsprüfung) | ✓ | ✓ | ✓ | ✓ | | ''--static-analysis'' | ✓ | ✓ | ✓ | — | | ''--stack-check'' (Stack-Report) | ✓ | ✓ | — | — | | ''--call-graph'' (Call-Graph-Dokumentation) | ✓ | ✓ | ✓ | — | | ''--mcdc-instrument'' + 100 % MC/DC | ✓ | ✓ | — | — | | Statement Coverage 100 % | ✓ | ✓ | ✓ | ✓ | | Branch Coverage 100 % | ✓ | ✓ | ✓ | — | | ''--provenance'' (Traceability) | ✓ | ✓ | — | — | | ''--trace-passes'' (Audit-Log) | ✓ | — | — | — | | ''@redundant'' (TMR) für Zustandsvariablen | ✓ (empfohlen) | — | — | — | | ''@integrity(mode: lockstep)'' | ✓ (empfohlen) | — | — | — | | Boundary Value Analysis in Tests | ✓ | ✓ | ✓ | — | | ''@dal''-Annotation im Quellcode | ✓ | ✓ | ✓ | ✓ | ---- ===== 12. Vollständiger Build-Ablauf (Skript) ===== Das folgende Skript führt alle Schritte in der richtigen Reihenfolge aus und legt alle Nachweise im ''evidence/''-Verzeichnis ab. Es kann als Basis für eine CI/CD-Pipeline oder einen manuellen Abnahme-Build dienen. #!/bin/bash set -e # Abbruch bei jedem Fehler echo "=== AltitudeMonitor — Safety Build ===" # 1. Typen-Unit kompilieren lyxc src/types.lyx \ --compile-unit \ --lint \ -o build/types.lyu # 2. Hauptkomponente — Lint + Statische Analyse lyxc src/altitude.lyx \ -I build/ \ --lint \ --static-analysis \ --stack-check \ --call-graph -o evidence/call_graph.dot \ --target=arm64 \ -o build/altitude.elf \ 2>&1 | tee evidence/static_analysis.log # 3. Tests bauen und ausführen lyxc tests/altitude_test.lyx \ -I build/ \ --lint \ -o build/altitude_test.elf ./build/altitude_test.elf # 4. MC/DC-Instrumentierung und Coverage lyxc src/altitude.lyx \ -I build/ \ --mcdc-instrument \ --target=arm64 \ -o build/altitude_instrumented.elf lyxc tests/altitude_test.lyx \ -I build/ \ --link build/altitude_instrumented.elf \ -o build/altitude_test_cov.elf ./build/altitude_test_cov.elf lyxc --coverage-report altitude_monitor.coverage \ -o evidence/coverage.html # 5. Final-Build mit Provenance lyxc src/altitude.lyx \ -I build/ \ --lint \ --static-analysis \ --stack-check \ --provenance \ --trace-passes \ --target=arm64 \ -o build/altitude_final.elf \ 2>&1 | tee evidence/provenance.log # 6. Call-Graph als PNG (optional, benötigt Graphviz) if command -v dot &> /dev/null; then dot -Tpng evidence/call_graph.dot -o evidence/call_graph.png fi echo "" echo "=== Build erfolgreich ===" echo "Nachweise in evidence/:" ls -lh evidence/ ---- ===== Zusammenfassung ===== ^ Schritt ^ Kommando ^ Artefakt ^ | Typen-Unit | ''lyxc --compile-unit --lint'' | ''build/types.lyu'' | | Safety-Build | ''--lint --static-analysis --stack-check'' | ''build/altitude.elf'' | | Tests ausführen | ''./build/altitude_test.elf'' | Konsolenausgabe | | Statische Analyse | ''--static-analysis'' | ''evidence/static_analysis.log'' | | Call-Graph | ''--call-graph'' | ''evidence/call_graph.dot'' | | Stack-Report | ''--stack-check'' | ''evidence/stack_report.log'' | | MC/DC-Coverage | ''--mcdc-instrument'' + ''--coverage-report'' | ''evidence/coverage.html'' | | Provenance | ''--provenance --trace-passes'' | ''evidence/provenance.log'' | → [[lyx_-_programmiersprache:aerospace-safety|Zurück: Aerospace & Safety – Sprachreferenz]]