chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You 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 BUILD file marks bazel/tools/ as a Bazel package so that loads
|
||||
# of the form `//bazel/tools:xxx.bzl` are valid. The directory only
|
||||
# hosts .bzl files (brpc_proto_library.bzl / proto_gen.bzl) and does
|
||||
# not define any build targets.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
exports_files(glob(["*.bzl"]))
|
||||
@@ -0,0 +1,138 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You 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.
|
||||
#
|
||||
# brpc_proto_library: a proto -> cc_library macro that is robust against
|
||||
# protobuf and Bazel version churn.
|
||||
#
|
||||
# Background:
|
||||
# - Old protobuf (< 3.21) used to expose a `cc_proto_library` macro
|
||||
# via `@com_google_protobuf//:protobuf.bzl`; newer protobuf removed
|
||||
# that macro.
|
||||
# - Newer protobuf expects callers to use Bazel's native
|
||||
# `proto_library` / `cc_proto_library` (or the `cc_proto_library`
|
||||
# re-exported from `@com_google_protobuf//bazel:cc_proto_library.bzl`),
|
||||
# but older protobuf does not surface a complete `ProtoInfo`, so
|
||||
# the native rules cannot build it.
|
||||
# - Bazel 8 additionally removed `cc_proto_library` from
|
||||
# `@rules_cc//cc:defs.bzl` (the load now resolves to a stub rule
|
||||
# that fails analysis), forcing every caller to either load it
|
||||
# from `@com_google_protobuf` or replace it.
|
||||
# - Bazel's `load()` is static and cannot be conditional on the
|
||||
# protobuf version, so a single brpc_proto_library.bzl cannot
|
||||
# directly satisfy both old and new protobuf by switching imports.
|
||||
#
|
||||
# Solution (inspired by https://github.com/trpc-group/trpc-cpp/blob/a69d2950f4a9c16b3cb40a2750c69d8940c96820/trpc/trpc.bzl):
|
||||
# We implement the proto compilation rule from scratch (see
|
||||
# proto_gen.bzl in this directory). Dependency information is
|
||||
# propagated through Bazel's native `ProtoInfo` provider, and the
|
||||
# default well-known-proto source is
|
||||
# `@com_google_protobuf//:descriptor_proto` -- a `proto_library`
|
||||
# whose name has been stable across protobuf 3.x / 27.x / 34.x.
|
||||
load("//bazel/tools:proto_gen.bzl", "brpc_proto_gen")
|
||||
|
||||
# `:descriptor_proto` is the protobuf repo's `proto_library` target;
|
||||
# its label has been stable since protobuf 3.x. We consume it through
|
||||
# Bazel's native `ProtoInfo` provider, which is uniform across PB
|
||||
# versions. If a caller's .proto needs additional well-known protos
|
||||
# (any.proto, timestamp.proto, ...), they can pass extra entries via
|
||||
# the `proto_deps` argument.
|
||||
_DEFAULT_PROTO_DEPS = ["@com_google_protobuf//:descriptor_proto"]
|
||||
|
||||
def brpc_proto_library(
|
||||
name,
|
||||
srcs,
|
||||
deps = [],
|
||||
include = None,
|
||||
proto_deps = None,
|
||||
visibility = None,
|
||||
testonly = 0):
|
||||
"""Generate a cc_library from a set of .proto files.
|
||||
|
||||
Args:
|
||||
name: target name.
|
||||
srcs: list of .proto files, paths relative to the current package.
|
||||
deps: list of other `brpc_proto_library` targets this target
|
||||
depends on. The macro internally translates these labels
|
||||
to the underlying `<name>_genproto` rule so that .proto
|
||||
include paths and sources propagate.
|
||||
include: protoc `-I` root AND the resulting cc_library `includes`
|
||||
root, relative to the current package.
|
||||
When omitted, "" or None, the include root is the
|
||||
current package itself (suitable for .proto files
|
||||
sitting directly under the package root, as in `test/`
|
||||
and `example/...`). The root `BUILD.bazel` of brpc must
|
||||
pass `"src"` so that code can reference the protos as
|
||||
`import "brpc/foo.proto"`.
|
||||
proto_deps: list of native `proto_library` dependencies
|
||||
(well-known protos or external .proto libraries).
|
||||
Defaults to
|
||||
`["@com_google_protobuf//:descriptor_proto"]`.
|
||||
Pass `[]` explicitly to disable the default; pass
|
||||
None (the default) to use it.
|
||||
visibility: same semantics as cc_library.
|
||||
testonly: same semantics as cc_library.
|
||||
"""
|
||||
|
||||
real_include = include if include != None else ""
|
||||
real_proto_deps = proto_deps if proto_deps != None else _DEFAULT_PROTO_DEPS
|
||||
|
||||
gen_name = name + "_genproto"
|
||||
brpc_proto_gen(
|
||||
name = gen_name,
|
||||
srcs = srcs,
|
||||
# Rewrite each `brpc_proto_library` dep to its underlying
|
||||
# `<dep>_genproto` rule, which exports BrpcProtoInfo.
|
||||
deps = [d + "_genproto" for d in deps],
|
||||
include = real_include,
|
||||
proto_deps = real_proto_deps,
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
)
|
||||
|
||||
# Split the generated files into .pb.h / .pb.cc via OutputGroupInfo
|
||||
# and feed them to cc_library's hdrs / srcs separately. Bazel
|
||||
# rejects declaring the same File in both hdrs and srcs, so a
|
||||
# plain DefaultInfo wouldn't work here.
|
||||
native.filegroup(
|
||||
name = gen_name + "_hdrs",
|
||||
srcs = [":" + gen_name],
|
||||
output_group = "hdrs",
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
)
|
||||
native.filegroup(
|
||||
name = gen_name + "_srcs",
|
||||
srcs = [":" + gen_name],
|
||||
output_group = "srcs",
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
)
|
||||
|
||||
native.cc_library(
|
||||
name = name,
|
||||
srcs = [":" + gen_name + "_srcs"],
|
||||
hdrs = [":" + gen_name + "_hdrs"],
|
||||
# cc_library `includes` is required, otherwise the .pb.cc
|
||||
# files inside this cc_library cannot find the .pb.h headers
|
||||
# they just generated (the headers live under
|
||||
# bazel-bin/<package>/<include>/...). When include="" we pass
|
||||
# "." to mean "the current package itself"; Bazel then exposes
|
||||
# both `-I <package>` and `-I bazel-bin/<package>`
|
||||
# automatically to dependents.
|
||||
includes = [real_include if real_include else "."],
|
||||
deps = deps + ["@com_google_protobuf//:protobuf"],
|
||||
visibility = visibility,
|
||||
testonly = testonly,
|
||||
)
|
||||
@@ -0,0 +1,240 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You 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.
|
||||
#
|
||||
# brpc's self-implemented proto -> .pb.{h,cc} compilation rule.
|
||||
#
|
||||
# Cross-protobuf-version compatibility strategy (inspired by trpc.bzl):
|
||||
# 1) Do NOT load `@com_google_protobuf//:protobuf.bzl` and do NOT
|
||||
# call `native.cc_proto_library` -- this side-steps the double
|
||||
# incompatibility of newer protobuf removing the macro and older
|
||||
# protobuf missing a complete `ProtoInfo` provider.
|
||||
# 2) Do NOT hardcode any protobuf-repo-internal filegroup names
|
||||
# (such as `well_known_protos` / `descriptor_proto_srcs`) -- the
|
||||
# names of those filegroups have shifted between protobuf 3.x
|
||||
# and 27.x+.
|
||||
# 3) Propagate dependencies via Bazel's native `ProtoInfo` provider:
|
||||
# callers pass `proto_library` targets through `proto_deps`
|
||||
# (defaulting to `@com_google_protobuf//:descriptor_proto`, a
|
||||
# `proto_library` whose label has been stable across PB versions),
|
||||
# and this rule walks `transitive_sources` / `transitive_proto_path`
|
||||
# to collect .proto source files and protoc `-I` paths -- fully
|
||||
# decoupled from the PB version.
|
||||
# 4) Among `brpc_proto_gen` targets themselves, dependencies are
|
||||
# propagated via the custom `BrpcProtoInfo` provider declared
|
||||
# below.
|
||||
#
|
||||
# Note on minimum Bazel version: this rule itself does not call any
|
||||
# Bazel-version-specific API, but it still consumes `ProtoInfo` from
|
||||
# `proto_library` targets (e.g. `descriptor_proto`) defined inside
|
||||
# the protobuf repo. Protobuf >= 34 calls
|
||||
# `ProtoInfo(option_deps = ..., extension_declarations = ...)` in its
|
||||
# own `proto_library` implementation, and those fields are only
|
||||
# accepted by Bazel >= 8. In other words, the minimum Bazel version
|
||||
# brpc requires is whatever the bundled protobuf version requires --
|
||||
# we just don't add any extra requirement on top of that.
|
||||
|
||||
BrpcProtoInfo = provider(
|
||||
doc = "Carries transitive .proto sources and protoc -I flags between brpc_proto_gen targets.",
|
||||
fields = {
|
||||
"transitive_srcs": "depset of all transitive .proto Files.",
|
||||
"transitive_imports": "depset of strings, all -I flags needed by protoc.",
|
||||
},
|
||||
)
|
||||
|
||||
def _resolve_include_dir(ctx):
|
||||
"""Compute this target's protoc include root (workspace-relative).
|
||||
|
||||
Examples:
|
||||
ctx.label.package = "" + include = "src" -> "src"
|
||||
ctx.label.package = "test" + include = "" -> "test"
|
||||
ctx.label.package = "" + include = "" -> "."
|
||||
"""
|
||||
pkg = ctx.label.package
|
||||
inc = ctx.attr.include.rstrip("/")
|
||||
if pkg and inc:
|
||||
return pkg + "/" + inc
|
||||
if pkg:
|
||||
return pkg
|
||||
if inc:
|
||||
return inc
|
||||
return "."
|
||||
|
||||
def _proto_gen_impl(ctx):
|
||||
srcs = ctx.files.srcs
|
||||
include_dir = _resolve_include_dir(ctx)
|
||||
bin_root = ctx.bin_dir.path
|
||||
|
||||
# `-I` flags for this target itself: the source-tree root plus
|
||||
# the corresponding bin-dir root. The bin-dir entry is needed
|
||||
# when a transitive dep generates .proto files into bazel-bin
|
||||
# (e.g. via a custom code generator).
|
||||
own_imports = ["-I" + include_dir]
|
||||
if include_dir == ".":
|
||||
own_imports.append("-I" + bin_root)
|
||||
else:
|
||||
own_imports.append("-I" + bin_root + "/" + include_dir)
|
||||
|
||||
# Collect transitive info from other `brpc_proto_gen` deps.
|
||||
dep_srcs_list = [d[BrpcProtoInfo].transitive_srcs for d in ctx.attr.deps]
|
||||
dep_imports_list = [d[BrpcProtoInfo].transitive_imports for d in ctx.attr.deps]
|
||||
|
||||
# Collect native `proto_library` deps (well-known protos or
|
||||
# external .proto libraries). Key design: .proto sources and
|
||||
# `-I` paths are obtained via Bazel's native `ProtoInfo`,
|
||||
# avoiding any reliance on protobuf-repo-internal filegroup
|
||||
# names (descriptor_proto_srcs / well_known_protos / ...).
|
||||
# `transitive_proto_path` already accounts for the
|
||||
# `_virtual_imports` paths created by `strip_import_prefix`, so
|
||||
# protoc can consume the paths directly.
|
||||
#
|
||||
# Important: `strip_import_prefix` causes .proto files to live at
|
||||
# virtual paths under bazel-out/<config>/bin/<workspace_root>/<virtual>
|
||||
# (see trpc.bzl for prior art). For every `proto_dep` repo we
|
||||
# therefore expose FOUR candidate `-I` paths to be safe:
|
||||
# 1) <workspace_root> -- source root (plain proto_library)
|
||||
# 2) <bin_dir>/<workspace_root> -- virtual root after strip_import_prefix
|
||||
# 3) <workspace_root>/src -- fallback for older PB descriptor_proto without strip
|
||||
# 4) <bin_dir>/<workspace_root>/src -- same as #3, under bin-dir
|
||||
# protoc only warns on non-existent `-I` paths, so this is harmless.
|
||||
proto_dep_src_depsets = []
|
||||
proto_dep_imports = []
|
||||
extra_pb_root_imports = []
|
||||
# Belt-and-suspenders: also feed each `proto_dep`'s default outputs
|
||||
# (i.e. the .proto files themselves) into `inputs`, in case the
|
||||
# ProtoInfo's transitive_sources does not cover everything we need.
|
||||
proto_dep_src_depsets.append(depset(direct = ctx.files.proto_deps))
|
||||
for pd in ctx.attr.proto_deps:
|
||||
pi = pd[ProtoInfo]
|
||||
proto_dep_src_depsets.append(pi.transitive_sources)
|
||||
for path in pi.transitive_proto_path.to_list():
|
||||
proto_dep_imports.append("-I" + path)
|
||||
wsroot = pd.label.workspace_root
|
||||
if wsroot:
|
||||
extra_pb_root_imports.append("-I" + wsroot)
|
||||
extra_pb_root_imports.append("-I" + bin_root + "/" + wsroot)
|
||||
extra_pb_root_imports.append("-I" + wsroot + "/src")
|
||||
extra_pb_root_imports.append("-I" + bin_root + "/" + wsroot + "/src")
|
||||
# Deduplicate the workspace-level `-I` entries so the same repo
|
||||
# is not listed multiple times when several proto_deps share it.
|
||||
proto_dep_imports.extend(depset(extra_pb_root_imports).to_list())
|
||||
|
||||
all_imports = depset(
|
||||
direct = own_imports + proto_dep_imports,
|
||||
transitive = dep_imports_list,
|
||||
)
|
||||
|
||||
# Output files: every .proto produces a .pb.h and a .pb.cc.
|
||||
# NB: the `path` argument of `ctx.actions.declare_file(path)` is
|
||||
# *relative to the current package*, while `src.short_path` is
|
||||
# *relative to the workspace root*. The two differ by the package
|
||||
# prefix; we must strip that prefix before calling declare_file,
|
||||
# otherwise the outputs would land at
|
||||
# bazel-bin/<pkg>/<pkg>/... (one level too deep).
|
||||
pkg = ctx.label.package
|
||||
pkg_prefix = pkg + "/" if pkg else ""
|
||||
outs = []
|
||||
for src in srcs:
|
||||
if not src.short_path.endswith(".proto"):
|
||||
fail("brpc_proto_gen srcs must be .proto, got: %s" % src.short_path)
|
||||
|
||||
rel = src.short_path
|
||||
if pkg_prefix and rel.startswith(pkg_prefix):
|
||||
rel = rel[len(pkg_prefix):]
|
||||
base = rel[:-len(".proto")]
|
||||
outs.append(ctx.actions.declare_file(base + ".pb.h"))
|
||||
outs.append(ctx.actions.declare_file(base + ".pb.cc"))
|
||||
|
||||
# protoc's --cpp_out points at the include root under bin_root.
|
||||
# After protoc organizes outputs by their import-relative path,
|
||||
# the .pb.{h,cc} files land exactly where declare_file declared
|
||||
# them above.
|
||||
if include_dir == ".":
|
||||
cpp_out_dir = bin_root
|
||||
else:
|
||||
cpp_out_dir = bin_root + "/" + include_dir
|
||||
|
||||
args = ctx.actions.args()
|
||||
args.add_all(all_imports.to_list())
|
||||
args.add("--cpp_out=" + cpp_out_dir)
|
||||
args.add_all([s.path for s in srcs])
|
||||
|
||||
ctx.actions.run(
|
||||
executable = ctx.executable.protoc,
|
||||
arguments = [args],
|
||||
inputs = depset(
|
||||
direct = srcs,
|
||||
transitive = dep_srcs_list + proto_dep_src_depsets,
|
||||
),
|
||||
outputs = outs,
|
||||
mnemonic = "BrpcProtoCompile",
|
||||
progress_message = "BrpcProtoCompile %s" % ctx.label,
|
||||
)
|
||||
|
||||
hdr_files = [f for f in outs if f.path.endswith(".pb.h")]
|
||||
src_files = [f for f in outs if f.path.endswith(".pb.cc")]
|
||||
|
||||
return [
|
||||
DefaultInfo(files = depset(outs)),
|
||||
# Split outputs so the brpc_proto_library macro can route
|
||||
# them to cc_library.hdrs vs cc_library.srcs separately.
|
||||
OutputGroupInfo(
|
||||
hdrs = depset(hdr_files),
|
||||
srcs = depset(src_files),
|
||||
),
|
||||
BrpcProtoInfo(
|
||||
transitive_srcs = depset(direct = srcs, transitive = dep_srcs_list),
|
||||
transitive_imports = all_imports,
|
||||
),
|
||||
]
|
||||
|
||||
brpc_proto_gen = rule(
|
||||
implementation = _proto_gen_impl,
|
||||
attrs = {
|
||||
"srcs": attr.label_list(
|
||||
allow_files = [".proto"],
|
||||
mandatory = True,
|
||||
),
|
||||
# Other `brpc_proto_gen` targets; deps are propagated via the
|
||||
# custom `BrpcProtoInfo` provider.
|
||||
"deps": attr.label_list(
|
||||
providers = [BrpcProtoInfo],
|
||||
default = [],
|
||||
),
|
||||
# The include root, relative to the current BUILD package
|
||||
# (e.g. "src" for the brpc root BUILD).
|
||||
"include": attr.string(default = ""),
|
||||
"protoc": attr.label(
|
||||
default = Label("@com_google_protobuf//:protoc"),
|
||||
executable = True,
|
||||
# `"host"` is the legacy spelling of `"exec"`. Modern
|
||||
# Bazel (>= 6) prefers `"exec"`, but still accepts
|
||||
# `"host"` as an alias through at least Bazel 8.x. We
|
||||
# keep `"host"` here for the broad range of Bazel
|
||||
# versions used to build brpc; switch to `"exec"` once
|
||||
# `"host"` is finally removed (likely a future major
|
||||
# Bazel release).
|
||||
cfg = "host",
|
||||
allow_files = True,
|
||||
),
|
||||
# Native `proto_library` deps (well-known protos or external
|
||||
# .proto libraries). .proto sources and -I paths are obtained
|
||||
# automatically through Bazel's native `ProtoInfo`, fully
|
||||
# decoupled from the protobuf version.
|
||||
"proto_deps": attr.label_list(
|
||||
providers = [ProtoInfo],
|
||||
default = [],
|
||||
),
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user