Stream: general

Topic: C# WIT Bindgen conflicting types from two C# libraries


view this post on Zulip SeanOMik (Nov 08 2024 at 00:29):

I have two C# packages, one called LyraApi, and one called dotnet-guest-test. The first has a WIT world, and uses bindgen to generate code. Then dotnet-guest-test is expected to be the WASM Component and depend on LyraApi to make it easier to use the API exported by the host in the component.

This is the wit of the guest:

package component:witguest;

/// An example world for the component to target.
world example {
    use lyra:api/ecs.{ecs-world, entity};

    export on-init: func(game-world: borrow<ecs-world>, owning-entity: entity) -> result;
}

The package lyra:api/ecs is defined in some other wit files:
image.png
Those wit files are also used by the csharp package LyraApi to generate bindings that it then wraps around to make it easier to interface with the Host. The current problem is that I cant reuse the types that were generated from LyraApi in the component package. They're both created from the same WIT files, but technically different types from different packages.

The Rust wit-bindgen crate has a with field in the bindgen macro that would allow me to reuse types, not sure if thats something that can be done here. I have this project hosted on self-hosted ForgeJo instance so you can see the project structure I'm trying to achieve.

A test zone for implementing WASM scripting into the Lyra engine

view this post on Zulip Joel Dice (Nov 08 2024 at 00:37):

That's certainly the kind of situation the with option of the Rust bindgen macro was intended to address, and it seems reasonable to add an equivalent option to the C# binding generator.

Short of implementing that, I don't know of any workarounds besides possibly editing and/or deleting some of the generated code on the dotnet-guest-test side to force the LyraApi-provided version of that code to be used instead.

view this post on Zulip SeanOMik (Nov 08 2024 at 00:54):

Joel Dice said:

That's certainly the kind of situation the with option of the Rust bindgen macro was intended to address, and it seems reasonable to add an equivalent option to the C# binding generator.

Short of implementing that, I don't know of any workarounds besides possibly editing and/or deleting some of the generated code on the dotnet-guest-test side to force the LyraApi-provided version of that code to be used instead.

Hmm.... Maybe I could try making a Target in the .csproj that would change the generated code to use the LyraApi generated versions. Should I make an issue on github for this?

view this post on Zulip SeanOMik (Nov 08 2024 at 04:07):

Well I used msbuild to modify the generated files after they were generated. I modified them manually but they were discarded when I rebuilt. The changes were made, and they appear to look correct, and the component will build and output a .wasm file.

However, when I try to run it under a wasmtime Rust host, the component runs into an error:

Unhandled exception. System.IO.FileNotFoundException: Could not find file 'LyraApi'.
File name: 'LyraApi'
   at Internal.Runtime.TypeLoaderExceptionHelper.CreateFileNotFoundException(ExceptionStringID, String)
   at ExampleWorld.exports.ExampleWorld.wasmExportOnInit(Int32, Int64, Int64)
Error: failed to call guest function on-init

Caused by:
    0: error while executing at wasm backtrace:
           0: 0x5abae3 - abort
                           at wasisdk://v24.0/build/sysroot/wasi-libc-wasm32-wasip2/libc-bottom-half/sources/abort.c:5:5
           1: 0x3b84d - .tmpmJFMmq!SystemNative_Abort
           2: 0xf841e - .tmpmJFMmq!S_P_CoreLib_Interop_Sys__Abort
           3: 0x45e86d - S_P_CoreLib_System_RuntimeExceptionHelpers__FailFast
                           at /_/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs:320:0
           4: 0xf7691 - S_P_CoreLib_System_RuntimeExceptionHelpers__RuntimeFailFast
                           at /_/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs:161:0
           5: 0x45c3bf - S_P_CoreLib_System_Runtime_EH__HandleUnhandledException
                           at /_/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.wasm.cs:355:0
           6: 0x214738 - .tmpmJFMmq!dotnet_guest_test_ExampleWorld_exports_ExampleWorld__wasmExportOnInit$F0_Filter
           7: 0x3b1077 - S_P_CoreLib_System_Runtime_EH__CallFilterFunclet
                           at /_/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.wasm.cs:163:0
           8: 0x4f9776 - S_P_CoreLib_System_Runtime_EH__DispatchException
                           at /_/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.wasm.cs:92:0
           9: 0x45d19b - S_P_CoreLib_System_Runtime_EH__RhpThrowEx
                           at /_/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.wasm.cs:39:0
          10: 0x27de0c - S_P_CoreLib_Internal_Runtime_TypeLoaderExceptionHelper__CreateFileNotFoundException
                           at /_/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/TypeLoaderExceptionHelper.cs:49:0
          11: 0x36a8b8 - S_P_CoreLib_Internal_Runtime_CompilerHelpers_ThrowHelpers__ThrowFileNotFoundException
                           at /_/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ThrowHelpers.cs:88:0
          12: 0x214691 - .tmpmJFMmq!dotnet_guest_test_ExampleWorld_exports_ExampleWorld__wasmExportOnInit
    1: wasm trap: wasm `unreachable` instruction executed

