Formatters and Linters

Section author: Simeon Ehrig

Pre-commit

This project is set up for use with pre-commit. Using it will make your code conform with most of our (easily automatable) code style guidelines automatically. Pre-commit is a tool that manages git hooks conveniently for you. In very short (for anything further see pre-commit), after running the following in your working clone of alpaka

# if not yet done, install the pre-commit executable following https://pre-commit.com
cd /path/to/alpaka-working-clone
pre-commit install

git will run a number of checks prior to every commit and push and will refuse to perform the pertinent action if they fail. Most of them (like e.g. the formatter) will have automatically altered your working tree with the necessary changes such that

git add -u

will make the next commit pass. Although discouraged, in urgent cases it might be needed to be able to commit even if the checks fail. For such cases, you can either use

git commit --no-verify [...]

to completely skip all checks or use the more fine-grained control described here.

You can use

pre-commit run --all-files

to run all the hooks on all files.

Formatting

This section lists all formatters used in the alpaka project. Normally, you should use pre-commit to format your source code. If you want to format your code without pre-commit, e.g., automatically in your IDE, you will find all the necessary information in the following sections.

To get exactly the same formatted code as expected in CI, you must use the same formatting version locally as in CI. The specific formatting versions can be found in the .pre-commit-config.yaml file, see Formatter versions.

C++: Clang-Format

For C++ code, we use clang-format to format the code. Our style guide for C++ code is defined in the .clang-format file, which is provided in the top-level directory of alpaka.

CMake: Gersemi

The CMake code is formatted with gersemi.

Formatter versions

.pre-commit-config.yaml
minimum_pre_commit_version: 3.2.0 # necessitated by Lucas-C's hooks
default_install_hook_types: [pre-commit, pre-push]
exclude: "thirdParty"
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
  rev: v20.1.8
  hooks:
  - id: clang-format
    files: \.(cpp|hpp)
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v6.0.0
  hooks:
  - id: no-commit-to-branch
    args: [-b, develop]
  - id: check-merge-conflict
  - id: trailing-whitespace
    exclude_types: [markdown, rst]
  - id: end-of-file-fixer
    exclude_types: [svg]
  - id: check-yaml
  - id: mixed-line-ending
  - id: check-executables-have-shebangs
  - id: check-shebang-scripts-are-executable
- repo: https://github.com/Lucas-C/pre-commit-hooks
  rev: v1.5.5
  hooks:
    - id: forbid-tabs
      types_or: [file]
      exclude_types: [rst]
    - id: remove-tabs
      types_or: [file]
      exclude_types: [rst]
    - id: forbid-crlf
    - id: remove-crlf
- repo: https://github.com/BlankSpruce/gersemi
  rev: 0.22.1
  hooks:
    - id: gersemi
      args: [-c, --diff]
    - id: gersemi
      args: [-i]
- repo: https://github.com/scop/pre-commit-shfmt
  rev: v3.13.1-1
  hooks:
    - id: shfmt
- repo: https://github.com/shellcheck-py/shellcheck-py
  rev: v0.11.0.1
  hooks:
    - id: shellcheck
      # required that shellcheck can follow sourced scripts
      args: [-x]
- repo: local
  hooks:
    - id: ascii-check
      name: ASCII check
      entry: python3 script/git_pre_commit/check_for_non_ascii.py
      language: system
      files: \.(c|cc|cpp|cxx|cu|h|hh|hpp|hxx|cuh)$
- repo: local
  hooks:
    - id: pragma-once
      name: "Check #pragma once"
      entry: script/git_pre_commit/check_pragma_once.sh
      language: system
      files: \.hpp$
- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.15.21
  hooks:
    - id: ruff
      types_or: [ python, pyi, jupyter ]
      # The ignores in here are chosen to conform with the currently
      # existing code and not motivated any other way.
      args: [ --fix]
    - id: ruff-format
      types_or: [ python, pyi, jupyter ]
      args: ["--line-length", "120"]
- repo: local
  hooks:
    - id: pylint
      name: pylint
      entry: pylint
      language: python
      types: [python]
      additional_dependencies: [pylint]
      require_serial: true
      args:
        [
          "-rn", # Only display messages
          "-sn", # Don't display the score
        ]
      # source: https://github.com/pre-commit/pre-commit/issues/1470#issuecomment-634381955
      exclude: |
          (?x)(
              ^docs/
          )
-   repo: https://github.com/pre-commit/mirrors-mypy
    rev: 'v2.3.0'
    hooks:
    - id: mypy
      exclude: |
          (?x)(
              ^docs/
          )

Code Changes with Tools

In the alpaka project, we use many tools for developers. One type of these tools are formatting programs for C++ code, CMake code, and more. If a commit contains code changes created by a formatting program, the author of the commit should not be a real person. Instead of a real person, a non-existent tool author should be used. The reason for this approach is that we can use git blame to distinguish between what is a functional change in the code and what has only been formatted.

The tool author can be set with git commit --author="Tools <alpaka@hzdr.de>" when the commit is created.

If a commit contains code changes and reformatted code, it must be split into two commits. The first commit with the code changes (e.g., changing the formatter configuration) is created with the developer’s normal authorship. The second commit contains only the changes made by the tool and has tool as the authorship.

This PR shows how the changes are split into two commits: https://github.com/alpaka-group/alpaka3/pull/237