Skip to content

Commit 2864607

Browse files
committed
Update lib loader
1 parent a86021c commit 2864607

File tree

1 file changed

+182
-77
lines changed

1 file changed

+182
-77
lines changed

HexaGen.Runtime/LibraryLoader.cs

Lines changed: 182 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,102 @@
1010

1111
public static class LibraryLoader
1212
{
13-
public static nint LoadLibrary()
13+
public static OSPlatform FreeBSD { get; } = OSPlatform.Create("FREEBSD");
14+
15+
public static OSPlatform Linux { get; } = OSPlatform.Create("LINUX");
16+
17+
public static OSPlatform OSX { get; } = OSPlatform.Create("OSX");
18+
19+
public static OSPlatform Windows { get; } = OSPlatform.Create("WINDOWS");
20+
21+
public static OSPlatform Android { get; } = OSPlatform.Create("ANDROID");
22+
23+
public static OSPlatform IOS { get; } = OSPlatform.Create("IOS");
24+
25+
public static OSPlatform Tizen { get; } = OSPlatform.Create("TIZEN");
26+
27+
public static OSPlatform ChromeOS { get; } = OSPlatform.Create("CHROMEOS");
28+
29+
public static OSPlatform WebAssembly { get; } = OSPlatform.Create("WEBASSEMBLY");
30+
31+
public static OSPlatform Solaris { get; } = OSPlatform.Create("SOLARIS");
32+
33+
public static OSPlatform WatchOS { get; } = OSPlatform.Create("WATCHOS");
34+
35+
public static OSPlatform TVOS { get; } = OSPlatform.Create("TVOS");
36+
37+
public static string GetExtension(IEnumerable<NativeLibraryExtensionAttribute> extensionAttributes)
1438
{
15-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
39+
foreach (var extensionAttribute in extensionAttributes)
1640
{
17-
return LoadLocalLibrary("bgfx");
41+
if (RuntimeInformation.IsOSPlatform(extensionAttribute.TargetPlatform))
42+
{
43+
return extensionAttribute.Extension;
44+
}
1845
}
19-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
46+
47+
// Default extension based on platform
48+
if (RuntimeInformation.IsOSPlatform(Windows))
2049
{
21-
return LoadLocalLibrary("bgfx");
50+
return ".dll";
2251
}
23-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
52+
else if (RuntimeInformation.IsOSPlatform(OSX))
2453
{
25-
return LoadLocalLibrary("bgfx");
54+
return ".dylib";
2655
}
27-
else
56+
else if (RuntimeInformation.IsOSPlatform(Linux))
2857
{
29-
return LoadLocalLibrary("bgfx");
58+
return ".so";
3059
}
31-
}
32-
33-
public static string GetExtension()
34-
{
35-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
60+
else if (RuntimeInformation.IsOSPlatform(Android))
3661
{
37-
return ".dll";
62+
return ".so";
3863
}
39-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
64+
else if (RuntimeInformation.IsOSPlatform(IOS))
4065
{
41-
return ".dylib";
66+
return ".dylib"; // iOS also uses .dylib for dynamic libraries
4267
}
43-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
68+
else if (RuntimeInformation.IsOSPlatform(FreeBSD))
69+
{
70+
return ".so";
71+
}
72+
else if (RuntimeInformation.IsOSPlatform(TVOS))
73+
{
74+
return ".dylib"; // tvOS uses the same dynamic library extension as iOS
75+
}
76+
else if (RuntimeInformation.IsOSPlatform(WatchOS))
77+
{
78+
return ".dylib"; // watchOS also uses .dylib
79+
}
80+
else if (RuntimeInformation.IsOSPlatform(Solaris))
81+
{
82+
return ".so";
83+
}
84+
else if (RuntimeInformation.IsOSPlatform(WebAssembly))
85+
{
86+
return ".wasm";
87+
}
88+
else if (RuntimeInformation.IsOSPlatform(Tizen))
89+
{
90+
return ".so";
91+
}
92+
else if (RuntimeInformation.IsOSPlatform(ChromeOS))
4493
{
4594
return ".so";
4695
}
4796

97+
// Default to .so if no platform matches
4898
return ".so";
4999
}
50100

51-
public static nint LoadLocalLibrary(string libraryName)
101+
public static nint LoadLibrary()
52102
{
53-
var extension = GetExtension();
103+
var libraryAttributes = Assembly.GetCallingAssembly().GetCustomAttributes<NativeLibraryAttribute>();
104+
var extensionAttributes = Assembly.GetCallingAssembly().GetCustomAttributes<NativeLibraryExtensionAttribute>();
105+
106+
var libraryName = GetLibraryName(libraryAttributes);
107+
108+
var extension = GetExtension(extensionAttributes);
54109

55110
if (!libraryName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
56111
{
@@ -59,74 +114,133 @@ public static nint LoadLocalLibrary(string libraryName)
59114

60115
var osPlatform = GetOSPlatform();
61116
var architecture = GetArchitecture();
62-
63117
var libraryPath = GetNativeAssemblyPath(osPlatform, architecture, libraryName);
64118

65-
static string GetOSPlatform()
66-
{
67-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
68-
{
69-
return "win";
70-
}
71-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
72-
{
73-
return "linux";
74-
}
75-
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
76-
{
77-
return "osx";
78-
}
119+
nint handle;
79120

80-
throw new ArgumentException("Unsupported OS platform.");
81-
}
121+
handle = NativeLibrary.Load(libraryPath);
82122

83-
static string GetArchitecture()
123+
if (handle == IntPtr.Zero)
84124
{
85-
return RuntimeInformation.ProcessArchitecture switch
86-
{
87-
Architecture.X86 => "x86",
88-
Architecture.X64 => "x64",
89-
Architecture.Arm => "arm",
90-
Architecture.Arm64 => "arm64",
91-
_ => throw new ArgumentException("Unsupported architecture."),
92-
};
125+
throw new DllNotFoundException($"Unable to load library '{libraryName}'.");
93126
}
94127

95-
var attribute = Assembly.GetCallingAssembly().GetCustomAttribute<NativeLibraryAttribute>();
96-
var methods = typeof(string).GetMethods();
128+
return handle;
129+
}
97130

98-
static string GetNativeAssemblyPath(string osPlatform, string architecture, string libraryName)
99-
{
100-
var assemblyLocation = AppContext.BaseDirectory;
131+
private static string GetNativeAssemblyPath(string osPlatform, string architecture, string libraryName)
132+
{
133+
var assemblyLocation = AppContext.BaseDirectory;
101134

102-
var paths = new[]
103-
{
135+
var paths = new[]
136+
{
104137
Path.Combine(assemblyLocation, libraryName),
105138
Path.Combine(assemblyLocation, "runtimes", osPlatform, "native", libraryName),
139+
Path.Combine(assemblyLocation, "runtimes", $"{osPlatform}-{architecture}", "debug", libraryName), // allows debug builds sideload.
106140
Path.Combine(assemblyLocation, "runtimes", $"{osPlatform}-{architecture}", "native", libraryName),
107141
};
108142

109-
foreach (var path in paths)
143+
foreach (var path in paths)
144+
{
145+
if (File.Exists(path))
110146
{
111-
if (File.Exists(path))
112-
{
113-
return path;
114-
}
147+
return path;
115148
}
149+
}
116150

117-
return libraryName;
151+
return libraryName;
152+
}
153+
154+
private static string GetArchitecture()
155+
{
156+
return RuntimeInformation.ProcessArchitecture switch
157+
{
158+
Architecture.X86 => "x86",
159+
Architecture.X64 => "x64",
160+
Architecture.Arm => "arm",
161+
Architecture.Arm64 => "arm64",
162+
_ => throw new ArgumentException("Unsupported architecture."),
163+
};
164+
}
165+
166+
private static string GetOSPlatform()
167+
{
168+
if (RuntimeInformation.IsOSPlatform(Windows))
169+
{
170+
return "win";
171+
}
172+
else if (RuntimeInformation.IsOSPlatform(Linux))
173+
{
174+
return "linux";
175+
}
176+
else if (RuntimeInformation.IsOSPlatform(OSX))
177+
{
178+
return "osx";
179+
}
180+
else if (RuntimeInformation.IsOSPlatform(Android))
181+
{
182+
return "android";
183+
}
184+
else if (RuntimeInformation.IsOSPlatform(IOS))
185+
{
186+
return "ios";
187+
}
188+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD")))
189+
{
190+
return "freebsd";
191+
}
192+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")))
193+
{
194+
return "tvos";
195+
}
196+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("WATCHOS")))
197+
{
198+
return "watchos";
199+
}
200+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("SOLARIS")))
201+
{
202+
return "solaris";
203+
}
204+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY")))
205+
{
206+
return "webassembly";
207+
}
208+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("TIZEN")))
209+
{
210+
return "tizen";
211+
}
212+
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("CHROMEOS")))
213+
{
214+
return "chromeos";
118215
}
119216

