aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-16 15:37:58 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-16 15:37:58 +0800
commita39d8f6f4ed2ad0f8435b73bd6b2a35769c6fead (patch)
treee18600b7459edd38c00c4074a30511691aeda345
parent3c998e2fc02c6ca7869c586cbf2e1cbb7ea3c7bf (diff)
downloadrcc-project-a39d8f6f4ed2ad0f8435b73bd6b2a35769c6fead.tar.gz
rcc-project-a39d8f6f4ed2ad0f8435b73bd6b2a35769c6fead.tar.xz
cmake: Run clang-tidy incrementally in parallel
-rw-r--r--backend/CMakeLists.txt4
-rw-r--r--backend/cmake/modules/RCCBackendBuild.cmake15
-rw-r--r--backend/cmake/modules/RCCBackendClangTidy.cmake83
-rw-r--r--backend/cmake/modules/RCCBackendDeveloperTools.cmake45
4 files changed, 132 insertions, 15 deletions
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt
index fcd75a8..2701c08 100644
--- a/backend/CMakeLists.txt
+++ b/backend/CMakeLists.txt
@@ -46,6 +46,10 @@ option(RCC_BACKEND_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF)
option(RCC_BACKEND_ENABLE_CLANG_TIDY "Run clang-tidy during each compilation" OFF)
option(RCC_BACKEND_ENABLE_EH "Enable C++ exception handling" OFF)
option(RCC_BACKEND_ENABLE_RTTI "Enable C++ run-time type information" OFF)
+set(RCC_BACKEND_TIDY_BASE "HEAD" CACHE STRING
+ "Git revision used as the merge base for incremental clang-tidy")
+set(RCC_BACKEND_TIDY_JOBS "0" CACHE STRING
+ "Parallel clang-tidy jobs; zero uses the logical CPU count")
if(RCC_BACKEND_ENABLE_EH AND NOT RCC_BACKEND_ENABLE_RTTI)
message(FATAL_ERROR "RCC Backend exception handling requires RTTI")
diff --git a/backend/cmake/modules/RCCBackendBuild.cmake b/backend/cmake/modules/RCCBackendBuild.cmake
index 52e3a71..9ecc41b 100644
--- a/backend/cmake/modules/RCCBackendBuild.cmake
+++ b/backend/cmake/modules/RCCBackendBuild.cmake
@@ -13,6 +13,18 @@ function(rcc_backend_initialize_toolchain)
NAMES "clang-tidy-${RCCBackendClangMajor}" clang-tidy
REQUIRED
)
+ find_program(
+ RCC_BACKEND_CLANG_TIDY_DIFF
+ NAMES clang-tidy-diff.py
+ HINTS "/usr/lib/llvm-${RCCBackendClangMajor}/share/clang"
+ REQUIRED
+ )
+ find_program(
+ RCC_BACKEND_RUN_CLANG_TIDY
+ NAMES "run-clang-tidy-${RCCBackendClangMajor}" run-clang-tidy
+ REQUIRED
+ )
+ find_program(RCC_BACKEND_GIT NAMES git REQUIRED)
foreach(Tool IN ITEMS RCC_BACKEND_CLANG_FORMAT RCC_BACKEND_CLANG_TIDY)
execute_process(
@@ -40,6 +52,9 @@ function(rcc_backend_initialize_toolchain)
set(RCC_BACKEND_CLANG_FORMAT "${RCC_BACKEND_CLANG_FORMAT}" PARENT_SCOPE)
set(RCC_BACKEND_CLANG_TIDY "${RCC_BACKEND_CLANG_TIDY}" PARENT_SCOPE)
+ set(RCC_BACKEND_CLANG_TIDY_DIFF "${RCC_BACKEND_CLANG_TIDY_DIFF}" PARENT_SCOPE)
+ set(RCC_BACKEND_RUN_CLANG_TIDY "${RCC_BACKEND_RUN_CLANG_TIDY}" PARENT_SCOPE)
+ set(RCC_BACKEND_GIT "${RCC_BACKEND_GIT}" PARENT_SCOPE)
endfunction()
function(rcc_backend_configure_target Target)
diff --git a/backend/cmake/modules/RCCBackendClangTidy.cmake b/backend/cmake/modules/RCCBackendClangTidy.cmake
new file mode 100644
index 0000000..16afeb4
--- /dev/null
+++ b/backend/cmake/modules/RCCBackendClangTidy.cmake
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+foreach(Variable IN ITEMS RCC_TIDY_GIT RCC_TIDY_SOURCE_DIR RCC_TIDY_BINARY_DIR RCC_TIDY_BASE
+ RCC_TIDY_JOBS RCC_TIDY_DIFF)
+ if(NOT DEFINED ${Variable} OR "${${Variable}}" STREQUAL "")
+ message(FATAL_ERROR "${Variable} is required for incremental clang-tidy")
+ endif()
+endforeach()
+
+execute_process(
+ COMMAND "${RCC_TIDY_GIT}" -C "${RCC_TIDY_SOURCE_DIR}" rev-parse --show-toplevel
+ RESULT_VARIABLE GitRootResult
+ OUTPUT_VARIABLE GitRoot
+ ERROR_VARIABLE GitRootError
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+if(NOT GitRootResult EQUAL 0)
+ message(FATAL_ERROR "cannot locate the Git worktree: ${GitRootError}")
+endif()
+
+file(RELATIVE_PATH TidyPath "${GitRoot}" "${RCC_TIDY_SOURCE_DIR}")
+if(TidyPath MATCHES "^\\.\\.")
+ message(FATAL_ERROR "backend source directory is outside its Git worktree")
+endif()
+
+set(DiffFile "${RCC_TIDY_BINARY_DIR}/CMakeFiles/rcc-backend-clang-tidy.diff")
+execute_process(
+ COMMAND "${RCC_TIDY_GIT}" -C "${GitRoot}" diff --no-ext-diff --unified=0 --merge-base
+ "${RCC_TIDY_BASE}" -- "${TidyPath}"
+ RESULT_VARIABLE DiffResult
+ OUTPUT_FILE "${DiffFile}"
+ ERROR_VARIABLE DiffError
+)
+if(NOT DiffResult EQUAL 0)
+ message(FATAL_ERROR "cannot produce incremental clang-tidy diff: ${DiffError}")
+endif()
+
+# git diff does not include untracked source files. Add their ordinary Git diff form so
+# LLVM's unchanged clang-tidy-diff.py driver checks new translation units before staging.
+execute_process(
+ COMMAND "${RCC_TIDY_GIT}" -C "${GitRoot}" ls-files --others --exclude-standard -- "${TidyPath}"
+ RESULT_VARIABLE UntrackedResult
+ OUTPUT_VARIABLE UntrackedFiles
+ ERROR_VARIABLE UntrackedError
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+if(NOT UntrackedResult EQUAL 0)
+ message(FATAL_ERROR "cannot list untracked clang-tidy files: ${UntrackedError}")
+endif()
+if(NOT UntrackedFiles STREQUAL "")
+ string(REPLACE "\n" ";" UntrackedFiles "${UntrackedFiles}")
+ foreach(UntrackedFile IN LISTS UntrackedFiles)
+ execute_process(
+ COMMAND "${RCC_TIDY_GIT}" -C "${GitRoot}" diff --no-index --no-ext-diff --unified=0 --
+ /dev/null "${UntrackedFile}"
+ RESULT_VARIABLE UntrackedDiffResult
+ OUTPUT_VARIABLE UntrackedDiff
+ ERROR_VARIABLE UntrackedDiffError
+ )
+ if(NOT UntrackedDiffResult EQUAL 0 AND NOT UntrackedDiffResult EQUAL 1)
+ message(FATAL_ERROR "cannot diff untracked file '${UntrackedFile}': ${UntrackedDiffError}")
+ endif()
+ file(APPEND "${DiffFile}" "${UntrackedDiff}")
+ endforeach()
+endif()
+
+execute_process(
+ COMMAND "${RCC_TIDY_DIFF}" -path "${RCC_TIDY_BINARY_DIR}" -p1 -quiet -j "${RCC_TIDY_JOBS}"
+ INPUT_FILE "${DiffFile}"
+ WORKING_DIRECTORY "${GitRoot}"
+ RESULT_VARIABLE TidyResult
+ OUTPUT_VARIABLE TidyOutput
+ ERROR_VARIABLE TidyError
+)
+set(TidyDiagnostics "${TidyOutput}\n${TidyError}")
+string(REGEX REPLACE "[0-9]+ warnings generated\\." "" TidyDiagnostics "${TidyDiagnostics}")
+string(STRIP "${TidyDiagnostics}" TidyDiagnostics)
+if(NOT TidyDiagnostics STREQUAL "")
+ message("${TidyDiagnostics}")
+endif()
+if(NOT TidyResult EQUAL 0 OR NOT TidyDiagnostics STREQUAL "")
+ message(FATAL_ERROR "incremental clang-tidy failed")
+endif()
diff --git a/backend/cmake/modules/RCCBackendDeveloperTools.cmake b/backend/cmake/modules/RCCBackendDeveloperTools.cmake
index 0313fe6..4c328f9 100644
--- a/backend/cmake/modules/RCCBackendDeveloperTools.cmake
+++ b/backend/cmake/modules/RCCBackendDeveloperTools.cmake
@@ -27,19 +27,34 @@ function(rcc_backend_add_developer_targets)
if(TidyFiles)
list(REMOVE_DUPLICATES TidyFiles)
- # LLVM's repository runs clang-tidy-diff.py for changed lines. Keep the
- # backend's explicit full audit deterministic by invoking clang-tidy once
- # with the registered translation units instead of using a process pool.
+ # Match LLVM's normal lint path: pass the changed backend lines to its
+ # clang-tidy-diff.py driver, which runs independent translation units in parallel.
add_custom_target(
rcc-backend-tidy
COMMAND
- "${RCC_BACKEND_CLANG_TIDY}"
- "--quiet"
+ "${CMAKE_COMMAND}"
+ "-DRCC_TIDY_GIT=${RCC_BACKEND_GIT}"
+ "-DRCC_TIDY_SOURCE_DIR=${RCC_BACKEND_SOURCE_DIR}"
+ "-DRCC_TIDY_BINARY_DIR=${CMAKE_BINARY_DIR}"
+ "-DRCC_TIDY_BASE=${RCC_BACKEND_TIDY_BASE}"
+ "-DRCC_TIDY_JOBS=${RCC_BACKEND_TIDY_JOBS}"
+ "-DRCC_TIDY_DIFF=${RCC_BACKEND_CLANG_TIDY_DIFF}"
+ -P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/RCCBackendClangTidy.cmake"
+ COMMENT "Running incremental clang-tidy on RCC Backend"
+ USES_TERMINAL
+ VERBATIM
+ )
+
+ add_custom_target(
+ rcc-backend-tidy-all
+ COMMAND
+ "${RCC_BACKEND_RUN_CLANG_TIDY}"
"-p=${CMAKE_BINARY_DIR}"
- "--warnings-as-errors=*"
- ${TidyFiles}
- COMMAND_EXPAND_LISTS
- COMMENT "Running clang-tidy on RCC Backend"
+ -j "${RCC_BACKEND_TIDY_JOBS}"
+ -quiet
+ "-warnings-as-errors=*"
+ "${RCC_BACKEND_SOURCE_DIR}/.*"
+ COMMENT "Running full parallel clang-tidy audit on RCC Backend"
USES_TERMINAL
VERBATIM
)
@@ -47,14 +62,14 @@ function(rcc_backend_add_developer_targets)
add_custom_target(
rcc-backend-analyze
COMMAND
- "${RCC_BACKEND_CLANG_TIDY}"
- "--quiet"
+ "${RCC_BACKEND_RUN_CLANG_TIDY}"
"-p=${CMAKE_BINARY_DIR}"
+ -j "${RCC_BACKEND_TIDY_JOBS}"
+ -quiet
"-checks=-*,clang-analyzer-*"
- "--warnings-as-errors=*"
- ${TidyFiles}
- COMMAND_EXPAND_LISTS
- COMMENT "Running Clang Static Analyzer checks on RCC Backend"
+ "-warnings-as-errors=*"
+ "${RCC_BACKEND_SOURCE_DIR}/.*"
+ COMMENT "Running full parallel Clang Static Analyzer audit on RCC Backend"
USES_TERMINAL
VERBATIM
)