Skip to content

Commit 7465c1a

Browse files
keithkrasimirgg
andauthored
Add test coverage support (#1324)
* WIP coverage support * Make it work * Regenerate documentation * Gate env vars on coverage being enabled * Add coverage targets * Allow 2 actions when generating coverage Co-authored-by: Krasimir Georgiev <[email protected]>
1 parent c5c3603 commit 7465c1a

File tree

11 files changed

+129
-12
lines changed

11 files changed

+129
-12
lines changed

.bazelci/presubmit.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ tasks:
2525
ubuntu2004:
2626
build_targets: *default_linux_targets
2727
test_targets: *default_linux_targets
28+
coverage_targets: *default_linux_targets
2829
rbe_ubuntu1604:
2930
shell_commands:
3031
- sed -i 's/^# load("@bazelci_rules/load("@bazelci_rules/' WORKSPACE.bazel
@@ -39,6 +40,7 @@ tasks:
3940
macos:
4041
build_targets: *default_macos_targets
4142
test_targets: *default_macos_targets
43+
coverage_targets: *default_macos_targets
4244
build_flags: *aspects_flags
4345
windows:
4446
build_flags:

docs/flatten.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,9 +1062,9 @@ Run the test with `bazel test //hello_lib:greeting_test`.
10621062

10631063
<pre>
10641064
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
1065-
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-env">env</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-llvm_tools">llvm_tools</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>,
1066-
<a href="#rust_toolchain-rust_lib">rust_lib</a>, <a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>,
1067-
<a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
1065+
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-env">env</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-llvm_cov">llvm_cov</a>, <a href="#rust_toolchain-llvm_profdata">llvm_profdata</a>, <a href="#rust_toolchain-llvm_tools">llvm_tools</a>,
1066+
<a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_lib">rust_lib</a>, <a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>,
1067+
<a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
10681068
</pre>
10691069

10701070
Declares a Rust toolchain for use.
@@ -1123,6 +1123,8 @@ See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX r
11231123
| <a id="rust_toolchain-dylib_ext"></a>dylib_ext | The extension for dynamic libraries created from rustc. | String | required | |
11241124
| <a id="rust_toolchain-env"></a>env | Environment variables to set in actions. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
11251125
| <a id="rust_toolchain-exec_triple"></a>exec_triple | The platform triple for the toolchains execution environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | required | |
1126+
| <a id="rust_toolchain-llvm_cov"></a>llvm_cov | The location of the <code>llvm-cov</code> binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
1127+
| <a id="rust_toolchain-llvm_profdata"></a>llvm_profdata | The location of the <code>llvm-profdata</code> binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
11261128
| <a id="rust_toolchain-llvm_tools"></a>llvm_tools | LLVM tools that are shipped with the Rust toolchain. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
11271129
| <a id="rust_toolchain-opt_level"></a>opt_level | Rustc optimization levels. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {"dbg": "0", "fastbuild": "0", "opt": "3"} |
11281130
| <a id="rust_toolchain-os"></a>os | The operating system for the current toolchain | String | required | |

docs/rust_repositories.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ A dedicated filegroup-like rule for Rust stdlib artifacts.
3535

3636
<pre>
3737
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
38-
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-env">env</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-llvm_tools">llvm_tools</a>, <a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>,
39-
<a href="#rust_toolchain-rust_lib">rust_lib</a>, <a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>, <a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>,
40-
<a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
38+
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-env">env</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-llvm_cov">llvm_cov</a>, <a href="#rust_toolchain-llvm_profdata">llvm_profdata</a>, <a href="#rust_toolchain-llvm_tools">llvm_tools</a>,
39+
<a href="#rust_toolchain-opt_level">opt_level</a>, <a href="#rust_toolchain-os">os</a>, <a href="#rust_toolchain-rust_doc">rust_doc</a>, <a href="#rust_toolchain-rust_lib">rust_lib</a>, <a href="#rust_toolchain-rust_std">rust_std</a>, <a href="#rust_toolchain-rustc">rustc</a>, <a href="#rust_toolchain-rustc_lib">rustc_lib</a>, <a href="#rust_toolchain-rustc_srcs">rustc_srcs</a>, <a href="#rust_toolchain-rustfmt">rustfmt</a>,
40+
<a href="#rust_toolchain-staticlib_ext">staticlib_ext</a>, <a href="#rust_toolchain-stdlib_linkflags">stdlib_linkflags</a>, <a href="#rust_toolchain-target_json">target_json</a>, <a href="#rust_toolchain-target_triple">target_triple</a>)
4141
</pre>
4242

