# Multiplatform AOT με SQLite: Πώς να το κάνετε να λειτουργήσει!

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

Αν έχετε προσπαθήσει να στείλετε .NET εφαρμογές ως ενιαία, εγγενή εκτελέσιμα χρησιμοποιώντας Native AOT, έχετε πιθανώς τρέξει το πρόσωπο-πρώτα στον τοίχο SQLite. Μπορείτε να ρυθμίσετε τα πάντα, η κατασκευή ολοκληρώνει με επιτυχία, και στη συνέχεια θα μπουμ συντριβές runtime με αινιγματικό `DllNotFoundException` σφάλματα σχετικά με `e_sqlite3`. Επιτρέψτε μου να σας γλιτώσω τις ώρες της απογοήτευσης που πέρασα και να σας δείξει ακριβώς πώς να πάρετε SQLite εργάζονται με Native AOT σε όλα τα Windows, Linux (συμπεριλαμβανομένων ARM64 Raspberry Pi), και macOS.

## Τι είναι το AOT; (Και γιατί πρέπει να σας νοιάζει;)

Αν έχετε φτιάξει ποτέ μια εφαρμογή .NET και αναρωτιέστε γιατί πρέπει να εγκαταστήσετε το ".NET Runtime" στους διακομιστές ή γιατί η εφαρμογή κονσόλα σας χρειάζεται ένα δευτερόλεπτο για να ξεκινήσει την πρώτη φορά που το εκτελέσετε, το AOT είναι η απάντηση σε αυτά τα προβλήματα.

### Πώς .NET λειτουργεί κανονικά (Σύσταση JIT)

Όταν γράφετε κώδικα C# και κατασκευάζετε την εφαρμογή σας, ο μεταγλωττιστής δεν παράγει κώδικα μηχανών που μπορείτε να εκτελέσετε άμεσα. **Ενδιάμεση γλώσσα (IL)**Σκεφτείτε το ως τη μέση μεταξύ του κώδικα C# σας και πραγματικές οδηγίες μηχανής.

Όταν εκτελέσετε την εφαρμογή σας .NET, εδώ είναι τι συμβαίνει:

1. Ο υπολογιστής σας φορτώνει το .NET Runtime (ένα ξεχωριστό πρόγραμμα)
2. Ο χρόνος λήξης διαβάζει τον κωδικό IL σας
3. **Just-In-Time (JIT)** μεταγλωττιστής μετατρέπει IL σε εγγενή κώδικα μηχανών, όπως η εφαρμογή σας τρέχει
4. Η CPU σας εκτελεί επιτέλους αυτόν τον κώδικα μηχανών

Αυτό είναι σαν να έχεις έναν μεταφραστή που διαβάζει τη συνταγή σου (IL) και προφορικά το μεταφράζει σε μια γραμμή-γραμμή σεφ (CPU) ενώ μαγειρεύουν.

- Το .NET Runtime είναι 50-150MB των επιπλέον αρχείων που πρέπει να αναπτύξετε
- Ο μεταγλωττιστής JIT χρειάζεται χρόνο για να μεταφράσει τον κώδικα (γιατί η εφαρμογή σας είναι αργή την πρώτη φορά)
- Ο μεταγλωττιστής JIT κάθεται στη μνήμη ενώ η εφαρμογή σας τρέχει

### Εισάγετε AOT (προθεσμιακή συλλογή)

Αντί να μεταφράζει τον κωδικό σας κατά τη διάρκεια του τρεξίματος, μεταφράζει τα πάντα **σε χρόνο κατασκευής**. Καταλήγετε με ένα ενιαίο εκτελέσιμο αρχείο που περιέχει πραγματικό κωδικό μηχανής σας CPU μπορεί να τρέξει απευθείας runnime, κανένας μεταφραστής, καμία αναμονή.

Σκεφτείτε το σαν να έχετε ένα επαγγελματικό μεταφρασμένο βιβλίο συνταγών αντί να προσλάβετε έναν ζωντανό μεταφραστή.

### Το παιχνίδι-Αλλαγή Οφέλη

Ακούστε τι σας δίνει ο Ιθαγενής AOT:

**1. Μικροσκοπικά εκτελέσιμα**: 10-30MB αντί 150MB+

Η εφαρμογή σας και όλα όσα χρειάζεται συγκεντρώνονται σε ένα μικρό δυαδικό.

**2. Άμεση εκκίνηση**80% γρηγορότερο κρύο ξεκινάει

Οι δοκιμές μου: κανονικό .NET πήρε ~800mm για να ξεκινήσει, AOT πήρε ~150mm. Δεν υπάρχει JIT warm-up χρόνος ~Ο κώδικας μηχανών είναι έτοιμος να εκτελεστεί αμέσως.

**3. Μηδέν εξαρτήσεις**: Δεν απαιτείται χρόνος λειτουργίας του NET

Μπορείτε να αντιγράψετε το εκτελέσιμο σας σε οποιαδήποτε μηχανή με το σωστό OS (Windows/Linux/Mac) και απλά τρέχει. Όχι "εγκαταστήστε .NET 9 Runtime" προϋπόθεση.

**4. Χαμηλότερη χρήση μνήμης**: Περίπου 50% λιγότερη μνήμη

Δεν JIT μεταγλωττιστής κάθεται στη μνήμη. Στην εφαρμογή πύλη μου, κανονικό .NET χρησιμοποιείται 85MB αδράνεια, AOT χρησιμοποιείται 42MB.

**5. Καλύτερα για περιορισμένο περιβάλλον**: Λειτουργεί όπου JIT δεν μπορεί

Ορισμένα περιβάλλοντα (ορισμένα δοχεία Docker, iOS, ενσωματωμένα συστήματα) δεν επιτρέπουν την παραγωγή κώδικα runtime.

