Udostępnij przez


Współdziałanie kodu natywnego z natywną funkcją AOT

Współdziałanie kodu natywnego to technologia, która umożliwia korzystanie z bibliotek niezarządzanych przez kod zarządzany lub udostępnianie bibliotek zarządzanych kodowi niezarządzanemu (w przeciwnym kierunku).

Mimo że współdziałanie kodu natywnego działa podobnie we wdrożeniach natywnej usługi AOT i innych niż AOT, istnieją pewne specyfiki, które różnią się podczas publikowania jako natywna funkcja AOT.

Bezpośrednie wywołania P/Invoke

Wywołania P/Invoke w plikach binarnych skompilowanych AOT są domyślnie wiązane bezczynnie podczas wykonywania, aby zapewnić lepszą zgodność. Kompilator AOT można skonfigurować tak, aby generował bezpośrednie wywołania dla wybranych metod P/Invoke powiązanych podczas uruchamiania przez dynamiczny moduł ładujący dostarczany z systemem operacyjnym. Niezarządzane biblioteki i punkty wejścia, do których odwołuje się bezpośrednie wywołania, muszą być zawsze dostępne w czasie wykonywania. W przeciwnym razie nie można uruchomić natywnego pliku binarnego.

Zalety bezpośrednich wywołań P/Invoke to:

  • Mają lepszą wydajność stanu stałego.
  • Umożliwiają one statyczne łączenie niezarządzanych zależności.

Konfigurację generowania P/Invoke bezpośrednio można ustawić przy użyciu elementów <DirectPInvoke> w pliku projektu. Nazwa elementu może być <nazwą modułu>, która umożliwia bezpośrednie wywołania dla wszystkich punktów wejścia w module lub <modulename!entrypointname>, co umożliwia bezpośrednie wywołanie tylko określonego modułu i punktu wejścia.

Aby określić listę punktów wejścia w pliku zewnętrznym, użyj <DirectPInvokeList> elementów w pliku projektu. Lista jest przydatna, gdy liczba bezpośrednich wywołań P/Invoke jest duża i niepraktyczne jest ich określanie za pomocą poszczególnych elementów <DirectPInvoke>. Plik może zawierać puste wiersze i komentarze rozpoczynające się od #.

Przykłady:

<ItemGroup>
  <!-- Generate direct PInvoke calls for everything in __Internal -->
  <!-- This option replicates Mono AOT behavior that generates direct PInvoke calls for __Internal -->
  <DirectPInvoke Include="__Internal" />
  <!-- Generate direct PInvoke calls for everything in libc (also matches libc.so on Linux or libc.dylib on macOS) -->
  <DirectPInvoke Include="libc" />
  <!-- Generate direct PInvoke calls for Sleep in kernel32 (also matches kernel32.dll on Windows) -->
  <DirectPInvoke Include="kernel32!Sleep" />
  <!-- Generate direct PInvoke for all APIs listed in DirectXAPIs.txt -->
  <DirectPInvokeList Include="DirectXAPIs.txt" />
</ItemGroup>

W systemie Windows natywna funkcja AOT używa wstępnie wypełnianej listy metod bezpośredniego P/Invoke, które są dostępne we wszystkich obsługiwanych wersjach systemu Windows.

Ostrzeżenie

Ponieważ metody bezpośrednie P/Invoke są rozpoznawane przez dynamiczny moduł ładujący systemu operacyjnego, a nie przez natywną bibliotekę środowiska uruchomieniowego AOT, metody bezpośrednie P/Invoke nie będą uwzględniać DefaultDllImportSearchPathsAttribute. Kolejność wyszukiwania biblioteki będzie przestrzegać reguł dynamicznego ładowania zdefiniowanych przez system operacyjny. Niektóre systemy operacyjne i moduły ładującego oferują sposoby kontrolowania dynamicznego ładowania za pośrednictwem flag konsolidatora (takich jak /DEPENDENTLOADFLAG w systemie Windows lub -rpath w systemie Linux). Aby uzyskać więcej informacji na temat określania flag linkera, zobacz sekcję Linkowanie.

Łączenie

Aby statycznie połączyć się z niezarządzaną biblioteką, należy określić <NativeLibrary Include="filename" /> prowadzący do pliku .lib w systemie Windows i pliku .a w systemach uniksopodobnych.

Przykłady:

<ItemGroup>
  <!-- Generate direct PInvokes for Dependency -->
  <DirectPInvoke Include="Dependency" />
  <!-- Specify library to link against -->
  <NativeLibrary Include="Dependency.lib" Condition="$(RuntimeIdentifier.StartsWith('win'))" />
  <NativeLibrary Include="Dependency.a" Condition="!$(RuntimeIdentifier.StartsWith('win'))" />
</ItemGroup>

Aby określić dodatkowe flagi dla konsolidatora natywnego, użyj <LinkerArg> elementu .

Przykłady:

<ItemGroup>
  <!-- link.exe is used as the linker on Windows -->
  <LinkerArg Include="/DEPENDENTLOADFLAG:0x800" Condition="$(RuntimeIdentifier.StartsWith('win'))" />

  <!-- Native AOT invokes clang/gcc as the linker, so arguments need to be prefixed with "-Wl," -->
  <LinkerArg Include="-Wl,-rpath,'/bin/'" Condition="$(RuntimeIdentifier.StartsWith('linux'))" />
</ItemGroup>

Eksporty natywne

Natywny kompilator AOT eksportuje metody oznaczone adnotacjami z niepustą właściwością UnmanagedCallersOnlyAttribute jako publiczne punkty wejścia w języku C. Dzięki temu można dynamicznie lub statycznie połączyć skompilowane moduły AOT z programami zewnętrznymi. Rozważane są tylko metody oznaczone UnmanagedCallersOnly w opublikowanym zestawie. Metody w odwołaniach do projektu lub pakietach NuGet nie zostaną wyeksportowane. Aby uzyskać więcej informacji, zobacz Przykład NativeLibrary.