Repository navigation
System.Globalization.Native: configure checks ignore CMAKE_ICU_DIR's headers on Unix targets other than wasm #135571
Description
Description
When CMAKE_ICU_DIR is passed for a Unix target other than Android, Apple, Browser and WASI, the two configure checks in System.Globalization.Native/configure.cmake compile without ${CMAKE_ICU_DIR}/include. Without system ICU headers both fail, config.h gets 0 for both, and the build still succeeds. With system ICU headers installed, the checks read those instead.
The bug is latent upstream. Only eng/native.wasm.targets passes CMAKE_ICU_DIR, for wasm, and wasm takes the hard-coded branch at the top of configure.cmake. Other Unix targets hit the bug only with -cmakeargs -DCMAKE_ICU_DIR=<dir> passed by hand.
With CMAKE_ICU_DIR defined, CMakeLists.txt skips find_path(UCURR_H ...), so UCURR_H is empty here:
if (CLR_CMAKE_TARGET_UNIX)
set(CMAKE_REQUIRED_INCLUDES ${UCURR_H} ${ICU_HOMEBREW_INC_PATH})${CMAKE_ICU_DIR}/include is added only after include(configure.cmake) (CMakeLists.txt:59):
if (NOT CLR_CMAKE_TARGET_APPLE_MOBILE AND DEFINED CMAKE_ICU_DIR)
include_directories(${CMAKE_ICU_DIR}/include)Reproduction Steps
On linux-x64 with no ICU development headers installed, from the root of a clone at d148189:
(mkdir -p artifacts/icu && cd artifacts/icu \
&& curl -sSLO https://github.com/unicode-org/icu/releases/download/release-78.3/icu4c-78.3-sources.tgz \
&& tar xzf icu4c-78.3-sources.tgz && cd icu/source \
&& ./configure --prefix="$PWD/../../static" --enable-static --disable-shared --disable-tests --disable-samples \
&& make -j"$(nproc)" && make install) > icu-build.log
./build.sh libs.native -c Release -cmakeargs "-DCMAKE_ICU_DIR=$PWD/artifacts/icu/static" > native-build.log; echo "build exit code: $?"
grep HAVE_ artifacts/obj/native/net11.0-linux-Release-x64/System.Globalization.Native/config.hExpected behavior
ICU 78.3 has both UDAT_STANDALONE_SHORTER_WEEKDAYS and ucol_clone:
build exit code: 0
#define HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS 1
#define HAVE_UCOL_CLONE 1
Actual behavior
build exit code: 0
#define HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS 0
#define HAVE_UCOL_CLONE 0
artifacts/obj/native/net11.0-linux-Release-x64/CMakeFiles/CMakeConfigureLog.yaml (paths shortened):
src.c:2:22: fatal error: 'unicode/udat.h' file not found
CheckSymbolExists.c:2:10: fatal error: 'unicode/ucol.h' file not found
With HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS 0, super-short day names use the narrow ones:
#if HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS
return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context);
#else
return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context);
#endifHAVE_UCOL_CLONE is read only under STATIC_ICU, which the LOCAL_BUILD configuration of src/native/libs/build-local.sh defines:
#if HAVE_UCOL_CLONE
pClonedCollator = ucol_clone(pCollator, pErr);
#else
pClonedCollator = ucol_safeClone(pCollator, NULL, NULL, pErr);
#endif // HAVE_UCOL_CLONEConfigured that way with CMAKE_ICU_DIR added by hand, both values are 0 again, and with -DCMAKE_C_FLAGS=-Werror the build fails:
CC=clang cmake -S src/native/libs/System.Globalization.Native -B <build-dir> -DLOCAL_BUILD:STRING=1 -DCLR_CMAKE_TARGET_UNIX:STRING=1 -DCMAKE_ICU_DIR=<icu-prefix> -DCMAKE_C_FLAGS=-Werror
make -C <build-dir>pal_collation.c:340:27: error: 'ucol_safeClone_78' is deprecated [-Werror,-Wdeprecated-declarations]
Regression?
No: CMAKE_ICU_DIR first appears in CMakeLists.txt in 0fc8978 (#82393), and configure.cmake has never named it.
Known Workarounds
System ICU headers: the checks then describe that ICU, not the static one.
Configuration
Ubuntu 24.04.4 LTS, x64, clang 18.1.3, CMake 3.28.3, static ICU 78.3, without and with libicu-dev 74.2; ./build.sh libs.native -c Release. Not tried on other OSes.
Other information
Proposed fix: append ${CMAKE_ICU_DIR}/include to CMAKE_REQUIRED_INCLUDES in configure.cmake when CMAKE_ICU_DIR is defined. With it the reproduction prints both values as 1, the -Werror LOCAL_BUILD builds without warnings, and a normal build produces a byte-identical libSystem.Globalization.Native.so.
Options not taken:
- Treat
CMAKE_ICU_DIRas wasm-only: nothing in the repo says so, andCMakeLists.txt:86-88applies it to every target but Apple mobile. - Move
include_directories(${CMAKE_ICU_DIR}/include)aboveinclude(configure.cmake): CMake ignores theINCLUDE_DIRECTORIESdirectory property in these checks; onlyCMAKE_REQUIRED_INCLUDEScounts. - Set
UCURR_Hto${CMAKE_ICU_DIR}/includeinCMakeLists.txt: would also work, but gives thefind_pathresult a second meaning, away from the checks.
I have a fix ready and will open a PR for it shortly. Could this be assigned to me?
Note
AI-generated, written at my direction and reviewed by me before posting.
Measured on dotnet/runtime d148189 with the Configuration above: the reproduction block, with and without the fix; the same build with libicu-dev installed, reading the checks' compile lines in CMakeConfigureLog.yaml; the LOCAL_BUILD commands; ./build.sh libs.native -c Release with and without the fix, comparing sha256sum of the .so.
Metadata
Metadata
Assignees
Type
Projects
- StatusShow more project fieldsDone
Activity
dotnet-policy-service commentedon Oct 12, 2026
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.
dotnet-policy-service commentedon Oct 12, 2026
Tagging subscribers to this area: @dotnet/area-system-globalization
See info in area-owners.md if you want to be subscribed.
Pass CMAKE_ICU_DIR headers to System.Globalization.Native configure c…