host.toolchain

Per-host toolchain configuration for coverage and build tools.

Each UnixHost carries a Toolchain that describes where lcov, gcov, and the compiler live. Tool paths are stored relative to the sysroot so that a single sysroot change is enough to switch an entire cross-toolchain.

Sensible defaults (sysroot='/', tools under usr/bin/) mean hosts with system-installed toolchains need no configuration at all.

class otto.host.toolchain.Toolchain(sysroot: Path = PosixPath('/'), lcov: Path = PosixPath('usr/bin/lcov'), gcov: Path = PosixPath('usr/bin/gcov'))

Bases: object

Describes the toolchain associated with a host’s products.

Variables:
sysroot : pathlib.Path

Root directory of the toolchain installation. Defaults to / (system toolchain).

lcov : pathlib.Path

Path to the lcov binary, relative to sysroot.

gcov : pathlib.Path

Path to the gcov binary (or an llvm-cov wrapper), relative to sysroot.

sysroot : Path

Root directory of the toolchain installation.

lcov : Path

Path to lcov, relative to sysroot.

gcov : Path

Path to gcov (or llvm-cov wrapper), relative to sysroot.

property lcov_bin : str

Absolute path to the lcov binary.

property gcov_bin : str

Absolute path to the gcov binary.

property compiler : Path | None

Derive the compiler path from the gcov path.

For GCC toolchains the gcov binary name mirrors the compiler (e.g. arm-linux-gnueabihf-gcovarm-linux-gnueabihf-gcc).

For Clang/LLVM toolchains where the gcov path contains llvm-cov, the compiler is assumed to be clang in the same directory.

Returns None when the compiler cannot be inferred.

host.toolchain_discovery

Resolve the gcov tool family from .gcno files.

A .gcno embeds no compiler path, but its 8-byte header carries the gcov format version stamp the producing compiler wrote: GCC stamps its own release (B33* for 13.3), while clang --coverage always stamps the GCC 4.8-era 408* (402* on old LLVM) it emulates. That stamp is the one reliable family signal:

  • GCC stamp — the default (or host-configured) gcov applies; a cross toolchain cannot be located from the .gcno alone and must be named in the host’s toolchain configuration.

  • LLVM stamp — GNU gcov refuses (or worse, crashes on) clang’s files; the counters must be read by llvm-cov gcov, which is resolved from PATH here.

lcov --gcov-tool takes a single command, but Clang’s reader is the two-word llvm-cov gcovensure_gcov_tool() bridges that with a generated one-word wrapper script at capture time.

otto.host.toolchain_discovery.read_gcno_version(gcno: Path) str | None

Return a .gcno’s 4-char version stamp (e.g. 'B33*', '408*').

Handles both byte orders: a little-endian target stores the magic as oncg and the stamp characters reversed; a big-endian target stores gcno and the stamp as-is. Returns None for anything unreadable or not a .gcno.

otto.host.toolchain_discovery.discover_toolchain_from_gcno(gcno_dir: Path) Toolchain | None

Infer the gcov tool family from the .gcno files under gcno_dir.

Reads the version stamp of a small sample of .gcno files. A clang stamp resolves to an llvm-cov from PATH; a GCC stamp returns None (the caller’s default gcov already matches same-host GCC builds, and a mismatched cross build fails loudly at capture with CoverageToolVersionError).

Parameters:

gcno_dir – Directory tree containing the build’s .gcno files.

Returns:

A Toolchain pointing at llvm-cov for clang builds, None otherwise.

otto.host.toolchain_discovery.ensure_gcov_tool(gcov: str, work_dir: Path) str

Return gcov as a single-command tool that lcov --gcov-tool can exec.

llvm-cov is gcov-compatible only through its gcov subcommand, and lcov rejects a two-word tool (“cannot access gcov tool”). When gcov names an llvm-cov binary, write (idempotently) and return a one-word wrapper script in work_dir that execs <llvm-cov> gcov; every other tool passes through unchanged.