pw_protobuf: Add support for imports
This updates the protobuf codegen to support importing external .proto
files, and the GN proto build to set include directories for proto
dependencies.
Change-Id: I28f4884935a266b1b40de1935ab67af9cad44e11
diff --git a/pw_protobuf_compiler/proto.gni b/pw_protobuf_compiler/proto.gni
index 97ac763..ee2e2dd 100644
--- a/pw_protobuf_compiler/proto.gni
+++ b/pw_protobuf_compiler/proto.gni
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 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
@@ -26,9 +26,14 @@
# protos: List of input .proto files.
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}}.pwpb.h")
+ _module_path = get_path_info(".", "abspath")
+ _relative_proto_paths = rebase_path(invoker.protos, _module_path)
+
+ _outputs = []
+ foreach(_proto, _relative_proto_paths) {
+ _output = string_replace(_proto, ".proto", ".pwpb.h")
+ _outputs += [ "$_proto_gen_dir/$_output" ]
+ }
_gen_target = "${target_name}_gen"
pw_python_script(_gen_target) {
@@ -37,34 +42,33 @@
"--language",
"cc",
"--module-path",
- "//",
+ _module_path,
+ "--include-file",
+ invoker.include_file,
"--out-dir",
_proto_gen_dir,
] + get_path_info(invoker.protos, "abspath")
inputs = invoker.protos
outputs = _outputs
-
+ deps = invoker.deps
if (defined(invoker.protoc_deps)) {
- deps = 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/$_include_root" ]
+ include_dirs = [ "$_proto_gen_dir" ]
}
# 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
- public_deps = [ dir_pw_protobuf ]
+ deps = [ ":$_gen_target" ]
+ public_deps = [ dir_pw_protobuf ] + invoker.gen_deps
sources = get_target_outputs(":$_gen_target")
public = filter_include(sources, [ "*.pwpb.h" ])
}
@@ -81,12 +85,18 @@
"\$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",
- ])
+ _module_path = get_path_info(".", "abspath")
+ _relative_proto_paths = rebase_path(invoker.protos, _module_path)
+
+ _outputs = []
+ foreach(_proto, _relative_proto_paths) {
+ _output_h = string_replace(_proto, ".proto", ".pb.h")
+ _output_c = string_replace(_proto, ".proto", ".pb.c")
+ _outputs += [
+ "$_proto_gen_dir/$_output_h",
+ "$_proto_gen_dir/$_output_c",
+ ]
+ }
_nanopb_plugin = "$dir_third_party_nanopb/generator/protoc-gen-nanopb"
if (host_os == "win") {
@@ -102,9 +112,11 @@
"--language",
"nanopb",
"--module-path",
- "//",
+ _module_path,
"--include-paths",
"$dir_third_party_nanopb/generator/proto",
+ "--include-file",
+ invoker.include_file,
"--out-dir",
_proto_gen_dir,
"--custom-plugin",
@@ -113,8 +125,9 @@
inputs = invoker.protos
outputs = _outputs
+ deps = invoker.deps
if (defined(invoker.protoc_deps)) {
- deps = invoker.protoc_deps
+ deps += invoker.protoc_deps
}
}
@@ -133,11 +146,8 @@
# 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,
- ]
+ deps = [ ":$_gen_target" ]
+ public_deps = [ dir_third_party_nanopb ] + invoker.gen_deps
sources = get_target_outputs(":$_gen_target")
public = filter_include(sources, [ "*.pb.h" ])
}
@@ -167,11 +177,13 @@
"go",
"--module-path",
"//",
+ "--include-file",
+ invoker.include_file,
"--out-dir",
_proto_gen_dir,
] + get_path_info(invoker.protos, "abspath")
inputs = invoker.protos
- deps = invoker.deps
+ deps = invoker.deps + invoker.gen_deps
stamp = true
}
}
@@ -203,18 +215,40 @@
assert(defined(invoker.sources) && invoker.sources != [],
"pw_proto_codegen requires .proto source files")
- foreach(_gen, pw_protobuf_generators) {
+ # For each proto target, create a file which collects the base directories of
+ # all of its dependencies to list as include paths to protoc.
+ _include_metadata_target = "${target_name}_include_paths"
+ _include_metadata_file = "${target_gen_dir}/${target_name}_includes.txt"
+ generated_file(_include_metadata_target) {
if (defined(invoker.deps)) {
- _gen_deps = process_file_template(invoker.deps, "{{source}}_${_gen}")
+ # Collect metadata from the include path files of each dependency.
+ deps = process_file_template(invoker.deps, "{{source}}_include_paths")
} else {
- _gen_deps = []
+ deps = []
}
+ data_keys = [ "protoc_includes" ]
+ outputs = [ _include_metadata_file ]
+
+ # Indicate this library's base directory for its dependents.
+ metadata = {
+ protoc_includes = [ rebase_path(".", root_out_dir) ]
+ }
+ }
+
+ foreach(_gen, pw_protobuf_generators) {
_lang_target = "${target_name}_${_gen}"
if (_gen == "pwpb") {
+ _gen_deps = []
+ if (defined(invoker.deps)) {
+ _gen_deps = process_file_template(invoker.deps, "{{source}}_${_gen}")
+ }
+
_pw_pwpb_proto_library(_lang_target) {
protos = invoker.sources
- deps = _gen_deps
+ deps = [ ":$_include_metadata_target" ]
+ include_file = _include_metadata_file
+ gen_deps = _gen_deps
# List the pw_protobuf plugin's files as a dependency to recompile
# generated code if they are modified.
@@ -223,12 +257,16 @@
} else if (_gen == "nanopb") {
_pw_nanopb_proto_library(_lang_target) {
protos = invoker.sources
- deps = _gen_deps
+ deps = [ ":$_include_metadata_target" ]
+ include_file = _include_metadata_file
+ gen_deps = _gen_deps
}
} else if (_gen == "go") {
_pw_go_proto_library(_lang_target) {
protos = invoker.sources
- deps = _gen_deps
+ deps = [ ":$_include_metadata_target" ]
+ include_file = _include_metadata_file
+ gen_deps = _gen_deps
}
} else {
assert(false,