#!/usr/bin/env python # Run clang-tidy recursively and parallel on directory # Usage: run-clang-tidy sourcedir builddir excludedirs extensions # extensions and excludedirs are specified as comma-separated # string without dot, e.g. 'c,cpp' # e.g. run-clang-tidy . build test,other c,cpp file import os, sys, subprocess, multiprocessing manager = multiprocessing.Manager() failedfiles = manager.list() # Get absolute current path and remove trailing seperators currentdir = os.path.realpath(os.getcwd()).rstrip(os.sep) print("Arguments: " + str(sys.argv)) # Get absolute source dir after removing leading and trailing seperators from input. sourcedir = currentdir + sys.argv[1].lstrip(os.sep).rstrip(os.sep) print("Source directory: " + sourcedir) builddir = sourcedir + os.sep + sys.argv[2].rstrip(os.sep) print("Build directory: " + builddir) # If exclude dirs is not empty, split it into a tuple excludedirs = () if sys.argv[3]: excludedirs = tuple([(sourcedir + os.sep + s).rstrip(os.sep) for s in sys.argv[3].split(',')]) # If the build directory is not the same as the source directory, exclude it if not sourcedir == builddir: excludedirs = excludedirs + (builddir, ) print("Exclude directories: " + str(excludedirs)) # Split extensions into a tuple extensions = tuple([("." + s) for s in sys.argv[4].split(',')]) print("Extensions: " + str(extensions)) def runclangtidy(filepath): print("Checking: " + filepath) proc = subprocess.Popen("clang-tidy --quiet -p=" + builddir + " " + filepath, shell=True) if proc.wait() != 0: failedfiles.append(filepath) def collectfiles(dir, exclude, exts): collectedfiles = [] for root, dirs, files in os.walk(dir): for file in files: filepath = root + os.sep + file if (len(exclude) == 0 or not filepath.startswith(exclude) ) and filepath.endswith(exts): collectedfiles.append(filepath) return collectedfiles # Define the pool AFTER the global variables and subprocess function because WTF python # See: https://stackoverflow.com/questions/41385708/multiprocessing-example-giving-attributeerror pool = multiprocessing.Pool() pool.map(runclangtidy, collectfiles(sourcedir, excludedirs, extensions)) pool.close() pool.join() if len(failedfiles) > 0: print("Errors in %d files" % len(failedfiles)) sys.exit(1) print("No errors found") sys.exit(0)