Five sets of compile-time widths. The whole library and the whole test suite are built against every one of them, in one build.
An environment is one set of width macros. It is not a target, a toolchain or a board: it is the handful of numbers that make one machine different from another, turned into a compile-time knob so that a wide host can exercise a narrow machine's code paths without owning the narrow machine.
CMakeLists.txt declares them as a flat list:
| name | definitions | what it is for |
|---|---|---|
| host | (none) | whatever this machine is. EMBED_WORD_BITS derives from UINTPTR_MAX. The default build. |
| word32 | EMBED_WORD_BITS=32 | a 32-bit word on a 64-bit host. Catches anything that assumed a word holds a pointer. |
| word16 | EMBED_WORD_BITS=16 | the narrowest carrier. Most likely to expose an off-by-one in a scan tail. |
| idx16 | EMBED_INDEX_BITS=16 | a 16-bit index against a 64-bit word, the pairing the static asserts in embed_types.h exist to police. |
| checks | MMGR_DEBUG_CHECKS=1 | the checks compiled in, and the trapping MMGR_ASSERT selected. A broken precondition fails a test instead of being a no-op. |
This is the part that surprises people. cmake/MMgrModule.cmake loops the environment list inside mmgr_add_module() and emits one library target per module per environment:
and src/CMakeLists.txt aggregates each column into an interface target, mmgr_host, mmgr_word32, mmgr_word16, mmgr_idx16, mmgr_checks. That aggregate is what a consumer or a test links.
A single cmake --build build builds all five, and a single ctest runs all five. There is no matrix to drive from the outside and nothing to remember:
A clean run is 240 CTest targets. Test names carry the environment as a suffix. A failure names the width it failed at:
To run one environment on its own, filter on the suffix:
word16 and idx16 are the two that earn their place most often. A SWAR scan is written once and runs at whatever the carrier is; the tail, the bytes after the last whole word, is where an off-by-one hides, and a 16-bit carrier reaches that tail four times sooner than a 64-bit one. idx16 exists because a narrow index against a wide word is the combination nothing else covers, and it is what the static asserts in embed_types.h are there to catch.
checks is not a width at all. It compiles in the library's checks and selects the trapping MMGR_ASSERT, which turns a broken precondition from a silent no-op into a failed test. It is the only environment where an assert is evaluated. An expectation that is never exercised there is one nothing has ever tested.
Two environments called swar16 and swar32 used to exist. They set the scan lane narrower than the machine word, a configuration no real target has, because the carrier is the machine word on every machine. They were replaced by narrowing the whole machine instead, which is a case that does exist. If you find swar16 in a path or a comment, it is stale.
One line in CMakeLists.txt:
Every module target, every aggregate and every test registration follows from it. Nothing central lists the modules, and so nothing central has to be kept in step.