Linters are tools that analyze the code and warn about bugs & style issues. Utilising such tools can help improve code quality and enforce a consistent style which can help with code maintainability and bug fixing, especially where multiple developers are likely to be maintaining the code.

This guide shows how to utilise the clang linter.

Install clang-format-linter locally

A custom local install of the linter for C, C++, Python and Bash/POSIX shell can be easily done.

On an Apertis image or on Debian install the relevant packages:

apt install arcanist-clang-format-linter pep8 shellcheck

Check the installation:

arc linters  # should list ‘clang-format’ as ‘configured’

Add a .clang-format file

clang-format accepts its format options from a hidden file, defined in YAML format. Create .clang-format and commit it to git:

BasedOnStyle: GNU
AlwaysBreakAfterDefinitionReturnType: All
BreakBeforeBinaryOperators: None
BinPackParameters: false
SpaceAfterCStyleCast: true

These are the current recommended formatting options from the coding conventions, but may change in future as clang-format evolves or corner cases in the configuration are found and fixed.

Add a .arclint file

To enable the linters to be used with arc lint, add a .arclint file to the project and commit it to git. This example file contains XML, Python and C linters. Note that you should adjust the include path for the clang-format-default linter to include the source directories in your project, while excluding any generated C or H files.

  "linters": {
    "clang-format-default": {
      "type": "clang-format",
      "version": ">=3.7.0",
      "include": "(^(src|tests|canterbury)/.*\\.(c|h)$)"
    "pep8-default": {
      "type": "pep8",
      "flags": ["--ignore=E402"],
      "include": "(\\.py$)"
    "xml-default": {
      "type": "xml",
      "include": "(\\.xml$)"
    "shellcheck-default": {
      "type": "script-and-regex",
      "script-and-regex.script": "sh -c '[ $(file --mime-type -b \"$1\") = \"text/x-shellscript\" ] && shellcheck --format gcc \"$1\" || true' sh-c",
      "script-and-regex.regex": "/^(?P<file>.*):(?P<line>\\d+):(?P<char>\\d+): (?P<message>.*) (?P<warning>\\[)(?P<code>SC\\d+)\\]$/m"

We ignore PEP8 error E402 because the recommended copyright headers, editor modelines and encoding lines push the first import statement below the recommended line number according to PEP8.

Add a .gitlab-ci.yml file

To run the linters automatically on GitLab CI as soon as a Merge Request is created, add a .gitlab-ci.yml file to the project:

  image: debian:buster
  stage: build
    - export DEBIAN_FRONTEND=noninteractive
    - apt update
    - apt install -y git-core arcanist-clang-format-linter pep8 shellcheck
    - cd "$CI_PROJECT_DIR"
    - arc lint --rev "$(git merge-base origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME HEAD)" --never-apply-patches
    - merge_requests