Compile ICU Break Rules Safely with genbrk
You will turn an ICU break-iteration rule file into a binary .brk data file, then verify that the expected file exists and has non-zero content. The example uses ICU 74.2 from Ubuntu's icu-devtools package and takes about five minutes if the rules are already written.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
You need a shell, the genbrk executable, a writable working directory and a rule file that follows ICU's break-rule syntax. Check the installed package and command before changing anything:
command -v genbrk
dpkg-query -W -f='${Package} ${Version}\n' icu-devtools
genbrk --help
On the system used for this guide, the package is icu-devtools 74.2-1ubuntu3.1. The help text shows the short and long forms documented by the manpage. This is a compiler, not a system service, so the normal command needs no elevated privileges.
Checkpoint: prepare a small rule file
- Create a UTF-8 rule file in a project or scratch directory you control.
This example keeps runs of letters together and treats other characters as a separate run:
!!forward;
$letters = [[:L:]];
$letters+;
[^$letters]+;
Save it as break-rules.txt. ICU's current documentation describes !!forward, variables such as $letters and UnicodeSet expressions such as [[:L:]]. A rule file is input data, so inspect it before compiling if it came from another person or project.
Checkpoint: compile to an explicit output file
- Run
genbrkwith both the input and output named explicitly.
genbrk \
--rules break-rules.txt \
--out build/break-rules.brk \
--verbose
Create build first if it does not exist:
mkdir -p build
genbrk -r break-rules.txt -o build/break-rules.brk -v
A successful run prints:
genbrk: tool completed successfully.
The output is a compiled ICU data file, not a readable copy of the rules. Keep the source file under version control alongside it if the binary will be rebuilt later.
Verify the result before using it
- Check the exit status and inspect the output file without replacing anything else.
test -s build/break-rules.brk && \
stat -c 'compiled %n (%s bytes)' build/break-rules.brk
You should see a line similar to this, with a size greater than zero:
compiled build/break-rules.brk (12600 bytes)
The exact size depends on the rules and ICU build. The useful checks are the zero exit status and the presence of a non-empty file. To make a reproducible build, run the command from the same source revision and record the ICU package version with the output.
Choose where the output is written
--out names the output file. If a build system supplies only a filename, --destdir places that file in a directory:
mkdir -p build/data
genbrk \
--rules break-rules.txt \
--out break-rules.brk \
--destdir build/data
test -s build/data/break-rules.brk
Do not assume that --destdir creates missing directories. Create the destination first, and use a path reserved for generated files. If an existing file has the same name, genbrk may overwrite it. Before running a build in a shared tree, check the destination with ls -l and copy the old file elsewhere if you need a rollback.
Encoding and ICU data
The manpage says a rule file beginning with the Unicode byte order mark U+FEFF is interpreted as Unicode. Without that mark, this installed tool reports that it assumes UTF-8. Saving the source as UTF-8 avoids an accidental dependency on a different shell or editor encoding. Do not add a BOM mechanically to a file whose project format says otherwise; follow the format used by the surrounding ICU rules.
Most installations find ICU data automatically. If genbrk cannot locate required data such as pnames.icu, pass its directory explicitly:
genbrk \
--icudatadir /path/to/icu-data/ \
--rules break-rules.txt \
--out build/break-rules.brk
The trailing slash matters for some ICU configurations. The alternative is the ICU_DATA environment variable. Use the directory belonging to the same ICU installation as genbrk, rather than guessing from a different version.
Diagnose failures without hiding them
Keep compiler output and the exit status. A missing input or output argument is an error, not a successful no-op:
genbrk --rules break-rules.txt
printf 'exit status: %s\n' "$?"
The command reports that both files must be specified and returns status 1. A syntax error in the rule file likewise prevents a trustworthy binary. Fix the rule source, then compile to a new output path and repeat the non-empty-file check. Do not replace a known-good production file until the new build succeeds and has been reviewed.
The manpage lists -V and --version, but this Ubuntu 74.2 build rejected both forms while displaying its usage text. Treat the package query above as the reliable local version check, and verify option behaviour on the exact package installed on another machine.
Done means
- The source rules are UTF-8 and follow ICU break-rule syntax.
genbrkcompleted with exit status 0.- The intended destination contains a non-empty
.brkfile. - The ICU package version and rule source are recorded for the build.
- No existing generated file was replaced before the new output was checked.