From 5ca528ec849e8643ae782b4379cbf1faa14eb205 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Tue, 17 Oct 2023 20:27:44 +0300 Subject: [PATCH 01/23] feat: enable importing/exporting functions from referenced assemblies --- Extism.Pdk.sln | 7 + samples/KitchenSink/KitchenSink.csproj | 5 + samples/KitchenSink/Program.cs | 2 + samples/SampleLib/Class1.cs | 19 +++ samples/SampleLib/SampleLib.csproj | 13 ++ src/Extism.Pdk.MSBuild/FFIGenerator.cs | 24 +++- src/Extism.Pdk.MSBuild/GenerateFFITask.cs | 10 +- src/Extism.Pdk/build/Extism.Pdk.targets | 6 +- .../ExtismFFIGeneratorTests.cs | 78 ++++++++++- .../snapshots/import-references.txt | 28 ++++ .../snapshots/reference-exports.txt | 125 ++++++++++++++++++ 11 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 samples/SampleLib/Class1.cs create mode 100644 samples/SampleLib/SampleLib.csproj create mode 100644 tests/Extism.Pdk.MsBuild.Tests/snapshots/import-references.txt create mode 100644 tests/Extism.Pdk.MsBuild.Tests/snapshots/reference-exports.txt diff --git a/Extism.Pdk.sln b/Extism.Pdk.sln index d0dc383..d6625d3 100644 --- a/Extism.Pdk.sln +++ b/Extism.Pdk.sln @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KitchenSink", "samples\Kitc EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Extism.Pdk.WasmTests", "tests\Extism.Pdk.WasmTests\Extism.Pdk.WasmTests.csproj", "{F603C66E-1821-4E5F-94EF-09D5BB9A04A3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleLib", "samples\SampleLib\SampleLib.csproj", "{FD3EBC89-BE62-402F-A5E4-D7298134658E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -61,6 +63,10 @@ Global {F603C66E-1821-4E5F-94EF-09D5BB9A04A3}.Debug|Any CPU.Build.0 = Debug|Any CPU {F603C66E-1821-4E5F-94EF-09D5BB9A04A3}.Release|Any CPU.ActiveCfg = Release|Any CPU {F603C66E-1821-4E5F-94EF-09D5BB9A04A3}.Release|Any CPU.Build.0 = Release|Any CPU + {FD3EBC89-BE62-402F-A5E4-D7298134658E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD3EBC89-BE62-402F-A5E4-D7298134658E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD3EBC89-BE62-402F-A5E4-D7298134658E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD3EBC89-BE62-402F-A5E4-D7298134658E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -72,6 +78,7 @@ Global {21861C9B-3C91-46BA-A4D1-5A919FF0113F} = {604F9655-E3D7-4E42-9D5D-91FBCACCD565} {F045BCA5-71DC-483F-8D9F-D1416F6AB588} = {E54FB503-86BE-459F-A7B4-DF2AA9094CEE} {F603C66E-1821-4E5F-94EF-09D5BB9A04A3} = {604F9655-E3D7-4E42-9D5D-91FBCACCD565} + {FD3EBC89-BE62-402F-A5E4-D7298134658E} = {E54FB503-86BE-459F-A7B4-DF2AA9094CEE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F37E205A-FB9F-4C44-B098-ACBF87CF9FF5} diff --git a/samples/KitchenSink/KitchenSink.csproj b/samples/KitchenSink/KitchenSink.csproj index 2f06f88..d874de2 100644 --- a/samples/KitchenSink/KitchenSink.csproj +++ b/samples/KitchenSink/KitchenSink.csproj @@ -14,6 +14,11 @@ + + + + + diff --git a/samples/KitchenSink/Program.cs b/samples/KitchenSink/Program.cs index 165a956..e2aa3d2 100644 --- a/samples/KitchenSink/Program.cs +++ b/samples/KitchenSink/Program.cs @@ -2,7 +2,9 @@ using System; using Extism; using System.Text.Json; +using SampleLib; +Class1.noop(); // Import Class1 from SampleLib so that it's included during compilation Console.WriteLine("Hello world!"); namespace Functions diff --git a/samples/SampleLib/Class1.cs b/samples/SampleLib/Class1.cs new file mode 100644 index 0000000..f57dc50 --- /dev/null +++ b/samples/SampleLib/Class1.cs @@ -0,0 +1,19 @@ +using System.Runtime.InteropServices; + +namespace SampleLib; +public class Class1 +{ + [DllImport("env", EntryPoint = "do_something")] + public static extern void do_something(); + + [UnmanagedCallersOnly(EntryPoint = "useful_method")] + public static void useful_method() + { + + } + + public static void noop() + { + + } +} diff --git a/samples/SampleLib/SampleLib.csproj b/samples/SampleLib/SampleLib.csproj new file mode 100644 index 0000000..6b68d7f --- /dev/null +++ b/samples/SampleLib/SampleLib.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/src/Extism.Pdk.MSBuild/FFIGenerator.cs b/src/Extism.Pdk.MSBuild/FFIGenerator.cs index 90e472f..f7e6424 100644 --- a/src/Extism.Pdk.MSBuild/FFIGenerator.cs +++ b/src/Extism.Pdk.MSBuild/FFIGenerator.cs @@ -15,21 +15,30 @@ public FFIGenerator(string env, Action logError) _env = env; } - public IEnumerable GenerateGlueCode(AssemblyDefinition assembly) + public IEnumerable GenerateGlueCode(AssemblyDefinition assembly, string directory, HashSet entryPointAssemblies) { - var exportedMethods = assembly.MainModule.Types - .SelectMany(t => t.Methods) - .Where(m => m.IsStatic && m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute")) + var assemblies = assembly.MainModule.AssemblyReferences + .Where(r => entryPointAssemblies.Contains(r.Name)) + .Select(r => AssemblyDefinition.ReadAssembly(Path.Combine(directory, r.Name + ".dll"))) + .ToList(); + + assemblies.Add(assembly); + + var types = assemblies.SelectMany(a => a.MainModule.Types).ToArray(); + + var exportedMethods = types + .SelectMany(t => t.Methods) + .Where(m => m.IsStatic && m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute")) .ToArray(); // TODO: also find F# module functions - var importedMethods = assembly.MainModule.Types + var importedMethods = types .SelectMany(t => t.Methods) .Where(m => m.HasPInvokeInfo) .ToArray(); var files = GenerateImports(importedMethods, _env); - files.Add(GenerateExports(assembly.Name.Name + ".dll", exportedMethods)); + files.Add(GenerateExports(exportedMethods)); return files; } @@ -80,7 +89,7 @@ private List GenerateImports(MethodDefinition[] importedMethods, stri return files; } - private FileEntry GenerateExports(string assemblyFileName, MethodDefinition[] exportedMethods) + private FileEntry GenerateExports(MethodDefinition[] exportedMethods) { var sb = new StringBuilder(); @@ -140,6 +149,7 @@ void extism_print_exception(MonoObject* exc) foreach (var method in exportedMethods) { + var assemblyFileName = method.Module.Assembly.Name.Name + ".dll"; var attribute = method.CustomAttributes.First(a => a.AttributeType.Name == "UnmanagedCallersOnlyAttribute"); var exportName = attribute.Fields.FirstOrDefault(p => p.Name == "EntryPoint").Argument.Value?.ToString() ?? method.Name; diff --git a/src/Extism.Pdk.MSBuild/GenerateFFITask.cs b/src/Extism.Pdk.MSBuild/GenerateFFITask.cs index 2b7b8cd..37812b7 100644 --- a/src/Extism.Pdk.MSBuild/GenerateFFITask.cs +++ b/src/Extism.Pdk.MSBuild/GenerateFFITask.cs @@ -17,6 +17,9 @@ public class GenerateFFITask : Microsoft.Build.Utilities.Task [Required] public string EnvPath { get; set; } + [Required] + public ITaskItem[] UnmanagedEntryPointsAssemblies { get; set; } + public override bool Execute() { try @@ -38,7 +41,12 @@ public override bool Execute() var generator = new FFIGenerator(File.ReadAllText(EnvPath), (string message) => Log.LogError(message)); - foreach (var file in generator.GenerateGlueCode(assembly)) + var references = new HashSet( + UnmanagedEntryPointsAssemblies + .Select(a => a.GetMetadata("Identity")) + .Where(x => x is not null)); + + foreach (var file in generator.GenerateGlueCode(assembly, Path.GetDirectoryName(AssemblyPath), references)) { File.WriteAllText(Path.Combine(OutputPath, file.Name), file.Content); } diff --git a/src/Extism.Pdk/build/Extism.Pdk.targets b/src/Extism.Pdk/build/Extism.Pdk.targets index 41a1610..57dfb67 100644 --- a/src/Extism.Pdk/build/Extism.Pdk.targets +++ b/src/Extism.Pdk/build/Extism.Pdk.targets @@ -1,7 +1,11 @@ - + + <_WasmNativeFileForLinking Include="@(NativeFileReference)" /> diff --git a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs index dc18893..ca870f6 100644 --- a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs +++ b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs @@ -18,7 +18,7 @@ public void CanHandleEmptyAssemblies() var assembly = CecilExtensions.CreateSampleAssembly("SampleApp"); - var files = generator.GenerateGlueCode(assembly); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); } [Fact] @@ -34,7 +34,7 @@ public void CanImportFromEnv() _ = type.CreateMethod("DoSomething", typeof(void), ("p1", typeof(int)), ("p2", typeof(byte)), ("p3", typeof(long))) .AddImport("env", "do_something"); - var files = generator.GenerateGlueCode(assembly); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); var envFile = files.Single(f => f.Name == "env.c"); envFile.Content.Trim().ShouldBe( @@ -66,7 +66,7 @@ public void CanImportFromCustomModules() _ = type.CreateMethod("GetLength", typeof(int), ("p1", typeof(float))) .AddImport("host", null); - var files = generator.GenerateGlueCode(assembly); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); var hostFile = files.Single(f => f.Name == "host.c"); var expected = File.ReadAllText("snapshots/import-custom-module.txt"); @@ -98,7 +98,7 @@ public void CanExportMethods() _ = type.CreateMethod("DoSomeOtherStuff", typeof(int), ("longParameterNameHere", typeof(double))) .AddExport("fancy_name"); - var files = generator.GenerateGlueCode(assembly); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); var file = files.Single(f => f.Name == "exports.c"); var expected = File.ReadAllText("snapshots/exports.txt"); @@ -106,6 +106,67 @@ public void CanExportMethods() AssertContent(env, files, "env.c"); } + + [Fact] + public void CanExportMethodFromReferences() + { + var env = "// env stuff"; + var generator = new FFIGenerator(env, (m) => { }); + + var lib = CecilExtensions.CreateSampleAssembly("SampleLib"); + + var type = lib.MainModule.CreateType("MyNamespace", "MyClass"); + + _ = type.CreateMethod("DoSomething", typeof(void), ("p1", typeof(int)), ("p2", typeof(byte)), ("p3", typeof(long))) + .AddExport(); + + _ = type.CreateMethod("DoSomeOtherStuff", typeof(int), ("longParameterNameHere", typeof(double))) + .AddExport("fancy_name"); + + lib.Write("SampleLib.dll"); + + var assembly = CecilExtensions.CreateSampleAssembly("SampleApp") + .WithReferenceTo(lib); + + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet { "SampleLib" }); + + var file = files.Single(f => f.Name == "exports.c"); + var expected = File.ReadAllText("snapshots/reference-exports.txt"); + file.Content.Trim().ShouldBe(expected, StringCompareShould.IgnoreLineEndings); + + AssertContent(env, files, "env.c"); + } + + // This breaks Cecil, see: https://github.com/jbevain/cecil/issues/926 + //[Fact] + public void CanImportFromReferences() + { + var env = "// env stuff"; + var generator = new FFIGenerator(env, (m) => { }); + + var lib = CecilExtensions.CreateSampleAssembly("SampleLib2"); + var type = lib.MainModule.CreateType("MyNamespace", "MyClass"); + + var m1 = type.CreateMethod("DoSomething", typeof(void), ("p1", typeof(int)), ("p2", typeof(byte)), ("p3", typeof(long))) + .AddImport("host", "do_something"); + + var m2 = type.CreateMethod("GetLength", typeof(int), ("p1", typeof(float))) + .AddImport("host", null); + + lib.Write("SampleLib2.dll"); + + var assembly = CecilExtensions.CreateSampleAssembly("SampleApp") + .WithReferenceTo(lib); + + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet { "SampleLib2" }); + + var hostFile = files.Single(f => f.Name == "host.c"); + var expected = File.ReadAllText("snapshots/import-references.txt"); + hostFile.Content.Trim().ShouldBe(expected, StringCompareShould.IgnoreLineEndings); + + AssertContent(env, files, "env.c"); + files.ShouldNotContain(f => f.Name == "export.c"); + } } public static class CecilExtensions @@ -121,6 +182,12 @@ public static AssemblyDefinition CreateSampleAssembly(string name) return assembly; } + public static AssemblyDefinition WithReferenceTo(this AssemblyDefinition main, AssemblyDefinition reference) + { + main.MainModule.AssemblyReferences.Add(reference.Name); + return main; + } + public static TypeDefinition CreateType(this ModuleDefinition module, string ns, string name) { var type = new TypeDefinition( @@ -157,6 +224,9 @@ public static MethodDefinition AddImport(this MethodDefinition method, string mo method.Attributes |= MethodAttributes.PInvokeImpl; method.ImplAttributes |= MethodImplAttributes.PreserveSig | (MethodImplAttributes)pinvokeInfo.Attributes; + method.IsPInvokeImpl = true; + method.IsPreserveSig = true; + return method; } diff --git a/tests/Extism.Pdk.MsBuild.Tests/snapshots/import-references.txt b/tests/Extism.Pdk.MsBuild.Tests/snapshots/import-references.txt new file mode 100644 index 0000000..3dcb814 --- /dev/null +++ b/tests/Extism.Pdk.MsBuild.Tests/snapshots/import-references.txt @@ -0,0 +1,28 @@ +#include +#include +#include + +// https://github.com/dotnet/runtime/blob/v7.0.0/src/mono/wasi/mono-wasi-driver/driver.c +#include + +#include "driver.h" + +#include +#include +#include +#include +#include + +#define IMPORT(a, b) __attribute__((import_module(a), import_name(b))) + +typedef uint64_t ExtismPointer; +IMPORT("host", "do_something") extern void do_something_import(int32_t p1, uint8_t p2, int64_t p3); + +void do_something(int32_t p1, uint8_t p2, int64_t p3) { + do_something_import(p1, p2, p3); +} +IMPORT("host", "GetLength") extern int32_t GetLength_import(float p1); + +int32_t GetLength(float p1) { + return GetLength_import(p1); +} \ No newline at end of file diff --git a/tests/Extism.Pdk.MsBuild.Tests/snapshots/reference-exports.txt b/tests/Extism.Pdk.MsBuild.Tests/snapshots/reference-exports.txt new file mode 100644 index 0000000..e7d0e66 --- /dev/null +++ b/tests/Extism.Pdk.MsBuild.Tests/snapshots/reference-exports.txt @@ -0,0 +1,125 @@ +#include +#include +#include + +// https://github.com/dotnet/runtime/blob/v7.0.0/src/mono/wasi/mono-wasi-driver/driver.c +#include + +#include "driver.h" + +#include +#include +#include +#include +#include + +#define IMPORT(a, b) __attribute__((import_module(a), import_name(b))) + +typedef uint64_t ExtismPointer; +// _initialize +void mono_wasm_load_runtime(const char* unused, int debug_level); + +#ifdef WASI_AFTER_RUNTIME_LOADED_DECLARATIONS +// This is supplied from the MSBuild itemgroup @(WasiAfterRuntimeLoaded) +WASI_AFTER_RUNTIME_LOADED_DECLARATIONS +#endif + +void initialize_runtime() { + mono_wasm_load_runtime("", 0); +} + +// end of _initialize + +void mono_wasm_invoke_method_ref(MonoMethod* method, MonoObject** this_arg_in, void* params[], MonoObject** _out_exc, MonoObject** out_result); +MonoString* mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error); +void mono_print_unhandled_exception(MonoObject *exc); + +MonoMethod* method_extism_print_exception; +void extism_print_exception(MonoObject* exc) +{ + if (!method_extism_print_exception) + { + method_extism_print_exception = lookup_dotnet_method("Extism.Pdk.dll", "Extism", "Native", "PrintException", -1); + + if (method_extism_print_exception == NULL) { + printf("Fatal: Failed to find Extism.Native.PrintException"); + } + + assert(method_extism_print_exception); + } + + void* method_params[] = { exc }; + MonoObject* exception = NULL; + MonoObject* result = NULL; + mono_wasm_invoke_method_ref(method_extism_print_exception, NULL, method_params, &exception, &result); + + if (exception != NULL) { + const char* message = "An exception was thrown while trying to print the previous exception. Please check stderr for details."; + mono_print_unhandled_exception(exception); + } +} + +MonoMethod* method_DoSomething; +__attribute__((export_name("DoSomething"))) int DoSomething() +{ + initialize_runtime(); + + if (!method_DoSomething) + { + method_DoSomething = lookup_dotnet_method("SampleLib.dll", "SampleNamespace", "SampleType", "DoSomething", -1); + assert(method_DoSomething); + } + + void* method_params[] = { }; + MonoObject* exception = NULL; + MonoObject* result = NULL; + mono_wasm_invoke_method_ref(method_DoSomething, NULL, method_params, &exception, &result); + + if (exception != NULL) { + const char* message = "An exception was thrown when calling DoSomething. Please check stderr for details."; + mono_print_unhandled_exception(exception); + + extism_print_exception(exception); + return 1; + } + + int int_result = 0; // Default value + + if (result != NULL) { + int_result = *(int*)mono_object_unbox(result); + } + + return int_result; +} +MonoMethod* method_fancy_name; +__attribute__((export_name("fancy_name"))) int fancy_name() +{ + initialize_runtime(); + + if (!method_fancy_name) + { + method_fancy_name = lookup_dotnet_method("SampleLib.dll", "SampleNamespace", "SampleType", "DoSomeOtherStuff", -1); + assert(method_fancy_name); + } + + void* method_params[] = { }; + MonoObject* exception = NULL; + MonoObject* result = NULL; + mono_wasm_invoke_method_ref(method_fancy_name, NULL, method_params, &exception, &result); + + if (exception != NULL) { + const char* message = "An exception was thrown when calling fancy_name. Please check stderr for details."; + mono_print_unhandled_exception(exception); + + extism_print_exception(exception); + return 1; + } + + int int_result = 0; // Default value + + if (result != NULL) { + int_result = *(int*)mono_object_unbox(result); + } + + return int_result; +} \ No newline at end of file From a683ec1ed79d6bbbe02e762440fbabc0307f0a31 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Thu, 19 Oct 2023 11:32:43 +0300 Subject: [PATCH 02/23] scan all references by default --- samples/KitchenSink/KitchenSink.csproj | 4 ---- samples/SampleLib/Class1.cs | 8 ++++---- src/Extism.Pdk.MSBuild/FFIGenerator.cs | 4 ++-- src/Extism.Pdk.MSBuild/GenerateFFITask.cs | 10 +--------- src/Extism.Pdk/build/Extism.Pdk.targets | 3 +-- .../ExtismFFIGeneratorTests.cs | 12 ++++++------ 6 files changed, 14 insertions(+), 27 deletions(-) diff --git a/samples/KitchenSink/KitchenSink.csproj b/samples/KitchenSink/KitchenSink.csproj index d874de2..17eceb4 100644 --- a/samples/KitchenSink/KitchenSink.csproj +++ b/samples/KitchenSink/KitchenSink.csproj @@ -17,10 +17,6 @@ - - - - diff --git a/samples/SampleLib/Class1.cs b/samples/SampleLib/Class1.cs index f57dc50..6e67e83 100644 --- a/samples/SampleLib/Class1.cs +++ b/samples/SampleLib/Class1.cs @@ -3,11 +3,11 @@ namespace SampleLib; public class Class1 { - [DllImport("env", EntryPoint = "do_something")] - public static extern void do_something(); + [DllImport("env", EntryPoint = "samplelib_import")] + public static extern void samplelib_import(); - [UnmanagedCallersOnly(EntryPoint = "useful_method")] - public static void useful_method() + [UnmanagedCallersOnly(EntryPoint = "samplelib_export")] + public static void samplelib_export() { } diff --git a/src/Extism.Pdk.MSBuild/FFIGenerator.cs b/src/Extism.Pdk.MSBuild/FFIGenerator.cs index f7e6424..d6bc1fa 100644 --- a/src/Extism.Pdk.MSBuild/FFIGenerator.cs +++ b/src/Extism.Pdk.MSBuild/FFIGenerator.cs @@ -15,10 +15,10 @@ public FFIGenerator(string env, Action logError) _env = env; } - public IEnumerable GenerateGlueCode(AssemblyDefinition assembly, string directory, HashSet entryPointAssemblies) + public IEnumerable GenerateGlueCode(AssemblyDefinition assembly, string directory) { var assemblies = assembly.MainModule.AssemblyReferences - .Where(r => entryPointAssemblies.Contains(r.Name)) + .Where(r => !r.Name.StartsWith("System") && !r.Name.StartsWith("Microsoft") && r.Name != "Extism.Pdk") .Select(r => AssemblyDefinition.ReadAssembly(Path.Combine(directory, r.Name + ".dll"))) .ToList(); diff --git a/src/Extism.Pdk.MSBuild/GenerateFFITask.cs b/src/Extism.Pdk.MSBuild/GenerateFFITask.cs index 37812b7..41a31c5 100644 --- a/src/Extism.Pdk.MSBuild/GenerateFFITask.cs +++ b/src/Extism.Pdk.MSBuild/GenerateFFITask.cs @@ -17,9 +17,6 @@ public class GenerateFFITask : Microsoft.Build.Utilities.Task [Required] public string EnvPath { get; set; } - [Required] - public ITaskItem[] UnmanagedEntryPointsAssemblies { get; set; } - public override bool Execute() { try @@ -41,12 +38,7 @@ public override bool Execute() var generator = new FFIGenerator(File.ReadAllText(EnvPath), (string message) => Log.LogError(message)); - var references = new HashSet( - UnmanagedEntryPointsAssemblies - .Select(a => a.GetMetadata("Identity")) - .Where(x => x is not null)); - - foreach (var file in generator.GenerateGlueCode(assembly, Path.GetDirectoryName(AssemblyPath), references)) + foreach (var file in generator.GenerateGlueCode(assembly, Path.GetDirectoryName(AssemblyPath))) { File.WriteAllText(Path.Combine(OutputPath, file.Name), file.Content); } diff --git a/src/Extism.Pdk/build/Extism.Pdk.targets b/src/Extism.Pdk/build/Extism.Pdk.targets index 57dfb67..961550d 100644 --- a/src/Extism.Pdk/build/Extism.Pdk.targets +++ b/src/Extism.Pdk/build/Extism.Pdk.targets @@ -3,8 +3,7 @@ + EnvPath="$(MSBuildThisFileDirectory)..\native\env.c" /> diff --git a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs index ca870f6..e261bba 100644 --- a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs +++ b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs @@ -18,7 +18,7 @@ public void CanHandleEmptyAssemblies() var assembly = CecilExtensions.CreateSampleAssembly("SampleApp"); - var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory()); } [Fact] @@ -34,7 +34,7 @@ public void CanImportFromEnv() _ = type.CreateMethod("DoSomething", typeof(void), ("p1", typeof(int)), ("p2", typeof(byte)), ("p3", typeof(long))) .AddImport("env", "do_something"); - var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory()); var envFile = files.Single(f => f.Name == "env.c"); envFile.Content.Trim().ShouldBe( @@ -66,7 +66,7 @@ public void CanImportFromCustomModules() _ = type.CreateMethod("GetLength", typeof(int), ("p1", typeof(float))) .AddImport("host", null); - var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory()); var hostFile = files.Single(f => f.Name == "host.c"); var expected = File.ReadAllText("snapshots/import-custom-module.txt"); @@ -98,7 +98,7 @@ public void CanExportMethods() _ = type.CreateMethod("DoSomeOtherStuff", typeof(int), ("longParameterNameHere", typeof(double))) .AddExport("fancy_name"); - var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet()); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory()); var file = files.Single(f => f.Name == "exports.c"); var expected = File.ReadAllText("snapshots/exports.txt"); @@ -128,7 +128,7 @@ public void CanExportMethodFromReferences() var assembly = CecilExtensions.CreateSampleAssembly("SampleApp") .WithReferenceTo(lib); - var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet { "SampleLib" }); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory()); var file = files.Single(f => f.Name == "exports.c"); var expected = File.ReadAllText("snapshots/reference-exports.txt"); @@ -158,7 +158,7 @@ public void CanImportFromReferences() var assembly = CecilExtensions.CreateSampleAssembly("SampleApp") .WithReferenceTo(lib); - var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory(), new HashSet { "SampleLib2" }); + var files = generator.GenerateGlueCode(assembly, Directory.GetCurrentDirectory()); var hostFile = files.Single(f => f.Name == "host.c"); var expected = File.ReadAllText("snapshots/import-references.txt"); From e18e2ec3e31bbd901ba850d79ee8a04ec852df7d Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Mon, 30 Oct 2023 17:07:53 +0300 Subject: [PATCH 03/23] fix: add module reference to assembly for CanImportFromReferences --- src/Extism.Pdk.MSBuild/FFIGenerator.cs | 2 +- tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Extism.Pdk.MSBuild/FFIGenerator.cs b/src/Extism.Pdk.MSBuild/FFIGenerator.cs index d6bc1fa..eaa0b48 100644 --- a/src/Extism.Pdk.MSBuild/FFIGenerator.cs +++ b/src/Extism.Pdk.MSBuild/FFIGenerator.cs @@ -201,7 +201,7 @@ void extism_print_exception(MonoObject* exc) private string ToImportStatement(MethodDefinition method) { var moduleName = method.PInvokeInfo.Module.Name; - var functionName = method.PInvokeInfo.EntryPoint ?? method.Name; + var functionName = string.IsNullOrEmpty(method.PInvokeInfo.EntryPoint) ? method.Name : method.PInvokeInfo.EntryPoint; if (!_types.ContainsKey(method.ReturnType.Name)) { diff --git a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs index e261bba..263f978 100644 --- a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs +++ b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs @@ -137,8 +137,7 @@ public void CanExportMethodFromReferences() AssertContent(env, files, "env.c"); } - // This breaks Cecil, see: https://github.com/jbevain/cecil/issues/926 - //[Fact] + [Fact] public void CanImportFromReferences() { var env = "// env stuff"; @@ -219,7 +218,8 @@ public static MethodDefinition CreateMethod(this TypeDefinition type, string nam public static MethodDefinition AddImport(this MethodDefinition method, string moduleName, string? entryPoint = null) { - var pinvokeInfo = new PInvokeInfo(PInvokeAttributes.CallConvCdecl, entryPoint, new ModuleReference(moduleName)); + var moduleReference = new ModuleReference(moduleName); + var pinvokeInfo = new PInvokeInfo(PInvokeAttributes.CallConvCdecl, entryPoint, moduleReference); method.PInvokeInfo = pinvokeInfo; method.Attributes |= MethodAttributes.PInvokeImpl; method.ImplAttributes |= MethodImplAttributes.PreserveSig | (MethodImplAttributes)pinvokeInfo.Attributes; @@ -227,6 +227,8 @@ public static MethodDefinition AddImport(this MethodDefinition method, string mo method.IsPInvokeImpl = true; method.IsPreserveSig = true; + method.Module.Assembly.MainModule.ModuleReferences.Add(moduleReference); + return method; } From 1b87462e5fb1a17436b564692d4170c6737350f2 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 14:23:50 +0300 Subject: [PATCH 04/23] use dotnet sdk for the tests --- samples/SampleLib/Class1.cs | 2 +- .../ExtismFFIGeneratorTests.cs | 4 +- .../Extism.Pdk.WasmTests.csproj | 44 ++--- .../Extism.Pdk.WasmTests/KitchenSinkTests.cs | 159 +++++++++++------- 4 files changed, 119 insertions(+), 90 deletions(-) diff --git a/samples/SampleLib/Class1.cs b/samples/SampleLib/Class1.cs index 6e67e83..796796d 100644 --- a/samples/SampleLib/Class1.cs +++ b/samples/SampleLib/Class1.cs @@ -9,7 +9,7 @@ public class Class1 [UnmanagedCallersOnly(EntryPoint = "samplelib_export")] public static void samplelib_export() { - + samplelib_import(); } public static void noop() diff --git a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs index 1f1d8c4..a19e628 100644 --- a/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs +++ b/tests/Extism.Pdk.MsBuild.Tests/ExtismFFIGeneratorTests.cs @@ -134,7 +134,7 @@ public void CanExportMethodFromReferences() var expected = File.ReadAllText("snapshots/reference-exports.txt"); file.Content.Trim().ShouldBe(expected, StringCompareShould.IgnoreLineEndings); - AssertContent(env, files, "env.c"); + AssertContent(env, files, "extism.c"); } [Fact] @@ -163,7 +163,7 @@ public void CanImportFromReferences() var expected = File.ReadAllText("snapshots/import-references.txt"); hostFile.Content.Trim().ShouldBe(expected, StringCompareShould.IgnoreLineEndings); - AssertContent(env, files, "env.c"); + AssertContent(env, files, "extism.c"); files.ShouldNotContain(f => f.Name == "export.c"); } } diff --git a/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj b/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj index fa236d7..71aafcc 100644 --- a/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj +++ b/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj @@ -1,27 +1,27 @@ - - net8.0 - enable - enable + + net8.0 + enable + enable + false + true + - false - true - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + diff --git a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs index f44a1d4..314e0a2 100644 --- a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs +++ b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs @@ -1,120 +1,123 @@ using CliWrap; using CliWrap.Buffered; +using Extism.Sdk.Native; using Shouldly; +using Extism.Sdk; +using System.Text; namespace Extism.Pdk.WasmTests; public class KitchenSinkTests { [Fact] - public async void TestLen() + public void TestLen() { - var path = GetWasmPath("KitchenSink"); - var (stdout, exit, stderr) = await Call(path, "len", new ExtismOptions - { - Loop = 3, - Input = "Hello World!" - }); + using var plugin = CreatePlugin("KitchenSink"); - stderr.ShouldBe(""); - exit.ShouldBe(0); - stdout.ShouldBe("12\n12\n12\n"); + for (var i = 0; i < 3; i++) + { + var result = plugin.Call("len", Encoding.UTF8.GetBytes("Hello World!")); + var stdout = Encoding.UTF8.GetString(result); + stdout.ShouldBe("12"); + } } [Fact] - public async void TestConcat() + public void TestConcat() { - var path = GetWasmPath("KitchenSink"); - var (stdout, exit, stderr) = await Call(path, "concat", new ExtismOptions - { - Loop = 3, - Input = $$"""{ "Separator": ",", "Parts": ["hello", "world!"]}""" - }); + using var plugin = CreatePlugin("KitchenSink"); + + var input = Encoding.UTF8.GetBytes("""{ "Separator": ",", "Parts": ["hello", "world!"]}"""); - stderr.ShouldBe(""); - exit.ShouldBe(0); - stdout.ShouldBe("hello,world!\nhello,world!\nhello,world!\n"); + for (var i = 0; i < 3; i++) + { + var result = plugin.Call("concat", input); + var stdout = Encoding.UTF8.GetString(result); + stdout.ShouldBe("hello,world!"); + } } [Fact] - public async void TestCount() + public void TestCount() { - var path = GetWasmPath("KitchenSink"); - var (stdout, exit, stderr) = await Call(path, "counter", new ExtismOptions - { - Loop = 3, - Input = "" - }); + using var plugin = CreatePlugin("KitchenSink"); - stderr.ShouldBe(""); - exit.ShouldBe(0); - stdout.ShouldBe("1\n2\n3\n"); + for (var i = 1; i <= 3; i++) + { + var result = plugin.Call("counter", []); + var stdout = Encoding.UTF8.GetString(result); + stdout.ShouldBe(i.ToString()); + } } [Theory] [InlineData("", "Greetings, Anonymous!")] [InlineData("John", "Greetings, John!")] - public async void TestConfig(string name, string expected) + public void TestConfig(string name, string expected) { - var path = GetWasmPath("KitchenSink"); - var (stdout, exit, stderr) = await Call(path, "greeter", new ExtismOptions + using var plugin = CreatePlugin("KitchenSink", manifest => { - Loop = 3, - Input = "", - Config = new Dictionary - { - { "name", name } - } + manifest.Config["name"] = name; }); - stderr.ShouldBe(""); - exit.ShouldBe(0); - stdout.ShouldBe($"{expected}\n{expected}\n{expected}\n"); + for (var i = 0; i < 3; i++) + { + var result = plugin.Call("greeter", []); + var stdout = Encoding.UTF8.GetString(result); + stdout.ShouldBe(expected); + } } [Theory] - [InlineData("123", "jsonplaceholder.*.com", true)] + [InlineData("123", "jsonplaceholder.typicode.com", true)] [InlineData("123", "", false)] [InlineData("", "jsonplaceholder.typicode.com", false)] - public async void TestHttp(string token, string allowedHost, bool expected) + public void TestHttp(string token, string allowedHost, bool expected) { - var path = GetWasmPath("KitchenSink"); - var (stdout, exit, stderr) = await Call(path, "get_todo", new ExtismOptions + using var plugin = CreatePlugin("KitchenSink", manifest => { - Loop = 3, - Input = "1", - Config = new Dictionary - { - { "api-token", token } - }, - AllowedHosts = [allowedHost] + manifest.Config["api-token"] = token; + + manifest.AllowedHosts.Add(allowedHost); }); + var input = Encoding.UTF8.GetBytes("1"); + if (expected) { - exit.ShouldBe(0); + var result = plugin.Call("get_todo", input); + var stdout = Encoding.UTF8.GetString(result); + stdout.ShouldNotContain("error"); } else { - exit.ShouldNotBe(0); + Should.Throw(() => plugin.Call("get_todo", input)); } } [Fact] - public async void TestThrow() + public void TestThrow() { - var path = GetWasmPath("KitchenSink"); - var (_, exit, stderr) = await Call(path, "throw", new ExtismOptions - { - Loop = 3, - Input = "Hello World!" - }); + using var plugin = CreatePlugin("KitchenSink"); + + var input = Encoding.UTF8.GetBytes("Hello World!"); - stderr.ShouldContain("Something bad happened."); - exit.ShouldBe(1); + for (var i = 0; i < 3; i++) + { + Should.Throw(() => plugin.Call("throw", [])); + } } - // TODO: test function imports + [Fact] + public void TestReferencedExport() + { + using var plugin = CreatePlugin("KitchenSink"); + + for (var i = 0; i < 3; i++) + { + var result = plugin.Call("samplelib_export", []); + } + } private string GetWasmPath(string name) { @@ -123,6 +126,32 @@ private string GetWasmPath(string name) $"../../../../../samples/{name}/bin/Debug/net8.0/wasi-wasm/AppBundle/{name}.wasm"); } + private Plugin CreatePlugin( + string name, + Action? config = null, + HostFunction[]? hostFunctions = null) + { + var source = new PathWasmSource(GetWasmPath(name)); + var manifest = new Manifest(source); + + if (config is not null) + { + config(manifest); + } + + HostFunction[] functions = [ + HostFunction.FromMethod("samplelib_import", 0, (cp) => { }), + .. (hostFunctions ?? []) + ]; + + foreach (var function in functions) + { + function.SetNamespace("env"); + } + + return new Plugin(manifest, functions, withWasi: true); + } + private async Task<(string, int, string)> Call(string wasmPath, string functionName, ExtismOptions options) { var args = new[] { "call", wasmPath, functionName }.Concat(options.ToCliArguments()); From 87f5c3ca47c33d721e23928a37317a36a3d1f3e2 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 14:40:04 +0300 Subject: [PATCH 05/23] ci: install extism runtime binary --- .github/workflows/ci.yml | 3 ++- .github/workflows/release.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d347ff3..ff27ffb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,8 @@ jobs: - name: Install Extism CLI run: | - go install github.com/extism/cli/extism@latest + go install github.com/extism/cli/extism@latest + extism lib install --libdir tests\Extism.Pdk.WasmTests\bin\Debug\net8.0\ --version git - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5557048..6f04dba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,7 +27,8 @@ jobs: - name: Install Extism CLI run: | - go install github.com/extism/cli/extism@latest + go install github.com/extism/cli/extism@latest + extism lib install --libdir tests\Extism.Pdk.WasmTests\bin\Debug\net8.0\ --version git - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 From 5ab96ab411159dfcf1e7fb2c414de24746a949d5 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 14:45:52 +0300 Subject: [PATCH 06/23] ci: copy shared object into bin --- .github/workflows/ci.yml | 3 ++- .github/workflows/release.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff27ffb..0d8489d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,8 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --libdir tests\Extism.Pdk.WasmTests\bin\Debug\net8.0\ --version git + extism lib install --version git + cp /usr/local/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f04dba..56b8126 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,8 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --libdir tests\Extism.Pdk.WasmTests\bin\Debug\net8.0\ --version git + extism lib install --version git + cp /usr/local/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 From e740195971cd50d1e6f2a316c1a44b012c308754 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 14:48:02 +0300 Subject: [PATCH 07/23] use ~ --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d8489d..32a103d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,8 +34,8 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --version git - cp /usr/local/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + extism lib install --prefix ~ --version git + cp ~/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 56b8126..2a5acdb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,8 +28,8 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --version git - cp /usr/local/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + extism lib install --prefix ~ --version git + cp ~/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 From 0b0f245a3aa20df0c0e2e8b60b6565ca993fec1e Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 14:54:34 +0300 Subject: [PATCH 08/23] make the path --- .github/workflows/ci.yml | 3 ++- .github/workflows/release.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32a103d..71e1879 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,8 @@ jobs: run: | go install github.com/extism/cli/extism@latest extism lib install --prefix ~ --version git - cp ~/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + mkdir -p ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/lib/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a5acdb..0c3cbf9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,7 @@ jobs: run: | go install github.com/extism/cli/extism@latest extism lib install --prefix ~ --version git + mkdir -p tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 cp ~/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK From c233bdcda795c5f5502ea59d6735de3e243618e8 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 14:59:12 +0300 Subject: [PATCH 09/23] reference the csproj in SampleLib --- samples/SampleLib/SampleLib.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/SampleLib/SampleLib.csproj b/samples/SampleLib/SampleLib.csproj index 6b68d7f..70ab331 100644 --- a/samples/SampleLib/SampleLib.csproj +++ b/samples/SampleLib/SampleLib.csproj @@ -7,7 +7,7 @@ - + From 770c80852aa1d410538b9e4e9d9d4e677afb57cf Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 15:16:27 +0300 Subject: [PATCH 10/23] document size trimming --- README.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e4682e..e646c5f 100644 --- a/README.md +++ b/README.md @@ -459,11 +459,40 @@ go run . # => Hello from Go! # => An argument to send to Go! ``` + ### Optimize Size -Normally, the .NET runtime is very conservative when trimming. This makes sure code doesn't break (when using reflection for example) but it also means large binary sizes. A hello world sample is about 20mb. To instruct the .NET compiler to be aggresive about trimming, you can try out these options: + +Normally, the .NET runtime is very conservative when trimming and includes a lot of metadata for debugging and exception purposes. This makes sure code doesn't break (when using reflection for example) but it also means large binary sizes. A hello world sample is about 20mb. To instruct the .NET compiler to be aggresive about trimming, you can try out these options: ```xml + + + net8.0 + wasi-wasm + Exe + true + true + true + + true + full + false + false + false + true + false + + ``` +And then, run: +``` +dotnet publish -c Release +``` + +Now, you'll have a significantly smaller `.wasm` file in `bin\Release\net8.0\wasi-wasm\AppBundle`. + +For more details, refer to [the official documentation](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-7-0#trimming-framework-library-features). + ### Reach Out! Have a question or just want to drop in and say hi? [Hop on the Discord](https://extism.org/discord)! \ No newline at end of file From 5a89876905b6562eee0160ee242b9bf09cdccb8b Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sun, 5 Nov 2023 15:44:40 +0300 Subject: [PATCH 11/23] add some docs about referenced libraries --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index e646c5f..39d6ca7 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,43 @@ go run . # => An argument to send to Go! ``` +### Referenced Assemblies + +Methods in referenced assemblies that are decorated with `[DllImport]` and `[UnmanagedCallersOnly]` are imported and exported respectively. + +**Note:** The library imports/exports are ignored if the app doesn't call at least one method from the library. + +For example, if we have a library that contains this class: +```csharp +namespace `MessagingBot.Pdk`; +public class Events +{ + // This function will be imported by all WASI apps that reference this library + [DllImport("env", EntryPoint = "send_message")] + public static extern void SendMessage(ulong offset); + + // You can wrap the imports in your own functions to make them easier to use + public static void SendMessage(string message) + { + using var block = Pdk.Allocate(message); + SendMessage(block.Offset); + } + + // This function will be exported by all WASI apps that reference this library + [UnmanagedCallersOnly] + public static extern void message_received(long offset); +} +``` + +Then, we can reference the library in a WASI app and use the functions: + +```csharp +using MessagingBot.Pdk; + +Events.SendMessage("Hello World!"); +``` + +This is useful when you want to provide a common set of imports and exports that are specific to your use case. ### Optimize Size Normally, the .NET runtime is very conservative when trimming and includes a lot of metadata for debugging and exception purposes. This makes sure code doesn't break (when using reflection for example) but it also means large binary sizes. A hello world sample is about 20mb. To instruct the .NET compiler to be aggresive about trimming, you can try out these options: From 0e53d5626445ada9f0e7de2ea1ecf70df4cb6f14 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Mon, 6 Nov 2023 14:56:03 +0300 Subject: [PATCH 12/23] iron out some issues with trimming --- README.md | 11 ++++++++++- samples/KitchenSink/KitchenSink.csproj | 10 ++++++++++ src/Extism.Pdk/build/Extism.Pdk.targets | 4 ++++ tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs | 4 ++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 39d6ca7..c2c291f 100644 --- a/README.md +++ b/README.md @@ -497,6 +497,7 @@ Events.SendMessage("Hello World!"); ``` This is useful when you want to provide a common set of imports and exports that are specific to your use case. + ### Optimize Size Normally, the .NET runtime is very conservative when trimming and includes a lot of metadata for debugging and exception purposes. This makes sure code doesn't break (when using reflection for example) but it also means large binary sizes. A hello world sample is about 20mb. To instruct the .NET compiler to be aggresive about trimming, you can try out these options: @@ -511,7 +512,8 @@ Normally, the .NET runtime is very conservative when trimming and includes a lot true true - full + + partial false false false @@ -521,6 +523,13 @@ Normally, the .NET runtime is very conservative when trimming and includes a lot ``` +If you have imports in referenced assemblies, make sure [you mark them as roots](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-7-0#root-assemblies): +```xml + + + +``` + And then, run: ``` dotnet publish -c Release diff --git a/samples/KitchenSink/KitchenSink.csproj b/samples/KitchenSink/KitchenSink.csproj index 17eceb4..2e4ffda 100644 --- a/samples/KitchenSink/KitchenSink.csproj +++ b/samples/KitchenSink/KitchenSink.csproj @@ -10,11 +10,21 @@ enable true false + + + partial + true + false + false + true + true + false + diff --git a/src/Extism.Pdk/build/Extism.Pdk.targets b/src/Extism.Pdk/build/Extism.Pdk.targets index 6751487..d88cb4a 100644 --- a/src/Extism.Pdk/build/Extism.Pdk.targets +++ b/src/Extism.Pdk/build/Extism.Pdk.targets @@ -1,4 +1,8 @@ + + + + diff --git a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs index 314e0a2..5d97a74 100644 --- a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs +++ b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs @@ -100,11 +100,11 @@ public void TestThrow() { using var plugin = CreatePlugin("KitchenSink"); - var input = Encoding.UTF8.GetBytes("Hello World!"); - for (var i = 0; i < 3; i++) { Should.Throw(() => plugin.Call("throw", [])); + // Waiting for https://github.com/extism/extism/issues/567 + // .Message.ShouldContain("Something bad happened."); } } From dc8a5e8db73617a90499409dd5a3d5acc569149a Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Mon, 6 Nov 2023 16:15:43 +0300 Subject: [PATCH 13/23] don't enable InvariantGlobalization mode --- README.md | 4 +--- samples/KitchenSink/KitchenSink.csproj | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c2c291f..e36d492 100644 --- a/README.md +++ b/README.md @@ -511,12 +511,10 @@ Normally, the .NET runtime is very conservative when trimming and includes a lot true true - true - + partial false false - false true false diff --git a/samples/KitchenSink/KitchenSink.csproj b/samples/KitchenSink/KitchenSink.csproj index 2e4ffda..aacf35c 100644 --- a/samples/KitchenSink/KitchenSink.csproj +++ b/samples/KitchenSink/KitchenSink.csproj @@ -11,12 +11,10 @@ true false - + partial - true false false - true true false From cb809ec3d345e4858419c56975dffa7a55bcfe3c Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 11:24:24 +0300 Subject: [PATCH 14/23] throw works now --- tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs index 5d97a74..b1b60d3 100644 --- a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs +++ b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs @@ -102,9 +102,8 @@ public void TestThrow() for (var i = 0; i < 3; i++) { - Should.Throw(() => plugin.Call("throw", [])); - // Waiting for https://github.com/extism/extism/issues/567 - // .Message.ShouldContain("Something bad happened."); + Should.Throw(() => plugin.Call("throw", [])) + .Message.ShouldContain("Something bad happened."); } } From 8a11fb10ee8739be5ae5486121d51f41b899f101 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 11:25:24 +0300 Subject: [PATCH 15/23] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e36d492..18714c0 100644 --- a/README.md +++ b/README.md @@ -521,7 +521,7 @@ Normally, the .NET runtime is very conservative when trimming and includes a lot ``` -If you have imports in referenced assemblies, make sure [you mark them as roots](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-7-0#root-assemblies): +If you have imports in referenced assemblies, make sure [you mark them as roots](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-7-0#root-assemblies) so that they don't get trimmed: ```xml From 91fb8cb7a6136103c93678f8e283e45d0172e398 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 11:27:17 +0300 Subject: [PATCH 16/23] fix workflow --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71e1879..2013a2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,9 +34,9 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --prefix ~ --version git + extism lib install --prefix ~/lib/extism --version git mkdir -p ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - cp ~/lib/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/lib/extism/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c3cbf9..fd65c73 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,9 +28,9 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --prefix ~ --version git + extism lib install --prefix ~/lib/extism --version git mkdir -p tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - cp ~/lib/** tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/lib/extism/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 From 1f49a92fe80fbf6017b7e9f6a2faf872c3603eb6 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 11:29:24 +0300 Subject: [PATCH 17/23] fix workflow --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2013a2c..0a000a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,9 +34,9 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --prefix ~/lib/extism --version git + extism lib install --prefix ~/extism --version git mkdir -p ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - cp ~/lib/extism/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/extism/lib/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fd65c73..650d010 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,9 +28,9 @@ jobs: - name: Install Extism CLI run: | go install github.com/extism/cli/extism@latest - extism lib install --prefix ~/lib/extism --version git - mkdir -p tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - cp ~/lib/extism/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + extism lib install --prefix ~/extism --version git + mkdir -p ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/extism/lib/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 From 2a2648c0475b297d77fbfe8cdf0af04d088d64b1 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 11:32:45 +0300 Subject: [PATCH 18/23] fix workflow --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a000a9..17a88ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: go install github.com/extism/cli/extism@latest extism lib install --prefix ~/extism --version git mkdir -p ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - cp ~/extism/lib/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/extism/lib/libextism.so ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 650d010..a60cf2a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: go install github.com/extism/cli/extism@latest extism lib install --prefix ~/extism --version git mkdir -p ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - cp ~/extism/lib/** ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 + cp ~/extism/lib/libextism.so ./tests/Extism.Pdk.WasmTests/bin/Debug/net8.0 - name: Setup .NET Core SDK uses: actions/setup-dotnet@v3.0.3 From e0ca0f1ced1223f919e82cef6962ef4f3fdf5f63 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 12:32:50 +0300 Subject: [PATCH 19/23] use published wasms for testing --- Makefile | 6 ++- README.md | 42 +++++++++---------- samples/KitchenSink/Program.cs | 6 ++- .../Extism.Pdk.WasmTests/KitchenSinkTests.cs | 2 +- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 2b54411..0a15ace 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,10 @@ NUGET_API_KEY ?= $(shell env | grep NUGET_API_KEY) prepare: dotnet build -test: prepare - dotnet test +test: + dotnet publish -c Release ./samples/KitchenSink + dotnet test ./tests/Extism.Pdk.MsBuild.Tests + dotnet test ./tests/Extism.Pdk.WasmTests clean: dotnet clean diff --git a/README.md b/README.md index 18714c0..dbee48b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,6 @@ module MyPlugin open System open System.Runtime.InteropServices -open System.Text.Json open Extism [] @@ -179,39 +178,38 @@ Extism export functions simply take bytes in and bytes out. Those can be whateve C#: ```csharp +[JsonSerializable(typeof(Add))] +[JsonSerializable(typeof(Sum))] +public partial class SourceGenerationContext : JsonSerializerContext {} + public record Add(int A, int B); public record Sum(int Result); -[UnmanagedCallersOnly] -public static int add() +public static class Functions { - var inputJson = Pdk.GetInputString(); - var options = new JsonSerializerOptions + [UnmanagedCallersOnly] + public static int add() { - PropertyNameCaseInsensitive = true - }; - - var parameters = JsonSerializer.Deserialize(inputJson, options); - var sum = new Sum(parameters.A + parameters.B); - var outputJson = JsonSerializer.Serialize(sum, options); - Pdk.SetOutput(outputJson); - return 0; + var inputJson = Pdk.GetInputString(); + var parameters = JsonSerializer.Deserialize(inputJson, SourceGenerationContext.Defaul + var sum = new Sum(parameters.A + parameters.B); + var outputJson = JsonSerializer.Serialize(sum, SourceGenerationContext.Default.Sum); + Pdk.SetOutput(outputJson); + return 0; + } } ``` F#: ```fsharp -type Add = { A: int; B: int } -type Sum = { Result: int } - [] let add () = let inputJson = Pdk.GetInputString() - let options = JsonSerializerOptions(PropertyNameCaseInsensitive = true) - let parameters = JsonSerializer.Deserialize(inputJson, options) - - let sum = { Result = parameters.A + parameters.B } - let outputJson = JsonSerializer.Serialize(sum, options) + let jsonData = JsonDocument.Parse(inputJson).RootElement + let a = jsonData.GetProperty("a").GetInt32() + let b = jsonData.GetProperty("b").GetInt32() + let result = a + b + let outputJson = $"{{ \"result\": {result} }}" Pdk.SetOutput(outputJson) 0 @@ -222,6 +220,8 @@ extism call .\bin\Debug\net8.0\wasi-wasm\AppBundle\readmeapp.wasm --wasi add --i # => {"Result":41} ``` +**Note:** When enabling trimming, make sure you use the [source generation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation) as reflection is disabled in that mode. + ## Configs Configs are key-value pairs that can be passed in by the host when creating a plug-in. These can be useful to statically configure the plug-in with some data that exists across every function call. Here is a trivial example using Pdk.TryGetConfig: diff --git a/samples/KitchenSink/Program.cs b/samples/KitchenSink/Program.cs index e2aa3d2..d80155c 100644 --- a/samples/KitchenSink/Program.cs +++ b/samples/KitchenSink/Program.cs @@ -3,6 +3,7 @@ using Extism; using System.Text.Json; using SampleLib; +using System.Text.Json.Serialization; Class1.noop(); // Import Class1 from SampleLib so that it's included during compilation Console.WriteLine("Hello world!"); @@ -24,7 +25,7 @@ public static int Length() public static int Concat() { var json = Pdk.GetInput(); - var payload = JsonSerializer.Deserialize(json); + var payload = JsonSerializer.Deserialize(json, SourceGenerationContext.Default.ConcatInput); if (payload is null) { @@ -89,6 +90,9 @@ public static int Throw() } } + [JsonSerializable(typeof(ConcatInput))] + public partial class SourceGenerationContext : JsonSerializerContext {} + public class ConcatInput { public string[] Parts { get; set; } diff --git a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs index b1b60d3..645ad34 100644 --- a/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs +++ b/tests/Extism.Pdk.WasmTests/KitchenSinkTests.cs @@ -122,7 +122,7 @@ private string GetWasmPath(string name) { return Path.Combine( Environment.CurrentDirectory, - $"../../../../../samples/{name}/bin/Debug/net8.0/wasi-wasm/AppBundle/{name}.wasm"); + $"../../../../../samples/{name}/bin/Release/net8.0/wasi-wasm/AppBundle/{name}.wasm"); } private Plugin CreatePlugin( From c36cddf9e23181abbe17a10f93c2f4a402488705 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 13:44:31 +0300 Subject: [PATCH 20/23] fix readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dbee48b..79473e2 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ C#: [JsonSerializable(typeof(Sum))] public partial class SourceGenerationContext : JsonSerializerContext {} -public record Add(int A, int B); +public record Add(int a, int b); public record Sum(int Result); public static class Functions @@ -192,7 +192,7 @@ public static class Functions { var inputJson = Pdk.GetInputString(); var parameters = JsonSerializer.Deserialize(inputJson, SourceGenerationContext.Defaul - var sum = new Sum(parameters.A + parameters.B); + var sum = new Sum(parameters.a + parameters.b); var outputJson = JsonSerializer.Serialize(sum, SourceGenerationContext.Default.Sum); Pdk.SetOutput(outputJson); return 0; @@ -209,7 +209,7 @@ let add () = let a = jsonData.GetProperty("a").GetInt32() let b = jsonData.GetProperty("b").GetInt32() let result = a + b - let outputJson = $"{{ \"result\": {result} }}" + let outputJson = $"{{ \"Result\": {result} }}" Pdk.SetOutput(outputJson) 0 From 6adae21a16cfcacaff3116fb72426462caf6fa50 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Wed, 8 Nov 2023 13:46:09 +0300 Subject: [PATCH 21/23] fix workflow --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 0a15ace..8ba02f4 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ prepare: dotnet build test: + dotnet build ./src/Extism.Pdk.MSBuild dotnet publish -c Release ./samples/KitchenSink dotnet test ./tests/Extism.Pdk.MsBuild.Tests dotnet test ./tests/Extism.Pdk.WasmTests From 93352707440427baa65bf7ceeabbcc05527d834a Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Sat, 11 Nov 2023 00:11:10 +0300 Subject: [PATCH 22/23] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 79473e2..b85e7ce 100644 --- a/README.md +++ b/README.md @@ -299,6 +299,7 @@ let count () = Pdk.SetOutput(count.ToString()) 0 +``` From [Extism CLI](https://github.com/extism/cli): ``` @@ -539,4 +540,4 @@ For more details, refer to [the official documentation](https://learn.microsoft. ### Reach Out! -Have a question or just want to drop in and say hi? [Hop on the Discord](https://extism.org/discord)! \ No newline at end of file +Have a question or just want to drop in and say hi? [Hop on the Discord](https://extism.org/discord)! From ccd890d3f7373fa7c38605609fd6b0cbd6b787a8 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Tue, 14 Nov 2023 15:21:35 +0300 Subject: [PATCH 23/23] fix build --- src/Extism.Pdk.MSBuild/FFIGenerator.cs | 2 +- tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Extism.Pdk.MSBuild/FFIGenerator.cs b/src/Extism.Pdk.MSBuild/FFIGenerator.cs index 2b7d093..9674df1 100644 --- a/src/Extism.Pdk.MSBuild/FFIGenerator.cs +++ b/src/Extism.Pdk.MSBuild/FFIGenerator.cs @@ -209,7 +209,7 @@ private string ToImportStatement(MethodDefinition method) moduleName = "extism:host/user"; } - var functionName = method.PInvokeInfo.EntryPoint ?? method.Name; + var functionName = string.IsNullOrEmpty(method.PInvokeInfo.EntryPoint) ? method.Name : method.PInvokeInfo.EntryPoint; if (!_types.ContainsKey(method.ReturnType.Name)) { diff --git a/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj b/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj index cf42c73..4573955 100644 --- a/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj +++ b/tests/Extism.Pdk.WasmTests/Extism.Pdk.WasmTests.csproj @@ -10,6 +10,7 @@ +