diff --git a/go/private/rules/library.bzl b/go/private/rules/library.bzl index 4afb629c6e..1a0a55733c 100644 --- a/go/private/rules/library.bzl +++ b/go/private/rules/library.bzl @@ -31,6 +31,10 @@ load( "GoLibrary", "INFERRED_PATH", ) +load( + "//go/private/rules:transition.bzl", + "non_go_transition", +) def _go_library_impl(ctx): """Implements the go_library() rule.""" @@ -59,6 +63,7 @@ go_library = rule( attrs = { "data": attr.label_list( allow_files = True, + cfg = non_go_transition, doc = """ List of files needed by this rule at run-time. This may include data files needed or other programs that may be executed. @@ -68,6 +73,7 @@ go_library = rule( ), "srcs": attr.label_list( allow_files = go_exts + asm_exts + cgo_exts, + cfg = non_go_transition, doc = """ The list of Go source files that are compiled to create the package. Only `.go` and `.s` files are permitted, unless the `cgo` attribute is set, @@ -110,6 +116,7 @@ go_library = rule( ), "embedsrcs": attr.label_list( allow_files = True, + cfg = non_go_transition, doc = """ The list of files that may be embedded into the compiled package using `//go:embed` directives. All files must be in the same logical directory or a subdirectory as source files. @@ -137,6 +144,7 @@ go_library = rule( """, ), "cdeps": attr.label_list( + cfg = non_go_transition, doc = """ List of other libraries that the c code depends on. This can be anything that would be allowed in [cc_library deps] Only valid if `cgo = True`. @@ -168,6 +176,9 @@ go_library = rule( """, ), "_go_context_data": attr.label(default = "//:go_context_data"), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), }, toolchains = [GO_TOOLCHAIN], doc = """This builds a Go library from a set of source files that are all part of diff --git a/go/private/rules/transition.bzl b/go/private/rules/transition.bzl index d08cb6f910..5d35163678 100644 --- a/go/private/rules/transition.bzl +++ b/go/private/rules/transition.bzl @@ -168,6 +168,46 @@ def _go_transition_impl(settings, attr): return settings +def _non_go_transition_impl(settings, attr): + """Sets all Go settings to the values they had before the last go_transition. + non_go_transition sets all of the //go/config settings to the value they had + before the last go_transition. This should be used on all attributes of + go_library/go_binary/go_test that are built in the target configuration and + do not constitute advertise any Go providers. + Examples: This transition is applied to the 'data' attribute of go_binary so + that other Go binaries used at runtime aren't affected by a non-standard + link mode set on the go_binary target, but still use the same top-level + settings such as e.g. race instrumentation. + """ + new_settings = {} + for key, original_key in _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.items(): + original_value = settings[original_key] + if original_value: + # Reset to the original value of the setting before go_transition. + new_settings[key] = json.decode(original_value) + else: + new_settings[key] = settings[key] + + # Reset the value of the helper setting to its default for two reasons: + # 1. Performance: This ensures that the Go settings of non-Go + # dependencies have the same values as before the go_transition, + # which can prevent unnecessary rebuilds caused by configuration + # changes. + # 2. Correctness in edge cases: If there is a path in the build graph + # from a go_binary's non-Go dependency to a go_library that does not + # pass through another go_binary (e.g., through a custom rule + # replacement for go_binary), this transition could be applied again + # and cause incorrect Go setting values. + new_settings[original_key] = "" + + return new_settings + +non_go_transition = transition( + implementation = _non_go_transition_impl, + inputs = TRANSITIONED_GO_SETTING_KEYS + _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.values(), + outputs = TRANSITIONED_GO_SETTING_KEYS + _SETTING_KEY_TO_ORIGINAL_SETTING_KEY.values(), +) + def _request_nogo_transition(settings, attr): """Indicates that we want the project configured nogo instead of a noop.