1 #!/usr/bin/env python 2 # 3 #=- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=# 4 # 5 # The LLVM Compiler Infrastructure 6 # 7 # This file is distributed under the University of Illinois Open Source 8 # License. See LICENSE.TXT for details. 9 # 10 #===------------------------------------------------------------------------===# 11 12 """ 13 Parallel find-all-symbols runner 14 ================================ 15 16 Runs find-all-symbols over all files in a compilation database. 17 18 Example invocations. 19 - Run find-all-symbols on all files in the current working directory. 20 run-find-all-symbols.py <source-file> 21 22 Compilation database setup: 23 http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html 24 """ 25 26 import argparse 27 import json 28 import multiprocessing 29 import os 30 import Queue 31 import shutil 32 import subprocess 33 import sys 34 import tempfile 35 import threading 36 37 38 def find_compilation_database(path): 39 """Adjusts the directory until a compilation database is found.""" 40 result = './' 41 while not os.path.isfile(os.path.join(result, path)): 42 if os.path.realpath(result) == '/': 43 print 'Error: could not find compilation database.' 44 sys.exit(1) 45 result += '../' 46 return os.path.realpath(result) 47 48 49 def MergeSymbols(directory, args): 50 """Merge all symbol files (yaml) in a given directaory into a single file.""" 51 invocation = [args.binary, '-merge-dir='+directory, args.saving_path] 52 subprocess.call(invocation) 53 print 'Merge is finished. Saving results in ' + args.saving_path 54 55 56 def run_find_all_symbols(args, tmpdir, build_path, queue): 57 """Takes filenames out of queue and runs find-all-symbols on them.""" 58 while True: 59 name = queue.get() 60 invocation = [args.binary, name, '-output-dir='+tmpdir, '-p='+build_path] 61 sys.stdout.write(' '.join(invocation) + '\n') 62 subprocess.call(invocation) 63 queue.task_done() 64 65 66 def main(): 67 parser = argparse.ArgumentParser(description='Runs find-all-symbols over all' 68 'files in a compilation database.') 69 parser.add_argument('-binary', metavar='PATH', 70 default='./bin/find-all-symbols', 71 help='path to find-all-symbols binary') 72 parser.add_argument('-j', type=int, default=0, 73 help='number of instances to be run in parallel.') 74 parser.add_argument('-p', dest='build_path', 75 help='path used to read a compilation database.') 76 parser.add_argument('-saving-path', default='./find_all_symbols_db.yaml', 77 help='result saving path') 78 args = parser.parse_args() 79 80 db_path = 'compile_commands.json' 81 82 if args.build_path is not None: 83 build_path = args.build_path 84 else: 85 build_path = find_compilation_database(db_path) 86 87 tmpdir = tempfile.mkdtemp() 88 89 # Load the database and extract all files. 90 database = json.load(open(os.path.join(build_path, db_path))) 91 files = [entry['file'] for entry in database] 92 93 max_task = args.j 94 if max_task == 0: 95 max_task = multiprocessing.cpu_count() 96 97 try: 98 # Spin up a bunch of tidy-launching threads. 99 queue = Queue.Queue(max_task) 100 for _ in range(max_task): 101 t = threading.Thread(target=run_find_all_symbols, 102 args=(args, tmpdir, build_path, queue)) 103 t.daemon = True 104 t.start() 105 106 # Fill the queue with files. 107 for name in files: 108 queue.put(name) 109 110 # Wait for all threads to be done. 111 queue.join() 112 113 MergeSymbols(tmpdir, args) 114 115 116 except KeyboardInterrupt: 117 # This is a sad hack. Unfortunately subprocess goes 118 # bonkers with ctrl-c and we start forking merrily. 119 print '\nCtrl-C detected, goodbye.' 120 os.kill(0, 9) 121 122 123 if __name__ == '__main__': 124 main() 125