4343
Declares a Rust toolchain for use.
@@ -96,6 +96,8 @@ See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX r
9696
| <a id="rust_toolchain-dylib_ext"></a>dylib_ext | The extension for dynamic libraries created from rustc. | String | required | |
9797
| <a id="rust_toolchain-env"></a>env | Environment variables to set in actions. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
9898
| <a id="rust_toolchain-exec_triple"></a>exec_triple | The platform triple for the toolchains execution environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | required | |
99+
| <a id="rust_toolchain-llvm_cov"></a>llvm_cov | The location of the <code>llvm-cov</code> binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
100+
| <a id="rust_toolchain-llvm_profdata"></a>llvm_profdata | The location of the <code>llvm-profdata</code> binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
99101
| <a id="rust_toolchain-llvm_tools"></a>llvm_tools | LLVM tools that are shipped with the Rust toolchain. | <a href="https://bazel.build/docs/build-ref.html#labels">Label</a> | optional | None |
100102
| <a id="rust_toolchain-opt_level"></a>opt_level | Rustc optimization levels. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {"dbg": "0", "fastbuild": "0", "opt": "3"} |
101103
| <a id="rust_toolchain-os"></a>os | The operating system for the current toolchain | String | required | |

rust/private/repository_utils.bzl

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,35 @@ def BUILD_for_clippy(target_triple):
137137
system = triple_to_system(target_triple)
138138
return _build_file_for_clippy_template.format(binary_ext = system_to_binary_ext(system))
139139

