mirror of https://github.com/mongodb/mongo
179 lines
6.5 KiB
Python
179 lines
6.5 KiB
Python
# Based heavily on https://github.com/mongodb-forks/bazel_clang_tidy/blob/master/clang_tidy/clang_tidy.bzl
|
|
# mixed with skylib's run_binary.bzl, and then enhanced to use unused_inputs_list.
|
|
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
|
|
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
|
|
|
|
def _run_mod_scan(
|
|
ctx, # type: ctx
|
|
flags,
|
|
compilation_context, # type: CompilationContext
|
|
infile,
|
|
discriminator):
|
|
cc_toolchain = find_cpp_toolchain(ctx)
|
|
tool_inputs, tool_input_mfs = ctx.resolve_tools(tools = [ctx.attr._mod_scanner])
|
|
inputs = depset(
|
|
direct = (
|
|
[infile]
|
|
),
|
|
transitive = [compilation_context.headers, cc_toolchain.all_files],
|
|
)
|
|
|
|
# specify the output file - twice
|
|
outfile = ctx.actions.declare_file(
|
|
"mod_scanner/" + infile.path + "." + discriminator + ".mod_scanner_decls.json.zst",
|
|
)
|
|
unused_inputs = ctx.actions.declare_file(
|
|
"mod_scanner/" + infile.path + "." + discriminator + ".mod_scanner.unused_inputs",
|
|
)
|
|
|
|
# start args passed to the compiler
|
|
args = ctx.actions.args()
|
|
args.add(infile.path)
|
|
|
|
# add includes
|
|
args.add_all(compilation_context.framework_includes, before_each = "-F")
|
|
args.add_all(compilation_context.includes, before_each = "-I")
|
|
args.add_all(compilation_context.quote_includes, before_each = "-iquote")
|
|
args.add_all(compilation_context.system_includes, before_each = "-isystem")
|
|
args.add_all(compilation_context.external_includes, before_each = "-isystem")
|
|
|
|
# add args specified by the toolchain, on the command line and rule copts
|
|
args.add_all(flags)
|
|
|
|
# add defines
|
|
args.add_all(compilation_context.defines, before_each = "-D")
|
|
args.add_all(compilation_context.local_defines, before_each = "-D")
|
|
|
|
ctx.actions.run(
|
|
inputs = inputs,
|
|
outputs = [outfile, unused_inputs],
|
|
executable = ctx.executable._mod_scanner,
|
|
arguments = [args],
|
|
mnemonic = "ModScanner",
|
|
#use_default_shell_env = True,
|
|
env = {
|
|
"MOD_SCANNER_OUTPUT": outfile.path,
|
|
"MOD_SCANNER_UNUSED": unused_inputs.path,
|
|
},
|
|
progress_message = "Run mod_scanner on {}".format(infile.short_path),
|
|
tools = tool_inputs,
|
|
input_manifests = tool_input_mfs,
|
|
unused_inputs_list = unused_inputs,
|
|
)
|
|
return outfile
|
|
|
|
def _rule_sources(ctx):
|
|
def check_valid_file_type(src):
|
|
"""
|
|
Returns True if the file type matches one of the permitted srcs file types for C and C++ header/source files.
|
|
"""
|
|
permitted_file_types = [
|
|
".c",
|
|
".cc",
|
|
".cpp",
|
|
".cxx",
|
|
".c++",
|
|
".C",
|
|
# We only analyze cc files (headers are effectively analyzed by being #include-d)
|
|
# ".h", ".hh", ".hpp", ".hxx", ".inc", ".inl", ".H",
|
|
]
|
|
for file_type in permitted_file_types:
|
|
if src.basename.endswith(file_type):
|
|
return True
|
|
return False
|
|
|
|
srcs = []
|
|
if hasattr(ctx.rule.attr, "srcs"):
|
|
for src in ctx.rule.attr.srcs:
|
|
srcs += [src for src in src.files.to_list() if check_valid_file_type(src)]
|
|
|
|
# Filter sources down to only those that are Mongo-specific.
|
|
# Although we also apply a filter mechanism in the clang-tidy config itself, this filter mechanism
|
|
# ensures we don't run clang-tidy at *all* on #include-d headers. Without this filter, Bazel
|
|
# runs clang-tidy individual on each 3P header, which massively increases execution time.
|
|
# For a long-term fix, see https://github.com/erenon/bazel_clang_tidy/issues/64
|
|
return [src for src in srcs if "src/mongo/" in src.path and "third_party" not in src.path]
|
|
|
|
def _toolchain_flags(ctx, action_name = ACTION_NAMES.cpp_compile):
|
|
cc_toolchain = find_cpp_toolchain(ctx)
|
|
feature_configuration = cc_common.configure_features(
|
|
ctx = ctx,
|
|
cc_toolchain = cc_toolchain,
|
|
)
|
|
compile_variables = cc_common.create_compile_variables(
|
|
feature_configuration = feature_configuration,
|
|
cc_toolchain = cc_toolchain,
|
|
user_compile_flags = ctx.fragments.cpp.cxxopts + ctx.fragments.cpp.copts,
|
|
)
|
|
flags = cc_common.get_memory_inefficient_command_line(
|
|
feature_configuration = feature_configuration,
|
|
action_name = action_name,
|
|
variables = compile_variables,
|
|
)
|
|
return flags
|
|
|
|
def _safe_flags(flags):
|
|
# Some flags might be used by GCC, but not understood by Clang.
|
|
# Remove them here, to allow users to run clang-tidy, without having
|
|
# a clang toolchain configured (that would produce a good command line with --compiler clang)
|
|
unsupported_flags = [
|
|
"-fno-canonical-system-headers",
|
|
"-fstack-usage",
|
|
]
|
|
|
|
return [flag for flag in flags if flag not in unsupported_flags]
|
|
|
|
def _expand_flags(ctx, flags):
|
|
return [ctx.expand_make_variables("mod_scanner_expand_flags", flag, ctx.var) for flag in flags]
|
|
|
|
def _mod_scanner_aspect_impl(target, ctx):
|
|
# if not a C/C++ target, we are not interested
|
|
if not CcInfo in target:
|
|
return []
|
|
|
|
# Ignore external targets
|
|
if target.label.workspace_root.startswith("external"):
|
|
return []
|
|
|
|
# Targets with specific tags will not be scan
|
|
if "no-mod-scan" in ctx.rule.attr.tags:
|
|
return []
|
|
|
|
compilation_context = target[CcInfo].compilation_context
|
|
|
|
rule_flags = ctx.rule.attr.copts if hasattr(ctx.rule.attr, "copts") else []
|
|
c_flags = _expand_flags(ctx, _safe_flags(_toolchain_flags(ctx, ACTION_NAMES.c_compile) + rule_flags) + ["-xc"])
|
|
cxx_flags = _expand_flags(ctx, _safe_flags(_toolchain_flags(ctx, ACTION_NAMES.cpp_compile) + rule_flags) + ["-xc++"])
|
|
|
|
srcs = _rule_sources(ctx)
|
|
|
|
outputs = [
|
|
_run_mod_scan(
|
|
ctx,
|
|
c_flags if src.extension == "c" else cxx_flags,
|
|
compilation_context,
|
|
src,
|
|
target.label.name,
|
|
)
|
|
for src in srcs
|
|
]
|
|
|
|
return [
|
|
OutputGroupInfo(report = depset(direct = outputs)),
|
|
]
|
|
|
|
mod_scanner_aspect = aspect(
|
|
implementation = _mod_scanner_aspect_impl,
|
|
fragments = ["cpp"],
|
|
attrs = {
|
|
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
|
|
"_mod_scanner": attr.label(
|
|
default = Label(":mod_scanner"),
|
|
cfg = "exec",
|
|
executable = True,
|
|
),
|
|
},
|
|
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
|
|
required_providers = [CcInfo],
|
|
)
|