Skip to main content

pre-commit hooks for CMake based projects

Project description

pre-commit hooks

PyPI - Python Version PyPI version CI Build CodeQL pre-commit.ci status

This is a pre-commit hooks repo that integrates C/C++ linters/formatters to work with CMake-based projects.

clang-format, clang-tidy, cppcheck, cpplint, lizard and iwyu

It is largely based on the work found here. The main difference with POCC's pre-commit hooks is that the ones from this repository will do a CMake configuration step prior to running any pre-commit hooks. This is done in order to have CMake generate the compilation database file that can then be used by the various hooks (using the -DCMAKE_EXPORT_COMPILE_COMMANDS=ON CMake option).

This repository is only has Python-based pre-commit hooks.

Current known issues

Currently, the hooks that depend on having a compilation database generated by CMake (e.g. clang-tidy, cppcheck) are not working on Windows if you are not using the Ninja or Makefile generators.

Example usage

Assuming that you have the following directory structure for your projects

root
├── .pre-commit-config.yaml
├── CMakeLists.txt
└── src
    └── err.cpp

with the following file contents:

.pre-commit-config.yaml

repos:
  - repo: https://github.com/Takishima/cmake-pre-commit-hooks
    rev: 1.0.0
    hooks:
      - id: clang-format
      - id: clang-tidy
        args: [--checks=readability-magic-numbers,--warnings-as-errors=*]
      - id: cppcheck
      - id: include-what-you-use

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)
project(LANGUAGE CXX)
add_library(mylib STATIC src/err.cpp)

src/err.cpp

#include <string>
int main() { int i; return 10; }

Running pre-commit on the above project will lead to an output similar to this one:

$ pre-commit run --all-files
clang-format.............................................................Failed
- hook id: clang-format
- exit code: 1

src/err.cpp
====================
<  int main() { int i; return 10; }
---
>  int main() {
>    int i;
>    return 10;
>  }

clang-tidy...............................................................Failed
- hook id: clang-tidy
- exit code: 1

/tmp/temp/src/err.cpp:2:28: error: 10 is a magic number; consider replacing it with a named constant [readability-magic-numbers,-warnings-as-errors]
int main() { int i; return 10; }
                           ^

cppcheck.................................................................Failed
- hook id: cppcheck
- exit code: 1

/tmp/temp/src/err.cpp:2:18: style: Unused variable: i [unusedVariable]
int main() { int i; return 10; }
                 ^
include-what-you-use.....................................................Failed
- hook id: include-what-you-use
- exit code: 1

Problem with /usr/local/bin/iwyu_tool.py: Include-What-You-Use violations found

/tmp/temp/src/err.cpp should add these lines:
/tmp/temp/src/err.cpp should remove these lines:
- #include <string>  // lines 1-1
The full include-list for /tmp/temp/src/err.cpp:
---

Note that your mileage may vary depending on the version of the tools. The example above was generated using clang-format 12.0.0, clang-tidy 12.0.0, cppcheck 2.4.1 and include-what-you-use 0.16.

Using the Hooks

Python 3.6+ is required to use these hooks as all 3 invoking scripts are written in it. As this is also the minimum version of pre-commit, this should not be an issue.

Running multiple hooks in parallel is currently supported by using the fastener Python package. If the hooks are run in parallel, only one of the hooks will run the CMake configure step while the others will simply wait until the call to CMake ends to continue. In the case where the hooks are run serially, all the hooks will be running the CMake configure step. However, if nothing changed in your CMake configuration, this should not cost too much time.

Installation

For installing the various utilities, refer to your package manager documentation. Some guidance can also be found here.

Hook Info

Hook Info Type Languages
clang-format Formatter C, C++, ObjC
clang-tidy Static code analyzer C, C++, ObjC
cppcheck Static code analyzer C, C++
cpplint Static code analyzer C, C++
include-what-you-use Static code analyzer C, C++
lizard code complexity analyzer C/C++, ObjC, ...

Hook options

Since v1.1.0 all hooks that depend on a compilation database (e.g. clang-tidy, cppcheck, include-what-you-use) will attempt to generate a CMake build directory before running the actual command.

These hooks accept all the most common CMake options:

CMake options Description
-S <path-to-source> Explicitly specify a source directory.
-B <path-to-build> Explicitly specify a build directory.
-D <var>[:<type>]=<value> Create or update a cmake cache entry.
-U <globbing_expr> Remove matching entries from CMake cache.
-G <generator-name> Specify a build system generator.
-T <toolset-name> Specify toolset name if supported by generator.
-A <platform-name> Specify platform name if supported by generator.
-Wdev Enable developer warnings.
-Wno-dev Suppress developer warnings.
-Werror=dev Make developer warnings errors.
-Wno-error=dev Make developer warnings not errors.

