diff --git a/src/Numerics/Providers/NativeProviderLoader.cs b/src/Numerics/Providers/NativeProviderLoader.cs index 591363ad..04cd6775 100644 --- a/src/Numerics/Providers/NativeProviderLoader.cs +++ b/src/Numerics/Providers/NativeProviderLoader.cs @@ -40,11 +40,9 @@ namespace MathNet.Numerics.Providers /// /// Helper class to load native libraries depending on the architecture of the OS and process. /// - [SuppressUnmanagedCodeSecurity] - [SecurityCritical] static internal class NativeProviderLoader { - private static Lazy> _platformDirectories + private static Lazy> _ArchitectureDirectories = new Lazy>( () => new Dictionary(StringComparer.OrdinalIgnoreCase) { @@ -55,9 +53,9 @@ namespace MathNet.Numerics.Providers }, true); /// - /// Default directories for each platform. + /// Default directories for each architecture. /// - private static Dictionary PlatformDirectories { get { return _platformDirectories.Value; } } + private static Dictionary ArchitectureDirectories { get { return _ArchitectureDirectories.Value; } } private static Lazy> _nativeHandles = new Lazy>(true); /// @@ -65,39 +63,48 @@ namespace MathNet.Numerics.Providers /// private static Dictionary NativeHandles { get { return _nativeHandles.Value; } } - private static string _Platform = null; + private static string _ArchDirectory = null; /// - /// Gets a string indicating the platform of the current process. + /// Gets a string indicating the architecture and bitness of the current process. /// - private static string Platform + private static string ArchDirectory { get { - if (string.IsNullOrEmpty(_Platform)) + if (string.IsNullOrEmpty(_ArchDirectory)) { string architecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); if (!Environment.Is64BitProcess && Environment.Is64BitOperatingSystem) { - _Platform = string.Equals(architecture, "ARM", StringComparison.OrdinalIgnoreCase) ? "ARM" : "x86"; - } - else - { - _Platform = architecture; + architecture = string.Equals(architecture, "ARM", StringComparison.OrdinalIgnoreCase) ? "ARM" : "x86"; } + + // Fallback to using the architecture name if unknown + if (!ArchitectureDirectories.TryGetValue(architecture, out _ArchDirectory)) + _ArchDirectory = architecture; } - return _Platform; + return _ArchDirectory; + } + } + + private static bool IsUnix + { + get + { + var p = Environment.OSVersion.Platform; + return p == PlatformID.Unix || p == PlatformID.MacOSX; } } /// /// If the last native library failed to load then gets the corresponding exception which occurred or null if the library was successfully loaded. /// - private static Exception LastException { get; private set; } + public static Exception LastException { get; private set; } private static object staticLock = new Object(); /// - /// Load the native library with the given filename, + /// Load the native library with the given filename. /// /// The file name of the library to load. /// True if the library was successfully loaded or if it has already been loaded. @@ -113,9 +120,9 @@ namespace MathNet.Numerics.Providers return true; string path = null; - if (PlatformDirectories.TryGetValue(Platform, out path)) + if (!IsUnix) { - path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), path, fileName); + path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), ArchDirectory, fileName); } if (string.IsNullOrEmpty(path) || !File.Exists(path)) { @@ -125,7 +132,7 @@ namespace MathNet.Numerics.Providers } // If successful this will return a handle to the library - libraryHandle = LoadLibrary(path); + libraryHandle = IsUnix ? UnixLoader.LoadLibrary(path) : UnixLoader.LoadLibrary(path); if (libraryHandle == IntPtr.Zero) { int lastError = Marshal.GetLastWin32Error(); @@ -142,7 +149,27 @@ namespace MathNet.Numerics.Providers } } - [DllImport("kernel32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - private static extern IntPtr LoadLibrary(string fileName); + [SuppressUnmanagedCodeSecurity] + [SecurityCritical] + private static class WindowsLoader + { + [DllImport("kernel32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr LoadLibrary(string fileName); + } + + [SuppressUnmanagedCodeSecurity] + [SecurityCritical] + private static class UnixLoader + { + public static IntPtr LoadLibrary(string fileName) + { + return dlopen(fileName, RTLD_NOW); + } + + const int RTLD_NOW = 2; + + [DllImport("libdl.so")] + private static extern IntPtr dlopen(String fileName, int flags); + } } }