# CoreBus i Native AOT: praktyczne doświadczenie kompilacji wieloplatformowego terminala
Kompilacja aplikacji .NET z użyciem Native AOT obiecuje przyspieszenie uruchamiania i zmniejszenie rozmiaru dystrybucji, ale w praktyce wiąże się z wieloma ograniczeniami technicznymi. W artykule omawiany jest rzeczywisty przypadek integracji Native AOT w CoreBus — wieloplatformowym terminalu do pracy z portami COM i protokołami Modbus.
Dlaczego Native AOT?
Główne motywy przejścia — wolny zimny start na słabych PC i duży rozmiar pakietu instalacyjnego. Po migracji z WPF na Avalonia UI rozmiar aplikacji zmniejszył się o ~60 MB, jednak cel rzędu 10 MB pozostawał nieosiągalny. Native AOT wydawał się logicznym następnym krokiem, zwłaszcza dla aplikacji skierowanej na sprzęt przemysłowy i systemy wbudowane, gdzie zasoby są często ograniczone.
Jednak już na etapie budowania okazało się, że wsparcie Native AOT wymaga przebudowy architektury bindingów, serializacji i strategii publikacji.
Problem 1: kompilowane bindingi w Avalonia
Avalonia domyślnie używa dynamicznych bindingów poprzez refleksję, co jest niezgodne z Native AOT. Aby to rozwiązać, należy włączyć wstępnie skompilowane bindingi:
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
Wymaga to jawnego wskazania typu danych w każdym pliku XAML za pomocą atrybutu x:DataType na elemencie głównym (Window, UserControl) oraz wewnątrz DataTemplate. Brak tego atrybutu powoduje błąd kompilacji (Dynamic code generation is not supported on this platform) lub awarię aplikacji zaraz po uruchomieniu.
W projekcie CoreBus należało zmodyfikować wszystkie pliki XAML, co pochłonęło sporo czasu, ale pozwoliło uniknąć wyjątków w czasie wykonywania.
Problem 2: serializacja bez refleksji
Ustawienia i presety CoreBus są przechowywane w plikach JSON z użyciem System.Text.Json. Standardowe metody serializacji są oznaczone atrybutami RequiresUnreferencedCode i RequiresDynamicCode, co powoduje ostrzeżenia IL2026 i IL3050 podczas budowania z Native AOT.
Rozwiązanie — użycie source-generated JSON serializerów poprzez JsonSerializerContext. Przykład poprawnej implementacji:
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);
Do deserializacji stosuje się analogiczne podejście:
var data = (T?)JsonSerializer.Deserialize(stream, typeof(T), SerializerContext.Default);
To całkowicie eliminuje refleksję i gwarantuje zgodność z trymowaniem i AOT.
Problem 3: wieloplatformowa kompilacja
Native AOT wymaga natywnej kompilacji pod docelowy system operacyjny i architekturę. Wersja jądra Linux i glibc mają kluczowy wpływ na zgodność:
- Kompilacja na Ubuntu 24.10 (jądro 6.11) nie uruchamiała się na Astra Linux CE (jądro 5.15).
- Kompilacja na Ubuntu 18.04 (glibc 2.27) nie działała na Astra Linux CE (glibc 2.24) z powodu braku kompatybilności wstecznej biblioteki C.
Ostateczna strategia:
- Windows: kompilacja na Windows 11, testy na Windows 7/10 — udana zgodność.
- Linux: kompilacja bezpośrednio na Astra Linux CE z jądrem 5.4 i glibc 2.24.
To zapewnia maksymalną przenośność, ale komplikuje proces CI/CD.
Problem 4: trymowanie i zależne projekty
Trymowanie (usuwanie nieużywanego kodu) daje główny zysk tylko w głównym projekcie wykonywalnym. Biblioteki pomocnicze oszczędzają mniej niż 300 KB łącznie.
Jednak agresywne trymowanie może usunąć niezbędne zasoby Avalonia, zwłaszcza style. Zaleca się jawne wyłączenie motywów z trymowania:
<ItemGroup>
<TrimmerRootAssembly Include="Avalonia.Themes.Fluent" />
</ItemGroup>
Chociaż w Avalonia 11.3.x może to nie być konieczne, lepiej zachować ustawienie jako zabezpieczenie.
Problem 5: fałszywe alarmy antywirusów
Aplikacje skompilowane z Native AOT + trymowanie często są rozpoznawane jako złośliwe. Windows Defender oznaczał instalator jako Trojan:Win32/Bearfoos.B!ml, a wersję przenośną — jako Trojan:Script/Wacatac.B!ml.
To znany problem związany ze zmianą struktury binarnej i brakiem podpisu cyfrowego. Rozwiązanie — przejście weryfikacji w Microsoft SmartScreen i dodanie podpisu cyfrowego.
Co ważne
- Native AOT wymaga całkowitej rezygnacji z refleksji i dynamicznej generacji kodu.
- Kompilacja musi być wykonywana na docelowej platformie z uwzględnieniem wersji jądra i bibliotek systemowych.
- Source-generated serializacja jest obowiązkowa do pracy z JSON.
- Trymowanie może uszkodzić zasoby UI — ręcznie wykluczaj kluczowe projekty.
- Antywirusy często fałszywie alarmują na binarne AOT bez podpisu.
— Editorial Team
Brak komentarzy.