Compile an ICU .ucm Converter Table with makeconv
This guide turns an ICU Unicode Codepage Mapping file, normally ending in .ucm, into the binary .cnv file that ICU can load. You will compile a real table into a separate directory, inspect the output, and understand where installation and packaging begin. The examples use ICU 74.2 as shipped by Ubuntu's icu-devtools package. Allow about 10 minutes if you already have a valid table.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
You need the makeconv executable and a source table in ICU UCM format. On this machine, both come from icu-devtools version 74.2-1ubuntu3.1. Check that before relying on behaviour from another release:
dpkg-query -W -f='${Package} ${Version}\n' icu-devtools
makeconv --version
The installed command reports tool version 6.2 even though the Debian package is version 74.2. The local manual is the authority for the documented interface: it lists -h, -?, --help, -c, -v, and -d. This guide stays with those portable options. The binary's help output also lists newer or build-specific options, but they are outside the documented contract used here.
A UCM file is input data, not a generic text file. It must contain the headers and mappings required by ICU. If you are creating one, start from a known-good ICU table and check the UCM format documentation. Do not edit a production table in place for a first attempt.
1. Put the source and output in a scratch area
Use a work directory that does not contain valuable converter files. Replace the source path with your own verified table. This example downloads no data and assumes the file is already present:
mkdir -p "$HOME/icu-converter-test/input" "$HOME/icu-converter-test/output"
cp /path/to/example.ucm "$HOME/icu-converter-test/input/"
cd "$HOME/icu-converter-test"
ls -l input/example.ucm
Expected output is one readable file with a non-zero size. The command does not require elevated privileges. Keep the original outside the output directory so a failed compile cannot replace it.
2. Compile the table into a chosen directory
Pass the UCM path as the final argument and select the destination with -d. The output keeps the source base name and changes its extension to .cnv:
makeconv -v \
-d "$HOME/icu-converter-test/output" \
"$HOME/icu-converter-test/input/example.ucm"
With a valid table, verbose mode prints progress and a final write message. The exact diagnostic text varies with the table and tool build. Check the result rather than treating a quiet terminal as proof:
test -s "$HOME/icu-converter-test/output/example.cnv" && \
file "$HOME/icu-converter-test/output/example.cnv" && \
printf '%s\n' 'converter compiled'
A normal result is a non-empty data file and the final line converter compiled. The binary is not intended to be read as text. Its base name matters because ICU uses the converter name stored in the table as well as the generated filename.
Checkpoint: confirm the first build
- The source still exists under
input/. - The output has the same base name with a
.cnvsuffix. - The output is non-empty and was written to the directory selected by
-d.
3. Add the copyright flag only when you need it
The -c option includes a copyright notice in the binary data. It does not repair a table, install a converter, or change the mapping. Use it when the notice is part of your distribution requirement:
rm -f "$HOME/icu-converter-test/output/example.cnv"
makeconv -c -v \
-d "$HOME/icu-converter-test/output" \
"$HOME/icu-converter-test/input/example.ucm"
test -s "$HOME/icu-converter-test/output/example.cnv"
The removal in this example targets only the generated scratch output. Do not copy that pattern to a shared data directory without checking the exact filename first. If you need to undo this experiment, inspect the scratch files, then remove the directory:
find "$HOME/icu-converter-test" -maxdepth 2 -type f -print
rm -r "$HOME/icu-converter-test"
Removing a generated file is reversible only if the UCM source is preserved. A converter already installed into an ICU data directory may also be part of a package or archive, so deleting the standalone file may not change what applications load.
4. Install only after deciding how ICU will load it
The manual says the default destination is the directory named by ICU_DATA. If you set that variable, include its trailing slash. You can inspect the intended directory without changing anything:
printf 'ICU_DATA=%s\n' "${ICU_DATA:-not set}"
makeconv -v -d /path/to/icu-data/ /path/to/example.ucm
The second command writes into the specified data directory and therefore may need elevated privileges. Stop and check ownership, package management, and backups before using sudo. Prefer a private data directory while testing:
mkdir -p "$HOME/icu-converter-test/icu-data"
ICU_DATA="$HOME/icu-converter-test/icu-data/" \
makeconv -v "$HOME/icu-converter-test/input/example.ucm"
test -s "$HOME/icu-converter-test/icu-data/example.cnv"
Do not assume that placing a standalone file beside packaged ICU data overrides an archive or shared library. If the converter was originally grouped with pkgdata, rebuild that package with the replacement .cnv file. A generated file is not a complete installation plan.
5. Diagnose failures without overwriting anything
A missing conversion type, malformed header, invalid mapping, unreadable input, or unwritable destination causes a non-zero failure and no usable result. Start with the complete command and error text:
makeconv -v -d "$HOME/icu-converter-test/output" \
"$HOME/icu-converter-test/input/example.ucm"
printf 'exit status: %s\n' "$?"
If the error mentions UCM structure, compare the file with a table from the ICU data repository and verify required headers such as the converter class, minimum and maximum character width, and substitution character. If it mentions the destination, check permissions and free space, then use a new scratch directory. If the compile succeeds but an application cannot find the converter, check the application's ICU data directory and whether it uses a packaged data archive.
Do not solve an input error by adding a converter alias. The manual distinguishes compilation from aliases: a newly installed converter can be found by ICU, while convrtrs.txt is needed for additional aliases or tags. Treat alias configuration and binary compilation as separate changes.
Done means
- You identified the local ICU package and tool version.
- A valid
.ucmsource compiled to a non-empty.cnvfile. - You verified the output directory and kept the source available for recovery.
- You know whether the consuming application reads standalone data or a packaged ICU archive.