From cda65db665af9d27c4e7ecf50ea69efdf26cb8c7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Mon, 26 Jun 2023 17:15:42 +0200 Subject: [PATCH 1/7] wip --- .../features/timezone-invariant-mode.md | 12 +++ ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 2 + .../sample/wasm/browser-advanced/Program.cs | 20 ++++ .../Wasm.Advanced.Sample.csproj | 1 + src/mono/wasi/build/WasiApp.Native.targets | 3 +- src/mono/wasi/build/WasiApp.targets | 1 + src/mono/wasi/runtime/driver.c | 4 + src/mono/wasi/wasi.proj | 2 +- .../InvariantTimezoneTests.cs | 97 +++++++++++++++++++ src/mono/wasm/build/WasmApp.Native.targets | 1 + src/mono/wasm/build/WasmApp.targets | 1 + src/mono/wasm/runtime/driver.c | 4 + src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 2 +- src/mono/wasm/wasm.proj | 2 +- 14 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 docs/design/features/timezone-invariant-mode.md create mode 100644 src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs diff --git a/docs/design/features/timezone-invariant-mode.md b/docs/design/features/timezone-invariant-mode.md new file mode 100644 index 00000000000000..e66da8ea5407d8 --- /dev/null +++ b/docs/design/features/timezone-invariant-mode.md @@ -0,0 +1,12 @@ +# Timezone Invariant Mode + +Author: [Pavel Savara](https://github.com/pavelsavara) + +It's currently only available for Browser OS + +- you enable it in project file: + ```xml + + true + + ``` diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 5cf78e89c3c156..60d60e74168987 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -47,6 +47,8 @@ Copyright (c) .NET Foundation. All rights reserved. false + true + false false true false diff --git a/src/mono/sample/wasm/browser-advanced/Program.cs b/src/mono/sample/wasm/browser-advanced/Program.cs index af6ca78e0bbdad..bec9cb3256b4c5 100644 --- a/src/mono/sample/wasm/browser-advanced/Program.cs +++ b/src/mono/sample/wasm/browser-advanced/Program.cs @@ -13,6 +13,26 @@ public partial class Test public static int Main(string[] args) { Console.WriteLine ("Hello, World!"); + + var start = DateTime.UtcNow; + var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count; + var end = DateTime.UtcNow; + Console.WriteLine($"Found {timezonesCount} timezones in the TZ database in {end-start}"); + + TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById("UTC"); + Console.WriteLine($"{utc.DisplayName} BaseUtcOffset is {utc.BaseUtcOffset}"); + + try + { + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo"); + Console.WriteLine($"{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}"); + } + catch (TimeZoneNotFoundException tznfe) + { + Console.WriteLine($"Could not find Asia/Tokyo: {tznfe.Message}"); + } + + return 0; } diff --git a/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj b/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj index d37b17495581b5..782efa96a8236b 100644 --- a/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj +++ b/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj @@ -14,6 +14,7 @@ <_ServeHeaders>$(_ServeHeaders) -h "Content-Security-Policy: default-src 'self' 'wasm-unsafe-eval'" browser; + true diff --git a/src/mono/wasi/build/WasiApp.Native.targets b/src/mono/wasi/build/WasiApp.Native.targets index e0e43c0edffc4b..8fd82eaca343f7 100644 --- a/src/mono/wasi/build/WasiApp.Native.targets +++ b/src/mono/wasi/build/WasiApp.Native.targets @@ -168,8 +168,9 @@ <_WasmCommonCFlags Include="-DGEN_PINVOKE=1" /> - <_WasmCommonCFlags Condition="'$(WasmSingleFileBundle)' == 'true'" Include="-DWASM_SINGLE_FILE=1" /> + <_WasmCommonCFlags Condition="'$(WasmSingleFileBundle)' == 'true'" Include="-DWASM_SINGLE_FILE=1" /> <_WasmCommonCFlags Condition="'$(InvariantGlobalization)' == 'true'" Include="-DINVARIANT_GLOBALIZATION=1" /> + <_WasmCommonCFlags Condition="'$(InvariantTimezone)' == 'true'" Include="-DINVARIANT_TIMEZONE=1" /> diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index c39ec3a0a880f9..2a711e5eeea2fc 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -29,6 +29,7 @@ - $(WasmProfilers) - Profilers to use - $(AOTProfilePath) - profile data file to be used for profile-guided optimization - $(InvariantGlobalization) - Whenever to disable ICU. Defaults to false. + - $(InvariantTimezone) - Whenever to disable Timezone database. Defaults to false. - $(WasmResolveAssembliesBeforeBuild) - Resolve the assembly dependencies. Defaults to false - $(WasmAssemblySearchPaths) - used for resolving assembly dependencies diff --git a/src/mono/wasi/runtime/driver.c b/src/mono/wasi/runtime/driver.c index d6a51f9be51b06..98fbe1fef04bbb 100644 --- a/src/mono/wasi/runtime/driver.c +++ b/src/mono/wasi/runtime/driver.c @@ -63,7 +63,9 @@ int32_t monoeg_g_hasenv(const char *variable); void mono_free (void*); int32_t mini_parse_debug_option (const char *option); char *mono_method_get_full_name (MonoMethod *method); +#ifndef INVARIANT_TIMEZONE extern void mono_register_timezones_bundle (void); +#endif /* INVARIANT_TIMEZONE */ #ifdef WASM_SINGLE_FILE extern void mono_register_assemblies_bundle (void); #ifndef INVARIANT_GLOBALIZATION @@ -439,7 +441,9 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mini_parse_debug_option ("top-runtime-invoke-unhandled"); +#ifndef INVARIANT_TIMEZONE mono_register_timezones_bundle (); +#endif /* INVARIANT_TIMEZONE */ #ifdef WASM_SINGLE_FILE mono_register_assemblies_bundle (); #endif diff --git a/src/mono/wasi/wasi.proj b/src/mono/wasi/wasi.proj index fbf434ce4964af..d601f2c9e09ab6 100644 --- a/src/mono/wasi/wasi.proj +++ b/src/mono/wasi/wasi.proj @@ -66,7 +66,7 @@ - + <_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data')) <_WasmTimezonesBundleObjectFile>wasm-bundled-timezones.o diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs new file mode 100644 index 00000000000000..1f10c80e14a38d --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests +{ + public class InvariantTimezoneTests : BuildTestBase + { + public InvariantTimezoneTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + public static IEnumerable InvariantTimezoneTestData(bool aot, RunHost host) + => ConfigWithAOTData(aot) + .Multiply( + new object?[] { null }, + new object?[] { false }, + new object?[] { true }) + .WithRunHosts(host) + .UnwrapItemsAsArrays(); + + [Theory] + [MemberData(nameof(InvariantTimezoneTestData), parameters: new object[] { /*aot*/ false, RunHost.All })] + [MemberData(nameof(InvariantTimezoneTestData), parameters: new object[] { /*aot*/ true, RunHost.All })] + public void AOT_InvariantTimezone(BuildArgs buildArgs, bool? invariantTimezone, RunHost host, string id) + => TestInvariantTimezone(buildArgs, invariantTimezone, host, id); + + [Theory] + [MemberData(nameof(InvariantTimezoneTestData), parameters: new object[] { /*aot*/ false, RunHost.All })] + public void RelinkingWithoutAOT(BuildArgs buildArgs, bool? invariantTimezone, RunHost host, string id) + => TestInvariantTimezone(buildArgs, invariantTimezone, host, id, + extraProperties: "true", + dotnetWasmFromRuntimePack: false); + + private void TestInvariantTimezone(BuildArgs buildArgs, bool? invariantTimezone, + RunHost host, string id, string extraProperties="", bool? dotnetWasmFromRuntimePack=null) + { + string projectName = $"invariant_{invariantTimezone?.ToString() ?? "unset"}"; + if (invariantTimezone != null) + extraProperties = $"{extraProperties}{invariantTimezone}"; + + buildArgs = buildArgs with { ProjectName = projectName }; + buildArgs = ExpandBuildArgs(buildArgs, extraProperties); + + if (dotnetWasmFromRuntimePack == null) + dotnetWasmFromRuntimePack = !(buildArgs.AOT || buildArgs.Config == "Release"); + + string programText = @" + using System; + + // https://github.com/dotnet/runtime/blob/main/docs/design/features/timezone-invariant-mode.md + + var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count; + Console.WriteLine($""Found {timezonesCount} timezones in the TZ database""); + + TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById(""UTC""); + Console.WriteLine($""{utc.DisplayName} BaseUtcOffset is {utc.BaseUtcOffset}""); + + try + { + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(""Asia/Tokyo""); + Console.WriteLine($""{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}""); + } + catch (TimeZoneNotFoundException tznfe) + { + Console.WriteLine($""Could not find Asia/Tokyo: {tznfe.Message}""); + } + + return 42; + "; + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), programText), + DotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack)); + + string output = RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id); + Assert.Contains("UTC BaseUtcOffset is 0", output); + if (invariantGlobalization == true) + { + Assert.Contains("Could not find Asia/Tokyo", output); + } + else + { + Assert.Contains("Asia/Tokyo BaseUtcOffset is 09:00:00", output); + } + } + } +} diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 310d77cf36d6df..403096064dd470 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -219,6 +219,7 @@ <_EmccCFlags Include="-DENABLE_AOT=1" Condition="'$(_WasmShouldAOT)' == 'true'" /> <_EmccCFlags Include="-DDRIVER_GEN=1" Condition="'$(_WasmShouldAOT)' == 'true'" /> <_EmccCFlags Include="-DINVARIANT_GLOBALIZATION=1" Condition="'$(InvariantGlobalization)' == 'true'" /> + <_EmccCFlags Include="-DINVARIANT_TIMEZONE=1" Condition="'$(InvariantTimezone)' == 'true'" /> <_EmccCFlags Include="-DLINK_ICALLS=1" Condition="'$(WasmLinkIcalls)' == 'true'" /> <_EmccCFlags Include="-DENABLE_AOT_PROFILER=1" Condition="$(WasmProfilers.Contains('aot'))" /> <_EmccCFlags Include="-DENABLE_BROWSER_PROFILER=1" Condition="$(WasmProfilers.Contains('browser'))" /> diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 929089695e14a5..b243b3d64b03dd 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -28,6 +28,7 @@ - $(WasmProfilers) - Profilers to use - $(AOTProfilePath) - profile data file to be used for profile-guided optimization - $(InvariantGlobalization) - Whenever to disable ICU. Defaults to false. + - $(InvariantTimezone) - Whenever to disable Timezone database. Defaults to false. - $(HybridGlobalization) - Whenever to enable reduced ICU + native platform functions. Defaults to false and can be set only for InvariantGlobalization=false, WasmIncludeFullIcuData=false and empty WasmIcuDataFileName. - $(WasmResolveAssembliesBeforeBuild) - Resolve the assembly dependencies. Defaults to false diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 51cd2497a1b9d6..551d1b4ca87095 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -54,7 +54,9 @@ int monoeg_g_setenv(const char *variable, const char *value, int overwrite); int32_t mini_parse_debug_option (const char *option); char *mono_method_get_full_name (MonoMethod *method); +#ifndef INVARIANT_TIMEZONE extern void mono_register_timezones_bundle (void); +#endif /* INVARIANT_TIMEZONE */ extern void mono_wasm_set_entrypoint_breakpoint (const char* assembly_name, int method_token); static void mono_wasm_init_finalizer_thread (void); @@ -473,7 +475,9 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mini_parse_debug_option ("top-runtime-invoke-unhandled"); +#ifndef INVARIANT_TIMEZONE mono_register_timezones_bundle (); +#endif /* INVARIANT_TIMEZONE */ mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL); mono_wasm_install_get_native_to_interp_tramp (get_native_to_interp); diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js index cea78ac93822af..8ea0b7deb2f891 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js @@ -137,6 +137,7 @@ linked_functions = [...linked_functions, "mono_wasm_install_js_worker_interop", "mono_wasm_uninstall_js_worker_interop", ] +#endif if (ENABLE_AOT_PROFILER) { linked_functions = [...linked_functions, @@ -153,7 +154,6 @@ if (ENABLE_AOT_PROFILER) { ] } -#endif if (!DISABLE_LEGACY_JS_INTEROP) { linked_functions = [...linked_functions, "mono_wasm_invoke_js_with_args_ref", diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index c150a1fe09d318..98a62905600f7b 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -80,7 +80,7 @@ - + <_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data')) <_WasmTimezonesBundleSourceFile>wasm-bundled-timezones.c From 754499812bed17d2a52c7df6b30610dc2765ca7f Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Mon, 26 Jun 2023 18:17:02 +0200 Subject: [PATCH 2/7] fix --- src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs index 1f10c80e14a38d..bf14e83da6898d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs @@ -84,7 +84,7 @@ private void TestInvariantTimezone(BuildArgs buildArgs, bool? invariantTimezone, string output = RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id); Assert.Contains("UTC BaseUtcOffset is 0", output); - if (invariantGlobalization == true) + if (invariantTimezone == true) { Assert.Contains("Could not find Asia/Tokyo", output); } From 75a14d174dd8da6a550c82ab01b64eb47145dff0 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 27 Jun 2023 22:35:26 +0200 Subject: [PATCH 3/7] WBT --- eng/testing/scenarios/BuildWasmAppsJobsList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index e84e70c3f8f730..64f6abf5a1a650 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -14,6 +14,7 @@ Wasm.Build.Tests.ConfigSrcTests Wasm.Build.Tests.IcuShardingTests Wasm.Build.Tests.HybridGlobalizationTests Wasm.Build.Tests.InvariantGlobalizationTests +Wasm.Build.Tests.InvariantTimezoneTests Wasm.Build.Tests.MainWithArgsTests Wasm.Build.Tests.NativeBuildTests Wasm.Build.Tests.NativeLibraryTests From 670b5138c6179091b68d8152ca9c2e86278db056 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 28 Jun 2023 13:39:15 +0200 Subject: [PATCH 4/7] feedback --- .../Wasi.Build.Tests/WasiTemplateTests.cs | 34 +++++++++++++++---- .../InvariantGlobalizationTests.cs | 21 +----------- .../InvariantTimezoneTests.cs | 26 +------------- .../InvariantGlobalization.cs | 16 +++++++++ .../InvariantTimezone.cs | 21 ++++++++++++ 5 files changed, 67 insertions(+), 51 deletions(-) create mode 100644 src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs create mode 100644 src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs diff --git a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs index cad75213793781..5a5a485fd8880d 100644 --- a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs +++ b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs @@ -74,19 +74,19 @@ public void ConsoleBuildThenPublish(string config) UseCache: false)); } - public static TheoryData TestDataForConsolePublishAndRun() + public static TheoryData TestDataForConsolePublishAndRun() { - var data = new TheoryData(); - data.Add("Debug", false); - data.Add("Debug", true); - data.Add("Release", false); // Release relinks by default + var data = new TheoryData(); + data.Add("Debug", false, false); + data.Add("Debug", true, true); + data.Add("Release", false, false); // Release relinks by default return data; } [ConditionalTheory(typeof(BuildTestBase), nameof(IsUsingWorkloads))] [ActiveIssue("https://github.com/dotnet/runtime/issues/82515", TestPlatforms.Windows)] [MemberData(nameof(TestDataForConsolePublishAndRun))] - public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinking) + public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinking, bool invariantTimezone) { string id = $"{config}_{Path.GetRandomFileName()}"; string projectFile = CreateWasmTemplateProject(id, "wasiconsole"); @@ -96,6 +96,8 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin string extraProperties = "true"; if (relinking) extraProperties += "true"; + if (invariantTimezone) + extraProperties += "true"; AddItemsPropertiesToProject(projectFile, extraProperties); @@ -125,6 +127,15 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin Assert.Contains("args[0] = x", res.Output); Assert.Contains("args[1] = y", res.Output); Assert.Contains("args[2] = z", res.Output); + if(invariantTimezone) + { + Assert.Contains("Could not find Asia/Tokyo", res.Output); + } + else + { + Assert.Contains("Asia/Tokyo BaseUtcOffset is 09:00:00", res.Output); + } + } private static readonly string s_simpleMainWithArgs = """ @@ -133,6 +144,17 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin Console.WriteLine("Hello, Wasi Console!"); for (int i = 0; i < args.Length; i ++) Console.WriteLine($"args[{i}] = {args[i]}"); + + try + { + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(""Asia/Tokyo""); + Console.WriteLine($""{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}""); + } + catch (TimeZoneNotFoundException tznfe) + { + Console.WriteLine($""Could not find Asia/Tokyo: {tznfe.Message}""); + } + return 42; """; } diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs index 41dac50141cf7c..ea5a045e7f6c24 100644 --- a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs @@ -54,29 +54,10 @@ private void TestInvariantGlobalization(BuildArgs buildArgs, bool? invariantGlob if (dotnetWasmFromRuntimePack == null) dotnetWasmFromRuntimePack = !(buildArgs.AOT || buildArgs.Config == "Release"); - string programText = @" - using System; - using System.Globalization; - - // https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#cultures-and-culture-data - try - { - CultureInfo culture = new (""es-ES"", false); - Console.WriteLine($""es-ES: Is Invariant LCID: {culture.LCID == CultureInfo.InvariantCulture.LCID}, NativeName: {culture.NativeName}""); - } - catch (CultureNotFoundException cnfe) - { - Console.WriteLine($""Could not create es-ES culture: {cnfe.Message}""); - } - - Console.WriteLine($""CurrentCulture.NativeName: {CultureInfo.CurrentCulture.NativeName}""); - return 42; - "; - BuildProject(buildArgs, id: id, new BuildProjectOptions( - InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), programText), + InitProject: () => File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Wasm.Buid.Tests.Programs", "InvariantGlobalization.cs"), Path.Combine(_projectDir!, "Program.cs")), DotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack, GlobalizationMode: invariantGlobalization == true ? GlobalizationMode.Invariant : null)); diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs index bf14e83da6898d..f89e04d508307d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs @@ -52,34 +52,10 @@ private void TestInvariantTimezone(BuildArgs buildArgs, bool? invariantTimezone, if (dotnetWasmFromRuntimePack == null) dotnetWasmFromRuntimePack = !(buildArgs.AOT || buildArgs.Config == "Release"); - string programText = @" - using System; - - // https://github.com/dotnet/runtime/blob/main/docs/design/features/timezone-invariant-mode.md - - var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count; - Console.WriteLine($""Found {timezonesCount} timezones in the TZ database""); - - TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById(""UTC""); - Console.WriteLine($""{utc.DisplayName} BaseUtcOffset is {utc.BaseUtcOffset}""); - - try - { - TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(""Asia/Tokyo""); - Console.WriteLine($""{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}""); - } - catch (TimeZoneNotFoundException tznfe) - { - Console.WriteLine($""Could not find Asia/Tokyo: {tznfe.Message}""); - } - - return 42; - "; - BuildProject(buildArgs, id: id, new BuildProjectOptions( - InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), programText), + InitProject: () => File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Wasm.Buid.Tests.Programs", "InvariantTimezone.cs"), Path.Combine(_projectDir!, "Program.cs")), DotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack)); string output = RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id); diff --git a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs new file mode 100644 index 00000000000000..9237110cbc4980 --- /dev/null +++ b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs @@ -0,0 +1,16 @@ +using System; +using System.Globalization; + +// https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#cultures-and-culture-data +try +{ + CultureInfo culture = new ("es-ES", false); + Console.WriteLine($"es-ES: Is Invariant LCID: {culture.LCID == CultureInfo.InvariantCulture.LCID}, NativeName: {culture.NativeName}"); +} +catch (CultureNotFoundException cnfe) +{ + Console.WriteLine($"Could not create es-ES culture: {cnfe.Message}"); +} + +Console.WriteLine($"CurrentCulture.NativeName: {CultureInfo.CurrentCulture.NativeName}"); +return 42; diff --git a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs new file mode 100644 index 00000000000000..deba28c7be27ea --- /dev/null +++ b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs @@ -0,0 +1,21 @@ +using System; + +// https://github.com/dotnet/runtime/blob/main/docs/design/features/timezone-invariant-mode.md + +var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count; +Console.WriteLine($"Found {timezonesCount} timezones in the TZ database"); + +TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById("UTC"); +Console.WriteLine($"{utc.DisplayName} BaseUtcOffset is {utc.BaseUtcOffset}"); + +try +{ + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo"); + Console.WriteLine($"{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}"); +} +catch (TimeZoneNotFoundException tznfe) +{ + Console.WriteLine($"Could not find Asia/Tokyo: {tznfe.Message}"); +} + +return 42; From d0ae247b8c505ed3d2a1f0307664294920b722b8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 28 Jun 2023 16:18:34 +0200 Subject: [PATCH 5/7] fix native build --- src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs | 6 +++--- src/mono/wasi/build/WasiApp.Native.targets | 5 +++++ src/mono/wasi/build/WasiApp.targets | 1 + src/mono/wasm/build/WasmApp.Native.targets | 8 ++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs index 5a5a485fd8880d..196d9305d1f25a 100644 --- a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs +++ b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs @@ -147,12 +147,12 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin try { - TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById(""Asia/Tokyo""); - Console.WriteLine($""{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}""); + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo"); + Console.WriteLine($"{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}"); } catch (TimeZoneNotFoundException tznfe) { - Console.WriteLine($""Could not find Asia/Tokyo: {tznfe.Message}""); + Console.WriteLine($"Could not find Asia/Tokyo: {tznfe.Message}"); } return 42; diff --git a/src/mono/wasi/build/WasiApp.Native.targets b/src/mono/wasi/build/WasiApp.Native.targets index 8fd82eaca343f7..bcc99310d6d897 100644 --- a/src/mono/wasi/build/WasiApp.Native.targets +++ b/src/mono/wasi/build/WasiApp.Native.targets @@ -63,6 +63,8 @@ true true + true + true true @@ -75,6 +77,8 @@ true true true + true + true false @@ -274,6 +278,7 @@ <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" /> + <_MonoRuntimeComponentDontLink Include="wasm-bundled-timezones.a" Condition="'$(InvariantTimezone)' == 'true'"/> <_WasmNativeFileForLinking Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)*.a" diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index 2a711e5eeea2fc..c79e12d2e2b1b1 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -120,6 +120,7 @@ false true true + true true wasmtime diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 403096064dd470..34736613dd8f6a 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -115,6 +115,10 @@ true + + true + true + true false @@ -129,6 +133,10 @@ true + + true + true + false From d717645f005432e3f7d66a2ad8c7a2fcaeb2dfe7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 29 Jun 2023 09:13:07 +0200 Subject: [PATCH 6/7] feedback --- docs/design/features/timezone-invariant-mode.md | 8 ++++++-- src/mono/wasi/build/WasiApp.targets | 12 ++++++------ src/mono/wasm/build/WasmApp.targets | 14 +++++++------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/docs/design/features/timezone-invariant-mode.md b/docs/design/features/timezone-invariant-mode.md index e66da8ea5407d8..f7be1b06e7f7eb 100644 --- a/docs/design/features/timezone-invariant-mode.md +++ b/docs/design/features/timezone-invariant-mode.md @@ -2,9 +2,13 @@ Author: [Pavel Savara](https://github.com/pavelsavara) -It's currently only available for Browser OS +It's currently only available for Browser OS. +The timezone database is not part of the browser environment (as opposed to other operating systems). +Therefore dotnet bundles the timezone database as binary as part of the runtime. +That makes download size larger and application startup slower. +If your application doesn't need to work with time zone information, you could use this feature to make the runtime about 200KB smaller. -- you enable it in project file: +You enable it in project file: ```xml true diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index c79e12d2e2b1b1..8909c89aa44009 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -11,9 +11,9 @@ Public properties (optional): - $(WasmAppDir) - AppBundle dir (Defaults to `$(OutputPath)\$(Configuration)\AppBundle`) - $(WasmMainAssemblyFileName)- Defaults to $(TargetFileName) - - $(WasmBuildNative) - Whenever to build the native executable. Defaults to false. - - $(WasmNativeStrip) - Whenever to strip the native executable. Defaults to true. - - $(WasmLinkIcalls) - Whenever to link out unused icalls. Defaults to $(WasmBuildNative). + - $(WasmBuildNative) - Whether to build the native executable. Defaults to false. + - $(WasmNativeStrip) - Whether to strip the native executable. Defaults to true. + - $(WasmLinkIcalls) - Whether to link out unused icalls. Defaults to $(WasmBuildNative). - $(RunAOTCompilation) - Defaults to false. - $(WasmDebugLevel) @@ -24,12 +24,12 @@ - $(WasmNativeDebugSymbols) - Build with native debug symbols, useful only with `$(RunAOTCompilation)`, or `$(WasmBuildNative)` Defaults to true. - $(WasmEmitSymbolMap) - Generates a `dotnet.js.symbols` file with a map of wasm function number to name. - - $(WasmDedup) - Whenever to dedup generic instances when using AOT. Defaults to true. + - $(WasmDedup) - Whether to dedup generic instances when using AOT. Defaults to true. - $(WasmProfilers) - Profilers to use - $(AOTProfilePath) - profile data file to be used for profile-guided optimization - - $(InvariantGlobalization) - Whenever to disable ICU. Defaults to false. - - $(InvariantTimezone) - Whenever to disable Timezone database. Defaults to false. + - $(InvariantGlobalization) - Whether to disable ICU. Defaults to false. + - $(InvariantTimezone) - Whether to disable Timezone database. Defaults to false. - $(WasmResolveAssembliesBeforeBuild) - Resolve the assembly dependencies. Defaults to false - $(WasmAssemblySearchPaths) - used for resolving assembly dependencies diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index ebc945aa5a9326..ee93107340dc9d 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -10,9 +10,9 @@ Public properties (optional): - $(WasmAppDir) - AppBundle dir (Defaults to `$(OutputPath)\$(Configuration)\AppBundle`) - $(WasmMainAssemblyFileName)- Defaults to $(TargetFileName) - - $(WasmBuildNative) - Whenever to build the native executable. Defaults to false. - - $(WasmNativeStrip) - Whenever to strip the native executable. Defaults to true. - - $(WasmLinkIcalls) - Whenever to link out unused icalls. Defaults to $(WasmBuildNative). + - $(WasmBuildNative) - Whether to build the native executable. Defaults to false. + - $(WasmNativeStrip) - Whether to strip the native executable. Defaults to true. + - $(WasmLinkIcalls) - Whether to link out unused icalls. Defaults to $(WasmBuildNative). - $(RunAOTCompilation) - Defaults to false. - $(WasmDebugLevel) @@ -23,13 +23,13 @@ - $(WasmNativeDebugSymbols) - Build with native debug symbols, useful only with `$(RunAOTCompilation)`, or `$(WasmBuildNative)` Defaults to true. - $(WasmEmitSymbolMap) - Generates a `dotnet.native.js.symbols` file with a map of wasm function number to name. - - $(WasmDedup) - Whenever to dedup generic instances when using AOT. Defaults to true. + - $(WasmDedup) - Whether to dedup generic instances when using AOT. Defaults to true. - $(WasmProfilers) - Profilers to use - $(AOTProfilePath) - profile data file to be used for profile-guided optimization - - $(InvariantGlobalization) - Whenever to disable ICU. Defaults to false. - - $(InvariantTimezone) - Whenever to disable Timezone database. Defaults to false. - - $(HybridGlobalization) - Whenever to enable reduced ICU + native platform functions. Defaults to false and can be set only for InvariantGlobalization=false, WasmIncludeFullIcuData=false and empty WasmIcuDataFileName. + - $(InvariantGlobalization) - Whether to disable ICU. Defaults to false. + - $(InvariantTimezone) - Whether to disable Timezone database. Defaults to false. + - $(HybridGlobalization) - Whether to enable reduced ICU + native platform functions. Defaults to false and can be set only for InvariantGlobalization=false, WasmIncludeFullIcuData=false and empty WasmIcuDataFileName. - $(WasmResolveAssembliesBeforeBuild) - Resolve the assembly dependencies. Defaults to false - $(WasmAssemblySearchPaths) - used for resolving assembly dependencies From 30fc1790860d8bd68b38d75740c98820991edac6 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 29 Jun 2023 19:07:19 +0200 Subject: [PATCH 7/7] whitespace --- docs/design/features/timezone-invariant-mode.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/features/timezone-invariant-mode.md b/docs/design/features/timezone-invariant-mode.md index f7be1b06e7f7eb..4fc3069602d1df 100644 --- a/docs/design/features/timezone-invariant-mode.md +++ b/docs/design/features/timezone-invariant-mode.md @@ -2,7 +2,7 @@ Author: [Pavel Savara](https://github.com/pavelsavara) -It's currently only available for Browser OS. +It's currently only available for Browser OS. The timezone database is not part of the browser environment (as opposed to other operating systems). Therefore dotnet bundles the timezone database as binary as part of the runtime. That makes download size larger and application startup slower.