# Multiplatform AOT mit SQLite-:, wie man es funktioniert

<!--category -- .NET, AOT, SQLite, DevOps -->
<datetime class="hidden">2025-12-16T15:00</datetime>

# Einleitung

Native AOT verspricht, Ihre .-NET-Anwendungen in winzige , self-- integrierte Executables umzuwandeln, die sofort starten und überall laufen lassen.—Keine Laufzeitinstallation erforderlich. `DllNotFoundException` Abstürze kämpfen mit transitiven Abhängigkeiten und fragen sich, warum `PublishSingleFile=true` doesns-' bündelt tatsächlich alles in eine einzelne Datei.. , Dies ist die komplette , , Anfänger ,- , zu erhalten SQLite Arbeit mit Native AOT , , , Gebäude für mehrere Plattformen , und Automatisierung von Releases mit GitHub Actions , . , Bis zum Ende haben ' , Sie haben Binärdateien , die unter Windows laufen , unter , , Linux , einschließlich Raspberry Pi...

## Was ist AOT.? und warum sollten Sie sich darum kümmern?

Lassen Sie die 's mit den absoluten Basics beginnen Wenn du jemals eine . NET-Anwendung gebaut hast und dich gefragt hast, warum du die ". NET Laufzeit auf Servern installieren musst oder warum deine Konsolen-App eine Sekunde dauert, um das erste Mal zu starten, wenn du es ausführst.,.AOT ist die Antwort auf diese Probleme.

### Wie .-NET normalerweise funktioniert (JIT Compilation

Wenn du den Code schreibst und deine Anwendung erstellst, dann produziert der Compiler doesns-'.t Maschinencode, den deine CPU direkt ausführen kann, stattdessen erzeugt es etwas namens ,. **Mittlere Sprache**Denken Sie daran, wie auf halbem Weg zwischen Ihrem Code und den eigentlichen Maschinenanweisungen.

Wenn du deine .-NET-App hier ausführst, was passiert

1. Ihr Computer lädt das separate Programm (
2. Die Laufzeit liest Ihren IL-Code
3. **Nur in der Zeit von (JIT-)** compiler konvertiert IL in nativen Maschinencode, während Ihre App läuft
4. Ihre CPU führt endlich diesen Maschinencode aus

Dies ist wie mit einem Übersetzer, der Ihr Rezept liest (.IL.) und übersetzt es mündlich zu einem Küchenchef übersetzt.

- Die Runtime von -. NET ist von zusätzlichen Dateien, die Sie bereitstellen müssen
- Der JIT-Compiler braucht Zeit, um Code zu übersetzen.
- Der JIT Compiler selbst sitzt im Speicher, während Ihre App läuft

### Geben Sie AOT (Ahead--Of ---Zeitkompilierung ein

Native AOT kippt dieses Modell auf seinen Kopf, statt Ihren Code zur Laufzeit zu übersetzen, es übersetzt alles **zur Bauzeit**Sie enden mit einer einzigen ausführbaren Datei, die tatsächlichen Maschinencode enthält, den Ihre CPU direkt ausführen kann.

Denken Sie daran, wie immer ein professionell übersetztes Rezept Buch statt der Einstellung eines Live-Übersetzers Die Arbeit wird einmal getan ., ?upfront ?, ? und das Ergebnis ist sofort einsatzbereit

### Die Vorteile des Spiels

Hier ist, was Native AOT Ihnen gibt.

**Ausführbare kleine Dateien**:, MKS1MB statt 150, MMS3, MWS3

Ihre App und alles, was es braucht, wird in eine kleine binäre kompiliert... Keine separaten Laufzeitdateien...

**Sofortige Inbetriebnahme**Schnellere Kaltstarts

Meine Tests...:... normal.... NET nahm ~800 ms, um zu starten., - AOT nahm ~150 ms. - There...'... kein JIT warm...- up time...MSC8...der Maschinencode ist sofort fertig.

**Keine Abhängigkeiten**Keine Laufzeit erforderlich

Sie können Ihre ausführbare Maschine auf eine beliebige Maschine kopieren, mit dem richtigen OS (.Windows./.Linux./.Mac...). und es läuft einfach.MS K4. Nein.MSC5.install.

**Untere Speichernutzung**Mehr als mehr als weniger Speicher

Kein JIT-Compiler, der im Speicher sitzt... in meiner Gateway-Anwendung... normales .-NET benutzte .85-MB im Leerlauf... verwendete AOT...

**Besser für eingeschränkte Umgebungen**Arbeiten, bei denen JIT

Einige Umgebungen – sichere Docker-Container – iOS – eingebettete Systeme – ) – don-' – erlauben die Erzeugung von Laufzeitcodes – . – AOT funktioniert überall

### Die Trade- ---offs - (-There immer ein Catch-)

AOT ist ,' ,t magic , . , You , ' ,re Trading-Laufzeitflexibilität für die Upfront-Optimierung

**Keine dynamische Codegenerierung**

Alles, was Code zur Laufzeit erzeugt won-'-t work-:-

- `System.Reflection.Emit` Arten dynamisch erzeugend
- Dynamische Beladung der Montage DLLs zur Laufzeit
- Einige ausgefallene Reflexionstricks

Der meiste normale Code ist fein, aber einige Frameworks, die stark auf Reflexion angewiesen sind, benötigen eine spezielle Konfiguration.

