diff options
Diffstat (limited to 'src/corefx/System.Globalization.Native/icushim.cpp')
-rw-r--r-- | src/corefx/System.Globalization.Native/icushim.cpp | 93 |
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)) |