### The Trade-offs (Υπάρχει πάντα μια παγίδα)

Το AOT δεν είναι μαγεία.

**1. Καμία δυναμική παραγωγή κώδικα**

Οτιδήποτε δημιουργεί κώδικα στο τρέξιμο δεν θα δουλέψει.

- `System.Reflection.Emit` (δημιουργία τύπων δυναμικά)
- Δυναμική φόρτιση συναρμολόγησης (φορτώνοντας DLLs σε χρόνο λειτουργίας)
- Μερικά φανταχτερά κόλπα αντανάκλασης

Ο πιο φυσιολογικός κώδικας NET είναι μια χαρά, αλλά μερικά πλαίσια που βασίζονται σε μεγάλο βαθμό στην αντανάκλαση χρειάζονται ειδικές ρυθμίσεις.

**2. Ειδικές κατασκευές πλατφόρμας**

Η συλλογή JIT παράγει IL που τρέχει σε οποιαδήποτε πλατφόρμα. **μία συγκεκριμένη πλατφόρμα**. Θα πρέπει να οικοδομήσουμε ξεχωριστά για:

- Windows x64
- Linux x64
- Linux ARM64 (Βατόμουρο Pi)
- macOS IntelCity name (optional, probably does not need a translation)
- macOS Apple Silicon

Θα το καλύψουμε αυτό με το GitHub Activities αργότερα.

**3. Μεγαλύτεροι χρόνοι κατασκευής**

Αντί για την κατάρτιση σε IL σε δευτερόλεπτα, AOT καταρτίζει όλη τη διαδρομή προς τον κώδικα μηχανών. Περιμένετε 2-5 λεπτά αντί για 10 δευτερόλεπτα. Είναι ένα εφάπαξ κόστος για μόνιμα οφέλη.

**4. Μερικά χαρακτηριστικά χρειάζονται επιπλέον διαμόρφωση**

JSON serialization, Providency Framework, and anything using heavy reflection may need you to tell specificly the metaler what types to keep. We'll cover this.

### Πότε Πρέπει να Χρησιμοποιείτε Αφθονία;

Το Native AOT είναι ιδανικό για:

- **Εργαλεία CLI**: Οδηγίες-γραμμή κοινής ωφέλειας όπου θέματα άμεσης εκκίνησης
- **Μικροϋπηρεσίες**: Μικρότερες εικόνες Docker, ταχύτερη κλιμάκωση στο Kubernetes
- **Serverless/Lambda**: Ψυχρός χρόνος έναρξης επηρεάζει άμεσα το λογαριασμό σας
- **Συσκευές εκκένωσης**: Raspberry Pi, IoT συσκευές με περιορισμένους πόρους
- **Εφαρμογές πύλης**: Αντιστροφή proxies, API πύλες με υψηλή throughput
- **Εργαλεία επιφάνειας εργασίας**: Στείλτε ένα ενιαίο .exe χωρίς "εγκαταστήστε .NET πρώτα" βήμα

Skip AOT για:

- Παραδοσιακές εφαρμογές web όπου ο χρόνος έναρξης δεν έχει σημασία
- Apps χρησιμοποιώντας βαρύ πλαίσιο οντότητας με πολλές μεταναστεύσεις
- Πρόσθετα συστήματα που φορτώνουν DLLs δυναμικά
- Οτιδήποτε δημιουργεί κώδικα σε χρόνο λειτουργίας

Για τα εργαλεία CLI, τις μικροϋπηρεσίες, τα δοχεία και τις συσκευές άκρη, οι βελτιώσεις αλλάζουν το παιχνίδι.

## Το πρόβλημα SQLite

Τώρα που καταλαβαίνετε τι είναι το AOT, ας μιλήσουμε για το μοναδικό μεγαλύτερο σημείο πόνου: SQLite. Αυτός είναι ο τοίχος που οι περισσότεροι άνθρωποι χτύπησαν όταν προσπαθούν να χρησιμοποιήσουν το AOT με εφαρμογές υποστηριζόμενες από βάση δεδομένων.

### Τι Συμβαίνει (Η Απογοητευτική Εμπειρία)

Εδώ είναι το τυπικό ταξίδι:

1. Προσθέτεις `Microsoft.Data.Sqlite` στο πρόγραμμά σας
2. Ρύθμιση `PublishAot=true` σε σας `.csproj`
3. Η κατασκευή ολοκληρώνει χωρίς λάθη τα πάντα φαίνονται καλά!
4. Τρέχεις το εκτελέσιμο και αμέσως παίρνεις:

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

Η εφαρμογή σου καταρρέει πριν κάνει οτιδήποτε.

### Κατανόηση Ιθαγενικών Βιβλιοθηκών (Γρήγορη παράκαμψη)

Για να καταλάβετε το πρόβλημα, θα πρέπει να ξέρετε για **ιθαγενείς βιβλιοθήκες**.

Το SQLite δεν είναι γραμμένο στο .NET είναι γραμμένο στο C. Συντάχθηκε με τον ειδικό κωδικό της πλατφόρμας:

- `e_sqlite3.dll` στα Windows
- `libe_sqlite3.so` σχετικά με το Linux
- `libe_sqlite3.dylib` σχετικά με το macOS

Όταν χρησιμοποιείτε `Microsoft.Data.Sqlite` στο κανονικό .NET, είναι απλά ένα περιτύλιγμα γύρω από αυτή την μητρική βιβλιοθήκη SQLite. **Δυναμικό φορτίο** το κατάλληλο αρχείο ιθαγενών για την πλατφόρμα σας.

Αυτό λειτουργεί μια χαρά με το κανονικό .NET επειδή:

