Skip to content

Installation

This page covers building Tero from source: host requirements, the two supported toolchain paths (system packages or nix develop), the build itself, verification, and troubleshooting.

flowchart LR
    A[Install toolchain<br/>GCC/Clang + CMake + Ninja + LLVM≥18] --> B[git clone]
    B --> C["cmake --preset default<br/>(fetches fmt / tl::expected / Catch2)"]
    C --> D["cmake --build build"]
    D --> E["ctest --test-dir build"]
    E --> F[./build/src/app/tero-emu]

Host requirements

Tero is developed and CI-tested on Linux x86-64. Linux ARM64 and macOS are functional but not CI-validated.

The C++ library dependencies (fmt, tl::expected, Catch2) are fetched automatically by CMake's FetchContent — they do not need to be installed on the host. The vendored SoftFloat 3e lives under third-party/softfloat3e/. LLVM is the exception: it is a mandatory build dependency for the binary-translation JIT and is not fetched — you must install LLVM ≥ 18 dev libraries on the host (see the table and the per-distribution commands below). As a reproducible alternative to installing the toolchain manually, the repo ships a flake.nix that pins everything — LLVM included — to known-good versions (see the Nix option below).

Strict host requirements (must be present)

Tool Minimum version Notes
CMake 3.25 CMakePresets.json declares this minimum; presets need it.
Ninja 1.10 Recommended generator (-G Ninja). The presets use it.
C++ compiler GCC ≥ 13 or Clang ≥ 17 Must support C++20, including concepts and std::span.
LLVM (dev libraries) 18 Mandatory — the binary-translation JIT links LLVM ORCv2 and uses the llvm::CodeGenOptLevel API added in LLVM 18 (ADR-003). Found via find_package(LLVM REQUIRED CONFIG); not fetched by CMake.
Git any For cloning + FetchContent.
Internet access First configure only; build/_deps/ is reused after.

Why LLVM is mandatory

Both execution methods are compiled into every build and selected at runtime by EmulatorConfig::translation (default true = JIT). There is no TERO_ENABLE_JIT option and no LLVM-free configuration — making LLVM mandatory removes a whole untested build permutation. The top-level CMakeLists.txt finds any LLVM and then fails the configure if the version is below 18:

find_package(LLVM REQUIRED CONFIG)
if(LLVM_PACKAGE_VERSION VERSION_LESS 18)
    message(FATAL_ERROR
        "Tero requires LLVM >= 18 (found ${LLVM_PACKAGE_VERSION})")
endif()

See Design decisions and IR and LLVM JIT for the rationale.

Optional tools

Tool Minimum version Notes
Python 3.10+ Only needed to build the documentation site (MkDocs Material).
Doxygen 1.9+ Optional — required only when building the C++ API reference.
doxybook2 1.5+ Optional — converts Doxygen XML to Markdown for the site.
RCC 1.3.2 Gaisler SPARC cross-toolchain; needed only to build RTEMS guests and to run GDB-interop tests. See RTEMS cross-toolchain.

Choose your toolchain path

Install the toolchain from your distribution, then build with CMake presets (see Cloning and Building).

Fedora 41+ / RHEL 10+

sudo dnf install cmake ninja-build gcc-c++ llvm-devel git \
                 python3 doxygen ncurses-compat-libs

llvm-devel provides the LLVM headers and the CMake config package (find_package(LLVM CONFIG)); on Fedora it tracks a recent LLVM (≥ 18). ncurses-compat-libs provides libtinfo.so.5, required by the Cobham Gaisler RCC 1.3.2 cross-debugger (sparc-gaisler-rtems5-gdb); without it the GDB-interop test SKIPs cleanly but does not run.

Ubuntu 24.04 / 24.10 / 26.04

sudo apt install cmake ninja-build g++ llvm-18-dev git \
                 python3 doxygen libtinfo5

llvm-18-dev (or any llvm-N-dev with N ≥ 18) provides the LLVM CMake config package. If the default llvm-dev on your release is older than 18, install the versioned package and point CMake at it with -DLLVM_DIR=/usr/lib/llvm-18/lib/cmake/llvm. On Ubuntu 24.04 the GDB runtime package is libtinfo5; on 26.04 it may have moved to libtinfo6 — install whichever provides the .so the GDB binary needs.

