1# Copyright 2014 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15load( 16 "//go/private:common.bzl", 17 "executable_path", 18) 19load( 20 "//go/private:nogo.bzl", 21 "go_register_nogo", 22) 23load( 24 "//go/private/skylib/lib:versions.bzl", 25 "versions", 26) 27 28MIN_SUPPORTED_VERSION = (1, 14, 0) 29 30def _go_host_sdk_impl(ctx): 31 goroot = _detect_host_sdk(ctx) 32 platform = _detect_sdk_platform(ctx, goroot) 33 version = _detect_sdk_version(ctx, goroot) 34 _sdk_build_file(ctx, platform, version, experiments = ctx.attr.experiments) 35 _local_sdk(ctx, goroot) 36 37go_host_sdk_rule = repository_rule( 38 implementation = _go_host_sdk_impl, 39 environ = ["GOROOT"], 40 attrs = { 41 "version": attr.string(), 42 "experiments": attr.string_list( 43 doc = "Go experiments to enable via GOEXPERIMENT", 44 ), 45 "_sdk_build_file": attr.label( 46 default = Label("//go/private:BUILD.sdk.bazel"), 47 ), 48 }, 49) 50 51def go_host_sdk(name, register_toolchains = True, **kwargs): 52 go_host_sdk_rule(name = name, **kwargs) 53 _go_toolchains( 54 name = name + "_toolchains", 55 sdk_repo = name, 56 sdk_type = "host", 57 sdk_version = kwargs.get("version"), 58 goos = kwargs.get("goos"), 59 goarch = kwargs.get("goarch"), 60 ) 61 if register_toolchains: 62 _register_toolchains(name) 63 64def _go_download_sdk_impl(ctx): 65 if not ctx.attr.goos and not ctx.attr.goarch: 66 goos, goarch = detect_host_platform(ctx) 67 else: 68 if not ctx.attr.goos: 69 fail("goarch set but goos not set") 70 if not ctx.attr.goarch: 71 fail("goos set but goarch not set") 72 goos, goarch = ctx.attr.goos, ctx.attr.goarch 73 platform = goos + "_" + goarch 74 75 version = ctx.attr.version 76 sdks = ctx.attr.sdks 77 78 if not sdks: 79 # If sdks was unspecified, download a full list of files. 80 # If version was unspecified, pick the latest version. 81 # Even if version was specified, we need to download the file list 82 # to find the SHA-256 sum. If we don't have it, Bazel won't cache 83 # the downloaded archive. 84 if not version: 85 ctx.report_progress("Finding latest Go version") 86 else: 87 ctx.report_progress("Finding Go SHA-256 sums") 88 ctx.download( 89 url = [ 90 "https://go.dev/dl/?mode=json&include=all", 91 "https://golang.google.cn/dl/?mode=json&include=all", 92 ], 93 output = "versions.json", 94 ) 95 96 data = ctx.read("versions.json") 97 sdks_by_version = _parse_versions_json(data) 98 99 if not version: 100 highest_version = None 101 for v in sdks_by_version.keys(): 102 pv = parse_version(v) 103 if not pv or _version_is_prerelease(pv): 104 # skip parse errors and pre-release versions 105 continue 106 if not highest_version or _version_less(highest_version, pv): 107 highest_version = pv 108 if not highest_version: 109 fail("did not find any Go versions in https://go.dev/dl/?mode=json") 110 version = _version_string(highest_version) 111 if version not in sdks_by_version: 112 fail("did not find version {} in https://go.dev/dl/?mode=json".format(version)) 113 sdks = sdks_by_version[version] 114 115 if platform not in sdks: 116 fail("unsupported platform {}".format(platform)) 117 filename, sha256 = sdks[platform] 118 _remote_sdk(ctx, [url.format(filename) for url in ctx.attr.urls], ctx.attr.strip_prefix, sha256) 119 120 detected_version = _detect_sdk_version(ctx, ".") 121 _sdk_build_file(ctx, platform, detected_version, experiments = ctx.attr.experiments) 122 123 if not ctx.attr.sdks and not ctx.attr.version: 124 # Returning this makes Bazel print a message that 'version' must be 125 # specified for a reproducible build. 126 return { 127 "name": ctx.attr.name, 128 "goos": ctx.attr.goos, 129 "goarch": ctx.attr.goarch, 130 "sdks": ctx.attr.sdks, 131 "urls": ctx.attr.urls, 132 "version": version, 133 "strip_prefix": ctx.attr.strip_prefix, 134 } 135 return None 136 137go_download_sdk_rule = repository_rule( 138 implementation = _go_download_sdk_impl, 139 attrs = { 140 "goos": attr.string(), 141 "goarch": attr.string(), 142 "sdks": attr.string_list_dict(), 143 "experiments": attr.string_list( 144 doc = "Go experiments to enable via GOEXPERIMENT", 145 ), 146 "urls": attr.string_list(default = ["https://dl.google.com/go/{}"]), 147 "version": attr.string(), 148 "strip_prefix": attr.string(default = "go"), 149 "_sdk_build_file": attr.label( 150 default = Label("//go/private:BUILD.sdk.bazel"), 151 ), 152 }, 153) 154 155def _define_version_constants(version, prefix = ""): 156 pv = parse_version(version) 157 if pv == None or len(pv) < 3: 158 fail("error parsing sdk version: " + version) 159 major, minor, patch = pv[0], pv[1], pv[2] 160 prerelease = pv[3] if len(pv) > 3 else "" 161 return """ 162{prefix}MAJOR_VERSION = "{major}" 163{prefix}MINOR_VERSION = "{minor}" 164{prefix}PATCH_VERSION = "{patch}" 165{prefix}PRERELEASE_SUFFIX = "{prerelease}" 166""".format( 167 prefix = prefix, 168 major = major, 169 minor = minor, 170 patch = patch, 171 prerelease = prerelease, 172 ) 173 174def _to_constant_name(s): 175 # Prefix with _ as identifiers are not allowed to start with numbers. 176 return "_" + "".join([c if c.isalnum() else "_" for c in s.elems()]).upper() 177 178def go_toolchains_single_definition(ctx, *, prefix, goos, goarch, sdk_repo, sdk_type, sdk_version): 179 if not goos and not goarch: 180 goos, goarch = detect_host_platform(ctx) 181 else: 182 if not goos: 183 fail("goarch set but goos not set") 184 if not goarch: 185 fail("goos set but goarch not set") 186 187 chunks = [] 188 loads = [] 189 identifier_prefix = _to_constant_name(prefix) 190 191 # If a sdk_version attribute is provided, use that version. This avoids 192 # eagerly fetching the SDK repository. But if it's not provided, we have 193 # no choice and must load version constants from the version.bzl file that 194 # _sdk_build_file creates. This will trigger an eager fetch. 195 if sdk_version: 196 chunks.append(_define_version_constants(sdk_version, prefix = identifier_prefix)) 197 else: 198 loads.append("""load( 199 "@{sdk_repo}//:version.bzl", 200 {identifier_prefix}MAJOR_VERSION = "MAJOR_VERSION", 201 {identifier_prefix}MINOR_VERSION = "MINOR_VERSION", 202 {identifier_prefix}PATCH_VERSION = "PATCH_VERSION", 203 {identifier_prefix}PRERELEASE_SUFFIX = "PRERELEASE_SUFFIX", 204) 205""".format( 206 sdk_repo = sdk_repo, 207 identifier_prefix = identifier_prefix, 208 )) 209 210 chunks.append("""declare_bazel_toolchains( 211 prefix = "{prefix}", 212 go_toolchain_repo = "@{sdk_repo}", 213 host_goarch = "{goarch}", 214 host_goos = "{goos}", 215 major = {identifier_prefix}MAJOR_VERSION, 216 minor = {identifier_prefix}MINOR_VERSION, 217 patch = {identifier_prefix}PATCH_VERSION, 218 prerelease = {identifier_prefix}PRERELEASE_SUFFIX, 219 sdk_type = "{sdk_type}", 220) 221""".format( 222 prefix = prefix, 223 identifier_prefix = identifier_prefix, 224 sdk_repo = sdk_repo, 225 goarch = goarch, 226 goos = goos, 227 sdk_type = sdk_type, 228 )) 229 230 return struct( 231 loads = loads, 232 chunks = chunks, 233 ) 234 235def go_toolchains_build_file_content( 236 ctx, 237 prefixes, 238 geese, 239 goarchs, 240 sdk_repos, 241 sdk_types, 242 sdk_versions): 243 if not _have_same_length(prefixes, geese, goarchs, sdk_repos, sdk_types, sdk_versions): 244 fail("all lists must have the same length") 245 246 loads = [ 247 """load("@io_bazel_rules_go//go/private:go_toolchain.bzl", "declare_bazel_toolchains")""", 248 ] 249 chunks = [ 250 """package(default_visibility = ["//visibility:public"])""", 251 ] 252 253 for i in range(len(geese)): 254 definition = go_toolchains_single_definition( 255 ctx, 256 prefix = prefixes[i], 257 goos = geese[i], 258 goarch = goarchs[i], 259 sdk_repo = sdk_repos[i], 260 sdk_type = sdk_types[i], 261 sdk_version = sdk_versions[i], 262 ) 263 loads.extend(definition.loads) 264 chunks.extend(definition.chunks) 265 266 return "\n".join(loads + chunks) 267 268def _go_multiple_toolchains_impl(ctx): 269 ctx.file( 270 "BUILD.bazel", 271 go_toolchains_build_file_content( 272 ctx, 273 prefixes = ctx.attr.prefixes, 274 geese = ctx.attr.geese, 275 goarchs = ctx.attr.goarchs, 276 sdk_repos = ctx.attr.sdk_repos, 277 sdk_types = ctx.attr.sdk_types, 278 sdk_versions = ctx.attr.sdk_versions, 279 ), 280 executable = False, 281 ) 282 283go_multiple_toolchains = repository_rule( 284 implementation = _go_multiple_toolchains_impl, 285 attrs = { 286 "prefixes": attr.string_list(mandatory = True), 287 "sdk_repos": attr.string_list(mandatory = True), 288 "sdk_types": attr.string_list(mandatory = True), 289 "sdk_versions": attr.string_list(mandatory = True), 290 "geese": attr.string_list(mandatory = True), 291 "goarchs": attr.string_list(mandatory = True), 292 }, 293) 294 295def _go_toolchains(name, sdk_repo, sdk_type, sdk_version = None, goos = None, goarch = None): 296 go_multiple_toolchains( 297 name = name, 298 prefixes = [""], 299 geese = [goos or ""], 300 goarchs = [goarch or ""], 301 sdk_repos = [sdk_repo], 302 sdk_types = [sdk_type], 303 sdk_versions = [sdk_version or ""], 304 ) 305 306def go_download_sdk(name, register_toolchains = True, **kwargs): 307 go_download_sdk_rule(name = name, **kwargs) 308 _go_toolchains( 309 name = name + "_toolchains", 310 sdk_repo = name, 311 sdk_type = "remote", 312 sdk_version = kwargs.get("version"), 313 goos = kwargs.get("goos"), 314 goarch = kwargs.get("goarch"), 315 ) 316 if register_toolchains: 317 _register_toolchains(name) 318 319def _go_local_sdk_impl(ctx): 320 goroot = ctx.attr.path 321 platform = _detect_sdk_platform(ctx, goroot) 322 version = _detect_sdk_version(ctx, goroot) 323 _sdk_build_file(ctx, platform, version, ctx.attr.experiments) 324 _local_sdk(ctx, goroot) 325 326_go_local_sdk = repository_rule( 327 implementation = _go_local_sdk_impl, 328 attrs = { 329 "path": attr.string(), 330 "version": attr.string(), 331 "experiments": attr.string_list( 332 doc = "Go experiments to enable via GOEXPERIMENT", 333 ), 334 "_sdk_build_file": attr.label( 335 default = Label("//go/private:BUILD.sdk.bazel"), 336 ), 337 }, 338) 339 340def go_local_sdk(name, register_toolchains = True, **kwargs): 341 _go_local_sdk(name = name, **kwargs) 342 _go_toolchains( 343 name = name + "_toolchains", 344 sdk_repo = name, 345 sdk_type = "remote", 346 sdk_version = kwargs.get("version"), 347 goos = kwargs.get("goos"), 348 goarch = kwargs.get("goarch"), 349 ) 350 if register_toolchains: 351 _register_toolchains(name) 352 353def _go_wrap_sdk_impl(ctx): 354 if not ctx.attr.root_file and not ctx.attr.root_files: 355 fail("either root_file or root_files must be provided") 356 if ctx.attr.root_file and ctx.attr.root_files: 357 fail("root_file and root_files cannot be both provided") 358 if ctx.attr.root_file: 359 root_file = ctx.attr.root_file 360 else: 361 goos, goarch = detect_host_platform(ctx) 362 platform = goos + "_" + goarch 363 if platform not in ctx.attr.root_files: 364 fail("unsupported platform {}".format(platform)) 365 root_file = Label(ctx.attr.root_files[platform]) 366 goroot = str(ctx.path(root_file).dirname) 367 platform = _detect_sdk_platform(ctx, goroot) 368 version = _detect_sdk_version(ctx, goroot) 369 _sdk_build_file(ctx, platform, version, ctx.attr.experiments) 370 _local_sdk(ctx, goroot) 371 372_go_wrap_sdk = repository_rule( 373 implementation = _go_wrap_sdk_impl, 374 attrs = { 375 "root_file": attr.label( 376 mandatory = False, 377 doc = "A file in the SDK root direcotry. Used to determine GOROOT.", 378 ), 379 "root_files": attr.string_dict( 380 mandatory = False, 381 doc = "A set of mappings from the host platform to a file in the SDK's root directory", 382 ), 383 "version": attr.string(), 384 "experiments": attr.string_list( 385 doc = "Go experiments to enable via GOEXPERIMENT", 386 ), 387 "_sdk_build_file": attr.label( 388 default = Label("//go/private:BUILD.sdk.bazel"), 389 ), 390 }, 391) 392 393def go_wrap_sdk(name, register_toolchains = True, **kwargs): 394 _go_wrap_sdk(name = name, **kwargs) 395 _go_toolchains( 396 name = name + "_toolchains", 397 sdk_repo = name, 398 sdk_type = "remote", 399 sdk_version = kwargs.get("version"), 400 goos = kwargs.get("goos"), 401 goarch = kwargs.get("goarch"), 402 ) 403 if register_toolchains: 404 _register_toolchains(name) 405 406def _register_toolchains(repo): 407 native.register_toolchains("@{}_toolchains//:all".format(repo)) 408 409def _remote_sdk(ctx, urls, strip_prefix, sha256): 410 if len(urls) == 0: 411 fail("no urls specified") 412 host_goos, _ = detect_host_platform(ctx) 413 414 ctx.report_progress("Downloading and extracting Go toolchain") 415 416 # TODO(#2771): After bazelbuild/bazel#18448 is merged and available in 417 # the minimum supported version of Bazel, remove the workarounds below. 418 # 419 # Go ships archives containing some non-ASCII file names, used in 420 # test cases for Go's build system. Bazel has a bug extracting these 421 # archives on certain file systems (macOS AFS at least, possibly also 422 # Docker on macOS with a bind mount). 423 # 424 # For .tar.gz files (available for most platforms), we work around this bug 425 # by using the system tar instead of ctx.download_and_extract. 426 # 427 # For .zip files, we use ctx.download_and_extract but with rename_files, 428 # changing certain paths that trigger the bug. This is only available 429 # in Bazel 6.0.0+ (bazelbuild/bazel#16052). The only situation where 430 # .zip files are needed seems to be a macOS host using a Windows toolchain 431 # for remote execution. 432 if urls[0].endswith(".tar.gz"): 433 if strip_prefix != "go": 434 fail("strip_prefix not supported") 435 ctx.download( 436 url = urls, 437 sha256 = sha256, 438 output = "go_sdk.tar.gz", 439 ) 440 res = ctx.execute(["tar", "-xf", "go_sdk.tar.gz", "--strip-components=1"]) 441 if res.return_code: 442 fail("error extracting Go SDK:\n" + res.stdout + res.stderr) 443 ctx.delete("go_sdk.tar.gz") 444 elif (urls[0].endswith(".zip") and 445 host_goos != "windows" and 446 # Development versions of Bazel have an empty version string. We assume that they are 447 # more recent than the version that introduced rename_files. 448 versions.is_at_least("6.0.0", versions.get() or "6.0.0")): 449 ctx.download_and_extract( 450 url = urls, 451 stripPrefix = strip_prefix, 452 sha256 = sha256, 453 rename_files = { 454 "go/test/fixedbugs/issue27836.dir/\336foo.go": "go/test/fixedbugs/issue27836.dir/thfoo.go", 455 "go/test/fixedbugs/issue27836.dir/\336main.go": "go/test/fixedbugs/issue27836.dir/thmain.go", 456 }, 457 ) 458 else: 459 ctx.download_and_extract( 460 url = urls, 461 stripPrefix = strip_prefix, 462 sha256 = sha256, 463 ) 464 465def _local_sdk(ctx, path): 466 for entry in ["src", "pkg", "bin", "lib", "misc"]: 467 ctx.symlink(path + "/" + entry, entry) 468 469def _sdk_build_file(ctx, platform, version, experiments): 470 ctx.file("ROOT") 471 goos, _, goarch = platform.partition("_") 472 473 pv = parse_version(version) 474 if pv != None and pv[1] >= 20: 475 # Turn off coverageredesign GOEXPERIMENT on 1.20+ 476 # until rules_go is updated to work with the 477 # coverage redesign. 478 if not "nocoverageredesign" in experiments and not "coverageredesign" in experiments: 479 experiments = experiments + ["nocoverageredesign"] 480 481 ctx.template( 482 "BUILD.bazel", 483 ctx.path(ctx.attr._sdk_build_file), 484 executable = False, 485 substitutions = { 486 "{goos}": goos, 487 "{goarch}": goarch, 488 "{exe}": ".exe" if goos == "windows" else "", 489 "{version}": version, 490 "{experiments}": repr(experiments), 491 }, 492 ) 493 494 ctx.file( 495 "version.bzl", 496 executable = False, 497 content = _define_version_constants(version), 498 ) 499 500def detect_host_platform(ctx): 501 goos = ctx.os.name 502 if goos == "mac os x": 503 goos = "darwin" 504 elif goos.startswith("windows"): 505 goos = "windows" 506 507 goarch = ctx.os.arch 508 if goarch == "aarch64": 509 goarch = "arm64" 510 elif goarch == "x86_64": 511 goarch = "amd64" 512 513 return goos, goarch 514 515def _detect_host_sdk(ctx): 516 root = "@invalid@" 517 if "GOROOT" in ctx.os.environ: 518 return ctx.os.environ["GOROOT"] 519 res = ctx.execute([executable_path(ctx, "go"), "env", "GOROOT"]) 520 if res.return_code: 521 fail("Could not detect host go version") 522 root = res.stdout.strip() 523 if not root: 524 fail("host go version failed to report it's GOROOT") 525 return root 526 527def _detect_sdk_platform(ctx, goroot): 528 path = ctx.path(goroot + "/pkg/tool") 529 if not path.exists: 530 fail("Could not detect SDK platform: failed to find " + str(path)) 531 tool_entries = path.readdir() 532 533 platforms = [] 534 for f in tool_entries: 535 if f.basename.find("_") >= 0: 536 platforms.append(f.basename) 537 538 if len(platforms) == 0: 539 fail("Could not detect SDK platform: found no platforms in %s" % path) 540 if len(platforms) > 1: 541 fail("Could not detect SDK platform: found multiple platforms %s in %s" % (platforms, path)) 542 return platforms[0] 543 544def _detect_sdk_version(ctx, goroot): 545 version_file_path = goroot + "/VERSION" 546 if ctx.path(version_file_path).exists: 547 # VERSION file has version prefixed by go, eg. go1.18.3 548 version = ctx.read(version_file_path)[2:] 549 if ctx.attr.version and ctx.attr.version != version: 550 fail("SDK is version %s, but version %s was expected" % (version, ctx.attr.version)) 551 return version 552 553 # The top-level VERSION file does not exist in all Go SDK distributions, e.g. those shipped by Debian or Fedora. 554 # Falling back to running "go version" 555 go_binary_path = goroot + "/bin/go" 556 result = ctx.execute([go_binary_path, "version"]) 557 if result.return_code != 0: 558 fail("Could not detect SDK version: '%s version' exited with exit code %d" % (go_binary_path, result.return_code)) 559 560 # go version output is of the form "go version go1.18.3 linux/amd64" or "go 561 # version devel go1.19-fd1b5904ae Tue Mar 22 21:38:10 2022 +0000 562 # linux/amd64". See the following links for how this output is generated: 563 # - https://github.com/golang/go/blob/2bdb5c57f1efcbddab536028d053798e35de6226/src/cmd/go/internal/version/version.go#L75 564 # - https://github.com/golang/go/blob/2bdb5c57f1efcbddab536028d053798e35de6226/src/cmd/dist/build.go#L333 565 # 566 # Read the third word, or the fourth word if the third word is "devel", to 567 # find the version number. 568 output_parts = result.stdout.split(" ") 569 if len(output_parts) > 2 and output_parts[2].startswith("go"): 570 version = output_parts[2][len("go"):] 571 elif len(output_parts) > 3 and output_parts[2] == "devel" and output_parts[3].startswith("go"): 572 version = output_parts[3][len("go"):] 573 else: 574 fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout)) 575 if parse_version(version) == None: 576 fail("Could not parse SDK version from '%s version' output: %s" % (go_binary_path, result.stdout)) 577 if ctx.attr.version and ctx.attr.version != version: 578 fail("SDK is version %s, but version %s was expected" % (version, ctx.attr.version)) 579 return version 580 581def _parse_versions_json(data): 582 """Parses version metadata returned by go.dev. 583 584 Args: 585 data: the contents of the file downloaded from 586 https://go.dev/dl/?mode=json. We assume the file is valid 587 JSON, is spaced and indented, and is in a particular format. 588 589 Return: 590 A dict mapping version strings (like "1.15.5") to dicts mapping 591 platform names (like "linux_amd64") to pairs of filenames 592 (like "go1.15.5.linux-amd64.tar.gz") and hex-encoded SHA-256 sums. 593 """ 594 sdks = json.decode(data) 595 return { 596 sdk["version"][len("go"):]: { 597 "%s_%s" % (file["os"], file["arch"]): ( 598 file["filename"], 599 file["sha256"], 600 ) 601 for file in sdk["files"] 602 if file["kind"] == "archive" 603 } 604 for sdk in sdks 605 } 606 607def parse_version(version): 608 """Parses a version string like "1.15.5" and returns a tuple of numbers or None""" 609 l, r = 0, 0 610 parsed = [] 611 for c in version.elems(): 612 if c == ".": 613 if l == r: 614 # empty component 615 return None 616 parsed.append(int(version[l:r])) 617 r += 1 618 l = r 619 continue 620 621 if c.isdigit(): 622 r += 1 623 continue 624 625 # pre-release suffix 626 break 627 628 if l == r: 629 # empty component 630 return None 631 parsed.append(int(version[l:r])) 632 if len(parsed) == 2: 633 # first minor version, like (1, 15) 634 parsed.append(0) 635 if len(parsed) != 3: 636 # too many or too few components 637 return None 638 if r < len(version): 639 # pre-release suffix 640 parsed.append(version[r:]) 641 return tuple(parsed) 642 643def _version_is_prerelease(v): 644 return len(v) > 3 645 646def _version_less(a, b): 647 if a[:3] < b[:3]: 648 return True 649 if a[:3] > b[:3]: 650 return False 651 if len(a) > len(b): 652 return True 653 if len(a) < len(b) or len(a) == 3: 654 return False 655 return a[3:] < b[3:] 656 657def _version_string(v): 658 suffix = v[3] if _version_is_prerelease(v) else "" 659 if v[-1] == 0: 660 v = v[:-1] 661 return ".".join([str(n) for n in v]) + suffix 662 663def _have_same_length(*lists): 664 if not lists: 665 fail("expected at least one list") 666 return len({len(l): None for l in lists}) == 1 667 668def go_register_toolchains(version = None, nogo = None, go_version = None, experiments = None): 669 """See /go/toolchains.rst#go-register-toolchains for full documentation.""" 670 if not version: 671 version = go_version # old name 672 673 sdk_kinds = ("go_download_sdk_rule", "go_host_sdk_rule", "_go_local_sdk", "_go_wrap_sdk") 674 existing_rules = native.existing_rules() 675 sdk_rules = [r for r in existing_rules.values() if r["kind"] in sdk_kinds] 676 if len(sdk_rules) == 0 and "go_sdk" in existing_rules: 677 # may be local_repository in bazel_tests. 678 sdk_rules.append(existing_rules["go_sdk"]) 679 680 if version and len(sdk_rules) > 0: 681 fail("go_register_toolchains: version set after go sdk rule declared ({})".format(", ".join([r["name"] for r in sdk_rules]))) 682 if len(sdk_rules) == 0: 683 if not version: 684 fail('go_register_toolchains: version must be a string like "1.15.5" or "host"') 685 elif version == "host": 686 go_host_sdk(name = "go_sdk", experiments = experiments) 687 else: 688 pv = parse_version(version) 689 if not pv: 690 fail('go_register_toolchains: version must be a string like "1.15.5" or "host"') 691 if _version_less(pv, MIN_SUPPORTED_VERSION): 692 print("DEPRECATED: Go versions before {} are not supported and may not work".format(_version_string(MIN_SUPPORTED_VERSION))) 693 go_download_sdk( 694 name = "go_sdk", 695 version = version, 696 experiments = experiments, 697 ) 698 699 if nogo: 700 # Override default definition in go_rules_dependencies(). 701 go_register_nogo( 702 name = "io_bazel_rules_nogo", 703 nogo = nogo, 704 ) 705