Skip to content

Commit 68103fa

Browse files
committed
Add miri_test
1 parent e8f3393 commit 68103fa

28 files changed

Lines changed: 1668 additions & 57 deletions

MODULE.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use_repo(
5252
bazel_dep(name = "bazel_lib", version = "3.0.0")
5353
bazel_dep(name = "bazel_features", version = "1.45.0")
5454
bazel_dep(name = "bazel_skylib", version = "1.4.1")
55+
bazel_dep(name = "hermetic_launcher", version = "0.0.8")
5556
bazel_dep(name = "package_metadata", version = "0.0.7")
5657
bazel_dep(name = "platforms", version = "1.1.0")
5758
bazel_dep(name = "protobuf", version = "34.0.bcr.1", repo_name = "com_google_protobuf")

MODULE.bazel.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rs/experimental/miri/BUILD.bazel

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
load("@bazel_lib//:bzl_library.bzl", "bzl_library")
2+
3+
package(default_visibility = ["//visibility:private"])
4+
5+
toolchain_type(
6+
name = "toolchain_type",
7+
visibility = ["//visibility:public"],
8+
)
9+
10+
toolchain_type(
11+
name = "sysroot_toolchain_type",
12+
visibility = ["//visibility:public"],
13+
)
14+
15+
bzl_library(
16+
name = "miri_test",
17+
srcs = ["miri_test.bzl"],
18+
visibility = ["//visibility:public"],
19+
deps = [
20+
"//rs/experimental/miri/private:compile",
21+
"//rs/experimental/miri/private:providers",
22+
"//rs/experimental/miri/private:toolchain",
23+
"@hermetic_launcher//launcher:lib_bzl",
24+
],
25+
)

rs/experimental/miri/miri_test.bzl

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
"""Miri test rule."""
2+
3+
load("@hermetic_launcher//launcher:lib.bzl", "launcher")
4+
load("//rs/experimental/miri/private:compile.bzl", "alias_for_dep", "miri_compile_aspect", "miri_extern_arg", "miri_process_wrapper_args", "miri_transitive_outputs")
5+
load("//rs/experimental/miri/private:providers.bzl", "MiriCrateInfo")
6+
load("//rs/experimental/miri/private:toolchain.bzl", "MIRI_TOOLCHAIN_TYPE")
7+
8+
def _default_crate_name(label):
9+
return label.name.replace("-", "_")
10+
11+
def _crate_root(ctx):
12+
if ctx.file.crate_root:
13+
return ctx.file.crate_root
14+
15+
for src in ctx.files.srcs:
16+
if src.basename in ("main.rs", "lib.rs"):
17+
return src
18+
19+
if len(ctx.files.srcs) == 1:
20+
return ctx.files.srcs[0]
21+
22+
fail("miri_test requires crate_root when srcs does not contain main.rs or lib.rs")
23+
24+
def _extern_arg(dep):
25+
return ["--extern", "{}={}".format(dep.name, dep.output.short_path)]
26+
27+
def _dirname(file):
28+
return file.dirname
29+
30+
def _short_path_dirname(file):
31+
path = file.short_path
32+
idx = path.rfind("/")
33+
return path[:idx] if idx != -1 else "."
34+
35+
def _direct_deps(ctx):
36+
direct_deps = []
37+
for dep in ctx.attr.deps:
38+
if MiriCrateInfo not in dep:
39+
continue
40+
miri_dep = dep[MiriCrateInfo]
41+
compiled_crate = miri_dep.target
42+
direct_deps.append(struct(
43+
name = alias_for_dep(ctx.attr.aliases, dep, miri_dep.crate_info),
44+
output = compiled_crate.output,
45+
transitive_inputs = compiled_crate.transitive_inputs,
46+
transitive_outputs = compiled_crate.transitive_outputs,
47+
))
48+
return direct_deps
49+
50+
def _declare_test_executable(ctx):
51+
name = ctx.label.name
52+
if ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]):
53+
name += ".exe"
54+
return ctx.actions.declare_file(name)
55+
56+
def _miri_compile_args(ctx, toolchain, crate_root, crate_name, direct_deps):
57+
args = ctx.actions.args()
58+
args.add(crate_root)
59+
args.add_all([
60+
"--crate-name",
61+
crate_name,
62+
"--crate-type",
63+
"bin",
64+
"--edition",
65+
ctx.attr.edition,
66+
"--test",
67+
"--target",
68+
toolchain.target_triple,
69+
"--cfg=miri",
70+
])
71+
args.add_all([toolchain.miri_sysroot], format_each = "--sysroot=%s", expand_directories = False)
72+
args.add_all(ctx.attr.rustc_flags)
73+
args.add_all(direct_deps, map_each = miri_extern_arg)
74+
args.add_all(
75+
miri_transitive_outputs(direct_deps),
76+
map_each = _dirname,
77+
format_each = "-Ldependency=%s",
78+
uniquify = True,
79+
)
80+
return args
81+
82+
def _emit_miri_check_action(ctx, toolchain, crate_root, crate_name, direct_deps):
83+
output = ctx.actions.declare_file(ctx.label.name + ".miri_check.rmeta")
84+
args = _miri_compile_args(ctx, toolchain, crate_root, crate_name, direct_deps)
85+
args.add(output, format = "--emit=metadata=%s")
86+
87+
ctx.actions.run(
88+
executable = toolchain.process_wrapper,
89+
arguments = miri_process_wrapper_args(ctx, toolchain, [], args),
90+
env = ctx.attr.env | {
91+
"MIRI_BE_RUSTC": "target",
92+
"MIRI_SYSROOT": toolchain.miri_sysroot.path,
93+
"REPOSITORY_NAME": ctx.label.workspace_name,
94+
},
95+
inputs = depset(
96+
direct = ctx.files.srcs + ctx.files.data + [crate_root],
97+
transitive = [toolchain.all_files] + [dep.transitive_inputs for dep in direct_deps],
98+
),
99+
outputs = [output],
100+
mnemonic = "MiriTestCheck",
101+
progress_message = "Compiling Miri test %{label}",
102+
toolchain = MIRI_TOOLCHAIN_TYPE,
103+
)
104+
return output
105+
106+
def _miri_runfiles(ctx, toolchain, crate_root, args_file, check_output, direct_deps):
107+
runfiles = ctx.runfiles(
108+
files = ctx.files.srcs + ctx.files.data + [crate_root, args_file, check_output, ctx.executable._runner],
109+
transitive_files = depset(transitive = [toolchain.all_files] + [dep.transitive_inputs for dep in direct_deps]),
110+
)
111+
return runfiles.merge_all(
112+
[ctx.attr._runner[DefaultInfo].default_runfiles] +
113+
[data[DefaultInfo].default_runfiles for data in ctx.attr.data if DefaultInfo in data],
114+
)
115+
116+
def _write_runner_args(ctx, toolchain, crate_root, crate_name, direct_deps):
117+
args_file = ctx.actions.declare_file(ctx.label.name + ".miri_runner_args")
118+
args = ctx.actions.args()
119+
args.set_param_file_format("multiline")
120+
args.add_all([
121+
toolchain.miri.short_path,
122+
"--sysroot",
123+
toolchain.miri_sysroot.short_path,
124+
crate_root.short_path,
125+
"--crate-name",
126+
crate_name,
127+
"--crate-type",
128+
"bin",
129+
"--edition",
130+
ctx.attr.edition,
131+
"--test",
132+
"--target",
133+
toolchain.target_triple,
134+
"--cfg=miri",
135+
])
136+
args.add_all(direct_deps, map_each = _extern_arg)
137+
args.add_all(
138+
miri_transitive_outputs(direct_deps),
139+
map_each = _short_path_dirname,
140+
format_each = "-Ldependency=%s",
141+
uniquify = True,
142+
)
143+
args.add_all(ctx.attr.rustc_flags)
144+
args.add_all(ctx.attr.miri_flags)
145+
args.add("--")
146+
args.add_all(ctx.attr.args)
147+
ctx.actions.write(args_file, args)
148+
return args_file
149+
150+
def _launcher_args(ctx, args_file):
151+
embedded_args, transformed_args = launcher.args_from_entrypoint(ctx.executable._runner)
152+
embedded_args.append("@" + args_file.short_path)
153+
return embedded_args, transformed_args
154+
155+
def _miri_test_impl(ctx):
156+
toolchain = ctx.toolchains[MIRI_TOOLCHAIN_TYPE]
157+
crate_root = _crate_root(ctx)
158+
crate_name = ctx.attr.crate_name or _default_crate_name(ctx.label)
159+
direct_deps = _direct_deps(ctx)
160+
check_output = _emit_miri_check_action(ctx, toolchain, crate_root, crate_name, direct_deps)
161+
args_file = _write_runner_args(ctx, toolchain, crate_root, crate_name, direct_deps)
162+
163+
executable = _declare_test_executable(ctx)
164+
embedded_args, transformed_args = _launcher_args(ctx, args_file)
165+
launcher.compile_stub(
166+
ctx = ctx,
167+
embedded_args = embedded_args,
168+
transformed_args = transformed_args,
169+
output_file = executable,
170+
)
171+
172+
return [
173+
DefaultInfo(
174+
executable = executable,
175+
files = depset([executable, check_output]),
176+
runfiles = _miri_runfiles(ctx, toolchain, crate_root, args_file, check_output, direct_deps),
177+
),
178+
RunEnvironmentInfo(environment = ctx.attr.env),
179+
]
180+
181+
miri_test = rule(
182+
implementation = _miri_test_impl,
183+
attrs = {
184+
"crate_name": attr.string(doc = "Rust crate name. Defaults to the target name with '-' replaced by '_'."),
185+
"crate_root": attr.label(allow_single_file = [".rs"]),
186+
"aliases": attr.label_keyed_string_dict(doc = "Remap direct dependencies to another extern crate name."),
187+
"data": attr.label_list(allow_files = True),
188+
"deps": attr.label_list(aspects = [miri_compile_aspect]),
189+
"edition": attr.string(default = "2021"),
190+
"env": attr.string_dict(doc = "Environment variables set while running Miri."),
191+
"miri_flags": attr.string_list(doc = "Extra flags passed to the Miri driver."),
192+
"rustc_flags": attr.string_list(doc = "Extra rustc-compatible flags passed to Miri."),
193+
"srcs": attr.label_list(allow_files = [".rs"], mandatory = True),
194+
"_runner": attr.label(
195+
default = Label("//rs/experimental/miri/private:miri_test_runner"),
196+
executable = True,
197+
cfg = "target",
198+
),
199+
"_windows_constraint": attr.label(default = "@platforms//os:windows"),
200+
},
201+
test = True,
202+
toolchains = [
203+
MIRI_TOOLCHAIN_TYPE,
204+
launcher.finalizer_toolchain_type,
205+
launcher.template_toolchain_type,
206+
],
207+
)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
load("@bazel_lib//:bzl_library.bzl", "bzl_library")
2+
load("//rs:rust_binary.bzl", "rust_binary")
3+
4+
package(default_visibility = ["//rs/experimental/miri:__pkg__"])
5+
6+
rust_binary(
7+
name = "miri_test_runner",
8+
srcs = ["miri_test_runner.rs"],
9+
crate_name = "miri_test_runner",
10+
edition = "2024",
11+
)
12+
13+
bzl_library(
14+
name = "providers",
15+
srcs = ["providers.bzl"],
16+
)
17+
18+
bzl_library(
19+
name = "toolchain",
20+
srcs = ["toolchain.bzl"],
21+
deps = [":providers"],
22+
)
23+
24+
bzl_library(
25+
name = "compile",
26+
srcs = ["compile.bzl"],
27+
deps = [
28+
":providers",
29+
":toolchain",
30+
"@bazel_skylib//lib:structs",
31+
"@rules_cc//cc/common",
32+
"@rules_rust//rust:bzl_lib",
33+
"@rules_rust//rust/platform:bzl_lib",
34+
"@rules_rust//rust/private:bzl_lib",
35+
],
36+
)
37+
38+
bzl_library(
39+
name = "sysroot",
40+
srcs = ["sysroot.bzl"],
41+
deps = [
42+
":compile",
43+
":providers",
44+
":toolchain",
45+
"@bazel_lib//lib:copy_to_directory",
46+
],
47+
)
48+
49+
bzl_library(
50+
name = "declare_toolchains",
51+
srcs = ["declare_toolchains.bzl"],
52+
deps = [
53+
":sysroot",
54+
":toolchain",
55+
"//rs/platforms:triples",
56+
"//rs/toolchains:toolchain_utils",
57+
"@rules_rust//rust/platform:bzl_lib",
58+
],
59+
)
60+
61+
bzl_library(
62+
name = "miri_repository",
63+
srcs = ["miri_repository.bzl"],
64+
visibility = ["//rs/toolchains:__pkg__"],
65+
deps = [
66+
"//rs/private:rust_repository_utils",
67+
"@rules_rust//rust/platform:bzl_lib",
68+
],
69+
)

0 commit comments

Comments
 (0)