140+
_build_file_for_llvm_tools = """\
141+
filegroup(
142+
name = "llvm_cov_bin",
143+
srcs = ["lib/rustlib/{target_triple}/bin/llvm-cov{binary_ext}"],
144+
visibility = ["//visibility:public"],
145+
)
146+
147+
filegroup(
148+
name = "llvm_profdata_bin",
149+
srcs = ["lib/rustlib/{target_triple}/bin/llvm-profdata{binary_ext}"],
150+
visibility = ["//visibility:public"],
151+
)
152+
"""
153+
154+
def BUILD_for_llvm_tools(target_triple):
155+
"""Emits a BUILD file the llvm-tools binaries.
156+
157+
Args:
158+
target_triple (str): The triple of the target platform
159+
160+
Returns:
161+
str: The contents of a BUILD file
162+
"""
163+
system = triple_to_system(target_triple)
164+
return _build_file_for_llvm_tools.format(
165+
binary_ext = system_to_binary_ext(system),
166+
target_triple = target_triple,
167+
)
168+
140169
_build_file_for_stdlib_template = """\
141170
load("@rules_rust//rust:toolchain.bzl", "rust_stdlib_filegroup")
142171
@@ -189,6 +218,8 @@ rust_toolchain(
189218
rustfmt = {rustfmt_label},
190219
cargo = "@{workspace_name}//:cargo",
191220
clippy_driver = "@{workspace_name}//:clippy_driver_bin",
221+
llvm_cov = {llvm_cov_label},
222+
llvm_profdata = {llvm_profdata_label},
192223
rustc_lib = "@{workspace_name}//:rustc_lib",
193224
rustc_srcs = {rustc_srcs},
194225
binary_ext = "{binary_ext}",
@@ -211,6 +242,7 @@ def BUILD_for_rust_toolchain(
211242
include_rustc_srcs,
212243
default_edition,
213244
include_rustfmt,
245+
include_llvm_tools,
214246
stdlib_linkflags = None):
215247
"""Emits a toolchain declaration to match an existing compiler and stdlib.
216248
@@ -222,6 +254,7 @@ def BUILD_for_rust_toolchain(
222254
include_rustc_srcs (bool, optional): Whether to download rustc's src code. This is required in order to use rust-analyzer support. Defaults to False.
223255
default_edition (str): Default Rust edition.
224256
include_rustfmt (bool): Whether rustfmt is present in the toolchain.
257+
include_llvm_tools (bool): Whether llvm-tools are present in the toolchain.
225258
stdlib_linkflags (list, optional): Overriden flags needed for linking to rust
226259
stdlib, akin to BAZEL_LINKLIBS. Defaults to
227260
None.
@@ -240,6 +273,11 @@ def BUILD_for_rust_toolchain(
240273
rustfmt_label = "None"
241274
if include_rustfmt:
242275
rustfmt_label = "\"@{workspace_name}//:rustfmt_bin\"".format(workspace_name = workspace_name)
276+
llvm_cov_label = "None"
277+
llvm_profdata_label = "None"
278+
if include_llvm_tools:
279+
llvm_cov_label = "\"@{workspace_name}//:llvm_cov_bin\"".format(workspace_name = workspace_name)
280+
llvm_profdata_label = "\"@{workspace_name}//:llvm_profdata_bin\"".format(workspace_name = workspace_name)
243281

244282
return _build_file_for_rust_toolchain_template.format(
245283
toolchain_name = name,
@@ -254,6 +292,8 @@ def BUILD_for_rust_toolchain(
254292
exec_triple = exec_triple,
255293
target_triple = target_triple,
256294
rustfmt_label = rustfmt_label,
295+
llvm_cov_label = llvm_cov_label,
296+
llvm_profdata_label = llvm_profdata_label,
257297
)
258298

259299
_build_file_for_toolchain_template = """\
@@ -369,12 +409,13 @@ filegroup(
369409
)""",
370410
)
371411

372-
def load_rust_stdlib(ctx, target_triple):
412+
def load_rust_stdlib(ctx, target_triple, include_llvm_tools):
373413
"""Loads a rust standard library and yields corresponding BUILD for it
374414
375415
Args:
376416
ctx (repository_ctx): A repository_ctx.
377417
target_triple (str): The rust-style target triple of the tool
418+
include_llvm_tools (bool): Whether to include LLVM tools in the toolchain
378419
379420
Returns:
380421
str: The BUILD file contents for this stdlib, and a toolchain decl to match
@@ -408,6 +449,7 @@ def load_rust_stdlib(ctx, target_triple):
408449
workspace_name = ctx.attr.name,
409450
default_edition = ctx.attr.edition,
410451
include_rustfmt = not (not ctx.attr.rustfmt_version),
452+
include_llvm_tools = include_llvm_tools,
411453
)
412454

413455
return stdlib_build_file + toolchain_build_file
@@ -449,6 +491,8 @@ def load_llvm_tools(ctx, target_triple):
449491
version = ctx.attr.version,
450492
)
451493

494+
return BUILD_for_llvm_tools(target_triple)
495+
452496
def check_version_valid(version, iso_date, param_prefix = ""):
453497
"""Verifies that the provided rust version and iso_date make sense.
454498

rust/private/rust.bzl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ def _rust_test_common(ctx, toolchain, output):
466466
getattr(ctx.attr, "env", {}),
467467
data,
468468
)
469+
if ctx.configuration.coverage_enabled:
470+
env["RUST_LLVM_COV"] = toolchain.llvm_cov.path
471+
env["RUST_LLVM_PROFDATA"] = toolchain.llvm_profdata.path
469472
providers.append(testing.TestEnvironment(env))
470473

471474
return providers
@@ -649,6 +652,11 @@ _common_attrs = {
649652
"_cc_toolchain": attr.label(
650653
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
651654
),
655+
"_collect_cc_coverage": attr.label(
656+
default = "//util:collect_coverage",
657+
executable = True,
658+
cfg = "exec",
659+
),
652660
"_error_format": attr.label(default = "//:error_format"),
653661
"_extra_exec_rustc_flags": attr.label(default = "//:extra_exec_rustc_flags"),
654662
"_extra_rustc_flags": attr.label(default = "//:extra_rustc_flags"),

rust/private/rustc.bzl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,9 @@ def construct_arguments(
805805
rustc_flags.add("--extern")
806806
rustc_flags.add("proc_macro")
807807

808+
if ctx.configuration.coverage_enabled:
809+
rustc_flags.add("--codegen=instrument-coverage")
810+
808811
# Make bin crate data deps available to tests.
809812
for data in getattr(attr, "data", []):
810813
if rust_common.crate_info in data:
@@ -993,8 +996,12 @@ def rustc_compile_action(
993996
),
994997
)
995998

999+
coverage_runfiles = []
1000+
if toolchain.llvm_cov and ctx.configuration.coverage_enabled and crate_info.is_test:
1001+
coverage_runfiles = [toolchain.llvm_cov, toolchain.llvm_profdata]
1002+
9961003
runfiles = ctx.runfiles(
997-
files = getattr(ctx.files, "data", []),
1004+
files = getattr(ctx.files, "data", []) + coverage_runfiles,
9981005
collect_data = True,
9991006
)
10001007

@@ -1009,6 +1016,12 @@ def rustc_compile_action(
10091016
runfiles = runfiles,
10101017
executable = crate_info.output if crate_info.type == "bin" or crate_info.is_test or out_binary else None,
10111018
),
1019+
coverage_common.instrumented_files_info(
1020+
ctx,
1021+
dependency_attributes = ["deps", "crate"],
1022+
extensions = ["rs"],
1023+
source_attributes = ["srcs"],
1024+
),
10121025
]
10131026

10141027
if crate_info.type in ["staticlib", "cdylib"]:

rust/repositories.bzl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,12 @@ def _rust_toolchain_repository_impl(ctx):
173173
build_components.append(load_rustfmt(ctx))
174174

175175
# Rust 1.45.0 and nightly builds after 2020-05-22 need the llvm-tools gzip to get the libLLVM dylib
176-
if ctx.attr.version >= "1.45.0" or (ctx.attr.version == "nightly" and ctx.attr.iso_date > "2020-05-22"):
177-
load_llvm_tools(ctx, ctx.attr.exec_triple)
176+
include_llvm_tools = ctx.attr.version >= "1.45.0" or (ctx.attr.version == "nightly" and ctx.attr.iso_date > "2020-05-22")
177+
if include_llvm_tools:
178+
build_components.append(load_llvm_tools(ctx, ctx.attr.exec_triple))
178179

179180
for target_triple in [ctx.attr.exec_triple] + ctx.attr.extra_target_triples:
180-
build_components.append(load_rust_stdlib(ctx, target_triple))
181+
build_components.append(load_rust_stdlib(ctx, target_triple, include_llvm_tools))
181182

182183
# extra_target_triples contains targets such as wasm, which don't have rustc_dev components
183184
if ctx.attr.dev_components and target_triple not in ctx.attr.extra_target_triples:

rust/toolchain.bzl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ def _rust_toolchain_impl(ctx):
495495
env = ctx.attr.env,
496496
exec_triple = ctx.attr.exec_triple,
497497
libstd_and_allocator_ccinfo = _make_libstd_and_allocator_ccinfo(ctx, rust_std, ctx.attr.allocator_library),
498+
llvm_cov = ctx.file.llvm_cov,
499+
llvm_profdata = ctx.file.llvm_profdata,
498500
make_variables = platform_common.TemplateVariableInfo(make_variables),
499501
os = ctx.attr.os,
500502
rust_doc = sysroot.rustdoc,
@@ -569,6 +571,16 @@ rust_toolchain = rule(
569571
),
570572
mandatory = True,
571573
),
574+
"llvm_cov": attr.label(
575+
doc = "The location of the `llvm-cov` binary. Can be a direct source or a filegroup containing one item.",
576+
allow_single_file = True,
577+
cfg = "exec",
578+
),
579+
"llvm_profdata": attr.label(
580+
doc = "The location of the `llvm-profdata` binary. Can be a direct source or a filegroup containing one item.",
581+
allow_single_file = True,
582+
cfg = "exec",
583+
),
572584
"llvm_tools": attr.label(
573585
doc = "LLVM tools that are shipped with the Rust toolchain.",
574586
allow_files = True,

test/unit/native_deps/native_deps_test.bzl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ def _staticlib_has_native_libs_test_impl(ctx):
4848
def _proc_macro_has_native_libs_test_impl(ctx):
4949
env = analysistest.begin(ctx)
5050
tut = analysistest.target_under_test(env)
51-
asserts.equals(env, 1, len(tut.actions))
51+
if ctx.configuration.coverage_enabled:
52+
asserts.equals(env, 2, len(tut.actions))
53+
else:
54+
asserts.equals(env, 1, len(tut.actions))
5255
action = tut.actions[0]
5356
assert_argv_contains_prefix_suffix(env, action, "-Lnative=", "/native_deps")
5457
assert_argv_contains(env, action, "--crate-type=proc-macro")

util/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,9 @@ filegroup(
1616
],
1717
visibility = ["//:__subpackages__"],
1818
)
19+
20+
filegroup(
21+
name = "collect_coverage",
22+
srcs = ["collect_coverage.sh"],
23+
visibility = ["//visibility:public"],
24+
)

0 commit comments

Comments
 (0)