Skip to content

charlock_holmes 0.7.9 fails to build against ICU 77: ICU headers require C++17 but extension compiles with older standard #203

@nielsonrolim

Description

@nielsonrolim

Summary

Building charlock_holmes 0.7.9 fails on systems with ICU 77+ because the native extension is compiled without an explicit C++ standard, and modern ICU headers now require C++17 features (std::u16string_view, std::enable_if_t, std::is_same_v, auto non-type template parameters, etc.).

Environment

  • OS: Fedora 44
  • Compiler: GCC 15
  • ICU: 77.1 (system libicu-devel)
  • Ruby: 4.0.3
  • charlock_holmes: 0.7.9
  • Bundler: 2.7.2

The same issue is reproducible on any distro that has shipped libicu 76+ where the compiler / Ruby CXXFLAGS does not already default to -std=c++17 or newer.

Steps to reproduce

gem install charlock_holmes -v 0.7.9

Actual behavior

Compilation of transliterator.cpp fails with hundreds of errors originating in ICU's own headers, e.g.:

/usr/include/unicode/char16ptr.h:271:38: error: 'enable_if_t' in namespace 'std' does not name a template type
  271 | template<typename T, typename = std::enable_if_t<std::is_same_v<T, UChar>>>
/usr/include/unicode/char16ptr.h:271:33: note: 'std::enable_if_t' is only available from C++14 onwards

/usr/include/unicode/unistr.h:3035:19: error: expected type-specifier
 3035 |   inline operator std::u16string_view() const {

/usr/include/unicode/localpointer.h:561:26: error: parameter declared 'auto'
  561 | template <typename Type, auto closeFunction>

Full failure mode is make exiting with Error 1 while compiling transliterator.o.

Root cause

ICU 76 (Oct 2024) and especially ICU 77 (Mar 2025) updated their public headers to use C++17 features as part of their normal API surface — std::u16string_view, std::enable_if_t, std::is_same_v, and auto non-type template parameters. ICU's own build documentation now states it requires a C++17-capable compiler.

charlock_holmes's extconf.rb does not set -std=c++17 (or newer) in $CXXFLAGS. Because Ruby's mkmf-generated Makefile typically inherits whatever RbConfig::CONFIG['CXXFLAGS'] was set to at Ruby build time, the compiler often ends up using C++11 (or no explicit standard at all), which then can't parse the modern ICU headers.

Workaround

Setting the C++ standard explicitly via Bundler works:

bundle config build.charlock_holmes --with-cxxflags=-std=c++17
gem uninstall charlock_holmes -v 0.7.9 -I
bundle install

Or directly via gem:

gem install charlock_holmes -v 0.7.9 -- --with-cxxflags=-std=c++17

Suggested fix

Append -std=c++17 to $CXXFLAGS in ext/charlock_holmes/extconf.rb, ideally guarded so it only applies when the compiler is GCC/Clang. Something like:

$CXXFLAGS << " -std=c++17" if RbConfig::CONFIG["CXX"] =~ /g\+\+|clang\+\+/

This matches what other gems wrapping modern C++ libraries have already done.

Happy to send a PR if that approach sounds right.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions