349 lines
11 KiB
Python
349 lines
11 KiB
Python
# Copyright 2022 The Pigweed Authors
|
|
#
|
|
# 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
|
|
#
|
|
# https://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.
|
|
|
|
"""Backend implementation for 'pw_protobuf_compiler/proto.bzl'"""
|
|
|
|
# Apache License, Version 2.0, January 2004, http://www.apache.org/licenses/
|
|
# Adapted from: https://github.com/rules-proto-grpc/rules_proto_grpc/
|
|
# Files adapted:
|
|
# - rules_proto_grpc/cpp/cpp_grpc_library.bzl
|
|
# - rules_proto_grpc/cpp/cpp_grpc_compile.bzl
|
|
# These two files have been adapted for use in Pigweed and combined into this
|
|
# file.
|
|
|
|
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
|
|
load(
|
|
"@rules_proto_grpc//:defs.bzl",
|
|
"ProtoLibraryAspectNodeInfo",
|
|
"ProtoPluginInfo",
|
|
"proto_compile_aspect_attrs",
|
|
"proto_compile_aspect_impl",
|
|
"proto_compile_attrs",
|
|
"proto_compile_impl",
|
|
)
|
|
load("@rules_proto_grpc//internal:filter_files.bzl", "filter_files")
|
|
|
|
def pwpb_proto_library(name, deps, **kwargs):
|
|
"""A C++ proto library generated using pw_protobuf.
|
|
|
|
Attributes:
|
|
deps: proto_library targets for which to generate this library.
|
|
"""
|
|
_pw_proto_library(
|
|
name = name,
|
|
compiler = pwpb_compile,
|
|
deps = deps,
|
|
cc_deps = ["@pigweed//pw_protobuf"],
|
|
has_srcs = False,
|
|
extra_tags = [],
|
|
**kwargs
|
|
)
|
|
|
|
def pwpb_rpc_proto_library(name, deps, pwpb_proto_library_deps, **kwargs):
|
|
"""A pwpb_rpc proto library target.
|
|
|
|
Attributes:
|
|
deps: proto_library targets for which to generate this library.
|
|
pwpb_proto_library_deps: A pwpb_proto_library generated
|
|
from the same proto_library. Required.
|
|
"""
|
|
_pw_proto_library(
|
|
name = name,
|
|
compiler = pwpb_rpc_compile,
|
|
deps = deps,
|
|
cc_deps = [
|
|
"@pigweed//pw_protobuf",
|
|
"@pigweed//pw_rpc/pwpb:server_api",
|
|
"@pigweed//pw_rpc/pwpb:client_api",
|
|
"@pigweed//pw_rpc",
|
|
] + pwpb_proto_library_deps,
|
|
has_srcs = False,
|
|
extra_tags = [],
|
|
**kwargs
|
|
)
|
|
|
|
def raw_rpc_proto_library(name, deps, **kwargs):
|
|
"""A raw C++ RPC proto library."""
|
|
_pw_proto_library(
|
|
name = name,
|
|
compiler = raw_rpc_compile,
|
|
deps = deps,
|
|
cc_deps = [
|
|
"@pigweed//pw_rpc",
|
|
"@pigweed//pw_rpc/raw:server_api",
|
|
"@pigweed//pw_rpc/raw:client_api",
|
|
],
|
|
has_srcs = False,
|
|
extra_tags = [],
|
|
**kwargs
|
|
)
|
|
|
|
def nanopb_proto_library(name, deps, **kwargs):
|
|
"""A C++ proto library generated using nanopb."""
|
|
_pw_proto_library(
|
|
name = name,
|
|
compiler = nanopb_compile,
|
|
deps = deps,
|
|
cc_deps = [
|
|
"@com_github_nanopb_nanopb//:nanopb",
|
|
],
|
|
has_srcs = True,
|
|
# TODO(tpudlik): Find a way to get Nanopb to generate nested structs.
|
|
# Otherwise add the manual tag to the resulting library, preventing it
|
|
# from being built unless directly depended on. e.g. The 'Pigweed'
|
|
# message in
|
|
# pw_protobuf/pw_protobuf_test_protos/full_test.proto will fail to
|
|
# compile as it has a self referring nested message. According to
|
|
# the docs
|
|
# https://jpa.kapsi.fi/nanopb/docs/reference.html#proto-file-options
|
|
# and https://github.com/nanopb/nanopb/issues/433 it seams like it
|
|
# should be possible to configure nanopb to generate nested structs.
|
|
extra_tags = ["manual"],
|
|
**kwargs
|
|
)
|
|
|
|
def nanopb_rpc_proto_library(name, deps, nanopb_proto_library_deps, **kwargs):
|
|
"""A C++ RPC proto library using nanopb.
|
|
|
|
Attributes:
|
|
deps: proto_library targets for which to generate this library.
|
|
nanopb_proto_library_deps: A pw_nanopb_cc_library generated
|
|
from the same proto_library. Required.
|
|
"""
|
|
_pw_proto_library(
|
|
name = name,
|
|
compiler = nanopb_rpc_compile,
|
|
deps = deps,
|
|
cc_deps = [
|
|
"@com_github_nanopb_nanopb//:nanopb",
|
|
"@pigweed//pw_rpc/nanopb:server_api",
|
|
"@pigweed//pw_rpc/nanopb:client_api",
|
|
"@pigweed//pw_rpc",
|
|
] + nanopb_proto_library_deps,
|
|
has_srcs = True,
|
|
# TODO(tpudlik): See nanopb_proto_library.
|
|
extra_tags = ["manual"],
|
|
**kwargs
|
|
)
|
|
|
|
# Create compile rule
|
|
def _proto_compiler_aspect(plugin_group, prefix):
|
|
return aspect(
|
|
implementation = proto_compile_aspect_impl,
|
|
provides = [ProtoLibraryAspectNodeInfo],
|
|
attr_aspects = ["deps"],
|
|
attrs = dict(
|
|
proto_compile_aspect_attrs,
|
|
_plugins = attr.label_list(
|
|
doc = "List of protoc plugins to apply",
|
|
providers = [ProtoPluginInfo],
|
|
default = plugin_group,
|
|
),
|
|
_prefix = attr.string(
|
|
doc = "String used to disambiguate aspects when generating \
|
|
outputs",
|
|
default = prefix,
|
|
),
|
|
),
|
|
toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))],
|
|
)
|
|
|
|
def _proto_compiler_rule(plugin_group, aspect):
|
|
return rule(
|
|
implementation = proto_compile_impl,
|
|
attrs = dict(
|
|
proto_compile_attrs,
|
|
_plugins = attr.label_list(
|
|
doc = "List of protoc plugins to apply",
|
|
providers = [ProtoPluginInfo],
|
|
default = plugin_group,
|
|
),
|
|
protos = attr.label_list(
|
|
providers = [ProtoInfo],
|
|
doc = "List of proto_library targets.",
|
|
),
|
|
deps = attr.label_list(
|
|
doc = "List of proto_library targets. Prefer protos.",
|
|
aspects = [aspect],
|
|
),
|
|
),
|
|
toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))],
|
|
)
|
|
|
|
nanopb_compile_aspect = _proto_compiler_aspect(
|
|
[Label("//pw_rpc:nanopb_plugin")],
|
|
"nanopb_proto_compile_aspect",
|
|
)
|
|
nanopb_compile = _proto_compiler_rule(
|
|
[Label("//pw_rpc:nanopb_plugin")],
|
|
nanopb_compile_aspect,
|
|
)
|
|
|
|
pwpb_compile_aspect = _proto_compiler_aspect(
|
|
[Label("@pigweed//pw_protobuf:pw_cc_plugin")],
|
|
"pwpb_proto_compile_aspect",
|
|
)
|
|
pwpb_compile = _proto_compiler_rule(
|
|
[Label("@pigweed//pw_protobuf:pw_cc_plugin")],
|
|
pwpb_compile_aspect,
|
|
)
|
|
|
|
pwpb_rpc_compile_aspect = _proto_compiler_aspect(
|
|
[
|
|
Label("@pigweed//pw_rpc:pw_cc_plugin_pwpb_rpc"),
|
|
Label("@pigweed//pw_protobuf:pw_cc_plugin"),
|
|
],
|
|
"pwpb_rpc_proto_compile_aspect",
|
|
)
|
|
pwpb_rpc_compile = _proto_compiler_rule(
|
|
[
|
|
Label("@pigweed//pw_rpc:pw_cc_plugin_pwpb_rpc"),
|
|
Label("@pigweed//pw_protobuf:pw_cc_plugin"),
|
|
],
|
|
pwpb_rpc_compile_aspect,
|
|
)
|
|
|
|
raw_rpc_compile_aspect = _proto_compiler_aspect(
|
|
[Label("@pigweed//pw_rpc:pw_cc_plugin_raw")],
|
|
"raw_rpc_proto_compile_aspect",
|
|
)
|
|
raw_rpc_compile = _proto_compiler_rule(
|
|
[Label("@pigweed//pw_rpc:pw_cc_plugin_raw")],
|
|
raw_rpc_compile_aspect,
|
|
)
|
|
|
|
nanopb_rpc_compile_aspect = _proto_compiler_aspect(
|
|
[
|
|
Label("@pigweed//pw_rpc:pw_cc_plugin_nanopb_rpc"),
|
|
Label("//pw_rpc:nanopb_plugin"),
|
|
],
|
|
"nanopb_rpc_proto_compile_aspect",
|
|
)
|
|
nanopb_rpc_compile = _proto_compiler_rule(
|
|
[
|
|
Label("@pigweed//pw_rpc:pw_cc_plugin_nanopb_rpc"),
|
|
Label("//pw_rpc:nanopb_plugin"),
|
|
],
|
|
nanopb_rpc_compile_aspect,
|
|
)
|
|
|
|
def _pw_proto_library(name, compiler, deps, cc_deps, has_srcs, extra_tags, **kwargs):
|
|
name_pb = name + ".pb"
|
|
additional_tags = [
|
|
tag
|
|
for tag in extra_tags
|
|
if tag not in kwargs.get("tags", [])
|
|
]
|
|
compiler(
|
|
name = name_pb,
|
|
tags = additional_tags,
|
|
# Forward deps and verbose tags to implementation
|
|
verbose = kwargs.get("verbose", 0),
|
|
deps = deps,
|
|
protos = kwargs.get("protos", []),
|
|
)
|
|
|
|
# Filter files to sources and headers
|
|
filter_files(
|
|
name = name_pb + "_srcs",
|
|
target = name_pb,
|
|
extensions = ["c", "cc", "cpp", "cxx"],
|
|
tags = additional_tags,
|
|
)
|
|
|
|
filter_files(
|
|
name = name_pb + "_hdrs",
|
|
target = name_pb,
|
|
extensions = ["h"],
|
|
tags = additional_tags,
|
|
)
|
|
|
|
# Cannot use pw_cc_library here as it will add cxxopts.
|
|
# Note that the srcs attribute here is passed in as a DefaultInfo
|
|
# object, which is not supported by pw_cc_library.
|
|
native.cc_library(
|
|
name = name,
|
|
hdrs = [name_pb + "_hdrs"],
|
|
includes = [name_pb],
|
|
alwayslink = kwargs.get("alwayslink"),
|
|
copts = kwargs.get("copts", []),
|
|
defines = kwargs.get("defines", []),
|
|
srcs = [name_pb + "_srcs"] if has_srcs else [],
|
|
deps = cc_deps,
|
|
linkopts = kwargs.get("linkopts", []),
|
|
linkstatic = kwargs.get("linkstatic", True),
|
|
local_defines = kwargs.get("local_defines", []),
|
|
nocopts = kwargs.get("nocopts", ""),
|
|
visibility = kwargs.get("visibility"),
|
|
tags = kwargs.get("tags", []) + additional_tags,
|
|
)
|
|
|
|
def pw_proto_library(name, **kwargs): # buildifier: disable=function-docstring
|
|
"""Generate all the Pigweed proto library targets.
|
|
|
|
Args:
|
|
name: Name of this proto library.
|
|
**kwargs: Forwarded to wrapped native.cc_library.
|
|
|
|
Deprecated: This macro is deprecated and will be removed in a future
|
|
Pigweed version. Please use one of the single-target macros above.
|
|
"""
|
|
|
|
pwpb_proto_library(
|
|
name = name + ".pwpb",
|
|
**kwargs
|
|
)
|
|
|
|
pwpb_rpc_proto_library(
|
|
name = name + ".pwpb_rpc",
|
|
pwpb_proto_library_deps = [name + ".pwpb"],
|
|
**kwargs
|
|
)
|
|
|
|
raw_rpc_proto_library(
|
|
name = name + ".raw_rpc",
|
|
**kwargs
|
|
)
|
|
|
|
nanopb_proto_library(
|
|
name = name + ".nanopb",
|
|
**kwargs
|
|
)
|
|
|
|
nanopb_rpc_proto_library(
|
|
name = name + ".nanopb_rpc",
|
|
nanopb_proto_library_deps = [name + ".nanopb"],
|
|
**kwargs
|
|
)
|
|
|
|
if "manual" in kwargs.get("tags", []):
|
|
additional_tags = []
|
|
else:
|
|
additional_tags = ["manual"]
|
|
|
|
# Combine all plugins into a single library.
|
|
native.cc_library(
|
|
name = name,
|
|
deps = [
|
|
name + "." + plugin_name
|
|
for plugin_name in ["pwpb", "pwpb_rpc", "raw_rpc", "nanopb", "nanopb_rpc"]
|
|
],
|
|
tags = kwargs.get("tags", []) + additional_tags,
|
|
**{
|
|
k: v
|
|
for k, v in kwargs.items()
|
|
if k not in ["deps", "protos", "tags"]
|
|
}
|
|
)
|