Add pw_protobuf_compiler module
This change adds a module responsible for invoking the protobuf compiler
to generate code from .proto definition files. It provides a GN template
which performs the codegen operation on a list of input .proto files.
The template currently only supports C++.
Change-Id: I5558fd5b4282e0d6f09f8fafebda972738dc1e83
diff --git a/pw_protobuf_compiler/proto.gni b/pw_protobuf_compiler/proto.gni
new file mode 100644
index 0000000..d20679a
--- /dev/null
+++ b/pw_protobuf_compiler/proto.gni
@@ -0,0 +1,140 @@
+# Copyright 2019 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.
+
+import("$dir_pw_build/python_script.gni")
+
+# Python script that invokes protoc.
+_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.
+#
+# Args:
+# protos: List of input .proto files.
+template("_pw_cc_proto_library") {
+ _proto_gen_dir = "$root_gen_dir/protos"
+ _outputs = process_file_template(
+ invoker.protos,
+ "$root_gen_dir/protos/{{source_root_relative_dir}}/{{source_name_part}}.pb.h")
+
+ _gen_target = "${target_name}_gen"
+ pw_python_script(_gen_target) {
+ script = _gen_script_path
+ args = [
+ "--language",
+ "cc",
+ "--module-path",
+ "//",
+ "--out-dir",
+ _proto_gen_dir,
+ ] + get_path_info(invoker.protos, "abspath")
+ inputs = invoker.protos
+ outputs = _outputs
+ }
+
+ # 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/$_include_root" ]
+ }
+
+ # Create a library with the generated source files.
+ # TODO(frolv): This currently only supports pw_protobuf, which is header-only.
+ # Figure out how to support .cc files.
+ source_set(target_name) {
+ all_dependent_configs = [ ":$_include_config_target" ]
+ deps = [ ":$_gen_target" ] + invoker.deps
+ sources = get_target_outputs(":$_gen_target")
+ }
+}
+
+# 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
+#
+# <target_name>_<language>
+#
+# For example, with the following definitions:
+#
+# pw_protobuf_langs = [ "cc", "py" ]
+#
+# pw_proto_library("my_protos") {
+# sources = [ "foo.proto" ]
+# }
+#
+# 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
+#
+# 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) {
+ if (defined(invoker.deps)) {
+ _lang_deps = process_file_template(invoker.deps, "{{source}}_${lang}")
+ } else {
+ _lang_deps = []
+ }
+ _lang_target = "${target_name}_${lang}"
+
+ if (lang == "cc") {
+ _pw_cc_proto_library(_lang_target) {
+ protos = invoker.sources
+ deps = _lang_deps
+ }
+ } else {
+ assert(false,
+ string_join(
+ " ",
+ [
+ "pw_proto_codegen doesn't know how to generate code for",
+ "language '$lang'. 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.
+ pw_python_script(target_name) {
+ script = string_join("/",
+ [
+ dir_pw_protobuf_compiler,
+ "py",
+ "pw_protobuf_compiler",
+ "proto_target_invalid.py",
+ ])
+ args = [
+ "--target",
+ target_name,
+ "--dir",
+ get_path_info(".", "abspath"),
+ "--root",
+ "//",
+ ] + pw_protobuf_langs
+ stamp = true
+ }
+}