Skip to content

Instantly share code, notes, and snippets.

@rrbutani
Created November 16, 2021 05:38
Show Gist options
  • Save rrbutani/b897b0b7c3d2347cff190ee6b5f57937 to your computer and use it in GitHub Desktop.
Save rrbutani/b897b0b7c3d2347cff190ee6b5f57937 to your computer and use it in GitHub Desktop.
.bazel-playground_aspect_in_a_transition
a PoC for this question on the Bazel slack: https://bazelbuild.slack.com/archives/CA31HN1T3/p1637031391447100
essentially, tries to have a transition on a rule use some attribute that was used to create a source of that rule using an aspect
in making this I realized that we can actually achieve the exact same thing by just having the rule producing the _source_ also create a provider giving us the information we want (rather than having to extract it with an aspect)
but that assumes we have control of that rule and can modify it and besides — this is a lot more fun anyways
unfortunately none of this works; transition function aren't allowed to access providers on attrs
this makes sense since transitions can _influence_ the providers exposed for a particular attribute
build --incompatible_enable_cc_toolchain_resolution
load(":defs.bzl", "plat_bin", "stripped_bin")
cc_binary(
name = "foo",
srcs = ["foo.cc"],
)
# `plat_bin` takes an executable target and builds it for a particular platform.
plat_bin(
name = "foo-x86",
src = ":foo",
platform = "@com_grail_bazel_toolchain//platforms:linux-x86_64",
)
plat_bin(
name = "foo-arm",
src = ":foo",
platform = "@com_grail_bazel_toolchain//platforms:linux-aarch64",
)
# `stripped_bin` produces a stripped binary (not actually; for the purposes
# of this demo it just give you back the same binary; note that if we were actually
# doing the stripping we'd *need* the transition so Bazel would give us a
# cc_toolchain capable of stripping <whatever executable format the particular
# platform uses>) *for the same platform as the source binary*.
stripped_bin(
name = "foo-x86-stripped",
src = ":foo-x86",
)
stripped_bin(
name = "foo-arm-stripped",
src = ":foo-arm",
)
def _platform_transition_impl(_settings, attrs):
return { "//command_line_option:platforms": [attrs.platform] }
_platform_transition = transition(
implementation = _platform_transition_impl,
inputs = [],
outputs = ["//command_line_option:platforms"],
)
def _plat_bin_impl(ctx):
out = ctx.attr.name
out = ctx.actions.declare_file(out)
ctx.actions.symlink(
output = out,
target_file = ctx.executable.src,
is_executable = True,
)
return [DefaultInfo(executable = out)]
plat_bin = rule(
implementation = _plat_bin_impl,
attrs = {
"src": attr.label(
doc = "TODO",
cfg = _platform_transition,
executable = True,
mandatory = True,
),
"platform": attr.label(
doc = "TODO",
providers = [], # hmmm
mandatory = True,
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
),
},
executable = True,
incompatible_use_toolchain_transition = True,
doc = "TODO",
)
_TargetPlatformInfo = provider(
fields = { 'plat': 'platform the target was built for' }
)
def _target_platform_aspect_impl(target, ctx):
if hasattr(ctx.rule.attr, "platform"):
return [_TargetPlatformInfo(plat = ctx.rule.attr.platform)]
else:
return []
_target_platform_aspect = aspect(
implementation = _target_platform_aspect_impl,
)
def _platform_transition_from_source_aspect_impl(settings, attrs):
print(attrs)
print(attrs.src)
if True or not _TargetPlatformInfo in attrs.src:
return settings
return { "//command_line_option:platforms": [attrs.src[_TargetPlatformInfo].plat] }
_platform_transition_from_source_aspect = transition(
implementation = _platform_transition_from_source_aspect_impl,
# Need to read in the existing `platforms` to fall back to them if we're given
# a `src` that's not a `plat_bin`.
inputs = ["//command_line_option:platforms"],
outputs = ["//command_line_option:platforms"],
)
def _stripped_bin_impl(ctx):
print(ctx.attr)
print(ctx.attr.src)
# TODO: actually strip the binary here using `ctx.toolchains[CcToolchain]` instead of
# just symlinking, etc.
out = ctx.attr.name
out = ctx.actions.declare_file(out)
ctx.actions.symlink(
output = out,
target_file = ctx.executable.src,
is_executable = True,
)
return [DefaultInfo(executable = out)]
stripped_bin = rule(
implementation = _stripped_bin_impl,
attrs = {
"src": attr.label(
doc = "TODO",
cfg = _platform_transition_from_source_aspect,
executable = True,
mandatory = True,
providers = [], # Don't actually need `CcInfo` for stripping...
aspects = [_target_platform_aspect],
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
),
},
executable = True,
toolchains = ["@rules_cc//cc:toolchain_type"],
incompatible_use_toolchain_transition = True,
doc = "TODO",
)
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
BAZEL_TOOLCHAIN_TAG = "0.6.3"
BAZEL_TOOLCHAIN_SHA = "da607faed78c4cb5a5637ef74a36fdd2286f85ca5192222c4664efec2d529bb8"
http_archive(
name = "com_grail_bazel_toolchain",
sha256 = BAZEL_TOOLCHAIN_SHA,
strip_prefix = "bazel-toolchain-{tag}".format(tag = BAZEL_TOOLCHAIN_TAG),
canonical_id = BAZEL_TOOLCHAIN_TAG,
url = "https://github.com/grailbio/bazel-toolchain/archive/{tag}.tar.gz".format(tag = BAZEL_TOOLCHAIN_TAG),
)
load("@com_grail_bazel_toolchain//toolchain:deps.bzl", "bazel_toolchain_dependencies")
bazel_toolchain_dependencies()
load("@com_grail_bazel_toolchain//toolchain:rules.bzl", "llvm_toolchain")
llvm_toolchain(
name = "llvm_toolchain",
llvm_version = "13.0.0",
)
load("@llvm_toolchain//:toolchains.bzl", "llvm_register_toolchains")
llvm_register_toolchains()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment