# Building fold ## TL;DR ```sh ./setup.sh release # autodetects LLVM on macOS or Linux # binary at: build/release/src/cli/fold # tests: meson test -C build/release ``` `setup.sh` also enables the tracked lint pre-commit hook (`.githooks/pre-commit`). Linux users without root can validate against a clean container: ```sh docker build -t fold-linux-validate -f docker/Dockerfile.linux-validate . docker run --rm -v "$PWD":/workspace:ro fold-linux-validate ``` The Dockerfile is the executable spec of the Linux dependency set. If you change a system dependency, change it there too — the GitHub Actions Linux job (`.github/workflows/build.yml`) installs the same packages. ## Required system dependencies These must be installed by the user before `./setup.sh` runs. Conan handles the rest (spdlog, CLI11, nlohmann_json, sqlite3, Catch2). ### LLVM / Clang - **Version range:** 18–22 (19 in CI, 22 on the macOS dev machine). - Provides `clang`, `clang++`, `llvm-config`, and the libclang development headers fold's frontend builds against. ### Z3 - **Why:** the SMT solver fold queries for every symbolic predicate. - Linux users must install `libz3-dev` system-wide. On macOS, Homebrew's `z3` formula installs both the library and the `z3.pc` pkg-config file that meson consumes. ### Build tooling - Meson ≥ 1.2, Ninja, pkg-config, Python 3, Conan 2.x. ### Optional - **radare2 dev headers** (`r_core.pc`): linked binary backend. Without it fold falls back to the `r2` CLI at runtime. - **sqlite3 dev headers**: needed for the incremental-scan store. ## Per-platform install commands ### Ubuntu / Debian ```sh sudo apt-get install \ clang-19 llvm-19-dev libclang-19-dev libclang-cpp19-dev \ libz3-dev libsqlite3-dev \ meson ninja-build pkg-config \ nlohmann-json3-dev libcli11-dev libspdlog-dev libfmt-dev \ python3-pip pip3 install --user 'conan>=2,<3' conan profile detect --force ``` Replace `19` with another version (18–22) if you prefer; `setup.sh` probes `/usr/lib/llvm-{22..18}/bin/llvm-config` newest-first. ### Fedora / RHEL ```sh sudo dnf install \ clang clang-devel llvm-devel \ z3-devel sqlite-devel \ meson ninja-build pkgconf-pkg-config \ python3-pip pip3 install --user 'conan>=2,<3' conan profile detect --force ``` ### macOS (Homebrew) ```sh brew install llvm@22 z3 meson ninja pkg-config conan conan profile detect --force ``` `setup.sh` finds Homebrew LLVM automatically (`/opt/homebrew/Cellar/llvm/*` on Apple Silicon, falls back to `brew --prefix llvm@N`). ## Build steps ### Quick build (recommended) ```sh ./setup.sh release ``` `setup.sh` autodetects LLVM, runs `conan install`, runs `meson setup`, and invokes `ninja`. Pass `debug` instead of `release` for a debug build. It builds the **vendored Ghidra P-Code binary backend** by default (`-Dghidra=auto` — the decompiler is vendored under `third_party/`, so `auto` always builds it; this powers the SSA P-Code pipeline and the ROP exploit primitives). It adds noticeable build time (compiling the decompiler and generating the per-arch `.sla` specs); pass `-Dghidra=disabled` for a lighter baseline that uses the r2-disasm fallback. It also enables **Capstone-backed ROP gadget discovery** (`-Dcapstone=auto` plus `--wrap-mode=default`). Capstone is built from the vendored wrap (`subprojects/capstone.wrap`) as a CMake subproject, so this needs **cmake** and network access on first configure; the `--wrap-mode=default` flag is required to override the `wrap_mode=nofallback` that Conan's native file sets. If Capstone can't be built (offline, or no cmake), the build still succeeds and gadget discovery falls back to the radare2 `/R` search — `setup.sh` prints the resolved status (`Capstone ROP gadget discovery: ENABLED|disabled`). A system Capstone (`brew install capstone`) is used instead of the wrap when present. For the manual build below, add `-Dghidra=auto --wrap-mode=default -Dcapstone=auto` to the `meson setup` line to get the same behavior. ### Manual build ```sh conan install . --output-folder build/release --build=missing \ -s build_type=Release -o build_tests=True meson setup build/release \ --native-file build/release/conan_meson_native.ini \ -Dcpp_std=c++23 -Dbuild-tests=true \ -Dllvm-config-path=/path/to/llvm-config meson compile -C build/release ``` On Linux, also symlink z3.pc into the build dir if pkg-config can't find it automatically (`setup.sh` does this for you): ```sh ln -sf /usr/lib/$(uname -m)-linux-gnu/pkgconfig/z3.pc build/release/z3.pc ``` ## Environment overrides | Variable | Effect | |---|---| | `LLVM_BIN` | Override the autodetected LLVM bin directory (e.g. `/opt/clang-20/bin`). | | `LLVM_CONFIG` | Full path to `llvm-config`. Threaded into `-Dllvm-config-path`. | | `CC`, `CXX` | Set the C / C++ compilers used by Conan + meson. Defaults to the discovered clang. | ## Tests ```sh meson test -C build/release ``` When `-Dbuild-tests=true` is set, Fold also defines `FOLD_ENABLE_DCHECK=1` so unit/integration tests exercise debug-only invariant checks. For an independent non-test canary or benchmark build with debug checks enabled, configure it with its own Conan/Meson files: ```sh conan install . --output-folder build/dcheck --build=missing \ -s build_type=Release -o build_tests=False meson setup build/dcheck \ --native-file build/dcheck/conan_meson_native.ini \ -Dcpp_std=c++23 -Denable-dcheck=true ninja -C build/dcheck ``` To toggle debug checks in an existing build dir: ```sh meson configure build/release -Denable-dcheck=true meson compile -C build/release ``` The optional `binary_backend` integration test uses radare2 and a real binary. Defaults to `/usr/bin/curl` when available: ```sh FOLD_TEST_BINARY=/path/to/binary meson test -C build/release binary_backend ``` The test skips itself when no suitable binary or `r2` command is present. The binary P-Code / ROP pipeline is covered by `test_binary_rop` (gadget discovery over the committed ELF fixtures in `tests/fixtures/binary/`, built only when Capstone is enabled) and the `sast_security_e2e` test (security detectors over `tests/fixtures/security/`). The full whole-binary BOF → ROP-chain scan is a manual step (`build/release/pcode_scan `) — it takes minutes, so it is not part of the automated suite. ## Optional backends ### Rust frontend (`-Drust-frontend=true`) Builds `fold-rust` (a Cargo binary under `tools/fold-rust/`) and links `RustBackend` into fold. Enables `fold scan --mode rust`. **Requires:** nightly Rust toolchain (hardcoded to `nightly-2026-05-28`). ```sh meson setup build/release ... -Drust-frontend=true ``` Disable when you don't have Rust installed or want a C++/binary-only build: ```sh meson setup build/release ... -Drust-frontend=false ``` When disabled, `--mode rust` scans fail with a build-time-disabled frontend error; Rust detector names are still accepted by `--detectors` but produce no findings in non-Rust modes. ### Swift frontend (`-Dswift-frontend=true`) Builds `fold-swift` (a C++ binary under `tools/fold-swift/`) and links `SwiftBackend` into fold. Enables `fold scan --mode swift`. **Runtime requirement:** `swiftc` on PATH when running Swift scans. ```sh meson setup build/release ... -Dswift-frontend=true ``` Disable when Swift is not installed or you want a C++/binary-only build: ```sh meson setup build/release ... -Dswift-frontend=false ``` ### Compatibility matrix | Option | Default | Requires | Enables | |---|---|---|---| | `rust-frontend` | `true` | nightly Rust | `--mode rust` scans, Rust IR symbolic encoding | | `swift-frontend` | `true` | `swiftc` at scan runtime | `--mode swift` scans, Swift SIL symbolic encoding | | `ghidra` | `auto` | vendored (always available) | P-Code binary pipeline, ROP primitives | | `capstone` | `auto` | cmake + network | Exhaustive ROP gadget discovery | | `radare2` | `auto` | `r_core.pc` | Linked binary backend (falls back to `r2` CLI) | ## Coverage ```sh ./scripts/coverage.sh ``` Builds an instrumented `build/coverage` (debug, ghidra + capstone), runs the suite, and writes a line/function coverage report to `build/coverage/coverage.{txt,html}` (terminal summary printed too). Vendored code under `third_party/` and `subprojects/` is excluded. Uses `gcovr` via `uvx` (no system install) and clang's `llvm-cov gcov`; set `LLVM_BIN` if LLVM isn't on the Homebrew/PATH default. ## Validation The Linux container at `docker/Dockerfile.linux-validate` runs the same pipeline against a clean Ubuntu 24.04 + clang-19 environment. Use it locally before pushing if you don't have a Linux host. See `docker/run-validate.sh` for the exact steps. ## More - `docs/USAGE.md` — runtime invocation, output formats, MCP/LSP. - `docs/BUILDING.md` — radare2 integration, vendoring notes.