Compile ICU Break Rules with genbrk
genbrk turns an ICU break-iteration rule file into a binary .brk data file that your application loads at runtime. This walkthrough uses ICU 74.2 from Ubuntu's icu-devtools package and takes about five minutes once the rules are 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 written in ICU's break-rule syntax. Check the installed package and command before you change anything:
command -v genbrk
dpkg-query -W -f='${Package} ${Version}\n' icu-devtools
genbrk --help
On the system used here, that is package icu-devtools 74.2-1ubuntu3.1. The help text shows the short and long option forms this manpage documents. This is a compiler, not a system service, so the normal command needs no elevated privileges.
1. Write 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 everything else as its own run:
!!forward;
$letters = [[:L:]];
$letters+;
[^$letters]+;
Save it as break-rules.txt. ICU's current documentation covers !!forward, variables such as $letters, and UnicodeSet expressions such as [[:L:]]. A rule file is input data, so read it over before compiling if it came from someone else.
2. Compile to an explicit output file
Run genbrk with 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 already exist:
mkdir -p build
genbrk -r break-rules.txt -o build/break-rules.brk -v
A successful run prints:
genbrk: tool completed successfully.
That output is a compiled ICU data file, not a readable copy of the rules. Keep the source under version control alongside it if the binary gets rebuilt later.
3. Verify the result before you trust it
Check the exit status and inspect the output file without touching anything else:
test -s build/break-rules.brk && \
stat -c 'compiled %n (%s bytes)' build/break-rules.brk
You should see a line like this, with a size greater than zero:
compiled build/break-rules.brk (12600 bytes)
The exact size depends on your rules and ICU build. What matters is the zero exit status and a non-empty file. For a reproducible build, run from the same source revision and record the ICU package version alongside the output.
4. Choose where the output lands
Name the file directly. --out sets the output path.
Or split name from location. If a build system only hands you a filename, --destdir puts that file in a directory of your choosing:
mkdir -p build/data
genbrk \
--rules break-rules.txt \
--out break-rules.brk \
--destdir build/data
test -s build/data/break-rules.brk
Warning
Do not assume --destdir creates missing directories, because it does not. Create the destination first, and use a path reserved for generated files. genbrk will happily overwrite an existing file with the same name, so before running a build in a shared tree, check the destination with ls -l and copy the old file elsewhere if you would need it back.
5. Get the encoding and ICU data right
The manpage says a rule file that opens with the Unicode byte order mark U+FEFF is read as Unicode. Without that mark, this installed build assumes UTF-8. Saving the source as UTF-8 avoids picking up a different shell or editor encoding by accident. Do not bolt a BOM onto a file whose project format says otherwise: follow whatever convention the surrounding ICU rules already use.
Most installs find ICU data on their own. If genbrk cannot locate something it needs, such as pnames.icu, point it at the 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 that belongs to the same ICU install as your genbrk, not one guessed from a different version.
6. Diagnose failures without hiding them
Keep the compiler output and the exit status. A missing input or output argument is an error, not a silent no-op:
genbrk --rules break-rules.txt
printf 'exit status: %s\n' "$?"
genbrk reports that both files must be specified and returns status 1. A syntax error in the rule file breaks trust in the binary the same way. Fix the source, compile to a new path, and repeat the non-empty-file check before you touch a known-good production file.
The manpage lists -V and --version, but this Ubuntu 74.2 build rejects both and just prints its usage text. Use the package query above as the real version check, and confirm option behaviour on whatever exact package is installed elsewhere.
Done means
- Source is clean. The rules are UTF-8 and follow ICU break-rule syntax.
- Compile succeeded.
genbrkexited with status 0. - Output verified. The intended destination holds a non-empty
.brkfile. - Build recorded. The ICU package version and rule source revision are noted alongside the output.
- Nothing clobbered. No existing generated file was overwritten before the new output was checked.