diff --git a/src/mono/sample/wasi/native/ILLink.Descriptors.xml b/src/mono/sample/wasi/native/ILLink.Descriptors.xml new file mode 100644 index 0000000000000..9df567cb73b38 --- /dev/null +++ b/src/mono/sample/wasi/native/ILLink.Descriptors.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/mono/sample/wasi/native/Program.cs b/src/mono/sample/wasi/native/Program.cs index d8d480869a8de..ffea2e7c343b7 100644 --- a/src/mono/sample/wasi/native/Program.cs +++ b/src/mono/sample/wasi/native/Program.cs @@ -4,6 +4,8 @@ using System; using System.Runtime.InteropServices; +namespace Sample; + public unsafe class Test { [UnmanagedCallersOnly(EntryPoint = "ManagedFunc")] diff --git a/src/mono/sample/wasi/native/Wasi.Native.Sample.csproj b/src/mono/sample/wasi/native/Wasi.Native.Sample.csproj index 9af9d62eeee98..123684c9f70f5 100644 --- a/src/mono/sample/wasi/native/Wasi.Native.Sample.csproj +++ b/src/mono/sample/wasi/native/Wasi.Native.Sample.csproj @@ -12,6 +12,8 @@ + + diff --git a/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs b/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs index 62f23c2648899..13f3787c0aff7 100644 --- a/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasi/Wasi.Build.Tests/BuildTestBase.cs @@ -693,6 +693,16 @@ public static int Main() .MultiplyWithSingleArgs(true, false) /*aot*/ .UnwrapItemsAsArrays(); + public static IEnumerable TestDataForConsolePublishAndRunRelease() => + new IEnumerable[] + { + new object?[] { true }, + new object?[] { false } + } + .AsEnumerable() + .MultiplyWithSingleArgs(true, false) /*aot*/ + .UnwrapItemsAsArrays(); + protected CommandResult RunWithoutBuild(string config, string id, bool enableHttp = false) { // wasmtime --wasi http is necessary because the default dotnet.wasm (without native rebuild depends on wasi:http world) diff --git a/src/mono/wasi/Wasi.Build.Tests/PInvokeTableGeneratorTests.cs b/src/mono/wasi/Wasi.Build.Tests/PInvokeTableGeneratorTests.cs index 6a47c0364658d..1405ec20bb715 100644 --- a/src/mono/wasi/Wasi.Build.Tests/PInvokeTableGeneratorTests.cs +++ b/src/mono/wasi/Wasi.Build.Tests/PInvokeTableGeneratorTests.cs @@ -17,58 +17,38 @@ public PInvokeTableGeneratorTests(ITestOutputHelper output, SharedBuildPerTestCl { } - [Fact] - public void InteropSupportForUnmanagedEntryPointWithoutDelegate() + [Theory] + [MemberData(nameof(TestDataForConsolePublishAndRunRelease))] + public void InteropSupportForUnmanagedEntryPointWithoutDelegate(bool singleFileBundle, bool aot) { - string config = "Release"; - string id = $"{config}_{GetRandomId()}"; - string projectFile = CreateWasmTemplateProject(id, "wasiconsole"); - string code = - """ - using System; - using System.Runtime.InteropServices; - public unsafe class Test - { - [UnmanagedCallersOnly(EntryPoint = "ManagedFunc")] - public static int MyExport(int number) - { - // called from MyImport aka UnmanagedFunc - Console.WriteLine($"MyExport({number}) -> 42"); - return 42; - } - - [DllImport("*", EntryPoint = "UnmanagedFunc")] - public static extern void MyImport(); // calls ManagedFunc aka MyExport + if(aot) + { + // Active issue https://github.com/dotnet/runtime/issues/101276 + return; + } - public unsafe static int Main(string[] args) - { - Console.WriteLine($"main: {args.Length}"); - MyImport(); - return 0; - } - } - """; - string cCode = - """ - #include - - int ManagedFunc(int number); + string id = $"Release_{GetRandomId()}"; + string projectFile = CreateWasmTemplateProject(id, "wasiconsole"); + string projectName = Path.GetFileNameWithoutExtension(projectFile); + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Native.cs"), Path.Combine(_projectDir!, "Program.cs"), true); + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native.c"), Path.Combine(_projectDir!, "native.c")!, true); + + // workaround for https://github.com/dotnet/runtime/issues/106627 + File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "ILLink.Native.Descriptors.xml"), Path.Combine(_projectDir!, "ILLink.Native.Descriptors.xml")!, true); - void UnmanagedFunc() - { - int ret = 0; - printf("UnmanagedFunc calling ManagedFunc\n"); - ret = ManagedFunc(123); - printf("ManagedFunc returned %d\n", ret); - } - """; - File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), code); - File.WriteAllText(Path.Combine(_projectDir!, "local.c"), cCode); string extraProperties = @"false - true"; - AddItemsPropertiesToProject(projectFile, extraProperties: extraProperties, extraItems: @""); - string projectName = Path.GetFileNameWithoutExtension(projectFile); - var buildArgs = new BuildArgs(projectName, config, AOT: true, ProjectFileContents: id, ExtraBuildArgs: null); + true + true + Wasi.Native.Test"; + if (aot) + extraProperties += "true<_WasmDevel>false"; + if (singleFileBundle) + extraProperties += "true"; + + string itemsProperties = @" + "; + AddItemsPropertiesToProject(projectFile, extraProperties: extraProperties, extraItems: itemsProperties); + var buildArgs = new BuildArgs(projectName, Config: "Release", AOT: true, ProjectFileContents: id, ExtraBuildArgs: null); buildArgs = ExpandBuildArgs(buildArgs); BuildProject(buildArgs, id: id, @@ -80,7 +60,7 @@ void UnmanagedFunc() CommandResult res = new RunCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(_projectDir!) - .ExecuteWithCapturedOutput($"run --no-silent --no-build -c {config}") + .ExecuteWithCapturedOutput($"run --no-silent --no-build -c Release") .EnsureSuccessful(); Assert.Contains("MyExport(123) -> 42", res.Output); } diff --git a/src/mono/wasi/build/WasiApp.props b/src/mono/wasi/build/WasiApp.props index d3e85d068e0da..b2f79014de3ec 100644 --- a/src/mono/wasi/build/WasiApp.props +++ b/src/mono/wasi/build/WasiApp.props @@ -5,7 +5,7 @@ wasm wasi wasi-wasm - partial + full true diff --git a/src/mono/wasi/testassets/ILLink.Native.Descriptors.xml b/src/mono/wasi/testassets/ILLink.Native.Descriptors.xml new file mode 100644 index 0000000000000..6f67d16fa0e1d --- /dev/null +++ b/src/mono/wasi/testassets/ILLink.Native.Descriptors.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/mono/wasi/testassets/Native.cs b/src/mono/wasi/testassets/Native.cs new file mode 100644 index 0000000000000..ffea2e7c343b7 --- /dev/null +++ b/src/mono/wasi/testassets/Native.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +namespace Sample; + +public unsafe class Test +{ + [UnmanagedCallersOnly(EntryPoint = "ManagedFunc")] + public static int MyExport(int number) + { + // called from MyImport aka UnmanagedFunc + Console.WriteLine($"MyExport({number}) -> 42"); + return 42; + } + + [DllImport("*", EntryPoint = "UnmanagedFunc")] + public static extern void MyImport(); // calls ManagedFunc aka MyExport + + public unsafe static int Main(string[] args) + { + Console.WriteLine($"main: {args.Length}"); + MyImport(); + return 0; + } +} diff --git a/src/mono/wasi/testassets/native.c b/src/mono/wasi/testassets/native.c new file mode 100644 index 0000000000000..9141571f949be --- /dev/null +++ b/src/mono/wasi/testassets/native.c @@ -0,0 +1,11 @@ +#include + +int ManagedFunc(int number); + +void UnmanagedFunc() +{ + int ret = 0; + printf("UnmanagedFunc calling ManagedFunc\n"); + ret = ManagedFunc(123); + printf("ManagedFunc returned %d\n", ret); +} \ No newline at end of file