build/toolbase/gotoolchain: init
Another piece of the toolbase puzzle, this one is a library which
provides information about the Go SDK picked by Bazel/rules_go, and
allows to build tools that call the `go` tool.
This is effectively the logic from //build/fietsje:def.bzl, but
rewritten to be reusable. In a later CL, we will make Fietsje use this
logic instead of its existing starlark/shell magic.
Change-Id: I2be723089410c81843b54df77bcd665a4e050cbb
Reviewed-on: https://review.monogon.dev/c/monogon/+/329
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/build/toolbase/gotoolchain/def.bzl b/build/toolbase/gotoolchain/def.bzl
new file mode 100644
index 0000000..1722cc4
--- /dev/null
+++ b/build/toolbase/gotoolchain/def.bzl
@@ -0,0 +1,78 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_context", "GoSource")
+
+# This implements the toolchain_library rule, which is used to generate a
+# rules_go compatible go_library-style target which contains toolchain.go.in
+# augmented with information about the Go SDK's toolchain used by Bazel.
+#
+# The library can then be used to build tools that call the `go` tool, for
+# example to perform static analysis or dependency management.
+
+def _toolchain_library_impl(ctx):
+ go = go_context(ctx)
+
+ importpath = ctx.attr.importpath
+
+ out = go.declare_file(go, ext = ".go")
+ ctx.actions.expand_template(
+ template = ctx.file._template,
+ output = out,
+ substitutions = {
+ 'GOROOT': go.root,
+ 'GOTOOL': go.go.path,
+ },
+ )
+
+ library = go.new_library(go)
+ source = go.library_to_source(go, struct(
+ srcs = [struct(files = [out])],
+ deps = ctx.attr.deps,
+ ), library, ctx.coverage_instrumented())
+
+ # Hack: we want to inject runfiles into the generated GoSource, because
+ # there's no other way to make rules_go pick up runfiles otherwise.
+ runfiles = ctx.runfiles(files = [
+ go.go,
+ go.sdk_root,
+ ] + go.sdk_files)
+ source = {
+ key: getattr(source, key)
+ for key in dir(source)
+ if key not in ['to_json', 'to_proto']
+ }
+ source['runfiles'] = runfiles
+ source = GoSource(**source)
+ archive = go.archive(go, source)
+
+
+ return [
+ library,
+ source,
+ archive,
+ DefaultInfo(
+ files = depset([archive.data.file]),
+ runfiles = runfiles,
+ ),
+ OutputGroupInfo(
+ cgo_exports = archive.cgo_exports,
+ compilation_outputs = [archive.data.file],
+ ),
+ ]
+
+
+toolchain_library = rule(
+ implementation = _toolchain_library_impl,
+ attrs = {
+ "importpath": attr.string(
+ mandatory = True,
+ ),
+ "deps": attr.label_list(),
+ "_template": attr.label(
+ allow_single_file = True,
+ default = ":toolchain.go.in",
+ ),
+ "_go_context_data": attr.label(
+ default = "@io_bazel_rules_go//:go_context_data",
+ ),
+ },
+ toolchains = ["@io_bazel_rules_go//go:toolchain"],
+)