| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 | #!/usr/bin/env python3# Copyright 2020 gRPC authors.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.# This is based on the script on the Envoy project# https://github.com/envoyproxy/envoy/blob/master/tools/gen_compilation_database.pyimport argparseimport globimport jsonimport loggingimport osimport reimport shleximport subprocessfrom pathlib import PathRE_INCLUDE_SYSTEM = re.compile("\s*-I\s+/usr/[^ ]+")# This method is equivalent to https://github.com/grailbio/bazel-compilation-database/blob/master/generate.shdef generateCompilationDatabase(args):    # We need to download all remote outputs for generated source code.    # This option lives here to override those specified in bazelrc.    bazel_options = shlex.split(os.environ.get("BAZEL_BUILD_OPTIONS", "")) + [        "--config=compdb",        "--remote_download_outputs=all",    ]    subprocess.check_call(["bazel", "build"] + bazel_options + [        "--aspects=@bazel_compdb//:aspects.bzl%compilation_database_aspect",        "--output_groups=compdb_files,header_files"    ] + args.bazel_targets)    execroot = subprocess.check_output(["bazel", "info", "execution_root"] +                                       bazel_options).decode().strip()    compdb = []    for compdb_file in Path(execroot).glob("**/*.compile_commands.json"):        compdb.extend(            json.loads(                "[" +                compdb_file.read_text().replace("__EXEC_ROOT__", execroot) +                "]"))    if args.dedup_targets:        compdb_map = {target["file"]: target for target in compdb}        compdb = list(compdb_map.values())    return compdbdef isHeader(filename):    for ext in (".h", ".hh", ".hpp", ".hxx"):        if filename.endswith(ext):            return True    return Falsedef isCompileTarget(target, args):    filename = target["file"]    if not args.include_headers and isHeader(filename):        return False    if not args.include_genfiles:        if filename.startswith("bazel-out/"):            return False    if not args.include_external:        if filename.startswith("external/"):            return False    return Truedef modifyCompileCommand(target, args):    cc, options = target["command"].split(" ", 1)    # Workaround for bazel added C++11 options, those doesn't affect build itself but    # clang-tidy will misinterpret them.    options = options.replace("-std=c++0x ", "")    options = options.replace("-std=c++11 ", "")    if args.vscode:        # Visual Studio Code doesn't seem to like "-iquote". Replace it with        # old-style "-I".        options = options.replace("-iquote ", "-I ")    if args.ignore_system_headers:        # Remove all include options for /usr/* directories        options = RE_INCLUDE_SYSTEM.sub("", options)    if isHeader(target["file"]):        options += " -Wno-pragma-once-outside-header -Wno-unused-const-variable"        options += " -Wno-unused-function"        if not target["file"].startswith("external/"):            # *.h file is treated as C header by default while our headers files are all C++11.            options = "-x c++ -std=c++11 -fexceptions " + options    target["command"] = " ".join([cc, options])    return targetdef fixCompilationDatabase(args, db):    db = [        modifyCompileCommand(target, args)        for target in db        if isCompileTarget(target, args)    ]    with open("compile_commands.json", "w") as db_file:        json.dump(db, db_file, indent=2)if __name__ == "__main__":    parser = argparse.ArgumentParser(        description='Generate JSON compilation database')    parser.add_argument('--include_external', action='store_true')    parser.add_argument('--include_genfiles', action='store_true')    parser.add_argument('--include_headers', action='store_true')    parser.add_argument('--vscode', action='store_true')    parser.add_argument('--ignore_system_headers', action='store_true')    parser.add_argument('--dedup_targets', action='store_true')    parser.add_argument('bazel_targets', nargs='*', default=["//..."])    args = parser.parse_args()    fixCompilationDatabase(args, generateCompilationDatabase(args))
 |