From 1c4f6fd1315ac4c3876c0e8d01be8a0dfd71a148 Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Wed, 13 Dec 2017 23:39:08 -0500 Subject: [PATCH] Fix aspect based proto builds (#1131) * Fix aspect based proto builds This changes the structure of our providers. It is now much more principled about configuration specific and transitive providers, separating them cleanly. It also allows the GoLibray provider to supply a function that can be used to produce the configuration specific version (GoSource). This allows us to fix the proto library dependancies when built in aspect mode. * Make it a little easier to write simple code generation rules * Review fixes --- examples/proto/BUILD.bazel | 13 +++ go/def.bzl | 4 - go/modes.rst | 2 +- go/private/actions/archive.bzl | 61 +++++------ go/private/actions/binary.bzl | 21 +--- go/private/actions/compile.bzl | 1 - go/private/actions/cover.bzl | 59 ++++------ go/private/actions/library.bzl | 62 ----------- go/private/actions/link.bzl | 22 ++-- go/private/common.bzl | 5 +- go/private/go_toolchain.bzl | 2 - go/private/providers.bzl | 93 +++++----------- go/private/repositories.bzl | 4 +- go/private/rules/aspect.bzl | 80 +++++--------- go/private/rules/binary.bzl | 28 +++-- go/private/rules/cgo.bzl | 48 +++++--- go/private/rules/helpers.bzl | 89 +++++++++++++++ go/private/rules/library.bzl | 36 +++--- go/private/rules/source.bzl | 17 ++- go/private/rules/test.bzl | 51 +++++---- go/private/tools/embed_data.bzl | 16 ++- go/private/tools/path.bzl | 14 ++- go/providers.rst | 189 ++++++++++++++++++++------------ proto/compiler.bzl | 38 +++++-- proto/def.bzl | 60 ++++++---- 25 files changed, 531 insertions(+), 484 deletions(-) delete mode 100644 go/private/actions/library.bzl create mode 100644 go/private/rules/helpers.bzl diff --git a/examples/proto/BUILD.bazel b/examples/proto/BUILD.bazel index 1230914953..a4a55ec99c 100644 --- a/examples/proto/BUILD.bazel +++ b/examples/proto/BUILD.bazel @@ -14,6 +14,19 @@ go_library( go_test( name = "proto_test", size = "small", + pure = "off", + srcs = ["proto_test.go"], + importpath = "github.com/bazelbuild/rules_go/examples/proto", + deps = [ + "//examples/proto/embed:go_default_library", + "//examples/proto/lib:lib_go_proto", + ], +) + +go_test( + name = "proto_pure_test", + size = "small", + pure = "on", srcs = ["proto_test.go"], importpath = "github.com/bazelbuild/rules_go/examples/proto", deps = [ diff --git a/go/def.bzl b/go/def.bzl index c9db559b12..1ea70f12cb 100644 --- a/go/def.bzl +++ b/go/def.bzl @@ -17,7 +17,6 @@ load("@io_bazel_rules_go//go/private:go_repository.bzl", ) load("@io_bazel_rules_go//go/private:providers.bzl", _GoLibrary = "GoLibrary", - _GoSourceList = "GoSourceList", ) load("@io_bazel_rules_go//go/private:repositories.bzl", "go_rules_dependencies", @@ -63,9 +62,6 @@ RULES_GO_VERSION = "0.8.1" GoLibrary = _GoLibrary """See go/providers.rst#GoLibrary for full documentation.""" -GoSourceList = _GoSourceList -"""See go/providers.rst#GoSourceList for full documentation.""" - go_library = _go_library_macro """See go/core.rst#go_library for full documentation.""" diff --git a/go/modes.rst b/go/modes.rst index 50b5763edc..e7f31ae7eb 100644 --- a/go/modes.rst +++ b/go/modes.rst @@ -92,7 +92,7 @@ following fields that control the bevhaviour of those actions: Build modes ----------- -The following is a description of the build modes. Not all build modes are truly independant, but +The following is a description of the build modes. Not all build modes are truly independent, but most combinations are valid. static diff --git a/go/private/actions/archive.bzl b/go/private/actions/archive.bzl index a75ddf4c9e..47db97ded8 100644 --- a/go/private/actions/archive.bzl +++ b/go/private/actions/archive.bzl @@ -20,90 +20,87 @@ load("@io_bazel_rules_go//go/private:common.bzl", load("@io_bazel_rules_go//go/private:mode.bzl", "mode_string", ) -load("@io_bazel_rules_go//go/private:rules/aspect.bzl", +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", "get_archive", ) load("@io_bazel_rules_go//go/private:providers.bzl", "GoArchive", "GoArchiveData", - "sources", ) -def emit_archive(ctx, go_toolchain, mode=None, importpath=None, source=None, importable=True): +def emit_archive(ctx, go_toolchain, source=None): """See go/toolchains.rst#archive for full documentation.""" - if not importpath: fail("golib is a required parameter") if source == None: fail("source is a required parameter") - if mode == None: fail("mode is a required parameter") - - source = sources.filter(ctx, source, mode) cover_vars = [] if ctx.configuration.coverage_enabled: - source, cover_vars = go_toolchain.actions.cover(ctx, go_toolchain, source=source, mode=mode, importpath=importpath) - - flat = sources.flatten(ctx, source) - split = split_srcs(flat.srcs) - lib_name = importpath + ".a" - compilepath = importpath if importable else None - out_lib = declare_file(ctx, path=lib_name, mode=mode) + source, cover_vars = go_toolchain.actions.cover(ctx, go_toolchain, source) + split = split_srcs(source.srcs) + compilepath = source.library.importpath if source.library.importpath else source.library.name + lib_name = compilepath + ".a" + out_lib = declare_file(ctx, path=lib_name, mode=source.mode) searchpath = out_lib.path[:-len(lib_name)] extra_objects = [] for src in split.asm: - obj = declare_file(ctx, path=src.basename[:-2], ext=".o", mode=mode) - go_toolchain.actions.asm(ctx, go_toolchain, mode=mode, source=src, hdrs=split.headers, out_obj=obj) + obj = declare_file(ctx, path=src.basename[:-2], ext=".o", mode=source.mode) + go_toolchain.actions.asm(ctx, go_toolchain, mode=source.mode, source=src, hdrs=split.headers, out_obj=obj) extra_objects.append(obj) - direct = [get_archive(dep) for dep in flat.deps] - runfiles = flat.runfiles + direct = [get_archive(dep) for dep in source.deps] + runfiles = source.runfiles for a in direct: runfiles = runfiles.merge(a.runfiles) - if a.mode != mode: fail("Archive mode does not match {} is {} expected {}".format(a.data.importpath, mode_string(a.mode), mode_string(mode))) + if a.source.mode != source.mode: fail("Archive mode does not match {} is {} expected {}".format(a.data.source.library.label, mode_string(a.source.mode), mode_string(source.mode))) - if len(extra_objects) == 0 and flat.cgo_archive == None: + if len(extra_objects) == 0 and source.cgo_archive == None: go_toolchain.actions.compile(ctx, go_toolchain = go_toolchain, sources = split.go, importpath = compilepath, archives = direct, - mode = mode, + mode = source.mode, out_lib = out_lib, - gc_goopts = flat.gc_goopts, + gc_goopts = source.gc_goopts, ) else: - partial_lib = declare_file(ctx, path="partial", ext=".a", mode=mode) + partial_lib = declare_file(ctx, path="partial", ext=".a", mode=source.mode) go_toolchain.actions.compile(ctx, go_toolchain = go_toolchain, sources = split.go, importpath = compilepath, archives = direct, - mode = mode, + mode = source.mode, out_lib = partial_lib, - gc_goopts = flat.gc_goopts, + gc_goopts = source.gc_goopts, ) go_toolchain.actions.pack(ctx, go_toolchain = go_toolchain, - mode = mode, + mode = source.mode, in_lib = partial_lib, out_lib = out_lib, objects = extra_objects, - archive = flat.cgo_archive, + archive = source.cgo_archive, ) data = GoArchiveData( + name = source.library.name, + label = source.library.label, + importpath = source.library.importpath, + exportpath = source.library.exportpath, file = out_lib, - importpath = importpath, + srcs = tuple(source.srcs), searchpath = searchpath, ) return GoArchive( - mode = mode, + source = source, data = data, - go_srcs = split.go, direct = direct, searchpaths = sets.union([searchpath], *[a.searchpaths for a in direct]), libs = sets.union([out_lib], *[a.libs for a in direct]), - cgo_deps = sets.union(flat.cgo_deps, *[a.cgo_deps for a in direct]), - cgo_exports = sets.union(flat.cgo_exports, *[a.cgo_exports for a in direct]), + transitive = sets.union([data], *[a.transitive for a in direct]), + cgo_deps = sets.union(source.cgo_deps, *[a.cgo_deps for a in direct]), + cgo_exports = sets.union(source.cgo_exports, *[a.cgo_exports for a in direct]), cover_vars = sets.union(cover_vars, *[a.cover_vars for a in direct]), runfiles = runfiles, ) diff --git a/go/private/actions/binary.bzl b/go/private/actions/binary.bzl index bf016b6b25..86e6eeacf5 100644 --- a/go/private/actions/binary.bzl +++ b/go/private/actions/binary.bzl @@ -12,17 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//go/private:mode.bzl", - "mode_string", - "get_mode", -) load("@io_bazel_rules_go//go/private:common.bzl", "declare_file", ) def emit_binary(ctx, go_toolchain, name="", - importpath = "", source = None, gc_linkopts = [], x_defs = {}, @@ -31,22 +26,14 @@ def emit_binary(ctx, go_toolchain, if name == "": fail("name is a required parameter") - mode = get_mode(ctx, ctx.attr._go_toolchain_flags) - golib, goarchive = go_toolchain.actions.library(ctx, - go_toolchain = go_toolchain, - mode = mode, - source = source, - importpath = importpath, - importable = False, - ) - executable = declare_file(ctx, name=name, ext=go_toolchain.data.extension, mode=mode) + archive = go_toolchain.actions.archive(ctx, go_toolchain, source) + executable = declare_file(ctx, name=name, ext=go_toolchain.data.extension, mode=source.mode) go_toolchain.actions.link(ctx, go_toolchain = go_toolchain, - archive=goarchive, - mode=mode, + archive=archive, executable=executable, gc_linkopts=gc_linkopts, x_defs=x_defs, ) - return golib, goarchive, executable + return archive, executable diff --git a/go/private/actions/compile.bzl b/go/private/actions/compile.bzl index 32041ea39a..b1a07f8233 100644 --- a/go/private/actions/compile.bzl +++ b/go/private/actions/compile.bzl @@ -51,7 +51,6 @@ def emit_compile(ctx, go_toolchain, cgo_sources = [s.path for s in sources if s.basename.startswith("_cgo")] inputs = sets.union(inputs, [archive.data.file for archive in archives]) - stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode) inputs = sets.union(inputs, stdlib.files) diff --git a/go/private/actions/cover.bzl b/go/private/actions/cover.bzl index 0598abae0b..380f4a74e7 100644 --- a/go/private/actions/cover.bzl +++ b/go/private/actions/cover.bzl @@ -17,52 +17,41 @@ load("@io_bazel_rules_go//go/private:actions/action.bzl", ) load("@io_bazel_rules_go//go/private:providers.bzl", "GoSource", - "GoSourceList", ) load("@io_bazel_rules_go//go/private:common.bzl", "declare_file", "structs", ) -def emit_cover(ctx, go_toolchain, - source = None, - mode = None, - importpath = ""): +def emit_cover(ctx, go_toolchain, source): """See go/toolchains.rst#cover for full documentation.""" if source == None: fail("source is a required parameter") - if mode == None: fail("mode is a required parameter") - if not importpath: fail("importpath is a required parameter") + if not source.cover: + return source, [] - stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode) + stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, source.mode) covered = [] cover_vars = [] - for s in source.entries: - if not s.want_coverage: - covered.append(s) + for src in source.srcs: + if not src.basename.endswith(".go") or src not in source.cover: + covered.append(src) continue - outputs = [] - for src in s.srcs: - if not src.basename.endswith(".go"): - outputs.append(src) - continue - cover_var = "Cover_" + src.basename[:-3].replace("-", "_").replace(".", "_") - cover_vars.append("{}={}={}".format(cover_var, src.short_path, importpath)) - out = declare_file(ctx, path=cover_var, ext='.cover.go') - outputs.append(out) - args = ctx.actions.args() - add_go_env(args, stdlib, mode) - args.add(["--", "--mode=set", "-var=%s" % cover_var, "-o", out, src]) - ctx.actions.run( - inputs = [src] + stdlib.files, - outputs = [out], - mnemonic = "GoCover", - executable = go_toolchain.tools.cover, - arguments = [args], - ) - - members = structs.to_dict(s) - members["srcs"] = outputs - covered.append(GoSource(**members)) - return GoSourceList(entries=covered), cover_vars + cover_var = "Cover_" + src.basename[:-3].replace("-", "_").replace(".", "_") + cover_vars.append("{}={}={}".format(cover_var, src.short_path, source.library.importpath)) + out = declare_file(ctx, path=cover_var, ext='.cover.go') + covered.append(out) + args = ctx.actions.args() + add_go_env(args, stdlib, source.mode) + args.add(["--", "--mode=set", "-var=%s" % cover_var, "-o", out, src]) + ctx.actions.run( + inputs = [src] + stdlib.files, + outputs = [out], + mnemonic = "GoCover", + executable = go_toolchain.tools.cover, + arguments = [args], + ) + members = structs.to_dict(source) + members["srcs"] = covered + return GoSource(**members), cover_vars diff --git a/go/private/actions/library.bzl b/go/private/actions/library.bzl deleted file mode 100644 index 3255bc79cb..0000000000 --- a/go/private/actions/library.bzl +++ /dev/null @@ -1,62 +0,0 @@ -# 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:common.bzl", - "split_srcs", - "join_srcs", - "structs", - "sets", - "to_set", -) -load("@io_bazel_rules_go//go/private:providers.bzl", - "GoLibrary", - "GoPackage", - "GoSourceList", - "GoSource", - "sources", -) -load("@io_bazel_rules_go//go/private:rules/aspect.bzl", - "get_archive", -) - -def emit_library(ctx, go_toolchain, - mode = None, - importpath = "", - source = None, - importable = True): - """See go/toolchains.rst#library for full documentation.""" - - transitive = [] - srcs = [] - for s in source.entries: - srcs.extend(s.srcs) - transitive.extend([dep[GoLibrary].transitive for dep in s.deps]) - package = GoPackage( - name = str(ctx.label), - importpath = importpath, # The import path for this library - srcs = sets.union(srcs), # The original unfiltered sources - ) - golib = GoLibrary( - package = package, - transitive = sets.union([package], *transitive), - ) - goarchive = go_toolchain.actions.archive(ctx, - go_toolchain = go_toolchain, - mode = mode, - importpath = importpath, - source = source, - importable = importable, - ) - - return [golib, goarchive] diff --git a/go/private/actions/link.bzl b/go/private/actions/link.bzl index 71f73acce5..da7af06881 100644 --- a/go/private/actions/link.bzl +++ b/go/private/actions/link.bzl @@ -26,7 +26,6 @@ load("@io_bazel_rules_go//go/private:actions/action.bzl", def emit_link(ctx, go_toolchain, archive = None, - mode = None, executable = None, gc_linkopts = [], x_defs = {}): @@ -34,9 +33,8 @@ def emit_link(ctx, go_toolchain, if archive == None: fail("archive is a required parameter") if executable == None: fail("executable is a required parameter") - if mode == None: fail("mode is a required parameter") - stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode) + stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, archive.source.mode) config_strip = len(ctx.configuration.bin_dir.path) + 1 pkg_depth = executable.dirname[config_strip:].count('/') + 1 @@ -51,15 +49,15 @@ def emit_link(ctx, go_toolchain, gc_linkopts, extldflags = _extract_extldflags(gc_linkopts, extldflags) # Add in any mode specific behaviours - if mode.race: + if archive.source.mode.race: gc_linkopts.append("-race") - if mode.msan: + if archive.source.mode.msan: gc_linkopts.append("-msan") - if mode.static: + if archive.source.mode.static: gc_linkopts.extend(["-linkmode", "external"]) extldflags.append("-static") - if mode.link != LINKMODE_NORMAL: - fail("Link mode {} is not yet supported".format(mode.link)) + if archive.source.mode.link != LINKMODE_NORMAL: + fail("Link mode {} is not yet supported".format(archive.source.mode.link)) link_opts = ["-L", "."] @@ -84,7 +82,7 @@ def emit_link(ctx, go_toolchain, link_opts.extend(["-X", "%s=%s" % (k, v)]) link_opts.extend(go_toolchain.flags.link) - if mode.strip: + if archive.source.mode.strip: link_opts.extend(["-w"]) if ld: @@ -94,7 +92,7 @@ def emit_link(ctx, go_toolchain, ]) link_opts.append(archive.data.file.path) link_args = ctx.actions.args() - add_go_env(link_args, stdlib, mode) + add_go_env(link_args, stdlib, archive.source.mode) # Stamping support stamp_inputs = [] if stamp_x_defs or ctx.attr.linkstamp: @@ -122,7 +120,6 @@ def emit_link(ctx, go_toolchain, def bootstrap_link(ctx, go_toolchain, archive = None, - mode = None, executable = None, gc_linkopts = [], x_defs = {}): @@ -130,7 +127,6 @@ def bootstrap_link(ctx, go_toolchain, if archive == None: fail("archive is a required parameter") if executable == None: fail("executable is a required parameter") - if mode == None: fail("mode is a required parameter") if x_defs: fail("link does not accept x_defs in bootstrap mode") @@ -138,7 +134,7 @@ def bootstrap_link(ctx, go_toolchain, args = ["tool", "link", "-o", executable.path] args.extend(gc_linkopts) args.append(archive.data.file.path) - bootstrap_action(ctx, go_toolchain, mode, + bootstrap_action(ctx, go_toolchain, archive.source.mode, inputs = inputs, outputs = [executable], mnemonic = "GoCompile", diff --git a/go/private/common.bzl b/go/private/common.bzl index 0e3329c2ed..25babb880f 100644 --- a/go/private/common.bzl +++ b/go/private/common.bzl @@ -107,10 +107,11 @@ def go_importpath(ctx): Returns: Go importpath of the library """ - path = ctx.attr.importpath + path = getattr(ctx.attr, "importpath", None) if path != "": return path - path = ctx.attr._go_prefix.go_prefix + prefix = getattr(ctx.attr, "_go_prefix", None) + path = prefix.go_prefix if prefix else "" if path.endswith("/"): path = path[:-1] if ctx.label.package: diff --git a/go/private/go_toolchain.bzl b/go/private/go_toolchain.bzl index 8cb786a6bd..0dfb55a1ff 100644 --- a/go/private/go_toolchain.bzl +++ b/go/private/go_toolchain.bzl @@ -19,7 +19,6 @@ load("@io_bazel_rules_go//go/private:actions/asm.bzl", "emit_asm") load("@io_bazel_rules_go//go/private:actions/binary.bzl", "emit_binary") load("@io_bazel_rules_go//go/private:actions/compile.bzl", "emit_compile", "bootstrap_compile") load("@io_bazel_rules_go//go/private:actions/cover.bzl", "emit_cover") -load("@io_bazel_rules_go//go/private:actions/library.bzl", "emit_library") load("@io_bazel_rules_go//go/private:actions/link.bzl", "emit_link", "bootstrap_link") load("@io_bazel_rules_go//go/private:actions/pack.bzl", "emit_pack") load("@io_bazel_rules_go//go/private:providers.bzl", "GoStdLib") @@ -58,7 +57,6 @@ def _go_toolchain_impl(ctx): binary = emit_binary, compile = emit_compile if ctx.executable._compile else bootstrap_compile, cover = emit_cover, - library = emit_library, link = emit_link if ctx.executable._link else bootstrap_link, pack = emit_pack, ), diff --git a/go/private/providers.bzl b/go/private/providers.bzl index bec509b8c6..15811ceb85 100644 --- a/go/private/providers.bzl +++ b/go/private/providers.bzl @@ -15,78 +15,35 @@ load("@io_bazel_rules_go//go/private:mode.bzl", "mode_string") GoLibrary = provider() -"""See go/providers.rst#GoLibrary for full documentation.""" - -GoPackage = provider() - -GoPath = provider() +""" +A represenatation of the inputs to a go package. +This is a configuration independent provider. +You must call resolve with a mode to produce a GoSource. +See go/providers.rst#GoLibrary for full documentation. +""" GoSource = provider() -"""See go/providers.rst#GoSource for full documentation.""" +""" +The filtered inputs and dependencies needed to build a GoArchive +This is a configuration specific provider. +It has no transitive information. +See go/providers.rst#GoSource for full documentation. +""" -GoSourceList = provider() -"""See go/providers.rst#GoSourceList for full documentation.""" +GoArchiveData = provider() +""" +This compiled form of a package used in transitive dependencies. +This is a configuration specific provider. +See go/providers.rst#GoArchiveData for full documentation. +""" GoArchive = provider() -"""See go/providers.rst#GoArchive for full documentation.""" - -GoArchiveData = provider() +""" +The compiled form of a GoLibrary, with everything needed to link it into a binary. +This is a configuration specific provider. +See go/providers.rst#GoArchive for full documentation. +""" +GoAspectProviders = provider() +GoPath = provider() GoStdLib = provider() - -def _merge_runfiles(a, b): - if not a: return b - if not b: return a - return a.merge(b) - -def _source_build_entry(srcs = [], deps = [], gc_goopts=[], runfiles=None, cgo_deps=[], cgo_exports=[], cgo_archive=None, want_coverage = False, source = None, exclude = None): - """Creates a new GoSource from a collection of values and an optional GoSourceList to merge in.""" - for e in (source.entries if source else []): - srcs = srcs + e.srcs - deps = deps + e.deps - gc_goopts = gc_goopts + e.gc_goopts - runfiles = _merge_runfiles(runfiles, e.runfiles) - cgo_deps = cgo_deps + e.cgo_deps - cgo_exports = cgo_exports + e.cgo_exports - if e.cgo_archive: - if cgo_archive: - fail("multiple libraries with cgo_archive embedded") - cgo_archive = e.cgo_archive - - return GoSource( - srcs = srcs, - deps = deps, - gc_goopts = gc_goopts, - runfiles = runfiles, - cgo_deps = cgo_deps, - cgo_exports = cgo_exports, - cgo_archive = cgo_archive, - want_coverage = want_coverage, - exclude = exclude, - ) - -def _source_new(**kwargs): - """Creates a new GoSourceList from a collection of values.""" - return GoSourceList(entries = [_source_build_entry(**kwargs)]) - -def _source_merge(source): - """Merges the entries of multiple GoSourceList providers to a single GoSourceList.""" - entries = [] - for e in source: - entries.extend(e.entries) - return GoSourceList(entries = entries) - -def _source_flatten(ctx, source): - """Flattens a GoSourceList to a single GoSource ready for use.""" - return _source_build_entry(source = source) - -def _source_filter(ctx, source, mode): - return GoSourceList(entries = [s for s in source.entries if not (s.exclude and s.exclude(ctx, mode))]) - -sources = struct( - new = _source_new, - merge = _source_merge, - flatten = _source_flatten, - filter = _source_filter, -) -"""sources holds the functions for manipulating GoSourceList providers.""" diff --git a/go/private/repositories.bzl b/go/private/repositories.bzl index 4781ae92c6..97eed9f4e0 100644 --- a/go/private/repositories.bzl +++ b/go/private/repositories.bzl @@ -76,7 +76,7 @@ def go_rules_dependencies(): name = "io_bazel_rules_go_repository_tools", ) - # Proto dependancies + # Proto dependencies _maybe(go_repository, name = "com_github_golang_protobuf", importpath = "github.com/golang/protobuf", @@ -97,7 +97,7 @@ def go_rules_dependencies(): strip_prefix = "protobuf-3.4.0", ) - # GRPC dependancies + # GRPC dependencies _maybe(go_repository, name = "org_golang_x_net", commit = "a04bdaca5b32abe1c069418fb7088ae607de5bd0", # master as of 2017-10-10 diff --git a/go/private/rules/aspect.bzl b/go/private/rules/aspect.bzl index 7d6ac26bca..21dfbd4d02 100644 --- a/go/private/rules/aspect.bzl +++ b/go/private/rules/aspect.bzl @@ -17,87 +17,57 @@ load("@io_bazel_rules_go//go/private:common.bzl", "to_set", "sets", ) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "library_to_source", + "new_aspect_provider", +) load("@io_bazel_rules_go//go/private:mode.bzl", - "get_mode", "mode_string", ) load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "GoSourceList", "GoArchive", "GoArchiveData", - "sources", + "GoSource", ) load("@io_bazel_rules_go//go/platform:list.bzl", "GOOS", "GOARCH", ) +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", +) -GoAspectProviders = provider() - -def get_archive(dep): - if GoAspectProviders in dep: - return dep[GoAspectProviders].archive - return dep[GoArchive] - -def get_source_list(dep): - if GoAspectProviders in dep: - return dep[GoAspectProviders].source - return dep[GoSourceList] - - -def collect_src(ctx, aspect=False, srcs = None, deps=None, want_coverage = None): - rule = ctx.rule if aspect else ctx - if srcs == None: - srcs = rule.files.srcs - if deps == None: - deps = rule.attr.deps - if want_coverage == None: - want_coverage = ctx.coverage_instrumented() and not rule.label.name.endswith("~library~") - return sources.merge([get_source_list(s) for s in rule.attr.embed] + [sources.new( - srcs = srcs, - deps = deps, - gc_goopts = rule.attr.gc_goopts, - runfiles = ctx.runfiles(collect_data = True), - want_coverage = want_coverage, - )]) def _go_archive_aspect_impl(target, ctx): mode = get_mode(ctx, ctx.rule.attr._go_toolchain_flags) - if GoArchive not in target: - if GoSourceList in target and hasattr(ctx.rule.attr, "embed"): - return [GoAspectProviders( - source = collect_src(ctx, aspect=True), - )] - return [] - goarchive = target[GoArchive] - if goarchive.mode == mode: - return [GoAspectProviders( - source = target[GoSourceList], - archive = goarchive, + source = target[GoSource] if GoSource in target else None + archive = target[GoArchive] if GoArchive in target else None + if source and source.mode == mode: + # The base layer already built the right mode for us + return [new_aspect_provider( + source = source, + archive = archive, )] - - source = collect_src(ctx, aspect=True) - for dep in ctx.rule.attr.deps: - a = get_archive(dep) - if a.mode != mode: fail("In aspect on {} found {} is {} expected {}".format(ctx.label, a.data.importpath, mode_string(a.mode), mode_string(mode))) - + if not GoLibrary in target: + # Not a rule we can do anything with + return [] + # We have a library and we need to compile it in a new mode + library = target[GoLibrary] + source = library_to_source(ctx, ctx.rule.attr, library, mode) go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"] - goarchive = go_toolchain.actions.archive(ctx, + archive = go_toolchain.actions.archive(ctx, go_toolchain = go_toolchain, - mode = mode, - importpath = target[GoLibrary].package.importpath, source = source, - importable = True, ) - return [GoAspectProviders( + return [new_aspect_provider( source = source, - archive = goarchive, + archive = archive, )] go_archive_aspect = aspect( _go_archive_aspect_impl, - attr_aspects = ["deps", "embed"], + attr_aspects = ["deps", "embed", "compiler"], attrs = { "pure": attr.string(values=["on", "off", "auto"]), "static": attr.string(values=["on", "off", "auto"]), diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl index 843f7ab4b6..d17f53807a 100644 --- a/go/private/rules/binary.bzl +++ b/go/private/rules/binary.bzl @@ -14,24 +14,27 @@ load("@io_bazel_rules_go//go/private:common.bzl", "go_filetype", - "go_importpath", ) load("@io_bazel_rules_go//go/private:rules/prefix.bzl", "go_prefix_default", ) load("@io_bazel_rules_go//go/private:rules/aspect.bzl", "go_archive_aspect", - "collect_src", ) load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "GoSourceList", - "sources", +) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", ) load("@io_bazel_rules_go//go/platform:list.bzl", "GOOS", "GOARCH", ) +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", +) def _go_binary_impl(ctx): """go_binary_impl emits actions for compiling and linking a go executable.""" @@ -39,22 +42,23 @@ def _go_binary_impl(ctx): go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"] else: go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:bootstrap_toolchain"] - gosource = collect_src(ctx) + mode = get_mode(ctx, ctx.attr._go_toolchain_flags) + library = new_go_library(ctx, importable=False) + source = library_to_source(ctx, ctx.attr, library, mode) name = ctx.attr.basename if not name: name = ctx.label.name - golib, goarchive, executable = go_toolchain.actions.binary(ctx, go_toolchain, + archive, executable = go_toolchain.actions.binary(ctx, go_toolchain, name = name, - importpath = go_importpath(ctx), - source = gosource, + source = source, gc_linkopts = gc_linkopts(ctx), x_defs = ctx.attr.x_defs, ) return [ - golib, gosource, goarchive, + library, source, archive, DefaultInfo( files = depset([executable]), - runfiles = goarchive.runfiles, + runfiles = archive.runfiles, executable = executable, ), ] @@ -70,7 +74,7 @@ go_binary = rule( "srcs": attr.label_list(allow_files = go_filetype), "deps": attr.label_list(providers = [GoLibrary], aspects = [go_archive_aspect]), "importpath": attr.string(), - "embed": attr.label_list(providers = [GoSourceList], aspects = [go_archive_aspect]), + "embed": attr.label_list(providers = [GoLibrary], aspects = [go_archive_aspect]), "pure": attr.string(values=["on", "off", "auto"], default="auto"), "static": attr.string(values=["on", "off", "auto"], default="auto"), "race": attr.string(values=["on", "off", "auto"], default="auto"), @@ -100,7 +104,7 @@ go_tool_binary = rule( "srcs": attr.label_list(allow_files = go_filetype), "deps": attr.label_list(providers = [GoLibrary]), "importpath": attr.string(), - "embed": attr.label_list(providers = [GoSourceList]), + "embed": attr.label_list(providers = [GoLibrary]), "gc_goopts": attr.string_list(), "gc_linkopts": attr.string_list(), "linkstamp": attr.string(), diff --git a/go/private/rules/cgo.bzl b/go/private/rules/cgo.bzl index 1d9d3ad7e0..b81213ec00 100644 --- a/go/private/rules/cgo.bzl +++ b/go/private/rules/cgo.bzl @@ -25,11 +25,14 @@ load("@io_bazel_rules_go//go/private:mode.bzl", ) load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "sources", ) load("@io_bazel_rules_go//go/private:actions/action.bzl", "add_go_env", ) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", +) _CgoCodegen = provider() @@ -224,29 +227,37 @@ def _pure(ctx, mode): def _not_pure(ctx, mode): return not mode.pure +def _cgo_library_to_source(ctx, attr, source): + library = source["library"] + if source["mode"].pure: + source["srcs"] = library.input_go_srcs + source["srcs"] + return + source["srcs"] = library.gen_go_srcs + source["srcs"] + source["cgo_deps"] = source["cgo_deps"] + library.cgo_deps + source["cgo_exports"] = source["cgo_exports"] + library.cgo_exports + source["cgo_archive"] = library.cgo_archive + source["runfiles"] = source["runfiles"].merge(attr.codegen.data_runfiles) + + def _cgo_collect_info_impl(ctx): codegen = ctx.attr.codegen[_CgoCodegen] runfiles = ctx.runfiles(collect_data = True) runfiles = runfiles.merge(ctx.attr.codegen.data_runfiles) + + library = new_go_library(ctx, + resolver=_cgo_library_to_source, + input_go_srcs = ctx.files.input_go_srcs, + gen_go_srcs = ctx.files.gen_go_srcs, + cgo_deps = ctx.attr.codegen[_CgoCodegen].deps, + cgo_exports = ctx.attr.codegen[_CgoCodegen].exports, + cgo_archive = _select_archive(ctx.files.lib), + ) + mode = get_mode(ctx, ctx.attr._go_toolchain_flags) + source = library_to_source(ctx, ctx.attr, library, mode) + return [ + source, library, DefaultInfo(files = depset(), runfiles = runfiles), - sources.merge([ - sources.new( - srcs = ctx.files.gen_go_srcs, - runfiles = runfiles, - cgo_deps = ctx.attr.codegen[_CgoCodegen].deps, - cgo_exports = ctx.attr.codegen[_CgoCodegen].exports, - cgo_archive = _select_archive(ctx.files.lib), - want_coverage = ctx.coverage_instrumented(), #TODO: not all sources? - exclude = _pure, - ), - sources.new( - srcs = ctx.files.input_go_srcs, - runfiles = runfiles, - want_coverage = ctx.coverage_instrumented(), #TODO: not all sources? - exclude = _not_pure, - ), - ]), ] _cgo_collect_info = rule( @@ -258,6 +269,7 @@ _cgo_collect_info = rule( "lib": attr.label(mandatory = True, providers = ["cc"]), "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")), }, + toolchains = ["@io_bazel_rules_go//go:toolchain"], ) """No-op rule that collects information from _cgo_codegen and cc_library info into a GoSourceList provider for easy consumption.""" diff --git a/go/private/rules/helpers.bzl b/go/private/rules/helpers.bzl new file mode 100644 index 0000000000..7ac54d948d --- /dev/null +++ b/go/private/rules/helpers.bzl @@ -0,0 +1,89 @@ +# Copyright 2017 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:common.bzl", + "go_importpath", + "sets", +) +load("@io_bazel_rules_go//go/private:providers.bzl", + "GoLibrary", + "GoSource", + "GoArchive", + "GoAspectProviders", +) + +def new_go_library(ctx, resolver=None, importable=True, **kwargs): + inferredpath = go_importpath(ctx) + return GoLibrary( + name = ctx.label.name, + label = ctx.label, + importpath = inferredpath if importable else None, # The canonical import path for this library + exportpath = inferredpath, # The export source path for this library + resolve = resolver, + **kwargs + ) + +def new_aspect_provider(source = None, archive = None): + return GoAspectProviders( + source = source, + archive = archive, + ) + +def get_source(dep): + if GoAspectProviders in dep: + return dep[GoAspectProviders].source + return dep[GoSource] + +def get_archive(dep): + if GoAspectProviders in dep: + return dep[GoAspectProviders].archive + return dep[GoArchive] + +def merge_embed(source, embed): + s = get_source(embed) + source["srcs"] = s.srcs + source["srcs"] + source["cover"] = source["cover"] + s.cover + source["deps"] = source["deps"] + s.deps + source["gc_goopts"] = source["gc_goopts"] + s.gc_goopts + source["runfiles"] = source["runfiles"].merge(s.runfiles) + source["cgo_deps"] = source["cgo_deps"] + s.cgo_deps + source["cgo_exports"] = source["cgo_exports"] + s.cgo_exports + if s.cgo_archive: + if source["cgo_archive"]: + fail("multiple libraries with cgo_archive embedded") + source["cgo_archive"] = s.cgo_archive + +def library_to_source(ctx, attr, library, mode): + attr_srcs = [f for t in getattr(attr, "srcs", []) for f in t.files] + generated_srcs = getattr(library, "srcs", []) + source = { + "library" : library, + "mode" : mode, + "srcs" : generated_srcs + attr_srcs, + "cover" : [], + "deps" : getattr(attr, "deps", []), + "gc_goopts" : getattr(attr, "gc_goopts", []), + "runfiles" : ctx.runfiles(collect_data = True), + "cgo_archive" : None, + "cgo_deps" : [], + "cgo_exports" : [], + } + if ctx.coverage_instrumented() and not attr.testonly: + source["cover"] = attr_srcs + for e in getattr(attr, "embed", []): + merge_embed(source, e) + if library.resolve: + library.resolve(ctx, attr, source) + return GoSource(**source) + diff --git a/go/private/rules/library.bzl b/go/private/rules/library.bzl index 842d081c10..e9656b9cc4 100644 --- a/go/private/rules/library.bzl +++ b/go/private/rules/library.bzl @@ -12,45 +12,35 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//go/private:common.bzl", - "go_importpath", -) -load("@io_bazel_rules_go//go/private:mode.bzl", - "get_mode", -) load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "GoSourceList", - "sources", +) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", ) load("@io_bazel_rules_go//go/private:rules/prefix.bzl", "go_prefix_default", ) -load("@io_bazel_rules_go//go/private:rules/aspect.bzl", - "collect_src", +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", ) def _go_library_impl(ctx): """Implements the go_library() rule.""" go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"] mode = get_mode(ctx, ctx.attr._go_toolchain_flags) - - gosource = collect_src(ctx) - golib, goarchive = go_toolchain.actions.library(ctx, - go_toolchain = go_toolchain, - mode = mode, - source = gosource, - importpath = go_importpath(ctx), - importable = True, - ) + library = new_go_library(ctx) + source = library_to_source(ctx, ctx.attr, library, mode) + archive = go_toolchain.actions.archive(ctx, go_toolchain, source) return [ - golib, gosource, goarchive, + library, source, archive, DefaultInfo( - files = depset([goarchive.data.file]), + files = depset([archive.data.file]), ), OutputGroupInfo( - cgo_exports = goarchive.cgo_exports, + cgo_exports = archive.cgo_exports, ), ] @@ -61,7 +51,7 @@ go_library = rule( "srcs": attr.label_list(allow_files = True), "deps": attr.label_list(providers = [GoLibrary]), "importpath": attr.string(), - "embed": attr.label_list(providers = [GoSourceList]), + "embed": attr.label_list(providers = [GoLibrary]), "gc_goopts": attr.string_list(), "_go_prefix": attr.label(default = go_prefix_default), "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")), diff --git a/go/private/rules/source.bzl b/go/private/rules/source.bzl index c825631df6..443560b079 100644 --- a/go/private/rules/source.bzl +++ b/go/private/rules/source.bzl @@ -22,15 +22,21 @@ load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "GoSourceList", ) -load("@io_bazel_rules_go//go/private:rules/aspect.bzl", - "collect_src", +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", +) +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", ) def _go_source_impl(ctx): """Implements the go_source() rule.""" - return [collect_src(ctx)] + mode = get_mode(ctx, ctx.attr._go_toolchain_flags) + library = new_go_library(ctx) + source = library_to_source(ctx, ctx.attr, library, mode) + return [library, source] go_source = rule( _go_source_impl, @@ -38,9 +44,10 @@ go_source = rule( "data": attr.label_list(allow_files = True, cfg = "data"), "srcs": attr.label_list(allow_files = True), "deps": attr.label_list(providers = [GoLibrary]), - "embed": attr.label_list(providers = [GoSourceList]), + "embed": attr.label_list(providers = [GoLibrary]), "gc_goopts": attr.string_list(), "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")), }, + toolchains = ["@io_bazel_rules_go//go:toolchain"], ) """See go/core.rst#go_source for full documentation.""" diff --git a/go/private/rules/test.bzl b/go/private/rules/test.bzl index da2075bf0c..1a4182585e 100644 --- a/go/private/rules/test.bzl +++ b/go/private/rules/test.bzl @@ -14,30 +14,35 @@ load("@io_bazel_rules_go//go/private:common.bzl", "go_filetype", - "go_importpath", "split_srcs", "pkg_dir", "declare_file", ) -load("@io_bazel_rules_go//go/private:mode.bzl", - "get_mode", -) load("@io_bazel_rules_go//go/private:rules/prefix.bzl", "go_prefix_default", ) load("@io_bazel_rules_go//go/private:rules/binary.bzl", "gc_linkopts") load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "sources", +) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "get_archive", + "new_go_library", + "library_to_source", ) load("@io_bazel_rules_go//go/private:actions/action.bzl", "add_go_env", ) load("@io_bazel_rules_go//go/private:rules/aspect.bzl", "go_archive_aspect", - "get_archive", +) +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", ) +def _testmain_library_to_source(ctx, attr, source): + source["deps"] = source["deps"] + [attr.library] + def _go_test_impl(ctx): """go_test_impl implements go testing. @@ -46,8 +51,8 @@ def _go_test_impl(ctx): go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"] mode = get_mode(ctx, ctx.attr._go_toolchain_flags) - stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, mode) archive = get_archive(ctx.attr.library) + stdlib = go_toolchain.stdlib.get(ctx, go_toolchain, archive.source.mode) # now generate the main function if ctx.attr.rundir: @@ -60,10 +65,10 @@ def _go_test_impl(ctx): main_go = declare_file(ctx, "testmain.go") arguments = ctx.actions.args() - add_go_env(arguments, stdlib, mode) + add_go_env(arguments, stdlib, archive.source.mode) arguments.add([ '--package', - archive.data.importpath, + archive.source.library.importpath, '--rundir', run_dir, '--output', @@ -71,9 +76,10 @@ def _go_test_impl(ctx): ]) for var in archive.cover_vars: arguments.add(["-cover", var]) - arguments.add(archive.go_srcs) + go_srcs = split_srcs(archive.source.srcs).go + arguments.add(go_srcs) ctx.actions.run( - inputs = archive.go_srcs, + inputs = go_srcs, outputs = [main_go], mnemonic = "GoTestGenTest", executable = go_toolchain.tools.test_generator, @@ -84,23 +90,22 @@ def _go_test_impl(ctx): ) # Now compile the test binary itself - _, goarchive, executable = go_toolchain.actions.binary(ctx, go_toolchain, + test_library = new_go_library(ctx, + resolver=_testmain_library_to_source, + srcs=[main_go], + importable=False, + ) + test_source = library_to_source(ctx, ctx.attr, test_library, mode) + test_archive, executable = go_toolchain.actions.binary(ctx, go_toolchain, name = ctx.label.name, - source = sources.new( - srcs = [main_go], - deps = [ctx.attr.library], - runfiles = ctx.runfiles(collect_data = True), - want_coverage = False, - ), - importpath = ctx.label.name + "~testmain~", + source = test_source, gc_linkopts = gc_linkopts(ctx), x_defs=ctx.attr.x_defs, ) - # TODO(bazel-team): the Go tests should do a chdir to the directory - # holding the data files, so open-source go tests continue to work - # without code changes. - runfiles = goarchive.runfiles.merge(ctx.runfiles(files = [executable])) + runfiles = ctx.runfiles(files = [executable]) + runfiles = runfiles.merge(archive.runfiles) + runfiles = runfiles.merge(test_archive.runfiles) return [ DefaultInfo( files = depset([executable]), diff --git a/go/private/tools/embed_data.bzl b/go/private/tools/embed_data.bzl index d2d79f2029..e1a542beb7 100644 --- a/go/private/tools/embed_data.bzl +++ b/go/private/tools/embed_data.bzl @@ -15,8 +15,12 @@ load("@io_bazel_rules_go//go/private:common.bzl", "declare_file", ) -load("@io_bazel_rules_go//go/private:providers.bzl", - "sources", +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", +) +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", ) def _go_embed_data_impl(ctx): @@ -53,6 +57,10 @@ def _go_embed_data_impl(ctx): args.add("-string") args.add(srcs) + mode = get_mode(ctx, ctx.attr._go_toolchain_flags) + library = new_go_library(ctx, srcs=srcs) + source = library_to_source(ctx, ctx.attr, library, mode) + ctx.actions.run( outputs = [out], inputs = srcs, @@ -62,7 +70,7 @@ def _go_embed_data_impl(ctx): ) return [ DefaultInfo(files = depset([out])), - sources.new(srcs = [out], want_coverage = False), + library, source, ] go_embed_data = rule( @@ -79,6 +87,8 @@ go_embed_data = rule( executable = True, cfg = "host", ), + "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")), }, + toolchains = ["@io_bazel_rules_go//go:toolchain"], ) """See go/extras.rst#go_embed_data for full documentation.""" diff --git a/go/private/tools/path.bzl b/go/private/tools/path.bzl index 4c8d1169ac..646e7b1ba2 100644 --- a/go/private/tools/path.bzl +++ b/go/private/tools/path.bzl @@ -14,10 +14,11 @@ load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", "GoPath") load("@io_bazel_rules_go//go/private:common.bzl", "declare_file") +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", "get_archive") def _tag(ctx, path, outputs): - """this generates a existance tag file for dependancies, and returns the path to the tag file""" + """this generates a existance tag file for dependencies, and returns the path to the tag file""" tag = declare_file(ctx, path=path+".tag") path, _, _ = tag.short_path.rpartition("/") ctx.actions.write(tag, content="") @@ -30,10 +31,11 @@ EXPERIMENTAL: the go_path rule is still very experimental Please do not rely on it for production use, but feel free to use it and file issues """) go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"] + #TODO: non specific mode? # First gather all the library rules golibs = depset() for dep in ctx.attr.deps: - golibs += dep[GoLibrary].transitive + golibs += get_archive(dep).transitive # Now scan them for sources seen_libs = {} @@ -41,7 +43,7 @@ Please do not rely on it for production use, but feel free to use it and file is outputs = [] packages = [] for golib in golibs: - if golib.importpath in seen_libs: + if golib.exportpath in seen_libs: # We found two different library rules that map to the same import path # This is legal in bazel, but we can't build a valid go path for it. # TODO: we might be able to ignore this if the content is identical @@ -49,13 +51,13 @@ Please do not rely on it for production use, but feel free to use it and file is Found {} in {} {} -""".format(golib.importpath, golib.name, seen_libs[golib.importpath].name)) +""".format(golib.exportpath, golib.label, seen_libs[golib.exportpath].label)) # for now we don't fail if we see duplicate packages # the most common case is the same source from two different workspaces continue - seen_libs[golib.importpath] = golib + seen_libs[golib.exportpath] = golib package_files = [] - prefix = "src/" + golib.importpath + "/" + prefix = "src/" + golib.exportpath + "/" for src in golib.srcs: outpath = prefix + src.basename if outpath in seen_paths: diff --git a/go/providers.rst b/go/providers.rst index 877f7993e2..db54628b0a 100644 --- a/go/providers.rst +++ b/go/providers.rst @@ -43,55 +43,15 @@ API GoLibrary ~~~~~~~~~ -This is the provider exposed by the go_library_ rule, or anything that wants to behave like one. -It provides all the information requried to use the library as a dependency, for other libraries, -binaries or tests. - -+--------------------------------+-----------------------------------------------------------------+ -| **Name** | **Type** | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`importpath` | :type:`string` | -+--------------------------------+-----------------------------------------------------------------+ -| The import path for this library. | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`direct` | :type:`depset(GoLibrary)` | -+--------------------------------+-----------------------------------------------------------------+ -| The direct depencancies of the library. | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`transitive` | :type:`depset(GoLibrary)` | -+--------------------------------+-----------------------------------------------------------------+ -| The full transitive set of Go libraries depended on. | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`srcs` | :type:`depset(File)` | -+--------------------------------+-----------------------------------------------------------------+ -| The original sources used to build the library. | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`cover_vars` | :type:`tuple(String)` | -+--------------------------------+-----------------------------------------------------------------+ -| The cover variables added to this library. | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`cgo_deps` | :type:`depset(cc_library)` | -+--------------------------------+-----------------------------------------------------------------+ -| The direct cgo dependencies of this library. | -| This has the same constraints as things that can appear in the deps of a cc_library_. | -+--------------------------------+-----------------------------------------------------------------+ -| :param:`runfiles` | runfiles_ | -+--------------------------------+-----------------------------------------------------------------+ -| The files needed to run anything that includes this library. | -+--------------------------------+-----------------------------------------------------------------+ - - -GoSourceList -~~~~~~~ - -GoSourceList is a provider designed to be used as the output of anything that provides Go code, and an -input to anything that compiles Go code. -It combines the source with dependencies that source will require. - -There are two main uses for this. +GoLibrary is the provider exposed by the go_library_ rule, or anything that wants to behave like one. +In general you should build these using the new_go_library helper function. +It provides all the information requried as inputs to building an archive. +It can also be used to just provide sources and deps (for use in the embed attribute). There are +two main uses for this. +This is a non build mode specific provider. #. Recompiling a library with additional sources. - go_library_ returns a GoSourceList provider with the transformed sources and deps that it was + go_library_ returns a GoLibrary provider with the original sources and deps that it was consuming. go_test_ uses this to recompile the library with additional test files, to build the test version of the library. You can use the same feature to recompile a proto library with @@ -102,52 +62,76 @@ There are two main uses for this. flatbuffers compiler to generate the serialization functions, you might hit the issue that the only thing that knows you depend on ``github.com/google/flatbuffers/go`` is the generated code. - You can instead have the generator return a GoSourceList provider instead of just the generated + You can instead have the generator return a GoLibrary provider instead of just the generated files, allowing you to tie the generated files to the additional dependencies they add to any package trying to compile them. + +--------------------------------+-----------------------------------------------------------------+ | **Name** | **Type** | +--------------------------------+-----------------------------------------------------------------+ -| :param:`entries` | :type:`list of GoSource` | +| :param:`name` | :type:`The package name for the sources.` | +--------------------------------+-----------------------------------------------------------------+ -| The full list of GoSource_ entries that this source set is composed of. | +| The direct depencancies of the library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`label` | :type:`The label of the rule that generated the library.` | ++--------------------------------+-----------------------------------------------------------------+ +| The direct depencancies of the library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`importpath` | :type:`string` | +--------------------------------+-----------------------------------------------------------------+ +| The import path for this library. May be None for things that cannot be imported. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`exportpath` | :type:`string` | ++--------------------------------+-----------------------------------------------------------------+ +| The source path for this library. May be None for things that should not be exported to a | +| GOPATH. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`resolve` | :type:`function` | ++--------------------------------+-----------------------------------------------------------------+ +| The function that can be called to resolve this library to a mode specific GoSource. | ++--------------------------------+-----------------------------------------------------------------+ + GoSource -~~~~~~~ +~~~~~~~~ -GoSource represents a single entry in a GoSourceList source provider. +GoSource represents a GoLibrary after mode specific processing, ready to build a GoArchive. +In general, only rules_go should need to build or handle these. +--------------------------------+-----------------------------------------------------------------+ | **Name** | **Type** | +--------------------------------+-----------------------------------------------------------------+ -| :param:`srcs` | :type:`depset(File)` | +| :param:`library` | :type:`GoLibrary` | +--------------------------------+-----------------------------------------------------------------+ -| The original sources for this library before transformations like cgo and coverage. | +| The go library that this GoSource was generated from. | +--------------------------------+-----------------------------------------------------------------+ -| :param:`deps` | :type:`depset(GoLibrary)` | +| :param:`srcs` | :type:`list of File` | ++--------------------------------+-----------------------------------------------------------------+ +| The sources to compile into the archive. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`cover` | :type:`list of File` | ++--------------------------------+-----------------------------------------------------------------+ +| The set of sources that should have coverage applied. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`deps` | :type:`list of GoLibrary` | +--------------------------------+-----------------------------------------------------------------+ | The direct dependencies needed by the :param:`srcs`. | +--------------------------------+-----------------------------------------------------------------+ -| :param:`gc_goopts` | :type:`tuple(string)` | +| :param:`gc_goopts` | :type:`list of string` | +--------------------------------+-----------------------------------------------------------------+ | Go compilation options that should be used when compiling these sources. | | In general these will be used for *all* sources of any library this provider is embedded into. | +--------------------------------+-----------------------------------------------------------------+ -| :param:`cover_vars` | :type:`string` | -+--------------------------------+-----------------------------------------------------------------+ -| The cover variables used in these sources. | -+--------------------------------+-----------------------------------------------------------------+ | :param:`runfiles` | :type:`Runfiles` | +--------------------------------+-----------------------------------------------------------------+ | The set of files needed by code in these sources at runtime. | +--------------------------------+-----------------------------------------------------------------+ -| :param:`cgo_deps` | :type:`depset(cc_library)` | +| :param:`cgo_deps` | :type:`list of cc_library` | +--------------------------------+-----------------------------------------------------------------+ | The direct cgo dependencies of this library. | +--------------------------------+-----------------------------------------------------------------+ -| :param:`cgo_exports` | :type:`depset(File)` | +| :param:`cgo_exports` | :type:`list of File` | +--------------------------------+-----------------------------------------------------------------+ | The exposed cc headers for these sources. | +--------------------------------+-----------------------------------------------------------------+ @@ -157,24 +141,93 @@ GoSource represents a single entry in a GoSourceList source provider. +--------------------------------+-----------------------------------------------------------------+ -GoArchive -~~~~~~~~~ +GoArchiveData +~~~~~~~~~~~~~ -GoArchive is a provider that exposes a compiled library. +GoArchiveData represents the compiled form of a package. +--------------------------------+-----------------------------------------------------------------+ | **Name** | **Type** | +--------------------------------+-----------------------------------------------------------------+ -| :param:`lib` | :type:`compiled archive file` | +| :param:`name` | :type:`The package name for the sources.` | ++--------------------------------+-----------------------------------------------------------------+ +| The direct depencancies of the library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`label` | :type:`The label of the rule that generated the library.` | ++--------------------------------+-----------------------------------------------------------------+ +| The direct depencancies of the library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`importpath` | :type:`string` | ++--------------------------------+-----------------------------------------------------------------+ +| The import path for this library. May be None for things that cannot be imported. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`exportpath` | :type:`string` | ++--------------------------------+-----------------------------------------------------------------+ +| The source path for this library. May be None for things that should not be exported to a | +| GOPATH. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`file` | :type:`compiled archive file` | +--------------------------------+-----------------------------------------------------------------+ | The archive file representing the library compiled in a specific :param:`mode` ready for linking | | into binaries. | +--------------------------------+-----------------------------------------------------------------+ +| :param:`srcs` | :type:`list of File` | ++--------------------------------+-----------------------------------------------------------------+ +| The sources compiled into the archive. | ++--------------------------------+-----------------------------------------------------------------+ | :param:`searchpath` | :type:`string` | +--------------------------------+-----------------------------------------------------------------+ | The search path entry under which the :param:`lib` would be found. | +--------------------------------+-----------------------------------------------------------------+ -| :param:`mode` | :type:`Mode` | + +GoArchive +~~~~~~~~~ + +GoArchive is a provider that exposes a compiled library along with it's full transitive +dependencies. +This is used when compiling and linking dependant libraries or binaries. + ++--------------------------------+-----------------------------------------------------------------+ +| **Name** | **Type** | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`source` | :type:`GoSource` | ++--------------------------------+-----------------------------------------------------------------+ +| The source provider this GoArchive was compiled from. | +--------------------------------+-----------------------------------------------------------------+ -| The mode the library was compiled in. | +| :param:`data` | :type:`GoArchiveData` | ++--------------------------------+-----------------------------------------------------------------+ +| The non transitive data for this archive. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`direct` | :type:`depset of GoLibrary` | ++--------------------------------+-----------------------------------------------------------------+ +| The direct depencancies of the library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`searchpaths` | :type:`depset of string` | ++--------------------------------+-----------------------------------------------------------------+ +| The transitive set of search paths needed to link with this archive. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`libs` | :type:`depset of File` | ++--------------------------------+-----------------------------------------------------------------+ +| The transitive set of libraries needed to link with this archive. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`transitive` | :type:`depset(GoLibrary)` | ++--------------------------------+-----------------------------------------------------------------+ +| The full transitive set of GoArchiveData's depended on, including this one. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`cgo_deps` | :type:`depset(cc_library)` | ++--------------------------------+-----------------------------------------------------------------+ +| The direct cgo dependencies of this library. | +| This has the same constraints as things that can appear in the deps of a cc_library_. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`cgo_exports` | :type:`depset of GoSource` | ++--------------------------------+-----------------------------------------------------------------+ +| The the transitive set of c headers needed to reference exports of this archive. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`cover_vars` | :type:`list of string` | ++--------------------------------+-----------------------------------------------------------------+ +| The cover variables added to this library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`runfiles` | runfiles_ | ++--------------------------------+-----------------------------------------------------------------+ +| The files needed to run anything that includes this library. | +--------------------------------+-----------------------------------------------------------------+ diff --git a/proto/compiler.bzl b/proto/compiler.bzl index 5d55123fb2..e0c2ea437b 100644 --- a/proto/compiler.bzl +++ b/proto/compiler.bzl @@ -19,6 +19,14 @@ load("@io_bazel_rules_go//go/private:common.bzl", load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", ) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", +) + +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", +) GoProtoCompiler = provider() @@ -75,15 +83,21 @@ def _proto_path(proto): def _go_proto_compiler_impl(ctx): - return [GoProtoCompiler( - deps = ctx.attr.deps, - compile = go_proto_compile, - options = ctx.attr.options, - suffix = ctx.attr.suffix, - go_protoc = ctx.file._go_protoc, - protoc = ctx.file._protoc, - plugin = ctx.file.plugin, - )] + mode = get_mode(ctx, ctx.attr._go_toolchain_flags) + library = new_go_library(ctx) + source = library_to_source(ctx, ctx.attr, library, mode) + return [ + GoProtoCompiler( + deps = ctx.attr.deps, + compile = go_proto_compile, + options = ctx.attr.options, + suffix = ctx.attr.suffix, + go_protoc = ctx.file._go_protoc, + protoc = ctx.file._protoc, + plugin = ctx.file.plugin, + ), + library, source, + ] go_proto_compiler = rule( _go_proto_compiler_impl, @@ -112,5 +126,9 @@ go_proto_compiler = rule( cfg = "host", default = Label("@com_github_google_protobuf//:protoc"), ), - } + "_go_toolchain_flags": attr.label(default=Label("@io_bazel_rules_go//go/private:go_toolchain_flags")), + }, + toolchains = [ + "@io_bazel_rules_go//go:toolchain", + ], ) diff --git a/proto/def.bzl b/proto/def.bzl index 20300164ca..7f8ae10459 100644 --- a/proto/def.bzl +++ b/proto/def.bzl @@ -1,23 +1,39 @@ +# Copyright 2017 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:common.bzl", "go_importpath", "sets", ) load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", - "GoSourceList", +) +load("@io_bazel_rules_go//go/private:rules/helpers.bzl", + "new_go_library", + "library_to_source", + "get_source", + "merge_embed", ) load("@io_bazel_rules_go//go/private:rules/prefix.bzl", "go_prefix_default", ) -load("@io_bazel_rules_go//go/private:mode.bzl", - "get_mode", -) -load("@io_bazel_rules_go//go/private:rules/aspect.bzl", - "collect_src", -) load("@io_bazel_rules_go//proto:compiler.bzl", "GoProtoCompiler", ) +load("@io_bazel_rules_go//go/private:mode.bzl", + "get_mode", +) GoProtoImports = provider() @@ -37,7 +53,12 @@ _go_proto_aspect = aspect( attr_aspects = ["deps", "embed"], ) +def _proto_library_to_source(ctx, attr, source): + compiler = attr.compiler[GoProtoCompiler] + merge_embed(source, attr.compiler) + def _go_proto_library_impl(ctx): + mode = get_mode(ctx, ctx.attr._go_toolchain_flags) compiler = ctx.attr.compiler[GoProtoCompiler] importpath = go_importpath(ctx) go_srcs = compiler.compile(ctx, @@ -47,23 +68,18 @@ def _go_proto_library_impl(ctx): importpath = importpath, ) go_toolchain = ctx.toolchains["@io_bazel_rules_go//go:toolchain"] - mode = get_mode(ctx, ctx.attr._go_toolchain_flags) - gosource = collect_src( - ctx, srcs = go_srcs, - deps = ctx.attr.deps + compiler.deps, - ) - golib, goarchive = go_toolchain.actions.library(ctx, - go_toolchain = go_toolchain, - mode = mode, - source = gosource, - importpath = importpath, - importable = True, + library = new_go_library(ctx, + resolver=_proto_library_to_source, + srcs=go_srcs, ) + source = library_to_source(ctx, ctx.attr, library, mode) + archive = go_toolchain.actions.archive(ctx, go_toolchain, source) + return [ - golib, gosource, goarchive, + library, source, archive, DefaultInfo( - files = depset([goarchive.data.file]), - runfiles = goarchive.runfiles, + files = depset([archive.data.file]), + runfiles = archive.runfiles, ), ] @@ -73,7 +89,7 @@ go_proto_library = rule( "proto": attr.label(mandatory=True, providers=["proto"]), "deps": attr.label_list(providers = [GoLibrary], aspects = [_go_proto_aspect]), "importpath": attr.string(), - "embed": attr.label_list(providers = [GoSourceList]), + "embed": attr.label_list(providers = [GoLibrary]), "gc_goopts": attr.string_list(), "compiler": attr.label(providers = [GoProtoCompiler], default = "@io_bazel_rules_go//proto:go_proto"), "_go_prefix": attr.label(default = go_prefix_default),