diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000000..76a3dd65c9
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "silk.net.silktouch.dotnettool": {
+ "version": "3.0.0-preview",
+ "commands": [
+ "silktouch"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/Directory.Packages.props b/Directory.Packages.props
index ef75ce2282..6abca158b0 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -17,7 +17,7 @@
-
+
diff --git a/Silk.NET.sln b/Silk.NET.sln
index c7bff49285..b64a83616c 100644
--- a/Silk.NET.sln
+++ b/Silk.NET.sln
@@ -44,10 +44,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.Maths.Benchmarks",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SilkTouch.Scraper", "src\generators\Silk.NET.SilkTouch.Scraper\Silk.NET.SilkTouch.Scraper.csproj", "{EA623F04-DADA-4714-B2C5-44C82E211492}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SilkTouch", "src\generators\SilkTouch\SilkTouch.csproj", "{7DF67686-3F46-4569-935F-4A9E9903B575}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SilkTouch.Roslyn", "src\generators\Silk.NET.SilkTouch.Roslyn\Silk.NET.SilkTouch.Roslyn.csproj", "{11841F56-7603-40D9-BC06-10EBBE17D905}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SilkTouch.Emitter", "src\generators\Silk.NET.SilkTouch.Emitter\Silk.NET.SilkTouch.Emitter.csproj", "{50F26B27-32B6-4D66-ADD5-CC9C38373B19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.Core", "src\libraries\Silk.NET.Core\Silk.NET.Core.csproj", "{69CF4437-59F7-4304-9AE1-4B58E1A93367}"
@@ -78,6 +74,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SilkTouch.TypeReso
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SilkTouch.TypeResolution.Tests", "tests\Silk.NET.SilkTouch.TypeResolution.Tests\Silk.NET.SilkTouch.TypeResolution.Tests.csproj", "{89E8EDA4-EB19-45FC-AFA1-B6A16211A9EE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silk.NET.SilkTouch.DotnetTool", "src\generators\Silk.NET.SilkTouch.DotnetTool\Silk.NET.SilkTouch.DotnetTool.csproj", "{50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -124,30 +122,6 @@ Global
{EA623F04-DADA-4714-B2C5-44C82E211492}.Release|x64.Build.0 = Release|Any CPU
{EA623F04-DADA-4714-B2C5-44C82E211492}.Release|x86.ActiveCfg = Release|Any CPU
{EA623F04-DADA-4714-B2C5-44C82E211492}.Release|x86.Build.0 = Release|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Debug|x64.Build.0 = Debug|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Debug|x86.Build.0 = Debug|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Release|Any CPU.Build.0 = Release|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Release|x64.ActiveCfg = Release|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Release|x64.Build.0 = Release|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Release|x86.ActiveCfg = Release|Any CPU
- {7DF67686-3F46-4569-935F-4A9E9903B575}.Release|x86.Build.0 = Release|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Debug|x64.ActiveCfg = Debug|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Debug|x64.Build.0 = Debug|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Debug|x86.ActiveCfg = Debug|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Debug|x86.Build.0 = Debug|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Release|Any CPU.Build.0 = Release|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Release|x64.ActiveCfg = Release|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Release|x64.Build.0 = Release|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Release|x86.ActiveCfg = Release|Any CPU
- {11841F56-7603-40D9-BC06-10EBBE17D905}.Release|x86.Build.0 = Release|Any CPU
{50F26B27-32B6-4D66-ADD5-CC9C38373B19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50F26B27-32B6-4D66-ADD5-CC9C38373B19}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50F26B27-32B6-4D66-ADD5-CC9C38373B19}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -316,6 +290,18 @@ Global
{89E8EDA4-EB19-45FC-AFA1-B6A16211A9EE}.Release|x64.Build.0 = Release|Any CPU
{89E8EDA4-EB19-45FC-AFA1-B6A16211A9EE}.Release|x86.ActiveCfg = Release|Any CPU
{89E8EDA4-EB19-45FC-AFA1-B6A16211A9EE}.Release|x86.Build.0 = Release|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Debug|x64.Build.0 = Debug|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Debug|x86.Build.0 = Debug|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Release|x64.ActiveCfg = Release|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Release|x64.Build.0 = Release|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Release|x86.ActiveCfg = Release|Any CPU
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -330,8 +316,6 @@ Global
{8238D9F3-E158-4633-8017-B29AA3AD61F7} = {EA3CA547-452A-4D9E-BDB3-3BC5D7F15ACA}
{CB8B28DE-456A-4B8E-85A6-2C50CEE08CA2} = {FD15E196-1C63-47D6-8AD5-64F015120B4B}
{EA623F04-DADA-4714-B2C5-44C82E211492} = {8238D9F3-E158-4633-8017-B29AA3AD61F7}
- {7DF67686-3F46-4569-935F-4A9E9903B575} = {8238D9F3-E158-4633-8017-B29AA3AD61F7}
- {11841F56-7603-40D9-BC06-10EBBE17D905} = {8238D9F3-E158-4633-8017-B29AA3AD61F7}
{50F26B27-32B6-4D66-ADD5-CC9C38373B19} = {8238D9F3-E158-4633-8017-B29AA3AD61F7}
{69CF4437-59F7-4304-9AE1-4B58E1A93367} = {C9718C94-2F21-4E8D-B55D-8F0B1A131346}
{AF6E05E0-9C51-4D52-AC7E-056714CAC5F4} = {9020C7C6-C366-4BD3-8C8A-F81394EC7174}
@@ -346,6 +330,7 @@ Global
{381D1039-3259-488F-BB25-D90EE63A3E82} = {94D5D1E1-B998-4CB1-9D04-DA138A2B0F3C}
{7D181E77-CAD4-4288-AC0A-9C4D55ED1EC2} = {8238D9F3-E158-4633-8017-B29AA3AD61F7}
{89E8EDA4-EB19-45FC-AFA1-B6A16211A9EE} = {94D5D1E1-B998-4CB1-9D04-DA138A2B0F3C}
+ {50F2BCCC-BDC8-4694-B55E-583A6A77E1CF} = {8238D9F3-E158-4633-8017-B29AA3AD61F7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F5273D7F-3334-48DF-94E3-41AE6816CD4D}
diff --git a/src/generators/Silk.NET.SilkTouch.DotnetTool/Program.cs b/src/generators/Silk.NET.SilkTouch.DotnetTool/Program.cs
new file mode 100644
index 0000000000..22750c22b7
--- /dev/null
+++ b/src/generators/Silk.NET.SilkTouch.DotnetTool/Program.cs
@@ -0,0 +1,524 @@
+using System;
+using System.Collections.Generic;
+using System.CommandLine;
+using System.CommandLine.Invocation;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata.Ecma335;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using System.Xml;
+using ClangSharp;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Silk.NET.SilkTouch.Emitter;
+using Silk.NET.SilkTouch.Scraper;
+using Silk.NET.SilkTouch.Symbols;
+using Silk.NET.SilkTouch.TypeResolution;
+using Symbol=Silk.NET.SilkTouch.Symbols.Symbol;
+using Type=System.Type;
+
+namespace Silk.NET.SilkTouch.DotnetTool
+{
+ internal class Program
+ {
+ static async Task Main(string[] args)
+ {
+ var logLevel = new Option(new[] { "log-level", "l" }, () => LogLevel.Information);
+ var useStandardIncludes = new Option(new[] { "standard-includes", "si" }, () => true);
+ var extraIncludedDirectories = new Option
+ (new[] { "extra-included-directories", "exd" }, Array.Empty)
+ {
+ AllowMultipleArgumentsPerToken = true
+ };
+ var includedNames = new Option
+ (new[] { "included-names" }, Array.Empty)
+ {
+ AllowMultipleArgumentsPerToken = true
+ };
+ var excludedNames = new Option
+ (new[] { "excluded-names" }, Array.Empty)
+ {
+ AllowMultipleArgumentsPerToken = true
+ };
+ var definedMacros = new Option
+ (new[] { "defined-macros" }, Array.Empty)
+ {
+ AllowMultipleArgumentsPerToken = true
+ };
+ var headerFile = new Option(new[] { "header-file" })
+ {
+ IsRequired = true
+ };
+
+ var usedSymbolVisitors = new Option
+ (
+ new[] { "used-symbol-visitors", "vs" },
+ () => AvailableSymbolVisitors.AllTypeResolvers,
+ "The symbol visitors called to process the raw symbols into those used to emit C#." +
+ " Generally includes most type resolvers and overloaders as appropriate."
+ );
+
+ var xmlFile = new Option(new[] { "xml-file", "xf" }, "The File to read/write XML from/to");
+ var rawSymbolsFile = new Option
+ (new[] { "raw-symbols-file", "rsf" }, "The File to read/write Raw Symbols from/to");
+ var processedSymbolsFile = new Option
+ (new[] { "processed-symbols-file", "psf" }, "The File to read/write Processed Symbols from/to");
+ var csharpDir = new Option
+ (new[] { "csharp-directory", "csharp-dir", "csd" }, "The Directory to read/write C# files from/to");
+
+ var generateBindings = new Command("bindings")
+ {
+ logLevel,
+ xmlFile,
+ rawSymbolsFile,
+ processedSymbolsFile,
+ csharpDir,
+ extraIncludedDirectories,
+ includedNames,
+ excludedNames,
+ definedMacros,
+ headerFile,
+ usedSymbolVisitors
+ };
+ generateBindings.SetHandler
+ (
+
+ (async (context) =>
+ {
+ var serviceProvider = CreateServiceProvider(context.ParseResult.GetValueForOption(logLevel));
+ XmlDocument xmlDoc = GetXml
+ (
+ serviceProvider,
+ context.ParseResult.GetValueForOption(useStandardIncludes),
+ context.ParseResult.GetValueForOption(extraIncludedDirectories)!,
+ context.ParseResult.GetValueForOption(headerFile)!.FullName,
+ context.ParseResult.GetValueForOption(includedNames)!,
+ context.ParseResult.GetValueForOption(excludedNames)!,
+ context.ParseResult.GetValueForOption(definedMacros)!
+ );
+ var xmlFileRes = context.ParseResult.GetValueForOption(xmlFile);
+ if (xmlFileRes is not null)
+ {
+ if (xmlFileRes.Exists) xmlFileRes.Delete();
+ await using var stream = xmlFileRes.OpenWrite();
+ await using var writer = new XmlTextWriter(stream, Encoding.UTF8);
+ xmlDoc.WriteTo(writer);
+ }
+
+ var (rawSymbols, typeStore) = GetSymbols(serviceProvider, xmlDoc);
+ var rawSymbolsFileRes = context.ParseResult.GetValueForOption(rawSymbolsFile);
+ if (rawSymbolsFileRes is not null)
+ {
+ if (rawSymbolsFileRes.Exists) rawSymbolsFileRes.Delete();
+ await using var stream = rawSymbolsFileRes.OpenWrite();
+ await JsonSerializer.SerializeAsync(stream, rawSymbols, GetJsonOptions());
+ }
+
+ var processedSymbols = ProcessSymbols
+ (
+ serviceProvider,
+ rawSymbols,
+ typeStore,
+ context.ParseResult.GetValueForOption(usedSymbolVisitors)
+ );
+ var processedSymbolsFileRes = context.ParseResult.GetValueForOption(processedSymbolsFile);
+ if (processedSymbolsFileRes is not null)
+ {
+ if (processedSymbolsFileRes.Exists) processedSymbolsFileRes.Delete();
+ await using var stream = processedSymbolsFileRes.OpenWrite();
+ await JsonSerializer.SerializeAsync(stream, processedSymbols, GetJsonOptions());
+ }
+
+ var csharp = GetCSharp(serviceProvider, processedSymbols, typeStore).Select(x => x.ToFullString())
+ .Select((x, i) => (x, i.ToString() + ".cs"));
+ var csharpDirRes = context.ParseResult.GetValueForOption(csharpDir);
+ if (csharpDirRes is not null)
+ {
+ foreach (var (contents, fileName) in csharp)
+ {
+ var path = Path.Combine(csharpDirRes.FullName, fileName);
+ await File.WriteAllTextAsync(path, contents);
+ }
+ }
+ })
+ );
+
+ var generateCSharp = new Command("csharp")
+ {
+ processedSymbolsFile, csharpDir, logLevel
+ };
+ generateCSharp.SetHandler
+ (
+ (async static (processedSymbolsFile, csharpDir, logLevel) =>
+ {
+ var serviceProvider = CreateServiceProvider(logLevel);
+ Symbol[] symbols;
+ TypeStore typeStore;
+ if (processedSymbolsFile is null)
+ {
+ symbols = Array.Empty();
+ typeStore = new TypeStore();
+ }
+ else
+ {
+ var logger = serviceProvider.GetRequiredService>();
+ logger.LogInformation("Loading Symbols from File...");
+ await using var stream = processedSymbolsFile.OpenRead();
+ symbols = await JsonSerializer.DeserializeAsync(stream, GetJsonOptions()) ?? Array.Empty();
+ logger.LogInformation("Loaded {count} Symbols from Disk. Restoring Type Store...", symbols.Length);
+ typeStore = RestoreTypeStore(symbols);
+ logger.LogInformation("Type Store Restored");
+ }
+
+ var csharp = GetCSharp(serviceProvider, symbols, typeStore).Select(x => x.ToFullString())
+ .Select((x, i) => (x, i.ToString() + ".cs"));
+ if (csharpDir is not null)
+ {
+ foreach (var (contents, fileName) in csharp)
+ {
+ var path = Path.Combine(csharpDir.FullName, fileName);
+ await File.WriteAllTextAsync(path, contents);
+ }
+ }
+ }),
+ processedSymbolsFile,
+ csharpDir,
+ logLevel
+ );
+
+ var generateRawSymbols = new Command("raw-symbols")
+ {
+ xmlFile,
+ rawSymbolsFile,
+ logLevel
+ };
+ generateRawSymbols.SetHandler(
+ (Func)
+ (async static (xmlFile, rawSymbolsFile, logLevel) =>
+ {
+ var serviceProvider = CreateServiceProvider(logLevel);
+ Symbol[] symbols;
+ TypeStore typeStore;
+ if (xmlFile is null)
+ {
+ symbols = Array.Empty();
+ typeStore = new TypeStore();
+ }
+ else
+ {
+ var logger = serviceProvider.GetRequiredService>();
+ var xmlDoc = new XmlDocument();
+ await using var stream = xmlFile.OpenRead();
+ xmlDoc.Load(stream);
+ (symbols, typeStore) = GetSymbols(serviceProvider, xmlDoc);
+ logger.LogTrace("{count} Symbols Scraped from XML", symbols.Length);
+ }
+
+ if (rawSymbolsFile is not null)
+ {
+ if (rawSymbolsFile.Exists) rawSymbolsFile.Delete();
+ await using var stream = rawSymbolsFile.OpenWrite();
+ await JsonSerializer.SerializeAsync(stream, symbols, GetJsonOptions());
+ }
+ }), xmlFile, rawSymbolsFile, logLevel);
+
+ var generateXML = new Command("xml")
+ {
+ xmlFile,
+ logLevel,
+ useStandardIncludes,
+ extraIncludedDirectories,
+ includedNames,
+ excludedNames,
+ definedMacros,
+ headerFile
+ };
+ generateXML.SetHandler
+ (
+ (async static (xmlFile, logLevel, useStandardIncludes, extraIncludedDirectories,
+ includedNames, excludedNames, definedMacros, headerFile) =>
+ {
+ var serviceProvider = CreateServiceProvider(logLevel);
+ XmlDocument xmlDoc = GetXml
+ (
+ serviceProvider,
+ useStandardIncludes,
+ extraIncludedDirectories,
+ headerFile.FullName,
+ includedNames,
+ excludedNames,
+ definedMacros
+ );
+ if (xmlFile is not null)
+ {
+ if (xmlFile.Exists) xmlFile.Delete();
+ await using var stream = xmlFile.OpenWrite();
+ await using var writer = new XmlTextWriter(stream, Encoding.UTF8);
+ xmlDoc.WriteTo(writer);
+ }
+ }),
+ xmlFile,
+ logLevel,
+ useStandardIncludes,
+ extraIncludedDirectories,
+ includedNames,
+ excludedNames,
+ definedMacros,
+ headerFile
+ );
+
+ var processSymbols = new Command("process-symbols")
+ {
+ logLevel,
+ rawSymbolsFile,
+ processedSymbolsFile,
+ usedSymbolVisitors
+ };
+ processSymbols.SetHandler(
+ async static (logLevel, rawSymbolsFile, processedSymbolsFile, usedSymbolVisitors) =>
+ {
+ var serviceProvider = CreateServiceProvider(logLevel);
+
+ Symbol[] rawSymbols;
+ TypeStore typeStore;
+ if (rawSymbolsFile is null)
+ {
+ rawSymbols = Array.Empty();
+ typeStore = new TypeStore();
+ }
+ else
+ {
+ var logger = serviceProvider.GetRequiredService>();
+ logger.LogInformation("Loading Symbols from File...");
+ await using var stream = rawSymbolsFile.OpenRead();
+ rawSymbols = await JsonSerializer.DeserializeAsync(stream, GetJsonOptions()) ?? Array.Empty();
+ logger.LogInformation("Loaded {count} Symbols from Disk. Restoring Type Store...", rawSymbols.Length);
+ typeStore = RestoreTypeStore(rawSymbols);
+ logger.LogInformation("Type Store Restored");
+ }
+
+ var processedSymbols = ProcessSymbols(serviceProvider, rawSymbols, typeStore, usedSymbolVisitors);
+ if (processedSymbolsFile is not null)
+ {
+ if (processedSymbolsFile.Exists) processedSymbolsFile.Delete();
+ await using var stream = processedSymbolsFile.OpenWrite();
+ await JsonSerializer.SerializeAsync(stream, processedSymbols, GetJsonOptions());
+ }
+
+ }, logLevel, rawSymbolsFile, processedSymbolsFile, usedSymbolVisitors);
+
+ var generate = new Command("generate")
+ {
+ generateBindings,
+ generateCSharp,
+ generateRawSymbols,
+ generateXML,
+ processSymbols
+ };
+
+ var rootCommand = new RootCommand
+ ("SilkTouch dotnet tool. Use to generate the silkiest bindings you've ever seen!")
+ {
+ generate
+ };
+
+ return await rootCommand.InvokeAsync(args);
+ }
+
+ private static IEnumerable ProcessSymbols
+ (IServiceProvider serviceProvider, IEnumerable symbols, TypeStore typeStore, AvailableSymbolVisitors usedSymbolVisitors)
+ {
+ var visitors = new List();
+
+ if ((usedSymbolVisitors & AvailableSymbolVisitors.PointerTypeResolver) != 0)
+ {
+ visitors.Add(ActivatorUtilities.CreateInstance(serviceProvider, typeStore));
+ }
+
+ if ((usedSymbolVisitors & AvailableSymbolVisitors.InternalTypeResolver) != 0)
+ {
+ var typeScopeSymbolVisitor = ActivatorUtilities.CreateInstance
+ (serviceProvider, typeStore);
+ visitors.Add(typeScopeSymbolVisitor);
+ visitors.Add
+ (
+ ActivatorUtilities.CreateInstance
+ (serviceProvider, typeScopeSymbolVisitor.RootScope, typeStore)
+ );
+ }
+
+ if ((usedSymbolVisitors & AvailableSymbolVisitors.PrimitiveTypeResolver) != 0)
+ {
+ visitors.Add(ActivatorUtilities.CreateInstance(serviceProvider, typeStore));
+ }
+
+
+ foreach (var visitor in visitors)
+ {
+ symbols = symbols.Select(visitor.Visit);
+ }
+
+ return symbols;
+ }
+
+ private static XmlDocument GetXml
+ (
+ IServiceProvider serviceProvider,
+ bool useStandardIncludes,
+ string[] extraIncludedDirectories,
+ string headerFile,
+ string[] includedNames,
+ string[] excludedNames,
+ string[] definedMacros
+ )
+ {
+ var scraper = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider);
+ var includedDirectories = new List();
+ if (useStandardIncludes)
+ {
+ includedDirectories.AddRange(scraper.ResolveStandardIncludes());
+ }
+ includedDirectories.AddRange(extraIncludedDirectories);
+
+ var xml = scraper.GenerateXML(headerFile, includedNames, excludedNames, includedDirectories.ToArray(), definedMacros);
+
+ return xml ?? new XmlDocument();
+ }
+
+ private static (Symbol[], TypeStore) GetSymbols(IServiceProvider serviceProvider, XmlDocument xml)
+ {
+ var scraper = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider);
+ var typeStore = new TypeStore();
+ var symbols = scraper.ScrapeXML(xml, typeStore).ToArray();
+
+ return (symbols, typeStore);
+ }
+
+ private static TypeStore RestoreTypeStore(IEnumerable symbols)
+ {
+ var typeStore = new TypeStore();
+ var visitor = new TypeStoreRestoreVisitor(typeStore);
+
+ foreach (var symbol in symbols)
+ {
+ visitor.Visit(symbol); // discard, we don't care
+ }
+
+ return typeStore;
+ }
+
+ private static IEnumerable GetCSharp(IServiceProvider serviceProvider, IEnumerable symbols, TypeStore typeStore)
+ {
+ var emitter = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider);
+
+ return symbols.Select(x => emitter.Transform(x, typeStore));
+ }
+
+
+ private sealed class TypeStoreRestoreVisitor : SymbolVisitor
+ {
+ public TypeStoreRestoreVisitor(TypeStore typeStore) : base(typeStore)
+ { }
+
+ protected override TypeReference VisitTypeReference(TypeReference typeReference)
+ {
+ if (typeReference is UnresolvedTypeReference) return typeReference;
+ return base.VisitTypeReference(typeReference);
+ }
+ }
+
+
+ private static IServiceProvider CreateServiceProvider(LogLevel minimum)
+ {
+
+ var configuration = new ConfigurationBuilder()
+ .AddEnvironmentVariables(source => source.Prefix = "SILK_DOTNET_")
+ .Build();
+ var serviceProvider = new ServiceCollection()
+ .AddLogging(builder =>
+ {
+ builder.AddConsole();
+ builder.SetMinimumLevel(minimum);
+ }
+ )
+ .Configure(configuration.GetSection("Scraper"))
+ .AddSingleton()
+ .AddSingleton()
+ .BuildServiceProvider();
+ return serviceProvider;
+ }
+
+ private static JsonSerializerOptions GetJsonOptions()
+ {
+ var opts = new JsonSerializerOptions();
+ opts.Converters.Add(new SymbolJsonConverterFactory());
+ return opts;
+ }
+
+ private sealed class SymbolJsonConverterFactory : JsonConverterFactory
+ {
+
+ public override bool CanConvert
+ (Type typeToConvert) => typeToConvert.IsAbstract && typeToConvert.IsAssignableTo(typeof(Symbol));
+ public override JsonConverter? CreateConverter
+ (Type typeToConvert, JsonSerializerOptions options) => (JsonConverter?) Activator.CreateInstance
+ (typeof(SymbolJsonConverter<>).MakeGenericType(typeToConvert));
+ }
+
+ private sealed class SymbolJsonConverter
+ : JsonConverter
+ where T : Symbol
+ {
+ public override bool CanConvert
+ // If a leaf type (non-abstract) is given, serialize as that
+ (Type typeToConvert) => typeToConvert.IsAbstract && typeToConvert.IsAssignableTo(typeof(T));
+
+ public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ using var document = JsonDocument.ParseValue(ref reader);
+ if (!document.RootElement.TryGetProperty("type", out var typeProp) || typeProp.GetString() is not {} type)
+ throw new InvalidOperationException("Cannot deserialize symbol without \"type\"");
+
+ var symbolType = typeof(T).Assembly.GetTypes().First(x => x.Name == type);
+ if (symbolType is null)
+ throw new InvalidOperationException($"Could not find type {type}");
+
+ return document.Deserialize(symbolType, options) as T;
+ }
+ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+ {
+ writer.WriteStartObject();
+
+ var type = value.GetType();
+ writer.WritePropertyName("type");
+ writer.WriteStringValue(type.Name);
+
+ var element = JsonSerializer.SerializeToElement(value, type, options);
+ foreach (var prop in element.EnumerateObject())
+ {
+ writer.WritePropertyName(prop.Name);
+ prop.Value.WriteTo(writer);
+ }
+
+ writer.WriteEndObject();
+ }
+ }
+
+ [Flags]
+ private enum AvailableSymbolVisitors
+ {
+ None = 0,
+ PointerTypeResolver = 1 << 1,
+ InternalTypeResolver = 1 << 2,
+ PrimitiveTypeResolver = 1 << 3,
+ AllTypeResolvers = PointerTypeResolver | InternalTypeResolver | PrimitiveTypeResolver,
+ }
+ }
+}
diff --git a/src/generators/SilkTouch/SilkTouch.csproj b/src/generators/Silk.NET.SilkTouch.DotnetTool/Silk.NET.SilkTouch.DotnetTool.csproj
similarity index 72%
rename from src/generators/SilkTouch/SilkTouch.csproj
rename to src/generators/Silk.NET.SilkTouch.DotnetTool/Silk.NET.SilkTouch.DotnetTool.csproj
index 59f591eb17..38845f6e12 100644
--- a/src/generators/SilkTouch/SilkTouch.csproj
+++ b/src/generators/Silk.NET.SilkTouch.DotnetTool/Silk.NET.SilkTouch.DotnetTool.csproj
@@ -5,22 +5,24 @@
net6.0
true
silktouch
+ DotnetTool
+ true
+
$(NETCoreSdkRuntimeIdentifier)
-
+
-
-
-
+
+
diff --git a/src/generators/Silk.NET.SilkTouch.Roslyn/Silk.NET.SilkTouch.Roslyn.csproj b/src/generators/Silk.NET.SilkTouch.Roslyn/Silk.NET.SilkTouch.Roslyn.csproj
deleted file mode 100644
index 621aa85eb3..0000000000
--- a/src/generators/Silk.NET.SilkTouch.Roslyn/Silk.NET.SilkTouch.Roslyn.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- netstandard2.0
-
-
-
-
-
-
-
-
diff --git a/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs b/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs
index 1d6d69e1f3..72c172c59e 100644
--- a/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs
+++ b/src/generators/Silk.NET.SilkTouch.Scraper/ClangScraper.cs
@@ -260,8 +260,29 @@ out var handle
try
{
-
- if (result != CXErrorCode.CXError_Success)
+ if (result == CXErrorCode.CXError_Failure)
+ {
+ if (handle.NumDiagnostics > 0)
+ {
+ for (uint i = 0; i < handle.NumDiagnostics; i++)
+ {
+ var x = handle.GetDiagnostic(i);
+
+ logger.Log(x.Severity switch
+ {
+ CXDiagnosticSeverity.CXDiagnostic_Ignored => LogLevel.Trace,
+ CXDiagnosticSeverity.CXDiagnostic_Note => LogLevel.Debug,
+ CXDiagnosticSeverity.CXDiagnostic_Warning => LogLevel.Warning,
+ CXDiagnosticSeverity.CXDiagnostic_Error => LogLevel.Error,
+ CXDiagnosticSeverity.CXDiagnostic_Fatal => LogLevel.Critical,
+ _ => throw new ArgumentOutOfRangeException()
+ }, "{category} {message}", x.CategoryText, x.Format(0));
+ }
+ }
+
+ throw new Exception($"Could not parse translational unit. {Enum.GetName(result)}");
+ }
+ else if (result != CXErrorCode.CXError_Success)
{
if (handle.NumDiagnostics > 0)
{
@@ -274,7 +295,7 @@ out var handle
}
}
}
-
+
throw new Exception($"Could not parse translational unit. {Enum.GetName(result)}");
}
diff --git a/src/generators/Silk.NET.SilkTouch.Scraper/Subagent/VisualStudioResolver.cs b/src/generators/Silk.NET.SilkTouch.Scraper/Subagent/VisualStudioResolver.cs
index 55c5d6fba9..d70027180c 100644
--- a/src/generators/Silk.NET.SilkTouch.Scraper/Subagent/VisualStudioResolver.cs
+++ b/src/generators/Silk.NET.SilkTouch.Scraper/Subagent/VisualStudioResolver.cs
@@ -96,10 +96,8 @@ public static bool TryGetVisualStudioInfo([NotNullWhen(true)] out VisualStudioIn
Debug.WriteLine(visualStudios.Length + " Visual Studio installation(s)");
// cycle through candidate installations, try and find everything we're looking for.
- var hasVs = false;
foreach (var visualStudio in visualStudios)
{
- hasVs = true;
Debug.WriteLine
(
$"Testing \"{visualStudio.Name}\" v{visualStudio.Version.ToString(3)} at " +
@@ -158,21 +156,8 @@ public static bool TryGetVisualStudioInfo([NotNullWhen(true)] out VisualStudioIn
return true;
}
- if (!hasVs)
- {
- Console.WriteLine("No instance of Visual Studio found whatsoever.");
- }
-
- // if any of it's still null, we couldn't find a candidate.
- Console.WriteLine
- (
- "Couldn't find a viable Visual Studio installation - ensure you have the Windows 10 SDK and C++ " +
- "tools installed. SilkTouch Scraper may not function correctly without Visual Studio or Visual " +
- "Studio Build Tools with these workloads."
- );
-
info = null;
_vsInfoKnownError = true;
return false;
}
-}
\ No newline at end of file
+}
diff --git a/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs b/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs
index c6641f8e45..1d4da4762c 100644
--- a/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs
+++ b/src/generators/Silk.NET.SilkTouch.Scraper/XmlVisitor.cs
@@ -26,6 +26,7 @@ public XmlVisitor(ILogger logger, TypeStore typeStore)
public IEnumerable Visit(XmlNode node)
{
+ _logger.LogTrace("Visiting XML Node of kind {name}", node.Name);
switch (node)
{
case XmlElement { Name: "bindings" } bindings:
@@ -38,7 +39,12 @@ public IEnumerable Visit(XmlNode node)
return VisitField(field);
default:
{
+ _logger.LogWarning("Skipping unknown XML Node of kind {name}", node.Name);
+ #if DEBUG
throw new NotImplementedException();
+ #else
+ return Array.Empty();
+ #endif
}
}
}
diff --git a/src/generators/Silk.NET.SilkTouch.Symbols/Silk.NET.SilkTouch.Symbols.csproj b/src/generators/Silk.NET.SilkTouch.Symbols/Silk.NET.SilkTouch.Symbols.csproj
index 6cb3c8870a..02fd2f7770 100644
--- a/src/generators/Silk.NET.SilkTouch.Symbols/Silk.NET.SilkTouch.Symbols.csproj
+++ b/src/generators/Silk.NET.SilkTouch.Symbols/Silk.NET.SilkTouch.Symbols.csproj
@@ -8,5 +8,6 @@
+
diff --git a/src/generators/Silk.NET.SilkTouch.Symbols/TypeId.cs b/src/generators/Silk.NET.SilkTouch.Symbols/TypeId.cs
index d8fd01e44f..b7e9b960c2 100644
--- a/src/generators/Silk.NET.SilkTouch.Symbols/TypeId.cs
+++ b/src/generators/Silk.NET.SilkTouch.Symbols/TypeId.cs
@@ -1,11 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
namespace Silk.NET.SilkTouch.Symbols;
///
/// The Id of a
///
+[JsonConverter(typeof(TypeId.JsonConverter))]
public readonly struct TypeId : IEquatable
{
private readonly Guid _guid;
@@ -34,4 +38,25 @@ private TypeId(Guid guid)
///
public static bool operator !=(TypeId left, TypeId right) => !left.Equals(right);
+
+ ///
+ public override string ToString()
+ {
+ return _guid.ToString();
+ }
+
+ private sealed class JsonConverter : JsonConverter
+ {
+ public override TypeId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (!reader.TryGetGuid(out var guid))
+ throw new InvalidOperationException("Could not parse TypeId");
+
+ return new TypeId(guid);
+ }
+ public override void Write(Utf8JsonWriter writer, TypeId value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(value._guid);
+ }
+ }
}
diff --git a/src/generators/SilkTouch/ExitCodes.cs b/src/generators/SilkTouch/ExitCodes.cs
deleted file mode 100644
index c4bfca7601..0000000000
--- a/src/generators/SilkTouch/ExitCodes.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace SilkTouch
-{
- internal enum ExitCodes
- {
- Ok,
- SubagentBadArgs,
- SubagentFailedToParse,
- SubagentFailedToStart,
- FailedToGetMSBuild
- }
-}
diff --git a/src/generators/SilkTouch/LogMode.cs b/src/generators/SilkTouch/LogMode.cs
deleted file mode 100644
index 010ed44754..0000000000
--- a/src/generators/SilkTouch/LogMode.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace SilkTouch
-{
- ///
- /// The level of logging to use during generation.
- ///
- public enum LogMode
- {
- ///
- /// Standard logging. Contains info throughout the generation process and warnings produced.
- ///
- Standard,
-
- ///
- /// Silent logging. Only logs if there's an error and suppresses the "logo".
- ///
- Silent,
-
- ///
- /// Verbose logging. Contains trace logs including suppressed diagnostics. Spammier.
- ///
- Verbose,
-
- ///
- /// Very verbose logging. Contains every log message ever possibly conceived.
- /// Spammiest, far too spammy for most uses.
- ///
- VVerbose
- }
-}
diff --git a/src/generators/SilkTouch/Program.cs b/src/generators/SilkTouch/Program.cs
deleted file mode 100644
index b88784b399..0000000000
--- a/src/generators/SilkTouch/Program.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace SilkTouch
-{
- internal class Program
- {
- static void Main(string[] args) { }
- }
-}