xref: /aosp_15_r20/external/grpc-grpc/tools/distrib/gen_compilation_database.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cc02d7e2SAndroid Build Coastguard Worker
3*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2020 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker#
5*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker#
9*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker#
11*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker
17*cc02d7e2SAndroid Build Coastguard Worker# This is based on the script on the Envoy project
18*cc02d7e2SAndroid Build Coastguard Worker# https://github.com/envoyproxy/envoy/blob/master/tools/gen_compilation_database.py
19*cc02d7e2SAndroid Build Coastguard Worker
20*cc02d7e2SAndroid Build Coastguard Workerimport argparse
21*cc02d7e2SAndroid Build Coastguard Workerimport glob
22*cc02d7e2SAndroid Build Coastguard Workerimport json
23*cc02d7e2SAndroid Build Coastguard Workerimport logging
24*cc02d7e2SAndroid Build Coastguard Workerimport os
25*cc02d7e2SAndroid Build Coastguard Workerfrom pathlib import Path
26*cc02d7e2SAndroid Build Coastguard Workerimport re
27*cc02d7e2SAndroid Build Coastguard Workerimport shlex
28*cc02d7e2SAndroid Build Coastguard Workerimport subprocess
29*cc02d7e2SAndroid Build Coastguard Worker
30*cc02d7e2SAndroid Build Coastguard WorkerRE_INCLUDE_SYSTEM = re.compile("\s*-I\s+/usr/[^ ]+")
31*cc02d7e2SAndroid Build Coastguard Worker
32*cc02d7e2SAndroid Build Coastguard Worker
33*cc02d7e2SAndroid Build Coastguard Worker# This method is equivalent to https://github.com/grailbio/bazel-compilation-database/blob/master/generate.sh
34*cc02d7e2SAndroid Build Coastguard Workerdef generateCompilationDatabase(args):
35*cc02d7e2SAndroid Build Coastguard Worker    # We need to download all remote outputs for generated source code.
36*cc02d7e2SAndroid Build Coastguard Worker    # This option lives here to override those specified in bazelrc.
37*cc02d7e2SAndroid Build Coastguard Worker    bazel_options = shlex.split(os.environ.get("BAZEL_BUILD_OPTIONS", "")) + [
38*cc02d7e2SAndroid Build Coastguard Worker        "--config=compdb",
39*cc02d7e2SAndroid Build Coastguard Worker        "--remote_download_outputs=all",
40*cc02d7e2SAndroid Build Coastguard Worker    ]
41*cc02d7e2SAndroid Build Coastguard Worker
42*cc02d7e2SAndroid Build Coastguard Worker    subprocess.check_call(
43*cc02d7e2SAndroid Build Coastguard Worker        ["bazel", "build"]
44*cc02d7e2SAndroid Build Coastguard Worker        + bazel_options
45*cc02d7e2SAndroid Build Coastguard Worker        + [
46*cc02d7e2SAndroid Build Coastguard Worker            "--aspects=@bazel_compdb//:aspects.bzl%compilation_database_aspect",
47*cc02d7e2SAndroid Build Coastguard Worker            "--output_groups=compdb_files,header_files",
48*cc02d7e2SAndroid Build Coastguard Worker        ]
49*cc02d7e2SAndroid Build Coastguard Worker        + args.bazel_targets
50*cc02d7e2SAndroid Build Coastguard Worker    )
51*cc02d7e2SAndroid Build Coastguard Worker
52*cc02d7e2SAndroid Build Coastguard Worker    execroot = (
53*cc02d7e2SAndroid Build Coastguard Worker        subprocess.check_output(
54*cc02d7e2SAndroid Build Coastguard Worker            ["bazel", "info", "execution_root"] + bazel_options
55*cc02d7e2SAndroid Build Coastguard Worker        )
56*cc02d7e2SAndroid Build Coastguard Worker        .decode()
57*cc02d7e2SAndroid Build Coastguard Worker        .strip()
58*cc02d7e2SAndroid Build Coastguard Worker    )
59*cc02d7e2SAndroid Build Coastguard Worker
60*cc02d7e2SAndroid Build Coastguard Worker    compdb = []
61*cc02d7e2SAndroid Build Coastguard Worker    for compdb_file in Path(execroot).glob("**/*.compile_commands.json"):
62*cc02d7e2SAndroid Build Coastguard Worker        compdb.extend(
63*cc02d7e2SAndroid Build Coastguard Worker            json.loads(
64*cc02d7e2SAndroid Build Coastguard Worker                "["
65*cc02d7e2SAndroid Build Coastguard Worker                + compdb_file.read_text().replace("__EXEC_ROOT__", execroot)
66*cc02d7e2SAndroid Build Coastguard Worker                + "]"
67*cc02d7e2SAndroid Build Coastguard Worker            )
68*cc02d7e2SAndroid Build Coastguard Worker        )
69*cc02d7e2SAndroid Build Coastguard Worker
70*cc02d7e2SAndroid Build Coastguard Worker    if args.dedup_targets:
71*cc02d7e2SAndroid Build Coastguard Worker        compdb_map = {target["file"]: target for target in compdb}
72*cc02d7e2SAndroid Build Coastguard Worker        compdb = list(compdb_map.values())
73*cc02d7e2SAndroid Build Coastguard Worker
74*cc02d7e2SAndroid Build Coastguard Worker    return compdb
75*cc02d7e2SAndroid Build Coastguard Worker
76*cc02d7e2SAndroid Build Coastguard Worker
77*cc02d7e2SAndroid Build Coastguard Workerdef isHeader(filename):
78*cc02d7e2SAndroid Build Coastguard Worker    for ext in (".h", ".hh", ".hpp", ".hxx"):
79*cc02d7e2SAndroid Build Coastguard Worker        if filename.endswith(ext):
80*cc02d7e2SAndroid Build Coastguard Worker            return True
81*cc02d7e2SAndroid Build Coastguard Worker    return False
82*cc02d7e2SAndroid Build Coastguard Worker
83*cc02d7e2SAndroid Build Coastguard Worker
84*cc02d7e2SAndroid Build Coastguard Workerdef isCompileTarget(target, args):
85*cc02d7e2SAndroid Build Coastguard Worker    filename = target["file"]
86*cc02d7e2SAndroid Build Coastguard Worker    if not args.include_headers and isHeader(filename):
87*cc02d7e2SAndroid Build Coastguard Worker        return False
88*cc02d7e2SAndroid Build Coastguard Worker    if not args.include_genfiles:
89*cc02d7e2SAndroid Build Coastguard Worker        if filename.startswith("bazel-out/"):
90*cc02d7e2SAndroid Build Coastguard Worker            return False
91*cc02d7e2SAndroid Build Coastguard Worker    if not args.include_external:
92*cc02d7e2SAndroid Build Coastguard Worker        if filename.startswith("external/"):
93*cc02d7e2SAndroid Build Coastguard Worker            return False
94*cc02d7e2SAndroid Build Coastguard Worker    return True
95*cc02d7e2SAndroid Build Coastguard Worker
96*cc02d7e2SAndroid Build Coastguard Worker
97*cc02d7e2SAndroid Build Coastguard Workerdef modifyCompileCommand(target, args):
98*cc02d7e2SAndroid Build Coastguard Worker    cc, options = target["command"].split(" ", 1)
99*cc02d7e2SAndroid Build Coastguard Worker
100*cc02d7e2SAndroid Build Coastguard Worker    # Workaround for bazel added C++14 options, those doesn't affect build itself but
101*cc02d7e2SAndroid Build Coastguard Worker    # clang-tidy will misinterpret them.
102*cc02d7e2SAndroid Build Coastguard Worker    options = options.replace("-std=c++0x ", "")
103*cc02d7e2SAndroid Build Coastguard Worker    options = options.replace("-std=c++14 ", "")
104*cc02d7e2SAndroid Build Coastguard Worker
105*cc02d7e2SAndroid Build Coastguard Worker    # Add -DNDEBUG so that editors show the correct size information for structs.
106*cc02d7e2SAndroid Build Coastguard Worker    options += " -DNDEBUG"
107*cc02d7e2SAndroid Build Coastguard Worker
108*cc02d7e2SAndroid Build Coastguard Worker    if args.vscode:
109*cc02d7e2SAndroid Build Coastguard Worker        # Visual Studio Code doesn't seem to like "-iquote". Replace it with
110*cc02d7e2SAndroid Build Coastguard Worker        # old-style "-I".
111*cc02d7e2SAndroid Build Coastguard Worker        options = options.replace("-iquote ", "-I ")
112*cc02d7e2SAndroid Build Coastguard Worker
113*cc02d7e2SAndroid Build Coastguard Worker    if args.ignore_system_headers:
114*cc02d7e2SAndroid Build Coastguard Worker        # Remove all include options for /usr/* directories
115*cc02d7e2SAndroid Build Coastguard Worker        options = RE_INCLUDE_SYSTEM.sub("", options)
116*cc02d7e2SAndroid Build Coastguard Worker
117*cc02d7e2SAndroid Build Coastguard Worker    if isHeader(target["file"]):
118*cc02d7e2SAndroid Build Coastguard Worker        options += " -Wno-pragma-once-outside-header -Wno-unused-const-variable"
119*cc02d7e2SAndroid Build Coastguard Worker        options += " -Wno-unused-function"
120*cc02d7e2SAndroid Build Coastguard Worker        if not target["file"].startswith("external/"):
121*cc02d7e2SAndroid Build Coastguard Worker            # *.h file is treated as C header by default while our headers files are all C++14.
122*cc02d7e2SAndroid Build Coastguard Worker            options = "-x c++ -std=c++14 -fexceptions " + options
123*cc02d7e2SAndroid Build Coastguard Worker
124*cc02d7e2SAndroid Build Coastguard Worker    target["command"] = " ".join([cc, options])
125*cc02d7e2SAndroid Build Coastguard Worker    return target
126*cc02d7e2SAndroid Build Coastguard Worker
127*cc02d7e2SAndroid Build Coastguard Worker
128*cc02d7e2SAndroid Build Coastguard Workerdef fixCompilationDatabase(args, db):
129*cc02d7e2SAndroid Build Coastguard Worker    db = [
130*cc02d7e2SAndroid Build Coastguard Worker        modifyCompileCommand(target, args)
131*cc02d7e2SAndroid Build Coastguard Worker        for target in db
132*cc02d7e2SAndroid Build Coastguard Worker        if isCompileTarget(target, args)
133*cc02d7e2SAndroid Build Coastguard Worker    ]
134*cc02d7e2SAndroid Build Coastguard Worker
135*cc02d7e2SAndroid Build Coastguard Worker    with open("compile_commands.json", "w") as db_file:
136*cc02d7e2SAndroid Build Coastguard Worker        json.dump(db, db_file, indent=2)
137*cc02d7e2SAndroid Build Coastguard Worker
138*cc02d7e2SAndroid Build Coastguard Worker
139*cc02d7e2SAndroid Build Coastguard Workerif __name__ == "__main__":
140*cc02d7e2SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(
141*cc02d7e2SAndroid Build Coastguard Worker        description="Generate JSON compilation database"
142*cc02d7e2SAndroid Build Coastguard Worker    )
143*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("--include_external", action="store_true")
144*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("--include_genfiles", action="store_true")
145*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("--include_headers", action="store_true")
146*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("--vscode", action="store_true")
147*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("--ignore_system_headers", action="store_true")
148*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("--dedup_targets", action="store_true")
149*cc02d7e2SAndroid Build Coastguard Worker    parser.add_argument("bazel_targets", nargs="*", default=["//..."])
150*cc02d7e2SAndroid Build Coastguard Worker    args = parser.parse_args()
151*cc02d7e2SAndroid Build Coastguard Worker    fixCompilationDatabase(args, generateCompilationDatabase(args))
152