Skip to content

Commit

Permalink
Declare toolchains in a separate repository (#3348)
Browse files Browse the repository at this point in the history
For instance, if the SDK repository is `@go_sdk`, the toolchain rules will be defined in `@go_sdk_toolchains`. This avoids eagerly fetching `@go_sdk`, fixing #3196.

One caveat: `:sdk_version_setting` needs to be defined in the same repo as the toolchain rule, e.g. in `@go_sdk_toolchains`. I tried `target_settings = "@go_sdk//:sdk_version_setting"`, but that causes `@go_sdk` to be eagerly fetched again.

This means that `@go_sdk_toolchains` needs to know the SDK version. There are two possibilities:
* The user specifies the version up front, for instance via `go_register_toolchains(version = ...)`. In that case, `@go_sdk_toolchains` uses this version.
* The user does not specify the version up front. `go_wrap_sdk`, `go_download_sdk`, and `go_local_sdk` do not require a `version` attribute. In this case, we have no choice but to inspect the SDK itself to obtain the version, forcing an eager load. However, we can at least add an optional `version` attribute to these rules, so that users can avoid the eager fetch if they wish.

In all cases, when a `version` attribute is provided by the user, the implementation (lazily) validates that it matches the actual SDK version.
  • Loading branch information
jfirebaugh committed Nov 24, 2022
1 parent 8a94066 commit b3ebe1f
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 108 deletions.
4 changes: 2 additions & 2 deletions MODULE.bazel
Expand Up @@ -21,8 +21,8 @@ use_repo(

go_sdk = use_extension("//go:extensions.bzl", "go_sdk")
go_sdk.download(name = "go_default_sdk", version = "1.18.3")
use_repo(go_sdk, "go_default_sdk")
register_toolchains("@go_default_sdk//:all")
use_repo(go_sdk, "go_default_sdk_toolchains")
register_toolchains("@go_default_sdk_toolchains//:all")

bazel_dep(name = "gazelle", version = "0.27.0")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
Expand Down
18 changes: 16 additions & 2 deletions go/def.bzl
Expand Up @@ -41,7 +41,8 @@ load(
)
load(
"//go/private:go_toolchain.bzl",
_declare_toolchains = "declare_toolchains",
_declare_bazel_toolchains = "declare_bazel_toolchains",
_declare_go_toolchains = "declare_go_toolchains",
_go_toolchain = "go_toolchain",
)
load(
Expand Down Expand Up @@ -126,7 +127,20 @@ TOOLS_NOGO = [
# check this to determine compatibility.
RULES_GO_VERSION = "0.36.0"

declare_toolchains = _declare_toolchains
def declare_toolchains(host, sdk, builder, sdk_version_setting):
host_goos, _, host_goarch = host.partition("_")
_declare_go_toolchains(
host_goos = host_goos,
sdk = sdk,
builder = builder,
)
_declare_bazel_toolchains(
host_goos = host_goos,
host_goarch = host_goarch,
toolchain_prefix = "",
sdk_version_setting = sdk_version_setting,
)

go_context = _go_context
go_embed_data = _go_embed_data
gomock = _gomock
Expand Down
73 changes: 4 additions & 69 deletions go/private/BUILD.sdk.bazel
@@ -1,7 +1,7 @@
load("@{rules_go_repo_name}//go/private/rules:binary.bzl", "go_tool_binary")
load("@{rules_go_repo_name}//go/private/rules:sdk.bzl", "package_list")
load("@{rules_go_repo_name}//go:def.bzl", "declare_toolchains", "go_sdk")
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@{rules_go_repo_name}//go/private:go_toolchain.bzl", "declare_go_toolchains")
load("@{rules_go_repo_name}//go:def.bzl", "go_sdk")

package(default_visibility = ["//visibility:public"])

Expand Down Expand Up @@ -59,75 +59,10 @@ package_list(
root_file = "ROOT",
)

sdk_version_label = "@{rules_go_repo_name}//go/toolchain:sdk_version"

config_setting(
name = "match_all_versions",
flag_values = {
sdk_version_label: "",
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_major_version",
flag_values = {
sdk_version_label: "{major_version}",
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_major_minor_version",
flag_values = {
sdk_version_label: "{major_version}.{minor_version}",
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_patch_version",
flag_values = {
sdk_version_label: "{major_version}.{minor_version}.{patch_version}",
},
visibility = ["//visibility:private"],
)

# If prerelease version is "", this will be the same as ":match_patch_version", but that's fine since we use match_any in config_setting_group.
config_setting(
name = "match_prerelease_version",
flag_values = {
sdk_version_label: "{major_version}.{minor_version}.{patch_version}{prerelease_suffix}",
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_sdk_type",
flag_values = {
sdk_version_label: "{sdk_type}",
},
visibility = ["//visibility:private"],
)

selects.config_setting_group(
name = "sdk_version_setting",
match_any = [
":match_all_versions",
":match_major_version",
":match_major_minor_version",
":match_patch_version",
":match_prerelease_version",
":match_sdk_type",
],
visibility = ["//visibility:private"],
)

declare_toolchains(
declare_go_toolchains(
builder = ":builder",
host = "{goos}_{goarch}",
host_goos = "{goos}",
sdk = ":go_sdk",
sdk_version_setting = ":sdk_version_setting",
)

filegroup(
Expand Down
77 changes: 77 additions & 0 deletions go/private/BUILD.toolchains.bazel
@@ -0,0 +1,77 @@
load("@{rules_go_repo_name}//go/private:go_toolchain.bzl", "declare_bazel_toolchains")
load("@bazel_skylib//lib:selects.bzl", "selects")

{version_constants}

package(default_visibility = ["//visibility:public"])

sdk_version_label = "@{rules_go_repo_name}//go/toolchain:sdk_version"

config_setting(
name = "match_all_versions",
flag_values = {
sdk_version_label: "",
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_major_version",
flag_values = {
sdk_version_label: MAJOR_VERSION,
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_major_minor_version",
flag_values = {
sdk_version_label: MAJOR_VERSION + "." + MINOR_VERSION,
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_patch_version",
flag_values = {
sdk_version_label: MAJOR_VERSION + "." + MINOR_VERSION + "." + PATCH_VERSION,
},
visibility = ["//visibility:private"],
)

# If prerelease version is "", this will be the same as ":match_patch_version", but that's fine since we use match_any in config_setting_group.
config_setting(
name = "match_prerelease_version",
flag_values = {
sdk_version_label: MAJOR_VERSION + "." + MINOR_VERSION + "." + PATCH_VERSION + PRERELEASE_SUFFIX,
},
visibility = ["//visibility:private"],
)

config_setting(
name = "match_sdk_type",
flag_values = {
sdk_version_label: "{sdk_type}",
},
visibility = ["//visibility:private"],
)

selects.config_setting_group(
name = "sdk_version_setting",
match_any = [
":match_all_versions",
":match_major_version",
":match_major_minor_version",
":match_patch_version",
":match_prerelease_version",
":match_sdk_type",
],
visibility = ["//visibility:private"],
)

declare_bazel_toolchains(
host_goos = "{goos}",
host_goarch = "{goarch}",
toolchain_prefix = "@{sdk_repo}//",
sdk_version_setting = ":sdk_version_setting",
)
39 changes: 22 additions & 17 deletions go/private/go_toolchain.bzl
Expand Up @@ -92,11 +92,8 @@ go_toolchain = rule(
provides = [platform_common.ToolchainInfo],
)

def declare_toolchains(host, sdk, builder, sdk_version_setting):
"""Declares go_toolchain and toolchain targets for each platform."""

# keep in sync with generate_toolchain_names
host_goos, _, host_goarch = host.partition("_")
def declare_go_toolchains(host_goos, sdk, builder):
"""Declares go_toolchain targets for each platform."""
for p in PLATFORMS:
if p.cgo:
# Don't declare separate toolchains for cgo_on / cgo_off.
Expand All @@ -111,17 +108,8 @@ def declare_toolchains(host, sdk, builder, sdk_version_setting):
if host_goos == "linux":
cgo_link_flags.append("-Wl,-whole-archive")

toolchain_name = "go_" + p.name
impl_name = toolchain_name + "-impl"

cgo_constraints = (
"@io_bazel_rules_go//go/toolchain:cgo_off",
"@io_bazel_rules_go//go/toolchain:cgo_on",
)
constraints = [c for c in p.constraints if c not in cgo_constraints]

go_toolchain(
name = impl_name,
name = "go_" + p.name + "-impl",
goos = p.goos,
goarch = p.goarch,
sdk = sdk,
Expand All @@ -131,14 +119,31 @@ def declare_toolchains(host, sdk, builder, sdk_version_setting):
tags = ["manual"],
visibility = ["//visibility:public"],
)

def declare_bazel_toolchains(host_goos, host_goarch, toolchain_prefix, sdk_version_setting):
"""Declares toolchain targets for each platform."""
for p in PLATFORMS:
if p.cgo:
# Don't declare separate toolchains for cgo_on / cgo_off.
# This is controlled by the cgo_context_data dependency of
# go_context_data, which is configured using constraint_values.
continue

cgo_constraints = (
"@io_bazel_rules_go//go/toolchain:cgo_off",
"@io_bazel_rules_go//go/toolchain:cgo_on",
)
constraints = [c for c in p.constraints if c not in cgo_constraints]

native.toolchain(
name = toolchain_name,
# keep in sync with generate_toolchain_names
name = "go_" + p.name,
toolchain_type = GO_TOOLCHAIN,
exec_compatible_with = [
"@io_bazel_rules_go//go/toolchain:" + host_goos,
"@io_bazel_rules_go//go/toolchain:" + host_goarch,
],
target_compatible_with = constraints,
target_settings = [sdk_version_setting],
toolchain = ":" + impl_name,
toolchain = toolchain_prefix + ":go_" + p.name + "-impl",
)

0 comments on commit b3ebe1f

Please sign in to comment.