-
Notifications
You must be signed in to change notification settings - Fork 5.6k
/
Copy pathmod_scanner.bzl
177 lines (154 loc) · 6.41 KB
/
mod_scanner.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# 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")
# 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],
)