Skip to content

[mono] Initial static ICU implementation for wasm #38057

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stdlib.h>
#include "pal_icushim_internal.h"

#if !defined(STATIC_ICU)
#if defined(TARGET_UNIX)
#include <dlfcn.h>
#elif defined(TARGET_WINDOWS)
Expand Down Expand Up @@ -482,3 +483,34 @@ int32_t GlobalizationNative_GetICUVersion()

return (versionInfo[0] << 24) + (versionInfo[1] << 16) + (versionInfo[2] << 8) + versionInfo[3];
}

#else // !defined(STATIC_ICU)

#include <unicode/putil.h>
#include <unicode/uversion.h>

int32_t GlobalizationNative_LoadICU(void)
{
const char* icudir = getenv("DOTNET_ICU_DIR");
if (!icudir)
return 0;

// path to a directory with icudt___.dat (e.g. icudt67l.dat)
// we can also use `udata_setCommonData(const void *data, UErrorCode *err)` API here
u_setDataDirectory(icudir);
return 1;
}

void GlobalizationNative_InitICUFunctions(void* icuuc, void* icuin, const char* version, const char* suffix)
{
// no-op for static
}

int32_t GlobalizationNative_GetICUVersion(void)
{
UVersionInfo versionInfo;
u_getVersion(versionInfo);

return (versionInfo[0] << 24) + (versionInfo[1] << 16) + (versionInfo[2] << 8) + versionInfo[3];
}
#endif // defined(STATIC_ICU)
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@

#include "pal_compiler.h"

#if !defined(STATIC_ICU)
// List of all functions from the ICU libraries that are used in the System.Globalization.Native.so
#define FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
PER_FUNCTION_BLOCK(u_charsToUChars, libicuuc) \
Expand Down Expand Up @@ -280,3 +281,4 @@ FOR_ALL_ICU_FUNCTIONS
#define usearch_getMatchedLength(...) usearch_getMatchedLength_ptr(__VA_ARGS__)
#define usearch_last(...) usearch_last_ptr(__VA_ARGS__)
#define usearch_openFromCollator(...) usearch_openFromCollator_ptr(__VA_ARGS__)
#endif // !defined(STATIC_ICU)
3 changes: 3 additions & 0 deletions src/mono/cmake/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@
/* Use static zlib */
#cmakedefine HAVE_STATIC_ZLIB 1

/* Use static ICU */
#cmakedefine STATIC_ICU 1

/* Use OS-provided zlib */
#cmakedefine HAVE_SYS_ZLIB 1

