xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/rules/transition.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das# Copyright 2020 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das#
3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das# You may obtain a copy of the License at
6*9bb1b549SSpandan Das#
7*9bb1b549SSpandan Das#    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das#
9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das# limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Dasload(
16*9bb1b549SSpandan Das    "@bazel_skylib//lib:paths.bzl",
17*9bb1b549SSpandan Das    "paths",
18*9bb1b549SSpandan Das)
19*9bb1b549SSpandan Dasload(
20*9bb1b549SSpandan Das    "//go/private:mode.bzl",
21*9bb1b549SSpandan Das    "LINKMODES",
22*9bb1b549SSpandan Das    "LINKMODE_NORMAL",
23*9bb1b549SSpandan Das)
24*9bb1b549SSpandan Dasload(
25*9bb1b549SSpandan Das    "//go/private:platforms.bzl",
26*9bb1b549SSpandan Das    "CGO_GOOS_GOARCH",
27*9bb1b549SSpandan Das    "GOOS_GOARCH",
28*9bb1b549SSpandan Das)
29*9bb1b549SSpandan Dasload(
30*9bb1b549SSpandan Das    "//go/private:providers.bzl",
31*9bb1b549SSpandan Das    "GoArchive",
32*9bb1b549SSpandan Das    "GoLibrary",
33*9bb1b549SSpandan Das    "GoSource",
34*9bb1b549SSpandan Das)
35*9bb1b549SSpandan Das
36*9bb1b549SSpandan Das# A list of rules_go settings that are possibly set by go_transition.
37*9bb1b549SSpandan Das# Keep their package name in sync with the implementation of
38*9bb1b549SSpandan Das# _original_setting_key.
39*9bb1b549SSpandan DasTRANSITIONED_GO_SETTING_KEYS = [
40*9bb1b549SSpandan Das    "//go/config:static",
41*9bb1b549SSpandan Das    "//go/config:msan",
42*9bb1b549SSpandan Das    "//go/config:race",
43*9bb1b549SSpandan Das    "//go/config:pure",
44*9bb1b549SSpandan Das    "//go/config:linkmode",
45*9bb1b549SSpandan Das    "//go/config:tags",
46*9bb1b549SSpandan Das]
47*9bb1b549SSpandan Das
48*9bb1b549SSpandan Dasdef _deduped_and_sorted(strs):
49*9bb1b549SSpandan Das    return sorted({s: None for s in strs}.keys())
50*9bb1b549SSpandan Das
51*9bb1b549SSpandan Dasdef _original_setting_key(key):
52*9bb1b549SSpandan Das    if not "//go/config:" in key:
53*9bb1b549SSpandan Das        fail("_original_setting_key currently assumes that all Go settings live under //go/config, got: " + key)
54*9bb1b549SSpandan Das    name = key.split(":")[1]
55*9bb1b549SSpandan Das    return "//go/private/rules:original_" + name
56*9bb1b549SSpandan Das
57*9bb1b549SSpandan Das_SETTING_KEY_TO_ORIGINAL_SETTING_KEY = {
58*9bb1b549SSpandan Das    setting: _original_setting_key(setting)
59*9bb1b549SSpandan Das    for setting in TRANSITIONED_GO_SETTING_KEYS
60*9bb1b549SSpandan Das}
61*9bb1b549SSpandan Das
62*9bb1b549SSpandan Dasdef _go_transition_impl(settings, attr):
63*9bb1b549SSpandan Das    # NOTE: Keep the list of rules_go settings set by this transition in sync
64*9bb1b549SSpandan Das    # with POTENTIALLY_TRANSITIONED_SETTINGS.
65*9bb1b549SSpandan Das    #
66*9bb1b549SSpandan Das    # NOTE(bazelbuild/bazel#11409): Calling fail here for invalid combinations
67*9bb1b549SSpandan Das    # of flags reports an error but does not stop the build.
68*9bb1b549SSpandan Das    # In any case, get_mode should mainly be responsible for reporting
69*9bb1b549SSpandan Das    # invalid modes, since it also takes --features flags into account.
70*9bb1b549SSpandan Das
71*9bb1b549SSpandan Das    original_settings = settings
72*9bb1b549SSpandan Das    settings = dict(settings)
73*9bb1b549SSpandan Das
74*9bb1b549SSpandan Das    _set_ternary(settings, attr, "static")
75*9bb1b549SSpandan Das    race = _set_ternary(settings, attr, "race")
76*9bb1b549SSpandan Das    msan = _set_ternary(settings, attr, "msan")
77*9bb1b549SSpandan Das    pure = _set_ternary(settings, attr, "pure")
78*9bb1b549SSpandan Das    if race == "on":
79*9bb1b549SSpandan Das        if pure == "on":
80*9bb1b549SSpandan Das            fail('race = "on" cannot be set when pure = "on" is set. race requires cgo.')
81*9bb1b549SSpandan Das        pure = "off"
82*9bb1b549SSpandan Das        settings["//go/config:pure"] = False
83*9bb1b549SSpandan Das    if msan == "on":
84*9bb1b549SSpandan Das        if pure == "on":
85*9bb1b549SSpandan Das            fail('msan = "on" cannot be set when msan = "on" is set. msan requires cgo.')
86*9bb1b549SSpandan Das        pure = "off"
87*9bb1b549SSpandan Das        settings["//go/config:pure"] = False
88*9bb1b549SSpandan Das    if pure == "on":
89*9bb1b549SSpandan Das        race = "off"
90*9bb1b549SSpandan Das        settings["//go/config:race"] = False
91*9bb1b549SSpandan Das        msan = "off"
92*9bb1b549SSpandan Das        settings["//go/config:msan"] = False
93*9bb1b549SSpandan Das    cgo = pure == "off"
94*9bb1b549SSpandan Das
95*9bb1b549SSpandan Das    goos = getattr(attr, "goos", "auto")
96*9bb1b549SSpandan Das    goarch = getattr(attr, "goarch", "auto")
97*9bb1b549SSpandan Das    _check_ternary("pure", pure)
98*9bb1b549SSpandan Das    if goos != "auto" or goarch != "auto":
99*9bb1b549SSpandan Das        if goos == "auto":
100*9bb1b549SSpandan Das            fail("goos must be set if goarch is set")
101*9bb1b549SSpandan Das        if goarch == "auto":
102*9bb1b549SSpandan Das            fail("goarch must be set if goos is set")
103*9bb1b549SSpandan Das        if (goos, goarch) not in GOOS_GOARCH:
104*9bb1b549SSpandan Das            fail("invalid goos, goarch pair: {}, {}".format(goos, goarch))
105*9bb1b549SSpandan Das        if cgo and (goos, goarch) not in CGO_GOOS_GOARCH:
106*9bb1b549SSpandan Das            fail('pure is "off" but cgo is not supported on {} {}'.format(goos, goarch))
107*9bb1b549SSpandan Das        platform = "@io_bazel_rules_go//go/toolchain:{}_{}{}".format(goos, goarch, "_cgo" if cgo else "")
108*9bb1b549SSpandan Das        settings["//command_line_option:platforms"] = platform
109*9bb1b549SSpandan Das
110*9bb1b549SSpandan Das    tags = getattr(attr, "gotags", [])
111*9bb1b549SSpandan Das    if tags:
112*9bb1b549SSpandan Das        settings["//go/config:tags"] = _deduped_and_sorted(tags)
113*9bb1b549SSpandan Das
114*9bb1b549SSpandan Das    linkmode = getattr(attr, "linkmode", "auto")
115*9bb1b549SSpandan Das    if linkmode != "auto":
116*9bb1b549SSpandan Das        if linkmode not in LINKMODES:
117*9bb1b549SSpandan Das            fail("linkmode: invalid mode {}; want one of {}".format(linkmode, ", ".join(LINKMODES)))
118*9bb1b549SSpandan Das        settings["//go/config:linkmode"] = linkmode
119*9bb1b549SSpandan Das
120*9bb1b549SSpandan Das    for key, original_key in _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.items():
121*9bb1b549SSpandan Das        old_value = original_settings[key]
122*9bb1b549SSpandan Das        value = settings[key]
123*9bb1b549SSpandan Das
124*9bb1b549SSpandan Das        # If the outgoing configuration would differ from the incoming one in a
125*9bb1b549SSpandan Das        # value, record the old value in the special original_* key so that the
126*9bb1b549SSpandan Das        # real setting can be reset to this value before the new configuration
127*9bb1b549SSpandan Das        # would cross a non-deps dependency edge.
128*9bb1b549SSpandan Das        if value != old_value:
129*9bb1b549SSpandan Das            # Encoding as JSON makes it possible to embed settings of arbitrary
130*9bb1b549SSpandan Das            # types (currently bool, string and string_list) into a single type
131*9bb1b549SSpandan Das            # of setting (string) with the information preserved whether the
132*9bb1b549SSpandan Das            # original setting wasn't set explicitly (empty string) or was set
133*9bb1b549SSpandan Das            # explicitly to its default  (always a non-empty string with JSON
134*9bb1b549SSpandan Das            # encoding, e.g. "\"\"" or "[]").
135*9bb1b549SSpandan Das            settings[original_key] = json.encode(old_value)
136*9bb1b549SSpandan Das        else:
137*9bb1b549SSpandan Das            settings[original_key] = ""
138*9bb1b549SSpandan Das
139*9bb1b549SSpandan Das    return settings
140*9bb1b549SSpandan Das
141*9bb1b549SSpandan Dasdef _request_nogo_transition(settings, _attr):
142*9bb1b549SSpandan Das    """Indicates that we want the project configured nogo instead of a noop.
143*9bb1b549SSpandan Das
144*9bb1b549SSpandan Das    This does not guarantee that the project configured nogo will be used (if
145*9bb1b549SSpandan Das    bootstrap is true we are currently building nogo so that is a cyclic
146*9bb1b549SSpandan Das    dependency).
147*9bb1b549SSpandan Das
148*9bb1b549SSpandan Das    The config setting nogo_active requires bootstrap to be false and
149*9bb1b549SSpandan Das    request_nogo to be true to provide the project configured nogo.
150*9bb1b549SSpandan Das    """
151*9bb1b549SSpandan Das    settings = dict(settings)
152*9bb1b549SSpandan Das    settings["//go/private:request_nogo"] = True
153*9bb1b549SSpandan Das    return settings
154*9bb1b549SSpandan Das
155*9bb1b549SSpandan Dasrequest_nogo_transition = transition(
156*9bb1b549SSpandan Das    implementation = _request_nogo_transition,
157*9bb1b549SSpandan Das    inputs = [],
158*9bb1b549SSpandan Das    outputs = ["//go/private:request_nogo"],
159*9bb1b549SSpandan Das)
160*9bb1b549SSpandan Das
161*9bb1b549SSpandan Dasgo_transition = transition(
162*9bb1b549SSpandan Das    implementation = _go_transition_impl,
163*9bb1b549SSpandan Das    inputs = [
164*9bb1b549SSpandan Das        "//command_line_option:platforms",
165*9bb1b549SSpandan Das    ] + TRANSITIONED_GO_SETTING_KEYS,
166*9bb1b549SSpandan Das    outputs = [
167*9bb1b549SSpandan Das        "//command_line_option:platforms",
168*9bb1b549SSpandan Das    ] + TRANSITIONED_GO_SETTING_KEYS + _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.values(),
169*9bb1b549SSpandan Das)
170*9bb1b549SSpandan Das
171*9bb1b549SSpandan Das_common_reset_transition_dict = dict({
172*9bb1b549SSpandan Das    "//go/private:request_nogo": False,
173*9bb1b549SSpandan Das    "//go/config:static": False,
174*9bb1b549SSpandan Das    "//go/config:msan": False,
175*9bb1b549SSpandan Das    "//go/config:race": False,
176*9bb1b549SSpandan Das    "//go/config:pure": False,
177*9bb1b549SSpandan Das    "//go/config:debug": False,
178*9bb1b549SSpandan Das    "//go/config:linkmode": LINKMODE_NORMAL,
179*9bb1b549SSpandan Das    "//go/config:tags": [],
180*9bb1b549SSpandan Das}, **{setting: "" for setting in _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.values()})
181*9bb1b549SSpandan Das
182*9bb1b549SSpandan Das_reset_transition_dict = dict(_common_reset_transition_dict, **{
183*9bb1b549SSpandan Das    "//go/private:bootstrap_nogo": True,
184*9bb1b549SSpandan Das})
185*9bb1b549SSpandan Das
186*9bb1b549SSpandan Das_reset_transition_keys = sorted(_reset_transition_dict.keys())
187*9bb1b549SSpandan Das
188*9bb1b549SSpandan Das_stdlib_keep_keys = sorted([
189*9bb1b549SSpandan Das    "//go/config:msan",
190*9bb1b549SSpandan Das    "//go/config:race",
191*9bb1b549SSpandan Das    "//go/config:pure",
192*9bb1b549SSpandan Das    "//go/config:linkmode",
193*9bb1b549SSpandan Das    "//go/config:tags",
194*9bb1b549SSpandan Das])
195*9bb1b549SSpandan Das
196*9bb1b549SSpandan Dasdef _go_tool_transition_impl(settings, _attr):
197*9bb1b549SSpandan Das    """Sets most Go settings to default values (use for external Go tools).
198*9bb1b549SSpandan Das
199*9bb1b549SSpandan Das    go_tool_transition sets all of the //go/config settings to their default
200*9bb1b549SSpandan Das    values and disables nogo. This is used for Go tool binaries like nogo
201*9bb1b549SSpandan Das    itself. Tool binaries shouldn't depend on the link mode or tags of the
202*9bb1b549SSpandan Das    target configuration and neither the tools nor the code they potentially
203*9bb1b549SSpandan Das    generate should be subject to nogo's static analysis. This transition
204*9bb1b549SSpandan Das    doesn't change the platform (goos, goarch), but tool binaries should also
205*9bb1b549SSpandan Das    have `cfg = "exec"` so tool binaries should be built for the execution
206*9bb1b549SSpandan Das    platform.
207*9bb1b549SSpandan Das    """
208*9bb1b549SSpandan Das    return dict(settings, **_reset_transition_dict)
209*9bb1b549SSpandan Das
210*9bb1b549SSpandan Dasgo_tool_transition = transition(
211*9bb1b549SSpandan Das    implementation = _go_tool_transition_impl,
212*9bb1b549SSpandan Das    inputs = _reset_transition_keys,
213*9bb1b549SSpandan Das    outputs = _reset_transition_keys,
214*9bb1b549SSpandan Das)
215*9bb1b549SSpandan Das
216*9bb1b549SSpandan Dasdef _non_go_tool_transition_impl(settings, _attr):
217*9bb1b549SSpandan Das    """Sets all Go settings to default values (use for external non-Go tools).
218*9bb1b549SSpandan Das
219*9bb1b549SSpandan Das    non_go_tool_transition sets all of the //go/config settings as well as the
220*9bb1b549SSpandan Das    nogo settings to their default values. This is used for all tools that are
221*9bb1b549SSpandan Das    not themselves targets created from rules_go rules and thus do not read
222*9bb1b549SSpandan Das    these settings. Resetting all of them to defaults prevents unnecessary
223*9bb1b549SSpandan Das    configuration changes for these targets that could cause rebuilds.
224*9bb1b549SSpandan Das
225*9bb1b549SSpandan Das    Examples: This transition is applied to attributes referencing proto_library
226*9bb1b549SSpandan Das    targets or protoc directly.
227*9bb1b549SSpandan Das    """
228*9bb1b549SSpandan Das    settings = dict(settings, **_reset_transition_dict)
229*9bb1b549SSpandan Das    settings["//go/private:bootstrap_nogo"] = False
230*9bb1b549SSpandan Das    return settings
231*9bb1b549SSpandan Das
232*9bb1b549SSpandan Dasnon_go_tool_transition = transition(
233*9bb1b549SSpandan Das    implementation = _non_go_tool_transition_impl,
234*9bb1b549SSpandan Das    inputs = _reset_transition_keys,
235*9bb1b549SSpandan Das    outputs = _reset_transition_keys,
236*9bb1b549SSpandan Das)
237*9bb1b549SSpandan Das
238*9bb1b549SSpandan Dasdef _go_stdlib_transition_impl(settings, _attr):
239*9bb1b549SSpandan Das    """Sets all Go settings to their default values, except for those affecting the Go SDK.
240*9bb1b549SSpandan Das
241*9bb1b549SSpandan Das    This transition is similar to _non_go_tool_transition except that it keeps the
242*9bb1b549SSpandan Das    parts of the configuration that determine how to build the standard library.
243*9bb1b549SSpandan Das    It's used to consolidate the configurations used to build the standard library to limit
244*9bb1b549SSpandan Das    the number built.
245*9bb1b549SSpandan Das    """
246*9bb1b549SSpandan Das    settings = dict(settings)
247*9bb1b549SSpandan Das    for label, value in _reset_transition_dict.items():
248*9bb1b549SSpandan Das        if label not in _stdlib_keep_keys:
249*9bb1b549SSpandan Das            settings[label] = value
250*9bb1b549SSpandan Das    settings["//go/config:tags"] = [t for t in settings["//go/config:tags"] if t in _TAG_AFFECTS_STDLIB]
251*9bb1b549SSpandan Das    settings["//go/private:bootstrap_nogo"] = False
252*9bb1b549SSpandan Das    return settings
253*9bb1b549SSpandan Das
254*9bb1b549SSpandan Dasgo_stdlib_transition = transition(
255*9bb1b549SSpandan Das    implementation = _go_stdlib_transition_impl,
256*9bb1b549SSpandan Das    inputs = _reset_transition_keys,
257*9bb1b549SSpandan Das    outputs = _reset_transition_keys,
258*9bb1b549SSpandan Das)
259*9bb1b549SSpandan Das
260*9bb1b549SSpandan Dasdef _go_reset_target_impl(ctx):
261*9bb1b549SSpandan Das    t = ctx.attr.dep[0]  # [0] seems to be necessary with the transition
262*9bb1b549SSpandan Das    providers = [t[p] for p in [GoLibrary, GoSource, GoArchive] if p in t]
263*9bb1b549SSpandan Das
264*9bb1b549SSpandan Das    # We can't pass DefaultInfo through as-is, since Bazel forbids executable
265*9bb1b549SSpandan Das    # if it's a file declared in a different target. To emulate that, symlink
266*9bb1b549SSpandan Das    # to the original executable, if there is one.
267*9bb1b549SSpandan Das    default_info = t[DefaultInfo]
268*9bb1b549SSpandan Das
269*9bb1b549SSpandan Das    new_executable = None
270*9bb1b549SSpandan Das    original_executable = default_info.files_to_run.executable
271*9bb1b549SSpandan Das    default_runfiles = default_info.default_runfiles
272*9bb1b549SSpandan Das    if original_executable:
273*9bb1b549SSpandan Das        # In order for the symlink to have the same basename as the original
274*9bb1b549SSpandan Das        # executable (important in the case of proto plugins), put it in a
275*9bb1b549SSpandan Das        # subdirectory named after the label to prevent collisions.
276*9bb1b549SSpandan Das        new_executable = ctx.actions.declare_file(paths.join(ctx.label.name, original_executable.basename))
277*9bb1b549SSpandan Das        ctx.actions.symlink(
278*9bb1b549SSpandan Das            output = new_executable,
279*9bb1b549SSpandan Das            target_file = original_executable,
280*9bb1b549SSpandan Das            is_executable = True,
281*9bb1b549SSpandan Das        )
282*9bb1b549SSpandan Das        default_runfiles = default_runfiles.merge(ctx.runfiles([new_executable]))
283*9bb1b549SSpandan Das
284*9bb1b549SSpandan Das    providers.append(
285*9bb1b549SSpandan Das        DefaultInfo(
286*9bb1b549SSpandan Das            files = default_info.files,
287*9bb1b549SSpandan Das            data_runfiles = default_info.data_runfiles,
288*9bb1b549SSpandan Das            default_runfiles = default_runfiles,
289*9bb1b549SSpandan Das            executable = new_executable,
290*9bb1b549SSpandan Das        ),
291*9bb1b549SSpandan Das    )
292*9bb1b549SSpandan Das    return providers
293*9bb1b549SSpandan Das
294*9bb1b549SSpandan Dasgo_reset_target = rule(
295*9bb1b549SSpandan Das    implementation = _go_reset_target_impl,
296*9bb1b549SSpandan Das    attrs = {
297*9bb1b549SSpandan Das        "dep": attr.label(
298*9bb1b549SSpandan Das            mandatory = True,
299*9bb1b549SSpandan Das            cfg = go_tool_transition,
300*9bb1b549SSpandan Das        ),
301*9bb1b549SSpandan Das        "_allowlist_function_transition": attr.label(
302*9bb1b549SSpandan Das            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
303*9bb1b549SSpandan Das        ),
304*9bb1b549SSpandan Das    },
305*9bb1b549SSpandan Das    doc = """Forwards providers from a target and applies go_tool_transition.
306*9bb1b549SSpandan Das
307*9bb1b549SSpandan Dasgo_reset_target depends on a single target, built using go_tool_transition. It
308*9bb1b549SSpandan Dasforwards Go providers and DefaultInfo.
309*9bb1b549SSpandan Das
310*9bb1b549SSpandan DasThis is used to work around a problem with building tools: Go tools should be
311*9bb1b549SSpandan Dasbuilt with 'cfg = "exec"' so they work on the execution platform, but we also
312*9bb1b549SSpandan Dasneed to apply go_tool_transition so that e.g. a tool isn't built as a shared
313*9bb1b549SSpandan Daslibrary with race instrumentation. This acts as an intermediate rule that allows
314*9bb1b549SSpandan Dasto apply both both transitions.
315*9bb1b549SSpandan Das""",
316*9bb1b549SSpandan Das)
317*9bb1b549SSpandan Das
318*9bb1b549SSpandan Dasnon_go_reset_target = rule(
319*9bb1b549SSpandan Das    implementation = _go_reset_target_impl,
320*9bb1b549SSpandan Das    attrs = {
321*9bb1b549SSpandan Das        "dep": attr.label(
322*9bb1b549SSpandan Das            mandatory = True,
323*9bb1b549SSpandan Das            cfg = non_go_tool_transition,
324*9bb1b549SSpandan Das        ),
325*9bb1b549SSpandan Das        "_allowlist_function_transition": attr.label(
326*9bb1b549SSpandan Das            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
327*9bb1b549SSpandan Das        ),
328*9bb1b549SSpandan Das    },
329*9bb1b549SSpandan Das    doc = """Forwards providers from a target and applies non_go_tool_transition.
330*9bb1b549SSpandan Das
331*9bb1b549SSpandan Dasnon_go_reset_target depends on a single target, built using
332*9bb1b549SSpandan Dasnon_go_tool_transition. It forwards Go providers and DefaultInfo.
333*9bb1b549SSpandan Das
334*9bb1b549SSpandan DasThis is used to work around a problem with building tools: Non-Go tools should
335*9bb1b549SSpandan Dasbe built with 'cfg = "exec"' so they work on the execution platform, but they
336*9bb1b549SSpandan Dasalso shouldn't be affected by Go-specific config changes applied by
337*9bb1b549SSpandan Dasgo_transition.
338*9bb1b549SSpandan Das""",
339*9bb1b549SSpandan Das)
340*9bb1b549SSpandan Das
341*9bb1b549SSpandan Dasdef _non_go_transition_impl(settings, _attr):
342*9bb1b549SSpandan Das    """Sets all Go settings to the values they had before the last go_transition.
343*9bb1b549SSpandan Das
344*9bb1b549SSpandan Das    non_go_transition sets all of the //go/config settings to the value they had
345*9bb1b549SSpandan Das    before the last go_transition. This should be used on all attributes of
346*9bb1b549SSpandan Das    go_library/go_binary/go_test that are built in the target configuration and
347*9bb1b549SSpandan Das    do not constitute advertise any Go providers.
348*9bb1b549SSpandan Das
349*9bb1b549SSpandan Das    Examples: This transition is applied to the 'data' attribute of go_binary so
350*9bb1b549SSpandan Das    that other Go binaries used at runtime aren't affected by a non-standard
351*9bb1b549SSpandan Das    link mode set on the go_binary target, but still use the same top-level
352*9bb1b549SSpandan Das    settings such as e.g. race instrumentation.
353*9bb1b549SSpandan Das    """
354*9bb1b549SSpandan Das    new_settings = {}
355*9bb1b549SSpandan Das    for key, original_key in _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.items():
356*9bb1b549SSpandan Das        original_value = settings[original_key]
357*9bb1b549SSpandan Das        if original_value:
358*9bb1b549SSpandan Das            # Reset to the original value of the setting before go_transition.
359*9bb1b549SSpandan Das            new_settings[key] = json.decode(original_value)
360*9bb1b549SSpandan Das        else:
361*9bb1b549SSpandan Das            new_settings[key] = settings[key]
362*9bb1b549SSpandan Das
363*9bb1b549SSpandan Das        # Reset the value of the helper setting to its default for two reasons:
364*9bb1b549SSpandan Das        # 1. Performance: This ensures that the Go settings of non-Go
365*9bb1b549SSpandan Das        #    dependencies have the same values as before the go_transition,
366*9bb1b549SSpandan Das        #    which can prevent unnecessary rebuilds caused by configuration
367*9bb1b549SSpandan Das        #    changes.
368*9bb1b549SSpandan Das        # 2. Correctness in edge cases: If there is a path in the build graph
369*9bb1b549SSpandan Das        #    from a go_binary's non-Go dependency to a go_library that does not
370*9bb1b549SSpandan Das        #    pass through another go_binary (e.g., through a custom rule
371*9bb1b549SSpandan Das        #    replacement for go_binary), this transition could be applied again
372*9bb1b549SSpandan Das        #    and cause incorrect Go setting values.
373*9bb1b549SSpandan Das        new_settings[original_key] = ""
374*9bb1b549SSpandan Das
375*9bb1b549SSpandan Das    return new_settings
376*9bb1b549SSpandan Das
377*9bb1b549SSpandan Dasnon_go_transition = transition(
378*9bb1b549SSpandan Das    implementation = _non_go_transition_impl,
379*9bb1b549SSpandan Das    inputs = TRANSITIONED_GO_SETTING_KEYS + _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.values(),
380*9bb1b549SSpandan Das    outputs = TRANSITIONED_GO_SETTING_KEYS + _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.values(),
381*9bb1b549SSpandan Das)
382*9bb1b549SSpandan Das
383*9bb1b549SSpandan Dasdef _check_ternary(name, value):
384*9bb1b549SSpandan Das    if value not in ("on", "off", "auto"):
385*9bb1b549SSpandan Das        fail('{}: must be "on", "off", or "auto"'.format(name))
386*9bb1b549SSpandan Das
387*9bb1b549SSpandan Dasdef _set_ternary(settings, attr, name):
388*9bb1b549SSpandan Das    value = getattr(attr, name, "auto")
389*9bb1b549SSpandan Das    _check_ternary(name, value)
390*9bb1b549SSpandan Das    if value != "auto":
391*9bb1b549SSpandan Das        label = "//go/config:{}".format(name)
392*9bb1b549SSpandan Das        settings[label] = value == "on"
393*9bb1b549SSpandan Das    return value
394*9bb1b549SSpandan Das
395*9bb1b549SSpandan Das_SDK_VERSION_BUILD_SETTING = "//go/toolchain:sdk_version"
396*9bb1b549SSpandan DasTRANSITIONED_GO_CROSS_SETTING_KEYS = [
397*9bb1b549SSpandan Das    _SDK_VERSION_BUILD_SETTING,
398*9bb1b549SSpandan Das    "//command_line_option:platforms",
399*9bb1b549SSpandan Das]
400*9bb1b549SSpandan Das
401*9bb1b549SSpandan Dasdef _go_cross_transition_impl(settings, attr):
402*9bb1b549SSpandan Das    settings = dict(settings)
403*9bb1b549SSpandan Das    if attr.sdk_version != None:
404*9bb1b549SSpandan Das        settings[_SDK_VERSION_BUILD_SETTING] = attr.sdk_version
405*9bb1b549SSpandan Das
406*9bb1b549SSpandan Das    if attr.platform != None:
407*9bb1b549SSpandan Das        settings["//command_line_option:platforms"] = str(attr.platform)
408*9bb1b549SSpandan Das
409*9bb1b549SSpandan Das    return settings
410*9bb1b549SSpandan Das
411*9bb1b549SSpandan Dasgo_cross_transition = transition(
412*9bb1b549SSpandan Das    implementation = _go_cross_transition_impl,
413*9bb1b549SSpandan Das    inputs = TRANSITIONED_GO_CROSS_SETTING_KEYS,
414*9bb1b549SSpandan Das    outputs = TRANSITIONED_GO_CROSS_SETTING_KEYS,
415*9bb1b549SSpandan Das)
416*9bb1b549SSpandan Das
417*9bb1b549SSpandan Das# A list of Go build tags that potentially affect the build of the standard
418*9bb1b549SSpandan Das# library.
419*9bb1b549SSpandan Das#
420*9bb1b549SSpandan Das# This should be updated to contain the union of all tags relevant for all
421*9bb1b549SSpandan Das# versions of Go that are still relevant.
422*9bb1b549SSpandan Das#
423*9bb1b549SSpandan Das# Currently supported versions: 1.18, 1.19, 1.20
424*9bb1b549SSpandan Das#
425*9bb1b549SSpandan Das# To regenerate, run and paste the output of
426*9bb1b549SSpandan Das#     bazel run //go/tools/internal/stdlib_tags:stdlib_tags -- path/to/go_sdk_1/src ...
427*9bb1b549SSpandan Das_TAG_AFFECTS_STDLIB = {
428*9bb1b549SSpandan Das    "alpha": None,
429*9bb1b549SSpandan Das    "appengine": None,
430*9bb1b549SSpandan Das    "asan": None,
431*9bb1b549SSpandan Das    "boringcrypto": None,
432*9bb1b549SSpandan Das    "cmd_go_bootstrap": None,
433*9bb1b549SSpandan Das    "compiler_bootstrap": None,
434*9bb1b549SSpandan Das    "debuglog": None,
435*9bb1b549SSpandan Das    "faketime": None,
436*9bb1b549SSpandan Das    "gc": None,
437*9bb1b549SSpandan Das    "gccgo": None,
438*9bb1b549SSpandan Das    "gen": None,
439*9bb1b549SSpandan Das    "generate": None,
440*9bb1b549SSpandan Das    "gofuzz": None,
441*9bb1b549SSpandan Das    "ignore": None,
442*9bb1b549SSpandan Das    "libfuzzer": None,
443*9bb1b549SSpandan Das    "m68k": None,
444*9bb1b549SSpandan Das    "math_big_pure_go": None,
445*9bb1b549SSpandan Das    "msan": None,
446*9bb1b549SSpandan Das    "netcgo": None,
447*9bb1b549SSpandan Das    "netgo": None,
448*9bb1b549SSpandan Das    "nethttpomithttp2": None,
449*9bb1b549SSpandan Das    "nios2": None,
450*9bb1b549SSpandan Das    "noopt": None,
451*9bb1b549SSpandan Das    "osusergo": None,
452*9bb1b549SSpandan Das    "purego": None,
453*9bb1b549SSpandan Das    "race": None,
454*9bb1b549SSpandan Das    "sh": None,
455*9bb1b549SSpandan Das    "shbe": None,
456*9bb1b549SSpandan Das    "tablegen": None,
457*9bb1b549SSpandan Das    "testgo": None,
458*9bb1b549SSpandan Das    "timetzdata": None,
459*9bb1b549SSpandan Das}
460