macOS (Homebrew)

brew install cmake ninja llvm git python doxygen

macOS builds are functional but not CI-validated. Point CMake at the Homebrew LLVM if find_package does not pick it up, e.g. -DLLVM_DIR="$(brew --prefix llvm)/lib/cmake/llvm". The SPARC cross-toolchain is Linux-only.

The repo includes a flake.nix that provides a reproducible alternative to installing the toolchain manually. It pins GCC, LLVM, CMake, Ninja, the LSP/clang-tools, and the docs toolchain to known-good versions:

# Enter the dev shell (first run downloads the pinned toolchain):
nix develop

# With direnv (automatic shell activation on cd):
#   1. Install nix-direnv: https://github.com/nix-community/nix-direnv
#   2. direnv allow        # (once, in the repo root)

The Nix shell includes: GCC 14, LLVM 19 (the mandatory JIT backend, with LLVM_DIR pre-set so find_package(LLVM CONFIG) resolves immediately), CMake, Ninja, clangd, clang-tidy, lcov, Doxygen, Python 3.13, and ncurses5 (libtinfo.so.5, so the GDB-interop test can run instead of skipping). Zensical (the docs site generator) is not yet in nixpkgs — install it with pip install -r docs/requirements.txt once inside the shell.

Nix pins the toolchain, not the C++ libraries

fmt, tl::expected and Catch2 are still fetched by CMake (FetchContent) inside the nix shell. Nix only guarantees a reproducible compiler/build-tool environment; the libraries are pinned by the GIT_TAG values in CMakeLists.txt.

RTEMS cross-toolchain

For full test coverage (RTEMS boot, sptests, GDB interop) and to build your own RTEMS guests, install the Cobham Gaisler RCC 1.3.2 toolchain and put sparc-gaisler-rtems5-gcc and sparc-gaisler-rtems5-gdb on PATH. The default install prefix the build scripts expect is /opt/rcc-1.3.2-gcc/. RCC 1.3.2 ships RTEMS 5.x. See First RTEMS boot and Testing for details on the conditional test skips that fire when the toolchain is absent.

Cloning

git clone https://github.com/claaj/tero.git
cd tero

Tero has three automatically-fetched C++ libraries and one vendored dependency:

Dependency Version How it arrives
tl::expected v1.1.0 FetchContent (CMakeLists.txt) — C++20 stand-in for std::expected.
fmt 10.2.1 FetchContent — type-safe formatting/logging.
Catch2 v3.5.3 FetchContent — only when TERO_BUILD_TESTS=ON.
Berkeley SoftFloat 3e vendored third-party/softfloat3e/ (BSD-3-Clause) — FPU backend.

The three fetched libraries are pinned to the tags above in CMakeLists.txt and downloaded on the first cmake configure; later builds reuse the contents of build/_deps/.

LLVM (≥ 18) must be installed before configuring — it is linked into tero_jit and is the one non-fetched, non-vendored dependency. Whether tero-emu also needs the LLVM shared library at run time depends on how your host packages LLVM (static component archives vs. libLLVM.so). The only other external runtime library is libtinfo.so.5, used by the SPARC GDB cross-debugger; everything else is header-only or statically linked.

Building

The repo ships CMake presets (CMakePresets.json). The default preset is a RelWithDebInfo Ninja build into build/ and matches CI:

cmake --preset default
cmake --build --preset default
cmake -S . -B build -G Ninja
cmake --build build

Both produce the same tree. The build emits:

  • build/src/app/tero-emu — the standalone CLI (CLI reference)
  • build/src/runtime/libtero_runtime.a — the runtime library to embed
  • build/examples/hello-gr712rc/hello-gr712rc, .../hello-gr740, .../gdb-demo/gdb-demo — the worked examples
  • build/tests/... — Catch2 test executables (when TERO_BUILD_TESTS=ON)

Available presets

