summaryrefslogtreecommitdiff
path: root/mesonbuild/scripts
diff options
context:
space:
mode:
authorJonathon Anderson <anderson.jonathonm@gmail.com>2024-08-20 08:59:37 -0500
committerDylan Baker <dylan@pnwbakers.com>2024-09-24 14:55:45 -0700
commit8eaeff5b1f3057f827dfc95ac3987903c9bcb828 (patch)
treef1ec6db6e77396b3f7b6cf142ee264a96122892b /mesonbuild/scripts
parentf3daf6265aa412c2d54784100c8618e9008a2f9d (diff)
downloadmeson-8eaeff5b1f3057f827dfc95ac3987903c9bcb828.tar.gz
clang-tidy: Avoid spawning too many threads
The clang-tidy-fix target uses run-clang-tidy to do the fixing, however this script itself spawns `os.cpu_count()` threads as part of its internal parallelism. When combined with Meson's parallelism this results in the creation of potentially thousands of unecessary threads. This commit rewrites the clang-tidy-fix to perform the same task run-clang-tidy does but exclusively on Meson's thread pool. "Fix-it" snippets are saved to `meson-private/clang-tidy-fix/` by a parallel clang-tidy phase, afterwards (to avoid races) all collected fixes are applied with a single call to clang-apply-replacements.
Diffstat (limited to 'mesonbuild/scripts')
-rw-r--r--mesonbuild/scripts/clangtidy.py50
1 files changed, 43 insertions, 7 deletions
diff --git a/mesonbuild/scripts/clangtidy.py b/mesonbuild/scripts/clangtidy.py
index 1e0c4a5a3..a922f8514 100644
--- a/mesonbuild/scripts/clangtidy.py
+++ b/mesonbuild/scripts/clangtidy.py
@@ -6,15 +6,22 @@ from __future__ import annotations
import argparse
import subprocess
from pathlib import Path
+import tempfile
+import os
+import shutil
+import sys
from .run_tool import run_tool
+from ..environment import detect_clangtidy, detect_clangapply
import typing as T
-def run_clang_tidy(fname: Path, builddir: Path) -> subprocess.CompletedProcess:
- return subprocess.run(['clang-tidy', '-quiet', '-p', str(builddir), str(fname)])
-
-def run_clang_tidy_fix(fname: Path, builddir: Path) -> subprocess.CompletedProcess:
- return subprocess.run(['run-clang-tidy', '-fix', '-format', '-quiet', '-p', str(builddir), str(fname)])
+def run_clang_tidy(fname: Path, tidyexe: list, builddir: Path, fixesdir: T.Optional[Path]) -> subprocess.CompletedProcess:
+ args = []
+ if fixesdir is not None:
+ handle, name = tempfile.mkstemp(prefix=fname.name + '.', suffix='.yaml', dir=fixesdir)
+ os.close(handle)
+ args.extend(['-export-fixes', name])
+ return subprocess.run(tidyexe + args + ['-quiet', '-p', str(builddir), str(fname)])
def run(args: T.List[str]) -> int:
parser = argparse.ArgumentParser()
@@ -26,5 +33,34 @@ def run(args: T.List[str]) -> int:
srcdir = Path(options.sourcedir)
builddir = Path(options.builddir)
- run_func = run_clang_tidy_fix if options.fix else run_clang_tidy
- return run_tool('clang-tidy', srcdir, builddir, run_func, builddir)
+ tidyexe = detect_clangtidy()
+ if not tidyexe:
+ print(f'Could not execute clang-tidy "{" ".join(tidyexe)}"')
+ return 1
+
+ fixesdir: T.Optional[Path] = None
+ if options.fix:
+ applyexe = detect_clangapply()
+ if not applyexe:
+ print(f'Could not execute clang-apply-replacements "{" ".join(applyexe)}"')
+ return 1
+
+ fixesdir = builddir / 'meson-private' / 'clang-tidy-fix'
+ if fixesdir.is_dir():
+ shutil.rmtree(fixesdir)
+ elif fixesdir.exists():
+ fixesdir.unlink()
+ fixesdir.mkdir(parents=True)
+
+ tidyret = run_tool('clang-tidy', srcdir, builddir, run_clang_tidy, tidyexe, builddir, fixesdir)
+ if fixesdir is not None:
+ print('Applying fix-its...')
+ applyret = subprocess.run(applyexe + ['-format', '-style=file', '-ignore-insert-conflict', fixesdir]).returncode
+
+ if tidyret != 0:
+ print('Errors encountered while running clang-tidy', file=sys.stderr)
+ return tidyret
+ if fixesdir is not None and applyret != 0:
+ print('Errors encountered while running clang-apply-replacements', file=sys.stderr)
+ return applyret
+ return 0