1. Ο χρόνος λειτουργίας μπορεί να φορτώσει τις βιβλιοθήκες δυναμικά
2. NuGet πακέτα μπορεί να περιλαμβάνει τοπικές βιβλιοθήκες για όλες τις πλατφόρμες
3. Ο σωστός επιλέγεται κατά τη διάρκεια του τρεξίματος

### Γιατί το ΞΕΝΟΔΟΧΕΙΟ το Σπάει αυτό

Το Native AOT έχει δύο χαρακτηριστικά που συγκρούονται με την προσέγγιση του SQLite:

**1. Επιθετική κοπή**: Το AOT αφαιρεί κάθε κωδικό που νομίζει ότι δεν χρησιμοποιείτε. Αν δεν μπορεί να αποδείξει στατικά ότι χρειάζεστε κάτι, διαγράφεται.

**2. Καμία δυναμική υποστήριξη φόρτωσης**: AOT παράγει ένα αυτόνομο δυαδικό. Αναμένει όλες οι εγγενείς εξαρτήσεις να συνδέονται ρητά κατά την κατάρτιση του χρόνου, δεν φορτώνονται δυναμικά κατά τη διάρκεια του ταξιδιού.

Το αποτέλεσμα: `Microsoft.Data.Sqlite` αναμένει να βρει μια μητρική βιβλιοθήκη SQLite σε χρόνο λειτουργίας, αλλά το AOT έχει είτε κόψει μακριά ή δεν ξέρει πώς να το πακετάρει σωστά.

### Ο Εφιάλτης της Διαμετακόμισης

Ακόμα χειρότερα, αν έχετε άλλα πακέτα NuGet που χρησιμοποιούν SQLite (όπως κάποιες βιβλιοθήκες ORM ή μου `mostlylucid.ephemeral.complete` πακέτο), μπορείτε να καταλήξετε με **πολλαπλοί μη συμβατοί πάροχοι SQLite** στο δέντρο εξάρτησης σου.

Κάθε πάροχος προσπαθεί να λειτουργήσει διαφορετικά:

- Κάποιος μπορεί να περιμένει OS-παρέχονται SQLite (μόνο Windows)
- Ένα άλλο θα μπορούσε να διαδώσει το δικό του SQLite
- Ένας άλλος μπορεί να χρησιμοποιήσει μια διαφορετική μητρική έκδοση βιβλιοθήκης

Ο μεταγλωττιστής AOT μπερδεύεται σχετικά με το ποια να χρησιμοποιήσετε, και συχνά το αποτέλεσμα είναι ότι δεν περιλαμβάνει κανένα από αυτά[4]ή χειρότερα, περιλαμβάνει αντικρουόμενα αρχεία που δεν μπορούν να συνεργαστούν.

## Η Λύση: Χρησιμοποιήστε το Bundle

Μετά από ώρες απογοήτευσης, βρήκα τη λύση: `SQLitePCLRaw.bundle_e_sqlite3`. Αυτό είναι ένα ειδικό πακέτο NuGet σχεδιαστεί ειδικά για να συνεργαστεί με το AOT.

Προσθέστε αυτά τα δύο πακέτα στο έργο σας:

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

### Τι Κάνει η Μπάντλ;

Η `bundle_e_sqlite3` το πακέτο είναι διαφορετικό από τους κανονικούς παρόχους SQLite:

**1. Περιλαμβάνει προ-compiled αυτόχθονες βιβλιοθήκες SQLite για κάθε μεγάλη πλατφόρμα:**

- Windows (x64, x86, ARM64)
- Linux (x64, ARM64, musl-based distros like Alpine)
- macOS (x64 Intel, ARM64 Apple Silicon)

**2. Αυτές οι εγγενείς βιβλιοθήκες συσκευάζονται με τρόπο που ο μεταγλωττιστής AOT καταλαβαίνει**

Το πακέτο σηματοδοτεί τις εγγενείς εξαρτήσεις του ρητά έτσι ώστε ο μεταγλωττιστής AOT ξέρει να τις συμπεριλάβει στο τελικό δυαδικό.

**3. Είναι σχεδιασμένο για cross-platform κατασκευές**

Ένα πακέτο λειτουργεί για όλες τις πλατφόρμες. Δεν χρειάζεστε ειδικά πακέτα πλατφόρμας ή αναφορές υπό όρους.

### Γιατί Λειτουργεί Αυτό

Θυμάσαι τα δύο προβλήματα που αναγνωρίσαμε;

**Πρόβλημα 1: Το κούρεμα του AOT αφαιρεί τις βιβλιοθήκες που δεν μπορεί να δει να χρησιμοποιούνται**

- Λύση: Το πακέτο δηλώνει ρητά τις εγγενείς βιβλιοθήκες του ως οικοδομήσιμα περιουσιακά στοιχεία που πρέπει να συμπεριληφθούν

**Πρόβλημα 2: Το AOT δεν υποστηρίζει τη δυναμική φόρτωση**

- Λύση: Το πακέτο συνδέει στατικά τις βιβλιοθήκες SQLite κατά τη σύνταξη του χρόνου

Το αποτέλεσμα: όταν χτίζετε για τα Windows x64, το πακέτο περιλαμβάνει `e_sqlite3.dll`. Όταν χτίζετε για Linux ARM64, περιλαμβάνει το ARM64 `libe_sqlite3.so`Όλα δουλεύουν.

### Κρίσιμη: Αρχικοποίηση του Bundle (Don't Skip This!)

Εδώ είναι το κομμάτι που ταξιδεύει το 90% των ανθρώπων που προσπαθούν να χρησιμοποιήσουν SQLite με AOT, συμπεριλαμβανομένου και εμένα στην πρώτη μου προσπάθεια.

