Skip to content

Commit adb0344

Browse files
committed
Better support for function tables and multi step generation.
1 parent bfc609d commit adb0344

13 files changed

+187
-263
lines changed

Hexa.NET.ImGui/Generated/Functions.VT.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ namespace Hexa.NET.ImGui
1717
{
1818
public unsafe partial class ImGui
1919
{
20-
internal static VTable vt;
20+
internal static FunctionTable vt;
2121

2222
public static void InitApi()
2323
{
24-
vt = new VTable(LibraryLoader.LoadLibrary(), 1420);
24+
vt = new FunctionTable(LibraryLoader.LoadLibrary(), 1420);
2525
vt.Load(0, "ImVec2_ImVec2_Nil");
2626
vt.Load(1, "ImVec2_destroy");
2727
vt.Load(2, "ImVec2_ImVec2_Float");

HexaGen.Runtime/VTable.cs renamed to HexaGen.Runtime/FunctionTable.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22
{
33
using System.Runtime.InteropServices;
44

5-
public unsafe class VTable : IDisposable
5+
public unsafe class FunctionTable : IDisposable
66
{
77
private nint library;
88
private void** _vtable;
99
private int length;
1010

11-
public VTable(void** vtable, int length)
11+
public FunctionTable(void** vtable, int length)
1212
{
1313
_vtable = vtable;
1414
this.length = length;
1515
}
1616

17-
public VTable(nint library, int length)
17+
public FunctionTable(nint library, int length)
1818
{
1919
_vtable = (void**)Marshal.AllocHGlobal(length * sizeof(void*));
2020
new Span<nint>(_vtable, length).Clear(); // Fill with null pointers
2121
this.library = library;
2222
this.length = length;
2323
}
2424

25-
public VTable(string libraryPath, int length)
25+
public FunctionTable(string libraryPath, int length)
2626
{
2727
library = NativeLibrary.Load(libraryPath);
2828
_vtable = (void**)Marshal.AllocHGlobal(length * sizeof(void*));

HexaGen.Runtime/HexaGen.Runtime.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<RepositoryUrl>https://github.com/JunaMeinhold/HexaGen</RepositoryUrl>
1212

1313
<AssemblyVersion>1.1.0</AssemblyVersion>
14-
<PackageVersion>1.1.9</PackageVersion>
14+
<PackageVersion>1.1.10</PackageVersion>
1515
<Description>The C Runtime for all C Wrappers generated with the HexaGen Code Generator.</Description>
1616
<Authors>Juna Meinhold</Authors>
1717
<PackageProjectUrl>https://github.com/JunaMeinhold/HexaGen</PackageProjectUrl>

HexaGen.Runtime/LibraryLoader.cs

Lines changed: 2 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,6 @@ public enum TargetPlatform
3030
Any = FreeBSD | Linux | OSX | Windows | Android | IOS | Tizen | ChromeOS | WebAssembly | Solaris | WatchOS | TVO
3131
}
3232

33-
public struct LibraryName
34-
{
35-
public string Name;
36-
public TargetPlatform TargetPlatform;
37-
}
38-
39-
public struct LibraryExtension
40-
{
41-
public string Extension;
42-
public TargetPlatform TargetPlatform;
43-
}
44-
45-
public struct LibraryLoaderHints
46-
{
47-
public LibraryName[] Names;
48-
public LibraryExtension[] Extensions;
49-
public string[] Paths;
50-
51-
public LibraryLoaderHints(LibraryName[] names, LibraryExtension[] extensions, string[] paths)
52-
{
53-
Names = names;
54-
Extensions = extensions;
55-
Paths = paths;
56-
}
57-
58-
public LibraryLoaderHints(LibraryName[] names, LibraryExtension[] extensions)
59-
{
60-
Names = names;
61-
Extensions = extensions;
62-
Paths = [];
63-
}
64-
}
65-
6633
public static class LibraryLoader
6734
{
6835
public static OSPlatform FreeBSD { get; } = OSPlatform.Create("FREEBSD");
@@ -89,16 +56,8 @@ public static class LibraryLoader
8956

9057
public static OSPlatform TVOS { get; } = OSPlatform.Create("TVOS");
9158

92-
public static string GetExtension(IEnumerable<NativeLibraryExtensionAttribute> extensionAttributes)
59+
public static string GetExtension()
9360
{
94-
foreach (var extensionAttribute in extensionAttributes)
95-
{
96-
if (RuntimeInformation.IsOSPlatform(extensionAttribute.TargetPlatform.Convert()))
97-
{
98-
return extensionAttribute.Extension;
99-
}
100-
}
101-
10261
// Default extension based on platform
10362
if (RuntimeInformation.IsOSPlatform(Windows))
10463
{
@@ -153,36 +112,6 @@ public static string GetExtension(IEnumerable<NativeLibraryExtensionAttribute> e
153112
return ".so";
154113
}
155114

156-
public static nint LoadLibrary()
157-
{
158-
var libraryAttributes = Assembly.GetCallingAssembly().GetCustomAttributes<NativeLibraryAttribute>();
159-
var extensionAttributes = Assembly.GetCallingAssembly().GetCustomAttributes<NativeLibraryExtensionAttribute>();
160-
161-
var libraryName = GetLibraryName(libraryAttributes);
162-
163-
var extension = GetExtension(extensionAttributes);
164-
165-
if (!libraryName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
166-
{
167-
libraryName += extension;
168-
}
169-
170-
var osPlatform = GetOSPlatform();
171-
var architecture = GetArchitecture();
172-
var libraryPath = GetNativeAssemblyPath(osPlatform, architecture, libraryName);
173-
174-
nint handle;
175-
176-
handle = NativeLibrary.Load(libraryPath);
177-
178-
if (handle == IntPtr.Zero)
179-
{
180-
throw new DllNotFoundException($"Unable to load library '{libraryName}'.");
181-
}
182-
183-
return handle;
184-
}
185-
186115
public delegate string LibraryNameCallback();
187116

188117
public delegate string LibraryExtensionCallback();
@@ -191,7 +120,7 @@ public static nint LoadLibrary(LibraryNameCallback libraryNameCallback, LibraryE
191120
{
192121
var libraryName = libraryNameCallback();
193122

194-
var extension = libraryExtensionCallback != null ? libraryExtensionCallback() : GetExtension([]);
123+
var extension = libraryExtensionCallback != null ? libraryExtensionCallback() : GetExtension();
195124

196125
if (!libraryName.EndsWith(extension, StringComparison.OrdinalIgnoreCase))
197126
{
@@ -311,110 +240,5 @@ private static string GetOSPlatform()
311240

312241
throw new ArgumentException("Unsupported OS platform.");
313242
}
314-
315-
private static string GetLibraryName(IEnumerable<NativeLibraryAttribute> nativeLibraries)
316-
{
317-
NativeLibraryAttribute? nativeLibrary = null;
318-
foreach (NativeLibraryAttribute attri in nativeLibraries)
319-
{
320-
if (attri.TargetPlatform == TargetPlatform.Any)
321-
{
322-
nativeLibrary = attri; // Default
323-
continue;
324-
}
325-
326-
if (RuntimeInformation.IsOSPlatform(attri.TargetPlatform.Convert()))
327-
{
328-
nativeLibrary = attri;
329-
break;
330-
}
331-
}
332-
333-
if (nativeLibrary == null)
334-
{
335-
throw new Exception("Dll not specified for this platform");
336-
}
337-
338-
return nativeLibrary.LibraryName;
339-
}
340-
341-
private static OSPlatform Convert(this TargetPlatform targetPlatform)
342-
{
343-
switch (targetPlatform)
344-
{
345-
case TargetPlatform.FreeBSD:
346-
return FreeBSD;
347-
348-
case TargetPlatform.Linux:
349-
return Linux;
350-
351-
case TargetPlatform.OSX:
352-
return OSX;
353-
354-
case TargetPlatform.Windows:
355-
return Windows;
356-
357-
case TargetPlatform.Android:
358-
return Android;
359-
360-
case TargetPlatform.IOS:
361-
return IOS;
362-
363-
case TargetPlatform.Tizen:
364-
return Tizen;
365-
366-
case TargetPlatform.ChromeOS:
367-
return ChromeOS;
368-
369-
case TargetPlatform.WebAssembly:
370-
return WebAssembly;
371-
372-
case TargetPlatform.Solaris:
373-
return Solaris;
374-
375-
case TargetPlatform.WatchOS:
376-
return WatchOS;
377-
378-
case TargetPlatform.TVO:
379-
return TVOS;
380-
381-
default:
382-
throw new PlatformNotSupportedException();
383-
}
384-
}
385-
}
386-
387-
[System.AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = true)]
388-
public sealed class NativeLibraryExtensionAttribute : Attribute
389-
{
390-
private readonly string extension;
391-
private readonly TargetPlatform targetPlatform;
392-
393-
public NativeLibraryExtensionAttribute(string extension, TargetPlatform targetPlatform = TargetPlatform.Any)
394-
{
395-
this.extension = extension;
396-
this.targetPlatform = targetPlatform;
397-
}
398-
399-
public string Extension => extension;
400-
401-
public TargetPlatform TargetPlatform => targetPlatform;
402-
}
403-
404-
[System.AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = true)]
405-
public sealed class NativeLibraryAttribute : Attribute
406-
{
407-
private readonly string libraryName;
408-
private readonly TargetPlatform targetPlatform;
409-
410-
public NativeLibraryAttribute(string libraryName, TargetPlatform targetPlatform = TargetPlatform.Any)
411-
{
412-
this.libraryName = libraryName;
413-
this.targetPlatform = targetPlatform;
414-
}
415-
416-
public string LibraryName => libraryName;
417-
418-
public TargetPlatform TargetPlatform => targetPlatform;
419243
}
420244
}

HexaGen/CsCodeGenerator.Functions.cs

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ public partial class CsCodeGenerator
2323
public readonly HashSet<string> DefinedFunctions = new();
2424
protected readonly HashSet<string> DefinedVariationsFunctions = new();
2525
protected readonly HashSet<string> OutReturnFunctions = new();
26-
27-
public int VTableLength { get; private set; }
26+
public readonly FunctionTableBuilder FunctionTableBuilder = new();
2827

2928
protected virtual List<string> SetupFunctionUsings()
3029
{
@@ -111,10 +110,10 @@ protected virtual void GenerateFunctions(CppCompilation compilation, string outp
111110
using var writer = new CsSplitCodeWriter(filePath, config.Namespace, SetupFunctionUsings(), config.HeaderInjector);
112111
GenContext context = new(compilation, filePath, writer);
113112

114-
VTableBuilder vTableBuilder = new(config.VTableStart);
113+
FunctionTableBuilder.Append(config.FunctionTableEntries);
115114
using (writer.PushBlock($"public unsafe partial class {config.ApiName}"))
116115
{
117-
if (!config.UseVTable)
116+
if (!config.UseFunctionTable)
118117
{
119118
writer.WriteLine($"internal const string LibName = \"{config.LibName}\";\n");
120119
}
@@ -167,8 +166,9 @@ protected virtual void GenerateFunctions(CppCompilation compilation, string outp
167166
modifiers = "internal static partial";
168167
break;
169168

170-
case ImportType.VTable:
169+
case ImportType.FunctionTable:
171170

171+
writer.WriteLine($"[MethodImpl(MethodImplOptions.AggressiveInlining)]");
172172
if (boolReturn)
173173
{
174174
writer.BeginBlock($"internal static {config.GetBoolType()} {csName}Native({argumentsString})");
@@ -201,15 +201,15 @@ protected virtual void GenerateFunctions(CppCompilation compilation, string outp
201201
// isolates the argument names
202202
string argumentNames = config.WriteFunctionMarshalling(cppFunction.Parameters);
203203

204-
int vTableIndex = vTableBuilder.Add(cppFunction.Name);
204+
int funcTableableIndex = FunctionTableBuilder.Add(cppFunction.Name);
205205

206206
if (returnCsName == "void")
207207
{
208-
writer.WriteLine($"(({delegateType})vt[{vTableIndex}])({argumentNames});");
208+
writer.WriteLine($"(({delegateType})funcTable[{funcTableableIndex}])({argumentNames});");
209209
}
210210
else
211211
{
212-
writer.WriteLine($"return (({delegateType})vt[{vTableIndex}])({argumentNames});");
212+
writer.WriteLine($"return (({delegateType})funcTable[{funcTableableIndex}])({argumentNames});");
213213
}
214214

215215
writer.WriteLine("#else");
@@ -237,11 +237,11 @@ protected virtual void GenerateFunctions(CppCompilation compilation, string outp
237237

238238
if (returnCsName == "void")
239239
{
240-
writer.WriteLine($"(({delegateTypeOld})vt[{vTableIndex}])({argumentNamesOld});");
240+
writer.WriteLine($"(({delegateTypeOld})funcTable[{funcTableableIndex}])({argumentNamesOld});");
241241
}
242242
else
243243
{
244-
writer.WriteLine($"return ({returnType})(({delegateTypeOld})vt[{vTableIndex}])({argumentNamesOld});");
244+
writer.WriteLine($"return ({returnType})(({delegateTypeOld})funcTable[{funcTableableIndex}])({argumentNamesOld});");
245245
}
246246

247247
writer.WriteLine("#endif");
@@ -272,28 +272,26 @@ protected virtual void GenerateFunctions(CppCompilation compilation, string outp
272272
}
273273
}
274274

275-
if (config.UseVTable)
275+
if (config.UseFunctionTable)
276276
{
277-
var initString = vTableBuilder.Finish(out var count);
278-
string filePathVT = Path.Combine(outputPath, "Functions.VT.cs");
279-
using var writerVt = new CsCodeWriter(filePathVT, config.Namespace, SetupFunctionUsings(), config.HeaderInjector);
280-
using (writerVt.PushBlock($"public unsafe partial class {config.ApiName}"))
277+
var initString = FunctionTableBuilder.Finish(out var count);
278+
string filePathfuncTable = Path.Combine(outputPath, "FunctionTable.cs");
279+
using var writerfuncTable = new CsCodeWriter(filePathfuncTable, config.Namespace, SetupFunctionUsings(), config.HeaderInjector);
280+
using (writerfuncTable.PushBlock($"public unsafe partial class {config.ApiName}"))
281281
{
282-
writerVt.WriteLine("internal static VTable vt;");
283-
writerVt.WriteLine();
284-
using (writerVt.PushBlock("public static void InitApi()"))
282+
writerfuncTable.WriteLine("internal static FunctionTable funcTable;");
283+
writerfuncTable.WriteLine();
284+
using (writerfuncTable.PushBlock("public static void InitApi()"))
285285
{
286-
writerVt.WriteLine($"vt = new VTable(LibraryLoader.LoadLibrary(), {count});");
287-
writerVt.WriteLines(initString);
286+
writerfuncTable.WriteLine($"funcTable = new FunctionTable(LibraryLoader.LoadLibrary({config.GetLibraryNameFunctionName}, {config.GetLibraryExtensionFunctionName ?? "null"}), {count});");
287+
writerfuncTable.WriteLines(initString);
288288
}
289-
writerVt.WriteLine();
290-
using (writerVt.PushBlock("public static void FreeApi()"))
289+
writerfuncTable.WriteLine();
290+
using (writerfuncTable.PushBlock("public static void FreeApi()"))
291291
{
292-
writerVt.WriteLine("vt.Free();");
292+
writerfuncTable.WriteLine("funcTable.Free();");
293293
}
294294
}
295-
296-
VTableLength = count;
297295
}
298296
}
299297

0 commit comments

Comments
 (0)