120-
nint handle;
217+
throw new ArgumentException("Unsupported OS platform.");
218+
}
121219

122-
handle = NativeLibrary.Load(libraryPath);
220+
private static string GetLibraryName(IEnumerable<NativeLibraryAttribute> nativeLibraries)
221+
{
222+
NativeLibraryAttribute? nativeLibrary = null;
223+
foreach (NativeLibraryAttribute attri in nativeLibraries)
224+
{
225+
if (attri.TargetPlatform == null)
226+
{
227+
nativeLibrary = attri; // Default
228+
continue;
229+
}
123230

124-
if (handle == IntPtr.Zero)
231+
if (RuntimeInformation.IsOSPlatform(attri.TargetPlatform.Value))
232+
{
233+
nativeLibrary = attri;
234+
break;
235+
}
236+
}
237+
238+
if (nativeLibrary == null)
125239
{
126-
throw new DllNotFoundException($"Unable to load library '{libraryName}'.");
240+
throw new Exception("Dll not specified for this platform");
127241
}
128242

129-
return handle;
243+
return nativeLibrary.LibraryName;
130244
}
131245
}
132246

@@ -136,7 +250,6 @@ public sealed class NativeLibraryExtensionAttribute : Attribute
136250
private readonly string extension;
137251
private readonly OSPlatform targetPlatform;
138252

139-
140253
public NativeLibraryExtensionAttribute(string extension, OSPlatform targetPlatform)
141254
{
142255
this.extension = extension;
@@ -152,24 +265,16 @@ public NativeLibraryExtensionAttribute(string extension, OSPlatform targetPlatfo
152265
public sealed class NativeLibraryAttribute : Attribute
153266
{
154267
private readonly string libraryName;
155-
private readonly OSPlatform targetPlatform;
268+
private readonly OSPlatform? targetPlatform;
156269

157-
public NativeLibraryAttribute(string libraryName, OSPlatform targetPlatform)
270+
public NativeLibraryAttribute(string libraryName, OSPlatform? targetPlatform = null)
158271
{
159272
this.libraryName = libraryName;
160-
this.TargetPlatform = targetPlatform;
273+
this.targetPlatform = targetPlatform;
161274
}
162275

163276
public string LibraryName => libraryName;
164277

165-
public OSPlatform TargetPlatform => targetPlatform;
166-
}
167-
168-
public enum TargetPlatform
169-
{
170-
Windows,
171-
Linux,
172-
OSX,
173-
Android,
278+
public OSPlatform? TargetPlatform => targetPlatform;
174279
}
175280
}

0 commit comments

Comments
 (0)