Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Transition on edges not nodes #3107

Closed
wants to merge 12 commits into from
Closed
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
100 changes: 50 additions & 50 deletions docs/go/core/rules.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions go/private/rules/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ bzl_library(
"//go/private:mode",
"//go/private:providers",
"//go/private/rules:transition",
"@bazel_skylib//lib:dicts",
],
)

Expand Down Expand Up @@ -117,6 +118,7 @@ bzl_library(
"//go/private:providers",
"//go/private/rules:binary",
"//go/private/rules:transition",
"@bazel_skylib//lib:dicts",
"@bazel_skylib//lib:structs",
],
)
Expand All @@ -133,6 +135,7 @@ bzl_library(
"//go/private:mode",
"//go/private:platforms",
"//go/private:providers",
"//go/private/skylib/lib:dicts",
],
)

Expand Down
440 changes: 230 additions & 210 deletions go/private/rules/binary.bzl

Large diffs are not rendered by default.

480 changes: 257 additions & 223 deletions go/private/rules/test.bzl

Large diffs are not rendered by default.

163 changes: 118 additions & 45 deletions go/private/rules/transition.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ load(
"//go/platform:crosstool.bzl",
"platform_from_crosstool",
)
load(
"//go/private/skylib/lib:dicts.bzl",
"dicts",
)

def filter_transition_label(label):
"""Transforms transition labels for the current workspace.
Expand All @@ -54,7 +58,24 @@ def filter_transition_label(label):
else:
return str(Label(label))

def go_transition_wrapper(kind, transition_kind, name, **kwargs):
ForwardingPastTransitionProvider = provider(
"""Provider for a go_transition_wrapper to forward information from its dep.

go_transition_wrapper symlinks outputs from some rule, after performing a
transition on the rule it depends on. It also forwards all of the providers
from that rule.

This provider allows structured passing of the required data in order to
perform that forwarding.
""",
fields = {
"executable": "File: The executable of the dep, which should be symlinked to.",
"runfiles": "Runfiles: The runfiles of the dep.",
"providers_to_forward": "[Provider]: The providers the transition-wrapping rule should expose.",
},
)

def go_transition_wrapper(kind, transition_kind, name, use_basename, keys_to_strip, **kwargs):
"""Wrapper for rules that may use transitions.

