File: Utility\NativeLibrary.cs
Web Access
Project: ..\..\..\test\Microsoft.ML.TestFrameworkCommon\Microsoft.ML.TestFrameworkCommon.csproj (Microsoft.ML.TestFrameworkCommon)
// Taken from https://github.com/mellinoe/nativelibraryloader/blob/586f9738ff12688df8f0662027da8c319aee3841/NativeLibraryLoader/NativeLibrary.cs
using System;
using System.Runtime.InteropServices;
#if NET5_0_OR_GREATER
using RuntimeNativeLibrary = System.Runtime.InteropServices.NativeLibrary;
#endif
 
namespace Microsoft.ML.TestFrameworkCommon.Utility
{
    /// <summary>
    /// Represents a native shared library opened by the operating system.
    /// </summary>
    public class NativeLibrary : IDisposable
    {
        private static readonly LibraryLoader _platformDefaultLoader = LibraryLoader.GetPlatformDefaultLoader();
        private readonly LibraryLoader _loader;
 
        public static bool NativeLibraryExists(string name)
        {
#if NET5_0_OR_GREATER
            // Use the runtime's assembly-aware loader to honor native NuGet asset probing.
            // The legacy loader below can falsely report missing libraries on Linux: its "libdl"
            // import may not resolve to libdl.so.2, and its distro-specific RID lookup can miss
            // portable linux-x64 assets. Passing the owning assembly avoids that custom probing.
            var assembly = typeof(NativeLibrary).Assembly;
            if (!RuntimeNativeLibrary.TryLoad(name, assembly, null, out var handle) &&
                !RuntimeNativeLibrary.TryLoad("lib" + name, assembly, null, out handle) &&
                !RuntimeNativeLibrary.TryLoad("lib_" + name, assembly, null, out handle))
            {
                return false;
            }
 
            RuntimeNativeLibrary.Free(handle);
            return true;
#else
            NativeLibrary nativeLibrary = default;
            string extension = default;
            string prefix = "lib";
 
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                extension = ".dylib";
            else if (Environment.OSVersion.Platform == PlatformID.Unix)
                extension = ".so";
            else
                extension = ".dll";
 
            try
            {
                // Try the native name as is.
                nativeLibrary = new NativeLibrary(name + extension);
                return true;
            }
            catch
            {
                // If that didn't load, dispose of the first attempt and try appending lib in front
                try
                {
                    nativeLibrary?.Dispose();
                    nativeLibrary = new NativeLibrary(prefix + name + extension);
                    return true;
                }
                catch
                {
                    // If that didn't load, dispose of the first attempt and try appending lib_ in front
                    try
                    {
                        nativeLibrary?.Dispose();
                        nativeLibrary = new NativeLibrary(prefix + "_" + name + extension);
                        return true;
                    }
                    catch
                    {
                        return false;
                    }
                }
            }
            finally
            {
                nativeLibrary?.Dispose();
            }
#endif
        }
 
        /// <summary>
        /// The operating system handle of the loaded library.
        /// </summary>
        private IntPtr Handle { get; }
 
        /// <summary>
        /// Constructs a new NativeLibrary using the platform's default library loader.
        /// </summary>
        /// <param name="name">The name of the library to load.</param>
        private NativeLibrary(string name)
        {
            _loader = _platformDefaultLoader;
            Handle = _loader.LoadNativeLibrary(name, PathResolver.Default);
        }
 
        /// <summary>
        /// Frees the native library.
        /// </summary>
        public void Dispose()
        {
            _loader.FreeNativeLibrary(Handle);
        }
    }
}