Clang Products¶
Products compiled with clang --coverage emit gcov-compatible
counters in the GCC 4.8-era file format (clang stamps 408*), which
modern GNU gcov refuses. They must be read by llvm-cov gcov:
Auto-discovery: with
llvm-cov(or a versionedllvm-cov-<N>) onPATH, otto detects the clang stamp and uses it automatically — no configuration needed.Explicit config: point the host toolchain’s
gcovat anllvm-covbinary; otto substitutes the required one-wordllvm-cov gcovwrapper forlcov --gcov-toolat capture time.
{
"toolchain": {
"sysroot": "/usr/lib/llvm-18",
"gcov": "bin/llvm-cov"
}
}
Warning
Do not force clang to imitate a GCC version stamp
(-Xclang -coverage-version=…): clang still writes its own record
layout, and GNU gcov trusts the stamp — it crashes or silently emits
empty data. Let otto route clang counters through llvm-cov instead.
Branch coverage (BRDA records) flows through the llvm path as well;
note that llvm-cov’s branch counts are coarser than GNU gcov’s
(hit/not-hit is reliable, exact execution counts may differ).
The otto host needs llvm-cov installed (the llvm package) in addition
to the lcov prerequisite from the main Coverage Collection page.
Stale deploys: why the GCC stamp guard doesn’t transfer¶
The .gcno stamp guard from the GCC page does not transfer to clang, because clang’s stamp behaves differently — so otto verifies the pairing itself, at collection:
The stamp is a hash of the program’s structure, not a per-compilation value. Rebuilding unchanged code reproduces the identical stamp, so a rebuild between deploy and collection is harmless — under GCC the same rebuild invalidates every previously shipped binary.
A stale deploy fails silently at the toolchain level — so otto checks the files directly. When the shipped binary’s code differs from the current
.gcno,llvm-cov gcovrejects the counters (“file checksums do not match” / “Invalid .gcda File!”) but still exits 0, and throughlcovthe affected files come back with all-zero hit counts and no error text at all — nothing to parse. otto therefore verifies the pairing structurally before invokinglcov: the 12-byte header stamps must agree, and — because clang’s structure stamp survives edits that merely shift lines (a comment or#includeadded above the code) — every function record in the.gcda(ident plus line-number and control-flow checksums, the same tripletllvm-covverifies) must appear in the.gcno. Either disagreement fails collection with the same friendly stamp-mismatch error GCC products get, naming the files; the remedy is the usual one — redeploy the current build and re-collect.One drift stays invisible to any gcov-level check: an in-place edit that changes neither control flow nor line positions (tweaking a constant).
llvm-covaccepts the stale binary’s counters as valid, and the files genuinely carry nothing to tell the difference; in otto’s e2e flow the base_commit guard is what covers that class.There is no ship-step binary scan for clang. clang does not lay out a
gcov_infostruct; the stamp is an inline constant in generated code, so the GCC page’s build-time scan has no anchor — the collection-time check above is the guard.