(the output had WASMTIME_BACKTRACE_DETAILS=1 set)
I'm guessing this is something with the WASM component expecting to import LyraApi at runtime, not sure how to fix it though.

view this post on Zulip Joel Dice (Nov 08 2024 at 15:25):

Yeah, the .NET AOT compiler will silently generate stub code which unconditionally throws a FileNotFoundException if it can't fine the actual code at build time. Are you explicitly declaring a dependency on LyraApi in your .csproj file, e.g. as a PackageReference. If so, it should be pulled in automatically as part of the build.

view this post on Zulip James Sturtevant (Nov 08 2024 at 16:43):

the mis-matched types is a known issue, for some of the base types we would like to move them out of the generator: https://github.com/bytecodealliance/wit-bindgen/issues/1073. As for types generated by your wit, would generating the types in a seperate package and then refrencing them from LyraAPI and dotnet-guest-test help as a work around? partial classes https://github.com/bytecodealliance/wit-bindgen/issues/1041 might help too?

A language binding generator for WebAssembly interface types - c#: Put shared types in a C# lib - https://github.com/bytecodealliance/cm-dotnet · Issue #1073 · bytecodealliance/wit-bindgen
So that the project could extend the types in other files, which are not re-generated. See https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/partial-classes-and-...

view this post on Zulip James Sturtevant (Nov 08 2024 at 16:44):

creating an issue would be helpful, especially with some example wit that would demonstrate the issue

view this post on Zulip SeanOMik (Nov 08 2024 at 20:46):

Joel Dice said:

Yeah, the .NET AOT compiler will silently generate stub code which unconditionally throws a FileNotFoundException if it can't fine the actual code at build time. Are you explicitly declaring a dependency on LyraApi in your .csproj file, e.g. as a PackageReference. If so, it should be pulled in automatically as part of the build.

I'm using ProjectReference, not PackageReference:

<ItemGroup>
  <ProjectReference Include="..\LyraApi\LyraApi.csproj" />
</ItemGroup>

Would ProjectReference not work the same as PackageReference? New to C# so I assumed the only difference was that one was so I could reference a local project.

view this post on Zulip SeanOMik (Nov 08 2024 at 20:49):

James Sturtevant said:

the mis-matched types is a known issue, for some of the base types we would like to move them out of the generator: https://github.com/bytecodealliance/wit-bindgen/issues/1073. As for types generated by your wit, would generating the types in a seperate package and then refrencing them from LyraAPI and dotnet-guest-test help as a work around?

That would work. I'm not sure how I would be able to do that though since I can't make wit-bindgen use generated bindings from another project.

partial classes https://github.com/bytecodealliance/wit-bindgen/issues/1041 might help too?

I dont think so. I want LyraApi to be a scripting api and wrap around the low level types. It would make it so the user of LyraApi doesn't have to deal with byte serialization and other low level things as much that is required to communicate with the host.

view this post on Zulip Joel Dice (Nov 08 2024 at 21:34):

Would ProjectReference not work the same as PackageReference? New to C# so I assumed the only difference was that one was so I could reference a local project.

I'm also new to C#, and my understanding is the same as yours, so I'm not sure what's wrong. You might want to consider posting to the NativeAOT-LLVM Discord thread with a link to the repo and steps to reproduce. The experts hang out there and are super helpful in my experience.

Discord is great for playing games and chilling with friends, or even building a worldwide community. Customize your own space to talk, play, and hang out.

view this post on Zulip Ralph (Nov 11 2024 at 22:26):

@Pavel Šavara is here at wasmcon, I'll see about grabbing his attention....

view this post on Zulip SeanOMik (Nov 11 2024 at 22:31):

I forgot to say here. The people in Discord were pretty helpful. "SingleAccretion" discovered that the way the build process of componentize-dotnet is made is broken, which causes the dependencies of my library to not be baked into the final WASM binary. Here's the messages of him explaining the issue more: https://discord.com/channels/143867839282020352/1141126727028985877/1304883306063724624
I can send a screenshot of the messages as well for people who don't have discord.

Discord is great for playing games and chilling with friends, or even building a worldwide community. Customize your own space to talk, play, and hang out.

Last updated: Dec 23 2024 at 12:05 UTC