Set up ICU for C++ in Xcode

Kevin Li
3 min readMay 1, 2023

Since there’s a lack of support for Unicode string operations in C++, the International Components for Unicode (ICU) is almost a must-have for any C++ applications that need to deal with Unicode. For users of Xcode, however, there’s no existing guide on how to set up ICU for C++ using in the editor. After much struggle, I figured out a way. Below are the detailed steps to set up ICU for C++ in Xcode.

1. Create a new Xcode project

(Skip if you already have a C++ project) We will create a sample C++ console app in Xcode.

  1. After opening Xcode, Click on “Create a new Xcode project” in the welcome popup.
  2. On the top bar, select “macOS”
  3. Under “Application” select “Command Line Tool”, click “Next”
  4. Give your project a “Product Name”
  5. Under the “Language” dropdown, select “C++”, click “Next”

2. Build ICU with icu4c-iosx

  1. Open a Terminal and cd into the project directory
  2. Clone the icu4c-iosx repository which contains setup script for building ICU for iOS, macOS (Intel & Apple Silicon), and Catalyst
git clone --recursive https://github.com/apotocki/icu4c-iosx

3. cd into the cloned repo and call build.sh to build ICU. It takes more than 10 minutes on my M1 macBook Pro so be patient.

cd icu4c-iosx
scripts/build.sh

3. Configure library path in Xcode

  1. Click on the project name in the left panel to open project settings
  2. On the top bar, select “Build Settings”
  3. In the filter search bar, type in “search paths”

a. Under “Search Paths”, set the “Header Search Paths” to be:

$(PROJECT_DIR)/icu4c-iosx/product/include

b. Under “Search Paths”, set the “Library Search Paths” to be:

$(PROJECT_DIR)/icu4c-iosx/product/lib

6. In the filter search bar, type in “Other Linker Flags”.

Under “Linking”, set the “Other Linker Flags” to be:

-licuuc -licudata -licuio -licui18n

ICU is a collection of C++ libraries for all kinds of Unicode processing needs. Your project doesn’t necessarily need all the ICU libraries. Here’s a summary of what each library does:

  • licuuc This is the ICU "base" library that provides core Unicode functionality, such as string manipulation, character set conversion, collation (sorting), and formatting of numbers, dates, and times. This library is typically required by all ICU applications.
  • licui18n: This library provides more advanced i18n features, such as text boundary analysis (word, line, and sentence breaking), transliteration (converting between scripts or writing systems), locale-specific formatting and parsing of numbers, dates, and times, and support for locale-specific calendars, time zones, and currency symbols.
  • licudata: This library contains the ICU data files that define the behavior of the ICU libraries for different locales and languages. This includes things like the collation rules, date and time formats, and currency symbols used in each locale. Applications that use ICU must ensure that the appropriate ICU data files are available at runtime.
  • licutu: This library provides various utility functions and classes for working with Unicode text, including string normalization (converting to a standard form), case mapping (converting between uppercase and lowercase), and Unicode code point iteration.
  • licuio: This library provides input and output functions for Unicode text streams, including file I/O, memory-mapped files, and conversion between different character encodings.
  • licutest: This library provides a framework for writing and running unit tests for ICU applications.

Note that the above list is not exhaustive and there may be additional ICU libraries or variations depending on the version of ICU and the platform or environment being used.

4. Test out ICU support

Replace the given main.cpp with the following script:

#include <iostream>
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/regex.h>

using namespace std;
using namespace icu;

int main() {
// Create a UnicodeString and print it out
UnicodeString hello("Hello, world!");
cout << "Original string: " << hello << endl;

// Modify the string and print it out again
hello.findAndReplace("world", "ICU library");
cout << "Modified string: " << hello << endl;

// Use regular expressions to search for a pattern in the string
UErrorCode status = U_ZERO_ERROR;
RegexMatcher matcher("\\p{L}+", 0, status);
matcher.reset(hello);
while (matcher.find(status) && U_SUCCESS(status)) {
UnicodeString match = matcher.group(status);
cout << "Found word: " << match << endl;
}

return 0;
}

Run the project by clicking on the small play icon on the top of the left panel. You should see the following output in the console, if ICU support is configured correctly:

Original string: Hello, world!
Modified string: Hello, ICU library!
Found word: Hello
Found word: ICU
Found word: library
Program ended with exit code: 0

--

--

Kevin Li

❤️ Open Source, Web Dev, programming languages, and Hanzi 漢字