Skip to content

Commit 31cdc0f

Browse files
committed
Update cargo_build_script to work without runfiles support.
1 parent 5a8b98d commit 31cdc0f

File tree

8 files changed

+388
-24
lines changed

8 files changed

+388
-24
lines changed

.bazelci/presubmit.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,21 @@ default_windows_targets: &default_windows_targets
3636
- "//..."
3737
- "-//test/proto/..."
3838
- "-//test/unit/pipelined_compilation/..."
39+
default_windows_no_runfiles_targets: &default_windows_no_runfiles_targets
40+
- "--" # Allows negative patterns; hack for https://github.com/bazelbuild/continuous-integration/pull/245
41+
- "//..."
42+
# TODO: https://github.com/bazelbuild/rules_rust/issues/1156
43+
- "-//crate_universe/..."
44+
- "-//test/chained_direct_deps:mod3_doc_test"
45+
- "-//test/out_dir_in_tests:demo_lib_doc_test"
46+
- "-//test/proto/..."
47+
- "-//test/rustc_env_files:output_test"
48+
- "-//test/test_env_launcher:test"
49+
- "-//test/test_env:test_manifest_dir"
50+
- "-//test/test_env:test_run"
51+
- "-//test/unit/pipelined_compilation/..."
52+
- "-//test/unit/rustdoc/..."
53+
- "-//tools/runfiles/..."
3954
crate_universe_vendor_example_targets: &crate_universe_vendor_example_targets
4055
- "//vendor_external:crates_vendor"
4156
- "//vendor_local_manifests:crates_vendor"
@@ -82,6 +97,15 @@ tasks:
8297
platform: windows
8398
build_targets: *default_windows_targets
8499
test_targets: *default_windows_targets
100+
windows_no_runfiles:
101+
name: No Runfiles
102+
platform: windows
103+
build_flags:
104+
- "--noenable_runfiles"
105+
test_flags:
106+
- "--noenable_runfiles"
107+
build_targets: *default_windows_no_runfiles_targets
108+
test_targets: *default_windows_no_runfiles_targets
85109
ubuntu2004_split_coverage_postprocessing:
86110
name: Split Coverage Postprocessing
87111
platform: ubuntu2004
@@ -175,6 +199,19 @@ tasks:
175199
- "--config=clippy"
176200
build_targets: *default_windows_targets
177201
test_targets: *default_windows_targets
202+
windows_no_runfiles_with_aspects:
203+
name: No Runfiles With Aspects
204+
platform: windows
205+
build_flags:
206+
- "--noenable_runfiles"
207+
- "--config=rustfmt"
208+
- "--config=clippy"
209+
test_flags:
210+
- "--noenable_runfiles"
211+
- "--config=rustfmt"
212+
- "--config=clippy"
213+
build_targets: *default_windows_no_runfiles_targets
214+
test_targets: *default_windows_no_runfiles_targets
178215
windows_rolling_with_aspects:
179216
name: "Windows Rolling Bazel Version With Aspects"
180217
platform: windows

cargo/private/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
2+
load(":runfiles_enabled.bzl", "runfiles_enabled_build_setting")
23

34
bzl_library(
45
name = "bzl_lib",
56
srcs = glob(["**/*.bzl"]),
67
visibility = ["//:__subpackages__"],
78
)
9+
10+
runfiles_enabled_build_setting(
11+
name = "runfiles_enabled",
12+
visibility = ["//visibility:public"],
13+
)

cargo/private/cargo_build_script.bzl

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ load(
2323
"find_toolchain",
2424
_name_to_crate_name = "name_to_crate_name",
2525
)
26+
load(":runfiles_enabled.bzl", "is_runfiles_enabled", "runfiles_enabled_attr")
2627

2728
# Reexport for cargo_build_script_wrapper.bzl
2829
name_to_crate_name = _name_to_crate_name
@@ -198,6 +199,38 @@ def _feature_enabled(ctx, feature_name, default = False):
198199

199200
return default
200201