**Plattform-®spezifische Builds**

JIT-Compilation produziert IL, die auf jeder Plattform läuft. **eine spezifische Plattform**Sie müssen separat für das Bauen bauen.

- Fenster x-64-
- Linux x.64.
- Linux-ARM-64Raspberry-Pi-)
- macOS Intel
- macOS Apple Silicon

Wir automatisieren dies mit GitHub Aktionen später

**Längere Bauzeiten**

Statt IL in Sekunden zu kompilieren, kompiliert AOT den ganzen Weg zum Maschinencode.Erwarten Sie Minuten anstelle von Sekunden.. ist ein einmaliger Kostenfaktor für dauerhafte Vorteile.

**Einige Funktionen benötigen eine zusätzliche Konfiguration**

JSON-Serialisierung-,-Entity Framework und alles, was schwere Reflexion verwendet möglicherweise müssen Sie ausdrücklich sagen, die Compiler, welche Arten zu halten ?....

### Wann sollten Sie AOT-? verwenden?

Native AOT ist perfekt für die

- **CLI-Werkzeuge**Befehlszeilen-Dienstprogramme, bei denen die sofortige Inbetriebnahme von Bedeutung ist
- **Mikrodienste**Skalierung in Kubernetes schneller
- **Serverlos, /-Lambda**Kalte Startzeit wirkt direkt auf Ihre Rechnung
- **Kanteneinrichtungen**IoT-Geräte mit begrenzten Ressourcen
- **Gateway-Anwendungen**API-Gateways mit hohem Durchsatz
- **Desktop-Werkzeuge**Verschiffen Sie ein einzelnes .exe ohne Installationsschritt

AOT für„:" überspringen

- Traditionelle Web-Apps, bei denen Startzeit nicht zählt
- Apps mit schweren Entity Framework mit vielen Migrationen
- Plugin-Systeme, die DLLs dynamisch laden
- Alles, was Code zur Laufzeit erzeugt

Für CLI-Tools, ,, Microservices, ,, Container und Kantengeräte sind die Verbesserungen Spiel.-, das Ändern von . Aber da ist ein Haken, wenn Sie Datenbanken hinzufügen, MSC7, speziell SQLite-.,

## Das SQLite-Problem

Jetzt, da Sie verstehen, was AOT ist let-'s sprechen über den einzigen größten Schmerzpunkt , : , SQLite ,. , Dies ist die Wand die meisten Menschen getroffen, wenn sie versuchen, AOT mit Datenbank verwenden , - , unterstützte Anwendungen ..

### Was passiert mit der Frustrierenden Erfahrung?

Hier ist die typische Reise.

1. Sie fügen hinzu: `Microsoft.Data.Sqlite` zu Ihrem Projekt
2. Sie konfigurieren `PublishAot=true` in Ihrem `.csproj`
3. Das Build komplettiert ohne Fehler alles sieht gut aus.
4. Sie führen die ausführbare Datei aus und erhalten sofort

```
DllNotFoundException: Unable to load DLL 'e_sqlite3' or one of its dependencies
```

Deine App stürzt ab, bevor sie alles tun kann.

### Native Bibliotheken verstehen

Um das Problem zu verstehen, müssen Sie wissen über **native Bibliotheken**.

SQLite ist ,' , geschrieben in , . , NET , — , in C , . , es ,' , kompiliert zu Plattform , E- , spezifischen nativen Code ,

- `e_sqlite3.dll` unter Windows
- `libe_sqlite3.so` unter Linux
- `libe_sqlite3.dylib` auf macOS

Wenn Sie `Microsoft.Data.Sqlite` in der normalen Version von .-NET-,.' ist nur ein Wrapper um diese native SQLite-Bibliothek herum... Zur Laufzeit versucht es **dynamisch laden** die entsprechende native Datei für Ihre Plattform

Dies funktioniert in Ordnung mit normalem .-NET, weil

1. Die Laufzeit kann Bibliotheken dynamisch laden
2. NuGet-Pakete können native Bibliotheken für alle Plattformen enthalten
3. Die richtige wird zur Laufzeit ausgewählt

### Warum AOT dies bricht

Native AOT hat zwei Eigenschaften, die mit SQLite kollidieren.

**Aggressive Beschneidung**Wenn es statisch beweisen kann, dass Sie etwas benötigen, wird es gelöscht..... Dynamische Bibliothek Laden verwirrt den Trimmer... ..' Sehen Sie die Verbindung zwischen Ihrem Code und der nativen SQLite DLL..

**Keine dynamische Belastungsunterstützung**Es erwartet, dass alle nativen Abhängigkeiten zur Kompilierungszeit explizit verknüpft werden.

Das Ergebnis `Microsoft.Data.Sqlite` erwartet, eine native SQLite-Bibliothek zur Laufzeit zu finden.,, aber AOT hat sie entweder weggetrimmt oder weiß nicht, wie man sie richtig bündelt

### Der Transitive Dependency Nightmare

Noch schlimmer, wenn Sie andere NuGet-Pakete haben, die SQLite verwenden, wie einige ORM-Bibliotheken oder meine `mostlylucid.ephemeral.complete` Paket-), , können Sie am Ende mit **mehrere inkompatible SQLite-Anbieter** in Ihrem Abhängigkeitsbaum

Jeder Anbieter versucht anders zu arbeiten.

