Services and Tools
NRC Resource Compiler
nrc is the repo's resource compiler. It turns per-target res/ directories into generated C sources
or external packed .res files, preserving localized message overrides and producing the ResPack
entry points consumed at runtime by core/respack.c.
Relevant Source Files
Role In The Build Graph
nrc is built as a standalone command app under tools/nrc. The tools super-build in
tools/CMakeLists.txt compiles sewer, osbs, core, and then the nrc executable
in a separate Debug-only tools tree.
When a target uses NRC_EMBEDDED or NRC_PACKED, nap_generate_tools() first makes sure a local
nrc binary exists under ${CMAKE_BINARY_DIR}/tools/build. Later, nap_resource_packs(...) invokes that
executable once for each immediate resource-pack directory under the target's res/ folder.
Resource Directory Contract
The build system treats each immediate subdirectory of a target-local res/ folder as one resource pack. Real examples in this
checkout include res_guihello, res_products, and res_htjson.
Localized overrides live one level deeper. For example, demo/products/res/res_products/ja_JP and
demo/die/res/res_die/es_es are locale directories under a pack. Outside the packs themselves, the same top-level res/
folder may also hold app icons, license.txt, and pack.txt, which CMake treats specially for packaging and installation.
What Counts As A Resource
The compiler recognizes three runtime categories:
- Message files:
.msgfiles become text resources. - Image files:
.png,.jpg,.gif, and.bmpare tagged as image resources. - Generic files: every other extension is still accepted and treated as a generic file resource.
So the resource compiler is permissive by default. It does not require a whitelist beyond the handful of extensions that deserve image-specific typing.
Message File Syntax And Localization Rules
msgparser.c accepts UTF-8 text with an optional BOM, skips whitespace, supports both // and
/* ... */ comments, and parses one message per logical line. Each entry begins with an uppercase-or-underscore identifier,
optionally followed by more uppercase letters, underscores, or digits, and the rest of the line becomes the message text.
Localization is anchored on the global pack. Global .msg files define the canonical set of message IDs. A localized
.msg file can override those IDs, but it does not create new ones. If a localized file references an ID that does not exist globally,
nrc emits a warning; if a global message has no localized counterpart, it emits a warning for that omission too.
Embedded Versus Packed Output
| Mode | CLI Option | Generated Files | Runtime Entry Point |
|---|---|---|---|
| Embedded | -dc |
<pack>.h and <pack>.c |
respack_embedded("<pack>") |
| Packed | -dp |
<pack>.h, <pack>.c, and <pack>.res |
respack_packed("<pack>", locale) |
In both modes the header exports one ResId per resource plus a function named <pack>_respack(const char_t *locale).
Resource IDs are not enums; they are generated strings with the form N23R3C75::<pack>::<index>.
What The Generator Actually Emits
Embedded mode writes the full payload into C source: messages become escaped string literals and binary resources become byte arrays.
For each locale, the generated <pack>_respack(...) function chooses a localized override when available and otherwise falls back
to the global resource.
Packed mode writes the same logical data into a binary .res file. The companion C file becomes a thin stub that only defines
the ResId values and forwards the pack load to respack_packed(...).
Runtime Loading Contract
The runtime half lives in src/core/respack.c. Packed resources are loaded from a path relative to the executable:
res/<pack>.res on Windows and Linux, and ../resources/<pack>.res for macOS bundles.
Once loaded, the runtime keeps the binary pack buffer alive and exposes resources through typed APIs. Text resources are returned with
respack_text(...), generic files with respack_file(...), and typed object resources such as images are materialized lazily
through respack_object(...). That is why the image-handling path in draw2d/image.c goes through the object API rather than
the raw file accessor.
Up-To-Date Checks And Exit Codes
nrclib.c only regenerates a pack when the source directory is newer than the generated .c and .h files.
The destination argument must name a .c file in an existing directory; nrc infers the matching header and packed file names from it.
0: regeneration happened successfully.1: the outputs were already up to date.-1: generation completed with warnings.-2: generation failed with errors.-3: command-line usage error.-4: asserts were triggered.
The CMake wrapper in nap_resource_packs(...) treats 0 and 1 as normal success, reports -1 as warnings,
and treats anything else as an error.
Reading Order
Start with nrc.c for the command-line surface, then read nrclib.c for validation and up-to-date checks,
then resgen.c for the real format and code-generation logic. Follow that with msgparser.c if localized text syntax matters,
and finish with prj/NAppTarget.cmake plus src/core/respack.c to connect build-time generation to runtime loading.