SteveSandersonMS / dotnet-wasi-sdk

Packages for building .NET projects as standalone WASI-compliant modules
518 stars 36 forks source link

C#-only way to declare wasm imports and exports #30

Open SteveSandersonMS opened 2 years ago

SteveSandersonMS commented 2 years ago

Currently to declare a custom WebAssembly import or export you have to write C code, e.g., https://github.com/SteveSandersonMS/dotnet-wasi-sdk/blob/main/src/Wasi.AspNetCore.Server.CustomHost/native/server_interop.c#L7-L17

We should make it possible to declare such imports/exports using just C# only without any native code.

At a basic level this could be achieved fairly easily by codegenerating the equivalent C code that uses the Mono embedding APIs to invoke C#. However going further, we'd want to be able to receive and return nontrivial types, which probably involves a C# sourcegenerator for WIT.

inkeliz commented 2 years ago

There's any simpler example of how use export/import, when using the C?

SteveSandersonMS commented 2 years ago

No, https://github.com/SteveSandersonMS/dotnet-wasi-sdk/blob/main/src/Wasi.AspNetCore.Server.CustomHost/native/server_interop.c is about as simple as it gets. That's why we should make a simpler mechanism with C# only.

inkeliz commented 2 years ago

I understand the motivation to add C#-only. I'm trying to figure out how server_interop.c works.

Just to make sure, I need to have the Mono toolchain and compile the my_interop.c? The README mention that "You can optionally include other native sources such as .c files in the compilation.", but I'm struggling to understand how to make my C code interact with Mono and get compiled. 🧐

SteveSandersonMS commented 2 years ago

No, you don't need Mono. No other build tools are needed. Just reference your .c file with WasiNativeFileReference like the Wasi.AspNetCore.Server.CustomHost project does, and it will be included in the compilation.

flavio commented 2 years ago

There's any simpler example of how use export/import, when using the C?

@inkeliz: you might want to take a look at https://github.com/flavio/wapc-guest-dotnet/blob/main/src/WapcGuest/native/wapc_ffi.c This is a smaller example.

I hope that helps!

inkeliz commented 2 years ago

Thank you, @flavio. I think that will be very useful for any future readers. My primary concern was how to compile that, since I'm not familiar with C#/Dotnet, so I'm not sure how things are suppose to compile. 😅

I manage to use force the compilation including the WasiNativeFileReference, as @SteveSandersonMS said. However, I need to include that into the .csproj directly. I'm not sure why the build folder doesn't work, where is the result. Since that is just for testing, not a library, I think it's fine.

SteveSandersonMS commented 2 years ago

I need to include that into the .csproj directly

Good, that's the right thing to do if you're just testing! Having .props/.targets files that get bundled into a NuGet package is only for people shipping NuGet packages - it's nothing specific to dotnet-wasi-sdk but more of a general NuGet/MSBuild pattern.

ChristianWeyer commented 1 year ago

Maybe the experimental LLVM-based approach could be a way forward...? https://github.com/dotnet/runtimelab/blob/feature/NativeAOT-LLVM/docs/using-nativeaot/compiling.md#webassembly-native-libraries

.cc @SteveSandersonMS

ghost commented 1 year ago

``Hello, i do have an unresolved doubt: is there a way, when for example compiling with wasi a classlib (.dll), to mark as exported the methods i want and use those methods importing the .wasm file in an application via wasmtime for example?

I tried, for ease of testing, to build a classlib with a generic method

namespace wasmlibrary;
public static class Class1
{
    public static int method(int i)
    {
        return i++;
    }
}

and in another console project use wasmtime.net to load the module


 using (var engine = new Engine())
        using (var store = new Store(engine))
        using (var linker = new Linker(engine))
        using (var module = Module.FromFile(engine, "../../../../wasmlibrary/bin/Debug/net7.0/wasmlibrary.wasm"))
        {
            linker.DefineWasi();  
            dynamic instance = linker.Instantiate(store, module);
            var run = instance.GetFunction<int, int>("method");
        }

but, debugging, module only exports the basic methods (malloc, free, _run, etc..), and run is null, meaning that the method is not exported.

thanks to everyone in advance!

iwate commented 1 year ago

I tried exporting wasi-wasm function by using ILCompiler.LLVM. And it worked.

https://github.com/iwate/learn-wasm-with-dotnet/tree/main/challenge09/wasilib