- Man könnte erwarten, dass OS--, vorausgesetzt SQLite nur ), Windows
- Ein anderer könnte seine eigene SQLite bündeln
- Ein anderer könnte eine andere native Bibliotheksversion verwenden

Der AOT-Compiler wird verwirrt, über welche man zu verwenden ist, und oft das Ergebnis ist, dass es keine von ihnen enthält.

## Die Lösung verwenden Sie das Bündel

Die Lösung ist: `SQLitePCLRaw.bundle_e_sqlite3`Ein spezielles NuGet-Paket, das speziell entwickelt wurde, um mit AOT-. zu arbeiten.

Fügen Sie diese beiden Pakete zu Ihrem Projekt hinzu

```xml
<ItemGroup>
  <PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
  <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.10" />
</ItemGroup>
```

### Was macht der Bundle?

Das `bundle_e_sqlite3` Paket unterscheidet sich von normalen SQLite-Providern.

**Es enthält vor-angepasste SQLite-Bibliotheken für jede große Plattform.**

- Fenster mit einer Breite von nicht mehr als 2 mm
- Linux-Distros wie Alpine, )
- macOS (-x-64-Intel.,-ARM, M64-Apfel-Silicium

**Diese nativen Bibliotheken sind in einer Weise verpackt, die der AOT Compiler versteht**

Das Bundle markiert seine nativen Abhängigkeiten explizit, so dass der AOT-Compiler weiß, sie in die finale Binärdatei einzubinden.

**Es wurde für cross-Versionen von - entwickelt**

Ein Paket funktioniert für alle Plattformen ,. , Sie brauchen nicht Plattform , - , spezifische Pakete oder bedingte Referenzen ..

### Warum das funktioniert

Erinnern Sie sich an die zwei Probleme, die wir identifizierten

**Problem-Beschneidung entfernt Bibliotheken kann es verwendet werden**

- Lösung: :-Das Bundle erklärt explizit seine nativen Bibliotheken als Build-Assets, die enthalten sein müssen

**Problem 2:-AOT unterstützt dynamisches Laden**

- Lösung: :-Das Bundle verknüpft die SQLite Bibliotheken statisch zur Kompilierungszeit

Das Ergebnis, wenn Sie für Windows x.64, Build das Bundle enthält `e_sqlite3.dll`Wenn Sie für Linux ARM.64, Build es enthält die ARM... `libe_sqlite3.so`Alles, was gerade funktioniert

### Kritisch ,: , Initialisieren Sie den Bundle , ( , Don , ' , Überspringen Sie dies ,!) ,

Hier ist der Teil, der nach oben stöbert.90%' von Leuten, die versuchen SQLite mit AOT-,' zu benutzen, inklusive mir bei meinem ersten Versuch.MSC3'

**mit normalem .-NET**Das SQLite-Bundle initialisiert sich automatisch, wenn Sie SQLite verwenden.

**Mit Native AOT**Diese automatische Initialisierung doesnts ,' work , . , Der AOT-Compiler can , ' , siehe den automatischen Startcode ,( , es sieht aus wie ungenutzter Code und wird getrimmt , so dass Sie **muss manuell initialisiert werden** das Bundle am Anfang Ihrer Anwendung

Hier ist die magische Linie, die du brauchst.

```csharp
using SQLitePCL;

public class Program
{
    public static void Main(string[] args)
    {
        // THIS IS CRITICAL: Initialize SQLite FIRST, before ANYTHING else
        SQLitePCL.Batteries.Init();

        // Now you can do normal application setup
        var builder = WebApplication.CreateBuilder(args);

        // This is now safe - SQLite is initialized
        builder.Services.AddDbContext<MyDbContext>(options =>
            options.UseSqlite("Data Source=app.db"));

        var app = builder.Build();
        app.Run();
    }
}
```

### Was tut `Batteries.Init()` Behandeln Sie:

Diese Methode sagt das SQLite-Bundle zu.

1. Finden Sie die richtige native SQLite-Bibliothek für Ihre aktuelle Plattform
2. Laden Sie es in den Speicher
3. Verkabeln Sie alle Verbindungen zwischen `Microsoft.Data.Sqlite` und die Heimatbibliothek

Es ist ', genannt ".Batterien, weil es ', die Batterien enthalten ", Bündel —, alles was Sie brauchen, wird zusammen verpackt.

### Wo soll man es hinstellen?

Setzen `Batteries.Init()` als **die erste Zeile** in Ihrem `Main` Methode vor der Behandlung mit :

- Erstellen des Anwendungs-Builders
- Abhängigkeits-Injektion konfigurieren
- Öffnen von Datenbankverbindungen
- Konfigurationsdateien lesen, die SQLite verwenden können

Denken Sie daran, wie das Einstecken eines Geräts vor dem Versuch, es einzuschalten ?.? Wenn Sie versuchen, SQLite vor dem Aufruf verwenden `Init()`Sie erhalten immer noch die `DllNotFoundException` auch wenn die DLL korrekt in Ihrer Anwendung gebündelt ist

### Was passiert, wenn Sie vergessen?

Wenn Sie vergessen zu rufen `Batteries.Init()`Ihre App wird von :

1. Mit Erfolg Builden Sie den Compiler Won , ' , warnt Sie nicht
2. Starten Sie
3. Absturz in dem Moment, in dem es versucht, SQLite mit zu verwenden.

```
DllNotFoundException: Unable to load DLL 'e_sqlite3' or one of its dependencies
```

Dies ist verwirrend, weil die DLL **wird** gebündelt in Ihrer Anwendung, nur nicht initialisiert

## Vollständige Projektkonfiguration

Hier ist ein vollständiges `.csproj` konfiguriert für Multi---Plattform Native AOT mit SQLite-:

```xml
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <!-- Native AOT -->
    <PublishAot>true</PublishAot>
    <PublishTrimmed>true</PublishTrimmed>
    <TrimMode>full</TrimMode>
    <InvariantGlobalization>true</InvariantGlobalization>

    <!-- Single File -->
    <PublishSingleFile>true</PublishSingleFile>
    <StripSymbols>true</StripSymbols>

    <!-- Optimization -->
    <OptimizationPreference>Speed</OptimizationPreference>

    <!-- Multi-platform targets -->
    <RuntimeIdentifiers>
      win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64
    </RuntimeIdentifiers>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
    <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.10" />
  </ItemGroup>

</Project>
```

### Schlüssel-Einstellungen erklärt im Klartext

Lassen Sie mich nach unten brechen, was jede dieser Einstellungen tut.

**`PublishAot=true`**

Dies ist der Master-Schalter, der Native AOT Compilation ermöglicht. ohne diese ,, erhalten Sie normales Verhalten von ., JIT compilation, )., mit diesem , erhalten Sie voran.

**`PublishTrimmed=true` und `TrimMode=full`**

Diese sagen dem Compiler, um jeden beliebigen Code zu entfernen you-'e nicht verwenden ?.?Denken Sie daran, wie das Reinigen Ihrer Garage vor dem Verschieben ?— ?warum Pack Dinge, die Sie brauchen nicht

- `PublishTrimmed=true` ermöglicht das Beschneiden
- `TrimMode=full` bedeutet, dass Sie alles entfernen, was Sie können

**Warnung**Dieses kann Code brechen, der schwere Reflexion verwendet...... wie einige JSON Serializer oder OR)... weil der Trimmer immer sehen kann, was du über reflection.......

