From e54eab1b58b4a79c408a02784cf8f6108d4c3029 Mon Sep 17 00:00:00 2001 From: Jay Conrod Date: Wed, 25 Jul 2018 11:09:53 -0400 Subject: [PATCH] Add go_sdk rule and GoSDK provider go_sdk is a new rule that gathers information about an SDK and returns a GoSDK provider which will get wired into the toolchain. package_list is a new rule that generates a list of importable packages from the sources in the SDK (previously, we invoked go list, which is slower). --- go/def.bzl | 8 +++ go/private/providers.bzl | 21 +++++++ go/private/rules/sdk.bzl | 124 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 go/private/rules/sdk.bzl diff --git a/go/def.bzl b/go/def.bzl index 24c5cc5611..b0c82e30af 100644 --- a/go/def.bzl +++ b/go/def.bzl @@ -23,6 +23,7 @@ load( _GoLibrary = "GoLibrary", _GoPath = "GoPath", _GoSource = "GoSource", + _GoSDK = "GoSDK", ) load( "@io_bazel_rules_go//go/private:repositories.bzl", @@ -35,6 +36,10 @@ load( "go_host_sdk", "go_local_sdk", ) +load( + "@io_bazel_rules_go//go/private:rules/sdk.bzl", + "go_sdk", +) load( "@io_bazel_rules_go//go/private:go_toolchain.bzl", "go_toolchain", @@ -89,6 +94,9 @@ GoArchive = _GoArchive GoArchiveData = _GoArchiveData """See go/providers.rst#GoArchiveData for full documentation.""" +GoSDK = _GoSDK +"""See go/providers.rst#GoSDK for full documentation.""" + go_library = _go_library_macro """See go/core.rst#go_library for full documentation.""" diff --git a/go/private/providers.bzl b/go/private/providers.bzl index 15e01fcada..9a5a3a3b3e 100644 --- a/go/private/providers.bzl +++ b/go/private/providers.bzl @@ -48,6 +48,27 @@ GoAspectProviders = provider() GoPath = provider() +GoSDK = provider( + doc = "Contains information about the Go SDK used in the toolchain", + fields = { + "goos": "The host OS the SDK was built for.", + "goarch": "The host architecture the SDK was built for.", + "root_file": "A file in the SDK root directory", + "libs": ("List of pre-compiled .a files for the standard library " + + "built for the execution platform."), + "headers": ("List of .h files from pkg/include that may be included " + + "in assembly sources."), + "srcs": ("List of source files for importable packages in the " + + "standard library. Internal, vendored, and tool packages " + + "may not be included."), + "package_list": ("A file containing a list of importable packages " + + "in the standard library."), + "tools": ("List of executable files from pkg/tool " + + "built for the execution platform."), + "go": "The go binary file", + }, +) + GoStdLib = provider() GoBuilders = provider() diff --git a/go/private/rules/sdk.bzl b/go/private/rules/sdk.bzl new file mode 100644 index 0000000000..3995080c9d --- /dev/null +++ b/go/private/rules/sdk.bzl @@ -0,0 +1,124 @@ +# Copyright 2014 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load( + "@io_bazel_rules_go//go/private:providers.bzl", + "GoSDK", +) + +def _go_sdk_impl(ctx): + return [GoSDK( + goos = ctx.attr.goos, + goarch = ctx.attr.goarch, + root_file = ctx.file.root_file, + package_list = ctx.file.package_list, + libs = ctx.files.libs, + headers = ctx.files.headers, + srcs = ctx.files.srcs, + tools = ctx.files.tools, + go = ctx.file.go, + )] + +go_sdk = rule( + _go_sdk_impl, + attrs = { + "goos": attr.string( + mandatory = True, + doc = "The host OS the SDK was built for", + ), + "goarch": attr.string( + mandatory = True, + doc = "The host architecture the SDK was built for", + ), + "root_file": attr.label( + mandatory = True, + allow_single_file = True, + doc = "A file in the SDK root directory. Used to determine GOROOT.", + ), + "package_list": attr.label( + mandatory = True, + allow_single_file = True, + doc = ("A text file containing a list of packages in the " + + "standard library that may be imported."), + ), + "libs": attr.label_list( + allow_files = [".a"], + doc = ("Pre-compiled .a files for the standard library, " + + "built for the execution platform"), + ), + "headers": attr.label_list( + allow_files = [".h"], + doc = (".h files from pkg/include that may be included in " + + "assembly sources"), + ), + "srcs": attr.label_list( + allow_files = True, + doc = "Source files for packages in the standard library", + ), + "tools": attr.label_list( + allow_files = True, + cfg = "host", + doc = ("List of executable files from pkg/tool " + + "built for the execution platform"), + ), + "go": attr.label( + mandatory = True, + allow_single_file = True, + executable = True, + cfg = "host", + doc = "The go binary", + ), + }, + doc = ("Collects information about a Go SDK. The SDK must have a normal " + + "GOROOT directory structure."), + provides = [GoSDK], +) + +def _package_list_impl(ctx): + packages = {} + src_dir = ctx.file.root_file.dirname + "/src/" + for src in ctx.files.srcs: + pkg_src_dir = src.dirname + if not pkg_src_dir.startswith(src_dir): + continue + pkg_name = pkg_src_dir[len(src_dir):] + if any([prefix in pkg_name for prefix in ("vendor/", "cmd/")]): + continue + packages[pkg_name] = None + content = "\n".join(sorted(packages.keys())) + "\n" + ctx.actions.write(ctx.outputs.out, content) + return [DefaultInfo(files = depset([ctx.outputs.out]))] + +package_list = rule( + _package_list_impl, + attrs = { + "srcs": attr.label_list( + allow_files = True, + doc = "Source files for packages in the standard library", + ), + "root_file": attr.label( + mandatory = True, + allow_single_file = True, + doc = "A file in the SDK root directory. Used to determine GOROOT.", + ), + "out": attr.output( + mandatory = True, + doc = "File to write. Must be 'packages.txt'.", + # Gazelle depends on this file directly. It has to be an output + # attribute because Bazel has no other way of knowing what rule + # produces this file. + # TODO(jayconrod): Update Gazelle and simplify this. + ), + }, +)