This is used in place of instantiating go_binary or go_transition_binary
Expand All @@ -64,51 +85,68 @@ def go_transition_wrapper(kind, transition_kind, name, **kwargs):
configuration identical to the default configuration.
"""
transition_keys = ("goos", "goarch", "pure", "static", "msan", "race", "gotags", "linkmode")
keys_to_strip = [k for k in keys_to_strip if k not in transition_keys]
need_transition = any([key in kwargs for key in transition_keys])
if need_transition:
transition_kind(name = name, **kwargs)
transitioned_name = name + ".transitioned"

# Strip out attrs that are expected by the underlying rule.
# This means that we strip out things like srcs, because we don't need them,
# but preserve things like tags and exec_compatible_with,
# which are general to all tests rather than specific to go_test specifically,
# and should apply to generated tests and binaries too.
transition_kwargs = dicts.omit(kwargs, keys_to_strip)
transition_kwargs["name"] = name
transition_kwargs["transition_dep"] = transitioned_name
transition_kwargs["is_windows"] = select({
"@bazel_tools//src/conditions:windows": True,
"//conditions:default": False,
})
transition_kind(**transition_kwargs)
tags = kwargs.pop("tags", [])
if "manual" not in tags:
tags += ["manual"]
kwargs["tags"] = tags
if use_basename and "basename" not in kwargs:
kwargs["basename"] = name
kind(name = transitioned_name, **kwargs)
else:
kind(name = name, **kwargs)

def go_transition_rule(**kwargs):
"""Like "rule", but adds a transition and mode attributes."""
kwargs = dict(kwargs)
kwargs["attrs"].update({
"goos": attr.string(
default = "auto",
values = ["auto"] + {goos: None for goos, _ in GOOS_GOARCH}.keys(),
),
"goarch": attr.string(
default = "auto",
values = ["auto"] + {goarch: None for _, goarch in GOOS_GOARCH}.keys(),
),
"pure": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"static": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"msan": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"race": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"gotags": attr.string_list(default = []),
"linkmode": attr.string(
default = "auto",
values = ["auto"] + LINKMODES,
),
"_whitelist_function_transition": attr.label(
default = "@bazel_tools//tools/whitelists/function_transition_whitelist",
),
})
kwargs["cfg"] = go_transition
return rule(**kwargs)
transition_attrs = {
"goos": attr.string(
default = "auto",
values = ["auto"] + {goos: None for goos, _ in GOOS_GOARCH}.keys(),
),
"goarch": attr.string(
default = "auto",
values = ["auto"] + {goarch: None for _, goarch in GOOS_GOARCH}.keys(),
),
"pure": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"static": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"msan": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"race": attr.string(
default = "auto",
values = ["auto", "on", "off"],
),
"gotags": attr.string_list(default = []),
"linkmode": attr.string(
default = "auto",
values = ["auto"] + LINKMODES,
),
"_whitelist_function_transition": attr.label(
default = "@bazel_tools//tools/whitelists/function_transition_whitelist",
),
}

def _go_transition_impl(settings, attr):
# NOTE(bazelbuild/bazel#11409): Calling fail here for invalid combinations
Expand Down Expand Up @@ -267,7 +305,7 @@ def _go_reset_target_impl(ctx):

new_executable = None
original_executable = default_info.files_to_run.executable
default_runfiles = default_info.default_runfiles
runfiles_wrapper = default_info
if original_executable:
# In order for the symlink to have the same basename as the original
# executable (important in the case of proto plugins), put it in a
Expand All @@ -278,13 +316,13 @@ def _go_reset_target_impl(ctx):
target_file = original_executable,
is_executable = True,
)
default_runfiles = default_runfiles.merge(ctx.runfiles([new_executable]))
runfiles_wrapper = _add_to_runfiles(ctx, runfiles_wrapper, new_executable)

providers.append(
DefaultInfo(
files = default_info.files,
data_runfiles = default_info.data_runfiles,
default_runfiles = default_runfiles,
data_runfiles = runfiles_wrapper.data_runfiles,
default_runfiles = runfiles_wrapper.default_runfiles,
executable = new_executable,
),
)
Expand Down Expand Up @@ -325,3 +363,38 @@ def _set_ternary(settings, attr, name):
label = filter_transition_label("@io_bazel_rules_go//go/config:{}".format(name))
settings[label] = value == "on"
return value

def _symlink_file_to_rule_name(ctx, src):
output_file_name = ctx.label.name + (".exe" if ctx.attr.is_windows else "")
dst = ctx.actions.declare_file(output_file_name)
ctx.actions.symlink(
output = dst,
target_file = src,
is_executable = True,
)
return dst

def _add_to_runfiles(ctx, default_info, file):
if file == None:
return default_info

data_runfiles = default_info.data_runfiles.merge(ctx.runfiles([file]))
default_runfiles = default_info.data_runfiles.merge(ctx.runfiles([file]))
return struct(
data_runfiles = data_runfiles,
default_runfiles = default_runfiles,
)

def forward_through_transition_impl(ctx):
forwarding_provider = ctx.attr.transition_dep[0][ForwardingPastTransitionProvider]
default_info = ctx.attr.transition_dep[0][DefaultInfo]

copied_executable = _symlink_file_to_rule_name(ctx, forwarding_provider.executable)
runfiles = _add_to_runfiles(ctx, default_info, copied_executable)

return [DefaultInfo(
executable = copied_executable,
files = default_info.files,
data_runfiles = runfiles.data_runfiles,
default_runfiles = runfiles.default_runfiles,
)] + forwarding_provider.providers_to_forward
6 changes: 4 additions & 2 deletions go/private/rules/wrappers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ load(
load(
"//go/private/rules:binary.bzl",
"go_binary",
"go_binary_attrs",
"go_transition_binary",
)
load(
"//go/private/rules:test.bzl",
"go_test",
"go_test_attrs",
"go_transition_test",
)
load(
Expand All @@ -48,7 +50,7 @@ def go_library_macro(name, **kwargs):
def go_binary_macro(name, **kwargs):
"""See docs/go/core/rules.md#go_binary for full documentation."""
_cgo(name, kwargs)
go_transition_wrapper(go_binary, go_transition_binary, name = name, **kwargs)
go_transition_wrapper(go_binary, go_transition_binary, name = name, use_basename = True, keys_to_strip = go_binary_attrs.keys(), **kwargs)
if kwargs.get("linkmode") in (LINKMODE_C_ARCHIVE, LINKMODE_C_SHARED):
# Create an alias to tell users of the `.cc` rule that it is deprecated.
native.alias(
Expand All @@ -62,4 +64,4 @@ def go_binary_macro(name, **kwargs):
def go_test_macro(name, **kwargs):
"""See docs/go/core/rules.md#go_test for full documentation."""
_cgo(name, kwargs)
go_transition_wrapper(go_test, go_transition_test, name = name, **kwargs)
go_transition_wrapper(go_test, go_transition_test, name = name, use_basename = False, keys_to_strip = go_test_attrs.keys(), **kwargs)
6 changes: 6 additions & 0 deletions go/private/skylib/lib/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ bzl_library(
srcs = ["versions.bzl"],
visibility = ["//go:__subpackages__"],
)

bzl_library(
name = "dicts",
srcs = ["dicts.bzl"],
visibility = ["//go:__subpackages__"],
)
16 changes: 16 additions & 0 deletions go/private/skylib/lib/dicts.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# This function isn't yet in a released skylib.

def _omit(dictionary, keys):
"""Returns a new `dict` that has all the entries of `dictionary` with keys not in `keys`.
Args:
dictionary: A `dict`.
keys: A sequence.
Returns:
A new `dict` that has all the entries of `dictionary` with keys not in `keys`.
"""
keys_set = {k: None for k in keys}
return {k: dictionary[k] for k in dictionary if k not in keys_set}

dicts = struct(
omit = _omit,
)