Fix brpc_proto_library failure when brpc is used as an external Bazel dependency (#3427)

This commit is contained in:
Bright Chen
2026-08-09 14:47:53 +08:00
committed by GitHub
parent 0ec3a9ddaa
commit 7a3e034e20
14 changed files with 369 additions and 57 deletions
+2
View File
@@ -1,4 +1,6 @@
./example/build_with_bazel
./example/build_with_bazel_module
./example/build_with_old_bazel
# `registry/` is brpc's self-maintained Bzlmod registry. Its overlay
# BUILD.bazel files reference sources from the libunwind tarball that is
+40 -7
View File
@@ -129,7 +129,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- run: |
- run: sudo apt-get update && sudo apt-get install -y libibverbs-dev
- name: root
run: |
bazel build --define with_mesalink=false \
--define with_glog=true \
--define with_thrift=true \
@@ -140,7 +142,21 @@ jobs:
--define with_bthread_tracer=true \
--define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \
--define with_babylon_counter=true \
-- //:brpc
-- //:brpc //example/...
- name: external
run: |
cd example/build_with_bazel_module
bazel build --define with_mesalink=false \
--define with_glog=true \
--define with_thrift=true \
--define BRPC_WITH_BORINGSSL=true \
--define with_debug_bthread_sche_safety=true \
--define with_debug_lock=true \
--define with_asan=true \
--define with_bthread_tracer=true \
--define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \
--define with_babylon_counter=true \
-- //...
clang-compile-with-make-protobuf:
runs-on: ubuntu-22.04
@@ -188,7 +204,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- run: |
- run: sudo apt-get update && sudo apt-get install -y libibverbs-dev
- name: root
run: |
bazel build --action_env=CC=clang \
--define with_mesalink=false \
--define with_glog=true \
@@ -200,7 +218,22 @@ jobs:
--define with_bthread_tracer=true \
--define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \
--define with_babylon_counter=true \
-- //:brpc
-- //:brpc //example/...
- name: external
run: |
cd example/build_with_bazel_module
bazel build --action_env=CC=clang \
--define with_mesalink=false \
--define with_glog=true \
--define with_thrift=true \
--define BRPC_WITH_BORINGSSL=true \
--define with_debug_bthread_sche_safety=true \
--define with_debug_lock=true \
--define with_asan=true \
--define with_bthread_tracer=true \
--define BRPC_WITH_NO_PTHREAD_MUTEX_HOOK=true \
--define with_babylon_counter=true \
-- //...
clang-unittest:
runs-on: ubuntu-22.04
@@ -246,9 +279,9 @@ jobs:
runs-on: ubuntu-22.04
env:
TEST_PROTOBUF_VERSION: "34.1"
# protobuf >= 34.x uses new ProtoInfo fields (option_deps,
# extension_declarations) introduced in Bazel 8.x. The repo's
# .bazelversion (7.2.1) is too old. bazelisk honors USE_BAZEL_VERSION.
# protobuf >= 34.x uses new ProtoInfo fields (option_deps, extension_declarations)
# introduced in Bazel 8.x. The repo's .bazelversion (7.2.1) is too old. bazelisk
# honors USE_BAZEL_VERSION.
USE_BAZEL_VERSION: "8.3.1"
steps:
- uses: actions/checkout@v2
+1
View File
@@ -34,6 +34,7 @@ header:
- 'example/*/*.json'
- 'example/*/*.pem'
- 'example/*/*.port'
- 'example/build_with_bazel_module/.bazelversion'
- 'src/bthread/offset_inl.list'
- 'test/*.crt'
- 'test/*.key'
+18 -2
View File
@@ -1,3 +1,20 @@
# 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.
module(
name = 'brpc',
version = '1.17.0',
@@ -10,11 +27,10 @@ bazel_dep(name = 'bazel_skylib', version = '1.0.3')
bazel_dep(name = 'boringssl', version = '0.0.0-20211025-d4f1ab9')
bazel_dep(name = 'protobuf', version = '27.3', repo_name = 'com_google_protobuf')
bazel_dep(name = 'gflags', version = '2.2.2', repo_name = 'com_github_gflags_gflags')
bazel_dep(name = 'glog', version = '0.5.0', repo_name = 'com_github_google_glog')
bazel_dep(name = 'glog', version = '0.7.1', repo_name = 'com_github_google_glog')
bazel_dep(name = 'platforms', version = '0.0.4')
bazel_dep(name = "apple_support", version = "1.22.1")
bazel_dep(name = 'rules_cc', version = '0.0.1')
bazel_dep(name = 'rules_proto', version = '4.0.0')
bazel_dep(name = 'zlib', version = '1.3.1.bcr.5', repo_name = 'com_github_madler_zlib')
bazel_dep(name = 'babylon', version = '1.4.4')
# --registry=https://raw.githubusercontent.com/apache/brpc/master/registry
+8 -12
View File
@@ -70,17 +70,13 @@ def brpc_proto_library(
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"`.
current package itself.
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.
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.
"""
@@ -127,11 +123,11 @@ def brpc_proto_library(
# 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 "."],
# bazel-bin/<package>/<include>/...). For a non-root package
# with include="", "." exposes the current package's source
# and bazel-bin directories. The root package needs no extra
# include because those roots are already on the search path.
includes = [real_include] if real_include else (["."] if native.package_name() else []),
deps = deps + ["@com_google_protobuf//:protobuf"],
visibility = visibility,
testonly = testonly,
+43 -26
View File
@@ -60,31 +60,46 @@ def _resolve_include_dir(ctx):
ctx.label.package = "" + include = "src" -> "src"
ctx.label.package = "test" + include = "" -> "test"
ctx.label.package = "" + include = "" -> "."
When the target is in an external repository, the returned path needs
to be prefixed with workspace_root.
"""
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 "."
rel_path = pkg + "/" + inc
elif pkg:
rel_path = pkg
elif inc:
rel_path = inc
else:
rel_path = "."
workspace_root = ctx.label.workspace_root
if workspace_root:
if rel_path == ".":
return workspace_root
else:
return workspace_root + "/" + rel_path
return rel_path
def _proto_gen_impl(ctx):
srcs = ctx.files.srcs
include_dir = _resolve_include_dir(ctx)
bin_root = ctx.bin_dir.path
current_workspace_root = ctx.label.workspace_root
# `-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).
# Add both the source-tree include root and its bazel-bin counterpart.
# For external repositories, include_dir already starts with workspace_root,
# so appending it to bin_root addresses generated protos in that repository.
own_imports = ["-I" + include_dir]
if include_dir == ".":
own_imports.append("-I" + bin_root)
else:
if current_workspace_root:
own_imports.append("-I" + bin_root + "/" + include_dir)
else:
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]
@@ -120,12 +135,12 @@ def _proto_gen_impl(ctx):
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")
dep_workspace_root = pd.label.workspace_root
if dep_workspace_root:
extra_pb_root_imports.append("-I" + dep_workspace_root)
extra_pb_root_imports.append("-I" + bin_root + "/" + dep_workspace_root)
extra_pb_root_imports.append("-I" + dep_workspace_root + "/src")
extra_pb_root_imports.append("-I" + bin_root + "/" + dep_workspace_root + "/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())
@@ -156,14 +171,16 @@ def _proto_gen_impl(ctx):
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:
# Point protoc at this target's include root under bazel-bin. For external
# repositories, include_dir includes workspace_root, which places generated
# files under the repository-specific portion of bazel-bin.
if current_workspace_root:
cpp_out_dir = bin_root + "/" + include_dir
else:
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())
-6
View File
@@ -12,9 +12,6 @@
# 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.
#
# Thie empty BUILD.bazel file is required to make Bazel treat
# this directory as a package.
cc_binary(
@@ -22,8 +19,5 @@ cc_binary(
srcs = ["test.cc"],
deps = [
"@apache_brpc//:brpc",
"@apache_brpc//:bthread",
"@apache_brpc//:bvar",
"@apache_brpc//:butil",
],
)
+61
View File
@@ -0,0 +1,61 @@
# 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.
# Bazel doesn't need more than 200MB of memory for local build based on memory profiling:
# https://docs.bazel.build/versions/master/skylark/performance.html#memory-profiling
# The default JVM max heapsize is 1/4 of physical memory up to 32GB which could be large
# enough to consume all memory constrained by cgroup in large host.
# Limiting JVM heapsize here to let it do GC more when approaching the limit to
# leave room for compiler/linker.
# The number 3G is chosen heuristically to both support large VM and small VM with RBE.
# Startup options cannot be selected via config.
startup --host_jvm_args=-Xmx3g
startup --host_jvm_args="-DBAZEL_TRACK_SOURCE_DIRECTORIES=1"
# Default build options. These are applied first and unconditionally.
common --registry=https://bcr.bazel.build
common --registry=https://baidu.github.io/babylon/registry
common --registry=https://raw.githubusercontent.com/apache/brpc/master/registry
build --verbose_failures
# Keep SHT_SYMTAB in built binaries so google::Symbolize can resolve
# in-binary functions (e.g. TestBody() in test binaries) by name
# instead of falling back to "<unknown>". Bazel's default
# `--strip=sometimes` strips debug/symbol sections in fastbuild mode,
# which is what `bazel test` uses unless `-c dbg` is given.
build --strip=never
build --cxxopt="-std=c++17"
build --copt="-fno-omit-frame-pointer"
# Use gnu17 for asm keyword.
build --conlyopt="-std=gnu17"
# Enable position independent code (this is the default on macOS and Windows)
# (Workaround for https://github.com/bazelbuild/rules_foreign_cc/issues/421)
build --copt=-fPIC
build --fission=dbg,opt
build --features=per_object_debug_info
# We already have absl in the build, define absl=1 to tell googletest to use absl for backtrace.
build --define absl=1
test --config=test
test --test_output=streamed
# Pass PATH, CC, CXX and LLVM_CONFIG variables from the environment.
build --action_env=CC
build --action_env=CXX
build --action_env=LLVM_CONFIG
build --action_env=PATH
@@ -0,0 +1 @@
7.2.1
@@ -0,0 +1,32 @@
# 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.
load("@apache_brpc//bazel/tools:brpc_proto_library.bzl", "brpc_proto_library")
brpc_proto_library(
name = "cc_echo_c++_proto",
srcs = ["echo.proto"],
)
cc_binary(
name = "echo_c++_server",
srcs = [
"server.cpp",
],
deps = [
":cc_echo_c++_proto",
"@apache_brpc//:brpc",
],
)
@@ -0,0 +1,30 @@
# 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.
module(
name = 'brpc-example',
version = '1.17.0',
compatibility_level = 1,
)
bazel_dep(name = 'protobuf', version = '27.3', repo_name = 'com_google_protobuf')
bazel_dep(name = 'brpc', version = '1.17.0', repo_name = 'apache_brpc')
local_path_override(
module_name = "brpc",
path = "../..",
)
@@ -0,0 +1,33 @@
// 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.
syntax="proto2";
option cc_generic_services = true;
package example;
message EchoRequest {
required string message = 1;
};
message EchoResponse {
required string message = 1;
};
service EchoService {
rpc Echo(EchoRequest) returns (EchoResponse);
};
@@ -0,0 +1,99 @@
// 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.
// A server to receive EchoRequest and send back EchoResponse.
#include <gflags/gflags.h>
#include <butil/logging.h>
#include <brpc/server.h>
#include "echo.pb.h"
DEFINE_bool(echo_attachment, true, "Echo attachment as well");
DEFINE_int32(port, 8002, "TCP Port of this server");
DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no "
"read/write operations during the last `idle_timeout_s'");
DEFINE_int32(max_concurrency, 0, "Limit of request processing in parallel");
DEFINE_int32(internal_port, -1, "Only allow builtin services at this port");
namespace example {
// Your implementation of EchoService
class EchoServiceImpl : public EchoService {
public:
EchoServiceImpl() {}
~EchoServiceImpl() {}
void Echo(google::protobuf::RpcController* cntl_base,
const EchoRequest* request,
EchoResponse* response,
google::protobuf::Closure* done) {
brpc::ClosureGuard done_guard(done);
brpc::Controller* cntl =
static_cast<brpc::Controller*>(cntl_base);
// Echo request and its attachment
response->set_message(request->message());
if (FLAGS_echo_attachment) {
cntl->response_attachment().append(cntl->request_attachment());
}
}
};
} // namespace example
DEFINE_bool(h, false, "print help information");
int main(int argc, char* argv[]) {
std::string help_str = "dummy help infomation";
GFLAGS_NAMESPACE::SetUsageMessage(help_str);
// Parse gflags. We recommend you to use gflags as well.
GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
if (FLAGS_h) {
fprintf(stderr, "%s\n%s\n%s", help_str.c_str(), help_str.c_str(), help_str.c_str());
return 0;
}
// Generally you only need one Server.
brpc::Server server;
// Instance of your service.
example::EchoServiceImpl echo_service_impl;
// Add the service into server. Notice the second parameter, because the
// service is put on stack, we don't want server to delete it, otherwise
// use brpc::SERVER_OWNS_SERVICE.
if (server.AddService(&echo_service_impl,
brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {
LOG(ERROR) << "Fail to add service";
return -1;
}
// Start the server.
brpc::ServerOptions options;
options.mutable_ssl_options()->default_cert.certificate = "cert.pem";
options.mutable_ssl_options()->default_cert.private_key = "key.pem";
options.idle_timeout_sec = FLAGS_idle_timeout_s;
options.max_concurrency = FLAGS_max_concurrency;
options.internal_port = FLAGS_internal_port;
if (server.Start(FLAGS_port, &options) != 0) {
LOG(ERROR) << "Fail to start EchoServer";
return -1;
}
// Wait until Ctrl-C is pressed, then Stop() and Join() the server.
server.RunUntilAskedToQuit();
return 0;
}
+1 -4
View File
@@ -470,10 +470,7 @@ private:
if (BAIDU_LIKELY(lp != NULL)) {
return lp;
}
lp = new(std::nothrow) LocalPool(this);
if (NULL == lp) {
return NULL;
}
lp = new LocalPool(this);
BAIDU_SCOPED_LOCK(_change_thread_mutex); //avoid race with clear()
BAIDU_SET_VOLATILE_THREAD_LOCAL(_local_pool, lp);
butil::thread_atexit(LocalPool::delete_local_pool, lp);