pw_protobuf_compiler: nanopb support
This change adds support for compiling nanopb protobufs using
pw_protobuf_compiler.
The pw_protobuf_langs build variable is renamed to
pw_protobuf_generators as there is no longer a 1:1 mapping of languages.
To compile nanopb, add the "nanopb" generator to pw_protobuf_generators.
The build variable $dir_third_party_nanopb must be set to point to a
local installation of nanopb with GN support:
https://github.com/frolv/nanopb/tree/gn-build
The host build will run a test which compiles nanopb code if
$dir_third_party_nanopb is set.
Change-Id: I29bf8780644917f35203a538b0bd7e4f3ec40180
diff --git a/pw_protobuf_compiler/proto.gni b/pw_protobuf_compiler/proto.gni
index 59637ee..c03f11a 100644
--- a/pw_protobuf_compiler/proto.gni
+++ b/pw_protobuf_compiler/proto.gni
@@ -18,17 +18,17 @@
_gen_script_path =
"$dir_pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py"
-# Generates C++ code for proto files, creating a source_set of the generated
-# files. This is internal and should not be used outside of this file. Use
-# pw_proto_library instead.
+# Generates pw_protobuf C++ code for proto files, creating a source_set of the
+# generated files. This is internal and should not be used outside of this file.
+# Use pw_proto_library instead.
#
# Args:
# protos: List of input .proto files.
-template("_pw_cc_proto_library") {
+template("_pw_pwpb_proto_library") {
_proto_gen_dir = "$root_gen_dir/protos"
_outputs = process_file_template(
invoker.protos,
- "$_proto_gen_dir/{{source_root_relative_dir}}/{{source_name_part}}.pb.h")
+ "$_proto_gen_dir/{{source_root_relative_dir}}/{{source_name_part}}.pwpb.h")
_gen_target = "${target_name}_gen"
pw_python_script(_gen_target) {
@@ -65,6 +65,78 @@
all_dependent_configs = [ ":$_include_config_target" ]
deps = [ ":$_gen_target" ] + invoker.deps
sources = get_target_outputs(":$_gen_target")
+ public = filter_include(sources, [ "*.pwpb.h" ])
+ }
+}
+
+# Generates nanopb code for proto files, creating a source_set of the generated
+# files. This is internal and should not be used outside of this file. Use
+# pw_proto_library instead.
+#
+# Args:
+# protos: List of input .proto files.
+template("_pw_nanopb_proto_library") {
+ assert(defined(dir_third_party_nanopb) && dir_third_party_nanopb != "",
+ "\$dir_third_party_nanopb must be set to compile nanopb protobufs")
+
+ _proto_gen_dir = "$root_gen_dir/protos"
+ _outputs = process_file_template(
+ invoker.protos,
+ [
+ "$_proto_gen_dir/{{source_root_relative_dir}}/{{source_name_part}}.pb.h",
+ "$_proto_gen_dir/{{source_root_relative_dir}}/{{source_name_part}}.pb.c",
+ ])
+
+ _nanopb_plugin = "$dir_third_party_nanopb/generator/protoc-gen-nanopb"
+ if (host_os == "win") {
+ _nanopb_plugin += ".bat"
+ }
+
+ # Create a target which runs protoc configured with the nanopb plugin to
+ # generate the C proto sources.
+ _gen_target = "${target_name}_gen"
+ pw_python_script(_gen_target) {
+ script = _gen_script_path
+ args = [
+ "--language",
+ "nanopb",
+ "--module-path",
+ "//",
+ "--out-dir",
+ _proto_gen_dir,
+ "--custom-plugin",
+ get_path_info(_nanopb_plugin, "abspath"),
+ ] + get_path_info(invoker.protos, "abspath")
+ inputs = invoker.protos
+ outputs = _outputs
+
+ if (defined(invoker.protoc_deps)) {
+ deps = invoker.protoc_deps
+ }
+ }
+
+ # For C++ proto files, the generated proto directory is added as an include
+ # path for the code. This requires using "all_dependent_configs" to force the
+ # include on any code that transitively depends on the generated protos.
+ _include_root = rebase_path(get_path_info(".", "abspath"), "//")
+ _include_config_target = "${target_name}_includes"
+ config(_include_config_target) {
+ include_dirs = [
+ "$_proto_gen_dir",
+ "$_proto_gen_dir/$_include_root",
+ ]
+ }
+
+ # Create a library with the generated source files.
+ source_set(target_name) {
+ all_dependent_configs = [ ":$_include_config_target" ]
+ deps = invoker.deps
+ public_deps = [
+ ":$_gen_target",
+ dir_third_party_nanopb,
+ ]
+ sources = get_target_outputs(":$_gen_target")
+ public = filter_include(sources, [ "*.pb.h" ])
}
}
@@ -103,14 +175,14 @@
# Generates protobuf code from .proto definitions for various languages.
#
-# The languages to generate are defined in the pw_protobuf_langs build variable.
-# Each listed language creates a generated code target called
+# The generators to use are defined in the pw_protobuf_generators build
+# variable. Each listed generator creates a generated code target called
#
-# <target_name>_<language>
+# <target_name>_<generator>
#
# For example, with the following definitions:
#
-# pw_protobuf_langs = [ "cc", "py" ]
+# pw_protobuf_generators = [ "pwpb", "py" ]
#
# pw_proto_library("my_protos") {
# sources = [ "foo.proto" ]
@@ -118,45 +190,42 @@
#
# Two build targets will be created for the declared "my_protos" target.
#
-# "my_protos_cc" <-- C++ source_set containing generated proto code
-# "my_protos_py" <-- Python module containing generated proto code
+# "my_protos_pwpb" <-- C++ source_set containing generated proto code
+# "my_protos_py" <-- Python module containing generated proto code
#
# Args:
# sources: List of input .proto files.
# deps: List of other pw_proto_library dependencies.
-#
-# TODO(frolv): Provide a way to set the protoc plugin for different languages.
template("pw_proto_library") {
assert(defined(invoker.sources) && invoker.sources != [],
"pw_proto_codegen requires .proto source files")
- foreach(lang, pw_protobuf_langs) {
+ foreach(_gen, pw_protobuf_generators) {
if (defined(invoker.deps)) {
- _lang_deps = process_file_template(invoker.deps, "{{source}}_${lang}")
+ _gen_deps = process_file_template(invoker.deps, "{{source}}_${_gen}")
} else {
- _lang_deps = []
+ _gen_deps = []
}
- _lang_target = "${target_name}_${lang}"
+ _lang_target = "${target_name}_${_gen}"
- if (lang == "cc") {
- _pw_cc_proto_library(_lang_target) {
+ if (_gen == "pwpb") {
+ _pw_pwpb_proto_library(_lang_target) {
protos = invoker.sources
- deps = _lang_deps
+ deps = _gen_deps
# List the pw_protobuf plugin's files as a dependency to recompile
# generated code if they are modified.
- #
- # TODO(frolv): This check is currently true as pw_protobuf is the
- # only supported plugin. It should be updated to support other proto
- # libraries such as nanopb.
- if (true) {
- protoc_deps = [ "$dir_pw_protobuf:codegen_protoc_plugin" ]
- }
+ protoc_deps = [ "$dir_pw_protobuf:codegen_protoc_plugin" ]
}
- } else if (lang == "go") {
+ } else if (_gen == "nanopb") {
+ _pw_nanopb_proto_library(_lang_target) {
+ protos = invoker.sources
+ deps = _gen_deps
+ }
+ } else if (_gen == "go") {
_pw_go_proto_library(_lang_target) {
protos = invoker.sources
- deps = _lang_deps
+ deps = _gen_deps
}
} else {
assert(false,
@@ -164,13 +233,13 @@
" ",
[
"pw_proto_codegen doesn't know how to generate code for",
- "language '$lang'. Please add support if you require it.",
+ "generator '$_gen'. Please add support if you require it.",
]))
}
}
# If the user attempts to use the target directly instead of one of the
- # language targets, run a script which prints a nice error message.
+ # generator targets, run a script which prints a nice error message.
pw_python_script(target_name) {
script = string_join("/",
[
@@ -186,7 +255,7 @@
get_path_info(".", "abspath"),
"--root",
"//",
- ] + pw_protobuf_langs
+ ] + pw_protobuf_generators
stamp = true
}
}