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


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:59:23