Skip to content

Commit af4bb8b

Browse files
authored
Change compile time dependency of ICU API ucol_setMaxVariable to be runtime instead. (#58485)
* Change compile time dependency of ICU API ucol_setMaxVariable to be runtime instead. * Fix Android Build Break
1 parent 1dd8a59 commit af4bb8b

3 files changed

Lines changed: 63 additions & 15 deletions

File tree

src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,25 @@ static UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t o
365365
{
366366
ucol_setAttribute(pClonedCollator, UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, pErr);
367367

368+
#if !defined(STATIC_ICU)
369+
if (ucol_setMaxVariable_ptr != NULL)
370+
{
371+
// by default, ICU alternate shifted handling only ignores punctuation, but
372+
// IgnoreSymbols needs symbols and currency as well, so change the "variable top"
373+
// to include all symbols and currency
374+
ucol_setMaxVariable(pClonedCollator, UCOL_REORDER_CODE_CURRENCY, pErr);
375+
}
376+
else
377+
{
378+
assert(ucol_setVariableTop_ptr != NULL);
379+
// 0xfdfc is the last currency character before the first digit character
380+
// in http://source.icu-project.org/repos/icu/icu/tags/release-52-1/source/data/unidata/FractionalUCA.txt
381+
const UChar ignoreSymbolsVariableTop[] = { 0xfdfc };
382+
ucol_setVariableTop_ptr(pClonedCollator, ignoreSymbolsVariableTop, 1, pErr);
383+
}
384+
385+
#else // !defined(STATIC_ICU)
386+
368387
// by default, ICU alternate shifted handling only ignores punctuation, but
369388
// IgnoreSymbols needs symbols and currency as well, so change the "variable top"
370389
// to include all symbols and currency
@@ -376,6 +395,8 @@ static UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t o
376395
const UChar ignoreSymbolsVariableTop[] = { 0xfdfc };
377396
ucol_setVariableTop(pClonedCollator, ignoreSymbolsVariableTop, 1, pErr);
378397
#endif
398+
399+
#endif //!defined(STATIC_ICU)
379400
}
380401

381402
ucol_setAttribute(pClonedCollator, UCOL_STRENGTH, strength, pErr);

src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ FOR_ALL_ICU_FUNCTIONS
3838

3939
static void* libicuuc = NULL;
4040
static void* libicui18n = NULL;
41+
ucol_setVariableTop_func ucol_setVariableTop_ptr = NULL;
4142

4243
#if defined (TARGET_UNIX)
4344

@@ -380,6 +381,34 @@ static void ValidateICUDataCanLoad()
380381
}
381382
}
382383

384+
static void InitializeVariableMaxAndTopPointers(char* symbolVersion)
385+
{
386+
if (ucol_setMaxVariable_ptr != NULL)
387+
{
388+
return;
389+
}
390+
391+
#if defined(TARGET_OSX) || defined(TARGET_ANDROID)
392+
// OSX and Android always run against ICU version which has ucol_setMaxVariable.
393+
// We shouldn't come here.
394+
assert(false);
395+
#elif defined(TARGET_WINDOWS)
396+
char symbolName[SYMBOL_NAME_SIZE];
397+
sprintf_s(symbolName, SYMBOL_NAME_SIZE, "ucol_setVariableTop%s", symbolVersion);
398+
ucol_setVariableTop_ptr = (ucol_setVariableTop_func)GetProcAddress((HMODULE)libicui18n, symbolName);
399+
#else
400+
char symbolName[SYMBOL_NAME_SIZE];
401+
sprintf(symbolName, "ucol_setVariableTop%s", symbolVersion);
402+
ucol_setVariableTop_ptr = (ucol_setVariableTop_func)dlsym(libicui18n, symbolName);
403+
#endif // defined(TARGET_OSX) || defined(TARGET_ANDROID)
404+
405+
if (ucol_setVariableTop_ptr == NULL)
406+
{
407+
fprintf(stderr, "Cannot get the symbols of ICU APIs ucol_setMaxVariable or ucol_setVariableTop.\n");
408+
abort();
409+
}
410+
}
411+
383412
// GlobalizationNative_LoadICU
384413
// This method get called from the managed side during the globalization initialization.
385414
// This method shouldn't get called at all if we are running in globalization invariant mode
@@ -413,6 +442,9 @@ int32_t GlobalizationNative_LoadICU()
413442

414443
FOR_ALL_ICU_FUNCTIONS
415444
ValidateICUDataCanLoad();
445+
446+
InitializeVariableMaxAndTopPointers(symbolVersion);
447+
416448
return true;
417449
}
418450

