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),