mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Add clang-tidy, codespell, and sanitizer checks to CI pipeline
libeigen/eigen!2178 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
37
.clang-tidy
Normal file
37
.clang-tidy
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
# Conservative clang-tidy configuration for Eigen.
|
||||||
|
#
|
||||||
|
# Focuses on bug-finding checks with low false-positive rates.
|
||||||
|
# Intentionally omits style-enforcement checks (modernize-*, google-*,
|
||||||
|
# cppcoreguidelines-*) since Eigen has its own conventions and is a
|
||||||
|
# heavily-templated math library where many "modern C++" idioms don't apply.
|
||||||
|
|
||||||
|
Checks: >
|
||||||
|
-*,
|
||||||
|
bugprone-*,
|
||||||
|
-bugprone-narrowing-conversions,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-bugprone-implicit-widening-of-multiplication-result,
|
||||||
|
-bugprone-exception-escape,
|
||||||
|
misc-redundant-expression,
|
||||||
|
misc-unused-using-decls,
|
||||||
|
misc-misleading-identifier,
|
||||||
|
performance-for-range-copy,
|
||||||
|
performance-implicit-conversion-in-loop,
|
||||||
|
performance-unnecessary-copy-initialization,
|
||||||
|
performance-unnecessary-value-param,
|
||||||
|
readability-container-size-empty,
|
||||||
|
readability-duplicate-include,
|
||||||
|
readability-misleading-indentation,
|
||||||
|
readability-redundant-control-flow,
|
||||||
|
readability-redundant-smartptr-get,
|
||||||
|
|
||||||
|
WarningsAsErrors: ''
|
||||||
|
|
||||||
|
HeaderFilterRegex: 'Eigen/.*|test/.*|blas/.*|lapack/.*|unsupported/Eigen/.*'
|
||||||
|
|
||||||
|
# Eigen uses its own assert macros.
|
||||||
|
CheckOptions:
|
||||||
|
- key: bugprone-assert-side-effect.AssertMacros
|
||||||
|
value: 'eigen_assert,eigen_internal_assert,EIGEN_STATIC_ASSERT,VERIFY,VERIFY_IS_APPROX,VERIFY_IS_EQUAL,VERIFY_IS_MUCH_SMALLER_THAN,VERIFY_IS_NOT_APPROX,VERIFY_IS_NOT_EQUAL,VERIFY_IS_UNITARY,VERIFY_RAISES_ASSERT'
|
||||||
|
...
|
||||||
@@ -125,20 +125,19 @@ build:linux:docs:
|
|||||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_PROJECT_NAMESPACE == "libeigen" && $CI_MERGE_REQUEST_LABELS =~ "/all-tests/"
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_PROJECT_NAMESPACE == "libeigen" && $CI_MERGE_REQUEST_LABELS =~ "/all-tests/"
|
||||||
|
|
||||||
|
|
||||||
# # Sanitizers (Disabled because ASAN hangs and MSAN requires instrumented libc++)
|
######## Sanitizers ############################################################
|
||||||
# build:linux:cross:x86-64:clang-12:default:asan:
|
|
||||||
# extends: build:linux:cross:x86-64:clang-12:default
|
|
||||||
# variables:
|
|
||||||
# EIGEN_CI_ADDITIONAL_ARGS:
|
|
||||||
# -DEIGEN_TEST_CUSTOM_CXX_FLAGS=-fsanitize=address,undefined
|
|
||||||
# -DEIGEN_TEST_CUSTOM_LINKER_FLAGS=-fsanitize=address,undefined
|
|
||||||
|
|
||||||
# build:linux:cross:x86-64:clang-12:default:msan:
|
build:linux:cross:x86-64:clang-19:default:asan-ubsan:
|
||||||
# extends: build:linux:cross:x86-64:clang-12:default
|
extends: .build:linux:cross:x86-64
|
||||||
# variables:
|
image: ubuntu:24.04
|
||||||
# EIGEN_CI_ADDITIONAL_ARGS:
|
variables:
|
||||||
# -DEIGEN_TEST_CUSTOM_CXX_FLAGS=-fsanitize=memory
|
EIGEN_CI_INSTALL: clang-19
|
||||||
# -DEIGEN_TEST_CUSTOM_LINKER_FLAGS=-fsanitize=memory
|
EIGEN_CI_C_COMPILER: clang-19
|
||||||
|
EIGEN_CI_CXX_COMPILER: clang++-19
|
||||||
|
EIGEN_CI_CROSS_INSTALL: g++-14-x86-64-linux-gnu clang-19
|
||||||
|
EIGEN_CI_ADDITIONAL_ARGS: >-
|
||||||
|
-DEIGEN_TEST_CUSTOM_CXX_FLAGS=-fsanitize=address,undefined;-fno-omit-frame-pointer;-fno-sanitize-recover=undefined
|
||||||
|
-DEIGEN_TEST_CUSTOM_LINKER_FLAGS=-fsanitize=address,undefined
|
||||||
|
|
||||||
######## NVHPC #################################################################
|
######## NVHPC #################################################################
|
||||||
|
|
||||||
@@ -327,3 +326,18 @@ build:linux:cross:x86-64:clang-12:default:smoketest:
|
|||||||
tags:
|
tags:
|
||||||
- saas-linux-medium-amd64
|
- saas-linux-medium-amd64
|
||||||
|
|
||||||
|
######## Sanitizer Smoke Tests #################################################
|
||||||
|
|
||||||
|
build:linux:cross:x86-64:clang-12:sanitizer:smoketest:
|
||||||
|
extends: build:linux:cross:x86-64:clang-12:default
|
||||||
|
variables:
|
||||||
|
EIGEN_CI_BUILD_TARGET: buildsmoketests
|
||||||
|
EIGEN_CI_ADDITIONAL_ARGS: >-
|
||||||
|
-DEIGEN_TEST_CUSTOM_CXX_FLAGS=-fsanitize=address,undefined;-fno-sanitize-recover=address;-fno-omit-frame-pointer
|
||||||
|
-DEIGEN_TEST_CUSTOM_LINKER_FLAGS=-fsanitize=address,undefined
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
|
tags:
|
||||||
|
- saas-linux-medium-amd64
|
||||||
|
allow_failure: true
|
||||||
|
timeout: 30m
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
checkformat:clangformat:
|
checkformat:clangformat:
|
||||||
stage: checkformat
|
stage: checkformat
|
||||||
image: alpine:3.19
|
image: alpine:3.20
|
||||||
only:
|
only:
|
||||||
- merge_requests
|
- merge_requests
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
@@ -8,3 +8,39 @@ checkformat:clangformat:
|
|||||||
- apk add --no-cache git clang17-extra-tools python3
|
- apk add --no-cache git clang17-extra-tools python3
|
||||||
script:
|
script:
|
||||||
- git clang-format --diff --commit ${CI_MERGE_REQUEST_DIFF_BASE_SHA}
|
- git clang-format --diff --commit ${CI_MERGE_REQUEST_DIFF_BASE_SHA}
|
||||||
|
|
||||||
|
checkformat:codespell:
|
||||||
|
stage: checkformat
|
||||||
|
image: alpine:3.20
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
|
allow_failure: true
|
||||||
|
before_script:
|
||||||
|
- apk add --no-cache py3-codespell
|
||||||
|
script:
|
||||||
|
- codespell --config setup.cfg
|
||||||
|
|
||||||
|
checkformat:clangtidy:
|
||||||
|
stage: checkformat
|
||||||
|
image: ubuntu:24.04
|
||||||
|
only:
|
||||||
|
- merge_requests
|
||||||
|
allow_failure: true
|
||||||
|
timeout: 15m
|
||||||
|
tags:
|
||||||
|
- saas-linux-medium-amd64
|
||||||
|
variables:
|
||||||
|
DEBIAN_FRONTEND: noninteractive
|
||||||
|
before_script:
|
||||||
|
- apt-get update -y > /dev/null
|
||||||
|
- apt-get install -y --no-install-recommends
|
||||||
|
git cmake ninja-build clang-tidy clang python3 > /dev/null
|
||||||
|
script:
|
||||||
|
- mkdir -p .tidy-build
|
||||||
|
- cmake -G Ninja -B .tidy-build
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++
|
||||||
|
-DCMAKE_C_COMPILER=clang
|
||||||
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||||
|
-DEIGEN_BUILD_TESTING=ON
|
||||||
|
- chmod +x ci/scripts/run-clang-tidy.sh
|
||||||
|
- ci/scripts/run-clang-tidy.sh ${CI_MERGE_REQUEST_DIFF_BASE_SHA} .tidy-build
|
||||||
|
|||||||
130
ci/scripts/run-clang-tidy.sh
Executable file
130
ci/scripts/run-clang-tidy.sh
Executable file
@@ -0,0 +1,130 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Run clang-tidy on files changed in the current MR.
|
||||||
|
#
|
||||||
|
# Usage: run-clang-tidy.sh <base_sha> <build_dir>
|
||||||
|
#
|
||||||
|
# <base_sha> The merge-base commit to diff against.
|
||||||
|
# <build_dir> Path to a CMake build directory containing compile_commands.json.
|
||||||
|
#
|
||||||
|
# For header files under Eigen/src/<Module>/, the script generates a minimal
|
||||||
|
# driver .cpp that includes the parent module header so that
|
||||||
|
# InternalHeaderCheck.h does not #error out.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BASE_SHA="${1:?Usage: run-clang-tidy.sh <base_sha> <build_dir>}"
|
||||||
|
BUILD_DIR="${2:?Usage: run-clang-tidy.sh <base_sha> <build_dir>}"
|
||||||
|
|
||||||
|
if [ ! -f "${BUILD_DIR}/compile_commands.json" ]; then
|
||||||
|
echo "ERROR: ${BUILD_DIR}/compile_commands.json not found."
|
||||||
|
echo "Run cmake with -DCMAKE_EXPORT_COMPILE_COMMANDS=ON first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# External-dependency modules that require third-party headers we don't have.
|
||||||
|
SKIP_MODULES="AccelerateSupport|CholmodSupport|KLUSupport|MetisSupport|PaStiXSupport|PardisoSupport|SPQRSupport|SuperLUSupport|UmfPackSupport"
|
||||||
|
|
||||||
|
# Get changed files (Added, Modified, Renamed).
|
||||||
|
CHANGED_FILES=$(git diff --name-only --diff-filter=AMR "${BASE_SHA}" HEAD)
|
||||||
|
|
||||||
|
if [ -z "${CHANGED_FILES}" ]; then
|
||||||
|
echo "No changed files to check."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMPDIR=$(mktemp -d)
|
||||||
|
trap 'rm -rf "${TMPDIR}"' EXIT
|
||||||
|
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Map a header path under Eigen/src/<Module>/ to its module include.
|
||||||
|
# e.g. Eigen/src/SVD/BDCSVD.h -> Eigen/SVD
|
||||||
|
module_include_for_header() {
|
||||||
|
local header="$1"
|
||||||
|
local module
|
||||||
|
|
||||||
|
# Handle Eigen/src/<Module>/... -> Eigen/<Module>
|
||||||
|
if [[ "${header}" =~ ^Eigen/src/([^/]+)/ ]]; then
|
||||||
|
module="${BASH_REMATCH[1]}"
|
||||||
|
# Handle unsupported/Eigen/src/<Module>/... -> unsupported/Eigen/<Module>
|
||||||
|
elif [[ "${header}" =~ ^unsupported/Eigen/src/([^/]+)/ ]]; then
|
||||||
|
module="unsupported/Eigen/${BASH_REMATCH[1]}"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Skip external-dependency modules.
|
||||||
|
if [[ "${module}" =~ ^(${SKIP_MODULES})$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${header}" =~ ^unsupported/ ]]; then
|
||||||
|
echo "${module}"
|
||||||
|
else
|
||||||
|
echo "Eigen/${module}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pick a compile command from compile_commands.json to use as a template.
|
||||||
|
# We just need a valid set of compiler flags.
|
||||||
|
TEMPLATE_CMD=$(python3 -c "
|
||||||
|
import json, sys
|
||||||
|
with open('${BUILD_DIR}/compile_commands.json') as f:
|
||||||
|
cmds = json.load(f)
|
||||||
|
# Pick the first .cpp entry.
|
||||||
|
for c in cmds:
|
||||||
|
if c['file'].endswith('.cpp'):
|
||||||
|
print(c['directory'])
|
||||||
|
break
|
||||||
|
")
|
||||||
|
|
||||||
|
echo "Checking changed files with clang-tidy..."
|
||||||
|
echo "Base SHA: ${BASE_SHA}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
for file in ${CHANGED_FILES}; do
|
||||||
|
# Only check C++ source and header files.
|
||||||
|
case "${file}" in
|
||||||
|
*.cpp|*.cc|*.cxx)
|
||||||
|
# Source file: run clang-tidy directly if it's in the compilation database.
|
||||||
|
if grep -q "\"${file}\"" "${BUILD_DIR}/compile_commands.json" 2>/dev/null; then
|
||||||
|
echo "=== ${file} ==="
|
||||||
|
if ! clang-tidy -p "${BUILD_DIR}" "${file}" 2>&1; then
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*.h|*.hpp)
|
||||||
|
# Header file: generate a driver .cpp that includes the right module.
|
||||||
|
MODULE_INCLUDE=$(module_include_for_header "${file}" || true)
|
||||||
|
if [ -z "${MODULE_INCLUDE}" ]; then
|
||||||
|
# Not a recognized module header or in skip list.
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
DRIVER="${TMPDIR}/tidy_driver_$(echo "${file}" | tr '/' '_').cpp"
|
||||||
|
cat > "${DRIVER}" <<EOF
|
||||||
|
#include <${MODULE_INCLUDE}>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "=== ${file} (via ${MODULE_INCLUDE}) ==="
|
||||||
|
if ! clang-tidy \
|
||||||
|
-p "${BUILD_DIR}" \
|
||||||
|
--header-filter="$(echo "${file}" | sed 's/[.[\*^$()+?{|]/\\&/g')" \
|
||||||
|
"${DRIVER}" 2>&1; then
|
||||||
|
ERRORS=$((ERRORS + 1))
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ${ERRORS} -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "clang-tidy reported issues in ${ERRORS} file(s)."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "clang-tidy: all clean."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
@@ -15,7 +15,8 @@ fi
|
|||||||
|
|
||||||
set +x
|
set +x
|
||||||
|
|
||||||
ctest_cmd="ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${NPROC} --output-on-failure --no-compress-output --build-noclean ${target}"
|
EIGEN_CI_CTEST_PARALLEL=${EIGEN_CI_CTEST_PARALLEL:-${NPROC}}
|
||||||
|
ctest_cmd="ctest ${EIGEN_CI_CTEST_ARGS} --parallel ${EIGEN_CI_CTEST_PARALLEL} --output-on-failure --no-compress-output --build-noclean ${target}"
|
||||||
|
|
||||||
echo "Running initial tests..."
|
echo "Running initial tests..."
|
||||||
if ${ctest_cmd} -T test; then
|
if ${ctest_cmd} -T test; then
|
||||||
|
|||||||
@@ -220,6 +220,29 @@ test:linux:x86-64:clang-19:generic:avx512dq:unsupported:
|
|||||||
variables:
|
variables:
|
||||||
EIGEN_CI_CTEST_LABEL: Unsupported
|
EIGEN_CI_CTEST_LABEL: Unsupported
|
||||||
|
|
||||||
|
##### Sanitizers ###############################################################
|
||||||
|
|
||||||
|
.test:linux:x86-64:clang-19:default:asan-ubsan:
|
||||||
|
extends: .test:linux:x86-64
|
||||||
|
image: ubuntu:24.04
|
||||||
|
needs: [ build:linux:cross:x86-64:clang-19:default:asan-ubsan ]
|
||||||
|
variables:
|
||||||
|
EIGEN_CI_INSTALL: clang-19 llvm-19
|
||||||
|
ASAN_OPTIONS: detect_leaks=0:print_stacktrace=1
|
||||||
|
UBSAN_OPTIONS: print_stacktrace=1
|
||||||
|
ASAN_SYMBOLIZER_PATH: /usr/lib/llvm-19/bin/llvm-symbolizer
|
||||||
|
EIGEN_CI_CTEST_ARGS: --timeout 2000
|
||||||
|
|
||||||
|
test:linux:x86-64:clang-19:default:asan-ubsan:official:
|
||||||
|
extends: .test:linux:x86-64:clang-19:default:asan-ubsan
|
||||||
|
variables:
|
||||||
|
EIGEN_CI_CTEST_LABEL: Official
|
||||||
|
|
||||||
|
test:linux:x86-64:clang-19:default:asan-ubsan:unsupported:
|
||||||
|
extends: .test:linux:x86-64:clang-19:default:asan-ubsan
|
||||||
|
variables:
|
||||||
|
EIGEN_CI_CTEST_LABEL: Unsupported
|
||||||
|
|
||||||
##### NVHPC ####################################################################
|
##### NVHPC ####################################################################
|
||||||
|
|
||||||
.test:linux:x86-64:nvhpc-25.1:default:
|
.test:linux:x86-64:nvhpc-25.1:default:
|
||||||
@@ -440,3 +463,22 @@ test:linux:x86-64:clang-12:default:smoketest:
|
|||||||
tags:
|
tags:
|
||||||
- saas-linux-medium-amd64
|
- saas-linux-medium-amd64
|
||||||
|
|
||||||
|
##### Sanitizer Smoke Tests ####################################################
|
||||||
|
|
||||||
|
test:linux:x86-64:clang-12:sanitizer:smoketest:
|
||||||
|
extends: .test:linux:x86-64:clang-12:default
|
||||||
|
needs: [ build:linux:cross:x86-64:clang-12:sanitizer:smoketest ]
|
||||||
|
variables:
|
||||||
|
EIGEN_CI_INSTALL: clang-12 llvm-12
|
||||||
|
EIGEN_CI_CTEST_LABEL: smoketest
|
||||||
|
EIGEN_CI_CTEST_PARALLEL: "2"
|
||||||
|
EIGEN_CI_CTEST_ARGS: --timeout 120
|
||||||
|
ASAN_OPTIONS: "detect_leaks=0:halt_on_error=1:abort_on_error=1:allocator_may_return_null=1:print_stacktrace=1:detect_stack_use_after_return=0"
|
||||||
|
ASAN_SYMBOLIZER_PATH: "/usr/lib/llvm-12/bin/llvm-symbolizer"
|
||||||
|
UBSAN_OPTIONS: "halt_on_error=0:print_stacktrace=1"
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
|
tags:
|
||||||
|
- saas-linux-medium-amd64
|
||||||
|
allow_failure: true
|
||||||
|
timeout: 30m
|
||||||
|
|||||||
26
setup.cfg
Normal file
26
setup.cfg
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[codespell]
|
||||||
|
# Skip build directories, third-party code, and binary files.
|
||||||
|
skip = .git,build,.build,build-clang,*.o,*.a,*.so,*.pyc,blas/f2c,blas/testing,lapack/f2c,CHANGELOG.md
|
||||||
|
# Ignore words that are false positives in this codebase.
|
||||||
|
# NOTE: codespell 2.2.x requires all entries to be lowercase.
|
||||||
|
# Variable names: matA/matC/MatA/MatC/matc, ComplexT, bReal, kInf, Indx,
|
||||||
|
# ans, ges, workd, whch, pres, dum, ot/Ot, bu/Bu, fo/Fo, ue/Ue,
|
||||||
|
# ALS, FOM, NIN, lowd (AVX), anc (TensorIntDiv), scond (LAPACK API),
|
||||||
|
# somme (bench/btl variable), copie/frequence (bench/btl French comments)
|
||||||
|
# Author name: Manuel Yguel (polynomial modules)
|
||||||
|
# Eigen packet op names: padd/padds (packet add), preverse (packet reverse)
|
||||||
|
# AltiVec function name: bload (block load)
|
||||||
|
# Tensor parameter name: vaccum (vector accumulator)
|
||||||
|
ignore-words-list =
|
||||||
|
nd,te,ba,ser,
|
||||||
|
mata,matc,
|
||||||
|
complext,breal,kinf,indx,
|
||||||
|
ans,padd,padds,ges,workd,whch,pres,dum,
|
||||||
|
ot,bu,fo,ue,
|
||||||
|
als,fom,nin,
|
||||||
|
lowd,anc,scond,
|
||||||
|
somme,copie,frequence,
|
||||||
|
preverse,halfs,compiletime,
|
||||||
|
ded,numer,inpt,overfl,lastr,
|
||||||
|
bload,vaccum,
|
||||||
|
manuel
|
||||||
Reference in New Issue
Block a user