# CoreBus et Native AOT : Expérience pratique de compilation d'un terminal multiplateforme
La compilation d'applications .NET avec Native AOT promet des temps de démarrage plus rapides et des tailles de distribution réduites, mais en pratique, elle comporte de nombreuses limitations techniques. Cet article explore un cas concret d'intégration de Native AOT dans CoreBus — un terminal multiplateforme pour travailler avec les ports COM et les protocoles Modbus.
Pourquoi Native AOT ?
Les principaux motifs du passage à Native AOT étaient les démarrages à froid lents sur les PC bas de gamme et la taille importante du package d'installation. Après la migration de WPF vers Avalonia UI, la taille de l'application a diminué d'environ 60 Mo, mais atteindre l'objectif de 10 Mo semblait encore hors de portée. Native AOT apparaissait comme l'étape logique suivante, surtout pour une application destinée à des équipements industriels et des systèmes embarqués où les ressources sont souvent limitées.
Cependant, dès l'étape de build, il est apparu clair que le support de Native AOT nécessitait une refonte complète de l'architecture des bindings, de la sérialisation et de la stratégie de publication.
Problème 1 : Bindings compilés dans Avalonia
Avalonia utilise par défaut des bindings dynamiques via la réflexion, ce qui n'est pas compatible avec Native AOT. La solution consiste à activer les bindings précompilés :
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
Cela implique de spécifier explicitement le type de données dans chaque fichier XAML en utilisant l'attribut x:DataType sur l'élément racine (Window, UserControl) et à l'intérieur des DataTemplates. Omettre cet attribut entraîne soit une erreur de compilation (Dynamic code generation is not supported on this platform), soit un crash juste après le lancement.
Dans le projet CoreBus, cela a nécessité la mise à jour de toutes les balises XAML, ce qui a pris un temps considérable mais a éliminé les exceptions d'exécution.
Problème 2 : Sérialisation sans réflexion
Les paramètres et préréglages de CoreBus sont stockés dans des fichiers JSON avec System.Text.Json. Les méthodes de sérialisation standard sont marquées avec les attributs RequiresUnreferencedCode et RequiresDynamicCode, ce qui déclenche les avertissements IL2026 et IL3050 lors des builds Native AOT.
La solution est d'utiliser des sérialiseurs JSON générés à partir de la source via JsonSerializerContext. Voici un exemple d'implémentation correcte :
var options = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
TypeInfoResolver = SerializerContext.Default
};
using var stream = new FileStream(correctFilePath, FileMode.Open);
var jsonTypeInfo = options.TypeInfoResolver.GetTypeInfo(typeof(T), options);
if (jsonTypeInfo == null)
{
throw new Exception($"Not succeeded nayti type {typeof(T)} in obyavlenii konteksta serializatsii.");
}
JsonSerializer.Serialize(stream, data, jsonTypeInfo);
Pour la désérialisation, utilisez une approche similaire :
var data = (T?)JsonSerializer.Deserialize(stream, typeof(T), SerializerContext.Default);
Cela évite complètement la réflexion et garantit la compatibilité avec le trimming et AOT.
Problème 3 : Builds multiplateformes
Native AOT nécessite une compilation native pour l'OS et l'architecture cibles. La version du noyau Linux et glibc sont critiques pour la compatibilité :
- Les builds sur Ubuntu 24.10 (noyau 6.11) ne fonctionnaient pas sur Astra Linux CE (noyau 5.15).
- Les builds sur Ubuntu 18.04 (glibc 2.27) échouaient sur Astra Linux CE (glibc 2.24) en raison du manque de compatibilité descendante dans la bibliothèque C.
Stratégie finale :
- Windows : Build sur Windows 11, tests sur Windows 7/10 — compatibilité réussie.
- Linux : Build directement sur Astra Linux CE avec noyau 5.4 et glibc 2.24.
Cela maximise la portabilité mais complique le processus CI/CD.
Problème 4 : Trimming et assemblies dépendants
Le trimming (suppression du code inutilisé) apporte les plus grandes économies uniquement dans le projet exécutable principal. Les bibliothèques auxiliaires génèrent moins de 300 Ko d'économies au total.
Cependant, un trimming agressif peut supprimer des ressources essentielles d'Avalonia, en particulier les styles. Il est recommandé d'exclure explicitement les thèmes du trimming :
<ItemGroup>
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup>
Bien que cela ne soit peut-être pas nécessaire dans Avalonia 11.3.x, il est préférable de conserver ce paramètre comme mesure de précaution.
Problème 5 : Faux positifs des logiciels antivirus
Les applications construites avec Native AOT + trimming sont souvent signalées comme malveillantes. Windows Defender a qualifié l'installateur de Trojan:Win32/Bearfoos.B!ml et la version portable de Trojan:Script/Wacatac.B!ml.
Il s'agit d'un problème connu lié aux changements dans la structure binaire et à l'absence de signature numérique. La solution consiste à passer par la vérification Microsoft SmartScreen et à ajouter une signature numérique.
Principales leçons
- Native AOT exige un rejet complet de la réflexion et de la génération de code dynamique.
- La compilation doit être effectuée sur la plateforme cible, en tenant compte des versions du noyau et des bibliothèques système.
- La sérialisation générée à partir de la source est obligatoire pour la gestion JSON.
- Le trimming peut endommager les ressources d'interface utilisateur — excluez manuellement les assemblies clés.
- Les outils antivirus génèrent souvent des faux positifs sur les binaires AOT non signés.
— Editorial Team
Aucun commentaire pour le moment.