pw_protobuf: Add Bazel plugin targets and deps
Adds bazel target for the python protoc plugin and includes
com_google_protobuf as a WORKSPACE dependency.
Change-Id: I346474fe8ddf7fec16b7e433596426bba50ba2ff
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/15321
Reviewed-by: Akira Baruah <akirabaruah@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Commit-Queue: Akira Baruah <akirabaruah@google.com>
diff --git a/.bazelrc b/.bazelrc
index 68e57cd..bd879cb 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,4 +1,25 @@
+# Copyright 2021 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.
+
+# Required for new toolchain resolution API.
build --incompatible_enable_cc_toolchain_resolution
+# Required for combined code coverage reports.
coverage --experimental_generate_llvm_lcov
-coverage --combined_report=lcov
\ No newline at end of file
+coverage --combined_report=lcov
+
+# Enforces consistent action environment variables. This is important to
+# address Protobuf's rebuild sensitivity on changes to the environment
+# variables.
+build --incompatible_strict_action_env
\ No newline at end of file
diff --git a/WORKSPACE b/WORKSPACE
index 6aa2053..9c25067 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -53,6 +53,22 @@
protobuf_deps()
+# Setup tools to build custom grpc rules.
+# Regquired by: pigweed.
+# Used in modules: //pw_protobuf
+http_archive(
+ name = "rules_proto_grpc",
+ sha256 = "5f0f2fc0199810c65a2de148a52ba0aff14d631d4e8202f41aff6a9d590a471b",
+ strip_prefix = "rules_proto_grpc-1.0.2",
+ urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/1.0.2.tar.gz"],
+)
+
+load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_repos", "rules_proto_grpc_toolchains")
+
+rules_proto_grpc_toolchains()
+
+rules_proto_grpc_repos()
+
# Set up build_bazel_rules_nodejs.
# Required by: pigweed.
# Used in modules: //pw_web_ui.
@@ -88,11 +104,14 @@
npm_bazel_karma_dependencies()
-load(
- "@io_bazel_rules_webtesting//web:repositories.bzl",
- "web_test_repositories",
+http_archive(
+ name = "io_bazel_rules_webtesting",
+ sha256 = "9bb461d5ef08e850025480bab185fd269242d4e533bca75bfb748001ceb343c3",
+ urls = ["https://github.com/bazelbuild/rules_webtesting/releases/download/0.3.3/rules_webtesting.tar.gz"],
)
+load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories")
+
web_test_repositories()
load(
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index 18a3843..6f8f3cb 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -221,6 +221,7 @@
"//pw_allocator/...",
"//pw_assert/...",
'//pw_assert_basic/...',
+ '//pw_protobuf/...',
'//pw_base64/...',
'//pw_build/...',
'//pw_chrono/...',
diff --git a/pw_protobuf/BUILD b/pw_protobuf/BUILD
index 40edf6d..d3772ad 100644
--- a/pw_protobuf/BUILD
+++ b/pw_protobuf/BUILD
@@ -1,4 +1,4 @@
-# Copyright 2020 The Pigweed Authors
+# Copyright 2021 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
@@ -12,11 +12,15 @@
# License for the specific language governing permissions and limitations under
# the License.
+load("@rules_proto//proto:defs.bzl", "proto_library")
load(
"//pw_build:pigweed.bzl",
"pw_cc_library",
"pw_cc_test",
)
+load("@rules_python//python:defs.bzl", "py_binary")
+load("@rules_proto_grpc//:plugin.bzl", "proto_plugin")
+load("//pw_protobuf_compiler:proto.bzl", "pw_proto_library")
package(default_visibility = ["//visibility:public"])
@@ -46,6 +50,8 @@
includes = ["public"],
deps = [
":config",
+ "//pw_bytes",
+ "//pw_result",
"//pw_span",
"//pw_status",
"//pw_varint",
@@ -80,12 +86,36 @@
],
)
-# TODO(frolv): Figure out how to integrate pw_protobuf codegen into Bazel.
-filegroup(
+proto_library(
+ name = "codegen_test_proto",
+ srcs = [
+ "pw_protobuf_protos/common.proto",
+ "pw_protobuf_test_protos/full_test.proto",
+ "pw_protobuf_test_protos/imported.proto",
+ "pw_protobuf_test_protos/importer.proto",
+ "pw_protobuf_test_protos/non_pw_package.proto",
+ "pw_protobuf_test_protos/proto2.proto",
+ "pw_protobuf_test_protos/repeated.proto",
+ ],
+ strip_import_prefix = "//pw_protobuf",
+)
+
+pw_proto_library(
+ name = "codegen_test_protos_pwpb",
+ deps = [":codegen_test_proto"],
+)
+
+pw_cc_test(
name = "codegen_test",
srcs = [
"codegen_test.cc",
],
+ deps = [
+ ":codegen_test_protos_pwpb",
+ ":pw_protobuf",
+ "//pw_span",
+ "//pw_unit_test",
+ ],
)
# TODO(frolv): Figure out how to add facade tests to Bazel.
@@ -103,3 +133,22 @@
"size_report/*.cc",
]),
)
+
+py_binary(
+ name = "plugin",
+ srcs = glob(["py/pw_protobuf/*.py"]),
+ imports = ["py"],
+ main = "py/pw_protobuf/plugin.py",
+ python_version = "PY3",
+ deps = ["@com_google_protobuf//:protobuf_python"],
+)
+
+proto_plugin(
+ name = "pw_cc_plugin",
+ outputs = [
+ "{protopath}.pwpb.h",
+ ],
+ protoc_plugin_name = "pwpb",
+ tool = "@pigweed//pw_protobuf:plugin",
+ visibility = ["//visibility:public"],
+)
diff --git a/pw_protobuf_compiler/deps.bzl b/pw_protobuf_compiler/deps.bzl
new file mode 100644
index 0000000..ed6492a
--- /dev/null
+++ b/pw_protobuf_compiler/deps.bzl
@@ -0,0 +1,32 @@
+# Copyright 2021 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.
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def pw_protobuf_dependencies():
+ """ Fetches workspace dependencies required for //pw_protobuf """
+ if "com_google_protobuf" not in native.existing_rules():
+ http_archive(
+ name = "com_google_protobuf",
+ sha256 = "71030a04aedf9f612d2991c1c552317038c3c5a2b578ac4745267a45e7037c29",
+ strip_prefix = "protobuf-3.12.3",
+ url = "https://github.com/protocolbuffers/protobuf/archive/v3.12.3.tar.gz",
+ )
+ if "rules_proto_grpc" not in native.existing_rules():
+ http_archive(
+ name = "rules_proto_grpc",
+ sha256 = "5f0f2fc0199810c65a2de148a52ba0aff14d631d4e8202f41aff6a9d590a471b",
+ strip_prefix = "rules_proto_grpc-1.0.2",
+ urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/1.0.2.tar.gz"],
+ )
diff --git a/pw_protobuf_compiler/docs.rst b/pw_protobuf_compiler/docs.rst
index eeb1620..fc9ed7b 100644
--- a/pw_protobuf_compiler/docs.rst
+++ b/pw_protobuf_compiler/docs.rst
@@ -302,3 +302,58 @@
.. code-block:: cpp
#include "my_other_protos/baz.pwpb.h"
+
+Bazel
+=====
+Bazel provides a ``pw_proto_library`` rule with similar features as the
+GN template. The Bazel build only supports building firmware code, so
+``pw_proto_library`` does not generate a Python package. The Bazel rules differ
+slightly compared to the GN build to be more in line with what would be
+considered idiomatic in Bazel.
+
+To use Pigweeds Protobuf rules you must first pull in the required dependencies
+into your Bazel WORKSPACE file. e.g.
+
+.. code-block:: python
+
+ # WORKSPACE ...
+ load("@pigweed//pw_protobuf_compiler:deps.bzl", "pw_protobuf_dependencies")
+ pw_protobuf_dependencies()
+
+Bazel uses a different set of rules to manage proto files than it does to
+compile them. e.g.
+
+.. code-block:: python
+
+ # BUILD ...
+ load("@rules_proto//proto:defs.bzl", "proto_library")
+ load("@pigweed//pw_protobuf_compiler:proto.bzl", "pw_proto_library")
+
+ # Manages proto sources and dependencies.
+ proto_library(
+ name = "my_proto",
+ srcs = [
+ "my_protos/foo.proto",
+ "my_protos/bar.proto",
+ ]
+ )
+
+ # Compiles dependant protos to C++.
+ pw_proto_library(
+ name = "my_cc_proto",
+ deps = [":my_proto"],
+ )
+
+ # Library that depends on generated proto targets.
+ pw_cc_library(
+ name = "my_lib",
+ srcs = ["my/lib.cc"],
+ deps = [":my_cc_proto"],
+ )
+
+From ``my/lib.cc`` you can now include the generated headers.
+e.g.
+
+.. code:: cpp
+
+ #include "my_protos/bar.pwpb.h"
\ No newline at end of file
diff --git a/pw_protobuf_compiler/proto.bzl b/pw_protobuf_compiler/proto.bzl
new file mode 100644
index 0000000..5273c46
--- /dev/null
+++ b/pw_protobuf_compiler/proto.bzl
@@ -0,0 +1,100 @@
+# Copyright 2021 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.
+load("//pw_build:pigweed.bzl", "pw_cc_library")
+load("@rules_proto//proto:defs.bzl", "ProtoInfo")
+load("@rules_proto_grpc//:plugin.bzl", "ProtoPluginInfo")
+load(
+ "@rules_proto_grpc//:aspect.bzl",
+ "ProtoLibraryAspectNodeInfo",
+ "proto_compile_aspect_attrs",
+ "proto_compile_aspect_impl",
+ "proto_compile_attrs",
+ "proto_compile_impl",
+)
+
+# Create aspect for cc_proto_compile
+cc_proto_compile_aspect = 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 = [
+ Label("@pigweed//pw_protobuf:pw_cc_plugin"),
+ ],
+ ),
+ _prefix = attr.string(
+ doc = "String used to disambiguate aspects when generating outputs",
+ default = "cc_proto_compile_aspect",
+ ),
+ ),
+ toolchains = [str(Label("@rules_proto_grpc//protobuf:toolchain_type"))],
+)
+
+# Create compile rule to apply aspect
+_rule = rule(
+ implementation = proto_compile_impl,
+ attrs = dict(
+ proto_compile_attrs,
+ deps = attr.label_list(
+ mandatory = True,
+ providers = [ProtoInfo, ProtoLibraryAspectNodeInfo],
+ aspects = [cc_proto_compile_aspect],
+ ),
+ ),
+)
+
+# Create macro for converting attrs and passing to compile
+def _cc_proto_compile(**kwargs):
+ _rule(
+ verbose_string = "{}".format(kwargs.get("verbose", 0)),
+ merge_directories = True,
+ **{k: v for k, v in kwargs.items() if k != "merge_directories"}
+ )
+
+def pw_proto_library(**kwargs):
+ """ Embedded friendly replacement for native.cc_proto_library
+
+ This Protobuf implementation is designed to run on embedded
+ computers. Because of this the cc API differs from the standard
+ Protobuf cc plugin. The generated headers in this library are not a drop in
+ replacement for the standard cc_proto_library.
+
+ Args:
+ **kwargs: Equivalent inputs to cc_proto_library
+ """
+
+ # Compile protos
+ name_pb = kwargs.get("name") + "_pb"
+ _cc_proto_compile(
+ name = name_pb,
+ # Forward deps and verbose tags to implementation
+ **{k: v for (k, v) in kwargs.items() if k in ("deps", "verbose")}
+ )
+
+ # Create cc_library
+ pw_cc_library(
+ name = kwargs.get("name"),
+ srcs = [name_pb],
+ deps = [
+ "@pigweed//pw_protobuf",
+ ],
+ includes = [name_pb],
+ strip_include_prefix = ".",
+ visibility = kwargs.get("visibility"),
+ linkstatic = 1,
+ )