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.