diff --git a/eng/Versions.props b/eng/Versions.props index 0b744bf6591a6..c3c03de846f9a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -263,5 +263,6 @@ $(runtimewinx64MicrosoftNETCoreRuntimeWasmNodeTransportPackageVersion) 3.1.56 + 9.0.0-rc.1.24413.1 diff --git a/eng/testing/scenarios/BuildWasiAppsJobsList.txt b/eng/testing/scenarios/BuildWasiAppsJobsList.txt index 86c0517585a48..4ddb5b555ba1a 100644 --- a/eng/testing/scenarios/BuildWasiAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasiAppsJobsList.txt @@ -1,7 +1 @@ -Wasi.Build.Tests.InvariantTests -Wasi.Build.Tests.ILStripTests -Wasi.Build.Tests.SdkMissingTests -Wasi.Build.Tests.RuntimeConfigTests -Wasi.Build.Tests.WasiTemplateTests -Wasi.Build.Tests.PInvokeTableGeneratorTests -Wasi.Build.Tests.WasiLibraryModeTests +Wasi.Build.Tests.NativeAOTTests diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index 818ff9e8edd3c..e2b91416b20bc 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -1,52 +1,2 @@ -Wasm.Build.NativeRebuild.Tests.FlagsChangeRebuildTests -Wasm.Build.NativeRebuild.Tests.NoopNativeRebuildTest -Wasm.Build.NativeRebuild.Tests.OptimizationFlagChangeTests -Wasm.Build.NativeRebuild.Tests.ReferenceNewAssemblyRebuildTest -Wasm.Build.NativeRebuild.Tests.SimpleSourceChangeRebuildTest -Wasm.Build.Tests.TestAppScenarios.InterpPgoTests -Wasm.Build.Templates.Tests.NativeBuildTests -Wasm.Build.Tests.Blazor.AppsettingsTests -Wasm.Build.Tests.Blazor.BuildPublishTests -Wasm.Build.Tests.Blazor.SimpleRunTests -Wasm.Build.Tests.Blazor.CleanTests -Wasm.Build.Tests.Blazor.MiscTests -Wasm.Build.Tests.Blazor.MiscTests2 -Wasm.Build.Tests.Blazor.MiscTests3 -Wasm.Build.Tests.Blazor.NativeTests -Wasm.Build.Tests.Blazor.NoopNativeRebuildTest -Wasm.Build.Tests.Blazor.WorkloadRequiredTests -Wasm.Build.Tests.Blazor.IcuTests -Wasm.Build.Tests.Blazor.IcuShardingTests -Wasm.Build.Tests.Blazor.SignalRClientTests -Wasm.Build.Tests.BuildPublishTests -Wasm.Build.Tests.ConfigSrcTests -Wasm.Build.Tests.HybridGlobalizationTests -Wasm.Build.Tests.IcuShardingTests -Wasm.Build.Tests.IcuShardingTests2 -Wasm.Build.Tests.IcuTests -Wasm.Build.Tests.InvariantGlobalizationTests -Wasm.Build.Tests.InvariantTimezoneTests -Wasm.Build.Tests.MainWithArgsTests -Wasm.Build.Tests.NativeBuildTests -Wasm.Build.Tests.NativeLibraryTests -Wasm.Build.Tests.NonWasmTemplateBuildTests -Wasm.Build.Tests.PInvokeTableGeneratorTests -Wasm.Build.Tests.RebuildTests -Wasm.Build.Tests.SatelliteAssembliesTests -Wasm.Build.Tests.TestAppScenarios.AppSettingsTests -Wasm.Build.Tests.TestAppScenarios.DownloadThenInitTests -Wasm.Build.Tests.TestAppScenarios.LazyLoadingTests -Wasm.Build.Tests.TestAppScenarios.LibraryInitializerTests -Wasm.Build.Tests.TestAppScenarios.SatelliteLoadingTests -Wasm.Build.Tests.TestAppScenarios.ModuleConfigTests -Wasm.Build.Tests.TestAppScenarios.MemoryTests -Wasm.Build.Tests.AspNetCore.SignalRClientTests -Wasm.Build.Tests.WasmBuildAppTest -Wasm.Build.Tests.WasmNativeDefaultsTests -Wasm.Build.Tests.WasmRunOutOfAppBundleTests -Wasm.Build.Tests.WasmSIMDTests -Wasm.Build.Tests.WasmTemplateTests -Wasm.Build.Tests.WorkloadTests -Wasm.Build.Tests.MT.Blazor.SimpleMultiThreadedTests -Wasm.Build.Tests.TestAppScenarios.WasmSdkDebugLevelTests -Wasm.Build.Tests.TestAppScenarios.WasmAppBuilderDebugLevelTests +Wasm.Build.Tests.NativeAOTTests + diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest.pkgproj b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest.pkgproj index f489f65e443a6..2c68ce9127dce 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest.pkgproj +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest.pkgproj @@ -53,6 +53,7 @@ <_WorkloadManifestValues Include="PackageVersionNet6" Value="$(PackageVersionNet6)" /> <_WorkloadManifestValues Include="NetCoreAppCurrent" Value="$(NetCoreAppCurrent)" /> <_WorkloadManifestValues Include="EmscriptenVersion" Value="$(MicrosoftNETRuntimeEmscriptenVersion)" /> + <_WorkloadManifestValues Include="WasmExperimentalNativeAOTLLVMILCompilerVersion" Value="$(WasmExperimentalNativeAOTLLVMILCompilerVersion)" /> + <_IsUsingNativeAOT Condition="'$(PublishAot)' == 'true'">true <_RuntimePackInWorkloadVersionCurrent>${PackageVersion} <_RuntimePackInWorkloadVersion8>${PackageVersionNet8} <_RuntimePackInWorkloadVersion7>${PackageVersionNet7} @@ -66,8 +67,27 @@ $(WasmNativeWorkloadAvailable) + + false + false + false + true + false + ${WasmExperimentalNativeAOTLLVMILCompilerVersion} + + + + + + + - + <_IsAndroidLibraryMode Condition="'$(RuntimeIdentifier)' == 'android-arm64' or '$(RuntimeIdentifier)' == 'android-arm' or '$(RuntimeIdentifier)' == 'android-x64' or '$(RuntimeIdentifier)' == 'android-x86'">true <_IsAppleMobileLibraryMode Condition="'$(RuntimeIdentifier)' == 'ios-arm64' or '$(RuntimeIdentifier)' == 'iossimulator-arm64' or '$(RuntimeIdentifier)' == 'iossimulator-x64' or '$(RuntimeIdentifier)' == 'maccatalyst-arm64' or '$(RuntimeIdentifier)' == 'maccatalyst-x64' or '$(RuntimeIdentifier)' == 'tvos-arm64'">true <_IsiOSLibraryMode Condition="'$(RuntimeIdentifier)' == 'ios-arm64' or '$(RuntimeIdentifier)' == 'iossimulator-arm64' or '$(RuntimeIdentifier)' == 'iossimulator-x64'">true @@ -187,7 +207,7 @@ Microsoft.NETCore.App.Runtime.Mono.multithread.**RID** - + $(_MonoWorkloadRuntimePackPackageVersion) diff --git a/src/mono/wasi/Wasi.Build.Tests/NativeAOTTests.cs b/src/mono/wasi/Wasi.Build.Tests/NativeAOTTests.cs new file mode 100644 index 0000000000000..967f291b45036 --- /dev/null +++ b/src/mono/wasi/Wasi.Build.Tests/NativeAOTTests.cs @@ -0,0 +1,88 @@ +// 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.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Wasm.Build.Tests; +using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +#nullable enable + +namespace Wasi.Build.Tests; + +public class NativeAOTTests : BuildTestBase +{ + public NativeAOTTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + [Fact] + public void PublishAndRun() + { + const string config = "Release"; + string id = $"nativeaot_{GetRandomId()}"; + string projectFile = CreateWasmTemplateProject(id, "wasiconsole"); + string projectName = Path.GetFileNameWithoutExtension(projectFile); + + string programCsContent = File.ReadAllText(Path.Combine(BuildEnvironment.TestAssetsPath, "SimpleMainWithArgs.cs")); + programCsContent = programCsContent.Replace("return 42;", "return 0;"); + File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), programCsContent); + File.Delete(Path.Combine(_projectDir!, "runtimeconfig.template.json")); + + var buildArgs = ExpandBuildArgs(new BuildArgs(projectName, config, AOT: false, id, null)); + + AddItemsPropertiesToProject(projectFile, extraProperties: + """ + $(RestoreAdditionalProjectSources);https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json + true + """ + ); + + try + { + bool isWindowsPlatform = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + (_, string buildOutput) = BuildProject( + buildArgs, + id: id, + new BuildProjectOptions( + AssertAppBundle: false, + CreateProject: false, + Publish: true, + TargetFramework: DefaultTargetFramework, + ExpectSuccess: isWindowsPlatform + ) + ); + + if (isWindowsPlatform) + { + string outputDir = Path.Combine(_projectDir!, "bin", config, DefaultTargetFramework, BuildEnvironment.DefaultRuntimeIdentifier, "native"); + string outputFileName = $"{id}.wasm"; + + Assert.True(File.Exists(Path.Combine(outputDir, outputFileName)), $"Expected {outputFileName} to exist in {outputDir}"); + Assert.Contains("Generating native code", buildOutput); + + using var runCommand = new ToolCommand(BuildEnvironment.GetExecutableName(@"wasmtime"), _testOutput) + .WithWorkingDirectory(outputDir); + + var result = runCommand.Execute(outputFileName).EnsureSuccessful(); + Assert.Contains("Hello, Wasi Console!", result.Output); + } + else + { + Assert.Contains("NETSDK1204", buildOutput); // Ahead-of-time compilation is not supported on the current platform 'linux-x64' + } + } + finally + { + _testOutput.WriteLine($"Content of {_nugetPackagesDir}"); + foreach (string file in Directory.EnumerateFiles(_nugetPackagesDir, "*", SearchOption.AllDirectories)) + _testOutput.WriteLine(file); + } + } +} diff --git a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs index 3dc64bc556d53..bf95b81e070e0 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs @@ -166,7 +166,10 @@ public BuildTestBase(ProjectProviderBase providerBase, ITestOutputHelper output, var cmd = new DotNetCommand(s_buildEnv, _testOutput) .WithWorkingDirectory(_projectDir!) .WithEnvironmentVariable("NUGET_PACKAGES", _nugetPackagesDir) - .WithEnvironmentVariables(buildProjectOptions.ExtraBuildEnvironmentVariables); + .WithEnvironmentVariables(buildProjectOptions.ExtraBuildEnvironmentVariables) + .WithEnvironmentVariable("COREHOST_TRACE", "1") + .WithEnvironmentVariable("COREHOST_TRACEFILE", Environment.GetEnvironmentVariable("HELIX_WORKITEM_UPLOAD_ROOT") ?? string.Empty) + .WithEnvironmentVariable("COREHOST_TRACE_VERBOSITY", "4"); if (UseWBTOverridePackTargets && s_buildEnv.IsWorkload) cmd.WithEnvironmentVariable("WBTOverrideRuntimePack", "true"); diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs b/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs index 0b71e4d663015..fe9084b71c2f1 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs @@ -140,9 +140,7 @@ public BuildEnvironment() EnvVars["WasmFingerprintAssets"] = "false"; } - DotNet = Path.Combine(sdkForWorkloadPath!, "dotnet"); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - DotNet += ".exe"; + DotNet = GetExecutableName(Path.Combine(sdkForWorkloadPath!, "dotnet")); if (!string.IsNullOrEmpty(EnvironmentVariables.TestLogPath)) { @@ -185,5 +183,13 @@ public bool IsMultiThreadingRuntimePackAvailableFor(string tfm) protected static string s_directoryBuildPropsForLocal = File.ReadAllText(Path.Combine(TestDataPath, "Local.Directory.Build.props")); protected static string s_directoryBuildTargetsForLocal = File.ReadAllText(Path.Combine(TestDataPath, "Local.Directory.Build.targets")); + + public static string GetExecutableName(string nameOrPath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + nameOrPath += ".exe"; + + return nameOrPath; + } } } diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/NativeAOTTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/NativeAOTTests.cs new file mode 100644 index 0000000000000..32c1069fdc4d2 --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/NativeAOTTests.cs @@ -0,0 +1,80 @@ +// 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.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Wasm.Build.Tests.Blazor; +using Xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +#nullable enable + +namespace Wasm.Build.Tests; + +public class NativeAOTTests : BlazorWasmTestBase +{ + public NativeAOTTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + [Theory] + [InlineData("NativeAOT")] + public async Task PublishAndRun(string assetName) + { + string config = "Release"; + string id = $"browser_{config}_{GetRandomId()}"; + + InitBlazorWasmProjectDir(id); + Utils.DirectoryCopy(Path.Combine(BuildEnvironment.TestAssetsPath, assetName), Path.Combine(_projectDir!)); + string projectName = Path.GetFileNameWithoutExtension(_projectDir!); + + try + { + bool isWindowsPlatform = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + (_, string buildOutput) = BuildTemplateProject( + ExpandBuildArgs(new BuildArgs(projectName, config, AOT: false, id, null)), + id: id, + new BuildProjectOptions( + AssertAppBundle: false, + CreateProject: false, + Publish: true, + TargetFramework: DefaultTargetFramework, + ExpectSuccess: isWindowsPlatform + ) + ); + + if (isWindowsPlatform) + { + string outputDir = Path.Combine(_projectDir!, "bin", config, DefaultTargetFramework, BuildEnvironment.DefaultRuntimeIdentifier, "native"); + + List consoleOutput = new(); + BlazorRunOptions blazorRunOptions = new( + CheckCounter: false, + Config: config, + OnConsoleMessage: (_, message) => consoleOutput.Add(message.Text), + Host: BlazorRunHost.WebServer + ); + await BlazorRunTest($"{s_xharnessRunnerCommand} wasm webserver --app=. --web-server-use-default-files", outputDir, blazorRunOptions); + + Assert.True(consoleOutput.Contains("Hello, NativeAOT!"), $"Expected 'Hello, NativeAOT!' wasn't emitted by the test app. Output was: {String.Join(", ", consoleOutput)}"); + } + else + { + Assert.Contains("NETSDK1204", buildOutput); // Ahead-of-time compilation is not supported on the current platform 'linux-x64' + } + } + finally + { + _testOutput.WriteLine($"Is64BitProcess '{Environment.Is64BitProcess}', Is64BitOperatingSystem '{Environment.Is64BitOperatingSystem}', OSVersion '{Environment.OSVersion}'"); + _testOutput.WriteLine($"Content of {_nugetPackagesDir}"); + foreach (string file in Directory.EnumerateFiles(_nugetPackagesDir, "*", SearchOption.AllDirectories)) + _testOutput.WriteLine(file); + } + } +} diff --git a/src/mono/wasm/testassets/NativeAOT/NativeAOT.csproj b/src/mono/wasm/testassets/NativeAOT/NativeAOT.csproj new file mode 100644 index 0000000000000..cdcc4f99d47f9 --- /dev/null +++ b/src/mono/wasm/testassets/NativeAOT/NativeAOT.csproj @@ -0,0 +1,13 @@ + + + net9.0 + browser-wasm + Exe + true + true + true + + + + + diff --git a/src/mono/wasm/testassets/NativeAOT/Program.cs b/src/mono/wasm/testassets/NativeAOT/Program.cs new file mode 100644 index 0000000000000..f78a98e8ec484 --- /dev/null +++ b/src/mono/wasm/testassets/NativeAOT/Program.cs @@ -0,0 +1,10 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.JavaScript; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +Console.WriteLine("Hello, NativeAOT!"); +Console.WriteLine($"Args {String.Join(", ", args)}"); diff --git a/src/mono/wasm/testassets/NativeAOT/wwwroot/index.html b/src/mono/wasm/testassets/NativeAOT/wwwroot/index.html new file mode 100644 index 0000000000000..1d1ae6ccf4495 --- /dev/null +++ b/src/mono/wasm/testassets/NativeAOT/wwwroot/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/mono/wasm/testassets/NativeAOT/wwwroot/main.js b/src/mono/wasm/testassets/NativeAOT/wwwroot/main.js new file mode 100644 index 0000000000000..7864eb322ca1f --- /dev/null +++ b/src/mono/wasm/testassets/NativeAOT/wwwroot/main.js @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import { dotnet } from './dotnet.js' + +await dotnet + .withApplicationArguments("A", "B", "C") + .withMainAssembly("NativeAOT") + .create(); + +await dotnet.run();