Expand Down
12 changes: 11 additions & 1 deletion src/mono/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,12 @@ AC_ARG_WITH(spectre-mitigation, [ --with-spectre-mitigation=yes,no
AC_ARG_WITH(spectre-indirect-branch-choice, [ --with-spectre-indirect-branch-choice=keep,thunk,inline,extern Convert indirect branches to the specified kind of thunk (defaults to inline)], [], [with_spectre_indirect_branch_choice=inline])
AC_ARG_WITH(spectre-function-return-choice, [ --with-spectre-function-return-choice=keep,thunk,inline,extern Convert function return instructions to the specified kind of thunk (defaults to inline)], [], [with_spectre_function_return_choice=inline])

AC_ARG_WITH(static_icu, [ --with-static-icu=yes|no Integrate ICU statically into the runtime (defaults to no)],[
if test x$with_static_icu = xyes ; then
AC_DEFINE(STATIC_ICU,1,[Integrate ICU statically into the runtime.])
fi
], [with_static_icu=no])

dnl
dnl Spectre compiler mitigation flag checks
dnl
Expand Down Expand Up @@ -1696,6 +1702,7 @@ AM_CONDITIONAL(INSTALL_MONOTOUCH, [test "x$with_monotouch" != "xno"])
AM_CONDITIONAL(INSTALL_MONOTOUCH_WATCH, [test "x$with_monotouch_watch" != "xno"])
AM_CONDITIONAL(INSTALL_MONOTOUCH_TV, [test "x$with_monotouch_tv" != "xno"])
AM_CONDITIONAL(BITCODE, test "x$with_bitcode" = "xyes")
AM_CONDITIONAL(STATIC_ICU, test "x$with_static_icu" = "xyes")
AM_CONDITIONAL(INSTALL_XAMMAC, [test "x$with_xammac" != "xno"])
AM_CONDITIONAL(INSTALL_TESTING_AOT_FULL_INTERP, [test "x$with_testing_aot_full_interp" != "xno"])
AM_CONDITIONAL(INSTALL_TESTING_AOT_HYBRID, [test "x$with_testing_aot_hybrid" != "xno"])
Expand Down Expand Up @@ -6836,7 +6843,10 @@ if test x$with_core = xonly; then
fi
if test x$have_shim_globalization = xyes || test x$cross_compiling = xyes; then
ICU_SHIM_PATH=../../../libraries/Native/Unix/System.Globalization.Native
if test x$target_osx = xyes; then
if test x$target_wasm = xyes && test x$with_static_icu = xyes; then
ICU_CFLAGS="-DTARGET_UNIX -DU_DISABLE_RENAMING"
have_sys_icu=yes
elif test x$target_osx = xyes; then
ORIG_CPPFLAGS=$CPPFLAGS
# adding icu path to pkg_config_path
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono.proj
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@
<_MonoConfigureParams Include="--disable-icall-tables"/>
<_MonoConfigureParams Include="--disable-crash-reporting"/>
<_MonoConfigureParams Include="--with-bitcode=yes"/>
<_MonoConfigureParams Condition="'$(ICU_REPO)' != ''" Include="--with-static-icu=yes"/>
<_MonoConfigureParams Include="--enable-minimal=ssa,com,jit,reflection_emit_save,portability,assembly_remapping,attach,verifier,full_messages,appdomains,shadowcopy,security,sgen_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,logging,remoting,shared_perfcounters,sgen_debug_helpers,soft_debug,interpreter,assert_messages,cleanup,mdb,gac,threads,$(_MonoEnableMinimal)"/>
<_MonoCFLAGS Include="-fexceptions" />
<_MonoCXXFLAGS Include="-fexceptions -s DISABLE_EXCEPTION_CATCHING=0" />
Expand Down
7 changes: 7 additions & 0 deletions src/mono/mono/metadata/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ nodist_libmonoruntime_shimglobalization_la_SOURCES = \
@ICU_SHIM_PATH@/entrypoints.c

libmonoruntime_shimglobalization_la_CFLAGS = @ICU_CFLAGS@ -I$(top_srcdir)/../libraries/Native/Unix/System.Globalization.Native/ -I$(top_srcdir)/../libraries/Native/Unix/Common/

if STATIC_ICU
libmonoruntime_shimglobalization_la_CFLAGS += -I$(ICU_REPO)/icu4c/source/wasm-usr/include/ \
-L$(ICU_REPO)/icu4c/source/wasm-build/lib/ -licui18n -licuuc -licutu -licuio \
-L$(ICU_REPO)/icu4c/source/wasm-build/stubdata -licudata
endif

endif
endif

Expand Down
11 changes: 11 additions & 0 deletions src/mono/wasm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ MONO_LIBS = \
$(MONO_BIN_DIR)/libmono-icall-table.a \
${SYS_NATIVE_DIR}/libSystem.Native.a

ifeq ($(ICU_REPO),)
@echo "ICU_REPO is not set."
else
MONO_LIBS := $(MONO_LIBS) \
$(ICU_REPO)/icu4c/source/wasm-build/lib/libicui18n.a \
$(ICU_REPO)/icu4c/source/wasm-build/lib/libicuio.a \
$(ICU_REPO)/icu4c/source/wasm-build/lib/libicuuc.a \
$(ICU_REPO)/icu4c/source/wasm-build/lib/libicutu.a \
$(ICU_REPO)/icu4c/source/wasm-build/stubdata/libicudata.a
endif

EMCC_FLAGS=--profiling-funcs -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s ALIASING_FUNCTION_POINTERS=0 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'FS_createPath', 'FS_createDataFile', 'cwrap', 'setValue', 'getValue', 'UTF8ToString', 'addFunction']" -s "EXPORTED_FUNCTIONS=['_putchar']" --source-map-base http://example.com -s WASM_OBJECT_FILES=0 -s FORCE_FILESYSTEM=1 -s USE_ZLIB=1
EMCC_DEBUG_FLAGS =-g -Os -s ASSERTIONS=1 -DENABLE_NETCORE=1 -DDEBUG=1
EMCC_RELEASE_FLAGS=-Oz --llvm-opts 2 --llvm-lto 1 -DENABLE_NETCORE=1
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/runtime/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ mono_wasm_load_runtime (const char *managed_path, int enable_debugging)
monoeg_g_setenv ("COMPlus_DebugWriteToStdErr", "1", 0);
#endif
#ifdef ENABLE_NETCORE
monoeg_g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", 0);
monoeg_g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", getenv("DOTNET_ICU_DIR") ? "0" : "1", 0);
#endif

mini_parse_debug_option ("top-runtime-invoke-unhandled");
Expand Down
1 change: 1 addition & 0 deletions src/mono/wasm/wasm.targets
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

<ItemGroup>
<WasmPInvokeModules Include="libSystem.Native"/>
<WasmPInvokeModules Include="QCall"/>
<WasmPInvokeAssemblies Include="$(MonoArtifactsPath)\System.Private.CoreLib.dll"/>
<WasmPInvokeAssemblies Include="$(ArtifactsBinDir)\System.Runtime\$(NetCoreAppCurrent)-$(Configuration)\System.Runtime.dll"/>
<WasmPInvokeAssemblies Include="$(ArtifactsBinDir)\System.Console\$(NetCoreAppCurrent)-Browser-$(Configuration)\System.Console.dll"/>
Expand Down