Inhaltsverzeichnis

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

Zurück: Aerospace & Safety – Sprachreferenz