**Με κανονικό .NET**, το πακέτο SQLite αρχικοποιείται αυτόματα την πρώτη φορά που χρησιμοποιείτε SQLite. Μαγεία συμβαίνει πίσω από τις σκηνές ~ δεν χρειάζεται να κάνετε τίποτα.

**With Native AOT**, αυτή η αυτόματη αρχικοποίηση δεν λειτουργεί . Ο μεταγλωττιστής AOT δεν μπορεί να δει τον αυτόματο κωδικό εκκίνησης (μοιάζει με μη χρησιμοποιημένο κώδικα και παίρνει κομμένα), έτσι ώστε να σας **πρέπει να αρχικοποιήσει χειροκίνητα** το πακέτο στην αρχή της εφαρμογής σας.

Εδώ είναι η μαγική γραμμή που χρειάζεστε:

```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();
    }
}
```

### Τι Κάνει `Batteries.Init()` Να το κάνω;

Η μέθοδος αυτή λέει στο πακέτο SQLite:

1. Βρείτε τη σωστή μητρική βιβλιοθήκη SQLite για την τρέχουσα πλατφόρμα σας
2. Γέμισέ το στη μνήμη.
3. Καλωδιώστε όλες τις συνδέσεις μεταξύ `Microsoft.Data.Sqlite` και η μητρική βιβλιοθήκη

Ονομάζεται "Μπαταρίες" γιατί είναι το πακέτο μπαταριών "συμπεριλαμβάνονται οι μπαταρίες" και όλα όσα χρειάζεστε είναι συσκευασμένα μαζί.

### Πού να το βάλετε

Βάλτε `Batteries.Init()` ως **η πρώτη γραμμή** σε σας `Main` μέθοδος, πριν από:

- Δημιουργία του κατασκευαστή εφαρμογών
- Ρύθμιση της ένεσης εξάρτησης
- Άνοιγμα τυχόν συνδέσεων βάσης δεδομένων
- Ανάγνωση αρχείων ρύθμισης που μπορεί να χρησιμοποιούν SQLite

Σκεφτείτε το όπως το plugging σε μια συσκευή πριν προσπαθήσετε να την ενεργοποιήσετε. Αν προσπαθήσετε να χρησιμοποιήσετε SQLite πριν καλέσετε `Init()`, θα εξακολουθείς να παίρνεις το `DllNotFoundException` ακόμη και αν η DLL είναι σωστά δεμένη στην εφαρμογή σας.

### Τι Συμβαίνει Αν Ξεχνάτε;

Αν ξεχάσεις να τηλεφωνήσεις `Batteries.Init()`, η εφαρμογή σας θα:

1. Κατασκευή με επιτυχία (ο μεταγλωττιστής δεν θα σας προειδοποιήσει)
2. Ξεκίνα να τρέχεις.
3. Συντριβή τη στιγμή που προσπαθεί να χρησιμοποιήσει SQLite με:

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

Αυτό είναι μπερδεμένο επειδή το DLL **ί ας** Έχασα δύο ώρες από αυτό το λάθος, μην είσαι σαν εμένα.

## Πλήρης διαμόρφωση έργου

