How do I build the system?

Table of Contents

Configure first if you haven't (see How do I configure the project?). For preset / output / parallelism details, see CMake setup.

Question

How do I build ORE Studio?

Answer

Day-to-day with compass

compass build resolves the checkout's preset from ORES_PRESET in .env and configures the build directory automatically on first use:

./compass.sh build                          # everything
./compass.sh build ores.iam.core            # specific target(s)
./compass.sh build site                     # friendly alias (deploy_site)
./compass.sh build --preset linux-clang-release-make   # preset override
./compass.sh build -j 4 --dry-run           # jobs override / print-only

Friendly aliases: sitedeploy_site, manualdeploy_manual, org-roam-db-syncorg_roam_db_sync; any raw cmake target is also accepted.

For documentation/agile targets, add --direct to skip cmake entirely and run the Emacs build script directly (no cmake/vcpkg — works in light environments): ./compass.sh build --direct site skills settings manual. See How do I deploy the site?.

Always build via compass build (not raw cmake --build) — never bypass it, even to "just quickly build one target". See Build locking below for why.

Build locking

This only matters on a host running several ORE Studio worktrees at once (each their own environment) — the common case for this repo's LLM-driven workflow, where multiple environments can be building in parallel. On a single-checkout machine with nothing else building, the lock is a no-op (you always get a free slot immediately).

Where it applies: concurrent, uncoordinated cmake --build invocations from different worktrees on the same host contend for the same CPUs and have been observed to corrupt shared library outputs when one build is killed mid-link while another links against the same target. A non-direct compass build automatically waits for one of two host-wide lock slots before invoking cmake, so at most two environments on the host build at once, each capped to that slot's -j:

./compass.sh build --status

reports each slot as held (with the holding environment's identity, pid, and start time) or free, plus a tail of that slot's build log. Every build's combined stdout/stderr is also streamed live to a well-known path per slot, /tmp/ores-build.log.<slot> (overwritten each run) — tail -f it directly if you want to watch a build you (or another environment) kicked off rather than polling --status. If both slots are busy, compass build prints a waiting message and blocks until one frees — this is expected, not a hang; let it wait rather than killing it or falling back to a raw cmake --build. --jobs overrides the slot's job count if you deliberately need a different value for one invocation. --dry-run does not take a lock or write a log.

The actual cmake --build step (not the configure step) also runs inside its own memory-capped app-build-<env>.slice when a user systemd manager is available — deployed on demand from a checked-in dash-truncated template drop-in (same mechanism as How do I launch Claude Code inside a systemd scope?'s app-claude-.slice.d/), so an overrunning build is killed by its own cgroup OOM instead of pushing the whole machine into swap. Inspect with:

systemd-cgls --user-unit=app-build-<env>.slice
systemctl --user show app-build-<env>.slice -p MemoryMax -p CPUWeight

Direct CMake

Only for local single-environment work where you know no other worktree on the host is building concurrently — it bypasses the lock entirely, so simultaneous invocations from other environments can corrupt shared build outputs (see Build locking above). Prefer compass build otherwise.

cmake --build --preset <preset> [--target <target_name>]

Script

compass build (projects/ores.compass/src/compass.py) wrapping cmake --build --preset. Locking is _acquire_build_lock=/ =BUILD_LOCK_SLOTS in the same file — two flock-based slots (-j2=/-j3=) under /tmp/ores-build.lock.<slot>, shared by every worktree on the host. The memory cap comes from _ensure_build_slice_deployed=/=_build_slice_name in the same file, syncing projects/ores.compass/src/systemd/app-build-.slice.d/50-limits.conf.

Tested by

CI builds every preset on every push.

See also

Emacs 29.3 (Org mode 9.6.15)