Preset Build dir Purpose
default build/ RelWithDebInfo, Ninja. Standard developer build; matches CI.
bench-profile build-bench-profile/ RelWithDebInfo plus -fno-omit-frame-pointer -gdwarf-4 for perf record + FlameGraph profiling. Costs ~1–3% throughput; do not use for normal development. Builds the tero_bench and sparc_test_binaries targets.

CMake options

Option Default Effect
TERO_BUILD_TESTS ON Builds Catch2 + the unit/integration test tree. Turn OFF to skip fetching Catch2 entirely.
TERO_OPCODE_HISTOGRAM OFF Phase 9.4 instrumentation: per-core SPARC InsnKind execution counters. Zero overhead when off; turn on only for profiling.
CMAKE_BUILD_TYPE RelWithDebInfo Toggle Debug, Release, etc.
LLVM_DIR (auto) Point find_package(LLVM CONFIG) at a specific LLVM install, e.g. /usr/lib/llvm-18/lib/cmake/llvm.

Example debug build with opcode histograms:

cmake -S . -B build-debug -G Ninja \
      -DCMAKE_BUILD_TYPE=Debug \
      -DTERO_OPCODE_HISTOGRAM=ON
cmake --build build-debug --target tero-emu

Warnings are errors

The project compiles with -Wall -Wextra -Wpedantic -Werror (plus -Wshadow, -Wconversion, and friends). A warning from your compiler will fail the build — this is intentional. If a new compiler version surfaces a warning in third-party code, report it.

Verifying

ctest --test-dir build --output-on-failure

Expected outcome: all tests pass with a small number of conditional skips that fire only when external artifacts are unavailable — the GDB interop test (no sparc-gaisler-rtems5-gdb), the RTEMS boot test (no pre-built RTEMS ELFs), and the RTEMS-aware live-guest test (no nm). All other tests are unconditional. The suite also covers the binary-translation path: IR/JIT lockstep against the interpreter plus a sanitiser-clean tero_jit_tests executable.

To run a focused subset:

ctest --test-dir build -R rtems_sptests --output-on-failure   # RTEMS sptests only
ctest --test-dir build -j 4                                    # parallel

Pass counts under heavy parallel load

Some timing-sensitive tests (e.g. the realtime-pacing test, certain SMP tests) can become flaky when ctest -j N saturates every host core or the machine is thermally throttled. Re-run a suspect test in isolation before treating it as a regression.

Building the documentation locally

python3 -m venv .venv
source .venv/bin/activate
pip install -r docs/requirements.txt

# 1. C++ API extraction (optional, requires doxygen + doxybook2):
doxygen docs/Doxyfile
doxybook2 --input build/doxygen/xml --output docs/api --config docs/doxybook2.json

# 2. Render and serve:
zensical serve

Open http://127.0.0.1:8000/ for the live preview. zensical build produces a static site/ directory ready for GitHub Pages, S3 or any plain static host. (In the nix develop shell, run pip install -r docs/requirements.txt first — see the note below.)

Troubleshooting

Symptom Cause Fix
Could NOT find LLVM (missing: LLVM_DIR) LLVM dev libraries not installed, or not discoverable. Install llvm-devel / llvm-18-dev, or pass -DLLVM_DIR=<path>/lib/cmake/llvm.
Tero requires LLVM >= 18 (found 17.x) Found LLVM is too old. Install a versioned package (llvm-18-dev) and point LLVM_DIR at it.
CMake 3.25 or higher is required Distro CMake is older. Use pip install cmake, the Kitware APT repo, or nix develop.
C++20 errors (std::span not found, concepts rejected) Compiler too old. Upgrade to GCC ≥ 13 / Clang ≥ 17, or set CC/CXX to a newer toolchain.
FetchContent clone fails No internet on first configure, or git missing. Configure once with network access; build/_deps/ is then reusable offline.
GDB-interop test SKIPs sparc-gaisler-rtems5-gdb and/or libtinfo.so.5 absent. Install RCC 1.3.2 and the ncurses-compat package; the skip is benign otherwise.
RTEMS boot / sptest tests SKIP Pre-built RTEMS ELFs not present. They are gitignored and built locally; see First RTEMS boot.

Next: the Quickstart runs your first SPARC instruction in under five minutes.