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+¶
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¶
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)¶
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¶
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:
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 embedbuild/examples/hello-gr712rc/hello-gr712rc,.../hello-gr740,.../gdb-demo/gdb-demo— the worked examplesbuild/tests/...— Catch2 test executables (whenTERO_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¶
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.