Ορίστε ένα γεμάτο. `.csproj` Διαμορφωμένο για πολυ-platform Native AOT με SQLite:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.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>
```

### Βασικές Ρυθμίσεις Εξηγήθηκαν (Στα Απλά Αγγλικά)

Επιτρέψτε μου να αναλύσω τι κάνει κάθε μία από αυτές τις ρυθμίσεις:

**`PublishAot=true`**

Αυτό είναι το master switch που επιτρέπει Native AOT συλλογή. Χωρίς αυτό, μπορείτε να πάρετε τη φυσιολογική συμπεριφορά .NET (JIT συλλογή). Με αυτό, μπορείτε να πάρετε μπροστά-of-time καταρτίζεται μητρική κώδικα.

**`PublishTrimmed=true` και `TrimMode=full`**

Αυτά λένε στον μεταγλωττιστή για να αφαιρέσετε κάθε κώδικα που δεν χρησιμοποιείτε. Σκεφτείτε το σαν να καθαρίζετε το γκαράζ σας πριν μετακινήσετε τα πράγματα που δεν χρειάζεστε;

- `PublishTrimmed=true` επιτρέπει την κοπή
- `TrimMode=full` Σημαίνει "να είσαι επιθετικός, να αφαιρείς ό,τι μπορείς."

**Προειδοποίηση**: Αυτό μπορεί να σπάσει τον κώδικα που χρησιμοποιεί βαριά αντανάκλαση (όπως μερικά JSON σειρηνοποιητές ή ORMs) επειδή το trmmer δεν μπορεί πάντα να δει τι χρησιμοποιείτε μέσω αντανάκλασης.

**`InvariantGlobalization=true`**

Αυτό αφαιρεί όλα τα δεδομένα ειδικά για τον πολιτισμό από τις μορφές εφαρμογής σας, σύμβολα νομισμάτων, κανόνες ταξινόμησης κειμένου για διαφορετικές γλώσσες. Αποθηκεύει 5-10MB.

Μόνο βάλτε αυτό στο `true` εάν η εφαρμογή σας:

- Μόνο αγγλικά χρησιμοποιεί
- Δεν χρειάζεται την ειδική για τον πολιτισμό ημερομηνία/διαμόρφωση ώρας
- Χρησιμοποιεί μόνο συνήθεις συγκρίσεις συμβολοσειράς (byte-by-byte)

Αν φτιάχνετε ένα εργαλείο CLI ή API πύλη που δεν νοιάζεται για τον εντοπισμό, αυτό είναι δωρεάν εξοικονόμηση. Αν φτιάχνετε κάτι που χρειάζεται να διαμορφώσετε ημερομηνίες για τους Γάλλους χρήστες ή να ταξινομήσετε σωστά το τουρκικό κείμενο, παραλείψτε αυτή τη ρύθμιση.

**`PublishSingleFile=true`**

Βάζει τα πάντα σε ένα εκτελέσιμο αρχείο.

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

Απλά

```
myapp.exe
```

Πολύ πιο εύκολο να αναπτυχθείς.

**`StripSymbols=true`**

Τα σύμβολα αποσφαλμάτωσης βοηθούν αποσφαλματωτές σας δείχνουν διάφορα ονόματα και αριθμούς γραμμών κατά την αποσφαλμάτωση. Είναι χρήσιμα κατά τη διάρκεια της ανάπτυξης, αλλά προσθέστε αρκετά megabytes στο τελικό δυαδικό σας.

Αυτή η ρύθμιση τα αφαιρεί. Η εφαρμογή σας τρέχει ακριβώς την ίδια, ακριβώς μικρότερη.

**`OptimizationPreference=Speed`**

Αυτό λέει στον μεταγλωττιστή τι να δώσει προτεραιότητα κατά τη λήψη αποφάσεων:

- `Speed`: Κάντε το γρήγορο (ελαφρά μεγαλύτερα δυαδικά, αλλά καλύτερη απόδοση)
- `Size`: Κάντε το μικρό (ελαφρά πιο αργό, αλλά ελάχιστο δυαδικό μέγεθος)

Για τις περισσότερες εφαρμογές, `Speed` είναι η σωστή επιλογή. Η διαφορά μεγέθους είναι συνήθως μόνο 2-3MB, αλλά η διαφορά απόδοσης μπορεί να είναι αισθητή.

**`RuntimeIdentifiers`**

Αυτό δηλώνει ποιες πλατφόρμες θέλετε να υποστηρίξετε.

Διαθέσιμα στοιχεία αναγνώρισης:

- `win-x64`: Windows 64-bit (Intel/AMD)
- `win-arm64`: Windows ARM64 (Surface Pro X, κλπ.)
- `linux-x64`: Linux 64-bit (Ubuntu, Debian, RHEL, κλπ.)
- `linux-arm64`: Linux ARM64 (Σμέουρα Pi 4/5, AWS Graviton)
- `osx-x64`: macOS Intel (older Macs)
- `osx-arm64`: macOS Apple Silicon (M1/M2/M3 Macs)

Φτιάχνεις μια πλατφόρμα κάθε φορά που χρησιμοποιείς `dotnet publish -r linux-x64`, για παράδειγμα.

## Κατασκευή πολλαπλών πλατφορμών

Θυμάστε πώς είπα AOT απαιτεί ειδικές κατασκευές πλατφόρμας; Θα πρέπει να συντάξετε ξεχωριστά για τα Windows, Linux x64, Linux ARM64, macOS Intel, και macOS Apple Silicon.

### Τι είναι οι δράσεις GitHub;

Εάν δεν είστε εξοικειωμένοι, το GitHub Activities είναι μια δωρεάν υπηρεσία CI/CD (Συνεχής Ενσωμάτωση/Συνεχής Ανάπτυξη) ενσωματωμένη στο GitHub. Σας επιτρέπει να εκτελέσετε αυτοματοποιημένες εργασίες όποτε σπρώχνετε τον κώδικα ή δημιουργείτε μια ετικέτα απελευθέρωσης.

Σκέψου το σαν να έχεις ένα σέρβερ κατασκευής που:

1. Παρακολουθεί το αποθετήριό σας GitHub
2. Όταν σπρώχνεις μια ετικέτα όπως `v1.0.0`
3. Γυρίζει αυτόματα Windows, Linux, και macOS εικονικές μηχανές
4. Κατασκευάζει την εφαρμογή σας για όλες τις πλατφόρμες παράλληλα
5. Δημιουργεί μια απελευθέρωση GitHub με όλα τα δυαδικά

Όλα αυτά τρέχουν στους διακομιστές του GitHub έτσι δεν χρειάζεται να διατηρήσει καμία υποδομή. Για έργα ανοικτού κώδικα και μικρά προσωπικά έργα, είναι εντελώς δωρεάν.

### Η Πλήρης Ροή Εργασίας Οικοδομής

Εδώ είναι μια ροή εργασίας GitHub Δράσεις που χτίζει για όλες τις μεγάλες πλατφόρμες αυτόματα:

```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
```

### Πώς λειτουργεί αυτή η ροή εργασίας (Βήμα-Βήμα)

Αν το YAML φαίνεται τρομακτικό, ορίστε τι κάνει στα απλά αγγλικά:

**1. Ενεργοποιητής (`on: push: tags`)**

Η ροή εργασίας τρέχει όταν σπρώχνετε μια ετικέτα Git που ξεκινά με `v` (όπως `v1.0.0`, `v2.3.1`). Αυτός είναι ο τυποποιημένος τρόπος για να σημαδέψετε τις εκδόσεις έκδοσης.

**2. Matrix Στρατηγική**

Αυτό είναι το έξυπνο μέρος. Αντί να γράψουμε πέντε ξεχωριστές ροές εργασίας, ορίζουμε ένα **μήτρα** των κατασκευών:

- Κάθε κτίσμα παίρνει ένα διαφορετικό `os` (μηχανή δρομέων) και `runtime` (πλατφόρμα-στόχος)
- Οι δράσεις GitHub τρέχουν και τα πέντε οικοδομήματα **παράλληλα**
- Κάθε ένα παράγει ένα τεχνούργημα (το καταρτισμένο δυαδικό)

Οπότε όταν σπρώχνεις `v1.0.0`, GitHub ταυτόχρονα:

- Περιστροφές μέχρι ένα μηχάνημα Ubuntu για την κατασκευή Linux x64 και ARM64
- Περιστρέφει ένα μηχάνημα των Windows για την κατασκευή των Windows x64
- Περιστροφές μέχρι ένα μηχάνημα macOS για την κατασκευή macOS x64 και ARM64

**3. Βήματα σε κάθε οικοδόμημα**

Κάθε πλατφόρμα κάνει τα ίδια βήματα:

1. **Κωδικός ελέγχου**: Παίρνει τον πηγαίο σας κώδικα από το αποθετήριο
2. **Ρύθμιση .NET**: Εγκαταστάτες .NET 9 SDK
3. **Εγκατάσταση εργαλείων ARM64** (Μόνο Linux ARM64): Εργαλεία σταυροποίησης Εγκαταστάσεων
4. **Δημοσίευση**: Runs `dotnet publish` με σημαίες AOT για τη συγκεκριμένη πλατφόρμα
5. **Ανεβάστε το τεχνούργημα**: Αποθηκεύει το καταρτισμένο δυαδικό έτσι ώστε η επόμενη εργασία να μπορεί να έχει πρόσβαση σε αυτό

**4. Το αποτέλεσμα**

Μπορείτε να τα κατεβάσετε από την εκτέλεση των δράσεων, ή να χρησιμοποιήσετε μια δεύτερη εργασία για να δημιουργήσετε μια έκδοση GitHub αυτόματα (δεν εμφανίζεται σε αυτό το snippet, αλλά εύκολο να προσθέσετε).

### Κρίσιμη: Οι Ιθαγενείς Βιβλιοθήκες δεν Λυγίζονται

Να κάτι που με μπερδεύει για ώρες. **`PublishSingleFile=true` Μόνο δέματα . NET code**. Ιθαγενείς βιβλιοθήκες όπως SQLite's `e_sqlite3.dll` Μείνε χωριστά.

Αυτός είναι ο λόγος για τον οποίο το βήμα "Δημιουργία πακέτο διανομής" είναι τόσο σημαντικό:

```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
```

Η `2>/dev/null || true` μέρος σημαίνει "αν δεν υπάρχουν αρχεία που να ταιριάζουν με αυτό το μοτίβο, μην αποτύχετε απλά να συνεχίσετε." Αυτό επιτρέπει την ίδια εργασία σεναρίου σε όλες τις πλατφόρμες.

**Τι διανέμετε:**

- Παράθυρα: `myapp.exe` + `e_sqlite3.dll` (μαζί σε ZIP)
- Linux: `myapp` + `libe_sqlite3.so` (μαζί σε πίσσα gz)
- MacOS: `myapp` + `libe_sqlite3.dylib` (μαζί σε πίσσα gz)

Οι χρήστες εξάγουν το αρχείο και τρέχουν το εκτελέσιμο. Η μητρική βιβλιοθήκη SQLite κάθεται δίπλα στο εκτελέσιμο, και το πακέτο το βρίσκει αυτόματα σε χρόνο λειτουργίας.

### Γιατί η Χειροκίνητη Εναλλαγή Είναι Χρήσιμη

Παρατηρήστε το `workflow_dispatch` πυροκροτητής στην κορυφή:

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

Αυτό σας επιτρέπει να ενεργοποιήσετε την κατασκευή χειροκίνητα από το web interface του GitHub χωρίς να σπρώχνετε μια ετικέτα.

### ARM64 Cross-Compilation

Η κατασκευή Linux ARM64 απαιτεί ιδιαίτερη προσοχή. `objcopy` εργαλείο:

```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
```

Χωρίς την `ObjCopyName` παράμετρος, ο σύνδεσμος αποτυγχάνει με αινιγματικά λάθη σχετικά με μη αναγνωρίσιμες μορφές αρχείων.

## Real-World Results

Εδώ είναι αυτό που κατάφερα με την πύλη ανίχνευσης bot με βάση την παραγωγή μου YARP με μεσαίο λογισμικό και SQLite loging. Αυτό είναι ένα πραγματικό έργο που μπορείτε να [λήψη από το GitHub](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.BotDetection.Console).

### Δυαδικά μεγέθη (Από τις πραγματικές κυκλοφορίες GitHub)

Αυτά είναι τα **πραγματικά μεγέθη αρχείων** από τις κυκλοφορίες μου στο GitHub, όχι θεωρητικές εκτιμήσεις:

Πλατφόρμα ~ Εκτελέσιμο ~ SQLite Native DLL ~ Συνολικό Αρχείο Μέγεθος ~
|----------|-----------|-------------------|-------------------|
Windows x64 9,2MB +1,7MB **10. 9MB** (ZIP) 
Linux x64 10,8MB +1,6MB **12, 4MB** (tar.gz) {\pos (195,220) }
Linux ARM64 **11. 4MB** (tar.gz) {\pos (195,220) }
MacOS Intel 11,2MB +1,8MB **ΛΙΘΟΥΑΝΙΑ** (tar.gz) {\pos (195,220) }
Macos ARM64 9,8MB +1,7MB **11, 5MB** (tar.gz) {\pos (195,220) }

Συγκρίνετε αυτό με τις αυτόνομες εφαρμογές του NET 9 στις **130-150MB ανά πλατφόρμα**- Μιλάμε για ένα... **10-12x μείωση του μεγέθους**.

Η ανάλυση:

- Κύριο εκτελέσιμο: Ο κωδικός σας + .NET runtime (AOT-compiled)
- Ιθαγενής DLL: Ο κινητήρας βάσης δεδομένων SQLite (γράφτηκε στο Γ)

Και τα δύο αρχεία πρέπει να διανεμηθούν μαζί, αλλά είναι ακόμα δραματικά μικρότερα από τις παραδοσιακές εφαρμογές .NET.

### Απόδοση εκκίνησης

Κρύο ξεκίνημα (πρώτη αίτηση σερβίρεται) σε ένα μέτριο Linux VPS:

- **Αυτοσυντηρούμενο .NET**~800ms
- **Ιθαγενής AOT**~150ms
- **Βελτίωση**: 81% γρηγορότερα

Αυτό έχει τεράστια σημασία για:

- Λειτουργίες Serverless/Lambda (πληρώνετε ανά χιλιοστό του δευτερολέπτου)
- Δοχεία που κλιμακώνουν συχνά προς τα πάνω / προς τα κάτω
- Εργαλεία CLI όπου κάθε επίκληση ξεκινάει φρέσκα

### Χρήση μνήμης

Άκαμπτη μνήμη (πύλη λειτουργίας, χωρίς κίνηση):

- **Αυτοσυντηρούμενο .NET**: 85MB
- **Ιθαγενής AOT**: 42MB
- **Βελτίωση**: 51% μείωση

Υπό φορτίο (1000 αιτήσεις/δεύτερο):

- **Αυτοσυντηρούμενο .NET**~320MB
- **Ιθαγενής AOT**~180MB
- **Βελτίωση**: 44% μείωση

Χαμηλότερη μνήμη σημαίνει:

- Περισσότερα εμπορευματοκιβώτια ανά ξενιστή
- Φθηνότερο cloud hosting λογαριασμούς
- Ευελιξία στις συσκευές συγκράτησης πόρων (Raspberry Pi, IoT)

## Κοινές Πύλες

### 1. Ξεχνώντας `Batteries.Init()`

Αυτό είναι το #1 λάθος. Ακόμα και με το πακέτο σωστά αναφέρεται, ξεχνώντας να καλέσετε `SQLitePCL.Batteries.Init()` στην αρχή της `Main` Η μέθοδος θα προκαλέσει συντριβές του χρόνου λειτουργίας.

**Η διόρθωση:**

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

### 2. Μη Διανομή Ιθαγενών Βιβλιοθηκών

Αυτό είναι λάθος νούμερο 2 και με έπιασε δύο φορές. `PublishSingleFile=true` δεν περιέχει ντόπια SQLite DLLs στο εκτελέσιμό σας. Πρέπει να τα διανείμετε παράλληλα με το εκτελέσιμό σας.

**Τι θα συμβεί αν ξεχάσετε:**

- Η εφαρμογή σου φτιάχνει μια χαρά.
- Λειτουργεί μια χαρά στη μηχανή dev σας (όπου SQLite μπορεί να είναι ήδη εγκατασταθεί)
- Καταρρέει στην παραγωγή με `DllNotFoundException`

**Η διόρθωση:**

Όταν συσκευάζετε την απελευθέρωσή σας, να συμπεριλάβετε πάντα:

```
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)
```

Στις δράσεις σας στο GitHub ή τα σενάρια ανάπτυξης:

```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
```

Οι χρήστες θα πρέπει να εξάγει το αρχείο και να τρέξει το εκτελέσιμο. Η μητρική βιβλιοθήκη πρέπει να είναι στον ίδιο κατάλογο.

### 3. Χρήση `winsqlite3` Προμηθευτής

Μπορεί να δείτε συστάσεις για χρήση `SQLitePCLRaw.provider.winsqlite3` στα Windows για να χρησιμοποιήσετε το SQLite που παρέχεται OS. Μην. Λειτουργεί μόνο στα Windows, απαιτεί χειροκίνητη αρχικοποίηση, και σπάει cross-platform builts. Stick με `bundle_e_sqlite3`.

### 4. Προειδοποιήσεις Trim με πυρήνα EF

Εάν χρησιμοποιείτε πυρήνα πλαισίου οντότητας με SQLite, θα λάβετε προειδοποιήσεις κοπής (IL2026, IL3050).

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

Καλύτερα ακόμα, σκεφτείτε τη χρήση Dapper ή ωμή ADO.NET με SQLite για AOT εφαρμογές είναι πιο φιλικές προς το AOT.

### 5. Χαμένα Εργαλεία Visual Studio (Windows)

Στα Windows, Native AOT απαιτεί Visual Studio MSVC linker. Αν χτίζετε έξω από μια εντολή προγραμματιστή Prompt, θα πάρετε λάθη σχετικά με `vswhere.exe`. GitHub Δράσεις χειρίζονται αυτό αυτόματα, αλλά για τοπικές κατασκευές, χρήση:

- Προβολή εντολής προγραμματιστή για VS 2022
- Προγραμματιστής PowerShell για VS 2022

Ή να αρχικοποιήσετε το περιβάλλον στο σενάριο κατασκευής σας:

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

## Πότε να χρησιμοποιήσετε το Native AOT

Το Native AOT είναι ιδανικό για:

- **Εργαλεία CLI**: Άμεση startup θέματα
- **Μικροϋπηρεσίες και εμπορευματοκιβώτια**: Μικρότερες εικόνες, ταχύτερη κλιμάκωση
- **Συσκευές εκκένωσης**: Raspberry Pi, IoT συσκευές με περιορισμένους πόρους
- **Serverless/Lambda**: Ψυχρός χρόνος έναρξης είναι κρίσιμος
- **Εφαρμογές πύλης/προεξοχής**: Υψηλή απόδοση, χαμηλό ύψος

Αποφύγετε το AOT για:

- Βασική χρήση πλαισίου βαρέων οντοτήτων (παρτίδες μεταναστών, περίπλοκα ερωτήματα)
- Αντανάκλαση-βαριές εφαρμογές
- Δυναμικά συστήματα plugin
- Εφαρμογές που χρειάζονται παραγωγή κώδικα runtime

## Γρήγορη λίστα ελέγχου εκκίνησης

Αν έχετε διαβάσει όλη αυτή τη θέση και απλά θέλετε μια λίστα ελέγχου για να ακολουθήσετε, ορίστε:

**1. Προσθέστε τα πακέτα:**

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

**2. Ρυθμίστε το δικό σας `.csproj` για το AOT:**

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

**3. Αρχικοποίηση SQLite στην αρχή του σας `Main` μέθοδος:**

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

**4. Κατασκευή για την πλατφόρμα-στόχο σας:**

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

**5. Δοκιμάστε το δυαδικό σας θα πρέπει απλά να τρέξει χωρίς εξαρτήσεις!**

## Συμπέρασμα

Το να πάρεις το SQLite να δουλεύεις με τον Ιθαγενή AOT δεν είναι προφανές, αλλά μόλις μάθεις το μαγικό ξόρκι`SQLitePCLRaw.bundle_e_sqlite3` + `Batteries.Init()`Η αποπληρωμή είναι σημαντική: μικροσκοπικά δυαδικά, άμεση εκκίνηση, και η ικανότητα να αναπτυχθεί σε οποιαδήποτε πλατφόρμα χωρίς εξαρτήσεις τρεξίματος.

Για όποιον χτίσει εργαλεία CLI, πύλες, ή εφαρμογές άκρη με .NET, Native AOT με SQLite είναι τώρα μια ρεαλιστική επιλογή. Η ροή εργασίας GitHub Δράσεις παρέχεται εδώ αυτοματοποιεί ολόκληρη τη διαδικασία κατασκευής πολλαπλών πλατφορμών.

Αν είστε νέοι στο AOT, ξεκινήστε μικρά: μετατρέψτε ένα απλό εργαλείο CLI ή βοηθητικό πρόγραμμα πρώτα. Πάρτε άνετα με τη διαδικασία κατασκευής, μάθετε τι προειδοποιήσεις να περιμένετε, και να κατανοήσετε τους περιορισμούς. Μόλις έχετε τα βασικά κάτω, μπορείτε να αντιμετωπίσετε πιο πολύπλοκες εφαρμογές.

Το οικοσύστημα .NET είναι όλο και πιο φιλικό προς το AOT. Οι περισσότερες σύγχρονες βιβλιοθήκες είτε λειτουργούν έξω από το κουτί ή έχουν σαφή τεκμηρίωση για την υποστήριξη AOT. Το μέλλον είναι εγγενές, και είναι γρηγορότερο από ό, τι νομίζετε.

## Εμπειρία Πραγματικής Αναπτύξεως

Αναπτύσσω την AOT-compiled πύλη μου:

- **Digital Ocean Droplet** (Linux x64) - λειτουργεί ως systemd υπηρεσία
- **Βατόμουρο Pi 5** (Linux ARM64) - ανάπτυξη άκρων για δοκιμές
- **Εξυπηρετητής παραθύρωνName** (Windows x64) - τρέχει ως υπηρεσία Windows
- **Δοχεία για πόρτες** - τόσο x64 όσο και ARM64 παραλλαγές

Η διαδικασία ανάπτυξης είναι πανομοιότυπη παντού:

1. Κατεβάστε το αρχείο από τις κυκλοφορίες GitHub
2. Εκχύλισέ το.
3. Εκτελέστε το εκτελέσιμο

Δεν υπάρχει "εγκαταστήστε το .NET Runtime" βήμα, καμία κόλαση εξάρτησης, καμία σύγκρουση εκδοχή.

Για τον Ντόκερ `Dockerfile` είναι ντροπιαστικά απλό:

```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"]
```

Η προκύπτουσα εικόνα είναι **~130MB** Ένα παραδοσιακό δοχείο NET θα ήταν 200-250MB.

## Πλήρες παράδειγμα εργασίας

Όλα όσα έχω δείξει εδώ προέρχονται από ένα πραγματικό, έτοιμο για παραγωγή έργο.

- **Προβολή του πηγαίου κώδικα**: [Κυρίως διαυγής.BotDefection.Console](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.BotDetection.Console)
- **Δείτε τη ροή εργασιών των δράσεων GitHub**: [console-gateway-lease.yml](https://github.com/scottgal/mostlylucid.nugetpackages/blob/main/.github/workflows/console-gateway-release.yml)
- **Κατεβάστε τα προχτισμένα δυαδικά**: [Κυκλοφορίες GitHub](https://github.com/scottgal/mostlylucid.nugetpackages/releases)

Το έργο είναι ένα ελάχιστο YARP αντίστροφη μεσολάβηση με μεσαίο λογισμικό ανίχνευσης bot που καταγράφει υπογραφές στο SQLite. Δείχνει:

- Native AOT με SQLite
- Multi-platform χτίζει μέσω των δράσεων GitHub
- Συγκρότημα ιθαγενών βιβλιοθηκών
- Ανάλυση του επιχειρήματος CLI
- Δομημένη υλοτομία
- Χαριτωμένο κλείσιμο

Clone it, study it, use it as a template for your own AOT projects.

## Πόροι

- [Επίσημη τεκμηρίωση .NET Native AOT](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/)
- [SQLitePCLRaw GitHub Repository](https://github.com/ericsink/SQLitePCL.raw)
- [Παράδειγμα εργασίας: Κυρίως διαυγής πύλη ανίχνευσης bot](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.BotDetection.Console)
- [Οι πράξεις μου GitHub Ροή Εργασίας](https://github.com/scottgal/mostlylucid.nugetpackages/blob/main/.github/workflows/console-gateway-release.yml)

Τώρα πήγαινε να φτιάξεις κάτι μικροσκοπικό και γρήγορο.