Update dependencies and fix some functionality (#140)
* Removing dependency on Microsoft.Net.Compilers.Toolset * Updating dependencies to their latest versions * Removing a System.CommandLine workaround for the argument arity * Make the --library optional * Adding support for with-setlasterror * Fixing function pointers to not unnecessarily add an indirection * Ensure ReferenceTypes are dereferenced using -> * Don't use pointers for the fixed sized-buffer ref codegen
This commit is contained in:
Родитель
05c0ee0ab2
Коммит
0ca80de67d
|
@ -65,9 +65,4 @@
|
|||
<UseSharedCompilation>true</UseSharedCompilation>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Package references which are consumed by all projects -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Net.Compilers.Toolset" IsImplicitlyDefined="true" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -30,9 +30,8 @@
|
|||
<PackageReference Update="libClang" Version="10.0.0" />
|
||||
<PackageReference Update="libClangSharp" Version="10.0.0-beta1" />
|
||||
<PackageReference Update="Microsoft.Bcl.HashCode" Version="1.1.0" />
|
||||
<PackageReference Update="Microsoft.Net.Compilers.Toolset" Version="3.5.0" />
|
||||
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Update="System.CommandLine" Version="2.0.0-beta1.20158.1" />
|
||||
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
<PackageReference Update="System.CommandLine" Version="2.0.0-beta1.20253.1" />
|
||||
<PackageReference Update="System.Memory" Version="4.5.4" />
|
||||
<PackageReference Update="xunit" Version="2.4.1" />
|
||||
<PackageReference Update="xunit.runner.visualstudio" Version="2.4.1" />
|
||||
|
|
|
@ -457,7 +457,7 @@ namespace ClangSharp
|
|||
|
||||
if (isVirtual)
|
||||
{
|
||||
Debug.Assert(!_config.GeneratePreviewCode);
|
||||
Debug.Assert(!_config.GeneratePreviewCodeFnptr);
|
||||
|
||||
_outputBuilder.AddUsingDirective("System.Runtime.InteropServices");
|
||||
|
||||
|
@ -490,7 +490,9 @@ namespace ClangSharp
|
|||
_outputBuilder.Write(cxxMethodDecl.Handle.Mangling);
|
||||
}
|
||||
|
||||
_outputBuilder.WriteLine("\", ExactSpelling = true)]");
|
||||
_outputBuilder.Write("\", ExactSpelling = true");
|
||||
WithSetLastError(name);
|
||||
_outputBuilder.WriteLine(")]");
|
||||
}
|
||||
|
||||
var returnType = functionDecl.ReturnType;
|
||||
|
@ -1034,7 +1036,7 @@ namespace ClangSharp
|
|||
|
||||
pinvokeGenerator._visitedDecls.Add(cxxMethodDecl);
|
||||
|
||||
if (!pinvokeGenerator._config.GeneratePreviewCode)
|
||||
if (!pinvokeGenerator._config.GeneratePreviewCodeFnptr)
|
||||
{
|
||||
pinvokeGenerator._outputBuilder.NeedsNewline = true;
|
||||
|
||||
|
@ -1217,7 +1219,7 @@ namespace ClangSharp
|
|||
outputBuilder.Write('*');
|
||||
}
|
||||
|
||||
if (!pinvokeGenerator._config.GeneratePreviewCode)
|
||||
if (!pinvokeGenerator._config.GeneratePreviewCodeFnptr)
|
||||
{
|
||||
outputBuilder.Write("Marshal.GetDelegateForFunctionPointer<");
|
||||
outputBuilder.Write(pinvokeGenerator.PrefixAndStripName(cxxMethodDeclName));
|
||||
|
@ -1228,7 +1230,7 @@ namespace ClangSharp
|
|||
outputBuilder.Write("lpVtbl->");
|
||||
outputBuilder.Write(pinvokeGenerator.EscapeAndStripName(cxxMethodDeclName));
|
||||
|
||||
if (!pinvokeGenerator._config.GeneratePreviewCode)
|
||||
if (!pinvokeGenerator._config.GeneratePreviewCodeFnptr)
|
||||
{
|
||||
outputBuilder.Write(')');
|
||||
}
|
||||
|
@ -1570,18 +1572,16 @@ namespace ClangSharp
|
|||
{
|
||||
return;
|
||||
}
|
||||
bool isUnsafe = typeName.Contains('*');
|
||||
|
||||
if (typeName.Contains('*'))
|
||||
{
|
||||
outputBuilder.AddUsingDirective("System");
|
||||
typeName = "IntPtr";
|
||||
}
|
||||
|
||||
outputBuilder.NeedsNewline = true;
|
||||
outputBuilder.WriteIndented(pinvokeGenerator.GetAccessSpecifierName(constantArray));
|
||||
outputBuilder.Write(' ');
|
||||
|
||||
if (isUnsafe)
|
||||
{
|
||||
outputBuilder.Write("unsafe");
|
||||
outputBuilder.Write(' ');
|
||||
}
|
||||
|
||||
outputBuilder.Write("partial struct");
|
||||
outputBuilder.Write(' ');
|
||||
outputBuilder.WriteLine(pinvokeGenerator.GetArtificalFixedSizedBufferName(constantArray));
|
||||
|
@ -1642,11 +1642,8 @@ namespace ClangSharp
|
|||
|
||||
if (pinvokeGenerator._config.GenerateCompatibleCode)
|
||||
{
|
||||
if (!isUnsafe)
|
||||
{
|
||||
outputBuilder.Write("unsafe");
|
||||
outputBuilder.Write(' ');
|
||||
}
|
||||
outputBuilder.Write("unsafe");
|
||||
outputBuilder.Write(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1766,7 +1763,7 @@ namespace ClangSharp
|
|||
}
|
||||
else if (pointeeType is FunctionProtoType functionProtoType)
|
||||
{
|
||||
if (_config.GeneratePreviewCode)
|
||||
if (_config.GeneratePreviewCodeFnptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ClangSharp.Interop;
|
||||
|
||||
namespace ClangSharp
|
||||
|
@ -587,7 +588,22 @@ namespace ClangSharp
|
|||
{
|
||||
Visit(memberExpr.Base);
|
||||
|
||||
if ((memberExpr.Base.Type is PointerType) && !(memberExpr.Base is CXXThisExpr))
|
||||
bool isPointerType;
|
||||
|
||||
if (memberExpr.Base is CXXThisExpr)
|
||||
{
|
||||
isPointerType = false;
|
||||
}
|
||||
else if (memberExpr.Base is DeclRefExpr declRefExpr)
|
||||
{
|
||||
isPointerType = (declRefExpr.Decl.Type is PointerType) || (declRefExpr.Decl.Type is ReferenceType);
|
||||
}
|
||||
else
|
||||
{
|
||||
isPointerType = (memberExpr.Base.Type is PointerType) || (memberExpr.Base.Type is ReferenceType);
|
||||
}
|
||||
|
||||
if (isPointerType)
|
||||
{
|
||||
_outputBuilder.Write('-');
|
||||
_outputBuilder.Write('>');
|
||||
|
|
|
@ -310,14 +310,17 @@ namespace ClangSharp
|
|||
|
||||
indentationString += outputBuilder.IndentationString;
|
||||
|
||||
sw.Write(indentationString);
|
||||
sw.Write("private const string LibraryPath =");
|
||||
sw.Write(' ');
|
||||
sw.Write('"');
|
||||
sw.Write(Config.LibraryPath);
|
||||
sw.Write('"');
|
||||
sw.WriteLine(';');
|
||||
sw.WriteLine();
|
||||
if (!string.IsNullOrWhiteSpace(Config.LibraryPath))
|
||||
{
|
||||
sw.Write(indentationString);
|
||||
sw.Write("private const string LibraryPath =");
|
||||
sw.Write(' ');
|
||||
sw.Write('"');
|
||||
sw.Write(Config.LibraryPath);
|
||||
sw.Write('"');
|
||||
sw.WriteLine(';');
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var line in outputBuilder.Contents)
|
||||
|
@ -766,7 +769,7 @@ namespace ClangSharp
|
|||
{
|
||||
if (_config.GenerateUnixTypes)
|
||||
{
|
||||
name = _config.GeneratePreviewCode ? "nuint" : "UIntPtr";
|
||||
name = _config.GeneratePreviewCodeNint ? "nuint" : "UIntPtr";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -816,7 +819,7 @@ namespace ClangSharp
|
|||
{
|
||||
if (_config.GenerateUnixTypes)
|
||||
{
|
||||
name = _config.GeneratePreviewCode ? "nint" : "IntPtr";
|
||||
name = _config.GeneratePreviewCodeNint ? "nint" : "IntPtr";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -856,33 +859,7 @@ namespace ClangSharp
|
|||
}
|
||||
else if (type is FunctionType functionType)
|
||||
{
|
||||
if (_config.GeneratePreviewCode && (functionType is FunctionProtoType functionProtoType))
|
||||
{
|
||||
var remappedName = GetRemappedName(name, cursor, tryRemapOperatorName: false);
|
||||
var callConv = GetCallingConventionName(cursor, functionType.CallConv, remappedName).ToLower();
|
||||
|
||||
var nameBuilder = new StringBuilder();
|
||||
nameBuilder.Append("delegate");
|
||||
nameBuilder.Append('*');
|
||||
nameBuilder.Append(' ');
|
||||
nameBuilder.Append((callConv != "winapi") ? callConv : "unmanaged");
|
||||
nameBuilder.Append('<');
|
||||
|
||||
foreach (var paramType in functionProtoType.ParamTypes)
|
||||
{
|
||||
nameBuilder.Append(GetRemappedTypeName(cursor, paramType, out _));
|
||||
nameBuilder.Append(',');
|
||||
nameBuilder.Append(' ');
|
||||
}
|
||||
|
||||
nameBuilder.Append(GetRemappedTypeName(cursor, functionType.ReturnType, out _));
|
||||
nameBuilder.Append('>');
|
||||
name = nameBuilder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "IntPtr";
|
||||
}
|
||||
name = GetTypeNameForPointeeType(cursor, functionType, out var nativeFunctionTypeName);
|
||||
}
|
||||
else if (type is PointerType pointerType)
|
||||
{
|
||||
|
@ -948,6 +925,36 @@ namespace ClangSharp
|
|||
{
|
||||
name = GetTypeNameForPointeeType(cursor, attributedType.ModifiedType, out var nativeModifiedTypeName);
|
||||
}
|
||||
else if (pointeeType is FunctionType functionType)
|
||||
{
|
||||
if (_config.GeneratePreviewCodeFnptr && (functionType is FunctionProtoType functionProtoType))
|
||||
{
|
||||
var remappedName = GetRemappedName(name, cursor, tryRemapOperatorName: false);
|
||||
var callConv = GetCallingConventionName(cursor, functionType.CallConv, remappedName).ToLower();
|
||||
|
||||
var nameBuilder = new StringBuilder();
|
||||
nameBuilder.Append("delegate");
|
||||
nameBuilder.Append('*');
|
||||
nameBuilder.Append(' ');
|
||||
nameBuilder.Append((callConv != "winapi") ? callConv : "unmanaged");
|
||||
nameBuilder.Append('<');
|
||||
|
||||
foreach (var paramType in functionProtoType.ParamTypes)
|
||||
{
|
||||
nameBuilder.Append(GetRemappedTypeName(cursor, paramType, out _));
|
||||
nameBuilder.Append(',');
|
||||
nameBuilder.Append(' ');
|
||||
}
|
||||
|
||||
nameBuilder.Append(GetRemappedTypeName(cursor, functionType.ReturnType, out _));
|
||||
nameBuilder.Append('>');
|
||||
name = nameBuilder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "IntPtr";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = GetTypeName(cursor, pointeeType, out nativePointeeTypeName);
|
||||
|
@ -1397,6 +1404,14 @@ namespace ClangSharp
|
|||
}
|
||||
}
|
||||
|
||||
private void WithSetLastError(string remappedName)
|
||||
{
|
||||
if (_config.WithSetLastErrors.Contains("*") || _config.WithSetLastErrors.Contains(remappedName))
|
||||
{
|
||||
_outputBuilder.Write(", SetLastError = true");
|
||||
}
|
||||
}
|
||||
|
||||
private void WithType(string remappedName, ref string integerTypeName, ref string nativeTypeName)
|
||||
{
|
||||
if (_config.WithTypes.TryGetValue(remappedName, out string type))
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace ClangSharp
|
|||
private readonly Dictionary<string, IReadOnlyList<string>> _withUsings;
|
||||
private readonly PInvokeGeneratorConfigurationOptions _options;
|
||||
|
||||
public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary<string, string> remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null)
|
||||
public PInvokeGeneratorConfiguration(string libraryPath, string namespaceName, string outputLocation, PInvokeGeneratorConfigurationOptions options = PInvokeGeneratorConfigurationOptions.None, string[] excludedNames = null, string headerFile = null, string methodClassName = null, string methodPrefixToStrip = null, IReadOnlyDictionary<string, string> remappedNames = null, string[] traversalNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, string[] withSetLastErrors = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null)
|
||||
{
|
||||
if (excludedNames is null)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ namespace ClangSharp
|
|||
|
||||
if (string.IsNullOrWhiteSpace(libraryPath))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(libraryPath));
|
||||
libraryPath = string.Empty;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(methodClassName))
|
||||
|
@ -60,6 +60,11 @@ namespace ClangSharp
|
|||
traversalNames = Array.Empty<string>();
|
||||
}
|
||||
|
||||
if (withSetLastErrors is null)
|
||||
{
|
||||
withSetLastErrors = Array.Empty<string>();
|
||||
}
|
||||
|
||||
_options = options;
|
||||
_remappedNames = new Dictionary<string, string>();
|
||||
_withAttributes = new Dictionary<string, IReadOnlyList<string>>();
|
||||
|
@ -77,10 +82,11 @@ namespace ClangSharp
|
|||
|
||||
// Normalize the traversal names to use \ rather than / so path comparisons are simpler
|
||||
TraversalNames = traversalNames.Select(traversalName => traversalName.Replace('\\', '/')).ToArray();
|
||||
WithSetLastErrors = withSetLastErrors;
|
||||
|
||||
if (!_options.HasFlag(PInvokeGeneratorConfigurationOptions.NoDefaultRemappings))
|
||||
{
|
||||
if (GeneratePreviewCode)
|
||||
if (GeneratePreviewCodeNint)
|
||||
{
|
||||
_remappedNames.Add("intptr_t", "nint");
|
||||
_remappedNames.Add("ptrdiff_t", "nint");
|
||||
|
@ -107,7 +113,9 @@ namespace ClangSharp
|
|||
|
||||
public bool GenerateCompatibleCode => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode);
|
||||
|
||||
public bool GeneratePreviewCode => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GeneratePreviewCode);
|
||||
public bool GeneratePreviewCodeFnptr => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GeneratePreviewCodeFnptr);
|
||||
|
||||
public bool GeneratePreviewCodeNint => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GeneratePreviewCodeNint);
|
||||
|
||||
public bool GenerateMultipleFiles => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateMultipleFiles);
|
||||
|
||||
|
@ -133,6 +141,8 @@ namespace ClangSharp
|
|||
|
||||
public IReadOnlyDictionary<string, string> WithCallConvs => _withCallConvs;
|
||||
|
||||
public string[] WithSetLastErrors { get; }
|
||||
|
||||
public IReadOnlyDictionary<string, string> WithTypes => _withTypes;
|
||||
|
||||
public IReadOnlyDictionary<string, IReadOnlyList<string>> WithUsings => _withUsings;
|
||||
|
|
|
@ -17,6 +17,10 @@ namespace ClangSharp
|
|||
|
||||
GenerateCompatibleCode = 0x00000008,
|
||||
|
||||
GeneratePreviewCode = 0x00000010,
|
||||
GeneratePreviewCodeNint = 0x00000010,
|
||||
|
||||
GeneratePreviewCodeFnptr = 0x00000020,
|
||||
|
||||
GeneratePreviewCode = GeneratePreviewCodeNint | GeneratePreviewCodeFnptr,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace ClangSharp
|
|||
AddTraverseOption(s_rootCommand);
|
||||
AddWithAttributeOption(s_rootCommand);
|
||||
AddWithCallConvOption(s_rootCommand);
|
||||
AddWithSetLastErrorOption(s_rootCommand);
|
||||
AddWithTypeOption(s_rootCommand);
|
||||
AddWithUsingOption(s_rootCommand);
|
||||
|
||||
|
@ -70,6 +71,7 @@ namespace ClangSharp
|
|||
var traversalNames = context.ParseResult.ValueForOption<string[]>("traverse");
|
||||
var withAttributeNameValuePairs = context.ParseResult.ValueForOption<string[]>("with-attribute");
|
||||
var withCallConvNameValuePairs = context.ParseResult.ValueForOption<string[]>("with-callconv");
|
||||
var withSetLastErrors = context.ParseResult.ValueForOption<string[]>("with-setlasterror");
|
||||
var withTypeNameValuePairs = context.ParseResult.ValueForOption<string[]>("with-type");
|
||||
var withUsingNameValuePairs = context.ParseResult.ValueForOption<string[]>("with-using");
|
||||
|
||||
|
@ -80,11 +82,6 @@ namespace ClangSharp
|
|||
errorList.Add("Error: No input C/C++ files provided. Use --file or -f");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(libraryPath))
|
||||
{
|
||||
errorList.Add("Error: No library path location provided. Use --libraryPath or -l");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(namespaceName))
|
||||
{
|
||||
errorList.Add("Error: No namespace provided. Use --namespace or -n");
|
||||
|
@ -96,8 +93,8 @@ namespace ClangSharp
|
|||
}
|
||||
|
||||
ParseKeyValuePairs(remappedNameValuePairs, errorList, out Dictionary<string, string> remappedNames);
|
||||
ParseKeyValuePairs(withCallConvNameValuePairs, errorList, out Dictionary<string, string> withCallConvs);
|
||||
ParseKeyValuePairs(withAttributeNameValuePairs, errorList, out Dictionary<string, IReadOnlyList<string>> withAttributes);
|
||||
ParseKeyValuePairs(withCallConvNameValuePairs, errorList, out Dictionary<string, string> withCallConvs);
|
||||
ParseKeyValuePairs(withTypeNameValuePairs, errorList, out Dictionary<string, string> withTypes);
|
||||
ParseKeyValuePairs(withUsingNameValuePairs, errorList, out Dictionary<string, IReadOnlyList<string>> withUsings);
|
||||
|
||||
|
@ -146,6 +143,20 @@ namespace ClangSharp
|
|||
break;
|
||||
}
|
||||
|
||||
case "preview-codegen-nint":
|
||||
{
|
||||
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode;
|
||||
configOptions |= PInvokeGeneratorConfigurationOptions.GeneratePreviewCodeNint;
|
||||
break;
|
||||
}
|
||||
|
||||
case "preview-codegen-fnptr":
|
||||
{
|
||||
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode;
|
||||
configOptions |= PInvokeGeneratorConfigurationOptions.GeneratePreviewCodeFnptr;
|
||||
break;
|
||||
}
|
||||
|
||||
case "single-file":
|
||||
{
|
||||
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateMultipleFiles;
|
||||
|
@ -201,7 +212,7 @@ namespace ClangSharp
|
|||
translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes; // Include attributed types in CXType
|
||||
translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes; // Implicit attributes should be visited
|
||||
|
||||
var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, configOptions, excludedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAttributes, withCallConvs, withTypes, withUsings);
|
||||
var config = new PInvokeGeneratorConfiguration(libraryPath, namespaceName, outputLocation, configOptions, excludedNames, headerFile, methodClassName, methodPrefixToStrip, remappedNames, traversalNames, withAttributes, withCallConvs, withSetLastErrors, withTypes, withUsings);
|
||||
|
||||
int exitCode = 0;
|
||||
|
||||
|
@ -553,7 +564,7 @@ namespace ClangSharp
|
|||
Argument = new Argument("<name>=<value>")
|
||||
{
|
||||
ArgumentType = typeof(string),
|
||||
Arity = new ArgumentArity(1, ushort.MaxValue),
|
||||
Arity = ArgumentArity.OneOrMore,
|
||||
}
|
||||
};
|
||||
option.Argument.SetDefaultValue(Array.Empty<string>());
|
||||
|
@ -621,6 +632,21 @@ namespace ClangSharp
|
|||
rootCommand.AddOption(option);
|
||||
}
|
||||
|
||||
private static void AddWithSetLastErrorOption(RootCommand rootCommand)
|
||||
{
|
||||
var option = new Option(new string[] { "--with-setlasterror", "-wsle" }, "Add the SetLastError=true modifier to a given DllImport or UnmanagedFunctionPointer.")
|
||||
{
|
||||
Argument = new Argument("<remapped-name>=<value>")
|
||||
{
|
||||
ArgumentType = typeof(string),
|
||||
Arity = ArgumentArity.OneOrMore,
|
||||
}
|
||||
};
|
||||
option.Argument.SetDefaultValue(Array.Empty<string>());
|
||||
|
||||
rootCommand.AddOption(option);
|
||||
}
|
||||
|
||||
private static void AddWithTypeOption(RootCommand rootCommand)
|
||||
{
|
||||
var option = new Option(new string[] { "--with-type", "-wt" }, "A type to be used for the given enum declaration during binding generation.")
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
"GenerateLLVM": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "\"@$(MSBuildProjectDirectory)/Properties/GenerateLLVM.rsp\" --file-directory \"$(LLVMIncludePath)\" --include-directory \"$(LLVMIncludePath)\" --libraryPath $(LibLLVMName)"
|
||||
},
|
||||
"GenerateTerraFX": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "@generate.rsp",
|
||||
"workingDirectory": "D:\\tagoo\\Repos\\terrafx.interop.windows\\generation\\um\\winnt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1339,6 +1339,41 @@ int MyFunction2(MyStruct* instance)
|
|||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RefToPtrTest()
|
||||
{
|
||||
var inputContents = @"struct MyStruct {
|
||||
int value;
|
||||
};
|
||||
|
||||
bool MyFunction(const MyStruct& lhs, const MyStruct& rhs)
|
||||
{
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
";
|
||||
|
||||
var expectedOutputContents = @"namespace ClangSharp.Test
|
||||
{
|
||||
public partial struct MyStruct
|
||||
{
|
||||
public int value;
|
||||
}
|
||||
|
||||
public static unsafe partial class Methods
|
||||
{
|
||||
private const string LibraryPath = ""ClangSharpPInvokeGenerator"";
|
||||
|
||||
public static bool MyFunction([NativeTypeName(""const MyStruct &"")] MyStruct* lhs, [NativeTypeName(""const MyStruct &"")] MyStruct* rhs)
|
||||
{
|
||||
return lhs->value == rhs->value;
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReturnCXXNullPtrTest()
|
||||
{
|
||||
|
|
|
@ -52,6 +52,49 @@ namespace ClangSharp.Test
|
|||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FunctionPointerParameterTest()
|
||||
{
|
||||
var inputContents = @"void MyFunction(void (*callback)());";
|
||||
|
||||
var expectedOutputContents = @"using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClangSharp.Test
|
||||
{
|
||||
public static partial class Methods
|
||||
{
|
||||
private const string LibraryPath = ""ClangSharpPInvokeGenerator"";
|
||||
|
||||
[DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = ""MyFunction"", ExactSpelling = true)]
|
||||
public static extern void MyFunction([NativeTypeName(""void (*)()"")] IntPtr callback);
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NoLibraryPathTest()
|
||||
{
|
||||
var inputContents = @"void MyFunction();";
|
||||
|
||||
var expectedOutputContents = @"using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClangSharp.Test
|
||||
{
|
||||
public static partial class Methods
|
||||
{
|
||||
[DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = ""MyFunction"", ExactSpelling = true)]
|
||||
public static extern void MyFunction();
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents, libraryPath: string.Empty);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("unsigned char value = 0", @"[NativeTypeName(""unsigned char"")] byte value = 0")]
|
||||
[InlineData("double value = 1.0", @"double value = 1.0")]
|
||||
|
@ -195,5 +238,63 @@ namespace ClangSharp.Test
|
|||
};
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents, withCallConvs: withCallConvs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WithSetLastErrorTest()
|
||||
{
|
||||
var inputContents = @"void MyFunction1(int value); void MyFunction2(int value);";
|
||||
|
||||
var expectedOutputContents = @"using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClangSharp.Test
|
||||
{
|
||||
public static partial class Methods
|
||||
{
|
||||
private const string LibraryPath = ""ClangSharpPInvokeGenerator"";
|
||||
|
||||
[DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = ""MyFunction1"", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern void MyFunction1(int value);
|
||||
|
||||
[DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = ""MyFunction2"", ExactSpelling = true)]
|
||||
public static extern void MyFunction2(int value);
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var withSetLastErrors = new string[]
|
||||
{
|
||||
"MyFunction1"
|
||||
};
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents, withSetLastErrors: withSetLastErrors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WithSetLastErrorStarTest()
|
||||
{
|
||||
var inputContents = @"void MyFunction1(int value); void MyFunction2(int value);";
|
||||
|
||||
var expectedOutputContents = @"using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClangSharp.Test
|
||||
{
|
||||
public static partial class Methods
|
||||
{
|
||||
private const string LibraryPath = ""ClangSharpPInvokeGenerator"";
|
||||
|
||||
[DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = ""MyFunction1"", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern void MyFunction1(int value);
|
||||
|
||||
[DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = ""MyFunction2"", ExactSpelling = true, SetLastError = true)]
|
||||
public static extern void MyFunction2(int value);
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
var withSetLastErrors = new string[]
|
||||
{
|
||||
"*"
|
||||
};
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents, withSetLastErrors: withSetLastErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft and Contributors. All rights reserved. Licensed under the University of Illinois/NCSA Open Source License. See LICENSE.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace ClangSharp.UnitTests
|
||||
{
|
||||
public sealed class FunctionPointerDeclarationTest : PInvokeGeneratorTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task BasicTest()
|
||||
{
|
||||
var inputContents = @"typedef void (*Callback)();";
|
||||
|
||||
var expectedOutputContents = @"using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClangSharp.Test
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void Callback();
|
||||
}
|
||||
";
|
||||
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,17 +24,17 @@ namespace ClangSharp.UnitTests
|
|||
"-Wno-pragma-once-outside-header" // We are processing files which may be header files
|
||||
};
|
||||
|
||||
protected Task ValidateGeneratedBindings(string inputContents, string expectedOutputContents, string[] excludedNames = null, IReadOnlyDictionary<string, string> remappedNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null, IEnumerable<Diagnostic> expectedDiagnostics = null)
|
||||
protected Task ValidateGeneratedBindings(string inputContents, string expectedOutputContents, string[] excludedNames = null, IReadOnlyDictionary<string, string> remappedNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, string[] withSetLastErrors = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null, IEnumerable<Diagnostic> expectedDiagnostics = null, string libraryPath = DefaultLibraryPath)
|
||||
{
|
||||
return ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.None, excludedNames, remappedNames, withAttributes, withCallConvs, withTypes, withUsings, expectedDiagnostics);
|
||||
return ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.None, excludedNames, remappedNames, withAttributes, withCallConvs, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath);
|
||||
}
|
||||
|
||||
protected Task ValidateGeneratedCompatibleBindings(string inputContents, string expectedOutputContents, string[] excludedNames = null, IReadOnlyDictionary<string, string> remappedNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null, IEnumerable<Diagnostic> expectedDiagnostics = null)
|
||||
protected Task ValidateGeneratedCompatibleBindings(string inputContents, string expectedOutputContents, string[] excludedNames = null, IReadOnlyDictionary<string, string> remappedNames = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes = null, IReadOnlyDictionary<string, string> withCallConvs = null, string[] withSetLastErrors = null, IReadOnlyDictionary<string, string> withTypes = null, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings = null, IEnumerable<Diagnostic> expectedDiagnostics = null, string libraryPath = DefaultLibraryPath)
|
||||
{
|
||||
return ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode, excludedNames, remappedNames, withAttributes, withCallConvs, withTypes, withUsings, expectedDiagnostics);
|
||||
return ValidateGeneratedBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode, excludedNames, remappedNames, withAttributes, withCallConvs, withSetLastErrors, withTypes, withUsings, expectedDiagnostics, libraryPath);
|
||||
}
|
||||
|
||||
private async Task ValidateGeneratedBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions configOptions, string[] excludedNames, IReadOnlyDictionary<string, string> remappedNames, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes, IReadOnlyDictionary<string, string> withCallConvs, IReadOnlyDictionary<string, string> withTypes, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings, IEnumerable<Diagnostic> expectedDiagnostics)
|
||||
private async Task ValidateGeneratedBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions configOptions, string[] excludedNames, IReadOnlyDictionary<string, string> remappedNames, IReadOnlyDictionary<string, IReadOnlyList<string>> withAttributes, IReadOnlyDictionary<string, string> withCallConvs, string[] withSetLastErrors, IReadOnlyDictionary<string, string> withTypes, IReadOnlyDictionary<string, IReadOnlyList<string>> withUsings, IEnumerable<Diagnostic> expectedDiagnostics, string libraryPath)
|
||||
{
|
||||
Assert.True(File.Exists(DefaultInputFileName));
|
||||
|
||||
|
@ -42,7 +42,7 @@ namespace ClangSharp.UnitTests
|
|||
using var unsavedFile = CXUnsavedFile.Create(DefaultInputFileName, inputContents);
|
||||
|
||||
var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
|
||||
var config = new PInvokeGeneratorConfiguration(DefaultLibraryPath, DefaultNamespaceName, Path.GetRandomFileName(), configOptions, excludedNames, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAttributes, withCallConvs, withTypes, withUsings);
|
||||
var config = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), configOptions, excludedNames, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAttributes, withCallConvs, withSetLastErrors, withTypes, withUsings);
|
||||
|
||||
using (var pinvokeGenerator = new PInvokeGenerator(config, (path) => outputStream))
|
||||
{
|
||||
|
|
|
@ -536,6 +536,48 @@ namespace ClangSharp.Test
|
|||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("double *", "IntPtr")]
|
||||
[InlineData("short *", "IntPtr")]
|
||||
[InlineData("int *", "IntPtr")]
|
||||
[InlineData("float *", "IntPtr")]
|
||||
public async Task FixedSizedBufferPointerTest(string nativeType, string expectedManagedType)
|
||||
{
|
||||
var inputContents = $@"struct MyStruct
|
||||
{{
|
||||
{nativeType} c[3];
|
||||
}};
|
||||
";
|
||||
|
||||
var expectedOutputContents = $@"using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ClangSharp.Test
|
||||
{{
|
||||
public partial struct MyStruct
|
||||
{{
|
||||
[NativeTypeName(""{nativeType}[3]"")]
|
||||
public _c_e__FixedBuffer c;
|
||||
|
||||
public partial struct _c_e__FixedBuffer
|
||||
{{
|
||||
internal {expectedManagedType} e0;
|
||||
internal {expectedManagedType} e1;
|
||||
internal {expectedManagedType} e2;
|
||||
|
||||
public ref {expectedManagedType} this[int index] => ref AsSpan()[index];
|
||||
|
||||
public Span<{expectedManagedType}> AsSpan() => MemoryMarshal.CreateSpan(ref e0, 3);
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
";
|
||||
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
|
||||
await ValidateGeneratedBindings(inputContents, expectedOutputContents);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("unsigned char", "byte")]
|
||||
[InlineData("double", "double")]
|
||||
|
|
Загрузка…
Ссылка в новой задаче