**`InvariantGlobalization=true`**

Dies entfernt alle Kultur- ,--spezifische Daten aus Ihrer App , — , Datumsformate , , , Währungssymbole , , , Textsortierungsregeln für verschiedene Sprachen , E. , speichert 5-10 , MB , und . ,

Nur die Einstellung auf `true` wenn Ihre App

- Nur Englisch
- Braucht Kultur nicht?
- Nur Verwendungen von Ordinal-Vergleichen mit (,-byte,--,- von -,-Byte und -)

Wenn Sie ein CLI-Tool oder API-Gateway bauen, das sich nicht um die Lokalisierung kümmert, ist es kostenlos zu sparen, wenn Sie etwas aufbauen, das Daten für französische Benutzer formatieren muss, oder Türkischen Text korrekt sortieren.

**`PublishSingleFile=true`**

Verbindet alles in eine ausführbare Datei.

```
myapp.exe
myapp.dll
System.Text.Json.dll
... 50 more files
```

Du erhältst einfach

```
myapp.exe
```

Viel einfacher zu implementieren

**`StripSymbols=true`**

Debug-Symbole helfen Debuggern, Ihnen variable Namen und Zeilennummern beim Debuggen zu zeigen..-Sie sind während der Entwicklung nützlich, fügen aber mehrere Megabyte zu Ihrer letzten Binärdatei hinzu.

Diese Einstellung entfernt sie... Ihre App läuft genau die gleiche...

**`OptimizationPreference=Speed`**

Dies sagt dem Compiler, was zu priorisieren ist, wenn Entscheidungen getroffen werden.

- `Speed`Machen Sie es schnell - leicht größere Binaries - aber bessere Leistung
- `Size`Machen Sie es klein - leicht langsamer - aber minimale binäre Größe -

Für die meisten Anwendungen `Speed` ist die richtige Wahl?Der Größenunterschied ist in der Regel nur 2-3,MB,,, aber die Leistungsdifferenz kann spürbar sein.

**`RuntimeIdentifiers`**

Dies erklärt, welche Plattformen Sie unterstützen möchten...Es doesns.'.t baut sie alle.MSC2.it sagt nur Tooling .MSSK3. Diese sind gültige Ziele.

Verfügbare Identifikatoren

- `win-x64`Weitere Informationen finden Sie unter: http://www.cordis.lu/
- `win-arm64`Windows ARM-64, (Surface Pro X.,, usw. .)
- `linux-x64`Weitere Informationen sind abrufbar unter: http:www.cordis.lu/index.htm
- `linux-arm64`Linux ARM-64-(-Raspberry Pi AWS Graviton
- `osx-x64`MacOS Intel Macs mit älteren Macs
- `osx-arm64`M:-MacOS-Apfelsilizium MMSC1-M.1/-M3-M3-Mcs-)-

Sie bauen eine Plattform zu einer Zeit mit `dotnet publish -r linux-x64`Z.B.:

## Gebäude für mehrere Plattformen

Denken Sie daran, wie ich sagte AOT erfordert platform-.--spezifische Builds, ?-Sie müssen separat für Windows kompilieren ?,-Linux x-64,-Linux-AR64,-macOS Intel-M,-und macOS Apple-Silicium?.-Dies manuell zu tun wäre mühsam, aber wir können es automatisieren

