Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support loading ICU data from managed Interop #49406

Merged
merged 5 commits into from
Mar 13, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/libraries/Common/src/Interop/Interop.ICU.iOS.cs
Original file line number Diff line number Diff line change
@@ -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);
steveisok marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,45 +89,50 @@ 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);
fprintf(stderr, "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) {
fprintf(stderr, "Unable to determine size of the dat file");
return ret;
steveisok marked this conversation as resolved.
Show resolved Hide resolved
}

long bufsize = ftell (fp);
long bufsize = ftell(fp);

if (bufsize == -1) {
fprintf (stderr, "Unable to determine size of the ICU dat file.");
fprintf(stderr, "Unable to determine size of the ICU dat file.");
return ret;
steveisok marked this conversation as resolved.
Show resolved Hide resolved
}

icu_data = malloc (sizeof (char) * (bufsize + 1));
icu_data = malloc(sizeof(char) * (bufsize + 1));
steveisok marked this conversation as resolved.
Show resolved Hide resolved

if (fseek (fp, 0L, SEEK_SET) != 0) {
fprintf (stderr, "Unable to seek ICU dat file.");
if (fseek(fp, 0L, SEEK_SET) != 0) {
fprintf(stderr, "Unable to seek ICU dat file.");
return ret;
steveisok marked this conversation as resolved.
Show resolved Hide resolved
}

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 ) {
fprintf(stderr, "Unable to read ICU dat file");
return ret;
steveisok marked this conversation as resolved.
Show resolved Hide resolved
}

fclose (fp);
fclose(fp);

return load_icu_data (icu_data);
if (load_icu_data(icu_data) == 0) {
fprintf(stderr, "ICU BAD EXIT %d.", ret);
Copy link
Member

@tarekgh tarekgh Mar 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fprintf [](start = 8, length = 7)

should we do log_icu_error instead in all places writing to the stderr?

return ret;
}

return GlobalizationNative_LoadICU();
}

const char* GlobalizationNative_GetICUDTName(const char* culture)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,9 @@
<Compile Include="$(CommonPath)Interop\Interop.ICU.cs">
<Link>Common\Interop\Interop.ICU.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Interop.ICU.iOS.cs" Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'">
<Link>Common\Interop\Interop.ICU.iOS.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Interop.Idna.cs">
<Link>Common\Interop\Interop.Idna.cs</Link>
</Compile>
Expand Down Expand Up @@ -1838,6 +1841,8 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GlobalizationMode.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GlobalizationMode.LoadICU.Unix.cs" Condition="'$(TargetsMacCatalyst)' != 'true' and '$(TargetsiOS)' != 'true' and '$(TargetstvOS)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GlobalizationMode.LoadICU.iOS.cs" Condition="'$(TargetsMacCatalyst)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'" />
steveisok marked this conversation as resolved.
Show resolved Hide resolved
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamHelpers.Unix.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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()
{
return Interop.Globalization.LoadICU();
}
steveisok marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/tasks/AppleAppBuilder/AppleAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
54 changes: 25 additions & 29 deletions src/tasks/AppleAppBuilder/Templates/runtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand All @@ -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];
Expand All @@ -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",
safern marked this conversation as resolved.
Show resolved Hide resolved
#ifndef INVARIANT_GLOBALIZATION
safern marked this conversation as resolved.
Show resolved Hide resolved
"ICU_DAT_FILE_PATH",
#endif
"APP_CONTEXT_BASE_DIRECTORY"
};
const char *appctx_values [] = {
APPLE_RUNTIME_IDENTIFIER,
#ifndef INVARIANT_GLOBALIZATION
icu_dat_path,
#endif
bundle
};

monovm_initialize (sizeof (appctx_keys) / sizeof (appctx_keys [0]), appctx_keys, appctx_values);

#if FORCE_INTERPRETER
os_log_info (OS_LOG_DEFAULT, "INTERP Enabled");
Expand Down Expand Up @@ -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);

Expand Down
6 changes: 5 additions & 1 deletion src/tasks/AppleAppBuilder/Xcode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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; }
Expand Down Expand Up @@ -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);
Expand Down