blob: 0c93ae611e2507ad80026866a9ee6b5a6eb9b4c8 [file] [log] [blame]
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -07001.. _module-pw_protobuf_compiler:
Alexei Frolov4a257c12020-03-02 14:09:42 -08002
Alexei Frolov942adf02019-12-11 17:07:28 -08003--------------------
4pw_protobuf_compiler
5--------------------
Alexei Frolov942adf02019-12-11 17:07:28 -08006The Protobuf compiler module provides build system integration and wrapper
7scripts for generating source code for Protobuf definitions.
8
Alexei Frolovf39cd8b2020-04-13 17:59:20 -07009Generator support
10=================
Alexei Frolovf39cd8b2020-04-13 17:59:20 -070011Protobuf code generation is currently supported for the following generators:
Alexei Frolov942adf02019-12-11 17:07:28 -080012
Alexei Frolov79b7cb02020-07-06 13:51:43 -070013+-------------+----------------+-----------------------------------------------+
14| Generator | Code | Notes |
15+-------------+----------------+-----------------------------------------------+
16| pw_protobuf | ``pwpb`` | Compiles using ``pw_protobuf``. |
17+-------------+----------------+-----------------------------------------------+
Alexei Frolov79b7cb02020-07-06 13:51:43 -070018| Nanopb | ``nanopb`` | Compiles using Nanopb. The build argument |
19| | | ``dir_pw_third_party_nanopb`` must be set to |
20| | | point to a local nanopb installation. |
21+-------------+----------------+-----------------------------------------------+
Alexei Frolovc912ea72020-10-26 08:43:27 -070022| Nanopb RPC | ``nanopb_rpc`` | Compiles pw_rpc service and client code for |
23| | | nanopb. Requires a nanopb installation. |
24+-------------+----------------+-----------------------------------------------+
25| Raw RPC | ``raw_rpc`` | Compiles raw binary pw_rpc service code. |
Alexei Frolov79b7cb02020-07-06 13:51:43 -070026+-------------+----------------+-----------------------------------------------+
Alexei Frolova4c0aee2020-12-01 13:48:48 -080027| Go | ``go`` | Compiles using the standard Go protobuf |
28| | | plugin with gRPC service support. |
29+-------------+----------------+-----------------------------------------------+
30| Python | ``python`` | Compiles using the standard Python protobuf |
31| | | plugin, creating a ``pw_python_package``. |
32+-------------+----------------+-----------------------------------------------+
Alexei Frolov942adf02019-12-11 17:07:28 -080033
Alexei Frolov942adf02019-12-11 17:07:28 -080034GN template
35===========
Armando Montanez377a68c2021-05-13 15:53:13 -070036This module provides a ``pw_proto_library`` GN template that defines a
37collection of protobuf files that should be compiled together. The template
38creates a sub-target for each supported generator, named
Alexei Frolovb499d3f2020-10-28 13:00:08 -070039``<target_name>.<generator>``. These sub-targets generate their respective
40protobuf code, and expose it to the build system appropriately (e.g. a
41``pw_source_set`` for C/C++).
Alexei Frolov942adf02019-12-11 17:07:28 -080042
Alexei Frolovb499d3f2020-10-28 13:00:08 -070043For example, given the following target:
Alexei Frolov942adf02019-12-11 17:07:28 -080044
Alexei Frolovb499d3f2020-10-28 13:00:08 -070045.. code-block::
Alexei Frolov942adf02019-12-11 17:07:28 -080046
47 pw_proto_library("test_protos") {
Wyatt Heplerd517afc2021-02-03 19:40:08 -080048 sources = [ "my_test_protos/test.proto" ]
Alexei Frolov942adf02019-12-11 17:07:28 -080049 }
50
Alexei Frolovb499d3f2020-10-28 13:00:08 -070051``test_protos.pwpb`` compiles code for pw_protobuf, and ``test_protos.nanopb``
52compiles using Nanopb (if it's installed).
53
54Protobuf code is only generated when a generator sub-target is listed as a
55dependency of another GN target.
Alexei Frolov942adf02019-12-11 17:07:28 -080056
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -070057GN permits using abbreviated labels when the target name matches the directory
58name (e.g. ``//foo`` for ``//foo:foo``). For consistency with this, the
59sub-targets for each generator are aliased to the directory when the target name
60is the same. For example, these two labels are equivalent:
61
62.. code-block::
63
64 //path/to/my_protos:my_protos.pwpb
65 //path/to/my_protos:pwpb
66
Wyatt Hepler2c6c0ba2021-04-07 09:50:23 -070067``pw_python_package`` subtargets are also available on the ``python`` subtarget:
68
69.. code-block::
70
71 //path/to/my_protos:my_protos.python.lint
72 //path/to/my_protos:python.lint
73
Armando Montanez377a68c2021-05-13 15:53:13 -070074**Supported Codegen**
75
76GN supports the following compiled proto libraries via the specified
77sub-targets generated by a ``pw_proto_library``.
78
79* ``${target_name}.pwpb`` - Generated C++ pw_protobuf code
80* ``${target_name}.nanopb`` - Generated C++ nanopb code (requires Nanopb)
81* ``${target_name}.nanopb_rpc`` - Generated C++ Nanopb pw_rpc code (requires
82 Nanopb)
83* ``${target_name}.raw_rpc`` - Generated C++ raw pw_rpc code (no protobuf
84 library)
85* ``${target_name}.go`` - Generated GO protobuf libraries
86* ``${target_name}.python`` - Generated Python protobuf libraries
87
Alexei Frolov942adf02019-12-11 17:07:28 -080088**Arguments**
89
Wyatt Hepler752d7d32021-03-02 09:02:23 -080090* ``sources``: List of input .proto files.
91* ``deps``: List of other pw_proto_library dependencies.
92* ``inputs``: Other files on which the protos depend (e.g. nanopb ``.options``
93 files).
94* ``prefix``: A prefix to add to the source protos prior to compilation. For
95 example, a source called ``"foo.proto"`` with ``prefix = "nested"`` will be
96 compiled with protoc as ``"nested/foo.proto"``.
97* ``strip_prefix``: Remove this prefix from the source protos. All source and
98 input files must be nested under this path.
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -070099* ``python_package``: Label of Python package to which to add the proto modules.
Wyatt Heplerb2062fd2021-06-01 21:33:07 -0700100 The .python subtarget will redirect to this package.
Alexei Frolov942adf02019-12-11 17:07:28 -0800101
102**Example**
103
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800104.. code-block::
Alexei Frolov942adf02019-12-11 17:07:28 -0800105
106 import("$dir_pw_protobuf_compiler/proto.gni")
107
108 pw_proto_library("my_protos") {
109 sources = [
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800110 "my_protos/foo.proto",
111 "my_protos/bar.proto",
Alexei Frolov942adf02019-12-11 17:07:28 -0800112 ]
113 }
114
115 pw_proto_library("my_other_protos") {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800116 sources = [ "some/other/path/baz.proto" ] # imports foo.proto
117
118 # This removes the "some/other/path" prefix from the proto files.
119 strip_prefix = "some/other/path"
120
121 # This adds the "my_other_protos/" prefix to the proto files.
122 prefix = "my_other_protos"
Alexei Frolov8e30d462020-10-22 13:54:36 -0700123
124 # Proto libraries depend on other proto libraries directly.
125 deps = [ ":my_protos" ]
Alexei Frolov942adf02019-12-11 17:07:28 -0800126 }
127
128 source_set("my_cc_code") {
129 sources = [
130 "foo.cc",
131 "bar.cc",
132 "baz.cc",
133 ]
Alexei Frolov8e30d462020-10-22 13:54:36 -0700134
135 # When depending on protos in a source_set, specify the generator suffix.
136 deps = [ ":my_other_protos.pwpb" ]
Alexei Frolov942adf02019-12-11 17:07:28 -0800137 }
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800138
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800139From C++, ``baz.proto`` included as follows:
140
141.. code-block:: cpp
142
143 #include "my_other_protos/baz.pwpb.h"
144
145From Python, ``baz.proto`` is imported as follows:
146
147.. code-block:: python
148
149 from my_other_protos import baz_pb2
150
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800151Proto file structure
152--------------------
153Protobuf source files must be nested under another directory when they are
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800154compiled. This ensures that they can be packaged properly in Python. The first
155directory is used as the Python package name, so must be unique across the
156build. The ``prefix`` option may be used to set this directory.
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800157
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800158Using ``prefix`` and ``strip_prefix`` together allows remapping proto files to
159a completely different path. This can be useful when working with protos defined
160in external libraries. For example, consider this proto library:
161
162.. code-block::
163
164 pw_proto_library("external_protos") {
165 sources = [
166 "//other/external/some_library/src/protos/alpha.proto",
167 "//other/external/some_library/src/protos/beta.proto,
168 "//other/external/some_library/src/protos/internal/gamma.proto",
169 ]
170 strip_prefix = "//other/external/some_library/src/protos"
171 prefix = "some_library"
172 }
173
174These protos will be compiled by protoc as if they were in this file structure:
175
176.. code-block::
177
178 some_library/
179 ├── alpha.proto
180 ├── beta.proto
181 └── internal
182 └── gamma.proto
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800183
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800184.. _module-pw_protobuf_compiler-add-to-python-package:
185
186Adding Python proto modules to an existing package
187--------------------------------------------------
188By default, generated Python proto modules are organized into their own Python
189package. These proto modules can instead be added to an existing Python package
Wyatt Heplerb8476152021-04-06 15:28:32 -0700190declared with ``pw_python_package``. This is done by setting the
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800191``python_package`` argument on the ``pw_proto_library`` and the
192``proto_library`` argument on the ``pw_python_package``.
193
194For example, the protos declared in ``my_protos`` will be nested in the Python
195package declared by ``my_package``.
196
197.. code-block::
198
199 pw_proto_library("my_protos") {
200 sources = [ "hello.proto ]
201 prefix = "foo"
202 python_package = ":my_package"
203 }
204
205 pw_python_pacakge("my_package") {
206 generate_setup = {
207 name = "foo"
208 version = "1.0"
209 }
210 sources = [ "foo/cool_module.py" ]
211 proto_library = ":my_protos"
212 }
213
214The ``hello_pb2.py`` proto module can be used alongside other files in the
215``foo`` package.
216
217.. code-block:: python
218
219 from foo import cool_module, hello_pb2
220
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800221Working with externally defined protos
222--------------------------------------
223``pw_proto_library`` targets may be used to build ``.proto`` sources from
224existing projects. In these cases, it may be necessary to supply the
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800225``strip_prefix`` argument, which specifies the protobuf include path to use for
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800226``protoc``. If only a single external protobuf is being compiled, the
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800227``python_module_as_package`` option can be used to override the requirement that
228the protobuf be nested under a directory. This option generates a Python package
229with the same name as the proto file, so that the generated proto can be
230imported as if it were a standalone Python module.
231
232For example, the ``pw_proto_library`` target for Nanopb sets
233``python_module_as_package`` to ``nanopb_pb2``.
234
235.. code-block::
236
237 pw_proto_library("proto") {
238 strip_prefix = "$dir_pw_third_party_nanopb/generator/proto"
239 sources = [ "$dir_pw_third_party_nanopb/generator/proto/nanopb.proto" ]
240 python_module_as_package = "nanopb_pb2"
241 }
242
243In Python, this makes ``nanopb.proto`` available as ``import nanopb_pb2`` via
244the ``nanopb_pb2`` Python package. In C++, ``nanopb.proto`` is accessed as
245``#include "nanopb.pwpb.h"``.
246
247The ``python_module_as_package`` feature should only be used when absolutely
248necessary --- for example, to support proto files that include
249``import "nanopb.proto"``.
250
251CMake
252=====
253CMake provides a ``pw_proto_library`` function with similar features as the
254GN template. The CMake build only supports building firmware code, so
255``pw_proto_library`` does not generate a Python package.
256
257**Arguments**
258
259* ``NAME``: the base name of the libraries to create
260* ``SOURCES``: .proto source files
261* ``DEPS``: dependencies on other ``pw_proto_library`` targets
262* ``PREFIX``: prefix add to the proto files
263* ``STRIP_PREFIX``: prefix to remove from the proto files
264* ``INPUTS``: files to include along with the .proto files (such as Nanopb
265 .options files)
266
267**Example**
268
269 .. code-block:: cmake
270
271 include($ENV{PW_ROOT}/pw_build/pigweed.cmake)
272 include($ENV{PW_ROOT}/pw_protobuf_compiler/proto.cmake)
273
274 pw_proto_library(my_module.my_protos
275 SOURCES
276 my_protos/foo.proto
277 my_protos/bar.proto
278 )
279
280 pw_proto_library(my_module.my_protos
281 SOURCES
282 my_protos/foo.proto
283 my_protos/bar.proto
284 )
285
286 pw_proto_library(my_module.my_other_protos
287 SOURCES
288 some/other/path/baz.proto # imports foo.proto
289
290 # This removes the "some/other/path" prefix from the proto files.
291 STRIP_PREFIX
292 some/other/path
293
294 # This adds the "my_other_protos/" prefix to the proto files.
295 PREFIX
296 my_other_protos
297
298 # Proto libraries depend on other proto libraries directly.
299 DEPS
300 my_module.my_protos
301 )
302
303 add_library(my_module.my_cc_code
304 foo.cc
305 bar.cc
306 baz.cc
307 )
308
309 # When depending on protos in a source_set, specify the generator suffix.
310 target_link_libraries(my_module.my_cc_code PUBLIC
311 my_module.my_other_protos.pwpb
312 )
313
314These proto files are accessed in C++ the same as in the GN build:
315
316.. code-block:: cpp
317
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700318 #include "my_other_protos/baz.pwpb.h"
Nathaniel Brough9d9a20d2020-08-04 16:46:56 +0800319
Armando Montanez377a68c2021-05-13 15:53:13 -0700320**Supported Codegen**
321
322CMake supports the following compiled proto libraries via the specified
323sub-targets generated by a ``pw_proto_library``.
324
325* ``${NAME}.pwpb`` - Generated C++ pw_protobuf code
326* ``${NAME}.nanopb`` - Generated C++ nanopb code (requires Nanopb)
327* ``${NAME}.nanopb_rpc`` - Generated C++ Nanopb pw_rpc code (requires Nanopb)
328* ``${NAME}.raw_rpc`` - Generated C++ raw pw_rpc code (no protobuf library)
329
Nathaniel Brough9d9a20d2020-08-04 16:46:56 +0800330Bazel
331=====
332Bazel provides a ``pw_proto_library`` rule with similar features as the
333GN template. The Bazel build only supports building firmware code, so
334``pw_proto_library`` does not generate a Python package. The Bazel rules differ
335slightly compared to the GN build to be more in line with what would be
336considered idiomatic in Bazel.
337
338To use Pigweeds Protobuf rules you must first pull in the required dependencies
339into your Bazel WORKSPACE file. e.g.
340
341.. code-block:: python
342
343 # WORKSPACE ...
344 load("@pigweed//pw_protobuf_compiler:deps.bzl", "pw_protobuf_dependencies")
345 pw_protobuf_dependencies()
346
347Bazel uses a different set of rules to manage proto files than it does to
348compile them. e.g.
349
350.. code-block:: python
351
352 # BUILD ...
353 load("@rules_proto//proto:defs.bzl", "proto_library")
354 load("@pigweed//pw_protobuf_compiler:proto.bzl", "pw_proto_library")
355
356 # Manages proto sources and dependencies.
357 proto_library(
358 name = "my_proto",
359 srcs = [
360 "my_protos/foo.proto",
361 "my_protos/bar.proto",
362 ]
363 )
364
365 # Compiles dependant protos to C++.
366 pw_proto_library(
367 name = "my_cc_proto",
368 deps = [":my_proto"],
369 )
370
371 # Library that depends on generated proto targets.
372 pw_cc_library(
373 name = "my_lib",
374 srcs = ["my/lib.cc"],
375 deps = [":my_cc_proto"],
376 )
377
378From ``my/lib.cc`` you can now include the generated headers.
379e.g.
380
381.. code:: cpp
382
Armando Montanez377a68c2021-05-13 15:53:13 -0700383 #include "my_protos/bar.pwpb.h"
Nathaniel Broughb4f4e7a2021-05-06 14:49:55 +0800384 // and/or RPC headers
385 #include "my_protos/bar.raw_rpc.pb.h
386
387.. note::
388
389 Currently only raw RPC is supported by the Bazel build.
Armando Montanez377a68c2021-05-13 15:53:13 -0700390
391**Supported Codegen**
392
393Bazel supports the following compiled proto libraries via the specified
394sub-targets generated by a ``pw_proto_library``.
395
396* ``${NAME}.pwpb`` - Generated C++ pw_protobuf code
Armando Montanez377a68c2021-05-13 15:53:13 -0700397* ``${NAME}.raw_rpc`` - Generated C++ raw pw_rpc code (no protobuf library)
Nathaniel Broughb4f4e7a2021-05-06 14:49:55 +0800398