One important thing to note (particularly for those that intend to use this on CIs), you may specify the build directory argument (-B) multiple times. The hooks will then simply cycle through all of the values provided and choose the first directory that contains a configured CMake project (by looking at the presence of the CMakeCache.txt file). This may be useful if you already have a build directory available somewhere that you would like to re-use. In the case where none of the provided options is viable, the first one will automatically be selected as the build directory.

In addition to the above CMake options, the hooks also accept the following:

Other hook options Description Note
--all-at-once Pass all filenames to the command at once Since v1.4.0
--cmake Specify path to CMake executable Since v1.4.0
--linux Linux-only CMake options Since v1.3.0
--mac MacOS-only CMake options Since v1.3.0
--win Windows-only CMake options Since v1.3.0

NB: by specifying --all-at-once the linter/formatter command will only be called once for all the files instead of calling the command once per file.

NB: Since v1.6.0, the --debug command line argument has been removed. Use the LOGLEVEL environment variable instead to control the level of verbosity of each of the commands. To show all debug messages, set LOGLEVEL=DEBUG in your environment variables when running the hooks.

Usage example:

repos:
- repo: https://github.com/Takishima/cmake-pre-commit-hooks
  rev: 1.0.0
  hooks:
    - id: cppcheck
      args: [-DBUILD_TESTING=ON,
             --unix="-DCMAKE_CXX_COMPILER=g++-10",
             --win="-DCMAKE_CXX_COMPILER=cl.exe"
             -Bpath/to/build_dir,
             -Bpath/to/other_build_dir,
             -Spath/to/src_dir
             ]

In the example above, the any hooks requiring a compilation database will first search for a build directory path/to/build_dir and then path/to/other_build_dir. If any of those is deemed valid (ie. is a CMake build directory that contains some CMake cache files), then it will be used. If none qualify, the hooks will default to using path/to/build_dir as a build directory, creating it as necessary.

Also, builds on Linux and MacOS will set the C++ compiler to g++-10, while builds on Windows will be using cl.exe. This is done by looking at the value returned by platform.system().

Hook Option Comparison

Hook Options Fix In Place Enable all Checks Set key/value
clang-format -i
clang-tidy --fix-errors [1] -checks=* -warnings-as-errors=* [2]
cppcheck -enable=all
include-what-you-use

[1]: -fix will fail if there are compiler errors. -fix-errors will -fix and fix compiler errors if it can, like missing semicolons.

[2]: Be careful with -checks=*. can have self-contradictory rules in newer versions of llvm (9+): modernize wants to use trailing return type but Fuchsia disallows it.

The '--' doubledash option

Options after -- like -std=c++11 will be interpreted correctly for clang-tidy. Make sure they sequentially follow the -- argument in the hook's args list.

Standalone Hooks

If you want to have predictable return codes for your C linters outside of pre-commit, these hooks are available via PyPI. Install it with pip install cmake-pre-commit-hooks. They are named as cmake-pc-$cmd-hook, so clang-format becomes cmake-pc-clang-format-hook.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cmake_pre_commit_hooks-1.6.0.tar.gz (33.6 kB view details)

Uploaded Source

Built Distribution

cmake_pre_commit_hooks-1.6.0-py2.py3-none-any.whl (22.8 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file cmake_pre_commit_hooks-1.6.0.tar.gz.

File metadata

File hashes

Hashes for cmake_pre_commit_hooks-1.6.0.tar.gz
Algorithm Hash digest
SHA256 acb8f4b31095f0f6e8242872551834ed7752ca810f92beef22e7f890ca0bf76d
MD5 215ce26382920a3ebb76b252b97ada3f
BLAKE2b-256 44d4ddc79be7396101534168d205e75fd6db63af2db7ac195b67727d5abbf4b5

See more details on using hashes here.

File details

Details for the file cmake_pre_commit_hooks-1.6.0-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for cmake_pre_commit_hooks-1.6.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 52b9fb7c9fd711883744815c0e9aee2b89db5befccbe555f7caa1743eaf5e635
MD5 2514651d41bd0b9849af30e0c442a34b
BLAKE2b-256 ce163a179a5a224dcdf597bdc2fe9c1c19461fab30a3b2a8bf8f6fe4d240e99f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page