Sign inSign up

gilleshenrard/c-linters

By gilleshenrard

•Updated 3 days ago

C static analysis Docker image — CppCheck, Clang-Tidy, Clang-Format, Lizard, REUSE and Doxygen.

Image
Developer tools
0

10K+

gilleshenrard/c-linters repository overview

⁠C Linting & Analysis Docker Image

License: MIT

A ready-to-use Docker image bundling several widely-used linters and documentation tools for C/C++ projects. Use it to run static analysis, format checks, complexity measurement, license compliance checks, and documentation generation — either as one-off local commands or as steps in a CI pipeline — without installing or version-managing each tool yourself.

Github: gilleshenrard/docker-c-linters⁠

DockerHub: gilleshenrard/docker-c-linters/general⁠

⁠Included Tools

Maintainer note: Tool versions are hardcoded in this README. Remember to update this table whenever versions are bumped in the Dockerfile.

ToolVersionPurpose
CppCheck⁠2.22.0Static analysis
Clang-Format⁠22.1.8Code formatting
Clang-Tidy⁠22.1.8Linting and static analysis
run-clang-tidy⁠22.1.8Parallel Clang-Tidy runner
Lizard⁠1.24.0Cyclomatic complexity measurement
REUSE⁠6.2.0SPDX license compliance checker
Doxygen⁠1.18.0Documentation generation

⁠Pulling the Image

The image is hosted on Docker Hub and can be pulled with:

docker pull gilleshenrard/c-linters:latest

⁠Usage

⁠Run a one-off tool
# Static analysis
docker run --rm -v "$(pwd)":/src c-linters:latest cppcheck --enable=all /src
docker run --rm -v "$(pwd)":/src c-linters:latest run-clang-tidy -p build/
 
# Format check
docker run --rm -v "$(pwd)":/src c-linters:latest clang-format --dry-run --Werror /src/main.c
 
# Complexity report
docker run --rm -v "$(pwd)":/src c-linters:latest lizard /src
 
# License compliance
docker run --rm -v "$(pwd)":/src c-linters:latest reuse lint
⁠Interactive shell
docker run --rm -it -v "$(pwd)":/src c-linters:latest bash

⁠GitHub Actions Integration

jobs:
  lint:
    runs-on: ubuntu-latest
    container:
      image: gilleshenrard/c-linters:latest
 
    steps:
      - uses: actions/checkout@v7
 
      - name: Static analysis (CppCheck)
        run: cppcheck --enable=all --error-exitcode=1 src/
 
      - name: Format check (Clang-Format)
        run: |
          find src/ -name '*.c' -o -name '*.h' | \
          xargs clang-format --dry-run --Werror
 
      - name: Linting (Clang-Tidy)
        run: run-clang-tidy -p build/
 
      - name: Complexity (Lizard)
        run: lizard src/ --CCN 10 --length 50 --arguments 5
 
      - name: License compliance (REUSE)
        run: reuse lint
 
      - name: Documentation (Doxygen)
        run: doxygen Doxyfile

⁠Building the Image

docker build -t c-linters:latest .
⁠Overriding Tool Versions

All versions are declared as ARG at the top of the Dockerfile and can be overridden at build time:

docker build \
  --build-arg CPPCHECKVERSION="2.21.0" \
  --build-arg CLANGVERSION="22.2.0" \
  --build-arg LIZARDVERSION="1.23.1" \
  --build-arg REUSEVERSION="6.3.0" \
  --build-arg DOXYGENVERSION="1.18.0" \
  -t c-linters:latest .

⁠Vulnerability Scanning

Vulnerabilities can be checked using Docker Scout⁠.

Note: Scout caches SBOMs locally, keyed by image digest. When re-scanning a freshly rebuilt image under the same tag, clear the cache first to avoid stale results.

# Clear Scout's local SBOM cache (non-interactive)
docker scout cache prune --sboms --force

# Generate a CVE report in Markdown format
docker scout cves c-linters:latest --format markdown --output <image_name>_report.md

Warning

**Residual vulnerabilities are expected and are not fixable from this image.** The overwhelming majority of CVEs flagged by Docker Scout come from OS-level packages that are part of the `debian:trixie-slim` base image itself, not from anything installed by this Dockerfile. These vulnerabilities remain until Debian's security team ships a patch upstream; no build-arg override, `apt` flag, or workaround in this repository can resolve them. Rebuilding the image regularly will pick up upstream fixes as they become available, but a completely clean Scout report should **not** be expected as a baseline for this image.

In practice, the security impact of this is limited: this image is meant to be run as a one-off tool (docker run --rm ...) rather than as a long-lived service, which significantly reduces the exposure window and attack surface these base-image CVEs would otherwise represent.

⁠Tracing a Flagged Package's Origin

To find out which installed package pulled in a given vulnerable dependency (e.g. a package named in a Scout report), run the following against the built image, not a fresh base image (dependency resolution can otherwise differ from what was actually installed):

# 1. Scout's report may name a bare library (e.g. "tiff"); find the actual installed
#    Debian package name, since it is often versioned or prefixed differently (e.g.
#    "libtiff6")
docker run --rm c-linters:latest bash -c "dpkg -l | grep -i <package>"

# 2. Once you have the real package name, trace which installed package depends on it
docker run --rm c-linters:latest bash -c \
  "apt-get update -qq && apt-get install -y aptitude >/dev/null 2>&1 && aptitude why <real_package_name>"

⁠Image Architecture

The image uses a two-stage build to keep the final image lean:

+-----------------------------------------------+
| Stage 1 : build (based on debian:trixie-slim) |
|                                               |
|  - Build CppCheck from source                 |
|  - Extract Clang binaries from LLVM release   |
|  - Install Doxygen from its Github repo       |
|  - Install Lizard + REUSE in Python venv      |
+------------------------|----------------------+
                         | COPY /opt
+------------------------|----------------------+
| Stage 2 : run (based on debian:trixie-slim)   |
|                                               |
|  - Minimal packages needed to run the tools   |
|  - Additional tools: git, graphviz            |
|  - Append tool paths to PATH                  |
+-----------------------------------------------+

No build toolchain (cmake, ninja, wget, gcc…) is present in the final image.

⁠Tool Locations at Runtime

PathContents
/opt/cppcheck/bin/cppcheck binary
/opt/clang/bin/clang-format, clang-tidy, run-clang-tidy
/opt/clang/lib/clang/22/Clang built-in headers
/opt/pip-packages/bin/lizard, reuse
/opt/doxygen/bin/doxygen

All of the above are appended to PATH, so every tool is callable directly by name.

⁠Versioning

Image tags and GitHub releases follow Semantic Versioning⁠ (vMAJOR.MINOR.PATCH):

  • MAJOR — a tool was added or removed, or the image's architecture changed in a way that can break existing usage.

  • MINOR — a pinned tool version was bumped (e.g. a newer Clang-Tidy). The tool is still invoked the same way, but its behavior may have evolved (for example, new warnings may fire that didn't before).

  • PATCH — a bug fix, or an automated rebuild that picked up an upstream security fix in the base image. Patch releases may occur with no visible change to this repository's source, since they can be triggered solely by Debian shipping a fix for a previously unfixable CVE.

⁠License

This Dockerfile is distributed under the MIT License⁠.
© 2026 Gilles Henrard [email protected]⁠

Tag summary

Content type

Image

Digest

sha256:74e63bad7…

Size

248.1 MB

Last updated

3 days ago

docker pull gilleshenrard/c-linters