@@ -466,6 +498,8 @@ void GlobalizationNative_InitICUFunctions(void* icuuc, void* icuin, const char*
466498

467499
FOR_ALL_ICU_FUNCTIONS
468500
ValidateICUDataCanLoad();
501+
502+
InitializeVariableMaxAndTopPointers(symbolVersion);
469503
}
470504

471505
#undef PER_FUNCTION_BLOCK

src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal.h

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,17 @@
5353
#include "pal_compiler.h"
5454

5555
#if !defined(STATIC_ICU)
56+
// ucol_setVariableTop is a deprecated function on the newer ICU versions and ucol_setMaxVariable should be used instead.
57+
// As can run against ICU versions which not supported ucol_setMaxVariable, we'll dynamically try to get the pointer to ucol_setVariableTop
58+
// when we couldn't get a pointer to ucol_setMaxVariable.
59+
typedef uint32_t (*ucol_setVariableTop_func)(UCollator* coll, const UChar* varTop, int32_t len, UErrorCode* status);
60+
extern ucol_setVariableTop_func ucol_setVariableTop_ptr;
5661

5762
#if !defined(TARGET_ANDROID)
5863
// (U_ICU_VERSION_MAJOR_NUM < 52)
5964
// The following APIs are not supported in the ICU versions less than 52. We need to define them manually.
6065
// We have to do runtime check before using the pointers to these APIs. That is why these are listed in the FOR_ALL_OPTIONAL_ICU_FUNCTIONS list.
66+
U_CAPI void U_EXPORT2 ucol_setMaxVariable(UCollator* coll, UColReorderCode group, UErrorCode* pErrorCode);
6167
U_CAPI int32_t U_EXPORT2 ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status);
6268
U_CAPI int32_t U_EXPORT2 ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status);
6369
#endif
@@ -164,15 +170,6 @@ U_CAPI int32_t U_EXPORT2 ucal_getWindowsTimeZoneID(const UChar* id, int32_t len,
164170
PER_FUNCTION_BLOCK(usearch_setPattern, libicui18n, true) \
165171
PER_FUNCTION_BLOCK(usearch_setText, libicui18n, true)
166172

167-
#if HAVE_SET_MAX_VARIABLE
168-
#define FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \
169-
PER_FUNCTION_BLOCK(ucol_setMaxVariable, libicui18n, true)
170-
#else
171-
172-
#define FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \
173-
PER_FUNCTION_BLOCK(ucol_setVariableTop, libicui18n, true)
174-
#endif
175-
176173
#if defined(TARGET_WINDOWS)
177174
#define FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS \
178175
PER_FUNCTION_BLOCK(ucurr_forLocale, libicuuc, true) \
@@ -195,11 +192,11 @@ U_CAPI int32_t U_EXPORT2 ucal_getWindowsTimeZoneID(const UChar* id, int32_t len,
195192
// Otherwise, we'll just not provide the functionality to users which needed these APIs.
196193
#define FOR_ALL_OPTIONAL_ICU_FUNCTIONS \
197194
PER_FUNCTION_BLOCK(ucal_getWindowsTimeZoneID, libicui18n, false) \
198-
PER_FUNCTION_BLOCK(ucal_getTimeZoneIDForWindowsID, libicui18n, false)
195+
PER_FUNCTION_BLOCK(ucal_getTimeZoneIDForWindowsID, libicui18n, false) \
196+
PER_FUNCTION_BLOCK(ucol_setMaxVariable, libicui18n, false)
199197

200198
#define FOR_ALL_ICU_FUNCTIONS \
201199
FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
202-
FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \
203200
FOR_ALL_OPTIONAL_ICU_FUNCTIONS \
204201
FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS
205202

@@ -249,11 +246,7 @@ FOR_ALL_ICU_FUNCTIONS
249246
#define ucol_openRules(...) ucol_openRules_ptr(__VA_ARGS__)
250247
#define ucol_safeClone(...) ucol_safeClone_ptr(__VA_ARGS__)
251248
#define ucol_setAttribute(...) ucol_setAttribute_ptr(__VA_ARGS__)
252-
#if HAVE_SET_MAX_VARIABLE
253249
#define ucol_setMaxVariable(...) ucol_setMaxVariable_ptr(__VA_ARGS__)
254-
#else
255-
#define ucol_setVariableTop(...) ucol_setVariableTop_ptr(__VA_ARGS__)
256-
#endif
257250
#define ucol_strcoll(...) ucol_strcoll_ptr(__VA_ARGS__)
258251
#define ucurr_forLocale(...) ucurr_forLocale_ptr(__VA_ARGS__)
259252
#define ucurr_getName(...) ucurr_getName_ptr(__VA_ARGS__)

0 commit comments

Comments
 (0)