-
Notifications
You must be signed in to change notification settings - Fork 564
Expand file tree
/
Copy pathextensions.bzl
More file actions
319 lines (289 loc) · 14.1 KB
/
extensions.bzl
File metadata and controls
319 lines (289 loc) · 14.1 KB
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
"""Module extensions for using rules_rust with bzlmod"""
load("@bazel_features//:features.bzl", "bazel_features")
load("//rust:defs.bzl", "rust_common")
load("//rust:repositories.bzl", "DEFAULT_TOOLCHAIN_TRIPLES", "rust_register_toolchains", "rust_repository_set", "rust_toolchain_tools_repository")
load("//rust/platform:triple.bzl", "get_host_triple")
load(
"//rust/private:repository_utils.bzl",
"DEFAULT_EXTRA_TARGET_TRIPLES",
"DEFAULT_NIGHTLY_VERSION",
"DEFAULT_STATIC_RUST_URL_TEMPLATES",
)
_RUST_TOOLCHAIN_VERSIONS = [
rust_common.default_version,
DEFAULT_NIGHTLY_VERSION,
]
def _find_modules(module_ctx):
# type: (module_ctx) -> tuple[bazel_module, bazel_module]
root = None
our_module = None
for mod in module_ctx.modules:
if mod.is_root:
root = mod
if mod.name == "rules_rust":
our_module = mod
if root == None:
root = our_module
if our_module == None:
fail("Unable to find rules_rust module")
return root, our_module
def _empty_repository_impl(repository_ctx):
repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
repository_ctx.name,
))
repository_ctx.file("BUILD.bazel", "")
_empty_repository = repository_rule(
doc = "Declare an empty repository.",
implementation = _empty_repository_impl,
)
def _rust_impl(module_ctx):
# type: (module_ctx) -> extension_metadata
# Toolchain configuration is only allowed in the root module, or in
# rules_rust.
# See https://github.com/bazelbuild/bazel/discussions/22024 for discussion.
root, rules_rust = _find_modules(module_ctx)
toolchain_triples = dict(DEFAULT_TOOLCHAIN_TRIPLES)
grouped_repository_sets = {}
for repository_set in root.tags.repository_set:
if repository_set.name not in grouped_repository_sets:
grouped_repository_sets[repository_set.name] = {
"allocator_library": repository_set.allocator_library,
"dev_components": repository_set.dev_components,
"edition": repository_set.edition,
"exec_triple": repository_set.exec_triple,
"extra_target_triples": {repository_set.target_triple: [str(v) for v in repository_set.target_compatible_with]},
"name": repository_set.name,
"opt_level": {repository_set.target_triple: repository_set.opt_level} if repository_set.opt_level else None,
"rustfmt_version": repository_set.rustfmt_version,
"sha256s": repository_set.sha256s,
"target_settings": [str(v) for v in repository_set.target_settings],
"urls": repository_set.urls,
"versions": repository_set.versions,
}
else:
for attr_name in _RUST_REPOSITORY_SET_TAG_ATTRS.keys():
if attr_name in ["extra_target_triples", "name", "target_compatible_with", "target_triple", "opt_level"]:
continue
attr_value = getattr(repository_set, attr_name, None)
if attr_value:
default_value = _COMMON_TAG_DEFAULTS.get(attr_name, None)
if not default_value or attr_value != default_value:
fail("You must only set `{}` on the first call to `repository_set` for a particular name but it was set multiple times for `{}`".format(attr_name, repository_set.name))
grouped_repository_sets[repository_set.name]["extra_target_triples"][repository_set.target_triple] = [str(v) for v in repository_set.target_compatible_with]
if repository_set.opt_level:
if grouped_repository_sets[repository_set.name]["opt_level"] == None:
grouped_repository_sets[repository_set.name]["opt_level"] = {}
grouped_repository_sets[repository_set.name]["opt_level"][repository_set.target_triple] = repository_set.opt_level
extra_toolchain_infos = {}
for repository_set in grouped_repository_sets.values():
toolchain_infos = rust_repository_set(
register_toolchain = False,
**repository_set
)
extra_toolchain_infos.update(**toolchain_infos)
if toolchain_triples.get(repository_set["exec_triple"]) == repository_set["name"]:
toolchain_triples.pop(repository_set["exec_triple"], None)
toolchains = root.tags.toolchain or rules_rust.tags.toolchain
for toolchain in toolchains:
if toolchain.extra_rustc_flags and toolchain.extra_rustc_flags_triples:
fail("Cannot define both extra_rustc_flags and extra_rustc_flags_triples")
if toolchain.extra_exec_rustc_flags and toolchain.extra_exec_rustc_flags_triples:
fail("Cannot define both extra_exec_rustc_flags and extra_exec_rustc_flags_triples")
if len(toolchain.versions) == 0:
# If the root module has asked for rules_rust to not register default
# toolchains, an empty repository named `rust_toolchains` is created
# so that the `register_toolchains()` in MODULES.bazel is still
# valid.
_empty_repository(name = "rust_toolchains")
else:
extra_rustc_flags = toolchain.extra_rustc_flags if toolchain.extra_rustc_flags else toolchain.extra_rustc_flags_triples
extra_exec_rustc_flags = toolchain.extra_exec_rustc_flags if toolchain.extra_exec_rustc_flags else toolchain.extra_exec_rustc_flags_triples
rust_register_toolchains(
hub_name = "rust_toolchains",
dev_components = toolchain.dev_components,
edition = toolchain.edition,
extra_rustc_flags = extra_rustc_flags,
extra_rustc_flags_exec = toolchain.extra_rustc_flags_exec_triples,
extra_exec_rustc_flags = extra_exec_rustc_flags,
extra_exec_rustc_flags_exec = toolchain.extra_exec_rustc_flags_exec_triples,
allocator_library = toolchain.allocator_library,
rustfmt_version = toolchain.rustfmt_version,
rust_analyzer_version = toolchain.rust_analyzer_version,
sha256s = toolchain.sha256s,
extra_target_triples = toolchain.extra_target_triples,
urls = toolchain.urls,
versions = toolchain.versions,
register_toolchains = False,
aliases = toolchain.aliases,
toolchain_triples = toolchain_triples,
target_settings = [str(v) for v in toolchain.target_settings],
extra_toolchain_infos = extra_toolchain_infos,
)
metadata_kwargs = {}
if bazel_features.external_deps.extension_metadata_has_reproducible:
metadata_kwargs["reproducible"] = True
return module_ctx.extension_metadata(**metadata_kwargs)
_COMMON_TAG_DEFAULTS = {
"allocator_library": "",
"rustfmt_version": DEFAULT_NIGHTLY_VERSION,
"urls": DEFAULT_STATIC_RUST_URL_TEMPLATES,
}
_COMMON_TAG_KWARGS = {
"allocator_library": attr.string(
doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.",
default = _COMMON_TAG_DEFAULTS["allocator_library"],
),
"dev_components": attr.bool(
doc = "Whether to download the rustc-dev components (defaults to False). Requires version to be \"nightly\".",
default = False,
),
"edition": attr.string(
doc = (
"The rust edition to be used by default (2015, 2018, or 2021). " +
"If absent, every rule is required to specify its `edition` attribute."
),
),
"rustfmt_version": attr.string(
doc = "The version of the tool among \"nightly\", \"beta\", or an exact version.",
default = _COMMON_TAG_DEFAULTS["rustfmt_version"],
),
"sha256s": attr.string_dict(
doc = "A dict associating tool subdirectories to sha256 hashes. See [rust_repositories](#rust_repositories) for more details.",
),
"urls": attr.string_list(
doc = "A list of mirror urls containing the tools from the Rust-lang static file server. These must contain the '{}' used to substitute the tool being fetched (using .format).",
default = _COMMON_TAG_DEFAULTS["urls"],
),
}
_RUST_REPOSITORY_SET_TAG_ATTRS = {
"exec_triple": attr.string(
doc = "Exec triple for this repository_set.",
),
"name": attr.string(
doc = "Name of the repository_set - if you're looking to replace default toolchains you must use the exact name you're replacing.",
),
"opt_level": attr.string_dict(
doc = "Rustc optimization levels. For more details see the documentation for `rust_toolchain.opt_level`.",
),
"target_compatible_with": attr.label_list(
doc = "List of platform constraints this toolchain produces, for the particular target_triple this call is for.",
),
"target_settings": attr.label_list(
doc = "A list of `config_settings` that must be satisfied by the target configuration in order for this toolchain to be selected during toolchain resolution.",
),
"target_triple": attr.string(
doc = "target_triple to configure.",
),
"versions": attr.string_list(
doc = (
"A list of toolchain versions to download. This parameter only accepts one version " +
"per channel. E.g. `[\"1.65.0\", \"nightly/2022-11-02\", \"beta/2020-12-30\"]`. " +
"May be set to an empty list (`[]`) to inhibit `rules_rust` from registering toolchains."
),
),
} | _COMMON_TAG_KWARGS
_RUST_REPOSITORY_SET_TAG = tag_class(
doc = "Tags for defining rust repository sets (where toolchains are defined).",
attrs = _RUST_REPOSITORY_SET_TAG_ATTRS,
)
_RUST_TOOLCHAIN_TAG = tag_class(
doc = "Tags for defining rust toolchains (where toolchain tools are fetched).",
attrs = {
"aliases": attr.string_dict(
doc = (
"Map of full toolchain repository name to an alias. If any repository is created by this " +
"extension matches a key in this dictionary, the name of the created repository will be " +
"remapped to the value instead. This may be required to work around path length limits " +
"on Windows."
),
default = {},
),
"extra_exec_rustc_flags": attr.string_list(
doc = "Extra flags to pass to rustc in exec configuration",
),
"extra_rustc_flags": attr.string_list(
doc = "Extra flags to pass to rustc in non-exec configuration",
),
"extra_exec_rustc_flags_triples": attr.string_list_dict(
doc = "Extra flags to pass to rustc in exec configuration. Key is the target triple, value is the flag.",
),
"extra_exec_rustc_flags_exec_triples": attr.string_list_dict(
doc = "Extra flags to pass to rustc in exec configuration. Key is the exec triple, value is the flag.",
),
"extra_rustc_flags_triples": attr.string_list_dict(
doc = "Extra flags to pass to rustc in non-exec configuration. Key is the target triple, value is the flag.",
),
"extra_rustc_flags_exec_triples": attr.string_list_dict(
doc = "Extra flags to pass to rustc in non-exec configuration. Key is the exec triple, value is the flag.",
),
"extra_target_triples": attr.string_list(
default = DEFAULT_EXTRA_TARGET_TRIPLES,
),
"rust_analyzer_version": attr.string(
doc = "The version of Rustc to pair with rust-analyzer.",
),
"target_settings": attr.label_list(
doc = "A list of `config_settings` that must be satisfied by the target configuration in order for this toolchain to be selected during toolchain resolution.",
),
"versions": attr.string_list(
doc = (
"A list of toolchain versions to download. This parameter only accepts one version " +
"per channel. E.g. `[\"1.65.0\", \"nightly/2022-11-02\", \"beta/2020-12-30\"]`. " +
"May be set to an empty list (`[]`) to inhibit `rules_rust` from registering toolchains."
),
default = _RUST_TOOLCHAIN_VERSIONS,
),
} | _COMMON_TAG_KWARGS,
)
rust = module_extension(
doc = "Rust toolchain extension.",
implementation = _rust_impl,
tag_classes = {
"repository_set": _RUST_REPOSITORY_SET_TAG,
"toolchain": _RUST_TOOLCHAIN_TAG,
},
)
_RUST_HOST_TOOLS_TAG = tag_class(
attrs = {
"name": attr.string(
doc = "The name of the module to create",
default = "rust_host_tools",
),
"version": attr.string(
doc = "The version of Rust to use for tools executed on the Bazel host.",
default = rust_common.default_version,
),
} | _COMMON_TAG_KWARGS,
)
# This is a separate module extension so that only the host tools are
# marked as reproducible and os and arch dependent
def _rust_host_tools_impl(module_ctx):
host_triple = get_host_triple(module_ctx)
for mod in module_ctx.modules:
for host_tools in mod.tags.host_tools:
attrs = {key: getattr(host_tools, key) for key in dir(host_tools)}
# Allow shorthand versions to follow the defaults
# defined by rules_rust.
if attrs["version"] == "nightly":
attrs["version"] = DEFAULT_NIGHTLY_VERSION
rust_toolchain_tools_repository(
exec_triple = host_triple.str,
target_triple = host_triple.str,
**attrs
)
metadata_kwargs = {}
if bazel_features.external_deps.extension_metadata_has_reproducible:
metadata_kwargs["reproducible"] = True
return module_ctx.extension_metadata(**metadata_kwargs)
_conditional_rust_host_tools_args = {
"arch_dependent": True,
"os_dependent": True,
} if bazel_features.external_deps.module_extension_has_os_arch_dependent else {}
rust_host_tools = module_extension(
doc = "An extension which exposes Rust tools compatible with the current host platform.",
implementation = _rust_host_tools_impl,
tag_classes = {
"host_tools": _RUST_HOST_TOOLS_TAG,
},
**_conditional_rust_host_tools_args
)