diff --git a/src/libraries/Common/src/Interop/Interop.ICU.iOS.cs b/src/libraries/Common/src/Interop/Interop.ICU.iOS.cs new file mode 100644 index 00000000000000..8eb0ee177ab8d4 --- /dev/null +++ b/src/libraries/Common/src/Interop/Interop.ICU.iOS.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Globalization + { + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_LoadICUData")] + internal static extern int LoadICUData(string path); + } +} diff --git a/src/libraries/Native/Unix/System.Globalization.Native/entrypoints.c b/src/libraries/Native/Unix/System.Globalization.Native/entrypoints.c index 85a39085270b46..30d5bb37748ba7 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/entrypoints.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/entrypoints.c @@ -49,6 +49,9 @@ static const Entry s_globalizationNative[] = DllImportEntry(GlobalizationNative_IsPredefinedLocale) DllImportEntry(GlobalizationNative_LastIndexOf) DllImportEntry(GlobalizationNative_LoadICU) +#if defined(STATIC_ICU) + DllImportEntry(GlobalizationNative_LoadICUData) +#endif DllImportEntry(GlobalizationNative_NormalizeString) DllImportEntry(GlobalizationNative_StartsWith) DllImportEntry(GlobalizationNative_ToAscii) diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h index 5f0123d8ef5212..51e117113de1c2 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h @@ -11,7 +11,7 @@ PALEXPORT int32_t GlobalizationNative_GetICUVersion(void); #if defined(STATIC_ICU) -PALEXPORT int32_t GlobalizationNative_LoadICUData(char* path); +PALEXPORT int32_t GlobalizationNative_LoadICUData(const char* path); PALEXPORT const char* GlobalizationNative_GetICUDTName(const char* culture); diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_static.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_static.c index 49dd64df6507cb..c81ce59e50acad 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_static.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_static.c @@ -22,10 +22,19 @@ static int32_t isLoaded = 0; static int32_t isDataSet = 0; +static void log_shim_error(const char* format, ...) +{ + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + static void log_icu_error(const char* name, UErrorCode status) { const char * statusText = u_errorName(status); - fprintf(stderr, "ICU call %s failed with error #%d '%s'.\n", name, status, statusText); + log_shim_error("ICU call %s failed with error #%d '%s'.\n", name, status, statusText); } static void U_CALLCONV icu_trace_data(const void* context, int32_t fnNumber, int32_t level, const char* fmt, va_list args) @@ -89,45 +98,60 @@ static int32_t load_icu_data(void* pData) } } -int32_t GlobalizationNative_LoadICUData(char* path) +int32_t GlobalizationNative_LoadICUData(const char* path) { int32_t ret = -1; char* icu_data; - FILE *fp = fopen (path, "rb"); + FILE *fp = fopen(path, "rb"); if (fp == NULL) { - fprintf (stderr, "Unable to load ICU dat file '%s'.", path); + log_shim_error("Unable to load ICU dat file '%s'.", path); return ret; } - if (fseek (fp, 0L, SEEK_END) != 0) { - fprintf (stderr, "Unable to determine size of the dat file"); + if (fseek(fp, 0L, SEEK_END) != 0) { + fclose(fp); + log_shim_error("Unable to determine size of the dat file"); return ret; } - long bufsize = ftell (fp); + long bufsize = ftell(fp); if (bufsize == -1) { - fprintf (stderr, "Unable to determine size of the ICU dat file."); + fclose(fp); + log_shim_error("Unable to determine size of the ICU dat file."); return ret; } - icu_data = malloc (sizeof (char) * (bufsize + 1)); + icu_data = malloc(sizeof(char) * (bufsize + 1)); + + if (icu_data == NULL) { + fclose(fp); + log_shim_error("Unable to allocate enough to read the ICU dat file"); + return ret; + } - if (fseek (fp, 0L, SEEK_SET) != 0) { - fprintf (stderr, "Unable to seek ICU dat file."); + if (fseek(fp, 0L, SEEK_SET) != 0) { + fclose(fp); + log_shim_error("Unable to seek ICU dat file."); return ret; } - fread (icu_data, sizeof (char), bufsize, fp); - if (ferror ( fp ) != 0 ) { - fprintf (stderr, "Unable to read ICU dat file"); + fread(icu_data, sizeof(char), bufsize, fp); + if (ferror( fp ) != 0 ) { + fclose(fp); + log_shim_error("Unable to read ICU dat file"); return ret; } - fclose (fp); + fclose(fp); + + if (load_icu_data(icu_data) == 0) { + log_shim_error("ICU BAD EXIT %d.", ret); + return ret; + } - return load_icu_data (icu_data); + return GlobalizationNative_LoadICU(); } const char* GlobalizationNative_GetICUDTName(const char* culture) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d9900d80412cd2..6dc1e58a9d7aff 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -11,6 +11,7 @@ enable true + true true true $(MSBuildThisFileDirectory)ILLink\ @@ -1082,6 +1083,9 @@ Common\Interop\Interop.ICU.cs + + Common\Interop\Interop.ICU.iOS.cs + Common\Interop\Interop.Idna.cs @@ -1831,11 +1835,13 @@ - + + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.LoadICU.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.LoadICU.Unix.cs new file mode 100644 index 00000000000000..c91596d3dee993 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.LoadICU.Unix.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Globalization +{ + internal static partial class GlobalizationMode + { + private static int LoadICU() => Interop.Globalization.LoadICU(); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.LoadICU.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.LoadICU.iOS.cs new file mode 100644 index 00000000000000..08c5feb8ad1898 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.LoadICU.iOS.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Globalization +{ + internal static partial class GlobalizationMode + { + private static int LoadICU() + { + object? datPath = AppContext.GetData("ICU_DAT_FILE_PATH"); + return (datPath != null) ? Interop.Globalization.LoadICUData(datPath!.ToString()!) : Interop.Globalization.LoadICU(); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs index 0149463c6aa0eb..cce3ae3a870dee 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs @@ -22,7 +22,7 @@ private static bool GetGlobalizationInvariantMode() } else { - int loaded = Interop.Globalization.LoadICU(); + int loaded = LoadICU(); if (loaded == 0 && !OperatingSystem.IsBrowser()) { // This can't go into resources, because a resource lookup requires globalization, which requires ICU diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index 4f9f05d68c15a1..a2af151915179c 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -50,6 +50,7 @@ if(HAVE_SYS_ICU) if(STATIC_ICU) set(pal_icushim_sources_base pal_icushim_static.c) + add_definitions(-DSTATIC_ICU=1) else() set(pal_icushim_sources_base pal_icushim.c) diff --git a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs index fc688ba239509c..d2e04a49598f74 100644 --- a/src/tasks/AppleAppBuilder/AppleAppBuilder.cs +++ b/src/tasks/AppleAppBuilder/AppleAppBuilder.cs @@ -182,7 +182,7 @@ public override bool Execute() if (GenerateXcodeProject) { - Xcode generator = new Xcode(TargetOS); + Xcode generator = new Xcode(TargetOS, Arch); generator.EnableRuntimeLogging = EnableRuntimeLogging; XcodeProjectPath = generator.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, diff --git a/src/tasks/AppleAppBuilder/Templates/runtime.m b/src/tasks/AppleAppBuilder/Templates/runtime.m index fe2845a10ad6de..ef8bdbd4dfce5c 100644 --- a/src/tasks/AppleAppBuilder/Templates/runtime.m +++ b/src/tasks/AppleAppBuilder/Templates/runtime.m @@ -24,6 +24,8 @@ #define MONO_ENTER_GC_UNSAFE #define MONO_EXIT_GC_UNSAFE +#define APPLE_RUNTIME_IDENTIFIER "//%APPLE_RUNTIME_IDENTIFIER%" + const char * get_bundle_path (void) { @@ -203,23 +205,6 @@ //%DllMap% } -int32_t GlobalizationNative_LoadICUData(char *path); - -static int32_t load_icu_data () -{ - char path [1024]; - int res; - - const char *dname = "icudt.dat"; - const char *bundle = get_bundle_path (); - - os_log_info (OS_LOG_DEFAULT, "Loading ICU data file '%s'.", dname); - res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle, dname); - assert (res > 0); - - return GlobalizationNative_LoadICUData(path); -} - #if FORCE_INTERPRETER || FORCE_AOT || (!TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST) void mono_jit_set_aot_mode (MonoAotMode mode); void register_aot_modules (void); @@ -237,16 +222,6 @@ static int32_t load_icu_data () setenv ("MONO_LOG_MASK", "all", TRUE); #endif -#if !INVARIANT_GLOBALIZATION - int32_t ret = load_icu_data (); - - if (ret == 0) { - os_log_info (OS_LOG_DEFAULT, "ICU BAD EXIT %d.", ret); - exit (ret); - return; - } -#endif - id args_array = [[NSProcessInfo processInfo] arguments]; assert ([args_array count] <= 128); const char *managed_argv [128]; @@ -261,8 +236,29 @@ static int32_t load_icu_data () const char* bundle = get_bundle_path (); chdir (bundle); + char icu_dat_path [1024]; + int res; + + res = snprintf (icu_dat_path, sizeof (icu_dat_path) - 1, "%s/%s", bundle, "icudt.dat"); + assert (res > 0); + // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES - monovm_initialize(0, NULL, NULL); + const char *appctx_keys [] = { + "RUNTIME_IDENTIFIER", + "APP_CONTEXT_BASE_DIRECTORY", +#ifndef INVARIANT_GLOBALIZATION + "ICU_DAT_FILE_PATH" +#endif + }; + const char *appctx_values [] = { + APPLE_RUNTIME_IDENTIFIER, + bundle, +#ifndef INVARIANT_GLOBALIZATION + icu_dat_path +#endif + }; + + monovm_initialize (sizeof (appctx_keys) / sizeof (appctx_keys [0]), appctx_keys, appctx_values); #if FORCE_INTERPRETER os_log_info (OS_LOG_DEFAULT, "INTERP Enabled"); @@ -300,7 +296,7 @@ static int32_t load_icu_data () assert (assembly); os_log_info (OS_LOG_DEFAULT, "Executable: %{public}s", executable); - int res = mono_jit_exec (mono_domain_get (), assembly, argi, managed_argv); + res = mono_jit_exec (mono_domain_get (), assembly, argi, managed_argv); // Print this so apps parsing logs can detect when we exited os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); diff --git a/src/tasks/AppleAppBuilder/Xcode.cs b/src/tasks/AppleAppBuilder/Xcode.cs index 0409fb3095c9f3..0435178116c50d 100644 --- a/src/tasks/AppleAppBuilder/Xcode.cs +++ b/src/tasks/AppleAppBuilder/Xcode.cs @@ -9,10 +9,11 @@ internal class Xcode { + private string RuntimeIdentifier { get; set; } private string SysRoot { get; set; } private string Target { get; set; } - public Xcode(string target) + public Xcode(string target, string arch) { Target = target; switch (Target) @@ -27,6 +28,8 @@ public Xcode(string target) SysRoot = Utils.RunProcess("xcrun", "--sdk macosx --show-sdk-path"); break; } + + RuntimeIdentifier = $"{Target}-{arch}"; } public bool EnableRuntimeLogging { get; set; } @@ -175,6 +178,7 @@ public string GenerateXCode( File.WriteAllText(Path.Combine(binDir, "runtime.m"), Utils.GetEmbeddedResource("runtime.m") .Replace("//%DllMap%", dllMap.ToString()) + .Replace("//%APPLE_RUNTIME_IDENTIFIER%", RuntimeIdentifier) .Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib))); Utils.RunProcess("cmake", cmakeArgs.ToString(), workingDir: binDir);