Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate binding and misc #272

Open
Odex64 opened this issue Oct 4, 2024 · 6 comments
Open

Generate binding and misc #272

Odex64 opened this issue Oct 4, 2024 · 6 comments
Labels
help wanted Extra attention is needed question Further information is requested

Comments

@Odex64
Copy link

Odex64 commented Oct 4, 2024

Consider using raylib's definitions from the official repo to auto generate source files.
This will make the latest APIs available in raylib-cs and drastically reduce the manual work of porting raylib's structs, enums and functions - make sure that all the structs are blittable.

Also consider these other changes

  • Upgrade to .NET Core 8 and C# 12.
  • Switch to LibraryImport for better AOT compatibility.
@chrisdill
Copy link
Owner

Looks like a nice way to generate bindings. Could probably handle most of the bindings. Would help with maintenance since the library is now passively maintained.

Open to updating .net and c# versions but only if we need to for specific features etc. As for LibraryImport, can you explain how the bindings would be better for AOT compared to the current approach?

@chrisdill chrisdill added question Further information is requested help wanted Extra attention is needed labels Oct 6, 2024
@Odex64
Copy link
Author

Odex64 commented Oct 6, 2024

Upgrading to .NET 8 should be fine for most users since it is LTS and defaults to C# 12. It it also required for the new p/invoke source generator (LibraryImport) to work.

As of LibraryImport there are the following benefits

  • NativeAOT support.
  • Better debugging the marshalling logic since LibraryImport generates some code at compile time rather than being completely runtime.
  • It should lead to better performance.
  • Can handle the string marshalling automatically instead of manually writing helper methods.

If you want I can work on a generator in order to generate all the source files from raylib's definitions.

@chrisdill
Copy link
Owner

chrisdill commented Oct 16, 2024

Still undecided but examples comparing/showing the pros and cons for both ideas would be useful either way.

@Odex64
Copy link
Author

Odex64 commented Oct 18, 2024

Here's more details of pros and cons of both.

LibraryImport

Pros

  1. Source Generation: LibraryImport leverages source generators to auto-generate P/Invoke calls. This means that some code is generated at compile time, minimizing errors that can occur with manual marshalling and having a better debugging experience.

  2. Improved Performance: Generated code via LibraryImport can be more optimized for performance because the marshalling logic is generated at compile-time. This can lead to more efficient interop calls compared to runtime-based in DllImport.

  3. More Flexible Type Marshaling: LibraryImport provides better support for complex types and marshaling scenarios, making it easier to handle custom marshalling, though we don't really need this since all structs should be blittable.

  4. NativeAOT Support: LibraryImport is compatible with NativeAOT, allowing you to use source-generated P/Invoke with ahead-of-time compilation, which can significantly reduce application startup time and improve performance in some scenarios.

  5. Automatic String Marshalling: LibraryImport can automatically handle string marshalling for you, reducing the boilerplate for helper methods.

Cons

  1. Newer Feature: LibraryImport is relatively new (introduced in .NET 7), and not all legacy systems or projects may fully adopt or support it. It might not be as battle-tested as DllImport in every edge case.

  2. Potential Compatibility Issues: LibraryImport may not work with older versions of .NET (prior to .NET 7), limiting its use in projects that need to maintain compatibility with older .NET frameworks.

  3. Less Documentation and Examples: Since it's newer, there are fewer examples and documentation available compared to DllImport, which has been in use for a much longer time.


DllImport

Pros

  1. Widespread Adoption: DllImport is widely used, well-documented, and supported in all versions of .NET, making it a safe and reliable choice for P/Invoke across different projects and .NET versions.

  2. Simpler to Use: DllImport might be simpler to use compared to LibraryImport, which can be beneficial for certain scenarios.

  3. Broad Compatibility: Since it has been around for a long time, DllImport is supported by all versions of .NET, including .NET Framework, ensuring better backward compatibility.

Cons

  1. Manual Code: Developers need to handle marshaling manually, which can lead to errors in complex scenarios, such as dealing with complex data types or memory management issues.

  2. Performance Overhead: Runtime marshaling in DllImport may introduce performance overhead, particularly in scenarios where complex types need to be marshaled frequently.

  3. Lack of Compile-Time Checks: DllImport does not offer the same level of compile-time diagnostics as LibraryImport, meaning issues with interop signatures may only be detected at runtime.


In Practice

Let's take for example the InitWindow function in this project:

[DllImport("raylib", CallingConvention = CallingConvention.Cdecl)]
public static extern void InitWindow(int width, int height, sbyte* title);

However this is unsuitable for managed code, therefore there's an helper method for that:

public static void InitWindow(int width, int height, string title)
{
    using var str1 = title.ToUtf8Buffer();
    InitWindow(width, height, str1.AsPointer());
}

Whereas we can achieve the same thing with only two lines of code:

[LibraryImport(Name, StringMarshalling = StringMarshalling.Utf8)]
public static partial void InitWindow(int width, int height, string title);

Notice the StringMarshalling = StringMarshalling.Utf8, that's used to handle the string marshalling automatically in the generated code.

Now if you want to expose the unsafe version as well, you can do the following:

[LibraryImport("raylib", StringMarshalling = StringMarshalling.Utf8)]
public static partial void InitWindow(int width, int height, string title);

[LibraryImport("raylib")]
public static partial void InitWindow(int width, int height, sbyte* title);

Here we get the following benefits:

  • NativeAOT compatibility.
  • Automatically handle the string marshalling for InitWindow without writing a helper function.
  • Eventually you can write an unsafe version as well with minimal code boilerplate.
  • The unsafe version should also be faster than the one using DllImport.

@MrScautHD
Copy link
Contributor

if you generate the binding you need a github action to build it for every platform or having a Windows, Linux and Mac pc.

@deathbeam
Copy link

deathbeam commented Oct 24, 2024

I was working on generator + new native bindings builder based on raylib zig build that I would want to eventually contribute to raylib-cs after i even out some remaining small issues, but thanks to zig being so easy to work with the natives support linux/osx/windows/wasm already together with support for cross-compilation so huge step up from what raylib-cs has now.

And for generator, the biggest issue is how raylib-cs is structured, e.g a lot of extra helper methods are spread out on the raylib structs, so im not sure how to deal with that. Ideally they should be just partial structs and the helper methods elsewhere, but moving all of them is about as big task as the effort it took to write the generator.

Anyway for anyone interested here is the code now for both bindings + generator:

https://github.com/deathbeam/Raylib.NET

And as i said the end goal is to PR it here ideally as im not interested in further fragmentation of CS raylib bindings (even though its mostly fault of the maintainers, raylib-cs included with its project structure, makes bigger contributions like this very hard).

EDIT:

So got the native generator to good state but the build.zig in 5.0 release is kinda unusable so raylib-cs would first need to get updated to 5.5, rip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants