#!/usr/bin/env python # #=- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=# # # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. # #===------------------------------------------------------------------------===# """ Parallel find-all-symbols runner ================================ Runs find-all-symbols over all files in a compilation database. Example invocations. - Run find-all-symbols on all files in the current working directory. run-find-all-symbols.py Compilation database setup: http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html """ import argparse import json import multiprocessing import os import Queue import shutil import subprocess import sys import tempfile import threading def find_compilation_database(path): """Adjusts the directory until a compilation database is found.""" result = './' while not os.path.isfile(os.path.join(result, path)): if os.path.realpath(result) == '/': print 'Error: could not find compilation database.' sys.exit(1) result += '../' return os.path.realpath(result) def MergeSymbols(directory, args): """Merge all symbol files (yaml) in a given directaory into a single file.""" invocation = [args.binary, '-merge-dir='+directory, args.saving_path] subprocess.call(invocation) print 'Merge is finished. Saving results in ' + args.saving_path def run_find_all_symbols(args, tmpdir, build_path, queue): """Takes filenames out of queue and runs find-all-symbols on them.""" while True: name = queue.get() invocation = [args.binary, name, '-output-dir='+tmpdir, '-p='+build_path] sys.stdout.write(' '.join(invocation) + '\n') subprocess.call(invocation) queue.task_done() def main(): parser = argparse.ArgumentParser(description='Runs find-all-symbols over all' 'files in a compilation database.') parser.add_argument('-binary', metavar='PATH', default='./bin/find-all-symbols', help='path to find-all-symbols binary') parser.add_argument('-j', type=int, default=0, help='number of instances to be run in parallel.') parser.add_argument('-p', dest='build_path', help='path used to read a compilation database.') parser.add_argument('-saving-path', default='./find_all_symbols_db.yaml', help='result saving path') args = parser.parse_args() db_path = 'compile_commands.json' if args.build_path is not None: build_path = args.build_path else: build_path = find_compilation_database(db_path) tmpdir = tempfile.mkdtemp() # Load the database and extract all files. database = json.load(open(os.path.join(build_path, db_path))) files = [entry['file'] for entry in database] max_task = args.j if max_task == 0: max_task = multiprocessing.cpu_count() try: # Spin up a bunch of tidy-launching threads. queue = Queue.Queue(max_task) for _ in range(max_task): t = threading.Thread(target=run_find_all_symbols, args=(args, tmpdir, build_path, queue)) t.daemon = True t.start() # Fill the queue with files. for name in files: queue.put(name) # Wait for all threads to be done. queue.join() MergeSymbols(tmpdir, args) except KeyboardInterrupt: # This is a sad hack. Unfortunately subprocess goes # bonkers with ctrl-c and we start forking merrily. print '\nCtrl-C detected, goodbye.' os.kill(0, 9) if __name__ == '__main__': main()