mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
This change is a no-op, as we already used the toolchain language version. PiperOrigin-RevId: 926779620
299 lines
9.9 KiB
Python
299 lines
9.9 KiB
Python
"""Go rules."""
|
|
|
|
load("@bazel_gazelle//:def.bzl", _gazelle = "gazelle")
|
|
load("@bazel_skylib//lib:paths.bzl", "paths")
|
|
load("@bazel_skylib//lib:shell.bzl", "shell")
|
|
load("@io_bazel_rules_go//go:def.bzl", "GoLibrary", _go_binary = "go_binary", _go_context = "go_context", _go_library = "go_library", _go_path = "go_path", _go_test = "go_test")
|
|
load("@io_bazel_rules_go//proto:def.bzl", _go_grpc_library = "go_grpc_library", _go_proto_library = "go_proto_library")
|
|
load("//tools/bazeldefs:defs.bzl", "select_arch", "select_system")
|
|
|
|
gazelle = _gazelle
|
|
|
|
go_path = _go_path
|
|
go_cov = native.genrule
|
|
|
|
def _go_proto_or_grpc_library(go_library_func, name, **kwargs):
|
|
if "importpath" in kwargs:
|
|
# If importpath is explicit, pass straight through.
|
|
go_library_func(name = name, **kwargs)
|
|
return
|
|
deps = []
|
|
com_google_protobuf = "@com_google_protobuf//"
|
|
org_golang_google_protobuf = "@org_golang_google_protobuf//"
|
|
for d in (kwargs.pop("deps", []) or []):
|
|
# Special cases: these protos have their Go definitions in a different
|
|
# repository.
|
|
if d == com_google_protobuf + ":timestamp_proto":
|
|
deps.append(org_golang_google_protobuf + "types/known/timestamppb")
|
|
continue
|
|
if d == com_google_protobuf + ":any_proto":
|
|
deps.append(org_golang_google_protobuf + "types/known/anypb")
|
|
continue
|
|
|
|
if "//" in d:
|
|
repo, path = d.split("//", 1)
|
|
deps.append(repo + "//" + path.replace("_proto", "_go_proto"))
|
|
else:
|
|
deps.append(d.replace("_proto", "_go_proto"))
|
|
go_library_func(
|
|
name = name + "_go_proto",
|
|
importpath = "gvisor.dev/gvisor/" + native.package_name() + "/" + name + "_go_proto",
|
|
proto = ":" + name + "_proto",
|
|
deps = deps,
|
|
**kwargs
|
|
)
|
|
|
|
def go_proto_library(name, **kwargs):
|
|
_go_proto_or_grpc_library(_go_proto_library, name, **kwargs)
|
|
|
|
def go_grpc_and_proto_libraries(name, **kwargs):
|
|
_go_proto_or_grpc_library(_go_grpc_library, name, **kwargs)
|
|
|
|
def go_binary(name, static = False, pure = False, x_defs = None, **kwargs):
|
|
"""Build a go binary.
|
|
|
|
Args:
|
|
name: name of the target.
|
|
static: build a static binary.
|
|
pure: build without cgo.
|
|
x_defs: additional definitions.
|
|
**kwargs: rest of the arguments are passed to _go_binary.
|
|
"""
|
|
if "noasan" in kwargs:
|
|
# no-op option, will need to do transitions when sanitizer configs are defined.
|
|
kwargs.pop("noasan")
|
|
|
|
if static:
|
|
kwargs["static"] = "on"
|
|
if pure:
|
|
kwargs["pure"] = "on"
|
|
gc_goopts = select({
|
|
"//conditions:default": kwargs.pop("gc_goopts", []),
|
|
"//tools:debug": kwargs.pop("gc_goopts", []) + ["-N", "-l"],
|
|
})
|
|
base_gotags = kwargs.pop("gotags", [])
|
|
kwargs["gotags"] = select({
|
|
"//tools/bazeldefs:pagesize_64k": base_gotags + ["pagesize_64k"],
|
|
"//tools:debug": base_gotags + ["debug"],
|
|
"//conditions:default": base_gotags,
|
|
})
|
|
_go_binary(
|
|
name = name,
|
|
x_defs = x_defs,
|
|
gc_goopts = gc_goopts,
|
|
**kwargs
|
|
)
|
|
|
|
def go_importpath(target):
|
|
"""Returns the importpath for the target."""
|
|
return target[GoLibrary].importpath
|
|
|
|
def go_library(name, bazel_cgo = False, bazel_cdeps = [], bazel_clinkopts = [], bazel_copts = [], **kwargs):
|
|
"""Wrapper for `go_library` rule.
|
|
|
|
Args:
|
|
name: name of the target.
|
|
bazel_cgo: if True, build with cgo.
|
|
cgo_cdeps: cgo deps to pass to `go_library`.
|
|
cgo_clinkopts: cgo linkopts to pass to `go_library`.
|
|
cgo_copts: cgo opts to pass to `go_library`.
|
|
**kwargs: rest of the arguments are passed to `go_library`.
|
|
"""
|
|
_go_library(
|
|
name = name,
|
|
cgo = bazel_cgo,
|
|
cdeps = bazel_cdeps,
|
|
copts = bazel_copts,
|
|
clinkopts = bazel_clinkopts,
|
|
importpath = "gvisor.dev/gvisor/" + native.package_name(),
|
|
**kwargs
|
|
)
|
|
|
|
def go_test(name, static = False, pure = False, library = None, **kwargs):
|
|
"""Build a go test.
|
|
|
|
Args:
|
|
name: name of the output binary.
|
|
static: build a static binary.
|
|
pure: should it be built without cgo.
|
|
library: the library to embed.
|
|
**kwargs: rest of the arguments to pass to _go_test.
|
|
"""
|
|
if pure:
|
|
kwargs["pure"] = "on"
|
|
if static:
|
|
kwargs["static"] = "on"
|
|
if library:
|
|
kwargs["embed"] = [library]
|
|
base_gotags = kwargs.pop("gotags", [])
|
|
kwargs["gotags"] = select({
|
|
"//tools/bazeldefs:pagesize_64k": base_gotags + ["pagesize_64k"],
|
|
"//tools:debug": base_gotags + ["debug"],
|
|
"//conditions:default": base_gotags,
|
|
})
|
|
_go_test(
|
|
name = name,
|
|
**kwargs
|
|
)
|
|
|
|
def go_rule(rule, implementation, **kwargs):
|
|
"""Wraps a rule definition with Go attributes.
|
|
|
|
Args:
|
|
rule: rule function (typically rule or aspect).
|
|
implementation: implementation function.
|
|
**kwargs: other arguments to pass to rule.
|
|
|
|
Returns:
|
|
The result of invoking the rule.
|
|
"""
|
|
kwargs.setdefault("attrs", dict()).update({
|
|
"_go_context_data": attr.label(default = "@io_bazel_rules_go//:go_context_data"),
|
|
"_stdlib": attr.label(default = "@io_bazel_rules_go//:stdlib"),
|
|
})
|
|
kwargs.setdefault("toolchains", []).append("@io_bazel_rules_go//go:toolchain")
|
|
return rule(implementation, **kwargs)
|
|
|
|
def go_embed_libraries(target):
|
|
if hasattr(target.attr, "embed"):
|
|
return target.attr.embed
|
|
return []
|
|
|
|
def go_context(ctx, goos = None, goarch = None):
|
|
"""Extracts a standard Go context struct.
|
|
|
|
Args:
|
|
ctx: the starlark context (required).
|
|
goos: the GOOS value.
|
|
goarch: the GOARCH value.
|
|
|
|
Returns:
|
|
A context Go struct with pointers to Go toolchain components.
|
|
"""
|
|
|
|
# We don't change anything for the standard library analysis. All Go files
|
|
# are available in all instances. Note that this includes the standard
|
|
# library sources, which are analyzed by nogo.
|
|
go_ctx = _go_context(ctx)
|
|
|
|
nogo_args = []
|
|
if go_ctx.mode.race:
|
|
nogo_args = nogo_args + ["-race"]
|
|
if go_ctx.mode.msan:
|
|
nogo_args = nogo_args + ["-msan"]
|
|
|
|
stdlib_mods = [f for f in go_ctx.sdk.srcs.to_list() if f.path.endswith("/src/go.mod")]
|
|
if len(stdlib_mods) != 1:
|
|
fail("expect exactly one stdlib src/go.mod in %s, found %s" % (go_ctx.sdk.srcs, stdlib_mods))
|
|
stdlib_mod = stdlib_mods[0]
|
|
|
|
return struct(
|
|
env = dict(go_ctx.env, CGO_ENABLED = "0"),
|
|
go = go_ctx.go,
|
|
goarch = goarch or go_ctx.sdk.goarch,
|
|
goos = goos or go_ctx.sdk.goos,
|
|
gotags = go_ctx.tags,
|
|
lang_version = "go" + go_ctx.sdk.version, # go_ctx.sdk.version excludes the go prefix.
|
|
nogo_args = nogo_args,
|
|
runfiles = depset([go_ctx.go] + go_ctx.sdk.srcs.to_list() + go_ctx.sdk.tools.to_list() + go_ctx.stdlib.libs.to_list()),
|
|
stdlib_srcs = go_ctx.sdk.srcs,
|
|
stdlib_mod = stdlib_mod,
|
|
)
|
|
|
|
def select_goarch():
|
|
return select_arch(amd64 = "amd64", arm64 = "arm64")
|
|
|
|
def select_goos():
|
|
return select_system(
|
|
linux = "linux",
|
|
darwin = "darwin",
|
|
)
|
|
|
|
# Defined by rules_go.
|
|
gotsan_values = None
|
|
gotsan_flag_values = {"@io_bazel_rules_go//go/config:race": "true"}
|
|
|
|
def _go_imports_impl(ctx):
|
|
"""Hermetic wrapper around goimports.
|
|
|
|
`goimports` shells out to the `go` command (via golang.org/x/tools internal
|
|
helpers) and therefore requires a usable `go` binary during the action.
|
|
|
|
See:
|
|
- https://github.com/golang/tools/blob/master/internal/gocommand/invoke.go
|
|
- https://github.com/golang/tools/blob/master/internal/imports/fix.go
|
|
- https://go.dev/doc/go1.19#os-exec-path
|
|
"""
|
|
go_ctx = go_context(ctx)
|
|
|
|
src = ctx.file.src
|
|
out = ctx.outputs.out
|
|
|
|
goimports_tool = ctx.attr._goimports[DefaultInfo].files_to_run
|
|
|
|
tools_path = paths.join(ctx.label.name + "_tools")
|
|
|
|
# Use a symlink to the `go` binary to avoid exposing undeclared dependencies
|
|
# on other binaries in the same directory in the toolchain.
|
|
go_symlink = ctx.actions.declare_file(paths.join(tools_path, "go"))
|
|
ctx.actions.symlink(
|
|
output = go_symlink,
|
|
target_file = go_ctx.go,
|
|
is_executable = True,
|
|
)
|
|
|
|
# Use a launcher script rather than ctx.actions.run(env=...) because we need
|
|
# to refer to the action's runtime working directory ($PWD) to build an
|
|
# absolute PATH entry. This matters because `goimports` locates `go` via
|
|
# os/exec.LookPath("go") and recent Go versions refuse to execute commands
|
|
# found via a relative PATH entry.
|
|
#
|
|
# See https://pkg.go.dev/os/exec#hdr-Executables_in_the_current_directory.
|
|
goimports_launcher = ctx.actions.declare_file(paths.join(tools_path, "goimports.sh"))
|
|
ctx.actions.write(
|
|
output = goimports_launcher,
|
|
is_executable = True,
|
|
content = "PATH=$PWD/{} exec {} {} > {}".format(
|
|
shell.quote(go_symlink.dirname),
|
|
shell.quote(goimports_tool.executable.path),
|
|
shell.quote(src.path),
|
|
shell.quote(out.path),
|
|
),
|
|
)
|
|
|
|
ctx.actions.run(
|
|
inputs = [src],
|
|
tools = [goimports_tool, go_symlink, go_ctx.runfiles],
|
|
outputs = [out],
|
|
executable = goimports_launcher,
|
|
env = go_ctx.env,
|
|
mnemonic = "GoImports",
|
|
progress_message = "GoImports {}".format(src.short_path),
|
|
)
|
|
|
|
return DefaultInfo(files = depset([out]))
|
|
|
|
_go_imports = go_rule(
|
|
rule,
|
|
implementation = _go_imports_impl,
|
|
attrs = {
|
|
"src": attr.label(mandatory = True, allow_single_file = [".go"]),
|
|
"out": attr.output(mandatory = True),
|
|
"_goimports": attr.label(
|
|
default = "@org_golang_x_tools//cmd/goimports:goimports",
|
|
executable = True,
|
|
cfg = "exec",
|
|
),
|
|
},
|
|
)
|
|
|
|
def go_imports(name, src, out):
|
|
_go_imports(
|
|
name = name,
|
|
src = src,
|
|
out = out,
|
|
)
|
|
|
|
def nogo_extra_proto_deps(target):
|
|
return []
|