Compile ICU Converter Aliases with gencnval

gencnval turns ICU's convrtrs.txt alias table into the binary cnvalias.icu file your programs load. This walkthrough checks the result was actually written, and keeps it well away from your system's ICU install. Give it about fifteen minutes; you need ICU 74.2's development tools and a readable ICU source tree containing the mapping file.

This covers the command installed here as package icu-devtools version 74.2-1ubuntu3.1; the installed manual identifies the utility as ICU 74.2. Running a different ICU version? Use that version's own source data and check its own help output before putting the command anywhere near a build.

1. Check the installed utility

Start with read-only checks. None of these need elevated privileges:

$ command -v gencnval
/usr/bin/gencnval
$ dpkg-query -W -f='${Package} ${Version}\n' icu-devtools
icu-devtools 74.2-1ubuntu3.1
$ gencnval --help
usage: gencnval [-options] [convrtrs.txt]
    read convrtrs.txt and create icudt74l_cnvalias.icu

The help output here also lists -q or --quiet. The local manual documents the core options -h, -v, -c, -s and -d, so stick to those documented ones in portable scripts. Do not treat --help as a version query either: this program reports an unknown --version flag as an error.

2. Locate the source alias table

The input is normally icu4c/source/data/mappings/convrtrs.txt inside the ICU source tree, and the development tools package does not normally install it for you. Confirm the file, and keep the source directory path separate from the filename:

$ ICU_SOURCE=/path/to/icu4c
$ test -r "$ICU_SOURCE/source/data/mappings/convrtrs.txt" && echo 'source file is readable'
source file is readable
$ printf '%s\n' "$ICU_SOURCE/source/data/mappings/convrtrs.txt"
/path/to/icu4c/source/data/mappings/convrtrs.txt

Use the convrtrs.txt that belongs to the ICU version you are building. It is an alias table, not a converter implementation: a table-level set of tags followed by converter names and aliases, with comments starting at #. Do not swap in some random encoding list, or edit the system's generated data in place.

3. Build into a disposable destination

Pick a new output directory first. This is an ordinary command that changes only that directory, so it needs no sudo:

$ BUILD_DIR=$(mktemp -d /tmp/gencnval-build.XXXXXX)
$ mkdir "$BUILD_DIR/output"
$ ICU_DATA=/usr/share/icu/74.2/ gencnval \
    --sourcedir "$ICU_SOURCE/source/data/mappings" \
    --destdir "$BUILD_DIR/output" \
    convrtrs.txt
$ printf 'exit status: %s\n' "$?"
exit status: 0

The source and destination options tell gencnval where to read and write. The installed manual says their defaults come from ICU_DATA, whose path here ends with a slash. Keeping both paths explicit makes the build reviewable and stops you accidentally writing into a shared ICU directory.

Checkpoint: the command should exit with status 0 and leave a file called cnvalias.icu in the destination directory on this install:

$ find "$BUILD_DIR/output" -maxdepth 1 -type f -printf '%f %s bytes\n'
cnvalias.icu 64002 bytes
$ test -s "$BUILD_DIR/output/cnvalias.icu" && echo 'generated data is non-empty'
generated data is non-empty

The exact byte count depends on the source file and build. Check the filename, non-zero size and exit status rather than baking a sample size into a test.

4. Check alias conflicts when the table changes

If you have edited a private copy of convrtrs.txt, add --verbose to review the alias table:

$ ICU_DATA=/usr/share/icu/74.2/ gencnval \
    --verbose \
    --sourcedir "$ICU_SOURCE/source/data/mappings" \
    --destdir "$BUILD_DIR/output" \
    convrtrs.txt

Verbose output can flag conflicting aliases and the converters they resolve to. Read it before trusting the generated file: a successful build does not prove a newly added alias expresses the policy you meant, only that it names a converter that actually exists in the ICU data you are packaging.

--copyright adds a copyright notice to the binary data. Include it only when your distribution's packaging rules ask for it; it changes nothing about alias resolution.

5. Hand the file to the packaging step

gencnval creates data that ICU reads directly, or that pkgdata folds into a larger archive. Keep the generated file in the build tree until the surrounding ICU build has validated it. Do not copy it over /usr/share/icu/74.2/ by hand while services or applications might be using that install.

Warning: replacing shared ICU data can change converter lookup for several programs at once. That is a deployment change, not a troubleshooting step. If your workflow genuinely requires installing it, use the normal package staging and rollback process, keep the previous file, and test dependent applications before you activate anything. A failed private build needs no undo: just remove the temporary build directory once you have inspected it, and keep it around first if you might need an audit trail, because removing it is irreversible.

6. Diagnose the common failures

An error such as unable to open input file usually means the filename was resolved somewhere below the source directory you supplied. Check both values without changing anything:

$ printf '%s\n' "$ICU_SOURCE/source/data/mappings/convrtrs.txt"
$ ls -l "$ICU_SOURCE/source/data/mappings/convrtrs.txt"
$ test -r "$ICU_SOURCE/source/data/mappings/convrtrs.txt" && echo readable

If the output directory is not writable, pick one you actually own: do not fix a path mistake with sudo. If ICU_DATA is set for a different ICU install, check it before retrying:

$ printf 'ICU_DATA=%s\n' "${ICU_DATA-}"
$ test -d /usr/share/icu/74.2/ && echo 'ICU 74.2 data directory exists'

The trailing slash matters for some ICU tools, so keep it when setting ICU_DATA. If verbose mode flags an alias conflict, fix the private source table and regenerate: do not silence the warning and ship the result blind.

Done means