Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions rust/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ load(
"DEFAULT_NIGHTLY_VERSION",
"DEFAULT_STATIC_RUST_URL_TEMPLATES",
)
load("//rust/private:strip_level.bzl", "build_strip_levels")

_RUST_TOOLCHAIN_VERSIONS = [
rust_common.default_version,
Expand Down Expand Up @@ -113,7 +114,14 @@ def _rust_impl(module_ctx):
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
# Toolchains and their `strip_level_select`s are read from the same module
# so that the selects always match the toolchains they refine.
if root.tags.toolchain:
toolchains = root.tags.toolchain
strip_level_selects = root.tags.strip_level_select
else:
toolchains = rules_rust.tags.toolchain
strip_level_selects = rules_rust.tags.strip_level_select

for toolchain in toolchains:
if toolchain.extra_rustc_flags and toolchain.extra_rustc_flags_triples:
Expand All @@ -130,6 +138,8 @@ def _rust_impl(module_ctx):
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_rustc_flags else toolchain.extra_exec_rustc_flags_triples

triples = list(toolchain_triples.keys()) + list(toolchain.extra_target_triples)

rust_register_toolchains(
hub_name = "rust_toolchains",
dev_components = toolchain.dev_components,
Expand All @@ -143,7 +153,11 @@ def _rust_impl(module_ctx):
sha256s = toolchain.sha256s,
extra_target_triples = toolchain.extra_target_triples,
opt_level = toolchain.opt_level if toolchain.opt_level else None,
strip_level = toolchain.strip_level if toolchain.strip_level else None,
strip_level = build_strip_levels(
strip_level_selects = strip_level_selects,
default_strip_level = toolchain.strip_level,
triples = triples,
) if triples else None,
urls = toolchain.urls,
versions = toolchain.versions,
compact_windows_names = True,
Expand Down Expand Up @@ -300,11 +314,44 @@ _RUST_TOOLCHAIN_TAG = tag_class(
} | _COMMON_TAG_KWARGS,
)

_RUST_STRIP_LEVEL_SELECT = tag_class(
doc = """\
Override the `strip_level` for specific target triples.

```python
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.strip_level_select(
triples = ["x86_64-unknown-linux-gnu"],
opt = "symbols",
)
```
""",
attrs = {
"dbg": attr.string(
doc = "Strip level for the `dbg` compilation mode.",
default = "none",
),
"fastbuild": attr.string(
doc = "Strip level for the `fastbuild` compilation mode.",
default = "none",
),
"opt": attr.string(
doc = "Strip level for the `opt` compilation mode.",
default = "debuginfo",
),
"triples": attr.string_list(
doc = "The target triples these strip levels apply to.",
mandatory = True,
),
},
)

rust = module_extension(
doc = "Rust toolchain extension.",
implementation = _rust_impl,
tag_classes = {
"repository_set": _RUST_REPOSITORY_SET_TAG,
"strip_level_select": _RUST_STRIP_LEVEL_SELECT,
"toolchain": _RUST_TOOLCHAIN_TAG,
},
)
Expand Down
47 changes: 47 additions & 0 deletions rust/private/strip_level.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Helpers for looking up strip levels."""

def build_strip_levels(*, strip_level_selects, default_strip_level, triples):
"""Look up the per-triple `strip_level` with defaults.

Args:
strip_level_selects (list): The `strip_level_select` tags, each with a
`triples` list and specified strip levels.
default_strip_level (dict): The fallback strip levels.
triples (list): The target triples toolchains are being registered for.
Must not be empty.

Returns:
dict: Mapping of target triple to strip levels (compilation mode to
level).
"""
if not triples:
fail("`triples` must not be empty.")

levels_by_triple = {} # { "x86_64-darwin" : { "dbg" = ...} }
for select in strip_level_selects:
# a select fully defines the strip level for each mode
levels = {
"dbg": select.dbg,
"fastbuild": select.fastbuild,
"opt": select.opt,
}

# insert all of this select's triples
for triple in select.triples:
# error out if triple is selected multiple times
if triple in levels_by_triple:
fail("Triple `{}` is configured by more than one `strip_level_select` tag.".format(triple))
levels_by_triple[triple] = levels

strip_level = {}
for triple in triples:
if triple in levels_by_triple:
strip_level[triple] = levels_by_triple[triple]
elif default_strip_level:
strip_level[triple] = default_strip_level

# Honor selects for triples that aren't part of the default triple set.
for triple, levels in levels_by_triple.items():
strip_level.setdefault(triple, levels)

return strip_level
3 changes: 3 additions & 0 deletions test/unit/strip_level_select/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
load(":strip_level_select_test.bzl", "strip_level_select_test_suite")

strip_level_select_test_suite(name = "strip_level_select_test_suite")
107 changes: 107 additions & 0 deletions test/unit/strip_level_select/strip_level_select_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""Unit tests for `build_strip_levels`, backing the `rust.strip_level_select` tag."""

load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")

# buildifier: disable=bzl-visibility
load("//rust/private:strip_level.bzl", "build_strip_levels")

# Mirrors the `strip_level_select` tag's attribute defaults, which match the
# `rust_toolchain` strip level defaults.
def _select(triples, dbg = "none", fastbuild = "none", opt = "debuginfo"):
return struct(triples = triples, dbg = dbg, fastbuild = fastbuild, opt = opt)

_DEFAULT = {"dbg": "none", "fastbuild": "none", "opt": "none"}

def _build_strip_levels_test_impl(ctx):
env = unittest.begin(ctx)

# No selects and no default: nothing is configured.
asserts.equals(
env,
{},
build_strip_levels(
strip_level_selects = [],
default_strip_level = {},
triples = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin"],
),
)

# The default is applied to every triple when there are no selects.
asserts.equals(
env,
{
"aarch64-apple-darwin": _DEFAULT,
"x86_64-unknown-linux-gnu": _DEFAULT,
},
build_strip_levels(
strip_level_selects = [],
default_strip_level = _DEFAULT,
triples = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin"],
),
)

# A matching select overrides the default; unmatched triples keep the default.
asserts.equals(
env,
{
"aarch64-apple-darwin": _DEFAULT,
"x86_64-unknown-linux-gnu": {"dbg": "none", "fastbuild": "none", "opt": "symbols"},
},
build_strip_levels(
strip_level_selects = [
_select(["x86_64-unknown-linux-gnu"], opt = "symbols"),
],
default_strip_level = _DEFAULT,
triples = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin"],
),
)

# A select applies even when there is no default for the other triples.
asserts.equals(
env,
{"x86_64-unknown-linux-gnu": {"dbg": "none", "fastbuild": "none", "opt": "symbols"}},
build_strip_levels(
strip_level_selects = [
_select(["x86_64-unknown-linux-gnu"], opt = "symbols"),
],
default_strip_level = {},
triples = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin"],
),
)

# One select can target multiple triples, and selects for triples outside the
# default triple set are still honored.
selected = {"dbg": "none", "fastbuild": "none", "opt": "symbols"}
asserts.equals(
env,
{
"aarch64-apple-darwin": selected,
"wasm32-unknown-unknown": selected,
"x86_64-unknown-linux-gnu": selected,
},
build_strip_levels(
strip_level_selects = [
_select(
["x86_64-unknown-linux-gnu", "aarch64-apple-darwin", "wasm32-unknown-unknown"],
opt = "symbols",
),
],
default_strip_level = {},
triples = ["x86_64-unknown-linux-gnu", "aarch64-apple-darwin"],
),
)

return unittest.end(env)

build_strip_levels_test = unittest.make(_build_strip_levels_test_impl)

def strip_level_select_test_suite(name):
"""Unit tests for `build_strip_levels`.

Args:
name: the test suite name
"""
unittest.suite(
name,
build_strip_levels_test,
)
Loading