diff --git a/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt b/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt
index 336825869e84db..2e596994dba648 100644
--- a/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt
+++ b/eng/testing/scenarios/BuildWasmAppsJobsListCoreCLR.txt
@@ -19,6 +19,7 @@ Wasm.Build.Tests.NativeLibraryTests
Wasm.Build.Tests.IcuShardingTests
Wasm.Build.Tests.IcuShardingTests2
Wasm.Build.Tests.IcuTests
+Wasm.Build.Tests.InvariantGlobalizationTests
Wasm.Build.Tests.MemoryTests
Wasm.Build.Tests.AppSettingsTests
Wasm.Build.Tests.Blazor.AppsettingsTests
diff --git a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
index 7df82320d2f495..932a759e397469 100644
--- a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
+++ b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
@@ -423,7 +423,8 @@
<_WasmPInvokeModules Include="%(_WasmSourceFileToCompile.FileName)" Condition="'%(_WasmSourceFileToCompile.ScanForPInvokes)' != 'false'" />
<_WasmPInvokeModules Include="libSystem.Native" />
<_WasmPInvokeModules Include="libSystem.IO.Compression.Native" />
- <_WasmPInvokeModules Include="libSystem.Globalization.Native" />
+ <_WasmPInvokeModules Include="libSystem.Globalization.Native" Condition="'$(InvariantGlobalization)' != 'true'" />
+ <_WasmIgnoredPInvokeModules Include="libSystem.Globalization.Native" Condition="'$(InvariantGlobalization)' == 'true'" />
<_WasmPInvokeModules Include="libSystem.Native.Browser" />
<_WasmPInvokeModules Include="libSystem.Runtime.InteropServices.JavaScript.Native" />
@@ -451,6 +452,7 @@
<_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libSystem.Runtime.InteropServices.JavaScript.Native.a" />
<_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libSystem.Native.a" />
-
- <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libSystem.Globalization.Native.a" />
- <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libicuuc.a" />
- <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libicui18n.a" />
- <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libicudata.a" />
+ <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libSystem.Globalization.Native.a" Condition="'$(InvariantGlobalization)' != 'true'" />
+ <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libicuuc.a" Condition="'$(InvariantGlobalization)' != 'true'" />
+ <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libicui18n.a" Condition="'$(InvariantGlobalization)' != 'true'" />
+ <_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libicudata.a" Condition="'$(InvariantGlobalization)' != 'true'" />
<_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libSystem.IO.Compression.Native.a" />
<_CoreCLRNativeLibs Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)libz.a" />
diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs
index 921fbb5cc152d0..53b8428c2bfaea 100644
--- a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs
+++ b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs
@@ -43,6 +43,29 @@ public async Task AOT_InvariantGlobalization(Configuration config, bool aot, boo
public async Task RelinkingWithoutAOT(Configuration config, bool aot, bool? invariantGlobalization)
=> await TestInvariantGlobalization(config, aot, invariantGlobalization, isNativeBuild: true);
+ [ConditionalTheory(typeof(BuildTestBase), nameof(IsCoreClrRuntime))]
+ [BuildAndRun(aot: false, config: Configuration.Release)]
+ [TestCategory("no-workload")]
+ public void CoreCLRInvariantGlobalizationDoesNotLinkGlobalizationNative(Configuration config, bool aot)
+ {
+ string extraProperties = "true";
+ ProjectInfo info = CopyTestAsset(config, aot, TestAsset.WasmBasicTestApp, "invariant_coreclr", extraProperties: extraProperties);
+ ReplaceFile(Path.Combine("Common", "Program.cs"), Path.Combine(BuildEnvironment.TestAssetsPath, "EntryPoints", "InvariantGlobalization.cs"));
+ ReplaceMainJsWithMinimalRunMain();
+
+ PublishProject(info, config, new PublishOptions(GlobalizationMode: GlobalizationMode.Invariant, AOT: aot), isNativeBuild: true);
+
+ string nativeBuildDir = Path.Combine(_projectDir, "obj", config.ToString(), DefaultTargetFramework, "wasm", "for-publish");
+ string pinvokeTable = File.ReadAllText(Path.Combine(nativeBuildDir, "callhelpers-pinvoke.cpp"));
+ Assert.DoesNotContain("GlobalizationNative_", pinvokeTable);
+
+ string linkRsp = File.ReadAllText(Path.Combine(nativeBuildDir, "emcc-link.rsp"));
+ Assert.DoesNotContain("libSystem.Globalization.Native.a", linkRsp);
+ Assert.DoesNotContain("libicuuc.a", linkRsp);
+ Assert.DoesNotContain("libicui18n.a", linkRsp);
+ Assert.DoesNotContain("libicudata.a", linkRsp);
+ }
+
private async Task TestInvariantGlobalization(Configuration config, bool aot, bool? invariantGlobalization, bool? isNativeBuild = null)
{
string extraProperties = isNativeBuild == true ? "true" : "";
diff --git a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs
index 368da23206f4a4..4aaaaf8d97179b 100644
--- a/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs
+++ b/src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs
@@ -21,6 +21,8 @@ public class ManagedToNativeGenerator : Task
[Required, NotNull]
public string[]? PInvokeModules { get; set; }
+ public string[] IgnoredPInvokeModules { get; set; } = Array.Empty();
+
[Required, NotNull]
public string? PInvokeOutputPath { get; set; }
@@ -93,7 +95,7 @@ private void ExecuteInternal(LogAdapter log)
// SignatureMapper.CharToNativeType method.
string[] pregeneratedInterpreterToNativeSignatures = Array.Empty(); // Currently none, but can be added here as needed in the future.
- IEnumerable cookies = pinvoke.Generate(PInvokeModules, PInvokeOutputPath, ReversePInvokeOutputPath);
+ IEnumerable cookies = pinvoke.Generate(PInvokeModules, IgnoredPInvokeModules, PInvokeOutputPath, ReversePInvokeOutputPath);
cookies = cookies.Concat(internalCallCollector.GetSignatures());
cookies = cookies.Concat(pregeneratedInterpreterToNativeSignatures);
@@ -101,7 +103,12 @@ private void ExecuteInternal(LogAdapter log)
m2n.Generate(cookies, InterpToNativeOutputPath);
if (!string.IsNullOrEmpty(CacheFilePath))
- File.WriteAllLines(CacheFilePath, PInvokeModules, Encoding.UTF8);
+ {
+ IEnumerable cacheLines = PInvokeModules
+ .Select(module => $"module:{module}")
+ .Concat(IgnoredPInvokeModules.Select(module => $"ignored:{module}"));
+ File.WriteAllLines(CacheFilePath, cacheLines, Encoding.UTF8);
+ }
List fileWritesList = new() { PInvokeOutputPath, InterpToNativeOutputPath };
if (!string.IsNullOrEmpty(CacheFilePath))
diff --git a/src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs b/src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs
index a8377c81dab2f3..8a4c8e037cde60 100644
--- a/src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs
+++ b/src/tasks/WasmAppBuilder/coreclr/PInvokeTableGenerator.cs
@@ -40,16 +40,23 @@ public void ScanAssembly(Assembly asm)
_pinvokeCollector.CollectPInvokes(pinvokes, callbacks, signatures, type);
}
- public IEnumerable Generate(string[] pinvokeModules, string outputPathPInvoke, string outputPathReversePInvoke)
+ public IEnumerable Generate(string[] pinvokeModules, string[] ignoredPInvokeModules, string outputPathPInvoke, string outputPathReversePInvoke)
{
+ var ignoredModules = new HashSet(ignoredPInvokeModules, StringComparer.Ordinal);
var modules = new SortedDictionary(StringComparer.Ordinal);
foreach (var module in pinvokeModules)
- modules[module] = module;
+ {
+ if (!ignoredModules.Contains(module))
+ modules[module] = module;
+ }
+
+ foreach (var module in ignoredModules.OrderBy(module => module, StringComparer.Ordinal))
+ Log.LogMessage(MessageImportance.Low, $"Ignoring PInvoke module {module}");
using TempFileName tmpFileNamePInvoke = new();
using (var w = new JoinedStringStreamWriter(tmpFileNamePInvoke.Path, false))
{
- EmitPInvokeTable(w, modules, pinvokes);
+ EmitPInvokeTable(w, modules, ignoredModules, pinvokes);
}
using TempFileName tmpFileNameReversePInvoke = new();
@@ -71,12 +78,14 @@ public IEnumerable Generate(string[] pinvokeModules, string outputPathPI
return signatures;
}
- private void EmitPInvokeTable(StreamWriter w, SortedDictionary modules, List pinvokes)
+ private void EmitPInvokeTable(StreamWriter w, SortedDictionary modules, HashSet ignoredModules, List pinvokes)
{
foreach (var pinvoke in pinvokes)
{
if (modules.ContainsKey(pinvoke.Module))
continue;
+ if (ignoredModules.Contains(pinvoke.Module))
+ continue;
// Handle special modules, and add them to the list of modules
// otherwise, skip them and throw an exception at runtime if they
// are called.