xoofx / cppast.codegen Goto Github PK
View Code? Open in Web Editor NEWAn extensible library providing C# PInvoke codegen from C/C++ files for .NET
License: BSD 2-Clause "Simplified" License
An extensible library providing C# PInvoke codegen from C/C++ files for .NET
License: BSD 2-Clause "Simplified" License
I am wanting to provide my own version of this Converter but the issue here is that CppElement
is internal set
on CSharpElement
which doesn't allow me to provide the same behavior as the default nor will it allow this to work with the mapping rules later.
Is there any specific reason this has to be internal ? Especially given the plugin architecture ?
Hi, I was having trouble getting these unions to generate correctly:
/*!
\brief Internal structure used to simplify access of Vec3f. Do not create
this structure directly and always use Vec3f instead.
*/
typedef struct XYZf {
float x;
float y;
float z;
} XYZf;
/*! 3D vector represented with X, Y, and Z floats. */
typedef struct Vec3f {
union {
XYZf xyz;
float values[3];
struct {
float x;
float y;
float z;
};
};
} Vec3f;
/*! Quaternion stored as X, Y, Z, W floats. */
typedef struct Quaternionf {
union {
/*! Values of the quaternions laid out as X, Y, Z, W. */
float values[4];
struct {
float x;
float y;
float z;
float w;
};
};
} Quaternionf;
/// <summary>
/// Internal structure used to simplify access of Vec3f Do not create
/// this structure directly and always use Vec3f instead
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct XYZf
{
public float x;
public float y;
public float z;
}
/// <summary>
/// 3D vector represented with X, Y, and Z floats
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Vec3f
{
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Vec3funion
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Vec3funionstruct
{
public float x;
public float y;
public float z;
}
[FieldOffset(0)]
public XYZf xyz;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]
public float[] values;
}
}
/// <summary>
/// Quaternion stored as X, Y, Z, W floats
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Quaternionf
{
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Quaternionfunion
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Quaternionfunionstruct
{
public float x;
public float y;
public float z;
public float w;
}
/// <summary>
/// Values of the quaternions laid out as X, Y, Z, W
/// </summary>
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPArray, SizeConst = 4)]
public float[] values;
}
}
/// <summary>
/// Internal structure used to simplify access of Vec3f Do not create
/// this structure directly and always use Vec3f instead
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct XYZf
{
public float x;
public float y;
public float z;
}
/// <summary>
/// 3D vector represented with X, Y, and Z floats
/// </summary>
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Vec3f
{
[FieldOffset(0)]
public float x;
[FieldOffset(4)]
public float y;
[FieldOffset(8)]
public float z;
[FieldOffset(0)]
public XYZf xyz;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]
public float[] values;
}
/// <summary>
/// Quaternion stored as X, Y, Z, W floats
/// </summary>
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct Quaternionf
{
[FieldOffset(0)]
public float x;
[FieldOffset(4)]
public float y;
[FieldOffset(8)]
public float z;
[FieldOffset(12)]
public float w;
/// <summary>
/// Values of the quaternions laid out as X, Y, Z, W
/// </summary>
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPArray, SizeConst = 4)]
public float[] values;
}
I have traveled the code in this repo and I want to add delegate* support.
typedef int (*fnAdd)(int,int);
struct S{
fnAdd pfnAdd;
};
generates
struct S
{
delegate* unmanaged[Cdelc]<int,int,int> pfnAdd;
}
I found that there is already an implementation of delegate pointers here, but it is not for function pointers, but for functions. And it doesn't seem to be used. Any tips on implementing this?
When generating delegate callbacks with multiple unnamed parameters, the code gen will produce names with the same name.
c++
typedef void(*CallbackMethod)(Context *, Result *);
C#
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackMethod(libnative.Context arg0, libnative.Result arg0);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackMethod(libnative.Context arg0, libnative.Result arg1);
When generating enums with uint
values only the first value is casted to the appropriate type
C++
/*!
\brief Fields that will be used for search operations.
\apilevel 2
*/
typedef enum ContactsSearchField {
/*! Search field for nickname. */
ContactsSearchField_Name = 1u,
/*! Search field for phone. */
ContactsSearchField_Phone = 1u << 1u,
/*! Search field for email. */
ContactsSearchField_Email = 1u << 2u,
/*! Search across all fields. */
ContactsSearchField_All = ContactsSearchField_Name | ContactsSearchField_Phone | ContactsSearchField_Email,
/*! Ensure enum is represented as 32 bits. */
ContactsSearchField_Ensure32Bits = 0x7FFFFFFF
} ContactsSearchField;
C#
/// <summary>
///
/// </summary>
/// <remarks>
/// @brief Fields that will be used for search operations.
/// @apilevel 2
/// </remarks>
[Flags]
public enum ContactsSearchField : int
{
/// <summary>
/// Search field for nickname.
/// </summary>
ContactsSearchField_Name = unchecked((int)1u),
/// <summary>
/// Search field for phone.
/// </summary>
ContactsSearchField_Phone = unchecked((int)1u<<1u),
/// <summary>
/// Search field for email.
/// </summary>
ContactsSearchField_Email = unchecked((int)1u<<2u),
/// <summary>
/// Search across all fields.
/// </summary>
ContactsSearchField_All = unchecked((int)ContactsSearchField_Name | ContactsSearchField_Phone | ContactsSearchField_Email),
/// <summary>
/// Ensure enum is represented as 32 bits.
/// </summary>
ContactsSearchField_Ensure32Bits = unchecked((int)0x7FFFFFFF),
}
/// <summary>
///
/// </summary>
/// <remarks>
/// Fields that will be used for search operations.
/// @apilevel 2
/// </remarks>
[Flags]
public enum ContactsSearchField : int
{
/// <summary>
/// Search field for nickname.
/// </summary>
ContactsSearchField_Name = unchecked((int)1u),
/// <summary>
/// Search field for phone.
/// </summary>
ContactsSearchField_Phone = unchecked((int)1u << (int)1u),
/// <summary>
/// Search field for email.
/// </summary>
ContactsSearchField_Email = unchecked((int)1u << (int)2u),
/// <summary>
/// Search across all fields.
/// </summary>
ContactsSearchField_All = unchecked((int)ContactsSearchField_Name | ContactsSearchField_Phone | ContactsSearchField_Email),
/// <summary>
/// Ensure enum is represented as 32 bits.
/// </summary>
ContactsSearchField_Ensure32Bits = unchecked((int)0x7FFFFFFF),
}
This one particular struct was improperly generated using a fixed keyword and a generated type.
c++
/*! Desired configuration of the input system. */
typedef struct InputConfiguration {
/*! Desired degrees-of-freedom mode of each controller. */
InputControllerDof dof[Input_MaxControllers];
} InputConfiguration;
C#
/// <summary>
/// Desired configuration of the input system.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public unsafe partial struct InputConfiguration
{
/// <summary>
/// Desired degrees-of-freedom mode of each controller.
/// </summary>
public fixed libnative.InputControllerDof dof[2];
}
Error
Fixed size buffer type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double
I'm not really sure what the expected result here would be either besides replacing the generated type with the int
equivalent value, but that doesn't seem correct.
/// <summary>
/// Desired configuration of the input system.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public unsafe partial struct InputConfiguration
{
/// <summary>
/// Desired degrees-of-freedom mode of each controller.
/// </summary>
public fixed int dof[2];
}
I don't see any commits since couple of years ago. Is the code in a stable state or is it abandoned?
Current:
/// <summary>
/// The summary for the cpp function delegate
/// </summary>
/// <param name="parameter1">parameter description.</param>
/// <param name="parameter2">parameter description.</param>
/// <param name="parameter3">parameter description.</param>
/// <remarks>
/// @brief This callback will be invoked whenever event is detected.
/// </remarks>
public ClassName.Callbacks.function_delegate event;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void function_delegate (byte parameter1, in Interop.DeviceState parameter2, IntPtr parameter3);
Expected:
/// <summary>
/// The summary for the cpp function delegate event.
/// </summary>
public ClassName.Callbacks.function_delegate event;
/// <summary>
/// The summary for the cpp function delegate.
/// </summary>
/// <param name="parameter1">parameter description.</param>
/// <param name="parameter2">parameter description.</param>
/// <param name="parameter3">parameter description.</param>
/// <remarks>
/// This callback will be invoked whenever event is detected.
/// </remarks>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void function_delegate (byte parameter1, in Interop.DeviceState parameter2, IntPtr parameter3);
A fixed size buffer of a typedef of a primitive generates improperly:
C
typedef uint64_t ecs_id_t;
typedef struct ecs_bulk_desc_t {
ecs_id_t ids[32];
}
C#
public readonly partial struct ecs_id_t : IEquatable<ecs_id_t> { ... }
public unsafe partial struct ecs_bulk_desc_t
{
public fixed IEquatable<ecs_id_t> ids[32];
}
The code path being hit that generates this is https://github.com/xoofx/CppAst.CodeGen/blob/master/src/CppAst.CodeGen/CSharp/Plugins/DefaultTypeConverter.cs#L177
Not sure what the correct way to resolve this is.
When attempting to generate an enum using a macro definition the code generated does not compile.
c++
/*! Macro to set a the prefix bytes of an API specific Result code. */
#define RESULT_PREFIX(val) (val << 16)
enum {
/*! Defines the prefix for global Result codes. */
ResultAPIPrefix_Global = RESULT_PREFIX(0),
};
enum {
/*! Defines the prefix for AudioResult codes. */
ResultAPIPrefix_Audio = RESULT_PREFIX(0x9e11)
};
C#
public enum __AnonymousCppEnum_api_3920AnonymousEnum : int
{
/// <summary>
/// Defines the prefix for global Result codes.
/// </summary>
ResultAPIPrefix_Global = unchecked((int)(0 16)enum{/*! Defines the prefix for global Result codes. */ResultAPIPrefix_Global=RESULT_PREFIX(0))),
}
public enum __AnonymousCppEnum_audio_8721AnonymousEnum : int
{
/// <summary>
/// Defines the prefix for AudioResult codes.
/// </summary>
ResultAPIPrefix_Audio = unchecked((int)(0x9e11 )), // Note this value should have also been computed using the macro.
}
public enum __AnonymousCppEnum_api_3920AnonymousEnum : int
{
/// <summary>
/// Defines the prefix for global Result codes.
/// </summary>
ResultAPIPrefix_Global = unchecked((int)0 << (int)16),
}
public enum __AnonymousCppEnum_audio_8721AnonymousEnum : int
{
/// <summary>
/// Defines the prefix for AudioResult codes.
/// </summary>
ResultAPIPrefix_Audio = unchecked((int)0x9e11 << (int)16),
}
First off thanks for this incredible library it's mostly easy to use and works well. I do have some questions though regarding the NoWrap option.
typedef struct Test Test;
[global::System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public readonly partial struct Test : IEquatable<native.Test >
{
public Test(nint handle) => Handle = handle;
public nint Handle { get; }
public bool Equals(Test other) => Handle.Equals(other.Handle);
public override bool Equals(object obj) => obj is Test other && Equals(other);
public override int GetHashCode() => Handle.GetHashCode();
public override string ToString() => "0x" + (nint.Size == 8 ? Handle.ToString("X16") : Handle.ToString("X8"));
public static bool operator ==(Test left, Test right) => left.Equals(right);
public static bool operator !=(Testleft, Testright) => !left.Equals(right);
}
Is it possible to just ignore the typedef if it is an opaque ptr and just use nint whenever it is used as a parameter or member?
typedef void (*Testfun)(int arg1, const char* arg2);
gets ignored and functions using it as param get the following signature
public static partial delegate*unmanaged[Cdecl]<int, byte*, void> setTestCallback(delegate*unmanaged[Cdecl]<int, byte*, void> callback);
Would it be possible to just not wrap it and add the delegate to the main class directly like so:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void Testfun(int arg1, const char* arg2);
And lastly maybe a bit unrelated question but what would be the easiest way to change the names of functions, types and constants?Within a c library they often prefix a library name as a sort of namespace, In c# this would be unnecessary as you already have both the namespace and the class. Is there a built-in way to remove such a suffix? for example testInit() to just Init() where test is the prefix?
Hi,
I first wanted to say that I've probably used about every ffigen out there (and wrote my own at one point). This is far and away the most pleasant one to use and modify. So: thank you
I did have a quick suggestion, not worth a PR. I assume this is incorrect?
namespace ns {
struct Foo { unsigned short _h; };
}
class Bar { ns::Foo member_; };
class Baz { ns::Foo member_; };
The struct Foo
is defined as libnative.Bar.Foo
instead of libnative.Foo
as expected
using System;
namespace LibNative
{
using System.Runtime.InteropServices;
public static partial class libnative
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public partial struct Bar
{
public libnative.Bar.Foo member_;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public partial struct Foo
{
public ushort _h;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public partial struct Baz
{
public libnative.Bar.Foo member_;
}
}
}
A void typedef generates to something that can't compile in C# via the default typedef converter.
typedef void ecs_poly_t;
-> public readonly partial struct ecs_poly_t { public readonly void Value; ... }
I'd be happy to open a PR to fix this, but I'm not 100% sure what the correct solution is. Should the typedef just be empty if the typedef's value's type is "void"?
The function declaration has the following first argument:
function0(git_my_repo* myrepo
At the same time the generated code declares it as
libnative.git_my_repo myrepo
which is incorrect. The structure is passed by pointer and should have ref or out in the c# declaration. It may work on some platforms as is (i.e. Windows) but may be broken on other (i.e. Linux).
Yeah, I know starting a title with the "Beyond" keyword is scary!
This is actually a prospective question; about the possibility, in the far future, to be able to convert C++ code to C# ... not just bindings, but the whole thing.
I don't expect it will be possible to make a full converter that works out of the box, we can only hope to have a converter that requires extensive rewriting at best... and there's two main issues that cannot be translated to c# easily: c++ templates and pointers semantics.
The c++ templating is almost impossible to handle.... and the pointers... I believe, it also was impossible to handle, until recently.
Recently I've been using Span<T>
a lot, and the more I use it, the more I recall when I used to program in c++, and I've began thinking about all the code I ported from c++ to c#, how difficult it was to port due to the pointer semantics, and how easily could have been ported now by using Span<T>
extensively...
So, maybe c++ to c# code conversion is not so far away? ... what do you think?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.