summaryrefslogtreecommitdiff
path: root/src/corefx/System.Globalization.Native/icushim.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corefx/System.Globalization.Native/icushim.cpp')
-rw-r--r--src/corefx/System.Globalization.Native/icushim.cpp93
1 files changed, 76 insertions, 17 deletions
diff --git a/src/corefx/System.Globalization.Native/icushim.cpp b/src/corefx/System.Globalization.Native/icushim.cpp
index 63f111b8b1..6e7817e85f 100644
--- a/src/corefx/System.Globalization.Native/icushim.cpp
+++ b/src/corefx/System.Globalization.Native/icushim.cpp
@@ -19,6 +19,33 @@ FOR_ALL_ICU_FUNCTIONS
static void* libicuuc = nullptr;
static void* libicui18n = nullptr;
+// .x.x.x, considering the max number of decimal digits for each component
+static const int MaxICUVersionStringLength = 33;
+
+#ifdef __APPLE__
+
+bool FindICULibs(char* symbolName, char* symbolVersion)
+{
+#ifndef OSX_ICU_LIBRARY_PATH
+ static_assert(false, "The ICU Library path is not defined");
+#endif // OSX_ICU_LIBRARY_PATH
+
+ // Usually OSX_ICU_LIBRARY_PATH is "/usr/lib/libicucore.dylib"
+ libicuuc = dlopen(OSX_ICU_LIBRARY_PATH, RTLD_LAZY);
+
+ if (libicuuc == nullptr)
+ {
+ return false;
+ }
+
+ // in OSX all ICU APIs exist in the same library libicucore.A.dylib
+ libicui18n = libicuuc;
+
+ return true;
+}
+
+#else // __APPLE__
+
// Version ranges to search for each of the three version components
// The rationale for major version range is that we support versions higher or
// equal to the version we are built against and less or equal to that version
@@ -31,9 +58,6 @@ static const int MaxMinorICUVersion = 5;
static const int MinSubICUVersion = 1;
static const int MaxSubICUVersion = 5;
-// .x.x.x, considering the max number of decimal digits for each component
-static const int MaxICUVersionStringLength = 33;
-
// Get filename of an ICU library with the requested version in the name
// There are three possible cases of the version components values:
// 1. Only majorVer is not equal to -1 => result is baseFileName.majorver
@@ -111,6 +135,22 @@ bool FindLibUsingOverride(int* majorVer, int* minorVer, int* subVer)
}
// Select the highest supported version of ICU present on the local machine
+// Search for library files with names including the major version.
+bool FindLibWithMajorVersion(int* majorVer)
+{
+ for (int i = MaxICUVersion; i >= MinICUVersion; i--)
+ {
+ if (OpenICULibraries(i, -1, -1))
+ {
+ *majorVer = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Select the highest supported version of ICU present on the local machine
// Search for library files with names including the major and minor version.
bool FindLibWithMajorMinorVersion(int* majorVer, int* minorVer)
{
@@ -154,9 +194,7 @@ bool FindLibWithMajorMinorSubVersion(int* majorVer, int* minorVer, int* subVer)
return false;
}
-// This function is ran at the end of dlopen for the current shared library
-__attribute__((constructor))
-void InitializeICUShim()
+bool FindICULibs(char* symbolName, char* symbolVersion)
{
int majorVer = -1;
int minorVer = -1;
@@ -164,16 +202,13 @@ void InitializeICUShim()
if (!FindLibUsingOverride(&majorVer, &minorVer, &subVer) &&
!FindLibWithMajorMinorVersion(&majorVer, &minorVer) &&
- !FindLibWithMajorMinorSubVersion(&majorVer, &minorVer, &subVer))
+ !FindLibWithMajorMinorSubVersion(&majorVer, &minorVer, &subVer) &&
+ // This is a fallback for the rare case when there are only lib files with major version
+ !FindLibWithMajorVersion(&majorVer))
{
// No usable ICU version found
- fprintf(stderr, "No usable version of the ICU libraries was found\n");
- abort();
+ return false;
}
-
- char symbolName[128];
- char symbolVersion[MaxICUVersionStringLength + 1] = "";
-
// Find out the format of the version string added to each symbol
// First try just the unversioned symbol
if (dlsym(libicuuc, "u_strlen") == nullptr)
@@ -181,25 +216,42 @@ void InitializeICUShim()
// Now try just the _majorVer added
sprintf(symbolVersion, "_%d", majorVer);
sprintf(symbolName, "u_strlen%s", symbolVersion);
- if (dlsym(libicuuc, symbolName) == nullptr)
+ if ((dlsym(libicuuc, symbolName) == nullptr) && (minorVer != -1))
{
// Now try the _majorVer_minorVer added
sprintf(symbolVersion, "_%d_%d", majorVer, minorVer);
sprintf(symbolName, "u_strlen%s", symbolVersion);
- if (dlsym(libicuuc, symbolName) == nullptr)
+ if ((dlsym(libicuuc, symbolName) == nullptr) && (subVer != -1))
{
// Finally, try the _majorVer_minorVer_subVer added
sprintf(symbolVersion, "_%d_%d_%d", majorVer, minorVer, subVer);
sprintf(symbolName, "u_strlen%s", symbolVersion);
if (dlsym(libicuuc, symbolName) == nullptr)
{
- fprintf(stderr, "ICU libraries use unknown symbol versioning\n");
- abort();
+ return false;
}
}
}
}
+ return true;
+
+}
+
+#endif // __APPLE__
+
+// GlobalizationNative_LoadICU
+// This method get called from the managed side during the globalization initialization.
+// This method shouldn't get called at all if we are running in globalization invariant mode
+// return 0 if failed to load ICU and 1 otherwise
+extern "C" int32_t GlobalizationNative_LoadICU()
+{
+ char symbolName[128];
+ char symbolVersion[MaxICUVersionStringLength + 1] = "";
+
+ if (!FindICULibs(symbolName, symbolVersion))
+ return 0;
+
// Get pointers to all the ICU functions that are needed
#define PER_FUNCTION_BLOCK(fn, lib) \
static_assert((sizeof(#fn) + MaxICUVersionStringLength + 1) <= sizeof(symbolName), "The symbolName is too small for symbol " #fn); \
@@ -209,6 +261,13 @@ void InitializeICUShim()
FOR_ALL_ICU_FUNCTIONS
#undef PER_FUNCTION_BLOCK
+
+#ifdef __APPLE__
+ // libicui18n initialized with libicuuc so we null it to avoid double closing same handle
+ libicui18n = nullptr;
+#endif // __APPLE__
+
+ return 1;
}
__attribute__((destructor))