From ff5a04c427418cfb0ea7dd50c88418ca316e9b27 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Sun, 5 May 2024 14:57:58 -0400 Subject: [PATCH 1/9] Minor refactoring --- .../CodeGenerator/CSharpCodeGenerator.cs | 2 +- .../CodeGenerator/CSharpLibraryCompiler.cs | 6 +- .../AliasTypeCodeGenerator.cs | 26 ++-- .../ConstantCodeGenerator.cs | 10 +- .../EnumCodeGenerator.cs | 16 ++- .../FunctionCodeGenerator.cs | 24 ++-- .../FunctionPointerCodeGenerator.cs | 46 +++--- .../MacroCodeGenerator.cs | 2 +- .../OpaqueTypeCodeGenerator.cs | 16 ++- .../StructCodeGenerator.cs | 133 ++++++++++-------- .../Domain/Mapper/CSharpCodeMapper.cs | 13 +- 11 files changed, 157 insertions(+), 137 deletions(-) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/AliasTypeCodeGenerator.cs (52%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/ConstantCodeGenerator.cs (79%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/EnumCodeGenerator.cs (90%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/FunctionCodeGenerator.cs (83%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/FunctionPointerCodeGenerator.cs (62%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/MacroCodeGenerator.cs (94%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/OpaqueTypeCodeGenerator.cs (73%) rename src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/{Handlers => Generators}/StructCodeGenerator.cs (62%) diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs index dc55ca10..a2512d36 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs @@ -9,7 +9,7 @@ using System.Reflection; using bottlenoselabs.Common.Diagnostics; using C2CS.Commands.WriteCodeCSharp.Data; -using C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +using C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpLibraryCompiler.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpLibraryCompiler.cs index 12e1dc08..316b5255 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpLibraryCompiler.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpLibraryCompiler.cs @@ -11,7 +11,7 @@ namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator; -public class CSharpLibraryCompiler +public sealed class CSharpLibraryCompiler { public Assembly? Compile( CSharpProject project, @@ -26,10 +26,10 @@ public class CSharpLibraryCompiler return null; } - return TryCompile(project, options, diagnostics); + return TryCompileProject(project, options, diagnostics); } - private static Assembly? TryCompile( + private static Assembly? TryCompileProject( CSharpProject project, CSharpCodeGeneratorOptions options, DiagnosticsSink diagnostics) diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/AliasTypeCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/AliasTypeCodeGenerator.cs similarity index 52% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/AliasTypeCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/AliasTypeCodeGenerator.cs index 2de33bb7..bf9f14b6 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/AliasTypeCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/AliasTypeCodeGenerator.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class AliasTypeCodeGenerator : GenerateCodeHandler { @@ -18,17 +18,19 @@ public AliasTypeCodeGenerator( protected override SyntaxNode GenerateCode(CSharpCodeGeneratorContext context, CSharpAliasType node) { - var code = $@" -[StructLayout(LayoutKind.Explicit, Size = {node.UnderlyingType.SizeOf}, Pack = {node.UnderlyingType.AlignOf})] -public struct {node.Name} -{{ - [FieldOffset(0)] - public {node.UnderlyingType.Name} Data; - - public static implicit operator {node.UnderlyingType.Name}({node.Name} data) => data.Data; - public static implicit operator {node.Name}({node.UnderlyingType.Name} data) => new() {{Data = data}}; -}} -"; + var code = $$""" + + [StructLayout(LayoutKind.Explicit, Size = {{node.UnderlyingType.SizeOf}}, Pack = {{node.UnderlyingType.AlignOf}})] + public struct {{node.Name}} + { + [FieldOffset(0)] + public {{node.UnderlyingType.Name}} Data; + + public static implicit operator {{node.UnderlyingType.Name}}({{node.Name}} data) => data.Data; + public static implicit operator {{node.Name}}({{node.UnderlyingType.Name}} data) => new() {Data = data}; + } + + """; var member = context.ParseMemberCode(code); return member; diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/ConstantCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/ConstantCodeGenerator.cs similarity index 79% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/ConstantCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/ConstantCodeGenerator.cs index 0b927e6c..869658ec 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/ConstantCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/ConstantCodeGenerator.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class ConstantCodeGenerator : GenerateCodeHandler { @@ -18,9 +18,11 @@ public ConstantCodeGenerator( protected override SyntaxNode GenerateCode(CSharpCodeGeneratorContext context, CSharpConstant node) { - var code = $@" -public const {node.Type} {node.Name} = {node.Value}; -"; + var code = $""" + + public const {node.Type} {node.Name} = {node.Value}; + + """; var member = context.ParseMemberCode(code); return member; diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/EnumCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/EnumCodeGenerator.cs similarity index 90% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/EnumCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/EnumCodeGenerator.cs index cfe6cb40..cede8aa5 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/EnumCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/EnumCodeGenerator.cs @@ -10,7 +10,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class EnumCodeGenerator : GenerateCodeHandler { @@ -38,12 +38,14 @@ protected override SyntaxNode GenerateCode(CSharpCodeGeneratorContext context, C var valuesString = values.Select(x => x.ToFullString()); var members = string.Join(",\n", valuesString); - var code = $@" -public enum {enumName} : {enumIntegerTypeName} - {{ - {members} - }} -"; + var code = $$""" + + public enum {{enumName}} : {{enumIntegerTypeName}} + { + {{members}} + } + + """; var member = context.ParseMemberCode(code); return member; diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/FunctionCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionCodeGenerator.cs similarity index 83% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/FunctionCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionCodeGenerator.cs index 72260437..4add39ac 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/FunctionCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionCodeGenerator.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class FunctionCodeGenerator : GenerateCodeHandler { @@ -32,10 +32,12 @@ protected override SyntaxNode GenerateCode(CSharpCodeGeneratorContext context, C var callingConvention = FunctionCallingConventionDllImport(node.CallingConvention); var dllImportParametersString = string.Join(',', "LibraryName", $"EntryPoint = \"{node.CName}\"", callingConvention); - code = $@" -[DllImport({dllImportParametersString})] -public static extern {node.ReturnType.FullName} {node.Name}({parametersString}); -"; + code = $""" + + [DllImport({dllImportParametersString})] + public static extern {node.ReturnType.FullName} {node.Name}({parametersString}); + + """; } else { @@ -50,11 +52,13 @@ protected override SyntaxNode GenerateCode(CSharpCodeGeneratorContext context, C var libraryImportParametersString = string.Join(",", libraryImportParameters); - code = $@" -[LibraryImport({libraryImportParametersString})] -[UnmanagedCallConv(CallConvs = new[] {{ typeof({callingConvention}) }})] -public static partial {node.ReturnType.FullName} {node.Name}({parametersString}); -"; + code = $$""" + + [LibraryImport({{libraryImportParametersString}})] + [UnmanagedCallConv(CallConvs = new[] { typeof({{callingConvention}}) })] + public static partial {{node.ReturnType.FullName}} {{node.Name}}({{parametersString}}); + + """; } var member = context.ParseMemberCode(code); diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/FunctionPointerCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs similarity index 62% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/FunctionPointerCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs index eff0c3c2..457b061a 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/FunctionPointerCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public sealed class FunctionPointerCodeGenerator : GenerateCodeHandler { @@ -37,13 +37,15 @@ private string GenerateCodeFunctionPointer(CSharpCodeGeneratorContext context, C var parameterTypesString = context.GenerateCodeParameters(node.Parameters, false); var parameterTypesAndReturnTypeString = string.IsNullOrEmpty(parameterTypesString) ? node.ReturnType.FullName : $"{parameterTypesString}, {node.ReturnType.FullName}"; - var code = $@" -[StructLayout(LayoutKind.Sequential)] -public struct {node.Name} -{{ - public delegate* unmanaged<{parameterTypesAndReturnTypeString}> Pointer; -}} -"; + var code = $$""" + + [StructLayout(LayoutKind.Sequential)] + public struct {{node.Name}} + { + public delegate* unmanaged<{{parameterTypesAndReturnTypeString}}> Pointer; + } + + """; return code; } @@ -51,21 +53,23 @@ private string GenerateCodeDelegate(CSharpCodeGeneratorContext context, CSharpFu { var parameterTypesString = context.GenerateCodeParameters(node.Parameters); - var code = $@" -[StructLayout(LayoutKind.Sequential)] -public struct {node.Name} -{{ - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate {node.ReturnType.FullName} @delegate({parameterTypesString}); + var code = $$""" + + [StructLayout(LayoutKind.Sequential)] + public struct {{node.Name}} + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public unsafe delegate {{node.ReturnType.FullName}} @delegate({{parameterTypesString}}); + + public IntPtr Pointer; - public IntPtr Pointer; + public {{node.Name}}(@delegate d) + { + Pointer = Marshal.GetFunctionPointerForDelegate(d); + } + } - public {node.Name}(@delegate d) - {{ - Pointer = Marshal.GetFunctionPointerForDelegate(d); - }} -}} -"; + """; return code; } } diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/MacroCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/MacroCodeGenerator.cs similarity index 94% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/MacroCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/MacroCodeGenerator.cs index cafebcac..a79c4579 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/MacroCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/MacroCodeGenerator.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class MacroCodeGenerator : GenerateCodeHandler { diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/OpaqueTypeCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/OpaqueTypeCodeGenerator.cs similarity index 73% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/OpaqueTypeCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/OpaqueTypeCodeGenerator.cs index c88ff71a..4664ea68 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/OpaqueTypeCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/OpaqueTypeCodeGenerator.cs @@ -6,7 +6,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class OpaqueTypeCodeGenerator : GenerateCodeHandler { @@ -18,12 +18,14 @@ public OpaqueTypeCodeGenerator( protected override SyntaxNode GenerateCode(CSharpCodeGeneratorContext context, CSharpOpaqueType node) { - var code = $@" -[StructLayout(LayoutKind.Sequential)] -public struct {node.Name} -{{ -}} -"; + var code = $$""" + + [StructLayout(LayoutKind.Sequential)] + public struct {{node.Name}} + { + } + + """; return context.ParseMemberCode(code); } diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/StructCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/StructCodeGenerator.cs similarity index 62% rename from src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/StructCodeGenerator.cs rename to src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/StructCodeGenerator.cs index cbe09ea8..3628186c 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Handlers/StructCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/StructCodeGenerator.cs @@ -1,7 +1,6 @@ // Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved. // Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information. -using System; using System.Collections.Immutable; using System.Linq; using C2CS.Commands.WriteCodeCSharp.Data; @@ -9,7 +8,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.Extensions.Logging; -namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Handlers; +namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator.Generators; public class StructCodeGenerator : GenerateCodeHandler { @@ -30,13 +29,15 @@ private StructDeclarationSyntax Struct(CSharpCodeGeneratorContext context, CShar var memberStrings = memberSyntaxes.Select(x => x.ToFullString()); var members = string.Join("\n\n", memberStrings); - var code = $@" -[StructLayout(LayoutKind.Explicit, Size = {@struct.SizeOf}, Pack = {@struct.AlignOf})] -public struct {@struct.Name} -{{ - {members} -}} -"; + var code = $$""" + + [StructLayout(LayoutKind.Explicit, Size = {{@struct.SizeOf}}, Pack = {{@struct.AlignOf}})] + public struct {{@struct.Name}} + { + {{members}} + } + + """; if (isNested) { @@ -99,29 +100,33 @@ private FieldDeclarationSyntax StructField( string code; if (field.Type.Name == "CString") { - code = $@" -[FieldOffset({field.OffsetOf})] // size = {field.Type.SizeOf} -public {field.Type.FullName} _{field.Name}; - -public string {field.Name} -{{ - get - {{ - return CString.ToString(_{field.Name}); - }} - set - {{ - _{field.Name} = CString.FromString(value); - }} -}} -".Trim(); + code = $$""" + + [FieldOffset({{field.OffsetOf}})] // size = {{field.Type.SizeOf}} + public {{field.Type.FullName}} _{{field.Name}}; + + public string {{field.Name}} + { + get + { + return CString.ToString(_{{field.Name}}); + } + set + { + _{{field.Name}} = CString.FromString(value); + } + } + + """.Trim(); } else { - code = $@" -[FieldOffset({field.OffsetOf})] // size = {field.Type.SizeOf} -public {field.Type.FullName} {field.Name}; -".Trim(); + code = $""" + + [FieldOffset({field.OffsetOf})] // size = {field.Type.SizeOf} + public {field.Type.FullName} {field.Name}; + + """.Trim(); } var member = context.ParseMemberCode(code); @@ -132,10 +137,12 @@ private FieldDeclarationSyntax EmitStructFieldFixedBuffer( CSharpCodeGeneratorContext context, CSharpStructField field) { - var code = $@" -[FieldOffset({field.OffsetOf})] // size = {field.Type.SizeOf} -public fixed byte {field.BackingFieldName}[{field.Type.SizeOf}]; // {field.Type.OriginalName} -".Trim(); + var code = $""" + + [FieldOffset({field.OffsetOf})] // size = {field.Type.SizeOf} + public fixed byte {field.BackingFieldName}[{field.Type.SizeOf}]; // {field.Type.OriginalName} + + """.Trim(); return context.ParseMemberCode(code); } @@ -149,37 +156,41 @@ private PropertyDeclarationSyntax StructFieldFixedBufferProperty( if (field.Type.Name == "CString") { - code = $@" -public string {field.Name} -{{ - get - {{ - fixed ({structName}*@this = &this) - {{ - var pointer = &@this->{field.BackingFieldName}[0]; - var cString = new CString(pointer); - return CString.ToString(cString); - }} - }} -}} -".Trim(); + code = $$""" + + public string {{field.Name}} + { + get + { + fixed ({{structName}}*@this = &this) + { + var pointer = &@this->{{field.BackingFieldName}}[0]; + var cString = new CString(pointer); + return CString.ToString(cString); + } + } + } + + """.Trim(); } else if (field.Type.Name == "CStringWide") { - code = $@" -public string {field.Name} -{{ - get - {{ - fixed ({structName}*@this = &this) - {{ - var pointer = &@this->{field.BackingFieldName}[0]; - var cString = new CStringWide(pointer); - return StringWide.ToString(cString); - }} - }} -}} -".Trim(); + code = $$""" + + public string {{field.Name}} + { + get + { + fixed ({{structName}}*@this = &this) + { + var pointer = &@this->{{field.BackingFieldName}}[0]; + var cString = new CStringWide(pointer); + return StringWide.ToString(cString); + } + } + } + + """.Trim(); } else { diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs index 9732ad4a..407335ff 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs @@ -170,19 +170,12 @@ private ImmutableArray CSharpFunctionParameters( var parameterNames = new List(); // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - foreach (var functionExternParameterC in functionParameters) + foreach (var functionParameter in functionParameters) { - var parameterName = CSharpUniqueParameterName(functionExternParameterC.Name, parameterNames); + var parameterName = CSharpUniqueParameterName(functionParameter.Name, parameterNames); parameterNames.Add(parameterName); var value = - FunctionParameter(context, functionName, functionExternParameterC, parameterName); - if (value.TypeName.Contains("uint16_t", StringComparison.InvariantCultureIgnoreCase)) - { - var value2 = - FunctionParameter(context, functionName, functionExternParameterC, parameterName); - Console.WriteLine(); - } - + FunctionParameter(context, functionName, functionParameter, parameterName); builder.Add(value); } From ea687c9b933761e4f761d0d83d323cc221ed0443 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 16:53:19 -0400 Subject: [PATCH 2/9] Introduce new setting for selecting target framework --- src/cs/C2CS.sln | 2 +- .../Generated/AssemblyAttributes.gen.cs | 10 +- .../Generated/Bindgen.Runtime.gen.cs | 766 +++++++++++++++++ .../helloworld-app/Generated/Runtime.gen.cs | 768 ------------------ .../LibraryImports.g.cs | 49 -- .../Generated/my_c_library.gen.cs | 85 +- .../helloworld/helloworld-app/Program.cs | 2 +- .../Program.cs | 2 +- .../config-build-c-library.json | 4 + .../config-extract.json | 0 .../config-generate-cs.json | 4 +- .../helloworld-bindgen.csproj} | 1 + .../my_c_library/CMakeLists.txt | 0 .../my_c_library/include/my_c_library.h | 10 +- .../my_c_library/src/my_c_library.c | 0 .../config-build-c-library.json | 4 - .../ffi-x/cross-platform.json | 308 ------- .../ffi/aarch64-apple-darwin.json | 600 -------------- .../ffi/x86_64-apple-darwin.json | 600 -------------- src/cs/production/C2CS.Tool/C2CS.Tool.csproj | 1 + .../CodeGenerator/CSharpCodeGenerator.cs | 68 +- .../CSharpCodeGeneratorOptions.cs | 10 +- .../Domain/Mapper/CSharpCodeMapper.cs | 2 +- .../Input/Sanitized/WriteCodeCSharpInput.cs | 1 + .../Input/Unsanitized/WriteCSharpCodeInput.cs | 114 +-- .../Input/WriteCodeCSharpInputSanitizer.cs | 156 +++- 26 files changed, 1058 insertions(+), 2509 deletions(-) create mode 100644 src/cs/examples/helloworld/helloworld-app/Generated/Bindgen.Runtime.gen.cs delete mode 100644 src/cs/examples/helloworld/helloworld-app/Generated/Runtime.gen.cs delete mode 100644 src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings => helloworld-bindgen}/Program.cs (97%) create mode 100644 src/cs/examples/helloworld/helloworld-bindgen/config-build-c-library.json rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings => helloworld-bindgen}/config-extract.json (100%) rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings => helloworld-bindgen}/config-generate-cs.json (54%) rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings/helloworld-compile-c-library-and-generate-bindings.csproj => helloworld-bindgen/helloworld-bindgen.csproj} (88%) rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings => helloworld-bindgen}/my_c_library/CMakeLists.txt (100%) rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings => helloworld-bindgen}/my_c_library/include/my_c_library.h (70%) rename src/cs/examples/helloworld/{helloworld-compile-c-library-and-generate-bindings => helloworld-bindgen}/my_c_library/src/my_c_library.c (100%) delete mode 100644 src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-build-c-library.json delete mode 100644 src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi-x/cross-platform.json delete mode 100644 src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/aarch64-apple-darwin.json delete mode 100644 src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/x86_64-apple-darwin.json diff --git a/src/cs/C2CS.sln b/src/cs/C2CS.sln index d9dc22e6..07a5ef32 100644 --- a/src/cs/C2CS.sln +++ b/src/cs/C2CS.sln @@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{56 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "helloworld", "helloworld", "{24028D61-CCE1-4893-9BD6-1D7C28563DC8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "helloworld-compile-c-library-and-generate-bindings", "examples\helloworld\helloworld-compile-c-library-and-generate-bindings\helloworld-compile-c-library-and-generate-bindings.csproj", "{841E561C-B3BB-499B-AEB3-0874ACDDB2BC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "helloworld-bindgen", "examples\helloworld\helloworld-bindgen\helloworld-bindgen.csproj", "{841E561C-B3BB-499B-AEB3-0874ACDDB2BC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C2CS.Tool", "production\C2CS.Tool\C2CS.Tool.csproj", "{1B67F4A2-24E6-43A6-A031-918DD44CD991}" EndProject diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.gen.cs b/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.gen.cs index 64359f59..d47c5f44 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.gen.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/AssemblyAttributes.gen.cs @@ -1,6 +1,6 @@ -// To disable generating this file set `isEnabledGenerateAssemblyAttributes` to `false` in the config file for generating C# code. + // -// This code was generated by the following tool on 2024-04-10 18:55:28 GMT-04:00: +// This code was generated by the following tool on 2024-05-07 16:36:40 GMT-04:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. @@ -11,7 +11,7 @@ #nullable enable #pragma warning disable CS1591 #pragma warning disable CS8981 -using bottlenoselabs.C2CS.Runtime; +using Bindgen.Runtime; using System; using System.Collections.Generic; using System.Globalization; @@ -20,7 +20,11 @@ #endregion #if NET7_0_OR_GREATER +// NOTE: Disabling runtime marshalling is preferred for performance improvements. You can learn more here: https://learn.microsoft.com/en-us/dotnet/standard/native-interop/disabled-marshalling [assembly: DisableRuntimeMarshalling] #endif +#if (NETCOREAPP1_0_OR_GREATER) || (NET45_OR_GREATER || NETFRAMEWORK && (NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48)) || (NETSTANDARD1_1_OR_GREATER || NETSTANDARD && !NETSTANDARD1_0) +// NOTE: Only takes effect on Windows. Specifies the recommended maximum number of directories (the application directory, the %WinDir%\System32 directory, and user directories in the DLL search path) to search for native libraries. You can learn more here at (1) https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.defaultdllimportsearchpathsattribute and (2) https://learn.microsoft.com/en-ca/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa#parameters [assembly: DefaultDllImportSearchPathsAttribute(DllImportSearchPath.SafeDirectories)] +#endif diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/Bindgen.Runtime.gen.cs b/src/cs/examples/helloworld/helloworld-app/Generated/Bindgen.Runtime.gen.cs new file mode 100644 index 00000000..40ca77cd --- /dev/null +++ b/src/cs/examples/helloworld/helloworld-app/Generated/Bindgen.Runtime.gen.cs @@ -0,0 +1,766 @@ + +// To disable generating this file set `isEnabledGeneratingRuntimeCode` to `false` in the config file for generating C# code. + +// +// This code was generated by the following tool on 2024-05-07 16:36:40 GMT-04:00: +// https://github.com/bottlenoselabs/c2cs (v0.0.0.0) +// +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. +// +// ReSharper disable All + +#region Template +#nullable enable +#pragma warning disable CS1591 +#pragma warning disable CS8981 +using Bindgen.Runtime; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +#endregion + +namespace Bindgen.Runtime; + +/// +/// A boolean value type with the same memory layout as a in both managed and unmanaged contexts; +/// equivalent to a standard bool found in C/C++/ObjC where 0 is false and any other value is +/// true. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CBool : IEquatable +{ + public readonly byte Value; + + private CBool(bool value) + { + Value = Convert.ToByte(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static implicit operator CBool(bool value) + { + return FromBoolean(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static CBool FromBoolean(bool value) + { + return new CBool(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static implicit operator bool(CBool value) + { + return ToBoolean(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static bool ToBoolean(CBool value) + { + return Convert.ToBoolean(value.Value); + } + + /// + public override string ToString() + { + return ToBoolean(this).ToString(); + } + + /// + public override bool Equals(object? obj) + { + return obj is CBool b && Equals(b); + } + + /// + public bool Equals(CBool other) + { + return Value == other.Value; + } + + /// + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool operator ==(CBool left, CBool right) + { + return left.Value == right.Value; + } + + /// + /// Returns a value that indicates whether two specified structures are not equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are not equal; otherwise, false. + public static bool operator !=(CBool left, CBool right) + { + return !(left == right); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool Equals(CBool left, CBool right) + { + return left.Value == right.Value; + } +} + +/// +/// A value type with the same memory layout as a in a managed context and char in +/// an unmanaged context. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly struct CChar : IEquatable, IEquatable +{ + public readonly byte Value; + + private CChar(byte value) + { + Value = Convert.ToByte(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static implicit operator CChar(byte value) + { + return FromByte(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static CChar FromByte(byte value) + { + return new CChar(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static implicit operator byte(CChar value) + { + return ToByte(value); + } + + /// + /// Converts the specified to a . + /// + /// The value. + /// A . + public static byte ToByte(CChar value) + { + return value.Value; + } + + /// + public override string ToString() + { + return Value.ToString(CultureInfo.InvariantCulture); + } + + /// + public override bool Equals(object? obj) + { + return obj is CChar value && Equals(value); + } + + /// + public bool Equals(byte other) + { + return Value == other; + } + + /// + public bool Equals(CChar other) + { + return Value == other.Value; + } + + /// + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool operator ==(CChar left, CChar right) + { + return left.Value == right.Value; + } + + /// + /// Returns a value that indicates whether two specified structures are not equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are not equal; otherwise, false. + public static bool operator !=(CChar left, CChar right) + { + return !(left == right); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool Equals(CChar left, CChar right) + { + return left.Value == right.Value; + } +} + +/// +/// A pointer value type of bytes that represent a string; the C type `char*`. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly unsafe struct CString : IEquatable, IDisposable +{ + public readonly nint Pointer; + + /// + /// Gets a value indicating whether this is a null pointer. + /// + public bool IsNull => Pointer == 0; + + /// + /// Initializes a new instance of the struct. + /// + /// The pointer value. + public CString(byte* value) + { + Pointer = (nint)value; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The pointer value. + public CString(nint value) + { + Pointer = value; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The string value. + public CString(string s) + { + Pointer = FromString(s).Pointer; + } + + /// + /// Attempts to free the memory pointed by the . + /// + public void Dispose() + { + Marshal.FreeHGlobal(Pointer); + } + + /// + /// Performs an explicit conversion from an to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static explicit operator CString(nint value) + { + return FromIntPtr(value); + } + + /// + /// Performs an explicit conversion from an to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static CString FromIntPtr(nint value) + { + return new CString(value); + } + + /// + /// Performs an implicit conversion from a byte pointer to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static implicit operator CString(byte* value) + { + return From(value); + } + + /// + /// Performs an implicit conversion from a byte pointer to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static CString From(byte* value) + { + return new CString((nint)value); + } + + /// + /// Performs an implicit conversion from a to a . + /// + /// The pointer. + /// + /// The resulting . + /// + public static implicit operator nint(CString value) + { + return value.Pointer; + } + + /// + /// Performs an implicit conversion from a to a . + /// + /// The pointer. + /// + /// The resulting . + /// + public static nint ToIntPtr(CString value) + { + return value.Pointer; + } + + /// + /// Performs an explicit conversion from a to a . + /// + /// The . + /// + /// The resulting . + /// + public static explicit operator string(CString value) + { + return ToString(value); + } + + /// + /// Converts a C style string (ANSI or UTF-8) of type `char` (one dimensional byte array + /// terminated by a 0x0) to a UTF-16 by allocating and copying. + /// + /// A pointer to the C string. + /// A equivalent of . + public static string ToString(CString value) + { + if (value.IsNull) + { + return string.Empty; + } + + // calls ASM/C/C++ functions to calculate length and then "FastAllocate" the string with the GC + // https://mattwarren.org/2016/05/31/Strings-and-the-CLR-a-Special-Relationship/ + var result = Marshal.PtrToStringAnsi(value.Pointer); + + if (string.IsNullOrEmpty(result)) + { + return string.Empty; + } + + return result; + } + + /// + /// Performs an explicit conversion from a to a . + /// + /// The . + /// + /// The resulting . + /// + public static explicit operator CString(string s) + { + return FromString(s); + } + + /// + /// Converts a UTF-16 to a C style string (one dimensional byte array terminated by a + /// 0x0) by allocating and copying. + /// + /// The . + /// A C string pointer. + public static CString FromString(string str) + { + var pointer = Marshal.StringToHGlobalAnsi(str); + return new CString(pointer); + } + + /// + public override string ToString() + { + return ToString(this); + } + + /// + public override bool Equals(object? obj) + { + return obj is CString value && Equals(value); + } + + /// + public bool Equals(CString other) + { + return Pointer == other.Pointer; + } + + /// + public override int GetHashCode() + { + return Pointer.GetHashCode(); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool operator ==(CString left, CString right) + { + return left.Pointer == right.Pointer; + } + + /// + /// Returns a value that indicates whether two specified structures are not equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are not equal; otherwise, false. + public static bool operator !=(CString left, CString right) + { + return !(left == right); + } +} + +/// +/// Utility methods for interoperability with C style strings in C#. +/// +public static unsafe class CStrings +{ + /// + /// Converts an array of strings to an array of C strings of type `char` (multi-dimensional array of one + /// dimensional byte arrays each terminated by a 0x0) by allocating and copying if not already cached. + /// + /// + /// Calls . + /// + /// The strings. + /// An array pointer of C string pointers. You are responsible for freeing the returned pointer. + public static CString* CStringArray(ReadOnlySpan values) + { + var pointerSize = IntPtr.Size; + var result = (CString*)Marshal.AllocHGlobal(pointerSize * values.Length); + for (var i = 0; i < values.Length; ++i) + { + var @string = values[i]; + var cString = CString.FromString(@string); + result[i] = cString; + } + + return result; + } + + /// + /// Converts an array of strings to an array of C strings of type `wchar_t` (multi-dimensional array of one + /// dimensional ushort arrays each terminated by a 0x0) by allocating and copying. + /// + /// + /// Calls . + /// + /// The strings. + /// An array pointer of C string pointers. You are responsible for freeing the returned pointer. + public static CStringWide* CStringWideArray(ReadOnlySpan values) + { + var pointerSize = IntPtr.Size; + var result = (CStringWide*)Marshal.AllocHGlobal(pointerSize * values.Length); + for (var i = 0; i < values.Length; ++i) + { + var @string = values[i]; + var cString = CStringWide.FromString(@string); + result[i] = cString; + } + + return result; + } +} + +/// +/// A pointer value type that represents a wide string; C type `wchar_t*`. +/// +[StructLayout(LayoutKind.Sequential)] +public readonly unsafe struct CStringWide : IEquatable +{ + public readonly nint Pointer; + + /// + /// Gets a value indicating whether this is a null pointer. + /// + public bool IsNull => Pointer == 0; + + /// + /// Initializes a new instance of the struct. + /// + /// The pointer value. + public CStringWide(byte* value) + { + Pointer = (nint)value; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The pointer value. + public CStringWide(nint value) + { + Pointer = value; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The string value. + public CStringWide(string s) + { + Pointer = FromString(s).Pointer; + } + + /// + /// Performs an explicit conversion from a to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static explicit operator CStringWide(nint value) + { + return FromIntPtr(value); + } + + /// + /// Performs an explicit conversion from a to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static CStringWide FromIntPtr(nint value) + { + return new CStringWide(value); + } + + /// + /// Performs an implicit conversion from a byte pointer to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static implicit operator CStringWide(byte* value) + { + return From(value); + } + + /// + /// Performs an implicit conversion from a byte pointer to a . + /// + /// The pointer value. + /// + /// The resulting . + /// + public static CStringWide From(byte* value) + { + return new CStringWide((nint)value); + } + + /// + /// Performs an implicit conversion from a to a . + /// + /// The pointer. + /// + /// The resulting . + /// + public static implicit operator nint(CStringWide value) + { + return value.Pointer; + } + + /// + /// Performs an implicit conversion from a to a . + /// + /// The pointer. + /// + /// The resulting . + /// + public static nint ToIntPtr(CStringWide value) + { + return value.Pointer; + } + + /// + /// Performs an explicit conversion from a to a . + /// + /// The . + /// + /// The resulting . + /// + public static explicit operator string(CStringWide value) + { + return ToString(value); + } + + /// + /// Converts a C style string (unicode) of type `wchar_t` (one dimensional ushort array + /// terminated by a 0x0) to a UTF-16 by allocating and copying. + /// + /// A pointer to the C string. + /// A equivalent of . + public static string ToString(CStringWide value) + { + if (value.IsNull) + { + return string.Empty; + } + + // calls ASM/C/C++ functions to calculate length and then "FastAllocate" the string with the GC + // https://mattwarren.org/2016/05/31/Strings-and-the-CLR-a-Special-Relationship/ + var result = Marshal.PtrToStringUni(value.Pointer); + + if (string.IsNullOrEmpty(result)) + { + return string.Empty; + } + + return result; + } + + /// + /// Performs an explicit conversion from a to a . + /// + /// The . + /// + /// The resulting . + /// + public static explicit operator CStringWide(string s) + { + return FromString(s); + } + + /// + /// Converts a C string pointer (one dimensional byte array terminated by a + /// 0x0) for a specified by allocating and copying if not already cached. + /// + /// The . + /// A C string pointer. + public static CStringWide FromString(string str) + { + var pointer = Marshal.StringToHGlobalUni(str); + return new CStringWide(pointer); + } + + /// + public override string ToString() + { + return ToString(this); + } + + /// + public override bool Equals(object? obj) + { + return obj is CStringWide value && Equals(value); + } + + /// + public bool Equals(CStringWide other) + { + return Pointer == other.Pointer; + } + + /// + public override int GetHashCode() + { + return Pointer.GetHashCode(); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool operator ==(CStringWide left, CStringWide right) + { + return left.Pointer == right.Pointer; + } + + /// + /// Returns a value that indicates whether two specified structures are not equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are not equal; otherwise, false. + public static bool operator !=(CStringWide left, CStringWide right) + { + return !(left == right); + } + + /// + /// Returns a value that indicates whether two specified structures are equal. + /// + /// The first to compare. + /// The second to compare. + /// true if and are equal; otherwise, false. + public static bool Equals(CStringWide left, CStringWide right) + { + return left.Pointer == right.Pointer; + } +} diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.gen.cs b/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.gen.cs deleted file mode 100644 index bf234ebd..00000000 --- a/src/cs/examples/helloworld/helloworld-app/Generated/Runtime.gen.cs +++ /dev/null @@ -1,768 +0,0 @@ - -// To disable generating this file set `isEnabledGeneratingRuntimeCode` to `false` in the config file for generating C# code. - -// -// This code was generated by the following tool on 2024-04-10 18:55:28 GMT-04:00: -// https://github.com/bottlenoselabs/c2cs (v0.0.0.0) -// -// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. -// -// ReSharper disable All - -#region Template -#nullable enable -#pragma warning disable CS1591 -#pragma warning disable CS8981 -using bottlenoselabs.C2CS.Runtime; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -#endregion - -namespace bottlenoselabs.C2CS.Runtime -{ - - /// - /// A boolean value type with the same memory layout as a in both managed and unmanaged contexts; - /// equivalent to a standard bool found in C/C++/ObjC where 0 is false and any other value is - /// true. - /// - [StructLayout(LayoutKind.Sequential)] - public readonly struct CBool : IEquatable - { - public readonly byte Value; - - private CBool(bool value) - { - Value = Convert.ToByte(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static implicit operator CBool(bool value) - { - return FromBoolean(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static CBool FromBoolean(bool value) - { - return new CBool(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static implicit operator bool(CBool value) - { - return ToBoolean(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static bool ToBoolean(CBool value) - { - return Convert.ToBoolean(value.Value); - } - - /// - public override string ToString() - { - return ToBoolean(this).ToString(); - } - - /// - public override bool Equals(object? obj) - { - return obj is CBool b && Equals(b); - } - - /// - public bool Equals(CBool other) - { - return Value == other.Value; - } - - /// - public override int GetHashCode() - { - return Value.GetHashCode(); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool operator ==(CBool left, CBool right) - { - return left.Value == right.Value; - } - - /// - /// Returns a value that indicates whether two specified structures are not equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are not equal; otherwise, false. - public static bool operator !=(CBool left, CBool right) - { - return !(left == right); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool Equals(CBool left, CBool right) - { - return left.Value == right.Value; - } - } - - /// - /// A value type with the same memory layout as a in a managed context and char in - /// an unmanaged context. - /// - [StructLayout(LayoutKind.Sequential)] - public readonly struct CChar : IEquatable, IEquatable - { - public readonly byte Value; - - private CChar(byte value) - { - Value = Convert.ToByte(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static implicit operator CChar(byte value) - { - return FromByte(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static CChar FromByte(byte value) - { - return new CChar(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static implicit operator byte(CChar value) - { - return ToByte(value); - } - - /// - /// Converts the specified to a . - /// - /// The value. - /// A . - public static byte ToByte(CChar value) - { - return value.Value; - } - - /// - public override string ToString() - { - return Value.ToString(CultureInfo.InvariantCulture); - } - - /// - public override bool Equals(object? obj) - { - return obj is CChar value && Equals(value); - } - - /// - public bool Equals(byte other) - { - return Value == other; - } - - /// - public bool Equals(CChar other) - { - return Value == other.Value; - } - - /// - public override int GetHashCode() - { - return Value.GetHashCode(); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool operator ==(CChar left, CChar right) - { - return left.Value == right.Value; - } - - /// - /// Returns a value that indicates whether two specified structures are not equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are not equal; otherwise, false. - public static bool operator !=(CChar left, CChar right) - { - return !(left == right); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool Equals(CChar left, CChar right) - { - return left.Value == right.Value; - } - } - - /// - /// A pointer value type of bytes that represent a string; the C type `char*`. - /// - [StructLayout(LayoutKind.Sequential)] - public readonly unsafe struct CString : IEquatable, IDisposable - { - public readonly nint Pointer; - - /// - /// Gets a value indicating whether this is a null pointer. - /// - public bool IsNull => Pointer == 0; - - /// - /// Initializes a new instance of the struct. - /// - /// The pointer value. - public CString(byte* value) - { - Pointer = (nint)value; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The pointer value. - public CString(nint value) - { - Pointer = value; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The string value. - public CString(string s) - { - Pointer = FromString(s).Pointer; - } - - /// - /// Attempts to free the memory pointed by the . - /// - public void Dispose() - { - Marshal.FreeHGlobal(Pointer); - } - - /// - /// Performs an explicit conversion from an to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static explicit operator CString(nint value) - { - return FromIntPtr(value); - } - - /// - /// Performs an explicit conversion from an to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static CString FromIntPtr(nint value) - { - return new CString(value); - } - - /// - /// Performs an implicit conversion from a byte pointer to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static implicit operator CString(byte* value) - { - return From(value); - } - - /// - /// Performs an implicit conversion from a byte pointer to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static CString From(byte* value) - { - return new CString((nint)value); - } - - /// - /// Performs an implicit conversion from a to a . - /// - /// The pointer. - /// - /// The resulting . - /// - public static implicit operator nint(CString value) - { - return value.Pointer; - } - - /// - /// Performs an implicit conversion from a to a . - /// - /// The pointer. - /// - /// The resulting . - /// - public static nint ToIntPtr(CString value) - { - return value.Pointer; - } - - /// - /// Performs an explicit conversion from a to a . - /// - /// The . - /// - /// The resulting . - /// - public static explicit operator string(CString value) - { - return ToString(value); - } - - /// - /// Converts a C style string (ANSI or UTF-8) of type `char` (one dimensional byte array - /// terminated by a 0x0) to a UTF-16 by allocating and copying. - /// - /// A pointer to the C string. - /// A equivalent of . - public static string ToString(CString value) - { - if (value.IsNull) - { - return string.Empty; - } - - // calls ASM/C/C++ functions to calculate length and then "FastAllocate" the string with the GC - // https://mattwarren.org/2016/05/31/Strings-and-the-CLR-a-Special-Relationship/ - var result = Marshal.PtrToStringAnsi(value.Pointer); - - if (string.IsNullOrEmpty(result)) - { - return string.Empty; - } - - return result; - } - - /// - /// Performs an explicit conversion from a to a . - /// - /// The . - /// - /// The resulting . - /// - public static explicit operator CString(string s) - { - return FromString(s); - } - - /// - /// Converts a UTF-16 to a C style string (one dimensional byte array terminated by a - /// 0x0) by allocating and copying. - /// - /// The . - /// A C string pointer. - public static CString FromString(string str) - { - var pointer = Marshal.StringToHGlobalAnsi(str); - return new CString(pointer); - } - - /// - public override string ToString() - { - return ToString(this); - } - - /// - public override bool Equals(object? obj) - { - return obj is CString value && Equals(value); - } - - /// - public bool Equals(CString other) - { - return Pointer == other.Pointer; - } - - /// - public override int GetHashCode() - { - return Pointer.GetHashCode(); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool operator ==(CString left, CString right) - { - return left.Pointer == right.Pointer; - } - - /// - /// Returns a value that indicates whether two specified structures are not equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are not equal; otherwise, false. - public static bool operator !=(CString left, CString right) - { - return !(left == right); - } - } - - /// - /// Utility methods for interoperability with C style strings in C#. - /// - public static unsafe class CStrings - { - /// - /// Converts an array of strings to an array of C strings of type `char` (multi-dimensional array of one - /// dimensional byte arrays each terminated by a 0x0) by allocating and copying if not already cached. - /// - /// - /// Calls . - /// - /// The strings. - /// An array pointer of C string pointers. You are responsible for freeing the returned pointer. - public static CString* CStringArray(ReadOnlySpan values) - { - var pointerSize = IntPtr.Size; - var result = (CString*)Marshal.AllocHGlobal(pointerSize * values.Length); - for (var i = 0; i < values.Length; ++i) - { - var @string = values[i]; - var cString = CString.FromString(@string); - result[i] = cString; - } - - return result; - } - - /// - /// Converts an array of strings to an array of C strings of type `wchar_t` (multi-dimensional array of one - /// dimensional ushort arrays each terminated by a 0x0) by allocating and copying if not already cached. - /// - /// - /// Calls . - /// - /// The strings. - /// An array pointer of C string pointers. You are responsible for freeing the returned pointer. - public static CStringWide* CStringWideArray(ReadOnlySpan values) - { - var pointerSize = IntPtr.Size; - var result = (CStringWide*)Marshal.AllocHGlobal(pointerSize * values.Length); - for (var i = 0; i < values.Length; ++i) - { - var @string = values[i]; - var cString = CStringWide.FromString(@string); - result[i] = cString; - } - - return result; - } - } - - /// - /// A pointer value type that represents a wide string; C type `wchar_t*`. - /// - [StructLayout(LayoutKind.Sequential)] - public readonly unsafe struct CStringWide : IEquatable - { - public readonly nint Pointer; - - /// - /// Gets a value indicating whether this is a null pointer. - /// - public bool IsNull => Pointer == 0; - - /// - /// Initializes a new instance of the struct. - /// - /// The pointer value. - public CStringWide(byte* value) - { - Pointer = (nint)value; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The pointer value. - public CStringWide(nint value) - { - Pointer = value; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The string value. - public CStringWide(string s) - { - Pointer = FromString(s).Pointer; - } - - /// - /// Performs an explicit conversion from a to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static explicit operator CStringWide(nint value) - { - return FromIntPtr(value); - } - - /// - /// Performs an explicit conversion from a to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static CStringWide FromIntPtr(nint value) - { - return new CStringWide(value); - } - - /// - /// Performs an implicit conversion from a byte pointer to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static implicit operator CStringWide(byte* value) - { - return From(value); - } - - /// - /// Performs an implicit conversion from a byte pointer to a . - /// - /// The pointer value. - /// - /// The resulting . - /// - public static CStringWide From(byte* value) - { - return new CStringWide((nint)value); - } - - /// - /// Performs an implicit conversion from a to a . - /// - /// The pointer. - /// - /// The resulting . - /// - public static implicit operator nint(CStringWide value) - { - return value.Pointer; - } - - /// - /// Performs an implicit conversion from a to a . - /// - /// The pointer. - /// - /// The resulting . - /// - public static nint ToIntPtr(CStringWide value) - { - return value.Pointer; - } - - /// - /// Performs an explicit conversion from a to a . - /// - /// The . - /// - /// The resulting . - /// - public static explicit operator string(CStringWide value) - { - return ToString(value); - } - - /// - /// Converts a C style string (unicode) of type `wchar_t` (one dimensional ushort array - /// terminated by a 0x0) to a UTF-16 by allocating and copying. - /// - /// A pointer to the C string. - /// A equivalent of . - public static string ToString(CStringWide value) - { - if (value.IsNull) - { - return string.Empty; - } - - // calls ASM/C/C++ functions to calculate length and then "FastAllocate" the string with the GC - // https://mattwarren.org/2016/05/31/Strings-and-the-CLR-a-Special-Relationship/ - var result = Marshal.PtrToStringUni(value.Pointer); - - if (string.IsNullOrEmpty(result)) - { - return string.Empty; - } - - return result; - } - - /// - /// Performs an explicit conversion from a to a . - /// - /// The . - /// - /// The resulting . - /// - public static explicit operator CStringWide(string s) - { - return FromString(s); - } - - /// - /// Converts a C string pointer (one dimensional byte array terminated by a - /// 0x0) for a specified by allocating and copying if not already cached. - /// - /// The . - /// A C string pointer. - public static CStringWide FromString(string str) - { - var pointer = Marshal.StringToHGlobalUni(str); - return new CStringWide(pointer); - } - - /// - public override string ToString() - { - return ToString(this); - } - - /// - public override bool Equals(object? obj) - { - return obj is CStringWide value && Equals(value); - } - - /// - public bool Equals(CStringWide other) - { - return Pointer == other.Pointer; - } - - /// - public override int GetHashCode() - { - return Pointer.GetHashCode(); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool operator ==(CStringWide left, CStringWide right) - { - return left.Pointer == right.Pointer; - } - - /// - /// Returns a value that indicates whether two specified structures are not equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are not equal; otherwise, false. - public static bool operator !=(CStringWide left, CStringWide right) - { - return !(left == right); - } - - /// - /// Returns a value that indicates whether two specified structures are equal. - /// - /// The first to compare. - /// The second to compare. - /// true if and are equal; otherwise, false. - public static bool Equals(CStringWide left, CStringWide right) - { - return left.Pointer == right.Pointer; - } - } -} diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs deleted file mode 100644 index b2e946cf..00000000 --- a/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -namespace my_c_library_namespace -{ - public static unsafe partial class my_c_library - { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_hello_world", ExactSpelling = true)] - public static extern partial void hw_hello_world(); - } -} -namespace my_c_library_namespace -{ - public static unsafe partial class my_c_library - { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_invoke_callback", ExactSpelling = true)] - public static extern partial void hw_invoke_callback(global::my_c_library_namespace.my_c_library.FnPtr_CString_Void f, global::bottlenoselabs.C2CS.Runtime.CString s); - } -} -namespace my_c_library_namespace -{ - public static unsafe partial class my_c_library - { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_enum", ExactSpelling = true)] - public static extern partial void hw_pass_enum(global::my_c_library_namespace.my_c_library.hw_my_enum_week_day e); - } -} -namespace my_c_library_namespace -{ - public static unsafe partial class my_c_library - { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_integers_by_reference", ExactSpelling = true)] - public static extern partial void hw_pass_integers_by_reference(ushort* a, int* b, ulong* c); - } -} -namespace my_c_library_namespace -{ - public static unsafe partial class my_c_library - { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_integers_by_value", ExactSpelling = true)] - public static extern partial void hw_pass_integers_by_value(ushort a, int b, ulong c); - } -} -namespace my_c_library_namespace -{ - public static unsafe partial class my_c_library - { - [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_string", ExactSpelling = true)] - public static extern partial void hw_pass_string(global::bottlenoselabs.C2CS.Runtime.CString s); - } -} diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs index 8a64b632..f0ab6bf7 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs @@ -1,6 +1,6 @@ // -// This code was generated by the following tool on 2024-04-10 18:55:28 GMT-04:00: +// This code was generated by the following tool on 2024-05-07 16:36:40 GMT-04:00: // https://github.com/bottlenoselabs/c2cs (v0.0.0.0) // // Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. @@ -11,7 +11,7 @@ #nullable enable #pragma warning disable CS1591 #pragma warning disable CS8981 -using bottlenoselabs.C2CS.Runtime; +using Bindgen.Runtime; using System; using System.Collections.Generic; using System.Globalization; @@ -19,61 +19,56 @@ using System.Runtime.CompilerServices; #endregion -namespace my_c_library_namespace +public static unsafe partial class my_c_library { + private const string LibraryName = "my_c_library"; - public static unsafe partial class my_c_library - { - private const string LibraryName = "my_c_library"; - - #region API - - [LibraryImport(LibraryName, EntryPoint = "hw_hello_world")] - [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_hello_world(); + #region API - [LibraryImport(LibraryName, EntryPoint = "hw_invoke_callback")] - [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_invoke_callback(FnPtr_CString_Void f, CString s); + [LibraryImport(LibraryName, EntryPoint = "hw_hello_world")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_hello_world(); - [LibraryImport(LibraryName, EntryPoint = "hw_pass_enum")] - [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_enum(hw_my_enum_week_day e); + [LibraryImport(LibraryName, EntryPoint = "hw_invoke_callback")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_invoke_callback(FnPtr_CString_Void f, CString s); - [LibraryImport(LibraryName, EntryPoint = "hw_pass_integers_by_reference")] - [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_integers_by_reference(ushort* a, int* b, ulong* c); + [LibraryImport(LibraryName, EntryPoint = "hw_pass_enum")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_enum(hw_my_enum_week_day e); - [LibraryImport(LibraryName, EntryPoint = "hw_pass_integers_by_value")] - [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_integers_by_value(ushort a, int b, ulong c); + [LibraryImport(LibraryName, EntryPoint = "hw_pass_integers_by_reference")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_integers_by_reference(ushort* a, int* b, ulong* c); - [LibraryImport(LibraryName, EntryPoint = "hw_pass_string")] - [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] - public static partial void hw_pass_string(CString s); + [LibraryImport(LibraryName, EntryPoint = "hw_pass_integers_by_value")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_integers_by_value(ushort a, int b, ulong c); - #endregion + [LibraryImport(LibraryName, EntryPoint = "hw_pass_string")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void hw_pass_string(CString s); - #region Types + #endregion - [StructLayout(LayoutKind.Sequential)] - public struct FnPtr_CString_Void - { - public delegate* unmanaged Pointer; - } + #region Types - public enum hw_my_enum_week_day : int - { - HW_MY_ENUM_WEEK_DAY_UNKNOWN = 0, - HW_MY_ENUM_WEEK_DAY_MONDAY = 1, - HW_MY_ENUM_WEEK_DAY_TUESDAY = 2, - HW_MY_ENUM_WEEK_DAY_WEDNESDAY = 3, - HW_MY_ENUM_WEEK_DAY_THURSDAY = 4, - HW_MY_ENUM_WEEK_DAY_FRIDAY = 5, - _HW_MY_ENUM_WEEK_DAY_FORCE_U32 = 2147483647 - } + [StructLayout(LayoutKind.Sequential)] + public struct FnPtr_CString_Void + { + public delegate* unmanaged Pointer; + } - #endregion + public enum hw_my_enum_week_day : int + { + HW_MY_ENUM_WEEK_DAY_UNKNOWN = 0, + HW_MY_ENUM_WEEK_DAY_MONDAY = 1, + HW_MY_ENUM_WEEK_DAY_TUESDAY = 2, + HW_MY_ENUM_WEEK_DAY_WEDNESDAY = 3, + HW_MY_ENUM_WEEK_DAY_THURSDAY = 4, + HW_MY_ENUM_WEEK_DAY_FRIDAY = 5, + _HW_MY_ENUM_WEEK_DAY_FORCE_U32 = 2147483647 } + #endregion } diff --git a/src/cs/examples/helloworld/helloworld-app/Program.cs b/src/cs/examples/helloworld/helloworld-app/Program.cs index 8ed5c6a9..5a85aa51 100644 --- a/src/cs/examples/helloworld/helloworld-app/Program.cs +++ b/src/cs/examples/helloworld/helloworld-app/Program.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; -using bottlenoselabs.C2CS.Runtime; +using Bindgen.Runtime; using static my_c_library_namespace.my_c_library; internal static class Program diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/Program.cs b/src/cs/examples/helloworld/helloworld-bindgen/Program.cs similarity index 97% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/Program.cs rename to src/cs/examples/helloworld/helloworld-bindgen/Program.cs index 059af49d..ce732ba2 100644 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/Program.cs +++ b/src/cs/examples/helloworld/helloworld-bindgen/Program.cs @@ -53,7 +53,7 @@ private static bool GenerateBindingsCSharp(string sourceDirectoryPath) return false; } - var configGenerateCSharpCodeFilePath = Path.GetFullPath(Path.Combine(sourceDirectoryPath, "config-generate-cs.json")); + var configGenerateCSharpCodeFilePath = Path.GetFullPath(Path.Combine(sourceDirectoryPath, "config-generate-cs-net80.json")); var parametersGenerateCSharpCode = new[] { "generate", "--config", configGenerateCSharpCodeFilePath }; C2CS.Program.Main(parametersGenerateCSharpCode); diff --git a/src/cs/examples/helloworld/helloworld-bindgen/config-build-c-library.json b/src/cs/examples/helloworld/helloworld-bindgen/config-build-c-library.json new file mode 100644 index 00000000..8452e0d8 --- /dev/null +++ b/src/cs/examples/helloworld/helloworld-bindgen/config-build-c-library.json @@ -0,0 +1,4 @@ +{ + "cMakeDirectoryPath": "./my_c_library", + "outputDirectoryPath": "../../helloworld/helloworld-app/" +} diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-extract.json b/src/cs/examples/helloworld/helloworld-bindgen/config-extract.json similarity index 100% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-extract.json rename to src/cs/examples/helloworld/helloworld-bindgen/config-extract.json diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-generate-cs.json b/src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json similarity index 54% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-generate-cs.json rename to src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json index 18bf9aef..ea224d5f 100644 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-generate-cs.json +++ b/src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json @@ -1,8 +1,6 @@ { "inputFilePath": "./ffi-x/cross-platform.json", "outputFileDirectory": "./../helloworld-app/Generated", - "namespaceName": "my_c_library_namespace", "className": "my_c_library", - "isEnabledFileScopedNamespace": false, - "isEnabledLibraryImport": true + "targetFramework": "net8.0" } diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/helloworld-compile-c-library-and-generate-bindings.csproj b/src/cs/examples/helloworld/helloworld-bindgen/helloworld-bindgen.csproj similarity index 88% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/helloworld-compile-c-library-and-generate-bindings.csproj rename to src/cs/examples/helloworld/helloworld-bindgen/helloworld-bindgen.csproj index 3351fbdf..fa332e56 100644 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/helloworld-compile-c-library-and-generate-bindings.csproj +++ b/src/cs/examples/helloworld/helloworld-bindgen/helloworld-bindgen.csproj @@ -9,6 +9,7 @@ true false false + helloworld-compile-c-library-and-generate-bindings diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/CMakeLists.txt b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/CMakeLists.txt similarity index 100% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/CMakeLists.txt rename to src/cs/examples/helloworld/helloworld-bindgen/my_c_library/CMakeLists.txt diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h similarity index 70% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h rename to src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h index 197107f6..caca0a14 100644 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h +++ b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/include/my_c_library.h @@ -2,10 +2,14 @@ #include -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) - #define MY_C_LIBRARY_API_DECL __declspec(dllexport) +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + #if defined(__clang__) + #define MY_C_LIBRARY_API_DECL __declspec(dllexport) __attribute__ ((visibility("default"))) + #else + #define MY_C_LIBRARY_API_DECL __declspec(dllexport) + #endif #else - #define MY_C_LIBRARY_API_DECL extern + #define MY_C_LIBRARY_API_DECL extern __attribute__ ((visibility("default"))) #endif typedef enum hw_my_enum_week_day { diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/src/my_c_library.c b/src/cs/examples/helloworld/helloworld-bindgen/my_c_library/src/my_c_library.c similarity index 100% rename from src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/src/my_c_library.c rename to src/cs/examples/helloworld/helloworld-bindgen/my_c_library/src/my_c_library.c diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-build-c-library.json b/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-build-c-library.json deleted file mode 100644 index a29a1a07..00000000 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/config-build-c-library.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "cMakeDirectoryPath": "./my_c_library", - "outputDirectoryPath": "../../hello-world/helloworld-app/" -} diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi-x/cross-platform.json b/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi-x/cross-platform.json deleted file mode 100644 index 3ef9fc16..00000000 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi-x/cross-platform.json +++ /dev/null @@ -1,308 +0,0 @@ -{ - "platforms": [ - "aarch64-apple-darwin", - "x86_64-apple-darwin" - ], - "macroObjects": {}, - "variables": {}, - "functions": { - "hw_hello_world": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [] - }, - "hw_invoke_callback": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [ - { - "name": "f", - "type": { - "name": "void (const char *)", - "kind": "functionPointer", - "size_of": 1, - "align_of": 4 - } - }, - { - "name": "s", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1 - } - } - } - ] - }, - "hw_pass_enum": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [ - { - "name": "e", - "type": { - "name": "hw_my_enum_week_day", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "inner_type": { - "name": "enum hw_my_enum_week_day", - "kind": "enum", - "size_of": 4, - "align_of": 4 - } - } - } - ] - }, - "hw_pass_integers_by_reference": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [ - { - "name": "a", - "type": { - "name": "const uint16_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "uint16_t", - "kind": "typeAlias", - "size_of": 2, - "align_of": 2, - "inner_type": { - "name": "unsigned short", - "kind": "primitive", - "size_of": 2, - "align_of": 2 - } - } - } - }, - { - "name": "b", - "type": { - "name": "const int32_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "int32_t", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "inner_type": { - "name": "int", - "kind": "primitive", - "size_of": 4, - "align_of": 4 - } - } - } - }, - { - "name": "c", - "type": { - "name": "const uint64_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "uint64_t", - "kind": "typeAlias", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "unsigned long long", - "kind": "primitive", - "size_of": 8, - "align_of": 8 - } - } - } - } - ] - }, - "hw_pass_integers_by_value": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [ - { - "name": "a", - "type": { - "name": "uint16_t", - "kind": "typeAlias", - "size_of": 2, - "align_of": 2, - "inner_type": { - "name": "unsigned short", - "kind": "primitive", - "size_of": 2, - "align_of": 2 - } - } - }, - { - "name": "b", - "type": { - "name": "int32_t", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "inner_type": { - "name": "int", - "kind": "primitive", - "size_of": 4, - "align_of": 4 - } - } - }, - { - "name": "c", - "type": { - "name": "uint64_t", - "kind": "typeAlias", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "unsigned long long", - "kind": "primitive", - "size_of": 8, - "align_of": 8 - } - } - } - ] - }, - "hw_pass_string": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [ - { - "name": "s", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1 - } - } - } - ] - } - }, - "records": {}, - "enums": { - "enum hw_my_enum_week_day": { - "size_of": 4, - "values": [ - { - "name": "HW_MY_ENUM_WEEK_DAY_UNKNOWN" - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_MONDAY", - "value": 1 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_TUESDAY", - "value": 2 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_WEDNESDAY", - "value": 3 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_THURSDAY", - "value": 4 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_FRIDAY", - "value": 5 - }, - { - "name": "_HW_MY_ENUM_WEEK_DAY_FORCE_U32", - "value": 2147483647 - } - ] - } - }, - "typeAliases": { - "hw_my_enum_week_day": { - "underlyingType": { - "name": "enum hw_my_enum_week_day", - "kind": "enum", - "size_of": 4, - "align_of": 4 - } - } - }, - "opaqueTypes": {}, - "functionPointers": { - "void (const char *)": { - "type": { - "name": "void (const char *)", - "kind": "functionPointer", - "size_of": 1, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "return_type": { - "name": "void", - "kind": "primitive" - }, - "parameters": [ - { - "name": "", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1 - } - } - } - ], - "CallingConvention": "cdecl" - } - } -} \ No newline at end of file diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/aarch64-apple-darwin.json b/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/aarch64-apple-darwin.json deleted file mode 100644 index 7d2f207b..00000000 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/aarch64-apple-darwin.json +++ /dev/null @@ -1,600 +0,0 @@ -{ - "fileName": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "platformRequested": "aarch64-apple-darwin", - "platformActual": "arm64-apple-macosx13.0.0", - "systemIncludeDirectories": [ - "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.3/include", - "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include" - ], - "userIncludeDirectories": [ - "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include" - ], - "pointerSize": 8, - "macroObjects": {}, - "variables": {}, - "functions": { - "hw_hello_world": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 21, - "column": 28 - } - }, - "hw_invoke_callback": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "f", - "type": { - "name": "void (const char *)", - "kind": "functionPointer", - "size_of": 1, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - { - "name": "s", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 22, - "column": 28 - } - }, - "hw_pass_enum": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "e", - "type": { - "name": "hw_my_enum_week_day", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 19, - "column": 3 - }, - "inner_type": { - "name": "enum hw_my_enum_week_day", - "kind": "enum", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 11, - "column": 14 - } - } - }, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 19, - "column": 3 - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 26, - "column": 28 - } - }, - "hw_pass_integers_by_reference": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "a", - "type": { - "name": "const uint16_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "uint16_t", - "kind": "typeAlias", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "_uint16_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint16_t.h", - "line": 31, - "column": 24, - "isSystem": true - }, - "inner_type": { - "name": "unsigned short", - "kind": "primitive", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - { - "name": "b", - "type": { - "name": "const int32_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "int32_t", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "_int32_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/sys/_types/_int32_t.h", - "line": 30, - "column": 33, - "isSystem": true - }, - "inner_type": { - "name": "int", - "kind": "primitive", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - { - "name": "c", - "type": { - "name": "const uint64_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "uint64_t", - "kind": "typeAlias", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "_uint64_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint64_t.h", - "line": 31, - "column": 28, - "isSystem": true - }, - "inner_type": { - "name": "unsigned long long", - "kind": "primitive", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 25, - "column": 28 - } - }, - "hw_pass_integers_by_value": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "a", - "type": { - "name": "uint16_t", - "kind": "typeAlias", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "_uint16_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint16_t.h", - "line": 31, - "column": 24, - "isSystem": true - }, - "inner_type": { - "name": "unsigned short", - "kind": "primitive", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "_uint16_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint16_t.h", - "line": 31, - "column": 24, - "isSystem": true - } - }, - { - "name": "b", - "type": { - "name": "int32_t", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "_int32_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/sys/_types/_int32_t.h", - "line": 30, - "column": 33, - "isSystem": true - }, - "inner_type": { - "name": "int", - "kind": "primitive", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "_int32_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/sys/_types/_int32_t.h", - "line": 30, - "column": 33, - "isSystem": true - } - }, - { - "name": "c", - "type": { - "name": "uint64_t", - "kind": "typeAlias", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "_uint64_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint64_t.h", - "line": 31, - "column": 28, - "isSystem": true - }, - "inner_type": { - "name": "unsigned long long", - "kind": "primitive", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "_uint64_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint64_t.h", - "line": 31, - "column": 28, - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 24, - "column": 28 - } - }, - "hw_pass_string": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "s", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 23, - "column": 28 - } - } - }, - "records": {}, - "enums": { - "enum hw_my_enum_week_day": { - "size_of": 4, - "values": [ - { - "name": "HW_MY_ENUM_WEEK_DAY_UNKNOWN" - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_MONDAY", - "value": 1 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_TUESDAY", - "value": 2 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_WEDNESDAY", - "value": 3 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_THURSDAY", - "value": 4 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_FRIDAY", - "value": 5 - }, - { - "name": "_HW_MY_ENUM_WEEK_DAY_FORCE_U32", - "value": 2147483647 - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 11, - "column": 14 - } - } - }, - "typeAliases": { - "hw_my_enum_week_day": { - "underlyingType": { - "name": "enum hw_my_enum_week_day", - "kind": "enum", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 11, - "column": 14 - } - }, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 19, - "column": 3 - } - } - }, - "opaqueTypes": {}, - "functionPointers": { - "void (const char *)": { - "type": { - "name": "void (const char *)", - "kind": "functionPointer", - "size_of": 1, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - } - ], - "CallingConvention": "cdecl", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } -} \ No newline at end of file diff --git a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/x86_64-apple-darwin.json b/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/x86_64-apple-darwin.json deleted file mode 100644 index 281ff886..00000000 --- a/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/ffi/x86_64-apple-darwin.json +++ /dev/null @@ -1,600 +0,0 @@ -{ - "fileName": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "platformRequested": "x86_64-apple-darwin", - "platformActual": "x86_64-apple-macosx13.0.0", - "systemIncludeDirectories": [ - "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.3/include", - "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include" - ], - "userIncludeDirectories": [ - "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include" - ], - "pointerSize": 8, - "macroObjects": {}, - "variables": {}, - "functions": { - "hw_hello_world": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 21, - "column": 28 - } - }, - "hw_invoke_callback": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "f", - "type": { - "name": "void (const char *)", - "kind": "functionPointer", - "size_of": 1, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - { - "name": "s", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 22, - "column": 28 - } - }, - "hw_pass_enum": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "e", - "type": { - "name": "hw_my_enum_week_day", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 19, - "column": 3 - }, - "inner_type": { - "name": "enum hw_my_enum_week_day", - "kind": "enum", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 11, - "column": 14 - } - } - }, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 19, - "column": 3 - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 26, - "column": 28 - } - }, - "hw_pass_integers_by_reference": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "a", - "type": { - "name": "const uint16_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "uint16_t", - "kind": "typeAlias", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "_uint16_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint16_t.h", - "line": 31, - "column": 24, - "isSystem": true - }, - "inner_type": { - "name": "unsigned short", - "kind": "primitive", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - { - "name": "b", - "type": { - "name": "const int32_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "int32_t", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "_int32_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/sys/_types/_int32_t.h", - "line": 30, - "column": 33, - "isSystem": true - }, - "inner_type": { - "name": "int", - "kind": "primitive", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - { - "name": "c", - "type": { - "name": "const uint64_t *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "uint64_t", - "kind": "typeAlias", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "_uint64_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint64_t.h", - "line": 31, - "column": 28, - "isSystem": true - }, - "inner_type": { - "name": "unsigned long long", - "kind": "primitive", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 25, - "column": 28 - } - }, - "hw_pass_integers_by_value": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "a", - "type": { - "name": "uint16_t", - "kind": "typeAlias", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "_uint16_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint16_t.h", - "line": 31, - "column": 24, - "isSystem": true - }, - "inner_type": { - "name": "unsigned short", - "kind": "primitive", - "size_of": 2, - "align_of": 2, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "_uint16_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint16_t.h", - "line": 31, - "column": 24, - "isSystem": true - } - }, - { - "name": "b", - "type": { - "name": "int32_t", - "kind": "typeAlias", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "_int32_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/sys/_types/_int32_t.h", - "line": 30, - "column": 33, - "isSystem": true - }, - "inner_type": { - "name": "int", - "kind": "primitive", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "_int32_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/sys/_types/_int32_t.h", - "line": 30, - "column": 33, - "isSystem": true - } - }, - { - "name": "c", - "type": { - "name": "uint64_t", - "kind": "typeAlias", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "_uint64_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint64_t.h", - "line": 31, - "column": 28, - "isSystem": true - }, - "inner_type": { - "name": "unsigned long long", - "kind": "primitive", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "_uint64_t.h", - "filePath": "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/usr/include/_types/_uint64_t.h", - "line": 31, - "column": 28, - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 24, - "column": 28 - } - }, - "hw_pass_string": { - "calling_convention": "cdecl", - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "s", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - }, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 23, - "column": 28 - } - } - }, - "records": {}, - "enums": { - "enum hw_my_enum_week_day": { - "size_of": 4, - "values": [ - { - "name": "HW_MY_ENUM_WEEK_DAY_UNKNOWN" - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_MONDAY", - "value": 1 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_TUESDAY", - "value": 2 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_WEDNESDAY", - "value": 3 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_THURSDAY", - "value": 4 - }, - { - "name": "HW_MY_ENUM_WEEK_DAY_FRIDAY", - "value": 5 - }, - { - "name": "_HW_MY_ENUM_WEEK_DAY_FORCE_U32", - "value": 2147483647 - } - ], - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 11, - "column": 14 - } - } - }, - "typeAliases": { - "hw_my_enum_week_day": { - "underlyingType": { - "name": "enum hw_my_enum_week_day", - "kind": "enum", - "size_of": 4, - "align_of": 4, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 11, - "column": 14 - } - }, - "location": { - "fileName": "my_c_library.h", - "filePath": "/Users/lstranks/Programming/bottlenoselabs/c2cs/src/cs/examples/helloworld/helloworld-compile-c-library-and-generate-bindings/my_c_library/include/my_c_library.h", - "line": 19, - "column": 3 - } - } - }, - "opaqueTypes": {}, - "functionPointers": { - "void (const char *)": { - "type": { - "name": "void (const char *)", - "kind": "functionPointer", - "size_of": 1, - "align_of": 4, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "return_type": { - "name": "void", - "kind": "primitive", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - }, - "parameters": [ - { - "name": "", - "type": { - "name": "const char *", - "kind": "pointer", - "size_of": 8, - "align_of": 8, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - }, - "inner_type": { - "name": "const char", - "kind": "primitive", - "size_of": 1, - "align_of": 1, - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } - } - ], - "CallingConvention": "cdecl", - "location": { - "fileName": "", - "filePath": "", - "isSystem": true - } - } - } -} \ No newline at end of file diff --git a/src/cs/production/C2CS.Tool/C2CS.Tool.csproj b/src/cs/production/C2CS.Tool/C2CS.Tool.csproj index ca59a248..9a5eea18 100644 --- a/src/cs/production/C2CS.Tool/C2CS.Tool.csproj +++ b/src/cs/production/C2CS.Tool/C2CS.Tool.csproj @@ -35,6 +35,7 @@ + diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs index a2512d36..be2d49a9 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGenerator.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Globalization; using System.IO; +using System.Linq; using System.Reflection; using bottlenoselabs.Common.Diagnostics; using C2CS.Commands.WriteCodeCSharp.Data; @@ -54,11 +55,8 @@ public CSharpCodeGenerator( documentsBuilder.Add(runtimeCodeDocument); } - if (_options.IsEnabledGenerateAssemblyAttributes) - { - var assemblyAttributesCodeDocument = EmitAssemblyAttributesCodeDocument(); - documentsBuilder.Add(assemblyAttributesCodeDocument); - } + var assemblyAttributesCodeDocument = EmitAssemblyAttributesCodeDocument(); + documentsBuilder.Add(assemblyAttributesCodeDocument); var project = new CSharpProject { @@ -78,20 +76,26 @@ public CSharpCodeGenerator( private CSharpProjectDocument EmitAssemblyAttributesCodeDocument() { - var code = "// To disable generating this file set `isEnabledGenerateAssemblyAttributes` to `false` in the config file for generating C# code." - + CodeDocumentTemplate(); + var code = CodeDocumentTemplate(); - code += """ + if (!_options.IsEnabledRuntimeMarshalling) + { + code += """ - #if NET7_0_OR_GREATER - [assembly: DisableRuntimeMarshalling] - #endif + #if NET7_0_OR_GREATER + // NOTE: Disabling runtime marshalling is preferred for performance improvements. You can learn more here: https://learn.microsoft.com/en-us/dotnet/standard/native-interop/disabled-marshalling + [assembly: DisableRuntimeMarshalling] + #endif - """; + """; + } code += """ + #if (NETCOREAPP1_0_OR_GREATER) || (NET45_OR_GREATER || NETFRAMEWORK && (NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48)) || (NETSTANDARD1_1_OR_GREATER || NETSTANDARD && !NETSTANDARD1_0) + // NOTE: Only takes effect on Windows. Specifies the recommended maximum number of directories (the application directory, the %WinDir%\System32 directory, and user directories in the DLL search path) to search for native libraries. You can learn more here at (1) https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.defaultdllimportsearchpathsattribute and (2) https://learn.microsoft.com/en-ca/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa#parameters [assembly: DefaultDllImportSearchPathsAttribute(DllImportSearchPath.SafeDirectories)] + #endif """; @@ -223,26 +227,29 @@ private string CompilationUnitCode( """; } - if (options.IsEnabledFileScopedNamespace) + if (!string.IsNullOrEmpty(options.NamespaceName)) { - code += $""" + if (options.IsEnabledFileScopedNamespace) + { + code += $""" - namespace {options.NamespaceName}; + namespace {options.NamespaceName}; - """; - } - else - { - code += $$""" + """; + } + else + { + code += $$""" - namespace {{options.NamespaceName}} { + namespace {{options.NamespaceName}} { - """; + """; + } } code += $$""" - public static unsafe partial class {{options.ClassName}} + public static unsafe partial class {{options.ClassName}} { private const string LibraryName = "{{options.LibraryName}}"; } @@ -258,7 +265,7 @@ public static unsafe partial class {{options.ClassName}} """; } - if (!options.IsEnabledFileScopedNamespace) + if (!string.IsNullOrEmpty(options.NamespaceName) && !options.IsEnabledFileScopedNamespace) { code += """ @@ -269,9 +276,14 @@ public static unsafe partial class {{options.ClassName}} var syntaxTree = ParseSyntaxTree(code); var compilationUnit = syntaxTree.GetCompilationUnitRoot(); - var rootNamespace = (BaseNamespaceDeclarationSyntax)compilationUnit.Members[0]; - var rootClassDeclarationOriginal = (ClassDeclarationSyntax)rootNamespace.Members[0]; - var rootClassDeclarationWithMembers = rootClassDeclarationOriginal; + + var rootClassDeclaration = compilationUnit.DescendantNodes().OfType().FirstOrDefault(); + if (rootClassDeclaration == null) + { + throw new InvalidOperationException("Unable to find class declaration."); + } + + var rootClassDeclarationWithMembers = rootClassDeclaration; foreach (var (className, classMembers) in membersByClassName) { @@ -295,7 +307,7 @@ public static unsafe partial class {{className}} } var newCompilationUnit = compilationUnit.ReplaceNode( - rootClassDeclarationOriginal, + rootClassDeclaration, rootClassDeclarationWithMembers); var formattedCode = newCompilationUnit.GetCode(); return formattedCode; diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGeneratorOptions.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGeneratorOptions.cs index f6ba139a..2804d6ec 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGeneratorOptions.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/CSharpCodeGeneratorOptions.cs @@ -1,10 +1,14 @@ // Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved. // Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information. +using NuGet.Frameworks; + namespace C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator; public sealed class CSharpCodeGeneratorOptions { + public NuGetFramework TargetFramework { get; set; } = NuGetFramework.AgnosticFramework; + public string ClassName { get; init; } = string.Empty; public string LibraryName { get; init; } = string.Empty; @@ -15,13 +19,13 @@ public sealed class CSharpCodeGeneratorOptions public string FooterCodeRegion { get; init; } = string.Empty; - public bool IsEnabledFunctionPointers { get; init; } - public bool IsEnabledVerifyCSharpCodeCompiles { get; init; } public bool IsEnabledGenerateCSharpRuntimeCode { get; init; } - public bool IsEnabledGenerateAssemblyAttributes { get; init; } + public bool IsEnabledFunctionPointers { get; init; } + + public bool IsEnabledRuntimeMarshalling { get; init; } public bool IsEnabledLibraryImportAttribute { get; init; } diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs index 407335ff..6d41b740 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs @@ -23,7 +23,7 @@ public sealed class CSharpCodeMapper private readonly CSharpCodeMapperOptions _options; private readonly ImmutableDictionary _userTypeNameAliases; - private static readonly string[] IgnoredNames = { "FFI_PLATFORM_NAME" }; + private static readonly string[] IgnoredNames = []; private static readonly char[] IdentifierSeparatorCharacters = { '_', '.', '@' }; public CSharpCodeMapper(CSharpCodeMapperOptions options) diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Sanitized/WriteCodeCSharpInput.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Sanitized/WriteCodeCSharpInput.cs index 4ba501af..53c596fa 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Sanitized/WriteCodeCSharpInput.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Sanitized/WriteCodeCSharpInput.cs @@ -3,6 +3,7 @@ using C2CS.Commands.WriteCodeCSharp.Domain.CodeGenerator; using C2CS.Commands.WriteCodeCSharp.Domain.Mapper; +using NuGet.Frameworks; namespace C2CS.Commands.WriteCodeCSharp.Input.Sanitized; diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Unsanitized/WriteCSharpCodeInput.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Unsanitized/WriteCSharpCodeInput.cs index de132e1f..37b4fb68 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Unsanitized/WriteCSharpCodeInput.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/Unsanitized/WriteCSharpCodeInput.cs @@ -13,10 +13,10 @@ namespace C2CS.Commands.WriteCodeCSharp.Input.Unsanitized; public sealed class WriteCSharpCodeInput : ToolUnsanitizedInput { /// - /// Gets or sets the path of the input cross-platform abstract syntax tree. + /// Gets or sets the path of the input cross-platform FFI json file. /// [JsonPropertyName("inputFilePath")] - public string? InputAbstractSyntaxTreeFilePath { get; set; } + public string? InputCrossPlatformFfiFilePath { get; set; } /// /// Gets or sets the path of the output C# `.cs` file. @@ -41,7 +41,10 @@ public sealed class WriteCSharpCodeInput : ToolUnsanitizedInput /// Gets or sets the name of the namespace to be used for the C# static class. /// /// - /// Default is null. If is null, is used. + /// + /// Default is null. If is null, no namespace is explicitly used + /// and thus the default implicit global namespace 'global::' is used. + /// /// [JsonPropertyName("namespaceName")] public string? NamespaceName { get; set; } @@ -107,20 +110,13 @@ public sealed class WriteCSharpCodeInput : ToolUnsanitizedInput public ImmutableArray? IgnoredNames { get; set; } /// - /// Gets or sets whether C# 9 function pointers is enabled or C# delegates for C function pointers is enabled. + /// Gets or sets the Target Framework Moniker (TFM) used for generating C# code. /// /// - /// - /// Default is true. Use true to generate C function pointers as C# 9 function pointers. Use - /// false to fallback to generate C function pointers as C# delegates. - /// - /// - /// If you have the choice, C# delegates are not recommended in comparison to C# function pointers as they - /// require more setup, teardown, and memory allocations. - /// + /// See https://learn.microsoft.com/en-us/dotnet/standard/frameworks#latest-versions for list of valid TFMs. /// - [JsonPropertyName("isEnabledFunctionPointers")] - public bool? IsEnabledFunctionPointers { get; set; } = true; + [JsonPropertyName("targetFrameworkMoniker")] + public string? TargetFrameworkMoniker { get; set; } /// /// Gets or sets whether to verify the generated C# code compiles without warnings or errors is enabled. @@ -147,76 +143,96 @@ public sealed class WriteCSharpCodeInput : ToolUnsanitizedInput public bool? IsEnabledGeneratingRuntimeCode { get; set; } = true; /// - /// Gets or sets whether C# source code generation using - /// is enabled or - /// is enabled. + /// Gets or sets whether generating idiomatic C# is enabled. /// /// /// - /// Default is false. Use true to generate C# source code using - /// . Use false to generate C# - /// source code using . - /// - /// - /// The is only available in .NET 7. - /// The advantages of using over - /// is that source generators are used to - /// create stubs at compile time instead of runtime. This can increase performance due to IL trimming and - /// inlining; make debugging easier with cleaner stack traces; and adds support for full NativeAOT scenarios - /// where the is not available. + /// Default is false. Use true to enabled generation of idiomatic C# which includes converting + /// converting C `snake_case` names to C# `PascalCase` names. Use false to leave names as they are + /// found in C. /// /// - [JsonPropertyName("isEnabledLibraryImport")] - public bool? IsEnabledLibraryImport { get; set; } = false; + [JsonPropertyName("isEnabledIdiomaticCSharp")] + public bool? IsEnabledIdiomaticCSharp { get; set; } = false; /// - /// Gets or sets whether generating the C# assembly attribute usages at the scope of the main namespace is - /// enabled. + /// Gets or sets whether parsing enum value names as upper-case when generating idiomatic C# is enabled. /// /// /// - /// Default is true. Use true to enabled generation of assembly attributes usages which are - /// applied at the scope of the main namespace. Use false to disable generation of assembly attribute - /// usages. + /// Default is true. Use true to enable parsing of enum value names as upper-case during + /// generation of idiomatic C#. Use false to leave enum value names as they are found in C. /// /// - [JsonPropertyName("isEnabledGenerateAssemblyAttributes")] - public bool? IsEnabledGenerateAssemblyAttributes { get; set; } = true; + [JsonPropertyName("isEnabledEnumValueNamesUpperCase")] + public bool? IsEnabledEnumValueNamesUpperCase { get; set; } = true; /// - /// Gets or sets whether generating idiomatic C# is enabled. + /// Gets or sets whether function pointers are enabled for unmanaged callbacks. /// /// /// - /// Default is false. Use true to enabled generation of idiomatic C# which includes converting - /// converting C `snake_case` names to C# `PascalCase` names. Use false to leave names as they are - /// found in C. + /// Default is true when is at least .NET Core 5 or greater + /// and false otherwise. Use true to generate C# function pointers for unmanaged callbacks. + /// Use false to fallback to using C# delegates for callbacks. + /// + /// + /// If you targeting .NET Core 5 or greater, you have the choice to use function pointers or delegates. + /// However, C# delegates are not recommended in comparison to C# function pointers as they require more + /// setup, teardown, memory allocations, and a level of indirection. /// /// - [JsonPropertyName("isEnabledIdiomaticCSharp")] - public bool? IsEnabledIdiomaticCSharp { get; set; } = false; + [JsonPropertyName("isEnabledFunctionPointers")] + public bool? IsEnabledFunctionPointers { get; set; } = true; /// - /// Gets or sets whether parsing enum value names as upper-case when generating idiomatic C# is enabled. + /// Gets or sets a value indicating whether runtime marshalling is enabled. /// /// /// - /// Default is true. Use true to enable parsing of enum value names as upper-case during - /// generation of idiomatic C#. Use false to leave enum value names as they are found in C. + /// Default is false when is at least .NET Core 7 or greater + /// and true otherwise. Use true to enable runtime marshalling. Use false to disable + /// runtime marshalling. + /// + /// + /// Disabling runtime marshalling is preferred for performance as it removes any possible slow downs that + /// could happen at runtime in transforming the data types to/from the unmanaged context. For more + /// information, see https://learn.microsoft.com/en-us/dotnet/standard/native-interop/disabled-marshalling. /// /// - [JsonPropertyName("isEnabledEnumValueNamesUpperCase")] - public bool? IsEnabledEnumValueNamesUpperCase { get; set; } = true; + [JsonPropertyName("isEnabledRuntimeMarshalling")] + public bool? IsEnabledRuntimeMarshalling { get; set; } /// /// Gets or sets whether creating a C# namespace scope is enabled. /// /// /// - /// Default is true. Use true to enable file scoped namespace when generating C# code. Use + /// Default is true when is at least .NET Core 6 or greater + /// and true otherwise. Use true to enable file scoped namespace when generating C# code. Use /// false to disable file scoped namespace and fallback to traditional namespace scope. /// /// [JsonPropertyName("isEnabledFileScopedNamespace")] public bool? IsEnabledFileScopedNamespace { get; set; } = true; + + /// + /// Gets or sets whether C# source code generation using + /// is enabled or + /// is enabled. + /// + /// + /// + /// Default is true when is at least .NET Core 7 or greater + /// and false otherwise. Use true to generate C# source code using + /// . Use false to generate C# + /// source code using . + /// + /// + /// For more information see: + /// https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke-source-generation. + /// + /// + [JsonPropertyName("isEnabledLibraryImport")] + public bool? IsEnabledLibraryImport { get; set; } = true; } diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs index 22ce69ed..6cfe9f5c 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs @@ -12,6 +12,7 @@ using C2CS.Commands.WriteCodeCSharp.Domain.Mapper; using C2CS.Commands.WriteCodeCSharp.Input.Sanitized; using C2CS.Commands.WriteCodeCSharp.Input.Unsanitized; +using NuGet.Frameworks; namespace C2CS.Commands.WriteCodeCSharp.Input; @@ -26,51 +27,50 @@ public WriteCodeCSharpInputSanitizer(IFileSystem fileSystem) public override WriteCodeCSharpInput Sanitize(WriteCSharpCodeInput unsanitizedInput) { - var inputFilePath = InputFilePath(unsanitizedInput.InputAbstractSyntaxTreeFilePath); + var inputFilePath = InputFilePath(unsanitizedInput.InputCrossPlatformFfiFilePath); var outputFileDirectory = OutputFileDirectory(unsanitizedInput.OutputCSharpCodeFileDirectory); - var className = ClassName(unsanitizedInput.ClassName); - var libraryName = LibraryName(unsanitizedInput.LibraryName, className); - var namespaceName = NamespaceName(unsanitizedInput.NamespaceName, libraryName); - var mappedTypeNames = MappedNames(unsanitizedInput.MappedNames); - var ignoredNames = IgnoredTypeNames(unsanitizedInput.IgnoredNames); - var headerCodeRegion = HeaderCodeRegion(unsanitizedInput.HeaderCodeRegionFilePath); - var footerCodeRegion = FooterCodeRegion(unsanitizedInput.FooterCodeRegionFilePath); - var isEnabledFunctionPointers = unsanitizedInput.IsEnabledFunctionPointers ?? true; - var isEnabledVerifyCSharpCodeCompiles = unsanitizedInput.IsEnabledVerifyCSharpCodeCompiles ?? true; - var isEnabledGenerateCSharpRuntimeCode = unsanitizedInput.IsEnabledGeneratingRuntimeCode ?? true; - var isEnabledLibraryImportAttribute = unsanitizedInput.IsEnabledLibraryImport ?? false; - var mappedCNamespaces = MappedNames(unsanitizedInput.MappedCNamespaces); - var isEnabledGenerateAssemblyAttributes = unsanitizedInput.IsEnabledGenerateAssemblyAttributes ?? true; - var isEnabledIdiomaticCSharp = unsanitizedInput.IsEnabledIdiomaticCSharp ?? false; - var isEnabledEnumValueNamesUpperCase = unsanitizedInput.IsEnabledEnumValueNamesUpperCase ?? true; - var isEnabledFileScopedNamespace = unsanitizedInput.IsEnabledFileScopedNamespace ?? true; return new WriteCodeCSharpInput { InputFilePath = inputFilePath, OutputFileDirectory = outputFileDirectory, - MapperOptions = new CSharpCodeMapperOptions - { - MappedTypeNames = mappedTypeNames, - IgnoredNames = ignoredNames, - MappedCNamespaces = mappedCNamespaces, - IsEnabledIdiomaticCSharp = isEnabledIdiomaticCSharp, - IsEnabledEnumValueNamesUpperCase = isEnabledEnumValueNamesUpperCase - }, - GeneratorOptions = new CSharpCodeGeneratorOptions - { - ClassName = className, - LibraryName = libraryName, - NamespaceName = namespaceName, - HeaderCodeRegion = headerCodeRegion, - FooterCodeRegion = footerCodeRegion, - IsEnabledFunctionPointers = isEnabledFunctionPointers, - IsEnabledVerifyCSharpCodeCompiles = isEnabledVerifyCSharpCodeCompiles, - IsEnabledGenerateCSharpRuntimeCode = isEnabledGenerateCSharpRuntimeCode, - IsEnabledLibraryImportAttribute = isEnabledLibraryImportAttribute, - IsEnabledGenerateAssemblyAttributes = isEnabledGenerateAssemblyAttributes, - IsEnabledFileScopedNamespace = isEnabledFileScopedNamespace - } + MapperOptions = MapperOptions(unsanitizedInput), + GeneratorOptions = GeneratorOptions(unsanitizedInput) + }; + } + + private static CSharpCodeMapperOptions MapperOptions(WriteCSharpCodeInput unsanitizedInput) + { + return new CSharpCodeMapperOptions + { + MappedTypeNames = MappedNames(unsanitizedInput.MappedNames), + IgnoredNames = IgnoredTypeNames(unsanitizedInput.IgnoredNames), + MappedCNamespaces = MappedNames(unsanitizedInput.MappedCNamespaces), + IsEnabledIdiomaticCSharp = unsanitizedInput.IsEnabledIdiomaticCSharp ?? false, + IsEnabledEnumValueNamesUpperCase = unsanitizedInput.IsEnabledEnumValueNamesUpperCase ?? true + }; + } + + private CSharpCodeGeneratorOptions GeneratorOptions(WriteCSharpCodeInput unsanitizedInput) + { + var className = ClassName(unsanitizedInput.ClassName); + var libraryName = LibraryName(unsanitizedInput.LibraryName, className); + var targetFramework = TargetFramework(unsanitizedInput.TargetFrameworkMoniker); + + return new CSharpCodeGeneratorOptions + { + TargetFramework = targetFramework, + ClassName = className, + LibraryName = libraryName, + NamespaceName = NamespaceName(unsanitizedInput.NamespaceName), + HeaderCodeRegion = HeaderCodeRegion(unsanitizedInput.HeaderCodeRegionFilePath), + FooterCodeRegion = FooterCodeRegion(unsanitizedInput.FooterCodeRegionFilePath), + IsEnabledVerifyCSharpCodeCompiles = unsanitizedInput.IsEnabledVerifyCSharpCodeCompiles ?? true, + IsEnabledGenerateCSharpRuntimeCode = unsanitizedInput.IsEnabledGeneratingRuntimeCode ?? true, + IsEnabledFunctionPointers = IsEnabledFunctionPointers(unsanitizedInput, targetFramework), + IsEnabledRuntimeMarshalling = IsEnabledRuntimeMarshalling(unsanitizedInput, targetFramework), + IsEnabledFileScopedNamespace = IsEnabledFileScopedNamespace(unsanitizedInput, targetFramework), + IsEnabledLibraryImportAttribute = IsEnabledLibraryImport(unsanitizedInput, targetFramework) }; } @@ -79,7 +79,7 @@ private string InputFilePath(string? filePath) if (string.IsNullOrWhiteSpace(filePath)) { throw new ToolInputSanitizationException( - $"The abstract syntax tree input directory can not be an empty or null string."); + $"The FFI input file path can not be an empty or a null string."); } var fullFilePath = _fileSystem.Path.GetFullPath(filePath); @@ -155,9 +155,9 @@ private static string LibraryName(string? libraryName, string className) return !string.IsNullOrEmpty(libraryName) ? libraryName : className; } - private static string NamespaceName(string? @namespace, string libraryName) + private static string NamespaceName(string? @namespace) { - return !string.IsNullOrEmpty(@namespace) ? @namespace : libraryName; + return !string.IsNullOrEmpty(@namespace) ? @namespace : string.Empty; } private static string ClassName(string? className) @@ -192,4 +192,76 @@ private static string FooterCodeRegion(string? footerCodeRegionFilePath) var code = File.ReadAllText(footerCodeRegionFilePath); return code; } + + private NuGetFramework TargetFramework(string? targetFrameworkMoniker) + { + if (string.IsNullOrEmpty(targetFrameworkMoniker)) + { + targetFrameworkMoniker = "net8.0"; + } + + // NuGet uses the word "folder" for what Microsoft calls a TFM + var nuGetFramework = NuGetFramework.ParseFolder(targetFrameworkMoniker); + if (nuGetFramework.HasProfile) + { + throw new InvalidOperationException( + $"The Target Framework Moniker (TFM) '{targetFrameworkMoniker}' is not supported because it has a profile. Remove the profile from the TFM and try again."); + } + + if (nuGetFramework.HasPlatform) + { + throw new InvalidOperationException( + $"The Target Framework Moniker (TFM) '{targetFrameworkMoniker}' is not supported because it has a platform. Remove the platform parts from the TFM and try again."); + } + + return nuGetFramework; + } + + private static bool IsEnabledFunctionPointers(WriteCSharpCodeInput unsanitizedInput, NuGetFramework nuGetFramework) + { + // Function pointers are supported only in C# 9+ and .NET 5+ + var isAtLeastNetCoreV5 = nuGetFramework is { Framework: ".NETCoreApp", Version.Major: >= 5 }; + if (!isAtLeastNetCoreV5) + { + return false; + } + + return unsanitizedInput.IsEnabledFunctionPointers ?? true; + } + + private bool IsEnabledRuntimeMarshalling(WriteCSharpCodeInput unsanitizedInput, NuGetFramework nuGetFramework) + { + // Disabling runtime marshalling is only supported in .NET 7+ + var isAtLeastNetCoreV7 = nuGetFramework is { Framework: ".NETCoreApp", Version.Major: >= 7 }; + if (!isAtLeastNetCoreV7) + { + return false; + } + + return unsanitizedInput.IsEnabledRuntimeMarshalling ?? false; + } + + private static bool IsEnabledFileScopedNamespace(WriteCSharpCodeInput unsanitizedInput, NuGetFramework nuGetFramework) + { + // File scoped namespaces are only supported in .NET 6+ + var isAtLeastNetCoreV6 = nuGetFramework is { Framework: ".NETCoreApp", Version.Major: >= 6 }; + if (!isAtLeastNetCoreV6) + { + return false; + } + + return unsanitizedInput.IsEnabledFileScopedNamespace ?? true; + } + + private static bool IsEnabledLibraryImport(WriteCSharpCodeInput unsanitizedInput, NuGetFramework nuGetFramework) + { + // LibraryImport is only supported in .NET 7+ + var isAtLeastNetCoreV7 = nuGetFramework is { Framework: ".NETCoreApp", Version.Major: >= 7 }; + if (!isAtLeastNetCoreV7) + { + return false; + } + + return unsanitizedInput.IsEnabledLibraryImport ?? true; + } } From 29f6724c837180295df1d25e6da4d3ef76ccff78 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:12:12 -0400 Subject: [PATCH 3/9] Use `IntPtr` where possible --- .../WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs index 6d41b740..db67f314 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/Mapper/CSharpCodeMapper.cs @@ -822,7 +822,8 @@ private string IdiomaticName(string name, bool isType, string enumName = "", boo or "nint" or "CBool" or "CString" - or "CStringWide") + or "CStringWide" + or "IntPtr") { return identifier + pointersTrailing; } @@ -896,7 +897,7 @@ private string TypeNameCSharp( // TODO: https://github.com/lithiumtoast/c2cs/issues/15 if (typeName == "va_list") { - typeName = "nint"; + typeName = "IntPtr"; } return typeName; @@ -984,12 +985,12 @@ private string TypeNameCSharpPointer(string typeName, CType? innerType) if (pointerTypeName.StartsWith("FILE *", StringComparison.InvariantCulture)) { - return pointerTypeName.ReplaceFirst("FILE *", "nint", StringComparison.InvariantCulture); + return pointerTypeName.ReplaceFirst("FILE *", "IntPtr", StringComparison.InvariantCulture); } if (pointerTypeName.StartsWith("DIR *", StringComparison.InvariantCulture)) { - return pointerTypeName.ReplaceFirst("DIR *", "nint", StringComparison.InvariantCulture); + return pointerTypeName.ReplaceFirst("DIR *", "IntPtr", StringComparison.InvariantCulture); } var elementTypeName = pointerTypeName.TrimEnd('*').TrimEnd(); From c7bcb14f74ab83d1ead38649eb7bfc2565be54a8 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:12:20 -0400 Subject: [PATCH 4/9] Fix path --- src/cs/examples/helloworld/helloworld-bindgen/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cs/examples/helloworld/helloworld-bindgen/Program.cs b/src/cs/examples/helloworld/helloworld-bindgen/Program.cs index ce732ba2..059af49d 100644 --- a/src/cs/examples/helloworld/helloworld-bindgen/Program.cs +++ b/src/cs/examples/helloworld/helloworld-bindgen/Program.cs @@ -53,7 +53,7 @@ private static bool GenerateBindingsCSharp(string sourceDirectoryPath) return false; } - var configGenerateCSharpCodeFilePath = Path.GetFullPath(Path.Combine(sourceDirectoryPath, "config-generate-cs-net80.json")); + var configGenerateCSharpCodeFilePath = Path.GetFullPath(Path.Combine(sourceDirectoryPath, "config-generate-cs.json")); var parametersGenerateCSharpCode = new[] { "generate", "--config", configGenerateCSharpCodeFilePath }; C2CS.Program.Main(parametersGenerateCSharpCode); From 27ce96bd9454e4bda5767c97c9957acb8524f10e Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:17:59 -0400 Subject: [PATCH 5/9] Throw if unsupported .NET --- .../WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs index 6cfe9f5c..9f669fae 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Input/WriteCodeCSharpInputSanitizer.cs @@ -214,6 +214,12 @@ private NuGetFramework TargetFramework(string? targetFrameworkMoniker) $"The Target Framework Moniker (TFM) '{targetFrameworkMoniker}' is not supported because it has a platform. Remove the platform parts from the TFM and try again."); } + if (nuGetFramework.IsUnsupported) + { + throw new InvalidOperationException( + $"The Target Framework Moniker (TFM) '{targetFrameworkMoniker}' is not supported."); + } + return nuGetFramework; } From b30b1caa4804a310124fb101a9846fb64422611e Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:21:51 -0400 Subject: [PATCH 6/9] ignore ffi files in C# examples --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 126d8cef..664bf403 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,8 @@ lib/ *.so # c2ffi artifacts +src/cs/examples/**/ffi/ +src/cs/examples/**/ffi-x/ src/c/tests/**/ffi/ src/c/tests/**/ffi-x/ From 3e7a0be8424105c56646c09cb0f88187d8ae5661 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:23:28 -0400 Subject: [PATCH 7/9] Fix config file --- .../helloworld/helloworld-bindgen/config-generate-cs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json b/src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json index ea224d5f..73a60db4 100644 --- a/src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json +++ b/src/cs/examples/helloworld/helloworld-bindgen/config-generate-cs.json @@ -2,5 +2,5 @@ "inputFilePath": "./ffi-x/cross-platform.json", "outputFileDirectory": "./../helloworld-app/Generated", "className": "my_c_library", - "targetFramework": "net8.0" + "targetFrameworkMoniker": "net8.0" } From d472b77bc24d970cbd098a07e38991fac79483a8 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:37:05 -0400 Subject: [PATCH 8/9] Add constructor for function pointer --- .../LibraryImports.g.cs | 31 +++++++++++++++++++ .../Generated/my_c_library.gen.cs | 5 +++ .../helloworld/helloworld-app/Program.cs | 13 +++++--- .../FunctionPointerCodeGenerator.cs | 11 +++++-- 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs b/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs new file mode 100644 index 00000000..46c3f224 --- /dev/null +++ b/src/cs/examples/helloworld/helloworld-app/Generated/SourceGenerators/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @@ -0,0 +1,31 @@ +// +public static unsafe partial class my_c_library +{ + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_hello_world", ExactSpelling = true)] + public static extern partial void hw_hello_world(); +} +public static unsafe partial class my_c_library +{ + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_invoke_callback", ExactSpelling = true)] + public static extern partial void hw_invoke_callback(global::my_c_library.FnPtr_CString_Void f, global::Bindgen.Runtime.CString s); +} +public static unsafe partial class my_c_library +{ + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_enum", ExactSpelling = true)] + public static extern partial void hw_pass_enum(global::my_c_library.hw_my_enum_week_day e); +} +public static unsafe partial class my_c_library +{ + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_integers_by_reference", ExactSpelling = true)] + public static extern partial void hw_pass_integers_by_reference(ushort* a, int* b, ulong* c); +} +public static unsafe partial class my_c_library +{ + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_integers_by_value", ExactSpelling = true)] + public static extern partial void hw_pass_integers_by_value(ushort a, int b, ulong c); +} +public static unsafe partial class my_c_library +{ + [global::System.Runtime.InteropServices.DllImportAttribute("my_c_library", EntryPoint = "hw_pass_string", ExactSpelling = true)] + public static extern partial void hw_pass_string(global::Bindgen.Runtime.CString s); +} diff --git a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs index f0ab6bf7..db3aa09c 100644 --- a/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs +++ b/src/cs/examples/helloworld/helloworld-app/Generated/my_c_library.gen.cs @@ -57,6 +57,11 @@ public static unsafe partial class my_c_library public struct FnPtr_CString_Void { public delegate* unmanaged Pointer; + + public FnPtr_CString_Void(delegate* unmanaged pointer) + { + Pointer = pointer; + } } public enum hw_my_enum_week_day : int diff --git a/src/cs/examples/helloworld/helloworld-app/Program.cs b/src/cs/examples/helloworld/helloworld-app/Program.cs index 5a85aa51..9cba6297 100644 --- a/src/cs/examples/helloworld/helloworld-app/Program.cs +++ b/src/cs/examples/helloworld/helloworld-app/Program.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; using Bindgen.Runtime; -using static my_c_library_namespace.my_c_library; +using static my_c_library; internal static class Program { @@ -23,14 +23,19 @@ private static unsafe void Main() ulong c = 24242; hw_pass_integers_by_reference(&a, &b, &c); - var callback = default(FnPtr_CString_Void); - callback.Pointer = &Callback; +#if NET5_0_OR_GREATER + var functionPointer = new FnPtr_CString_Void(&Callback); +#else + var functionPointer = new FnPtr_CString_Void(Callback); +#endif var cString2 = (CString)"Hello from callback!"; - hw_invoke_callback(callback, cString2); + hw_invoke_callback(functionPointer, cString2); Marshal.FreeHGlobal(cString2); } +#if NET5_0_OR_GREATER [UnmanagedCallersOnly] +#endif private static void Callback(CString param) { // This C# function is called from C diff --git a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs index 457b061a..718d2e8d 100644 --- a/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs +++ b/src/cs/production/C2CS.Tool/Commands/WriteCodeCSharp/Domain/CodeGenerator/Generators/FunctionPointerCodeGenerator.cs @@ -43,6 +43,11 @@ private string GenerateCodeFunctionPointer(CSharpCodeGeneratorContext context, C public struct {{node.Name}} { public delegate* unmanaged<{{parameterTypesAndReturnTypeString}}> Pointer; + + public FnPtr_CString_Void(delegate* unmanaged<{{parameterTypesAndReturnTypeString}}> pointer) + { + Pointer = pointer; + } } """; @@ -64,9 +69,9 @@ public struct {{node.Name}} public IntPtr Pointer; public {{node.Name}}(@delegate d) - { - Pointer = Marshal.GetFunctionPointerForDelegate(d); - } + { + Pointer = Marshal.GetFunctionPointerForDelegate(d); + } } """; From ddec994f2fe53bd3a1e5c59917b6cc7f251436f7 Mon Sep 17 00:00:00 2001 From: Lucas Girouard-Stranks <519592+lithiumtoast@users.noreply.github.com> Date: Tue, 7 May 2024 17:43:23 -0400 Subject: [PATCH 9/9] Use `IntPtr` in Bindgen.Runtime --- src/cs/production/Bindgen.Runtime/CString.cs | 18 +++++++++--------- .../production/Bindgen.Runtime/CStringWide.cs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/cs/production/Bindgen.Runtime/CString.cs b/src/cs/production/Bindgen.Runtime/CString.cs index 11075795..2a5ba77a 100644 --- a/src/cs/production/Bindgen.Runtime/CString.cs +++ b/src/cs/production/Bindgen.Runtime/CString.cs @@ -12,12 +12,12 @@ namespace Bindgen.Runtime; [StructLayout(LayoutKind.Sequential)] public readonly unsafe struct CString : IEquatable, IDisposable { - public readonly nint Pointer; + public readonly IntPtr Pointer; /// /// Gets a value indicating whether this is a null pointer. /// - public bool IsNull => Pointer == 0; + public bool IsNull => Pointer == IntPtr.Zero; /// /// Initializes a new instance of the struct. @@ -25,14 +25,14 @@ namespace Bindgen.Runtime; /// The pointer value. public CString(byte* value) { - Pointer = (nint)value; + Pointer = (IntPtr)value; } /// /// Initializes a new instance of the struct. /// /// The pointer value. - public CString(nint value) + public CString(IntPtr value) { Pointer = value; } @@ -61,7 +61,7 @@ public void Dispose() /// /// The resulting . /// - public static explicit operator CString(nint value) + public static explicit operator CString(IntPtr value) { return FromIntPtr(value); } @@ -73,7 +73,7 @@ public static explicit operator CString(nint value) /// /// The resulting . /// - public static CString FromIntPtr(nint value) + public static CString FromIntPtr(IntPtr value) { return new CString(value); } @@ -99,7 +99,7 @@ public static implicit operator CString(byte* value) /// public static CString From(byte* value) { - return new CString((nint)value); + return new CString((IntPtr)value); } /// @@ -109,7 +109,7 @@ public static CString From(byte* value) /// /// The resulting . /// - public static implicit operator nint(CString value) + public static implicit operator IntPtr(CString value) { return value.Pointer; } @@ -121,7 +121,7 @@ public static implicit operator nint(CString value) /// /// The resulting . /// - public static nint ToIntPtr(CString value) + public static IntPtr ToIntPtr(CString value) { return value.Pointer; } diff --git a/src/cs/production/Bindgen.Runtime/CStringWide.cs b/src/cs/production/Bindgen.Runtime/CStringWide.cs index 44cb49b0..ebae2ea4 100644 --- a/src/cs/production/Bindgen.Runtime/CStringWide.cs +++ b/src/cs/production/Bindgen.Runtime/CStringWide.cs @@ -12,12 +12,12 @@ namespace Bindgen.Runtime; [StructLayout(LayoutKind.Sequential)] public readonly unsafe struct CStringWide : IEquatable { - public readonly nint Pointer; + public readonly IntPtr Pointer; /// /// Gets a value indicating whether this is a null pointer. /// - public bool IsNull => Pointer == 0; + public bool IsNull => Pointer == IntPtr.Zero; /// /// Initializes a new instance of the struct. @@ -25,14 +25,14 @@ namespace Bindgen.Runtime; /// The pointer value. public CStringWide(byte* value) { - Pointer = (nint)value; + Pointer = (IntPtr)value; } /// /// Initializes a new instance of the struct. /// /// The pointer value. - public CStringWide(nint value) + public CStringWide(IntPtr value) { Pointer = value; } @@ -53,7 +53,7 @@ public CStringWide(string s) /// /// The resulting . /// - public static explicit operator CStringWide(nint value) + public static explicit operator CStringWide(IntPtr value) { return FromIntPtr(value); } @@ -65,7 +65,7 @@ public static explicit operator CStringWide(nint value) /// /// The resulting . /// - public static CStringWide FromIntPtr(nint value) + public static CStringWide FromIntPtr(IntPtr value) { return new CStringWide(value); } @@ -91,7 +91,7 @@ public static implicit operator CStringWide(byte* value) /// public static CStringWide From(byte* value) { - return new CStringWide((nint)value); + return new CStringWide((IntPtr)value); } /// @@ -101,7 +101,7 @@ public static CStringWide From(byte* value) /// /// The resulting . /// - public static implicit operator nint(CStringWide value) + public static implicit operator IntPtr(CStringWide value) { return value.Pointer; } @@ -113,7 +113,7 @@ public static implicit operator nint(CStringWide value) /// /// The resulting . /// - public static nint ToIntPtr(CStringWide value) + public static IntPtr ToIntPtr(CStringWide value) { return value.Pointer; }