blob: 8655af137bb2798e7e9998d52f5a6c7971f166f5 [file] [log] [blame]
#!/usr/bin/env python
#=- - Parallel find-all-symbols runner -*- python -*-=#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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. <source-file>
Compilation database setup:
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.'
result += '../'
return os.path.realpath(result)
def MergeSymbols(directory, args):
"""Merge all symbol files (yaml) in a given directory into a single file."""
invocation = [args.binary, '-merge-dir='+directory, args.saving_path]
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')
def main():
parser = argparse.ArgumentParser(description='Runs find-all-symbols over all'
'files in a compilation database.')
parser.add_argument('-binary', metavar='PATH',
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
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]
# Filter out .rc files on Windows. CMake includes them for some reason.
files = [f for f in files if not f.endswith('.rc')]
max_task = args.j
if max_task == 0:
max_task = multiprocessing.cpu_count()
# 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
# Fill the queue with files.
for name in files:
# Wait for all threads to be done.
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__':