Skip to content

Commit

Permalink
Add compatibility repository for supporting older Bazel versions (#1933)
Browse files Browse the repository at this point in the history
io_bazel_rules_go_compat is a new repository, which contains
compat.bzl, a symbolic link to a file in go/private/compat. There are
multiple versions that compat.bzl may point to (v18.bzl, v22.bzl
initially). These files provide the same definitions with different
implementations.

Initially, this provides abstraction for accessing cc and proto
providers, which are changing in Bazel 0.23.

Fixes #1888
  • Loading branch information
jayconrod authored Feb 3, 2019
1 parent 4a01b5a commit 8670623
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 26 deletions.
47 changes: 47 additions & 0 deletions go/private/compat/compat_repo.bzl
Original file line number Diff line number Diff line change
@@ -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)
80 changes: 80 additions & 0 deletions go/private/compat/v18.bzl
Original file line number Diff line number Diff line change
@@ -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
113 changes: 113 additions & 0 deletions go/private/compat/v22.bzl
Original file line number Diff line number Diff line change
@@ -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
10 changes: 8 additions & 2 deletions go/private/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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",
Expand Down
33 changes: 23 additions & 10 deletions go/private/rules/cgo.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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.
Expand All @@ -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():
Expand Down Expand Up @@ -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),
},
Expand Down
Loading

0 comments on commit 8670623

Please sign in to comment.