### Was ist GitHub Aktionen?

Wenn du nicht vertraut bist, ist die GitHub-Aktionen ein kostenloser CIP-Dienst./CD Kontinuierliche Integration.../"Continuous Deployment )-Dienst, der in GitHub" gebaut wurde, ermöglicht es dir, automatisierte Aufgaben auszuführen, wenn du Code drückst oder ein Release-Tag erstellst.

Denken Sie daran, wie mit einem Build-Server, dass

1. Uhren Ihr GitHub Repository
2. Wenn du ein Tag wie `v1.0.0`
3. Es dreht sich automatisch nach oben Windows-,-Linux- und macOS-virtuellen Maschinen
4. Baut Ihre App für alle Plattformen parallel
5. Erstellt ein GitHub Release mit allen beigefügten Binärdateien

All dies läuft auf GitHub-''s Servern.—'you don.''t Notwendigkeit, irgendeine Infrastruktur zu pflegen..' Für offene -`source Projekte und kleine persönliche Projekte...,'s völlig frei

### Der komplette Build-Workflow

Hier ist ein GitHub Actions Workflow, der für alle gängigen Plattformen automatisch erstellt wird.

```yaml
name: Build Native AOT Binaries

on:
  push:
    tags:
      - 'v*'

jobs:
  build-binaries:
    name: Build ${{ matrix.runtime }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            runtime: linux-x64
            artifact-name: myapp-linux-x64

          - os: ubuntu-latest
            runtime: linux-arm64
            artifact-name: myapp-linux-arm64

          - os: windows-latest
            runtime: win-x64
            artifact-name: myapp-win-x64

          - os: macos-latest
            runtime: osx-x64
            artifact-name: myapp-osx-x64

          - os: macos-latest
            runtime: osx-arm64
            artifact-name: myapp-osx-arm64

    steps:
    - uses: actions/checkout@v4

    - name: Setup .NET
      uses: actions/setup-dotnet@v4
      with:
        dotnet-version: '9.0.x'

    - name: Install ARM64 tools (Linux ARM64 only)
      if: matrix.runtime == 'linux-arm64'
      run: |
        sudo apt-get update
        sudo apt-get install -y clang zlib1g-dev gcc-aarch64-linux-gnu

    - name: Publish
      shell: bash
      run: |
        # Set objcopy for ARM64 cross-compilation
        if [ "${{ matrix.runtime }}" = "linux-arm64" ]; then
          OBJCOPY_PARAM="-p:ObjCopyName=aarch64-linux-gnu-objcopy"
        else
          OBJCOPY_PARAM=""
        fi

        dotnet publish \
          -c Release \
          -r ${{ matrix.runtime }} \
          --self-contained \
          --output ./publish/${{ matrix.runtime }} \
          -p:PublishAot=true \
          -p:PublishTrimmed=true \
          -p:StripSymbols=true \
          $OBJCOPY_PARAM

    - name: Create distribution package
      shell: bash
      run: |
        mkdir -p ./dist
        cd ./publish/${{ matrix.runtime }}

        # Copy the main executable
        cp myapp${{ matrix.file-ext }} ../../dist/

        # CRITICAL: Copy native libraries (SQLite and any other native dependencies)
        # PublishSingleFile bundles .NET code, but native DLLs remain separate
        cp *.dll ../../dist/ 2>/dev/null || true
        cp *.so ../../dist/ 2>/dev/null || true
        cp *.dylib ../../dist/ 2>/dev/null || true

        # Copy config files if needed
        cp ../../appsettings.json ../../dist/ || true

        cd ../../dist

        # Create archive with all files
        if [ "${{ runner.os }}" = "Windows" ]; then
          7z a -tzip ../${{ matrix.artifact-name }}.zip *
        else
          tar czf ../${{ matrix.artifact-name }}.tar.gz *
        fi

    - name: Upload artifact
      uses: actions/upload-artifact@v4
      with:
        name: ${{ matrix.artifact-name }}
        path: |
          ${{ matrix.artifact-name }}.zip
          ${{ matrix.artifact-name }}.tar.gz
        retention-days: 7
        if-no-files-found: ignore
```

### Wie dieser Workflow funktioniert Schritt für Schritt

Wenn das YAML sieht einschüchternd aus hier was es im Klaren Englisch macht

**Auslösung des Auslösers`on: push: tags`)**

Der Workflow läuft, wenn Sie ein Git-Tag drücken, das mit `v` ,( , ähnlich `v1.0.0`, `v2.3.1`Dies ist die Standard-Methode, um Release-Versionen zu markieren.

**Matrix-Strategie**

Dies ist der clevere Teil, statt fünf separate Workflows zu schreiben, definieren wir eine **Matrix** von Builds-:

- Jeder Bau bekommt einen anderen `os` Maschinen, Apparate und Geräte `runtime` Zielplattform)
- GitHub Actions läuft alle fünf Builds **parallel**
- Jeder produziert ein Artefakt, das kompilierte Binärmaterial.

Wenn du also drückst `v1.0.0`GITHUB simultan :

- Dreht sich eine Ubuntu-Maschine, um Linux zu bauen x- und ARM-64
- Dreht sich eine Windows-Maschine, um Windows zu bauen
- Dreht eine macOS-Maschine hoch, um mac OS x- und ARM-64 zu bauen

**Schritte in jedem Bau**

Jede Plattform baut die gleichen Schritte

1. **Kassencode**Bekommt Ihren Quellcode aus dem Repository
2. **Konfigurieren von .-NET**Installation von . NET SDK
3. **ARM-64-Werkzeuge installieren** Linux ARM-64 Installiert Werkzeuge für die cross-Sammlung von -
4. **Veröffentlichen**Laufende Nummer `dotnet publish` mit AOT-Flags für die jeweilige Plattform
5. **Artefakt hochladen**Speichert die kompilierte Binärdatei, damit der nächste Auftrag darauf zugreifen kann

**Das Ergebnis**

Nachdem alle Builds komplett sind, haben Sie fünf Artefakte.(.binaries.). bereit zum Verteilen von .. Sie können sie aus den Aktionen herunterladen.MSC4. oder einen zweiten Job verwenden, um ein GitHub Release automatisch zu erstellen.

### Kritisch ,: , Native Bibliotheken sind nicht gebündelt

Hier ist etwas, das mich für Stunden verwirrt hat. **`PublishSingleFile=true` Nur Bundles-Code für .-NET**Native Bibliotheken wie SQLite, ' `e_sqlite3.dll` bleiben Sie getrennt.

Aus diesem Grund ist der Schritt "Verteilungspaket erstellen" so wichtig.

```bash
# Copy native libraries - these are NOT included in the main executable
cp *.dll ../../dist/ 2>/dev/null || true    # Windows
cp *.so ../../dist/ 2>/dev/null || true     # Linux
cp *.dylib ../../dist/ 2>/dev/null || true  # macOS
```

Das `2>/dev/null || true` Teil bedeutet ", wenn es keine Dateien gibt, die mit diesem Muster übereinstimmen.,, dont. ',t fail."—,just continue".", Dies lässt dasselbe Skript auf allen Plattformen funktionieren.

**Was du austeilst**

- Fenster mit einem Durchmesser von mehr als 2 mm `myapp.exe` + `e_sqlite3.dll` zusammen in einem ZIP-)
- Linux®:- `myapp` + `libe_sqlite3.so` zusammengeschweißt in einem tar.., gz, ),
- macOS-: `myapp` + `libe_sqlite3.dylib` zusammengeschweißt in einem tar.., gz, ),

Benutzer extrahieren das Archiv und führen die ausführbare Version aus.Die native SQLite-Bibliothek sitzt neben der ausführbaren Datei und das Bundle findet es automatisch zur Laufzeit.

### Warum manuelles Triggern nützlich ist

Beachten Sie die `workflow_dispatch` Trigger an der Oberseite

```yaml
on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to publish'
        required: true
```

So können Sie Builds manuell von GitHub-'aus der Weboberfläche auslösen, ohne einen Tag zu drücken..e Nützlich zum Testen des Workflows oder zur Erstellung von Beta-Builds.

### ARM-64-Cross---Compilation

Der Linux-ARM-64-Build erfordert besondere Aufmerksamkeit. Sie benötigen cross-MSC2-Compilation-Tools und müssen die richtigen `objcopy` Werkzeug„:"

```bash
# Install tools
sudo apt-get install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu

# Build with objcopy specified
dotnet publish \
  -r linux-arm64 \
  -p:PublishAot=true \
  -p:ObjCopyName=aarch64-linux-gnu-objcopy
```

Ohne die `ObjCopyName` Parameter: Der Linker schlägt mit kryptischen Fehlern über unerkannte Dateiformate fehl

## Ergebnisse der Welt

Hier ist, was ich mit meiner Produktion YARP--.based Bot Detection Gateway mit Middleware und SQLite Logging erreicht habe. [Download von GitHub](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.BotDetection.Console).

### Binäre Größen aus tatsächlichen GitHub-Veröffentlichungen

Das sind die **tatsächliche Dateigrößen** aus meinem GitHub veröffentlicht nicht theoretische Schätzungen

Ausführbare SQLite Native DLL Archivgröße
|----------|-----------|-------------------|-------------------|
Weitere Informationen finden Sie unter: http:www.cordis.lu/ **10.9-MB** ](-ZIP-)-Zip-|-
Weitere Informationen: http:www.cordis.lu/index.html **12.4-MB** (-tar-.-gz®)-g
Linux ARM-64, |, M9.9MB, MKSK4, +1.5, MCSK6 **11.4-MB** (-tar-.-gz®)-g
Weitere Informationen sind abrufbar unter: http:www.cordis.lu/ **13.0-MB** (-tar-.-gz®)-g
M|-MacOS-AR64-|-9.8-MB-MSC4-MSSK5-MB **11.5-MB** (-tar-.-gz®)-g

Vergleichen Sie dies mit den in sich geschlossenen Bereitstellungen von ..NET. **130-150,MB pro Plattform**Wir sprechen über eine **Verkleinerung der Größe**.

Der Zusammenbruch

- Wichtigste ausführbare Version Ihr kompilierter Code +...NET Laufzeit (.-.compiliert ).
- Die SQLite Datenbank-Engine von Native DLL.

Beide Dateien müssen zusammen verteilt werden, aber sie sind immer noch dramatisch kleiner als die herkömmlichen . NET-Bereitstellungen.

### Inbetriebnahmeleistung

Kalter Start Erste Anfrage auf einem bescheidenen Linux-VPS-:

- **Selbstbeherrschendes --integriertes .-NET**,:, , ~800,ms
- **Natives AOT**,:, , ~150,ms
- **Verbesserung**Schneller

Dies ist sehr wichtig für die

- Serverlos ,/ ,Lambda-Funktionen , ( , zahlen Sie pro Millisekunde , ) ,
- Container, die häufig nach oben skalieren
- CLI-Werkzeuge, bei denen jede Anrufung neu beginnt

### Speichernutzung

Idle-Speicher (-Gateway läuft ,-kein Verkehr

- **Selbstbeherrschendes --integriertes .-NET**:, 85MB
- **Natives AOT**:, 42MB
- **Verbesserung**Verringerung der CO2-Emissionen

Unter Last Anforderungen /.Sekunden):.

- **Selbstbeherrschendes --integriertes .-NET**:, ~320MB
- **Natives AOT**:, ~180MB
- **Verbesserung**Verringerung der CO2-Emissionen

Unterer Speicher bedeutet:„:"

- Mehr Container pro Wirt
- Billigere Cloud-Hosting Rechnungen
- Machbarkeit auf ressource---beschränkten Geräten

## Häufige Pitfalls

### Vergeudung `Batteries.Init()`

Dies ist der Fehler von ., selbst mit dem korrekt referenzierten Bundle, vergessen zu rufen `SQLitePCL.Batteries.Init()` am Anfang Ihrer `Main` Methode verursacht Laufzeitabstürze

**Die Fixierung**

```csharp
public static void Main(string[] args)
{
    SQLitePCL.Batteries.Init(); // FIRST LINE
    // ... rest of your code
}
```

### Native Bibliotheken nicht verteilen

Dies ist ein Fehler, und es hat mich zweimal bekommen. `PublishSingleFile=true` does NOT bündeln native SQLite DLLs in Ihre ausführbare Version. Sie müssen sie neben Ihrer ausführbaren Datei verteilen.

**Was passiert, wenn Sie vergessen?**

- Deine App baut gut auf
- Es läuft in Ordnung auf Ihrem dev-Rechner, wo SQLite bereits installiert sein könnte.
- Es stürzt in der Produktion mit `DllNotFoundException`

**Die Fixierung**

Beim Verpacken Ihres Releases sind , immer inbegriffen.

```
myapp.exe               # Your main executable
e_sqlite3.dll           # SQLite native library (Windows)
# or libe_sqlite3.so    # SQLite native library (Linux)
# or libe_sqlite3.dylib # SQLite native library (macOS)
```

In Ihren GitHub-Aktionen oder Bereitstellungsskripten

```bash
# Copy ALL native libraries from the publish directory
cp *.dll ./dist/ 2>/dev/null || true
cp *.so ./dist/ 2>/dev/null || true
cp *.dylib ./dist/ 2>/dev/null || true
```

Benutzer sollten das Archiv extrahieren und die ausführbare Datei ausführen.Die native Bibliothek muss im gleichen Verzeichnis sein.

### Verwendung `winsqlite3` Anbieter

Vielleicht sehen Sie Empfehlungen zu verwenden `SQLitePCLRaw.provider.winsqlite3` unter Windows, um das OS-- zur Verfügung gestellt SQLite .. . Don ?' . . . Es funktioniert nur auf Windows erfordert manuelle Initialisierung und bricht cross -- . `bundle_e_sqlite3`.

### Warnungen mit EF-Kern

Wenn Sie den Entity Framework Core mit SQLite verwenden, erhalten Sie die Trimmwarnungen von '. Diese sind normalerweise sicher für EF-Core zu unterdrücken.

```xml
<PropertyGroup>
  <NoWarn>$(NoWarn);IL2026;IL3050</NoWarn>
</PropertyGroup>
```

Besser noch: ,, in Betracht ziehen, Dapper oder Roh ADO-.,NET mit SQLite für AOT-Anwendungen zu verwenden. —,they-',re mehr: AOT.-,friendly

### Fehlende visuelle Studio-Werkzeuge

Unter Windows erfordert Native AOT Visual Studio, ' und MSVC-Linker, wenn Sie außerhalb eines Developer Command Prompt, bauen, erhalten Sie Fehler über `vswhere.exe`GitHub Aktionen behandelt diese automatisch, aber für lokale Builds.

- Entwickler-Befehlsaufforderung für VS
- Entwickler PowerShell für VS

Oder initialisieren Sie die Umgebung in Ihrem Build-Skript

```powershell
& "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Launch-VsDevShell.ps1" -Arch amd64
dotnet publish -c Release -r win-x64
```

## Wann Native AOT verwendet werden soll

Native AOT ist perfekt für die

- **CLI-Werkzeuge**Sofortige Inbetriebnahme ist wichtig
- **Mikroservices und Container**Kleinere Bilder Schnellere Skalierung
- **Kanteneinrichtungen**IoT-Geräte mit begrenzten Ressourcen
- **Serverlos, /-Lambda**Kalte Startzeit ist entscheidend
- **Gateway-Anwendungen für /Proxy**Hohe Durchsatzleistung Niedriger Overhead

Vermeiden Sie AOT für

- Schweres Entity-Framework Core-Verwendung Viel Migrationen – komplexe Abfragen – )
- Reflection---schwere Anwendungen
- Dynamische Plugin-Systeme
- Anwendungen, die Laufzeitcode-Generierung benötigen

## Schnellstart-Checkliste

Wenn du diesen ganzen Beitrag liest und nur eine Checkliste willst, um hier zu folgen

**Die Pakete hinzufügen**

```xml
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.10" />
```

**Konfigurieren Sie Ihre `.csproj` für AOT-:-**

```xml
<PublishAot>true</PublishAot>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
<InvariantGlobalization>true</InvariantGlobalization>
<PublishSingleFile>true</PublishSingleFile>
<StripSymbols>true</StripSymbols>
<OptimizationPreference>Speed</OptimizationPreference>
```

**Starten Sie SQLite am Anfang Ihrer `Main` Methode:**

```csharp
SQLitePCL.Batteries.Init();
```

**Bauen Sie für Ihre Zielplattform**

```bash
dotnet publish -c Release -r linux-x64 --self-contained
```

**Testen Sie Ihre binäre Version sollte nur ohne Abhängigkeiten laufen.**

## Schlußfolgerung

SQLite zu bekommen, die mit Native AOT arbeitet, ist nicht offensichtlich, aber sobald Sie die magische Beschwörung kennen.`SQLitePCLRaw.bundle_e_sqlite3` + `Batteries.Init()`Die Auszahlung ist substantiell , die winzigen binaries , , , Instant-Startup ,, , und die Fähigkeit, auf jeder Plattform ohne Laufzeitabhängigkeiten bereitstellen ,

Für jeden, der CLI-Tools baut, sind die Gateways von , oder Edge-Anwendungen mit SQLite nun eine realistische Option Der hier bereitgestellte GitHub Actions Workflow automatisiert den gesamten Multi-- platform build Prozess.

Wenn du ein einfaches CLI-Tool oder Dienstprogramm zuerst umwandelst Bequem mit dem Build-Prozess lernen Sie, welche Warnungen zu erwarten sind , und verstehen Sie die Einschränkungen messk6 Sobald Sie die Basics unten haben down mess k8 können Sie komplexere Anwendungen angehen

Die meisten modernen Bibliotheken funktionieren entweder aus dem Kasten heraus oder haben eine klare Dokumentation auf AOT-Unterstützung.Die Zukunft ist natives... und es ist schneller, als Sie denken.

## Reale Beschäftigungserfahrung

Ich entwickle mein AOT---kompiliertes Gateway zu ,:'

- **Digital Ocean Droplet** Linux x-64), läuft als Systemdienst
- **Himbeer-Pi** Linux-ARM-64), Kantenausbringung zum Testen
- **Windows Server** Windows x.64). läuft als Windows-Dienst
- **Dockerbehältnisse** Die beiden Varianten x,64 und ARM, 64

Der Deployment-Prozess ist überall identisch

1. Das Archiv von GitHub Releases herunterladen
2. Es extrahieren
3. Ausführen der ausführbaren Datei

Keine Installation von . NET Laufzeit" schritt. , keine Abhängigkeit hell. , Keine Versionskonflikte , nur extrahieren und ausführen

Für Docker-, `Dockerfile` ist peinlich einfach

```dockerfile
FROM debian:bookworm-slim

# Copy just the two files we need
COPY minigw /app/minigw
COPY libe_sqlite3.so /app/libe_sqlite3.so

WORKDIR /app
RUN chmod +x minigw

EXPOSE 5000
ENTRYPOINT ["./minigw"]
```

Das resultierende Bild ist **~130-MB** Die meisten Debian-Images aus der Basis). Ein traditioneller Container von .'NET wäre 200-250.MB...

## Vollständiges Arbeitsbeispiel

Alles, was hier gezeigt wird, kommt aus einer echten ?,?-Produktion?MSC2?ready project?.?-Sie können ♪:?-

- **Siehe den Quellcode**: [Meistlylucid, ., BotDetection,., Konsole](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.BotDetection.Console)
- **Siehe den Workflow von GitHub-Aktionen**: [Konsole--Gateway--Release.-yml](https://github.com/scottgal/mostlylucid.nugetpackages/blob/main/.github/workflows/console-gateway-release.yml)
- **Vorgefertigte Binärdateien herunterladen**: [GitHub veröffentlicht](https://github.com/scottgal/mostlylucid.nugetpackages/releases)

Das Projekt ist ein minimaler YARP Reverse Proxy mit Bot Detection Middleware, der Signaturen auf SQLite protokolliert.

- Native AOT mit SQLite
- Multi---Plattform baut über GitHub Aktionen
- Einheimische Bibliothek bündeln
- CLI-Argument zur Parsierung
- Strukturierte Protokollierung
- Anmutige Abschaltung

Es als Vorlage für Ihre eigenen AOT-Projekte verwenden

## Aufkommen

- [Offizielle Dokumentation der Native AOT-Dokumentation](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/)
- [SQLitePCLRaw GitHub Repository](https://github.com/ericsink/SQLitePCL.raw)
- [Arbeitsbeispiel: :-Mostlylucid Bot Detection Gateway](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.BotDetection.Console)
- [Mein GitHub-Aktionen Workflow](https://github.com/scottgal/mostlylucid.nugetpackages/blob/main/.github/workflows/console-gateway-release.yml)

Jetzt gehen Sie etwas winziges und schnelles bauen