1 // 2 // Copyright (c) 2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections; 9 using System.IO; 10 using System.Linq; 11 using System.Reflection; 12 using System.Runtime.InteropServices; 13 using System.Xml.Linq; 14 15 namespace Antmicro.Renode.UI 16 { 17 public static class DllMap 18 { 19 // Register a call-back for native library resolution. Register(Assembly assembly)20 public static void Register(Assembly assembly) 21 { 22 NativeLibrary.SetDllImportResolver(assembly, MapAndLoad); 23 } 24 25 // The callback which loads the mapped libray in place of the original. MapAndLoad(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)26 private static IntPtr MapAndLoad(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath) 27 { 28 var wasMapped = MapLibraryName(assembly.Location, libraryName, out var mappedName); 29 if(!wasMapped) 30 { 31 mappedName = libraryName; 32 } 33 // First try loading the library normally, then retry falling back to libraries from homebrew, which 34 // are installed to /opt/homebrew/lib on macOS/ARM64, which is not on the dyld search path. 35 if(NativeLibrary.TryLoad(mappedName, assembly, dllImportSearchPath, out var handle)) 36 { 37 return handle; 38 } 39 return NativeLibrary.Load(Path.Combine("/opt/homebrew/lib", mappedName), assembly, dllImportSearchPath); 40 } 41 42 // Parse the dll.config file and map the old name to the new name of a library. MapLibraryName(string assemblyLocation, string originalLibName, out string mappedLibName)43 private static bool MapLibraryName(string assemblyLocation, string originalLibName, out string mappedLibName) 44 { 45 string xmlPath = Path.Combine(Path.GetDirectoryName(assemblyLocation), Path.GetFileNameWithoutExtension(assemblyLocation) + ".dll.config"); 46 mappedLibName = null; 47 48 if (!File.Exists(xmlPath)) 49 { 50 return false; 51 } 52 53 var currOsAttr = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx" : 54 RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "windows" : 55 RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" : null; 56 57 XElement root = XElement.Load(xmlPath); 58 var map = ( 59 from el in root.Elements("dllmap") 60 where (string)el.Attribute("dll") == originalLibName 61 let osAttr = (string)el.Attribute("os") 62 where (osAttr == null || osAttr == currOsAttr || (osAttr.StartsWith("!") && !osAttr.Contains(currOsAttr))) 63 select el 64 ).SingleOrDefault(); 65 66 if (map != null) 67 { 68 mappedLibName = map.Attribute("target").Value; 69 } 70 71 return (mappedLibName != null); 72 } 73 } 74 }