diff --git a/.github/workflows/run-update-script.yml b/.github/workflows/run-update-script.yml index ac06e4e..6ddfed2 100644 --- a/.github/workflows/run-update-script.yml +++ b/.github/workflows/run-update-script.yml @@ -18,6 +18,11 @@ jobs: cd clang-format/build/linux ./build-docker-linux.sh + - name: Update cppcheck + run: | + cd cppcheck/build/linux + ./build-cppcheck-linux.sh + - name: Git Auto Commit uses: stefanzweifel/git-auto-commit-action@v4.9.1 with: @@ -38,6 +43,11 @@ jobs: run: | ./clang-format/build/windows/build-clang-format.bat + - name: Update cppcheck + run: | + cd cppcheck/build/windows + ./build-cppcheck.bat + - name: Git Auto Commit uses: stefanzweifel/git-auto-commit-action@v4.9.1 with: @@ -58,6 +68,11 @@ jobs: run: | ./clang-format/build/mac/build-clang-format-mac.sh + - name: Update cppcheck + run: | + cd cppcheck/build/mac + ./build-cppcheck-mac.sh + - name: Git Auto Commit uses: stefanzweifel/git-auto-commit-action@v4.9.1 with: diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index d5c83a7..042ef0b 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -4,3 +4,10 @@ entry: ./clang-format/bin/clang-format-hook language: script files: \.(c|cc|cxx|cpp|h|tcc)$ + +- id: cppcheck + name: cppcheck + description: Ensure files are cppcheck compliant + entry: ./cppcheck/bin/cppcheck-hook + language: script + files: \.(c|cc|cxx|cpp|h|tcc) diff --git a/README.md b/README.md index 0ec6612..9588d0e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Custom pre-commit hooks for the pre-commit framework The hooks present in this repository are: * clang-format (self-contained hook not reliant on clang-format being available externally) +* Cppcheck (self-contained hook not reliant on cppcheck being available externally) To use the hooks copy this to your .pre-commit-config.yaml: ```yaml @@ -8,4 +9,5 @@ To use the hooks copy this to your .pre-commit-config.yaml: rev: main hooks: - id: clang-format + - id: cppcheck ``` diff --git a/clang-format/bin/clang-format-darwin b/clang-format/bin/clang-format-darwin index dcaf92f..9d10fc0 100755 Binary files a/clang-format/bin/clang-format-darwin and b/clang-format/bin/clang-format-darwin differ diff --git a/clang-format/bin/clang-format.exe b/clang-format/bin/clang-format.exe index 843efb6..4bd0fbb 100644 Binary files a/clang-format/bin/clang-format.exe and b/clang-format/bin/clang-format.exe differ diff --git a/clang-format/build/linux/README.md b/clang-format/build/linux/README.md index 7ff364d..80269ab 100644 --- a/clang-format/build/linux/README.md +++ b/clang-format/build/linux/README.md @@ -6,4 +6,4 @@ This is best built using Docker. Change to this directory and run: > build-docker-linux.sh ``` -The new binary will be placed in `llvm-build/bin`. \ No newline at end of file +The new binary will be placed in the bin folder. \ No newline at end of file diff --git a/cppcheck/bin/cppcheck-darwin b/cppcheck/bin/cppcheck-darwin new file mode 100755 index 0000000..20153c4 Binary files /dev/null and b/cppcheck/bin/cppcheck-darwin differ diff --git a/cppcheck/bin/cppcheck-hook b/cppcheck/bin/cppcheck-hook new file mode 100755 index 0000000..5fd1ed4 --- /dev/null +++ b/cppcheck/bin/cppcheck-hook @@ -0,0 +1,69 @@ +#!/usr/bin/env python +""" +pre-commit cppcheck hook +============================ + +Runs cppcheck on the given file and exits with a non-zero code if it is a valid cppcheck file +""" +# std imports +import argparse +import os +import subprocess +import sys + +USAGE = 'cppcheck-hook [ ...]' + +DESCRIPTION = ''' +Runs cppcheck on the given file and exits with a non-zero code if any changes were made. +''' + +if sys.platform.startswith('win32'): + CPPCHECK_EXE = os.path.join(os.path.dirname(__file__), 'cppcheck.exe') +elif sys.platform.startswith('linux'): + CPPCHECK_EXE = os.path.join(os.path.dirname(__file__), 'cppcheck-linux-64') +elif sys.platform.startswith('darwin'): + CPPCHECK_EXE = os.path.join(os.path.dirname(__file__), 'cppcheck-darwin') +else: + raise RuntimeError('Unknown platform "{}"'.format(sys.platform)) + + +class main: + def __init__(self): + super().__init__() + parser = argparse.ArgumentParser(usage=USAGE, description=DESCRIPTION) + parser.add_argument('files', nargs='+', help='File to run cppcheck on.') + parser.add_argument('suppressions_list', nargs=1, help='File containing paths for ignorable ') + parser.add_argument('std', nargs=1, help='The cpp standard to be judged against') + self.args = parser.parse_args() + + def main(self): + # return non-zero exit code if files will not compliant + return 1 if self.cppcheck_all() else 0 + + def cppcheck_all(self): + invalid = map(self.cppcheck, self.args.files) + return any(invalid) + + def cppcheck(self, filepath): + return_val = self.run_cppcheck_exe(filepath) + pass + + def run_cppcheck_exe(self, filepath): + p = subprocess.Popen([CPPCHECK_EXE, + f'--suppressions-list=${self.args.suppressions_list}', + f'--std=${self.args.std}', + '--enable=all', + '--inline-suppr', + '--max-configs=120', + '--quiet', + filepath], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + if p.returncode != 0: + raise RuntimeError(stderr) + return stdout + + +if __name__ == '__main__': + sys.exit(main().main()) diff --git a/cppcheck/bin/cppcheck-linux-64 b/cppcheck/bin/cppcheck-linux-64 new file mode 100755 index 0000000..33d34d6 Binary files /dev/null and b/cppcheck/bin/cppcheck-linux-64 differ diff --git a/cppcheck/bin/cppcheck.exe b/cppcheck/bin/cppcheck.exe new file mode 100644 index 0000000..971dddc Binary files /dev/null and b/cppcheck/bin/cppcheck.exe differ diff --git a/cppcheck/build/linux/README.md b/cppcheck/build/linux/README.md new file mode 100644 index 0000000..066fb2f --- /dev/null +++ b/cppcheck/build/linux/README.md @@ -0,0 +1,7 @@ +# Build Statically Linked Executable on Linux + +Change to this directory and run: + +```shell +> build-cppcheck-linux.sh +``` \ No newline at end of file diff --git a/cppcheck/build/linux/build-cppcheck-linux.sh b/cppcheck/build/linux/build-cppcheck-linux.sh new file mode 100755 index 0000000..a6e4a30 --- /dev/null +++ b/cppcheck/build/linux/build-cppcheck-linux.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Compiles Cppcheck +set -ex + +# tarballs +CPPCHECK=https://github.com/danmar/cppcheck/archive/2.3.tar.gz +TAR_FILE=$(basename ${CPPCHECK}) + +# extract source +mkdir cppcheck +cd cppcheck +wget --quiet ${CPPCHECK} +tar --extract --gz --strip-components=1 --file ${TAR_FILE} +# patch CMakeLists.txt to statically link to libgcc and libstdc++ to clang-format exe +sed -i -e 's@${CLANG_FORMAT_LIB_DEPS}@${CLANG_FORMAT_LIB_DEPS} -static-libgcc -static-libstdc++@' CMakeLists.txt + +# build +cd .. +mkdir cppcheck-build +cd cppcheck-build +cmake ../cppcheck \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_GUI=OFF \ + -DHAVE_RULES=OFF \ + -DUSE_MATCHCOMPILER=ON +cmake --build . + +# Move binary +mv bin/cppcheck ../../../bin/cppcheck-linux-64 +cd .. + +# Cleanup +rm -rf cppcheck +rm -rf ${TAR_FILE} +rm -rf cppcheck-build \ No newline at end of file diff --git a/cppcheck/build/mac/README.md b/cppcheck/build/mac/README.md new file mode 100644 index 0000000..e9524f9 --- /dev/null +++ b/cppcheck/build/mac/README.md @@ -0,0 +1,7 @@ +# Build Statically Linked Executable on macOS + +Change to this directory and run: + +```shell +> build-cppcheck-mac.sh +``` \ No newline at end of file diff --git a/cppcheck/build/mac/build-cppcheck-mac.sh b/cppcheck/build/mac/build-cppcheck-mac.sh new file mode 100755 index 0000000..e983ef4 --- /dev/null +++ b/cppcheck/build/mac/build-cppcheck-mac.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# Compiles Cppcheck +set -ex + +# tarballs +CPPCHECK=https://github.com/danmar/cppcheck/archive/2.3.tar.gz +TAR_FILE=$(basename ${CPPCHECK}) + +# extract source +mkdir cppcheck +cd cppcheck +wget --quiet ${CPPCHECK} +tar --extract --gz --strip-components=1 --file ${TAR_FILE} +cd .. + + +# build +mkdir cppcheck-build +cd cppcheck-build +cmake ../cppcheck \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_GUI=OFF \ + -DHAVE_RULES=OFF \ + -DUSE_MATCHCOMPILER=ON +cmake --build . + +# Move binary +mv bin/cppcheck ../../../bin/cppcheck-darwin +cd .. + +# Cleanup +rm -rf cppcheck +rm -rf ${TAR_FILE} +rm -rf cppcheck-build \ No newline at end of file diff --git a/cppcheck/build/windows/README.md b/cppcheck/build/windows/README.md new file mode 100644 index 0000000..78c8242 --- /dev/null +++ b/cppcheck/build/windows/README.md @@ -0,0 +1,13 @@ +# Building Statically Linked Executable on Windows + +Requirements: + - Visual Studio 2019 Community Edition installed in the standard location + - [7-zip](https://www.7-zip.org/download.html) installed in *C:\Program Files\7-Zip* + +From the commandline change to this directory and run: + +```shell +> build-clang-format +``` + +The new binary will be placed in `llvm-build\bin`. \ No newline at end of file diff --git a/cppcheck/build/windows/build-cppcheck.bat b/cppcheck/build/windows/build-cppcheck.bat new file mode 100644 index 0000000..a714c8b --- /dev/null +++ b/cppcheck/build/windows/build-cppcheck.bat @@ -0,0 +1,45 @@ +@setlocal enableextensions +:: build statically linked executable + +:: enable VC environment. activates cmake, ninja +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 || call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64 +:: assume 7z is installed in standard path +set PATH=C:\Program Files\7-Zip;%PATH% +set SCRIPTDIR=%~dp0 +set CPPCHECK_URL=https://github.com/danmar/cppcheck/archive/2.3.tar.gz +set CPPCHECK_TGZ=cppcheck.tar.gz + +:: sources +mkdir cppcheck +cd cppcheck +curl -L %CPPCHECK_URL% -o %CPPCHECK_TGZ% +call:extract-tgz %CPPCHECK_TGZ% +cd .. + +:: build +mkdir cppcheck-build +cd cppcheck-build +cmake ^ + -DBUILD_GUI=OFF ^ + -DHAVE_RULES=OFF ^ + -DUSE_MATCHCOMPILER=ON ^ + ../cppcheck/cppcheck-2.3 +cmake --build . --config Release +copy /Y bin\Release\cppcheck.exe ..\..\..\bin\ + +:: cleanup +cd .. +rmdir /S /Q cppcheck +rmdir /S /Q cppcheck-build + +goto:eof + + +:extract-tgz +:: Using the -J filter on tar directly seems to hang... +set _tgzfile=%~1 +set _tarfile=%_tgzfile:~0,-3% +del /Q %_tarfile% +7z -bb0 x %_tgzfile% +7z -bb0 x %_tarfile% +goto:eof \ No newline at end of file