Share a Cppcheck HTML report

Static analysis on a C or C++ codebase produces two things: a genuinely useful list of defects, and an argument about which of them are real. The second is where the value leaks out, because the argument happens in a place with no access to the first.

Cppcheck's HTML generator exists precisely to make the findings arguable — each one rendered inside the function it occurs in, with the surrounding lines.

cppcheck --enable=all --inconclusive --xml --xml-version=2 src/ 2> cppcheck.xml
cppcheck-htmlreport --file=cppcheck.xml --report-dir=cppcheck-report --source-dir=.
cppcheck-report/
├── index.html      # findings grouped by file and severity
├── 0.html 1.html   # one page per source file, code inline
└── style.css

Two details that trip people up: the XML goes to stderr, not stdout, and --source-dir must point at the root the XML paths resolve against — get it wrong and every finding renders with no code under it.

Publish the folder

Drag cppcheck-report/ (or a zip of it) into Comma:

  • index.html becomes the report body.
  • Per-file pages and the stylesheet upload alongside it, with relative references rewritten to the uploaded copies, so clicking a finding opens the source it is in.
  • Scripts run inside a sandboxed iframe (allow-scripts, no allow-same-origin).

One URL, openable by a reviewer who has no toolchain, no compile_commands.json, and no intention of building your project to look at a warning.

From CI

cppcheck --enable=all --xml --xml-version=2 \
  --project=build/compile_commands.json 2> cppcheck.xml
cppcheck-htmlreport --file=cppcheck.xml --report-dir=cppcheck-report --source-dir=.

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html cppcheck-report/index.html \
        --arg t "Static analysis — $(git rev-parse --short HEAD)" \
        '{title: $t, html: $html}')"

Using --project=compile_commands.json gets the include paths and defines right, which is most of the difference between a useful run and three hundred missingInclude notes. Supporting pages go up through POST /api/v1/reports/$REPORT_ID/assets as base64 — see the API reference and publishing from CI.

Triage is the product

The reason a static-analysis rollout stalls is that triage decisions have nowhere to live. A finding is marked false-positive in one engineer's head, the next release reports it again, and the team concludes the tool is noisy.

Anchored comments put the verdict on the finding: "false positive — p is checked in the caller, see net_recv". It stays there across republishes, so the second reviewer reads the decision instead of repeating the analysis. See commenting on HTML, and revisions for tracking the count across releases.

Who can see it

Per report: private, your team, anyone signed in at your domain, or anyone with the link. Static-analysis output contains source excerpts and hints at exploitable defects — keep it restricted. See sharing & access control.

Limits

  • Entry HTML: 5 MB. Assets: 25 MB per file, 250 MB and 500 files total. A large tree can exceed 500 pages — run per component, which is how most teams triage anyway.
  • Scripts run, sandboxed — no same-origin access.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish an analysis report →

Related