File: run-find-all-symbols.py

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (133 lines) | stat: -rwxr-xr-x 4,016 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python3
#
# =- 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()