다음을 통해 공유


네이티브 라이브러리 로딩

이 문서에서는 P/Invoke를 통해 네이티브 라이브러리를 로드할 때 런타임이 검색하는 경로를 설명합니다. 또한 SetDllImportResolver를 사용하는 방법을 보여 줍니다.

라이브러리 이름 변형

더 간단한 플랫폼 간 P/Invoke 코드를 용이하게 하기 위해 런타임은 정식 공유 라이브러리 확장(.dll, .so 또는 .dylib)을 네이티브 라이브러리 이름에 추가합니다. Unix 기반 플랫폼에서는 런타임이 앞에 lib를 추가하려고 시도합니다. 이러한 라이브러리 이름 변형은 DllImportAttribute와 같은 네이티브 라이브러리를 로드하는 API를 사용할 때 자동으로 검색됩니다.

참고 항목

라이브러리 이름(예: /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 라이브러리 이름에 디렉터리 구분 문자(/)가 포함되지 않은 경우에만 경로가 확인됩니다.

사용자 지정 가져오기 해결 프로그램

더 복잡한 시나리오에서는 SetDllImportResolver를 사용하여 런타임에 DLL 가져오기를 해결할 수 있습니다. 다음 예에서는 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;
        }
    }
}

참고 항목