@ -39,15 +39,12 @@ using System.Threading;
namespace MathNet.Numerics.Providers.Common
{
internal enum Runtim e
internal enum ProcArchitectur e
{
Unknown = 0 ,
WindowsX64 ,
WindowsX86 ,
WindowsArm64 ,
WindowsArm ,
LinuxX64 ,
LinuxX86 ,
X64 ,
X86 ,
Arm ,
Arm64
}
/// <summary>
@ -62,55 +59,52 @@ namespace MathNet.Numerics.Providers.Common
/// </summary>
static readonly Lazy < Dictionary < string , IntPtr > > NativeHandles = new Lazy < Dictionary < string , IntPtr > > ( LazyThreadSafetyMode . PublicationOnly ) ;
/// <summary>
/// Gets a string indicating the architecture and bitness of the current process.
/// </summary>
static readonly Lazy < Runtime > RuntimeKey = new Lazy < Runtime > ( EvaluateRuntime , LazyThreadSafetyMode . PublicationOnly ) ;
/// <summary>
/// If the last native library failed to load then gets the corresponding exception
/// which occurred or null if the library was successfully loaded.
/// </summary>
internal static Exception LastException { get ; private set ; }
static bool IsUnix
{
get
{
var p = Environment . OSVersion . Platform ;
return p = = PlatformID . Unix | | p = = PlatformID . MacOSX ;
}
}
static bool IsWindows { get ; }
static bool IsLinux { get ; }
static bool IsMac { get ; }
static bool IsUnix { get ; }
static Runtime EvaluateRuntime ( )
{
//return (IntPtr.Size == 8) ? X64 : X86;
if ( IsUnix )
{
// Only support x86 and amd64 on Unix as there isn't a reliable way to detect the architecture
return Environment . Is64BitProcess ? Runtime . LinuxX64 : Runtime . LinuxX86 ;
}
static ProcArchitecture ProcArchitecture { get ; }
static string Extension { get ; }
var architecture = Environment . GetEnvironmentVariable ( "PROCESSOR_ARCHITECTURE" ) ;
if ( string . Equals ( architecture , "x86" , StringComparison . OrdinalIgnoreCase ) )
{
return Runtime . WindowsX86 ;
}
static NativeProviderLoader ( )
{
#if !NET461
IsLinux = RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) ;
IsMac = RuntimeInformation . IsOSPlatform ( OSPlatform . OSX ) ;
if ( string . Equals ( architecture , "amd64" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( architecture , "x64" , StringComparison . OrdinalIgnoreCase ) )
{
return Environment . Is64BitProcess ? Runtime . WindowsX64 : Runtime . WindowsX86 ;
}
var a = RuntimeInformation . ProcessArchitecture ;
bool arm = a = = Architecture . Arm | | a = = Architecture . Arm64 ;
#else
var p = Environment . OSVersion . Platform ;
IsLinux = p = = PlatformID . Unix ;
IsMac = p = = PlatformID . MacOSX ;
if ( string . Equals ( architecture , "arm" , StringComparison . OrdinalIgnoreCase ) )
{
return Environment . Is64BitProcess ? Runtime . WindowsArm64 : Runtime . WindowsArm ;
}
bool arm = false ;
#endif
// Fallback if unknown
return Runtime . Unknown ;
IsUnix = IsLinux | | IsMac ;
IsWindows = ! IsUnix ;
Extension = IsWindows
? ".dll"
: IsLinux
? ".so"
: ".dylib" ;
ProcArchitecture = Environment . Is64BitProcess
? arm
? ProcArchitecture . Arm64
: ProcArchitecture . X64
: arm
? ProcArchitecture . Arm
: ProcArchitecture . X86 ;
}
/// <summary>
@ -126,6 +120,11 @@ namespace MathNet.Numerics.Providers.Common
throw new ArgumentNullException ( nameof ( fileName ) ) ;
}
if ( string . IsNullOrEmpty ( Path . GetExtension ( fileName ) ) )
{
fileName = Path . ChangeExtension ( fileName , Extension ) ;
}
// If we have hint path provided by the user, look there first
if ( hintPath ! = null & & TryLoadFromDirectory ( fileName , hintPath ) )
{
@ -168,67 +167,110 @@ namespace MathNet.Numerics.Providers.Common
directory = Path . GetFullPath ( directory ) ;
// If we have a know architecture, try the matching subdirectory first
switch ( RuntimeKey . Value )
if ( IsWindows )
{
switch ( ProcArchitecture )
{
case ProcArchitecture . X64 :
return TryLoadFile ( directory , "runtimes/win-x64/native" , fileName )
| | TryLoadFile ( directory , "win-x64/native" , fileName )
| | TryLoadFile ( directory , "win-x64" , fileName )
| | TryLoadFile ( directory , "x64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . X86 :
return TryLoadFile ( directory , "runtimes/win-x86/native" , fileName )
| | TryLoadFile ( directory , "win-x86/native" , fileName )
| | TryLoadFile ( directory , "win-x86" , fileName )
| | TryLoadFile ( directory , "x86" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm64 :
return TryLoadFile ( directory , "runtimes/win-arm64/native" , fileName )
| | TryLoadFile ( directory , "win-arm64/native" , fileName )
| | TryLoadFile ( directory , "win-arm64" , fileName )
| | TryLoadFile ( directory , "arm64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm :
return TryLoadFile ( directory , "runtimes/win-arm/native" , fileName )
| | TryLoadFile ( directory , "win-arm/native" , fileName )
| | TryLoadFile ( directory , "win-arm" , fileName )
| | TryLoadFile ( directory , "arm" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
default :
return TryLoadFile ( directory , string . Empty , fileName ) ;
}
}
if ( IsLinux )
{
case Runtime . WindowsX64 :
if ( TryLoadFile ( directory , "x64" , fileName )
| | TryLoadFile ( directory , "runtimes/win-x64/native" , fileName )
| | TryLoadFile ( directory , "win-x64/native" , fileName )
| | TryLoadFile ( directory , "win-x64" , fileName ) )
{
return true ;
}
break ;
case Runtime . WindowsX86 :
if ( TryLoadFile ( directory , "x86" , fileName )
| | TryLoadFile ( directory , "runtimes/win-x86/native" , fileName )
| | TryLoadFile ( directory , "win-x86/native" , fileName )
| | TryLoadFile ( directory , "win-x86" , fileName ) )
{
return true ;
}
break ;
case Runtime . WindowsArm64 :
if ( TryLoadFile ( directory , "arm64" , fileName )
| | TryLoadFile ( directory , "runtimes/win-arm64/native" , fileName )
| | TryLoadFile ( directory , "win-arm64/native" , fileName )
| | TryLoadFile ( directory , "win-arm64" , fileName ) )
{
return true ;
}
break ;
case Runtime . WindowsArm :
if ( TryLoadFile ( directory , "arm" , fileName )
| | TryLoadFile ( directory , "runtimes/win-arm/native" , fileName )
| | TryLoadFile ( directory , "win-arm/native" , fileName )
| | TryLoadFile ( directory , "win-arm" , fileName ) )
{
return true ;
}
break ;
case Runtime . LinuxX64 :
if ( TryLoadFile ( directory , "x64" , fileName )
| | TryLoadFile ( directory , "runtimes/linux-x64/native" , fileName )
| | TryLoadFile ( directory , "linux-x64/native" , fileName )
| | TryLoadFile ( directory , "linux-x64" , fileName ) )
{
return true ;
}
break ;
case Runtime . LinuxX86 :
if ( TryLoadFile ( directory , "x86" , fileName )
| | TryLoadFile ( directory , "runtimes/linux-x86/native" , fileName )
| | TryLoadFile ( directory , "linux-x86/native" , fileName )
| | TryLoadFile ( directory , "linux-x86" , fileName ) )
{
return true ;
}
break ;
switch ( ProcArchitecture )
{
case ProcArchitecture . X64 :
return TryLoadFile ( directory , "runtimes/linux-x64/native" , fileName )
| | TryLoadFile ( directory , "linux-x64/native" , fileName )
| | TryLoadFile ( directory , "linux-x64" , fileName )
| | TryLoadFile ( directory , "x64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . X86 :
return TryLoadFile ( directory , "runtimes/linux-x86/native" , fileName )
| | TryLoadFile ( directory , "linux-x86/native" , fileName )
| | TryLoadFile ( directory , "linux-x86" , fileName )
| | TryLoadFile ( directory , "x86" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm64 :
return TryLoadFile ( directory , "runtimes/linux-arm64/native" , fileName )
| | TryLoadFile ( directory , "linux-arm64/native" , fileName )
| | TryLoadFile ( directory , "linux-arm64" , fileName )
| | TryLoadFile ( directory , "arm64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm :
return TryLoadFile ( directory , "runtimes/linux-arm/native" , fileName )
| | TryLoadFile ( directory , "linux-arm/native" , fileName )
| | TryLoadFile ( directory , "linux-arm" , fileName )
| | TryLoadFile ( directory , "arm" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
default :
return TryLoadFile ( directory , string . Empty , fileName ) ;
}
}
// Otherwise try to load directly from the provided directory
return TryLoadFile ( directory , string . Empty , fileName ) ;
if ( IsMac )
{
switch ( ProcArchitecture )
{
case ProcArchitecture . X64 :
return TryLoadFile ( directory , "runtimes/osx-x64/native" , fileName )
| | TryLoadFile ( directory , "osx-x64/native" , fileName )
| | TryLoadFile ( directory , "osx-x64" , fileName )
| | TryLoadFile ( directory , "x64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm64 :
return TryLoadFile ( directory , "runtimes/osx-arm64/native" , fileName )
| | TryLoadFile ( directory , "osx-arm64/native" , fileName )
| | TryLoadFile ( directory , "osx-arm64" , fileName )
| | TryLoadFile ( directory , "arm64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
default :
return TryLoadFile ( directory , string . Empty , fileName ) ;
}
}
switch ( ProcArchitecture )
{
case ProcArchitecture . X64 :
return TryLoadFile ( directory , "x64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . X86 :
return TryLoadFile ( directory , "x86" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm64 :
return TryLoadFile ( directory , "arm64" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
case ProcArchitecture . Arm :
return TryLoadFile ( directory , "arm" , fileName )
| | TryLoadFile ( directory , string . Empty , fileName ) ;
default :
return TryLoadFile ( directory , string . Empty , fileName ) ;
}
}
/// <summary>
@ -302,7 +344,7 @@ namespace MathNet.Numerics.Providers.Common
const int RTLD_NOW = 2 ;
[DllImport("lib dl", SetLastError = true)]
[DllImport("dl", SetLastError = true)]
static extern IntPtr dlopen ( String fileName , int flags ) ;
}
#endif