Skip to content

Instantly share code, notes, and snippets.

@clarvalon
Created September 24, 2019 23:06
Show Gist options
  • Save clarvalon/1b11a43e0e002cd7c6bae5df14f4782b to your computer and use it in GitHub Desktop.
Save clarvalon/1b11a43e0e002cd7c6bae5df14f4782b to your computer and use it in GitHub Desktop.
FNA Net Core 3 using NativeLibrary (proof of concept v2)
// in Program.cs
// Get FNA Assembly
var fnaAssembly = Assembly.GetAssembly(typeof(Microsoft.Xna.Framework.Graphics.ColorWriteChannels));
// Register mechanism for determining native libraries based on NativeLibrary instead of DllImport
DllMap.Register(fnaAssembly);
// in DllMap.cs
using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml.Linq;
public static class DllMap
{
// Register a call-back for native library resolution.
public static void Register(Assembly assembly)
{
NativeLibrary.SetDllImportResolver(assembly, MapAndLoad);
}
// The callback: which loads the mapped libray in place of the original
private static IntPtr MapAndLoad(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)
{
string mappedName = null;
mappedName = MapLibraryName(assembly.Location, libraryName, out mappedName) ? mappedName : libraryName;
return NativeLibrary.Load(mappedName, assembly, dllImportSearchPath);
}
// Parse the assembly.xml file, and map the old name to the new name of a library.
private static bool MapLibraryName(string assemblyLocation, string originalLibName, out string mappedLibName)
{
// TODO: Cache xml results to prevent costly loads? Store os and cpu also
// TODO: Remove Console.Writeline use
string os = GetCurrentPlatform().ToString().ToLowerInvariant();
string cpu = GetCurrentRuntimeArchitecture().ToString().ToLowerInvariant();
string xmlPath = Path.Combine(Path.GetDirectoryName(assemblyLocation),
Path.GetFileNameWithoutExtension(assemblyLocation) + ".dll.config");
mappedLibName = null;
if (!File.Exists(xmlPath))
{
Console.WriteLine($"=== Cannot find XML");
return false;
}
XElement root = XElement.Load(xmlPath);
var map =
(from el in root.Elements("dllmap")
where (string)el.Attribute("dll") == originalLibName
&& el.Attribute("os").ToString().IndexOf(os) >= 0
&& (el.Attribute("cpu") == null || string.IsNullOrEmpty(cpu) || el.Attribute("cpu").ToString().IndexOf("cpu") >= 0)
select el).SingleOrDefault();
if (map != null)
mappedLibName = map.Attribute("target").Value;
Console.WriteLine($"=== OS={os}, CPU={cpu}, Original={originalLibName}, Mapped={mappedLibName}");
return (mappedLibName != null);
}
// Below pinched from Mono.DllMap project: https://github.com/Firwood-Software/AdvancedDLSupport/tree/1b7394211a655b2f77649ce3b610a3161215cbdc/Mono.DllMap
public static DllMapOS GetCurrentPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return DllMapOS.Linux;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return DllMapOS.Windows;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return DllMapOS.OSX;
}
var operatingDesc = RuntimeInformation.OSDescription.ToUpperInvariant();
foreach (var system in Enum.GetValues(typeof(DllMapOS)).Cast<DllMapOS>()
.Except(new[] { DllMapOS.Linux, DllMapOS.Windows, DllMapOS.OSX }))
{
if (operatingDesc.Contains(system.ToString().ToUpperInvariant()))
{
return system;
}
}
throw new PlatformNotSupportedException($"Couldn't detect platform: {RuntimeInformation.OSDescription}");
}
public static DllMapArchitecture GetCurrentRuntimeArchitecture()
{
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm:
{
return DllMapArchitecture.ARM;
}
case Architecture.X64:
{
return DllMapArchitecture.x86_64;
}
case Architecture.X86:
{
return DllMapArchitecture.x86;
}
}
typeof(object).Module.GetPEKind(out _, out var machine);
switch (machine)
{
case ImageFileMachine.I386:
{
return DllMapArchitecture.x86;
}
case ImageFileMachine.AMD64:
{
return DllMapArchitecture.x86_64;
}
case ImageFileMachine.ARM:
{
return DllMapArchitecture.ARM;
}
case ImageFileMachine.IA64:
{
return DllMapArchitecture.IA64;
}
}
throw new PlatformNotSupportedException("Couldn't detect the current architecture.");
}
public enum DllMapOS
{
Linux = 1 << 0,
OSX = 1 << 1,
Solaris = 1 << 2,
FreeBSD = 1 << 3,
OpenBSD = 1 << 4,
NetBSD = 1 << 5,
Windows = 1 << 6,
AIX = 1 << 7,
HPUX = 1 << 8
}
public enum DllMapArchitecture
{
x86 = 1 << 0,
x86_64 = 1 << 1,
SPARC = 1 << 2,
PPC = 1 << 3,
S390 = 1 << 4,
S390X = 1 << 5,
ARM = 1 << 6,
ARMV8 = 1 << 7,
MIPS = 1 << 8,
Alpha = 1 << 9,
HPPA = 1 << 10,
IA64 = 1 << 11
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment