diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets
index e602f23f060464..df6a2a54846efe 100644
--- a/eng/liveBuilds.targets
+++ b/eng/liveBuilds.targets
@@ -248,6 +248,9 @@
$(HostSharedFrameworkDir)dotnet.native.js;
$(HostSharedFrameworkDir)dotnet.native.wasm;
"
+ Exclude="$(LibrariesSharedFrameworkDir)libminipal.a;
+ $(LibrariesSharedFrameworkDir)libSystem.IO.Compression.Native.a;
+ $(LibrariesSharedFrameworkDir)libz.a"
IsNative="true" />
+
+
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj
index f8e03ff1dc0b71..6b7483cc170f4a 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj
@@ -14,6 +14,8 @@
NetCore.SharedFramework
true
true
+
+ true
diff --git a/src/libraries/sendtohelix-browser.targets b/src/libraries/sendtohelix-browser.targets
index 3af0478473c414..34f936a2f6d7db 100644
--- a/src/libraries/sendtohelix-browser.targets
+++ b/src/libraries/sendtohelix-browser.targets
@@ -158,6 +158,7 @@
+
@@ -165,6 +166,7 @@
+
@@ -283,6 +285,24 @@
+
+
+ <_CoreCLRWbtMinipalPayloadDir>$(ArtifactsObjDir)helix-staging\coreclr-wbt-minipal\
+
+
+ <_CoreCLRWbtMinipalFiles Include="$(RepoRoot)src\native\minipal\utils.h" />
+
+
+
+
+
+
diff --git a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
index ab69d2c3d8465b..8a06d1d068f24a 100644
--- a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
+++ b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
@@ -74,15 +74,27 @@
-
+
+
+
+
+ true
+
+
+
+
+ DependsOnTargets="_CoreCLRSetWasmBuildNativeDefaults;_CoreCLRWasmBuildAppCore" />
@@ -153,6 +165,7 @@
<_WasmIntermediateOutputPath Condition="'$(WasmBuildingForNestedPublish)' == 'true'">$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'wasm', 'for-publish'))
<_WasmCompileRsp>$(_WasmIntermediateOutputPath)emcc-compile.rsp
+ <_WasmCompileRspGenerated>$(_WasmIntermediateOutputPath)emcc-compile-generated.rsp
<_WasmLinkRsp>$(_WasmIntermediateOutputPath)emcc-link.rsp
@@ -270,11 +283,29 @@
<_EmccCFlags Include="@(_EmccCommonFlags)" />
<_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"" />
+
+
+ <_MinipalIncludeDir Condition="'$(MINIPAL_INCLUDE_DIR)' != ''">$([MSBuild]::EnsureTrailingSlash($([System.IO.Path]::GetFullPath('$(MINIPAL_INCLUDE_DIR)'))))
+ <_MinipalIncludeDir Condition="'$(_MinipalIncludeDir)' == ''">$([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..', '..', '..', 'native', 'minipal'))
+
+
+ <_EmccCFlagsGenerated Include="@(_EmccCFlags)" />
+ <_EmccCFlagsGenerated Include="-include "$(MSBuildThisFileDirectory)coreclr_compat.h"" />
+ <_EmccCFlagsGenerated Include="-include "$(_MinipalIncludeDir)utils.h"" />
@@ -282,8 +313,8 @@
<_WasmSourceFileToCompile Remove="@(_WasmSourceFileToCompile)" />
<_WasmSourceFileToCompile Include="@(NativeFileReference)" Condition="'%(Extension)' == '.c' or '%(Extension)' == '.cpp'" />
<_WasmSourceFileToCompile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" />
-
- <_WasmSourceFileToCompile Dependencies="$(_WasmCompileRsp);$(_WasmIntermediateOutputPath)coreclr_compat.h" />
+
+ <_WasmSourceFileToCompile Dependencies="$(_WasmCompileRsp)" />
@@ -352,69 +383,40 @@
cause duplicate symbol errors when the archive object is pulled in for
other required symbols (e.g., SystemInteropJS_*). -->
- <_WasmSourceFileToCompile Include="$(_WasmPInvokeTablePath)" ObjectFile="$(_WasmIntermediateOutputPath)pinvoke-table.o"
- Dependencies="$(_WasmCompileRsp);$(_WasmIntermediateOutputPath)coreclr_compat.h" />
- <_WasmSourceFileToCompile Include="$(_WasmInterpToNativeTablePath)" ObjectFile="$(_WasmIntermediateOutputPath)wasm_m2n_invoke.o"
- Dependencies="$(_WasmCompileRsp);$(_WasmIntermediateOutputPath)coreclr_compat.h" />
+ <_WasmSourceFileToCompileGenerated Remove="@(_WasmSourceFileToCompileGenerated)" />
+ <_WasmSourceFileToCompileGenerated Include="$(_WasmPInvokeTablePath)" ObjectFile="$(_WasmIntermediateOutputPath)pinvoke-table.o"
+ Dependencies="$(_WasmCompileRspGenerated);$(MSBuildThisFileDirectory)coreclr_compat.h;$(_MinipalIncludeDir)utils.h" />
+ <_WasmSourceFileToCompileGenerated Include="$(_WasmInterpToNativeTablePath)" ObjectFile="$(_WasmIntermediateOutputPath)wasm_m2n_invoke.o"
+ Dependencies="$(_WasmCompileRspGenerated);$(MSBuildThisFileDirectory)coreclr_compat.h;$(_MinipalIncludeDir)utils.h" />
-
-
-
- <_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)" />
+ <_WasmCFlagsGenerated Include="@(_EmccCFlagsGenerated)" />
-
+
+
-
+
+
-
-
- <_WasmCompileArguments Remove="@(_WasmCompileArguments)" />
- <_WasmCompileArguments Include=""@$(_WasmCompileRsp)"" Condition="'$(_WasmCompileRsp)' != ''" />
-
+
+
+
+
+
+
+
<_WasmNativeFileForLinking Include="%(_WasmSourceFileToCompile.ObjectFile)" />
+ <_WasmNativeFileForLinking Include="%(_WasmSourceFileToCompileGenerated.ObjectFile)" />
diff --git a/src/mono/browser/build/coreclr_compat.h b/src/mono/browser/build/coreclr_compat.h
new file mode 100644
index 00000000000000..f5fb46e96057c5
--- /dev/null
+++ b/src/mono/browser/build/coreclr_compat.h
@@ -0,0 +1,67 @@
+// 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 is not
+// part of the payload).
+//
+// Macro definitions consumed by generator output (NOINLINE, ARRAY_SIZE, ...)
+// come from src/native/minipal/utils.h, which is shipped to the WBT Helix
+// payload and force-included alongside this header by
+// BrowserWasmApp.CoreCLR.targets.
+//
+// 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/BrowserStructures/AssertBundleOptions.cs b/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/AssertBundleOptions.cs
index a2794ab4e91f19..266d7d25fc29fb 100644
--- a/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/AssertBundleOptions.cs
+++ b/src/mono/wasm/Wasm.Build.Tests/BrowserStructures/AssertBundleOptions.cs
@@ -15,5 +15,11 @@ public record AssertBundleOptions(
bool ExpectSymbolsFile = true,
bool AssertIcuAssets = true,
bool AssertSymbolsFile = true,
- bool? ExpectDotnetJsFingerprinting = null
+ bool? ExpectDotnetJsFingerprinting = null,
+ // Runtime pack root (the directory that contains runtimes//native/...) as resolved
+ // by the build, parsed from MSBuild output. When set, ICU asset assertions resolve their
+ // source paths from here instead of the workload-installed pack dir, so CoreCLR no-workload
+ // runs (where the publish-time pack comes from a per-test NuGet cache that doesn't match
+ // the SDK's pre-installed dotnet/packs/ contents) can still be validated correctly.
+ string? RuntimePackDir = 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..0b2782f3885ca7 100644
--- a/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs
+++ b/src/mono/wasm/Wasm.Build.Tests/Common/BuildEnvironment.cs
@@ -165,6 +165,8 @@ public BuildEnvironment()
EnvVars["WASM_APP_BUILDER_TASKS_ASSEMBLY_PATH"] = EnvironmentVariables.WasmAppBuilderTasksAssemblyPath;
if (!string.IsNullOrEmpty(EnvironmentVariables.EmsdkPath))
EnvVars["EMSDK_PATH"] = EnvironmentVariables.EmsdkPath;
+ if (!string.IsNullOrEmpty(EnvironmentVariables.MinipalIncludeDir))
+ EnvVars["MINIPAL_INCLUDE_DIR"] = EnvironmentVariables.MinipalIncludeDir;
}
DotNet = Path.Combine(sdkForWorkloadPath!, "dotnet");
@@ -195,11 +197,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/Common/EnvironmentVariables.cs b/src/mono/wasm/Wasm.Build.Tests/Common/EnvironmentVariables.cs
index c121945a78c226..81a28c8a8928dc 100644
--- a/src/mono/wasm/Wasm.Build.Tests/Common/EnvironmentVariables.cs
+++ b/src/mono/wasm/Wasm.Build.Tests/Common/EnvironmentVariables.cs
@@ -32,5 +32,6 @@ internal static class EnvironmentVariables
internal static readonly string? BrowserBuildTargetsDir = Environment.GetEnvironmentVariable("BROWSER_BUILD_TARGETS_DIR");
internal static readonly string? WasmAppBuilderTasksAssemblyPath = Environment.GetEnvironmentVariable("WASM_APP_BUILDER_TASKS_ASSEMBLY_PATH");
internal static readonly string? EmsdkPath = Environment.GetEnvironmentVariable("EMSDK_PATH");
+ internal static readonly string? MinipalIncludeDir = Environment.GetEnvironmentVariable("MINIPAL_INCLUDE_DIR");
}
}
diff --git a/src/mono/wasm/Wasm.Build.Tests/DllImportTests.cs b/src/mono/wasm/Wasm.Build.Tests/DllImportTests.cs
index 4d84a6d567dc0e..1d2aa5645cdaaa 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");
@@ -176,6 +178,11 @@ private ProjectInfo PrepareProjectForVariadicFunction(Configuration config, bool
string extraItems = $"";
ProjectInfo info = CopyTestAsset(config, aot, TestAsset.WasmBasicTestApp, prefix, extraItems: extraItems, extraProperties: extraProperties);
File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", objectFilename), Path.Combine(_projectDir, objectFilename));
+
+ // The variadic-function test program does not use JS interop, so the JS interop
+ // assembly would be linked away by the trimmer (CoreCLR-Wasm) and the template
+ // main.js (which calls getAssemblyExports) would fail at startup.
+ ReplaceMainJsWithMinimalRunMain();
return info;
}
}
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