The README listed 11 of fold's 17 detectors, never explained the confidence tiers every finding carries, did not mention the new exit code 2 / coverage reporting, and spent half its length on a performance roadmap. It now says what fold is, defines the five tiers (from include/fold/report/finding.hpp, including concrete-witness and latent), what "bounded" means after the loop-exit fix, a quick start, output formats and exit codes (0 none, 1 any unsuppressed finding, 2 unwritable report or any unanalysed translation unit), and links. The detector list defers to the complete table in docs/USAGE.md. The performance section moves to docs/architecture/performance.md, with one correction: the gold set was derived from fold's own reviewed output and is matched by detector kind and file, so it catches drift rather than measuring precision/recall independently. The lint pre-commit hook note moves to BUILD.md.
267 lines
8.6 KiB
Markdown
267 lines
8.6 KiB
Markdown
# 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 <binary>`) — 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.
|