Import a CMake project
September 5, 2026 · View on GitHub
CMake is used only to import or refresh build records. Normal builds and
certifying verification do not invoke it. After init, setup, source review,
and placing the reference binary at its configured path, run:
rbit import cmake .
This guide owns the import and refresh workflows. The generated option table lists every flag and default.
This one command creates the minimal initial build records and empty per-source
review shards, configures the existing CMake project without building it, and
saves the direct compiler and linker graph. It does not edit CMakeLists.txt.
In the single rbit init command, repeat --target NAME for every binary the
project produces.
ReproBit target IDs map to CMake targets with the same name by default. When the ReproBit ID is
program but the CMake target and output are app, declare both facts
explicitly. The --oracle option names the reference binary:
rbit init . --target program --artifact build/app.exe --oracle reference/program.exe
# After setup, source review, and placing the reference binary:
rbit import cmake . --target program=app
For the simplest path, pass the real CMake target name to rbit init --target
when starting the project; the default rebuilt-output and reference filenames
then follow that name. Use the mapping form only when the ReproBit ID intentionally
differs, and make sure the artifact declared at init matches the target's real
output path.
For example, initialize a target whose real output name is GAME.EXE with:
rbit init . --target game --artifact build/GAME.EXE --oracle reference/GAME.EXE
Pass ordinary CMake cache settings explicitly when configuration needs them:
rbit import cmake . \
--cmake-define BUILD_SHARED_LIBS=OFF \
--cmake-define GAME_LANGUAGE=en
Repeat --cmake-define NAME=VALUE for each setting. ReproBit passes each value
as one CMake argument and refuses duplicate names or settings it owns itself.
The import records these values, the selected CMake program, the configuration,
the timeout, and directive inputs so a later refresh can replay the same setup.
Passing one of those options to --refresh intentionally replaces its saved
value for the refreshed graph. Use --clear-cmake-defines or
--clear-directive-inputs when a refresh should replace a saved list with no
values.
The generated files are ordinary JSON that can be reviewed and committed. A failed first import removes only its new scaffold and retains the temporary workspace for diagnosis. ReproBit builds use only the committed graph.
Refresh after adding or removing source files
Start with a read-only preview whenever the reviewed source list changes:
rbit source preview .
For an existing CMake import, preview prints the complete refresh command. Run that command directly—do not lock the new list separately first:
rbit import cmake . --refresh
If preview used repeated --path values, its refresh command repeats the same
values in the same order. Without them, both commands use the Git index.
Refresh prepares the new source list and CMake records privately, keeps saved
adjustments and checks for compiler steps that are still compatible, starts new
or changed steps with empty review files, and retires steps CMake no longer
produces.
It then verifies every target from scratch and publishes the complete update at
once: source and build records, verified binaries, matching debug files, and
the JSON and HTML report. An ambiguous compiler step, a failed verification, or
a concurrent project change leaves the published project unchanged. --target
is only for the first import.
Use --jobs COUNT to set the refresh verification's parallelism and the shared
--initialization-timeout, --compile-timeout, --link-timeout, and
--cleanup-timeout options to adjust its execution limits. These options
require --refresh and apply only to this run; they do not become part of the
saved CMake recipe. --timeout separately controls CMake configuration.
Older recorded graphs may not contain the original CMake options. They remain
valid for builds and verification, but refresh will ask you to run one ordinary
rbit import cmake . with those options first.
Advanced: how the CMake import works and how to split it for CI
The import materializes the reviewed source, then performs one
bounded configure—never a project build—in a fresh workspace. It uses Unix
Makefiles on POSIX and the provisioned, authenticated NMake Makefiles
frontend on native Windows. Both paths request CMAKE_EXPORT_COMPILE_COMMANDS,
the locked compiler-role frontends, and reprobit-target-plan.json.
Run rbit cmake-module --file to inspect the installed ReproBit.cmake.
The guided import supplies that module through CMAKE_PROJECT_INCLUDE and
defers its generated target plan until the project has declared its targets.
Projects that deliberately use the lower-level split commands can instead
contain this thin import hook:
if(REPROBIT_PROJECT_PLAN)
include("${REPROBIT_CMAKE_MODULE}")
include("${REPROBIT_PROJECT_PLAN}")
endif()
The generated plan is declarative CMake data. It may use these checked graph operations:
reprobit_insert_generated_sourceinserts a freshly materialized source at a zero-based target index. It checks the existing before/after neighbours, the file SHA-256 and size, project-root containment, and that neither the file nor its seat is redirected.reprobit_insert_link_iteminserts an existing link item at a checked index and validates its exact neighbours.reprobit_register_targetrecords the selected output and optional PDB for a target.reprobit_add_link_admissionrecords a typed produced-object admission, including its exact index or neighbour selector and expected symbol.reprobit_write_planemits resolved target and admission metadata at CMake generate time. Python re-parses it with duplicate-key and unknown-field rejection before it becomes proof input.
For example, an adapter-generated include can contain:
reprobit_insert_generated_source(
TARGET program
SOURCE generated/carrier.cpp
INDEX 4
AFTER src/third.cpp
BEFORE src/fifth.cpp
LANGUAGE CXX
SHA256 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
SIZE 128
)
reprobit_insert_link_item(
TARGET program
ITEM generated_supplier
INDEX 2
AFTER first_library
BEFORE second_library
)
Projects should not duplicate recipe dispatch, source rendering, path transport, or provenance logic in CMake. Keep target definitions project-specific and let the adapter own the generated plan.
Create the ignored configure tree, then extract the closed graph using the exact roots reported by the first command:
rbit graph configure . \
--workspace-root .reprobit-state/import \
--toolchain-root /opt/toolchains/msvc42 \
--compiler-transport /opt/toolchains/msvc42/wine/x86/cl \
--resource-transport /opt/toolchains/msvc42/wine/x86/rc \
--cmake-define FEATURE_SET=classic
rbit graph extract . \
--configured-build-root .reprobit-state/import/build \
--effective-source-root .reprobit-state/import/source \
--effective-source-digest SHA256_FROM_CONFIGURE \
--toolchain-root /opt/toolchains/msvc42 \
--directive-input config=mfcs42 \
--directive-input config=msvcprt.lib
Replace SHA256_FROM_CONFIGURE with the effective-source digest printed by
graph configure. The workspace must be absent or empty; ReproBit will not
erase or reuse a configured tree. The configure command seals the effective
source tree before and after CMake, rejects a changed target universe, and
reports a configure log and command digest for review. The default target-plan path is
.reprobit-state/import/build/reprobit-target-plan.json; use
--target-plan only for another path beneath the configured build root. The
extractor reads compile_commands.json, resource rules, link.txt, and bounded
response files, then rejects commands or inputs outside the effective source,
configured build, and admitted toolchain roots. It publishes a canonical
reprobit/producer-graph.json only after validating the complete candidate
project tree and rechecking all authority files transactionally.
Older MSVC COFF objects and archive members can contribute /DEFAULTLIB controls
through their .drectve sections even though those libraries do not appear in
the extracted linker command. Such edges are never inferred or authorized at
certification time. Run a prelink audit, review its missing-edge diagnostic,
and repeat --directive-input TARGET=LIBRARY once for every approved target
and bare library. The extractor lowercases the name, adds .lib when omitted,
canonicalizes the references as system-library/*.lib, and rejects unknown
targets, paths, and duplicates. A certifying run requires every effective
DEFAULTLIB to match exactly one argv-derived or committed directive input;
its failure prints the exact flags needed for the next reviewed extraction.
Review and commit that graph, then discard the ignored configure tree. Later
rbit build (warm by default), rbit build --cold, and rbit verify runs
expand only its symbolic
${SOURCE}, ${BUILD}, and ${TOOLCHAIN} seats and invoke the locked producer
roles directly. Graph schema v3 requires every source edge to resolve through
the source manifest or a reviewed overlay output. Unrelated manifest entries
may be added or removed without changing the command DAG; removing a graph
input, or changing the toolchain lock, logical-path profile, target set,
terminal artifact path, or producer commands requires a new import extraction.
Warm build stores non-certifying node artifacts in the leased project-local
CAS. The first run normally misses; an unchanged second run should be all-hit
with zero backend runtime starts. build --cold and verify, which always builds from
scratch, bypass the cache entirely.