Package ICU Resource Data into a .dat Archive with pkgdata
You will turn a compiled ICU resource bundle into a small .dat package and verify the result without touching the original source files. Allow about 15 minutes for a simple test. This guide targets the pkgdata 74.2 shipped by Ubuntu's icu-devtools package; option details and build output can differ in other ICU releases.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the installed tool
Run this as your ordinary user. The command does not need root for packaging in a directory you own.
$ command -v pkgdata
/usr/bin/pkgdata
$ dpkg-query -W -f='${Package} ${Version}\n' icu-devtools
icu-devtools 74.2-1ubuntu3.1
$ pkgdata --help
usage: pkgdata [-options] [-] [packageFile]
...
The installed help is useful here because it exposes a few build options not described in the older manual page, including --force-prefix and --without-assembly. This article uses only options confirmed by both the local manual page and the installed command. There is no --version option in this build: asking for it is an error, so use the package query to identify the version.
Checkpoint
You have /usr/bin/pkgdata and a recorded ICU package version.
2. Prepare a real ICU input file
pkgdata packages ICU binary data. A plain text file is not a valid input for the common mode, even if the command can read its name. For a harmless demonstration, compile one small resource bundle with the installed genrb tool.
$ workdir=/tmp/pkgdata-demo
$ mkdir -p "$workdir/source" "$workdir/res" "$workdir/out"
$ printf '%s\n' 'menu { title { "Example" } }' > "$workdir/source/menu.txt"
$ genrb -s "$workdir/source" -d "$workdir/res" menu.txt
$ find "$workdir/res" -maxdepth 1 -type f -printf '%f\n'
menu.res
The input to pkgdata is now menu.res. Keep the source directory and the generated resource directory separate so that a failed packaging attempt cannot overwrite your source text.
When you already have ICU .res, .cnv or other supported binary data, use those files instead. Do not use an arbitrary application document as a test input: the resulting package must contain ICU data objects.
Checkpoint
test -r /tmp/pkgdata-demo/res/menu.res succeeds, and the file is not an input you need to recreate from memory.
3. Build the default archive
Use common, also called archive, to create one architecture-dependent data file. Set the source and destination directories explicitly. Pass the input name relative to the source directory; this avoids the installed tool treating an absolute path as an old-style package path.
$ cd /tmp/pkgdata-demo/res
$ pkgdata --verbose \
--mode common \
--name demo \
--sourcedir . \
--destdir /tmp/pkgdata-demo/out \
menu.res
# pkgdata: Reading menu.res..
# Writing package file /tmp/pkgdata-demo/out/demo.dat ..
--name demo controls the output name, so the result is demo.dat. The default mode is already common, but stating it makes a build script easier to review. The archive is architecture-dependent, as the manual describes, and is normally looked up through an ICU data directory or loaded by an ICU API.
Verify both the exit status and the output file:
$ test "$?" -eq 0
$ file /tmp/pkgdata-demo/out/demo.dat
/tmp/pkgdata-demo/out/demo.dat: ICU data file
The exact file description can vary. The important checks are a zero exit status, a non-empty demo.dat, and no error from the packaging command.
Checkpoint
/tmp/pkgdata-demo/out/demo.dat exists and the original menu.res is unchanged.
4. Choose a different packaging mode deliberately
The modes are not interchangeable output formats:
commonorarchivemakes one.datpackage.dllorlibrarybuilds a shared library. The manual says this is useful for ICU itself or data linked to an application, but it is not a general-purpose dynamically loaded ICU data plug-in.staticbuilds a static library and is intended for applications that link the data.fileskeeps data as separate files. It is useful when separate files are required by a packaging workflow, but it does not produce a single archive.
For example, the same resource can be processed in files mode:
$ mkdir -p /tmp/pkgdata-demo/files
$ pkgdata --verbose --mode files --name demo \
--sourcedir /tmp/pkgdata-demo/res \
--destdir /tmp/pkgdata-demo/files \
menu.res
# pkgdata: Reading menu.res..
In this mode the command prepares separate data files rather than writing demo.dat. Treat the destination as a staging directory and inspect it before any installation step.
5. Install only after inspection
--install changes where data is placed. That is a separate operational decision from building it. The manual documents DESTDIR as the installation prefix used by --install, but the installed help says to specify an installation target and the exact invocation depends on the surrounding ICU build workflow. Do not point it at a live ICU data directory during an experiment. Use the same build inputs and a staging target owned by your user, then inspect the result before copying anything into a system location:
$ find /tmp/pkgdata-demo/stage -type f -printf '%p %s bytes\n'
If a real deployment requires a protected directory, stop at this point, review the staged files, and use your normal change process with the necessary elevated privileges. A failed package build can leave a partial destination; use a fresh staging directory for the next attempt rather than guessing which files are safe to keep. The safe recovery for this demonstration is simply to abandon the temporary directory and rebuild into a new one. Do not delete a system data directory as an undo step.
6. Diagnose the common traps
"not an ICU data file" or an input access error: check that the input is a compiled ICU data object and that the argument is relative to --sourcedir. Generate a resource with genrb, or use the binary data produced by your ICU build.
The output is in an unexpected directory: remember that --destdir controls the build destination, while --install performs installation. The default destination is the current directory, and the default temporary directory is the destination directory.
A rebuild appears to do nothing: use --rebuild to force rebuilding of all data. Use it when inputs or build settings changed and the normal timestamp checks do not produce the result you expect.
A shared-library build fails: dll and static modes use compiler and linker settings from ICU's build configuration. On this installation, pkgdata reads ICU build settings from /usr/lib/x86_64-linux-gnu/icu/74.2/pkgdata.inc. Fix the ICU build environment first; adding sudo will not repair missing compiler settings.
Unexpected package contents: use --verbose and review every input line. A package file can also be supplied as an argument; the installed help describes a package file as a text file containing the list of files to package. Keep such a list under version control or inspect it before running the command, because it defines the package contents.
Done means
- You confirmed the installed
pkgdataversion and help output. - Your inputs are valid ICU binary data, not arbitrary text files.
- You built the intended mode with explicit source, destination and package name options.
- You checked the exit status and inspected the generated file or staging tree.
- You kept installation separate from packaging and did not overwrite a live ICU data directory during testing.