@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2016 Math.NET
// Copyright (c) 2009-202 1 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@ -35,8 +35,21 @@ using System.Runtime.InteropServices;
using System.Security ;
using System.Threading ;
// ReSharper disable InconsistentNaming
namespace MathNet.Numerics.Providers.MKL
{
internal enum Runtime
{
Unknown = 0 ,
WindowsX64 ,
WindowsX86 ,
WindowsArm64 ,
WindowsArm ,
LinuxX64 ,
LinuxX86 ,
}
/// <summary>
/// Helper class to load native libraries depending on the architecture of the OS and process.
/// </summary>
@ -44,12 +57,6 @@ namespace MathNet.Numerics.Providers.MKL
{
static readonly object StaticLock = new Object ( ) ;
const string X86 = "x86" ;
const string X64 = "x64" ;
const string IA64 = "ia64" ;
const string ARM = "arm" ;
const string ARM64 = "arm64" ;
/// <summary>
/// Dictionary of handles to previously loaded libraries,
/// </summary>
@ -58,7 +65,7 @@ namespace MathNet.Numerics.Providers.MKL
/// <summary>
/// Gets a string indicating the architecture and bitness of the current process.
/// </summary>
static readonly Lazy < string > Architectur eKey = new Lazy < string > ( EvaluateArchitectureKey , LazyThreadSafetyMode . PublicationOnly ) ;
static readonly Lazy < Runtime > Runtim eKey = new Lazy < Runtime > ( EvaluateRuntime , LazyThreadSafetyMode . PublicationOnly ) ;
/// <summary>
/// If the last native library failed to load then gets the corresponding exception
@ -75,42 +82,35 @@ namespace MathNet.Numerics.Providers.MKL
}
}
static string EvaluateArchitectureKey ( )
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 ? X64 : X86 ;
return Environment . Is64BitProcess ? Runtime . LinuxX64 : Runtime . LinuxX86 ;
}
var architecture = Environment . GetEnvironmentVariable ( "PROCESSOR_ARCHITECTURE" ) ;
if ( string . Equals ( architecture , "x86" , StringComparison . OrdinalIgnoreCase ) )
{
return X86 ;
return Runtime . Windows X86;
}
if ( string . Equals ( architecture , "amd64" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( architecture , "x64" , StringComparison . OrdinalIgnoreCase ) )
{
return Environment . Is64BitProcess ? X64 : X86 ;
}
if ( string . Equals ( architecture , "ia64" , StringComparison . OrdinalIgnoreCase ) )
{
return IA64 ;
return Environment . Is64BitProcess ? Runtime . WindowsX64 : Runtime . WindowsX86 ;
}
if ( string . Equals ( architecture , "arm" , StringComparison . OrdinalIgnoreCase ) )
{
return Environment . Is64BitProcess ? ARM64 : ARM ;
return Environment . Is64BitProcess ? Runtime . WindowsArm64 : Runtime . WindowsArm ;
}
// Fallback if unknown
return architecture ;
return Runtime . Unknown ;
}
/// <summary>
@ -169,31 +169,77 @@ namespace MathNet.Numerics.Providers.MKL
directory = Path . GetFullPath ( directory ) ;
// If we have a know architecture, try the matching subdirectory first
var architecture = ArchitectureKey . Value ;
if ( ! string . IsNullOrEmpty ( architecture ) & & TryLoadFile ( new FileInfo ( Path . Combine ( Path . Combine ( directory , architecture ) , fileName ) ) ) )
switch ( RuntimeKey . Value )
{
return true ;
case Runtime . WindowsX64 :
if ( TryLoadFile ( directory , "x64" , 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 , "win-x86/native" , fileName )
| | TryLoadFile ( directory , "win-x86" , fileName ) )
{
return true ;
}
break ;
case Runtime . WindowsArm64 :
if ( TryLoadFile ( directory , "arm64" , 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 , "win-arm/native" , fileName )
| | TryLoadFile ( directory , "win-arm" , fileName ) )
{
return true ;
}
break ;
case Runtime . LinuxX64 :
if ( TryLoadFile ( directory , "x64" , 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 , "linux-x86/native" , fileName )
| | TryLoadFile ( directory , "linux-x86" , fileName ) )
{
return true ;
}
break ;
}
// Otherwise try to load directly from the provided directory
return TryLoadFile ( new FileInfo ( Path . Combine ( directory , fileName ) ) ) ;
return TryLoadFile ( directory , string . Empt y, fileName ) ;
}
/// <summary>
/// Try to load a native library by providing the full path including the file name of the library.
/// </summary>
/// <returns>True if the library was successfully loaded or if it has already been loaded.</returns>
static bool TryLoadFile ( FileInfo file )
static bool TryLoadFile ( string directory , string relativePath , string fileNam e)
{
lock ( StaticLock )
{
IntPtr libraryHandle ;
if ( NativeHandles . Value . TryGetValue ( file . Name , out libraryHandle ) )
if ( NativeHandles . Value . TryGetValue ( fileName , out IntPtr libraryHandle ) )
{
return true ;
}
if ( ! file . Exists )
var fullPath = Path . GetFullPath ( Path . Combine ( Path . Combine ( directory , relativePath ) , fileName ) ) ;
if ( ! File . Exists ( fullPath ) )
{
// If the library isn't found within an architecture specific folder then return false
// to allow normal P/Invoke searching behavior when the library is called
@ -201,7 +247,7 @@ namespace MathNet.Numerics.Providers.MKL
}
// If successful this will return a handle to the library
libraryHandle = IsUnix ? UnixLoader . LoadLibrary ( file . FullName ) : WindowsLoader . LoadLibrary ( file . FullName ) ;
libraryHandle = IsUnix ? UnixLoader . LoadLibrary ( fullPath ) : WindowsLoader . LoadLibrary ( fullPath ) ;
if ( libraryHandle = = IntPtr . Zero )
{
int lastError = Marshal . GetLastWin32Error ( ) ;
@ -211,7 +257,7 @@ namespace MathNet.Numerics.Providers.MKL
else
{
LastException = null ;
NativeHandles . Value [ file . Name ] = libraryHandle ;
NativeHandles . Value [ fileName ] = libraryHandle ;
}
return libraryHandle ! = IntPtr . Zero ;