202+
def _rlocationpath(file, workspace_name):
203+
if file.short_path.startswith("../"):
204+
return file.short_path[len("../"):]
205+
206+
return "{}/{}".format(workspace_name, file.short_path)
207+
208+
def _create_runfiles_dir(ctx, script):
209+
runfiles_dir = ctx.actions.declare_directory("{}.cargo_runfiles".format(ctx.label.name))
210+
211+
# External repos always fall into the `../` branch of `_rlocationpath`.
212+
workspace_name = ctx.workspace_name
213+
214+
def _runfiles_map(file):
215+
return "{}={}".format(file.path, _rlocationpath(file, workspace_name))
216+
217+
runfiles = script[DefaultInfo].default_runfiles
218+
219+
args = ctx.actions.args()
220+
args.use_param_file("@%s", use_always = True)
221+
args.add(runfiles_dir.path)
222+
args.add_all(runfiles.files, map_each = _runfiles_map, allow_closure = True)
223+
224+
ctx.actions.run(
225+
mnemonic = "CargoBuildScriptRunfilesDir",
226+
executable = ctx.executable._runfiles_maker,
227+
arguments = [args],
228+
inputs = runfiles.files,
229+
outputs = [runfiles_dir],
230+
)
231+
232+
return runfiles_dir
233+
201234
def _cargo_build_script_impl(ctx):
202235
"""The implementation for the `cargo_build_script` rule.
203236
@@ -208,16 +241,37 @@ def _cargo_build_script_impl(ctx):
208241
list: A list containing a BuildInfo provider
209242
"""
210243
script = ctx.executable.script
244+
script_info = ctx.attr.script[CargoBuildScriptRunfilesInfo]
211245
toolchain = find_toolchain(ctx)
212246
out_dir = ctx.actions.declare_directory(ctx.label.name + ".out_dir")
213247
env_out = ctx.actions.declare_file(ctx.label.name + ".env")
214248
dep_env_out = ctx.actions.declare_file(ctx.label.name + ".depenv")
215249
flags_out = ctx.actions.declare_file(ctx.label.name + ".flags")
216250
link_flags = ctx.actions.declare_file(ctx.label.name + ".linkflags")
217251
link_search_paths = ctx.actions.declare_file(ctx.label.name + ".linksearchpaths") # rustc-link-search, propagated from transitive dependencies
218-
manifest_dir = "%s.runfiles/%s/%s" % (script.path, ctx.label.workspace_name or ctx.workspace_name, ctx.label.package)
219252
compilation_mode_opt_level = get_compilation_mode_opts(ctx, toolchain).opt_level
220253

