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