| #!/usr/bin/env python |
| # |
| # =- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=# |
| # |
| # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt 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. |
| run-find-all-symbols.py <source-file> |
| |
| 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 directory 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] |
| |
| # 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() |
| |
| 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() |