ネイティブ ライブラリの読み込み

この記事では、P/Invoke を介したネイティブ ライブラリの読み込み時にランタイムで検索されるパスについて説明します。 また、SetDllImportResolver の使用方法についても示します。

ライブラリ名のバリエーション

クロス プラットフォームの P/Invoke コードをさらに単純にするために、正規の共有ライブラリ拡張機能 (.dll.so または .dylib) が、ランタイムによってネイティブ ライブラリ名に追加されます。 また、Unix ベースのプラットフォームでは、ランタイムによって lib の付加も試みられます。 これらのライブラリ名のバリエーションは、ネイティブ ライブラリを読み込む DllImportAttribute などの API を使用すると、自動的に検索されます。

Note

ライブラリ名の絶対パス (/usr/lib/libc.so など) はそのままの状態で扱われ、バリエーションは検索されません。

P/Invoke を使用する次の例を考えてみましょう。

[DllImport("nativedep")]
static extern int ExportedFunction();

Windows で実行している場合、DLL は次の順序で検索されます。

  1. nativedep
  2. nativedep.dll (ライブラリ名の末尾が .dll または .exe ではない場合)

Linux または macOS で実行されている場合、ランタイムによって、lib の付加、および正規の共有ライブラリ拡張機能の追加が試みられます。 これらの OS では、ライブラリ名のバリエーションは次の順序で試行されます。

  1. nativedep.so / nativedep.dylib
  2. libnativedep.so / libnativedep.dylib 1
  3. nativedep
  4. libnativedep 1

Linux では、ライブラリ名の末尾が .so、またはライブラリ名に .so. (末尾の . に注意) が含まれている場合に、検索の順序が異なります。 次に例を示します。

[DllImport("nativedep.so.6")]
static extern int ExportedFunction();

この場合、ライブラリ名のバリエーションは、次の順序で試みられます。

  1. nativedep.so.6
  2. libnativedep.so.6 1
  3. nativedep.so.6.so
  4. libnativedep.so.6.so 1

1 パスは、ライブラリ名にディレクトリの区切り文字 (/) が含まれていない場合にのみ確認されます。

カスタム インポート リゾルバー

より複雑なシナリオでは、実行時での DLL のインポートを解決する、SetDllImportResolver を使用できます。 次の例では、CPU がサポートする場合に、nativedepnativedep_avx2 に解決されます。

ヒント

この機能は、.NET Core 3.1 以降および .NET 5 以降でのみ使用できます。

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace PInvokeSamples
{
    public static partial class Program
    {
        [LibraryImport("nativedep")]
        private static partial int ExportedFunction();

        public static void Main(string[] args)
        {
            // Register the import resolver before calling the imported function.
            // Only one import resolver can be set for a given assembly.
            NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), DllImportResolver);

            int value = ExportedFunction();
            Console.WriteLine(value);
        }

        private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
        {
            if (libraryName == "nativedep")
            {
                // On systems with AVX2 support, load a different library.
                if (System.Runtime.Intrinsics.X86.Avx2.IsSupported)
                {
                    return NativeLibrary.Load("nativedep_avx2", assembly, searchPath);
                }
            }

            // Otherwise, fallback to default import resolver.
            return IntPtr.Zero;
        }
    }
}

関連項目