diff --git a/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt b/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt index 4f567f5cba1082..f6cbcd4dd63241 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt @@ -12,3 +12,12 @@ Wasm.Build.Tests.WasmRunOutOfAppBundleTests Wasm.Build.Tests.WasmTemplateTests Wasm.Build.Tests.MaxParallelDownloadsTests Wasm.Build.Tests.LibraryInitializerTests +Wasm.Build.Tests.NativeBuildTests +Wasm.Build.Tests.DllImportTests +Wasm.Build.Tests.PInvokeTableGeneratorTests +Wasm.Build.Tests.NativeLibraryTests +Wasm.Build.Tests.IcuShardingTests +Wasm.Build.Tests.IcuShardingTests2 +Wasm.Build.Tests.IcuTests +Wasm.Build.Tests.InvariantGlobalizationTests +Wasm.Build.Tests.MemoryTests diff --git a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets index 02f69b8e2be52c..b20a1b073f83e7 100644 --- a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets +++ b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets @@ -271,10 +271,11 @@ <_EmccCFlags Include="-DGEN_PINVOKE=1" /> <_EmccCFlags Include="$(EmccExtraCFlags)" /> - - <_EmccCFlags Include="-I"$(RepoRoot)src/coreclr/vm/wasm"" Condition="Exists('$(RepoRoot)src/coreclr/vm/wasm/callhelpers.hpp')" /> - <_EmccCFlags Include="-I"$(RepoRoot)src/native"" Condition="Exists('$(RepoRoot)src/native/minipal/entrypoints.h')" /> - <_EmccCFlags Include="-include "$(_WasmIntermediateOutputPath)coreclr_compat.h"" /> + + <_EmccCFlags Include="-include "$(MSBuildThisFileDirectory)coreclr_compat.h"" /> @@ -283,7 +284,7 @@ <_WasmSourceFileToCompile Include="@(NativeFileReference)" Condition="'%(Extension)' == '.c' or '%(Extension)' == '.cpp'" /> <_WasmSourceFileToCompile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" /> - <_WasmSourceFileToCompile Dependencies="$(_WasmCompileRsp);$(_WasmIntermediateOutputPath)coreclr_compat.h" /> + <_WasmSourceFileToCompile Dependencies="$(_WasmCompileRsp);$(MSBuildThisFileDirectory)coreclr_compat.h" /> @@ -362,39 +363,6 @@ - - - <_WasmCoreclrCompatHeader>$(_WasmIntermediateOutputPath)coreclr_compat.h - - - <_CompatHeaderLines Include="// Auto-generated CoreCLR compat header for app native build" /> - <_CompatHeaderLines Include="#pragma once" /> - <_CompatHeaderLines Include="#include <stddef.h>" /> - <_CompatHeaderLines Include="#include <stdint.h>" /> - <_CompatHeaderLines Include="#include <stdlib.h>" /> - <_CompatHeaderLines Include="#include <stdio.h>" /> - <_CompatHeaderLines Include="// CoreCLR type stubs" /> - <_CompatHeaderLines Include="#ifndef _CORECLR_COMPAT_TYPES" /> - <_CompatHeaderLines Include="#define _CORECLR_COMPAT_TYPES" /> - <_CompatHeaderLines Include="typedef void MethodDesc%3B" /> - <_CompatHeaderLines Include="typedef uintptr_t PCODE%3B" /> - <_CompatHeaderLines Include="typedef uint32_t ULONG%3B" /> - <_CompatHeaderLines Include="#define INTERP_STACK_SLOT_SIZE 8u" /> - <_CompatHeaderLines Include="#endif" /> - <_CompatHeaderLines Include="// CoreCLR logging stubs" /> - <_CompatHeaderLines Include="#define LF_INTEROP 0" /> - <_CompatHeaderLines Include="#define LL_INFO1000 0" /> - <_CompatHeaderLines Include="#define LOG(x)" /> - <_CompatHeaderLines Include="// CoreCLR assertion stubs" /> - <_CompatHeaderLines Include="#define PORTABILITY_ASSERT(msg) do { fprintf(stderr, "PORTABILITY_ASSERT: %25s", msg)%3B fprintf(stderr, "\n")%3B abort()%3B } while(0)" /> - - - - - - - <_WasmCFlags Include="@(_EmccCFlags)" /> diff --git a/src/mono/browser/build/coreclr_compat.h b/src/mono/browser/build/coreclr_compat.h new file mode 100644 index 00000000000000..ace0ee12f3a77f --- /dev/null +++ b/src/mono/browser/build/coreclr_compat.h @@ -0,0 +1,62 @@ +// Auto-included CoreCLR compat header for app native build. +// +// This header is pre-included via -include when compiling pinvoke-table.cpp +// and wasm_m2n_invoke.g.cpp produced by ManagedToNativeGenerator, so those +// files can be compiled outside the full CoreCLR build context (e.g. in +// Wasm.Build.Tests on Helix where src/coreclr/vm/wasm/callhelpers.hpp and +// src/native/minipal headers are not part of the payload). +// +// Definitions for the symbols declared here live in libcoreclr_static.a (which +// is linked in later) or in the same generated .cpp (e.g. g_wasmThunks / +// g_ReverseThunks tables are emitted by the generator itself). + +#pragma once + +#include +#include +#include +#include +#include + +// CoreCLR type stubs +#ifndef _CORECLR_COMPAT_TYPES +#define _CORECLR_COMPAT_TYPES +typedef void MethodDesc; +typedef uintptr_t PCODE; +typedef uint32_t ULONG; +#define INTERP_STACK_SLOT_SIZE 8u +#endif + +// CoreCLR logging stubs +#define LF_INTEROP 0 +#define LL_INFO1000 0 +#define LOG(x) + +// CoreCLR assertion stub +#define PORTABILITY_ASSERT(msg) do { fprintf(stderr, "PORTABILITY_ASSERT: %s\n", msg); abort(); } while(0) + +// Mirrors of declarations from src/coreclr/vm/wasm/callhelpers.hpp. +#define TERMINATE_R2R_STACK_WALK 1 +struct StringToWasmSigThunk { const char* key; void* value; }; +extern const StringToWasmSigThunk g_wasmThunks[]; +extern const size_t g_wasmThunksCount; +struct ReverseThunkMapValue { MethodDesc** Target; void* EntryPoint; }; +struct ReverseThunkMapEntry { ULONG hashCode; const char* Source; ReverseThunkMapValue value; }; +extern const ReverseThunkMapEntry g_ReverseThunks[]; +extern const size_t g_ReverseThunksCount; + +// Mirrors of declarations from src/native/minipal/entrypoints.h, used by +// pinvoke-table.cpp. Marked static inline (rather than the upstream 'static') +// so cpp files that #include this compat header but don't call the helper +// don't trigger -Wunused-function. +typedef struct { const char* name; const void* method; } Entry; +#define DllImportEntry(impl) {#impl, (void*)&impl}, +static inline const void* minipal_resolve_dllimport(const Entry* resolutionTable, size_t tableLength, const char* name) +{ + for (size_t i = 0; i < tableLength; i++) + { + if (strcmp(name, resolutionTable[i].name) == 0) + return resolutionTable[i].method; + } + return NULL; +} diff --git a/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs b/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs index 77be019fbfaf5b..193232149415e1 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs @@ -195,11 +195,19 @@ public string GetRuntimePackVersion(string tfm) : throw new ArgumentException($"No runtime pack version found for tfm={tfm} ."); public string GetRuntimePackDir(string tfm, RuntimeVariant runtimeType = RuntimeVariant.SingleThreaded) - => Path.Combine(WorkloadPacksDir, - runtimeType is RuntimeVariant.SingleThreaded - ? $"Microsoft.NETCore.App.Runtime.Mono.{DefaultRuntimeIdentifier}" - : $"Microsoft.NETCore.App.Runtime.Mono.multithread.{DefaultRuntimeIdentifier}", - GetRuntimePackVersion(tfm)); + => Path.Combine(WorkloadPacksDir, GetRuntimePackName(runtimeType), GetRuntimePackVersion(tfm)); + + private string GetRuntimePackName(RuntimeVariant runtimeType) + { + // CoreCLR ships browser-wasm via Microsoft.NETCore.App.Runtime.{rid} (no flavor segment). + // Mono uses Microsoft.NETCore.App.Runtime.Mono.{rid}, with a separate .multithread. variant. + if (IsCoreClrRuntime) + return $"Microsoft.NETCore.App.Runtime.{DefaultRuntimeIdentifier}"; + + return runtimeType is RuntimeVariant.SingleThreaded + ? $"Microsoft.NETCore.App.Runtime.Mono.{DefaultRuntimeIdentifier}" + : $"Microsoft.NETCore.App.Runtime.Mono.multithread.{DefaultRuntimeIdentifier}"; + } public string GetRuntimeNativeDir(string tfm, RuntimeVariant runtimeType = RuntimeVariant.SingleThreaded) => Path.Combine(GetRuntimePackDir(tfm, runtimeType), "runtimes", DefaultRuntimeIdentifier, "native"); public bool IsMultiThreadingRuntimePackAvailableFor(string tfm) diff --git a/src/mono/wasm/Wasm.Build.Tests/DllImportTests.cs b/src/mono/wasm/Wasm.Build.Tests/DllImportTests.cs index 4d84a6d567dc0e..beff38039aa6cc 100644 --- a/src/mono/wasm/Wasm.Build.Tests/DllImportTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/DllImportTests.cs @@ -14,7 +14,6 @@ namespace Wasm.Build.Tests { - [TestCategory("native")] public class DllImportTests : PInvokeTableGeneratorTestsBase { public DllImportTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) @@ -24,6 +23,9 @@ public DllImportTests(ITestOutputHelper output, SharedBuildPerTestClassFixture b [Theory] [BuildAndRun(aot: false)] + // The "warning ... native function ... varargs" check is emitted by Mono's PInvokeTableGenerator. + // CoreCLR's PInvokeTableGenerator does not emit that warning, so this test is Mono-only. + [TestCategory("mono")] public async Task NativeLibraryWithVariadicFunctions(Configuration config, bool aot) { ProjectInfo info = PrepareProjectForVariadicFunction(config, aot, "variadic"); diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs index 2883967abc0105..4975294e26448c 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests.cs @@ -41,13 +41,13 @@ from locale in locales [Theory] [MemberData(nameof(IcuExpectedAndMissingCustomShardTestData), parameters: new object[] { Configuration.Release })] - [TestCategory("native")] + [TestCategory("native-coreclr")] public async Task CustomIcuShard(Configuration config, bool aot, string customIcuPath, string customLocales, bool onlyPredefinedCultures) => await TestIcuShards(config, Template.WasmBrowser, aot, customIcuPath, customLocales, GlobalizationMode.Custom, onlyPredefinedCultures); [Theory] [MemberData(nameof(IcuExpectedAndMissingAutomaticShardTestData), parameters: new object[] { Configuration.Release })] - [TestCategory("native")] + [TestCategory("native-coreclr")] public async Task AutomaticShardSelectionDependingOnEnvLocale(Configuration config, bool aot, string environmentLocale, string testedLocales) => await PublishAndRunIcuTest(config, Template.WasmBrowser, aot, testedLocales, GlobalizationMode.Sharded, locale: environmentLocale); } diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs index 7005b99642b21e..fc7b0316dca708 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuShardingTests2.cs @@ -38,7 +38,7 @@ from locale in locales [Theory] [MemberData(nameof(IcuExpectedAndMissingShardFromRuntimePackTestData), parameters: new object[] { Configuration.Release })] - [TestCategory("native")] + [TestCategory("native-coreclr")] public async Task DefaultAvailableIcuShardsFromRuntimePack(Configuration config, bool aot, string shardName, string testedLocales) => await TestIcuShards(config, Template.WasmBrowser, aot, shardName, testedLocales, GlobalizationMode.Custom); } diff --git a/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs b/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs index f57e229bc0200d..b67e7c1a9bfba1 100644 --- a/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/IcuTests.cs @@ -53,7 +53,7 @@ public static IEnumerable IncorrectIcuTestData(Configuration config) [Theory] [MemberData(nameof(FullIcuWithInvariantTestData), parameters: new object[] { Configuration.Release })] - [TestCategory("native")] + [TestCategory("native-coreclr")] public async Task FullIcuFromRuntimePackWithInvariant(Configuration config=Configuration.Release, bool aot=false, bool invariant=true, bool fullIcu=true, string testedLocales="Array.Empty()") => await PublishAndRunIcuTest( config, @@ -67,7 +67,7 @@ await PublishAndRunIcuTest( [Theory] [MemberData(nameof(FullIcuWithICustomIcuTestData), parameters: new object[] { Configuration.Release })] - [TestCategory("native")] + [TestCategory("native-coreclr")] public async Task FullIcuFromRuntimePackWithCustomIcu(Configuration config, bool aot, bool fullIcu) { string customIcuProperty = "BlazorIcuDataFileName"; diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs index 9a7950b7a5ec4b..6d35c3265ac4d0 100644 --- a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs @@ -39,7 +39,7 @@ public async Task AOT_InvariantGlobalization(Configuration config, bool aot, boo // TODO: What else should we use to verify a relinked build? [Theory] [MemberData(nameof(InvariantGlobalizationTestData), parameters: new object[] { /*aot*/ false })] - [TestCategory("native")] + [TestCategory("native-coreclr")] public async Task RelinkingWithoutAOT(Configuration config, bool aot, bool? invariantGlobalization) => await TestInvariantGlobalization(config, aot, invariantGlobalization, isNativeBuild: true); diff --git a/src/mono/wasm/Wasm.Build.Tests/MemoryTests.cs b/src/mono/wasm/Wasm.Build.Tests/MemoryTests.cs index d4c4a32c3b6412..e796b8791476e6 100644 --- a/src/mono/wasm/Wasm.Build.Tests/MemoryTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/MemoryTests.cs @@ -13,7 +13,7 @@ namespace Wasm.Build.Tests; -[TestCategory("native")] +[TestCategory("native-coreclr")] public class MemoryTests : WasmTemplateTestsBase { public MemoryTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeBuildTests.cs b/src/mono/wasm/Wasm.Build.Tests/NativeBuildTests.cs index ff33906df14d1a..689377aa7bb97b 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeBuildTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeBuildTests.cs @@ -13,7 +13,6 @@ namespace Wasm.Build.Tests { - [TestCategory("native")] public class NativeBuildTests : WasmTemplateTestsBase { public NativeBuildTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) @@ -41,6 +40,7 @@ public async Task SimpleNativeBuild(Configuration config, bool aot) [Theory] [BuildAndRun(aot: true)] + [TestCategory("native")] public void AOTNotSupportedWithNoTrimming(Configuration config, bool aot) { ProjectInfo info = CreateWasmTemplateProject( @@ -59,6 +59,7 @@ public void AOTNotSupportedWithNoTrimming(Configuration config, bool aot) [Theory] [BuildAndRun(config: Configuration.Release, aot: true)] + [TestCategory("native")] public void IntermediateBitcodeToObjectFilesAreNotLLVMIR(Configuration config, bool aot) { string printFileTypeTarget = @" @@ -91,6 +92,7 @@ public void IntermediateBitcodeToObjectFilesAreNotLLVMIR(Configuration config, b [Theory] [BuildAndRun(config: Configuration.Release, aot: true)] + [TestCategory("native")] public void NativeBuildIsRequired(Configuration config, bool aot) { ProjectInfo info = CreateWasmTemplateProject( diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs b/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs index 9cbe49352c147c..ce9b35aa0b3838 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeLibraryTests.cs @@ -11,7 +11,6 @@ namespace Wasm.Build.Tests { - [TestCategory("native")] public class NativeLibraryTests : WasmTemplateTestsBase { public NativeLibraryTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) @@ -21,8 +20,16 @@ public NativeLibraryTests(ITestOutputHelper output, SharedBuildPerTestClassFixtu [Theory] [BuildAndRun(aot: false)] + public Task ProjectWithNativeReference(Configuration config, bool aot) => + ProjectWithNativeReferenceCore(config, aot); + + [Theory] [BuildAndRun(config: Configuration.Release, aot: true)] - public async Task ProjectWithNativeReference(Configuration config, bool aot) + [TestCategory("native")] + public Task ProjectWithNativeReference_AOT(Configuration config, bool aot) => + ProjectWithNativeReferenceCore(config, aot); + + private async Task ProjectWithNativeReferenceCore(Configuration config, bool aot) { string objectFilename = "native-lib.o"; string extraItems = $""; @@ -42,9 +49,18 @@ public async Task ProjectWithNativeReference(Configuration config, bool aot) [Theory] [BuildAndRun(aot: false)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/103566")] + public Task ProjectUsingSkiaSharp(Configuration config, bool aot) => + ProjectUsingSkiaSharpCore(config, aot); + + [Theory] [BuildAndRun(config: Configuration.Release, aot: true)] + [TestCategory("native")] [ActiveIssue("https://github.com/dotnet/runtime/issues/103566")] - public async Task ProjectUsingSkiaSharp(Configuration config, bool aot) + public Task ProjectUsingSkiaSharp_AOT(Configuration config, bool aot) => + ProjectUsingSkiaSharpCore(config, aot); + + private async Task ProjectUsingSkiaSharpCore(Configuration config, bool aot) { string prefix = $"AppUsingSkiaSharp"; string extraItems = @$" @@ -62,8 +78,16 @@ public async Task ProjectUsingSkiaSharp(Configuration config, bool aot) [Theory] [BuildAndRun(aot: false)] + public Task ProjectUsingBrowserNativeCrypto(Configuration config, bool aot) => + ProjectUsingBrowserNativeCryptoCore(config, aot); + + [Theory] [BuildAndRun(config: Configuration.Release, aot: true)] - public async Task ProjectUsingBrowserNativeCrypto(Configuration config, bool aot) + [TestCategory("native")] + public Task ProjectUsingBrowserNativeCrypto_AOT(Configuration config, bool aot) => + ProjectUsingBrowserNativeCryptoCore(config, aot); + + private async Task ProjectUsingBrowserNativeCryptoCore(Configuration config, bool aot) { ProjectInfo info = CopyTestAsset(config, aot, TestAsset.WasmBasicTestApp, "AppUsingBrowserNativeCrypto"); ReplaceFile(Path.Combine("Common", "Program.cs"), Path.Combine(BuildEnvironment.TestAssetsPath, "EntryPoints", "NativeCrypto.cs")); @@ -80,8 +104,16 @@ public async Task ProjectUsingBrowserNativeCrypto(Configuration config, bool aot [Theory] [BuildAndRun(aot: false)] + public Task ProjectWithNativeLibrary(Configuration config, bool aot) => + ProjectWithNativeLibraryCore(config, aot); + + [Theory] [BuildAndRun(config: Configuration.Release, aot: true)] - public async Task ProjectWithNativeLibrary(Configuration config, bool aot) + [TestCategory("native")] + public Task ProjectWithNativeLibrary_AOT(Configuration config, bool aot) => + ProjectWithNativeLibraryCore(config, aot); + + private async Task ProjectWithNativeLibraryCore(Configuration config, bool aot) { string extraItems = "\n"; ProjectInfo info = CopyTestAsset(config, aot, TestAsset.WasmBasicTestApp, "AppUsingNativeLib-a", extraItems: extraItems); diff --git a/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs b/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs index f88a5013b92f95..604eadcdd7f53d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs @@ -14,7 +14,6 @@ namespace Wasm.Build.Tests { - [TestCategory("native")] public class PInvokeTableGeneratorTests : PInvokeTableGeneratorTestsBase { public PInvokeTableGeneratorTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) @@ -351,6 +350,7 @@ private async Task EnsureWasmAbiRulesAreFollowed(Configuration config, bool aot) [Theory] [BuildAndRun(aot: true, config: Configuration.Release)] + [TestCategory("native")] public async Task EnsureWasmAbiRulesAreFollowedInAOT(Configuration config, bool aot) => await EnsureWasmAbiRulesAreFollowed(config, aot); @@ -361,6 +361,7 @@ public async Task EnsureWasmAbiRulesAreFollowedInInterpreter(Configuration confi [Theory] [BuildAndRun(aot: true, config: Configuration.Release)] + [TestCategory("native")] public void EnsureComInteropCompilesInAOT(Configuration config, bool aot) { ProjectInfo info = CopyTestAsset(config, aot, TestAsset.WasmBasicTestApp, "com"); diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs index c5d56480561582..04ce63edc4696e 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs @@ -89,6 +89,14 @@ public ProjectInfo CreateWasmTemplateProject( EnsureWasmTemplatesInstalled(); + // [diag] Log DOTNET_CLI_HOME inherited by the `dotnet new