diff --git a/go/private/compat/compat_repo.bzl b/go/private/compat/compat_repo.bzl new file mode 100644 index 0000000000..0afe2866b0 --- /dev/null +++ b/go/private/compat/compat_repo.bzl @@ -0,0 +1,47 @@ +# Copyright 2019 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. + +# This file provides an abstraction over parts of the Bazel API. It is +# intended to be stable across Bazel's breaking API changes so that rules_go +# can support a wider range of Bazel versions. +# +# The compatibility layer is implemented with a repository rule used to provide +# @io_bazel_rules_go_compat, which is declared by go_rules_dependencies. +# The repository has one file, compat.bzl, which is a symbolic link +# to a file in this directory. The destination of the symbolic link is +# determined by the current Bazel version. Each version of compat.bzl contains +# the same definitions but with different implementations. The version names +# like v18.bzl indicate the minimum version of Bazel for that file. + +load("@io_bazel_rules_go//go/private:skylib/lib/versions.bzl", "versions") + +def _go_rules_compat_impl(ctx): + ctx.file("BUILD.bazel") + ctx.symlink(ctx.attr.impl, "compat.bzl") + +_go_rules_compat = repository_rule( + implementation = _go_rules_compat_impl, + attrs = { + "impl": attr.label(), + }, +) + +def go_rules_compat(**kwargs): + v = native.bazel_version + if versions.is_at_most("0.21.0", v): + stem = "v18" + else: + stem = "v22" + impl = "@io_bazel_rules_go//go/private:compat/{}.bzl".format(stem) + _go_rules_compat(impl = impl, **kwargs) diff --git a/go/private/compat/v18.bzl b/go/private/compat/v18.bzl new file mode 100644 index 0000000000..ac3a157260 --- /dev/null +++ b/go/private/compat/v18.bzl @@ -0,0 +1,80 @@ +# Copyright 2019 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. + +# Compatibility for --incompatible_disable_legacy_cc_provider + +CC_PROVIDER_NAME = "cc" + +def has_cc(target): + return hasattr(target, "cc") + +def cc_transitive_headers(target): + return target.cc.transitive_headers + +def cc_defines(target): + return target.cc.defines + +def cc_system_includes(target): + return target.cc.system_include_directories + +def cc_includes(target): + return target.cc.include_directories + +def cc_quote_includes(target): + return target.cc.quote_include_directories + +def cc_link_flags(target): + return target.cc.link_flags + +def cc_libs(target): + return target.cc.libs + +def cc_compile_flags(target): + return target.cc.compile_flags + +# Compatibility for --incompatible_disable_legacy_proto_provider + +PROTO_PROVIDER_NAME = "proto" + +def has_proto(target): + return hasattr(target, "proto") + +def get_proto(target): + return target.proto + +def proto_check_deps_sources(target): + return target.proto.check_deps_sources + +def proto_direct_descriptor_set(target): + return target.proto.direct_descriptor_set + +def proto_direct_sources(target): + return target.proto.direct_sources + +def proto_source_root(target): + # proto_source_root was added in Bazel 0.21.0. + # Existing code paths check for it. + return getattr(target.proto, "proto_source_root", None) + +def proto_transitive_descriptor_sets(target): + return target.proto.transitive_descriptor_sets + +def proto_transitive_imports(target): + return target.proto.transitive_imports + +def proto_transitive_proto_path(target): + return target.proto.transitive_proto_path + +def proto_transitive_sources(target): + return target.proto.transitive_sources diff --git a/go/private/compat/v22.bzl b/go/private/compat/v22.bzl new file mode 100644 index 0000000000..8a71d963d0 --- /dev/null +++ b/go/private/compat/v22.bzl @@ -0,0 +1,113 @@ +# Copyright 2019 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. + +# Compatibility for --incompatible_disable_legacy_cc_provider + +CC_PROVIDER_NAME = CcInfo + +def has_cc(target): + return CcInfo in target + +def cc_transitive_headers(target): + return target[CcInfo].compilation_context.headers + +def cc_defines(target): + return target[CcInfo].compilation_context.defines.to_list() + +def cc_system_includes(target): + return target[CcInfo].compilation_context.system_includes.to_list() + +def cc_includes(target): + return target[CcInfo].compilation_context.includes.to_list() + +def cc_quote_includes(target): + return target[CcInfo].compilation_context.quote_includes.to_list() + +def cc_link_flags(target): + return target[CcInfo].linking_context.user_link_flags + +def cc_libs(target): + # Copied from get_libs_for_static_executable in migration instructions + # from bazelbuild/bazel#7036. + libraries_to_link = target[CcInfo].linking_context.libraries_to_link + libs = [] + for library_to_link in libraries_to_link: + if library_to_link.static_library != None: + libs.append(library_to_link.static_library) + elif library_to_link.pic_static_library != None: + libs.append(library_to_link.pic_static_library) + elif library_to_link.interface_library != None: + libs.append(library_to_link.interface_library) + elif library_to_link.dynamic_library != None: + libs.append(library_to_link.dynamic_library) + return libs + +def cc_compile_flags(target): + # Copied from get_compile_flags in migration instructions from + # bazelbuild/bazel#7036. + options = [] + compilation_context = target[CcInfo].compilation_context + for define in compilation_context.defines.to_list(): + options.append("-D{}".format(define)) + + for system_include in compilation_context.system_includes.to_list(): + if len(system_include) == 0: + system_include = "." + options.append("-isystem {}".format(system_include)) + + for include in compilation_context.includes.to_list(): + if len(include) == 0: + include = "." + options.append("-I {}".format(include)) + + for quote_include in compilation_context.quote_includes.to_list(): + if len(quote_include) == 0: + quote_include = "." + options.append("-iquote {}".format(quote_include)) + + return options + +# Compatibility for --incompatible_disable_legacy_proto_provider + +PROTO_PROVIDER_NAME = ProtoInfo + +def has_proto(target): + return ProtoInfo in target + +def get_proto(target): + return target[ProtoInfo] + +def proto_check_deps_sources(target): + return target[ProtoInfo].check_deps_sources + +def proto_direct_descriptor_set(target): + return target[ProtoInfo].direct_descriptor_set + +def proto_direct_sources(target): + return target[ProtoInfo].direct_sources + +def proto_source_root(target): + return target[ProtoInfo].proto_source_root + +def proto_transitive_descriptor_sets(target): + return target[ProtoInfo].transitive_descriptor_sets + +def proto_transitive_imports(target): + return target[ProtoInfo].transitive_imports + +def proto_transitive_proto_path(target): + return target[ProtoInfo].transitive_proto_path + +def proto_transitive_sources(target): + return target[ProtoInfo].transitive_sources diff --git a/go/private/repositories.bzl b/go/private/repositories.bzl index 2c8a3c73c5..5c1782da39 100644 --- a/go/private/repositories.bzl +++ b/go/private/repositories.bzl @@ -15,6 +15,7 @@ # Once nested repositories work, this file should cease to exist. load("@io_bazel_rules_go//go/private:common.bzl", "MINIMUM_BAZEL_VERSION") +load("@io_bazel_rules_go//go/private:compat/compat_repo.bzl", "go_rules_compat") load("@io_bazel_rules_go//go/private:skylib/lib/versions.bzl", "versions") load("@io_bazel_rules_go//go/private:nogo.bzl", "DEFAULT_NOGO", "go_register_nogo") load("@io_bazel_rules_go//go/platform:list.bzl", "GOOS_GOARCH") @@ -27,8 +28,13 @@ def go_rules_dependencies(): if getattr(native, "bazel_version", None): versions.check(MINIMUM_BAZEL_VERSION, bazel_version = native.bazel_version) - # Was needed by Gazelle in the past. Will likely be needed for go/packages - # and analysis in the future. + # Compatibility layer, needed to support older versions of Bazel. + _maybe( + go_rules_compat, + name = "io_bazel_rules_go_compat", + ) + + # Needed for nogo vet checks and go/packages. _maybe( http_archive, name = "org_golang_x_tools", diff --git a/go/private/rules/cgo.bzl b/go/private/rules/cgo.bzl index 20faf29190..a504e3c450 100644 --- a/go/private/rules/cgo.bzl +++ b/go/private/rules/cgo.bzl @@ -54,6 +54,19 @@ load( "MSAN_GOOS_GOARCH", "RACE_GOOS_GOARCH", ) +load( + "@io_bazel_rules_go_compat//:compat.bzl", + "CC_PROVIDER_NAME", + "cc_compile_flags", + "cc_defines", + "cc_includes", + "cc_libs", + "cc_link_flags", + "cc_quote_includes", + "cc_system_includes", + "cc_transitive_headers", + "has_cc", +) _CgoCodegen = provider() _CgoInfo = provider() @@ -218,17 +231,17 @@ def _cgo_codegen_impl(ctx): runfiles = ctx.runfiles(collect_data = True) for d in ctx.attr.deps: runfiles = runfiles.merge(d.data_runfiles) - if hasattr(d, "cc"): - inputs = sets.union(inputs, d.cc.transitive_headers) - deps = sets.union(deps, d.cc.libs) - cppopts.extend(["-D" + define for define in d.cc.defines]) - for inc in d.cc.include_directories: + if has_cc(d): + inputs = sets.union(inputs, cc_transitive_headers(d)) + deps = sets.union(deps, cc_libs(d)) + cppopts.extend(["-D" + define for define in cc_defines(d)]) + for inc in cc_includes(d): _include_unique(cppopts, "-I", inc, seen_includes) - for inc in d.cc.quote_include_directories: + for inc in cc_quote_includes(d): _include_unique(cppopts, "-iquote", inc, seen_quote_includes) - for inc in d.cc.system_include_directories: + for inc in cc_system_includes(d): _include_unique(cppopts, "-isystem", inc, seen_system_includes) - for lib in as_iterable(d.cc.libs): + for lib in cc_libs(d): # If both static and dynamic variants are available, Bazel will only give # us the static variant. We'll get one file for each transitive dependency, # so the same file may appear more than once. @@ -243,7 +256,7 @@ def _cgo_codegen_impl(ctx): linkopts.extend(["-L", lib.dirname, "-l", libname]) else: linkopts.append(lib.path) - linkopts.extend(d.cc.link_flags) + linkopts.extend(cc_link_flags(d)) elif hasattr(d, "objc"): cppopts.extend(["-D" + define for define in d.objc.define.to_list()]) for inc in d.objc.include.to_list(): @@ -437,7 +450,7 @@ _cgo_collect_info = go_rule( "libs": attr.label_list( mandatory = True, allow_files = True, - providers = ["cc"], + providers = [CC_PROVIDER_NAME], ), "cgo_import": attr.label(mandatory = True), }, diff --git a/proto/def.bzl b/proto/def.bzl index 9ee5177a78..55b282031e 100644 --- a/proto/def.bzl +++ b/proto/def.bzl @@ -34,23 +34,30 @@ load( "@io_bazel_rules_go//go/private:providers.bzl", "INFERRED_PATH", ) +load( + "@io_bazel_rules_go_compat//:compat.bzl", + "PROTO_PROVIDER_NAME", + "get_proto", + "has_proto", + "proto_check_deps_sources", +) GoProtoImports = provider() def get_imports(attr): - protos = [] + proto_deps = [] - if hasattr(attr, "proto") and hasattr(attr.proto, "proto"): - protos = [attr.proto.proto] + if hasattr(attr, "proto") and attr.proto and has_proto(attr.proto): + proto_deps = [attr.proto] elif hasattr(attr, "protos"): - for proto in attr.protos: - if hasattr(proto, "proto"): - protos.append(proto.proto) + proto_deps = [d for d in attr.protos if has_proto(d)] + else: + proto_deps = [] direct = dict() - for proto in protos: - for src in proto.check_deps_sources.to_list(): - direct["{}={}".format(proto_path(src, proto), attr.importpath)] = True + for dep in proto_deps: + for src in proto_check_deps_sources(dep).to_list(): + direct["{}={}".format(proto_path(src, dep), attr.importpath)] = True deps = getattr(attr, "deps", []) + getattr(attr, "embed", []) transitive = [ @@ -93,11 +100,11 @@ def _go_proto_library_impl(ctx): #TODO: print("DEPRECATED: proto attribute on {}, use protos instead".format(ctx.label)) if ctx.attr.protos: fail("Either proto or protos (non-empty) argument must be specified, but not both") - protos = [ctx.attr.proto] + proto_deps = [ctx.attr.proto] else: if not ctx.attr.protos: fail("Either proto or protos (non-empty) argument must be specified") - protos = ctx.attr.protos + proto_deps = ctx.attr.protos go_srcs = [] valid_archive = False @@ -109,7 +116,7 @@ def _go_proto_library_impl(ctx): go_srcs.extend(compiler.compile( go, compiler = compiler, - protos = [proto.proto for proto in protos], + protos = [get_proto(d) for d in proto_deps], imports = get_imports(ctx.attr), importpath = go.importpath, )) @@ -138,9 +145,9 @@ def _go_proto_library_impl(ctx): go_proto_library = go_rule( _go_proto_library_impl, attrs = { - "proto": attr.label(providers = ["proto"]), + "proto": attr.label(providers = [PROTO_PROVIDER_NAME]), "protos": attr.label_list( - providers = ["proto"], + providers = [PROTO_PROVIDER_NAME], default = [], ), "deps": attr.label_list(