254+
script_tools = []
255+
script_data = []
256+
for target in script_info.data:
257+
script_data.append(target[DefaultInfo].files)
258+
script_data.append(target[DefaultInfo].default_runfiles.files)
259+
for target in script_info.tools:
260+
script_tools.append(target[DefaultInfo].files)
261+
script_tools.append(target[DefaultInfo].default_runfiles.files)
262+
263+
workspace_name = ctx.label.workspace_name
264+
if not workspace_name:
265+
workspace_name = ctx.workspace_name
266+
267+
if not is_runfiles_enabled(ctx.attr):
268+
runfiles_dir = _create_runfiles_dir(ctx, ctx.attr.script)
269+
script_data.append(depset([runfiles_dir]))
270+
manifest_dir = "{}/{}/{}".format(runfiles_dir.path, workspace_name, ctx.label.package)
271+
else:
272+
script_data.append(ctx.attr.script[DefaultInfo].default_runfiles.files)
273+
manifest_dir = "{}.runfiles/{}/{}".format(script.path, workspace_name, ctx.label.package)
274+
221275
streams = struct(
222276
stdout = ctx.actions.declare_file(ctx.label.name + ".stdout.log"),
223277
stderr = ctx.actions.declare_file(ctx.label.name + ".stderr.log"),
@@ -331,8 +385,6 @@ def _cargo_build_script_impl(ctx):
331385
variables = getattr(target[platform_common.TemplateVariableInfo], "variables", depset([]))
332386
env.update(variables)
333387

334-
script_info = ctx.attr.script[CargoBuildScriptRunfilesInfo]
335-
336388
_merge_env_dict(env, expand_dict_value_locations(
337389
ctx,
338390
ctx.attr.build_script_env,
@@ -343,15 +395,6 @@ def _cargo_build_script_impl(ctx):
343395
script_info.tools,
344396
))
345397

346-
script_tools = []
347-
script_data = []
348-
for target in script_info.data:
349-
script_data.append(target[DefaultInfo].files)
350-
script_data.append(target[DefaultInfo].default_runfiles.files)
351-
for target in script_info.tools:
352-
script_tools.append(target[DefaultInfo].files)
353-
script_tools.append(target[DefaultInfo].default_runfiles.files)
354-
355398
tools = depset(
356399
direct = [
357400
script,
@@ -379,6 +422,7 @@ def _cargo_build_script_impl(ctx):
379422
args.add(ctx.attr.rundir)
380423

381424
build_script_inputs = []
425+
382426
for dep in ctx.attr.link_deps:
383427
if rust_common.dep_info in dep and dep[rust_common.dep_info].dep_env:
384428
dep_env_file = dep[rust_common.dep_info].dep_env
@@ -520,7 +564,14 @@ cargo_build_script = rule(
520564
"_experimental_symlink_execroot": attr.label(
521565
default = Label("//cargo/settings:experimental_symlink_execroot"),
522566
),
523-
},
567+
"_runfiles_maker": attr.label(
568+
cfg = "exec",
569+
executable = True,
570+
default = Label("//cargo/private/runfiles_maker"),
571+
),
572+
} | runfiles_enabled_attr(
573+
default = Label("//cargo/private:runfiles_enabled"),
574+
),
524575
fragments = ["cpp"],
525576
toolchains = [
526577
str(Label("//rust:toolchain_type")),

cargo/private/runfiles_enabled.bzl

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
"""A small utility module dedicated to detecting whether or not the `--enable_runfiles` and `--windows_enable_symlinks` flag are enabled
2+
"""
3+
4+
load("@bazel_skylib//lib:selects.bzl", "selects")
5+
load("@bazel_skylib//rules:common_settings.bzl", "bool_setting")
6+
7+
RunfilesEnabledInfo = provider(
8+
doc = "A singleton provider that contains the raw value of a build setting",
9+
fields = {
10+
"value": "The value of the build setting in the current configuration. " +
11+
"This value may come from the command line or an upstream transition, " +
12+
"or else it will be the build setting's default.",
13+
},
14+
)
15+
16+
def _runfiles_enabled_setting_impl(ctx):
17+
return RunfilesEnabledInfo(value = ctx.attr.value)
18+
19+
runfiles_enabled_setting = rule(
20+
implementation = _runfiles_enabled_setting_impl,
21+
doc = "A bool-typed build setting that cannot be set on the command line",
22+
attrs = {
23+
"value": attr.bool(
24+
doc = "A boolean value",
25+
mandatory = True,
26+
),
27+
},
28+
)
29+
30+
_RUNFILES_ENABLED_ATTR_NAME = "_runfiles_enabled"
31+
32+
def runfiles_enabled_attr(default):
33+
return {
34+
_RUNFILES_ENABLED_ATTR_NAME: attr.label(
35+
doc = "A flag representing whether or not runfiles are enabled.",
36+
providers = [RunfilesEnabledInfo],
37+
default = default,
38+
cfg = "exec",
39+
),
40+
}
41+
42+
def runfiles_enabled_build_setting(name, **kwargs):
43+
"""Define a build setting identifying if runfiles are enabled.
44+
45+
Args:
46+
name (str): The name of the build setting
47+
**kwargs: Additional keyword arguments for the target.
48+
"""
49+
native.config_setting(
50+
name = "{}__enable_runfiles".format(name),
51+
values = {"enable_runfiles": "true"},
52+
)
53+
54+
native.config_setting(
55+
name = "{}__disable_runfiles".format(name),
56+
values = {"enable_runfiles": "false"},
57+
)
58+
59+
bool_setting(
60+
name = "{}__always_true".format(name),
61+
build_setting_default = True,
62+
)
63+
64+
native.config_setting(
65+
name = "{}__always_true_setting".format(name),
66+
flag_values = {":{}__always_true".format(name): "True"},
67+
)
68+
69+
native.config_setting(
70+
name = "{}__always_false_setting".format(name),
71+
flag_values = {":{}__always_true".format(name): "False"},
72+
)
73+
74+
# There is no way to query a setting that is unset. By utilizing constant
75+
# settings, we can filter to a fallback setting where no known value is
76+
# defined.
77+
native.alias(
78+
name = "{}__unset_runfiles".format(name),
79+
actual = select({
80+
":{}__disable_runfiles".format(name): ":{}__always_false_setting".format(name),
81+
":{}__enable_runfiles".format(name): ":{}__always_false_setting".format(name),
82+
"//conditions:default": ":{}__always_true_setting".format(name),
83+
}),
84+
)
85+
86+
selects.config_setting_group(
87+
name = "{}__windows_enable_runfiles".format(name),
88+
match_all = [
89+
":{}__enable_runfiles".format(name),
90+
"@platforms//os:windows",
91+
],
92+
)
93+
94+
selects.config_setting_group(
95+
name = "{}__windows_disable_runfiles".format(name),
96+
match_all = [
97+
":{}__disable_runfiles".format(name),
98+
"@platforms//os:windows",
99+
],
100+
)
101+
102+
selects.config_setting_group(
103+
name = "{}__windows_unset_runfiles".format(name),
104+
match_all = [
105+
":{}__unset_runfiles".format(name),
106+
"@platforms//os:windows",
107+
],
108+
)
109+
110+
native.alias(
111+
name = "{}__unix".format(name),
112+
actual = select({
113+
"@platforms//os:windows": ":{}__always_false_setting".format(name),
114+
"//conditions:default": ":{}__always_true_setting".format(name),
115+
}),
116+
)
117+
118+
selects.config_setting_group(
119+
name = "{}__unix_enable_runfiles".format(name),
120+
match_all = [
121+
":{}__enable_runfiles".format(name),
122+
":{}__unix".format(name),
123+
],
124+
)
125+
126+
selects.config_setting_group(
127+
name = "{}__unix_disable_runfiles".format(name),
128+
match_all = [
129+
":{}__disable_runfiles".format(name),
130+
":{}__unix".format(name),
131+
],
132+
)
133+
134+
selects.config_setting_group(
135+
name = "{}__unix_unset_runfiles".format(name),
136+
match_all = [
137+
":{}__unset_runfiles".format(name),
138+
":{}__unix".format(name),
139+
],
140+
)
141+
142+
runfiles_enabled_setting(
143+
name = name,
144+
value = select({
145+
":{}__windows_enable_runfiles".format(name): True,
146+
":{}__windows_disable_runfiles".format(name): False,
147+
":{}__windows_unset_runfiles".format(name): False,
148+
":{}__unix_enable_runfiles".format(name): True,
149+
":{}__unix_disable_runfiles".format(name): False,
150+
":{}__unix_unset_runfiles".format(name): True,
151+
"//conditions:default": True,
152+
}),
153+
**kwargs
154+
)
155+
156+
def is_runfiles_enabled(attr):
157+
"""Determine whether or not runfiles are enabled.
158+
159+
Args:
160+
attr (struct): A rule's struct of attributes (`ctx.attr`)
161+
Returns:
162+
bool: The enable_runfiles value.
163+
"""
164+
165+
runfiles_enabled = getattr(attr, _RUNFILES_ENABLED_ATTR_NAME, None)
166+
167+
return runfiles_enabled[RunfilesEnabledInfo].value if runfiles_enabled else True
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
load("//rust:defs.bzl", "rust_binary")
2+
3+
rust_binary(
4+
name = "runfiles_maker",
5+
srcs = ["runfiles_maker.rs"],
6+
edition = "2021",
7+
visibility = ["//visibility:public"],
8+
)

0 commit comments

Comments
 (0)