blob: c6348c942014129cad6acf7df1e47da774b1a7ea [file] [log] [blame]
Alexei Frolove19ebb82020-05-14 17:21:20 -07001# Copyright 2020 The Pigweed Authors
Alexei Frolov942adf02019-12-11 17:07:28 -08002#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
Armando Montanezfb3d3fb2020-06-09 18:12:12 -070015import("//build_overrides/pigweed.gni")
16
Alexei Frolovb499d3f2020-10-28 13:00:08 -070017import("$dir_pw_build/error.gni")
Alexei Frolov05d8ef22020-06-08 10:32:29 -070018import("$dir_pw_build/input_group.gni")
Wyatt Hepler752d7d32021-03-02 09:02:23 -080019import("$dir_pw_build/mirror_tree.gni")
Alexei Frolova4c0aee2020-12-01 13:48:48 -080020import("$dir_pw_build/python.gni")
Wyatt Hepler51ded742020-10-19 14:45:27 -070021import("$dir_pw_build/python_action.gni")
Alexei Frolovedd2f142020-06-09 19:11:27 -070022import("$dir_pw_build/target_types.gni")
Alexei Frolovdd6fa5c2020-08-11 10:04:01 -070023import("$dir_pw_third_party/nanopb/nanopb.gni")
Wyatt Heplerf6f74f42021-04-13 19:26:20 -070024import("toolchain.gni")
Wyatt Heplerd49f8fe2020-10-15 10:13:47 -070025
Wyatt Heplerd9336a42020-11-10 09:47:30 -080026# Variables forwarded from the public pw_proto_library template to the final
27# pw_source_set.
Wyatt Heplere0c4fdc2020-05-29 17:26:19 -070028_forwarded_vars = [
29 "testonly",
30 "visibility",
31]
32
Wyatt Heplerd9336a42020-11-10 09:47:30 -080033# Internal template that invokes protoc with a pw_python_action. This should not
34# be used outside of this file; use pw_proto_library instead.
35#
36# This creates the internal GN target $target_name.$language._gen that compiles
37# proto files with protoc.
38template("_pw_invoke_protoc") {
Wyatt Heplerf6f74f42021-04-13 19:26:20 -070039 if (current_toolchain == pw_protobuf_compiler_TOOLCHAIN) {
Wyatt Heplera0377642021-03-09 08:37:10 -080040 if (defined(invoker.out_dir)) {
41 _out_dir = invoker.out_dir
Wyatt Hepler752d7d32021-03-02 09:02:23 -080042 } else {
Wyatt Heplera0377642021-03-09 08:37:10 -080043 _out_dir = "${invoker.base_out_dir}/${invoker.language}"
44 if (defined(invoker.module_as_package) &&
45 invoker.module_as_package != "") {
46 assert(invoker.language == "python")
47 _out_dir = "$_out_dir/${invoker.module_as_package}"
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -080048 }
49 }
Wyatt Heplera0377642021-03-09 08:37:10 -080050
51 _includes =
52 rebase_path(get_target_outputs(":${invoker.base_target}._includes"))
53
54 pw_python_action("$target_name._gen") {
55 script =
56 "$dir_pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py"
57
58 python_deps = [ "$dir_pw_protobuf_compiler/py" ]
59 if (defined(invoker.python_deps)) {
60 python_deps += invoker.python_deps
61 }
62
63 deps = [
64 ":${invoker.base_target}._includes",
65 ":${invoker.base_target}._sources",
66 ]
67
68 foreach(dep, invoker.deps) {
69 deps += [ get_label_info(dep, "label_no_toolchain") + "._gen" ]
70 }
71
72 args = [
73 "--language",
74 invoker.language,
75 "--include-file",
76 _includes[0],
77 "--compile-dir",
78 rebase_path(invoker.compile_dir),
79 "--out-dir",
80 rebase_path(_out_dir),
81 "--sources",
82 ] + rebase_path(invoker.sources)
83
84 if (defined(invoker.plugin)) {
85 inputs = [ invoker.plugin ]
86 args += [ "--plugin-path=" + rebase_path(invoker.plugin) ]
87 }
88
89 if (defined(invoker.outputs)) {
90 outputs = invoker.outputs
91 } else {
92 stamp = true
93 }
94
95 if (defined(invoker.metadata)) {
96 metadata = invoker.metadata
97 } else {
98 metadata = {
99 protoc_outputs = rebase_path(outputs)
100 root = [ rebase_path(_out_dir) ]
101 }
102 }
103 }
104 } else {
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700105 # protoc is only ever invoked from pw_protobuf_compiler_TOOLCHAIN.
Wyatt Heplera0377642021-03-09 08:37:10 -0800106 not_needed([ "target_name" ])
107 not_needed(invoker, "*")
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800108 }
109}
110
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700111# Generates pw_protobuf C++ code for proto files, creating a source_set of the
112# generated files. This is internal and should not be used outside of this file.
113# Use pw_proto_library instead.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700114template("_pw_pwpb_proto_library") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800115 _pw_invoke_protoc(target_name) {
116 forward_variables_from(invoker, "*", _forwarded_vars)
117 language = "pwpb"
118 plugin = "$dir_pw_protobuf/py/pw_protobuf/plugin.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800119 python_deps = [ "$dir_pw_protobuf/py" ]
Alexei Frolov942adf02019-12-11 17:07:28 -0800120 }
121
122 # Create a library with the generated source files.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800123 config("$target_name._include_path") {
124 include_dirs = [ "${invoker.base_out_dir}/pwpb" ]
125 visibility = [ ":*" ]
126 }
127
Alexei Frolovedd2f142020-06-09 19:11:27 -0700128 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800129 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800130 public_configs = [ ":$target_name._include_path" ]
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700131 deps = [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800132 public_deps = [ dir_pw_protobuf ] + invoker.deps
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800133 sources = invoker.outputs
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700134 public = filter_include(sources, [ "*.pwpb.h" ])
135 }
136}
137
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700138# Generates nanopb RPC code for proto files, creating a source_set of the
139# generated files. This is internal and should not be used outside of this file.
140# Use pw_proto_library instead.
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700141template("_pw_nanopb_rpc_proto_library") {
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700142 # Create a target which runs protoc configured with the nanopb_rpc plugin to
143 # generate the C++ proto RPC headers.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800144 _pw_invoke_protoc(target_name) {
145 forward_variables_from(invoker, "*", _forwarded_vars)
146 language = "nanopb_rpc"
147 plugin = "$dir_pw_rpc/py/pw_rpc/plugin_nanopb.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800148 python_deps = [ "$dir_pw_rpc/py" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700149 }
150
151 # Create a library with the generated source files.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800152 config("$target_name._include_path") {
153 include_dirs = [ "${invoker.base_out_dir}/nanopb_rpc" ]
154 visibility = [ ":*" ]
155 }
156
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700157 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800158 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800159 public_configs = [ ":$target_name._include_path" ]
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700160 deps = [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700161 public_deps = [
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800162 ":${invoker.base_target}.nanopb",
Wyatt Heplercbd09c22020-09-15 11:17:24 -0700163 "$dir_pw_rpc:server",
Alexei Frolova4d71502020-10-14 12:43:14 -0700164 "$dir_pw_rpc/nanopb:method_union",
Alexei Frolovdd6fa5c2020-08-11 10:04:01 -0700165 "$dir_pw_third_party/nanopb",
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800166 ] + invoker.deps
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800167 public = invoker.outputs
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700168 }
169}
170
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700171# Generates nanopb code for proto files, creating a source_set of the generated
172# files. This is internal and should not be used outside of this file. Use
173# pw_proto_library instead.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700174template("_pw_nanopb_proto_library") {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800175 # When compiling with the Nanopb plugin, the nanopb.proto file is already
176 # compiled internally, so skip recompiling it with protoc.
177 if (rebase_path(invoker.sources, invoker.compile_dir) == [ "nanopb.proto" ]) {
178 group("$target_name._gen") {
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700179 deps = [
180 ":${invoker.base_target}._sources($pw_protobuf_compiler_TOOLCHAIN)",
181 ]
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800182 }
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700183
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800184 group("$target_name") {
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700185 deps = invoker.deps +
186 [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800187 }
188 } else {
189 # Create a target which runs protoc configured with the nanopb plugin to
190 # generate the C proto sources.
191 _pw_invoke_protoc(target_name) {
192 forward_variables_from(invoker, "*", _forwarded_vars)
193 language = "nanopb"
194 plugin = "$dir_pw_third_party_nanopb/generator/protoc-gen-nanopb"
195 }
196
197 # Create a library with the generated source files.
198 config("$target_name._include_path") {
199 include_dirs = [ "${invoker.base_out_dir}/nanopb" ]
200 visibility = [ ":*" ]
201 }
202
203 pw_source_set(target_name) {
204 forward_variables_from(invoker, _forwarded_vars)
205 public_configs = [ ":$target_name._include_path" ]
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700206 deps = [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800207 public_deps = [ "$dir_pw_third_party/nanopb" ] + invoker.deps
208 sources = invoker.outputs
209 public = filter_include(sources, [ "*.pb.h" ])
210 }
Alexei Frolov942adf02019-12-11 17:07:28 -0800211 }
212}
213
Alexei Frolovc912ea72020-10-26 08:43:27 -0700214# Generates raw RPC code for proto files, creating a source_set of the generated
215# files. This is internal and should not be used outside of this file. Use
216# pw_proto_library instead.
Alexei Frolovc912ea72020-10-26 08:43:27 -0700217template("_pw_raw_rpc_proto_library") {
Alexei Frolovc912ea72020-10-26 08:43:27 -0700218 # Create a target which runs protoc configured with the nanopb_rpc plugin to
219 # generate the C++ proto RPC headers.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800220 _pw_invoke_protoc(target_name) {
221 forward_variables_from(invoker, "*", _forwarded_vars)
222 language = "raw_rpc"
223 plugin = "$dir_pw_rpc/py/pw_rpc/plugin_raw.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800224 python_deps = [ "$dir_pw_rpc/py" ]
Alexei Frolovc912ea72020-10-26 08:43:27 -0700225 }
226
227 # Create a library with the generated source files.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800228 config("$target_name._include_path") {
229 include_dirs = [ "${invoker.base_out_dir}/raw_rpc" ]
230 visibility = [ ":*" ]
231 }
232
Alexei Frolovc912ea72020-10-26 08:43:27 -0700233 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800234 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800235 public_configs = [ ":$target_name._include_path" ]
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700236 deps = [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Alexei Frolovc912ea72020-10-26 08:43:27 -0700237 public_deps = [
238 "$dir_pw_rpc:server",
239 "$dir_pw_rpc/raw:method_union",
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800240 ] + invoker.deps
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800241 public = invoker.outputs
Alexei Frolovc912ea72020-10-26 08:43:27 -0700242 }
243}
244
Alexei Frolovdef14712019-12-23 13:03:32 -0800245# Generates Go code for proto files, listing the proto output directory in the
246# metadata variable GOPATH. Internal use only.
Alexei Frolovdef14712019-12-23 13:03:32 -0800247template("_pw_go_proto_library") {
248 _proto_gopath = "$root_gen_dir/go"
Alexei Frolovdef14712019-12-23 13:03:32 -0800249
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800250 _pw_invoke_protoc(target_name) {
251 forward_variables_from(invoker, "*")
252 language = "go"
Alexei Frolovdef14712019-12-23 13:03:32 -0800253 metadata = {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800254 gopath = [ "GOPATH+=" + rebase_path(_proto_gopath) ]
Alexei Frolovc15a9882019-12-23 14:29:02 -0800255 external_deps = [
256 "github.com/golang/protobuf/proto",
257 "google.golang.org/grpc",
258 ]
Alexei Frolovdef14712019-12-23 13:03:32 -0800259 }
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800260
261 # Override the default "$base_out_dir/$language" output path.
262 out_dir = "$_proto_gopath/src"
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800263 }
264
265 group(target_name) {
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700266 deps =
267 invoker.deps + [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Alexei Frolovdef14712019-12-23 13:03:32 -0800268 }
269}
270
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800271# Generates Python code for proto files, creating a pw_python_package containing
272# the generated files. This is internal and should not be used outside of this
273# file. Use pw_proto_library instead.
274template("_pw_python_proto_library") {
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800275 _pw_invoke_protoc(target_name) {
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800276 forward_variables_from(invoker, "*", _forwarded_vars + [ "python_package" ])
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800277 language = "python"
Wyatt Hepler4b921c12021-03-05 15:33:29 -0800278 python_deps = [ "$dir_pw_protobuf_compiler:protobuf_requirements" ]
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800279 }
280
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800281 if (defined(invoker.python_package) && invoker.python_package != "") {
282 # If nested in a Python package, write the package's name to a file so
283 # pw_python_package can check that the dependencies are correct.
284 write_file("${invoker.base_out_dir}/python_package.txt",
285 get_label_info(invoker.python_package, "label_no_toolchain"))
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800286
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800287 # If anyone attempts to depend on this Python package, print an error.
288 pw_error(target_name) {
289 _pkg = get_label_info(invoker.python_package, "label_no_toolchain")
290 message_lines = [
291 "This proto Python package is embedded in the $_pkg Python package.",
292 "It cannot be used directly; instead, depend on $_pkg.",
293 ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800294 }
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800295 foreach(subtarget, pw_python_package_subtargets) {
296 group("$target_name.$subtarget") {
297 deps = [ ":${invoker.target_name}" ]
298 }
299 }
300 } else {
301 write_file("${invoker.base_out_dir}/python_package.txt", "")
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800302
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800303 # Create a Python package with the generated source files.
304 pw_python_package(target_name) {
305 forward_variables_from(invoker, _forwarded_vars)
306 generate_setup = {
307 name = invoker._package_dir
308 version = "0.0.1" # TODO(hepler): Need to be able to set this verison.
309 }
310 sources = invoker.outputs
311 strip_prefix = "${invoker.base_out_dir}/python"
312 python_deps = invoker.deps
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700313 other_deps = [ ":$target_name._gen($pw_protobuf_compiler_TOOLCHAIN)" ]
Wyatt Heplerc2ce5242021-03-17 08:42:14 -0700314 static_analysis = []
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800315
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800316 _pw_module_as_package = invoker.module_as_package != ""
317 }
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800318 }
319}
320
Alexei Frolov942adf02019-12-11 17:07:28 -0800321# Generates protobuf code from .proto definitions for various languages.
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700322# For each supported generator, creates a sub-target named:
Alexei Frolov942adf02019-12-11 17:07:28 -0800323#
Alexei Frolov8e30d462020-10-22 13:54:36 -0700324# <target_name>.<generator>
Alexei Frolov942adf02019-12-11 17:07:28 -0800325#
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700326# GN permits using abbreviated labels when the target name matches the directory
327# name (e.g. //foo for //foo:foo). For consistency with this, the sub-targets
328# for each generator are aliased to the directory when the target name is the
329# same. For example, these two labels are equivalent:
330#
331# //path/to/my_protos:my_protos.pwpb
332# //path/to/my_protos:pwpb
333#
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800334# pw_protobuf_library targets generate Python packages. As such, they must have
335# globally unique package names. The first directory of the prefix or the first
336# common directory of the sources is used as the Python package.
337#
Alexei Frolov942adf02019-12-11 17:07:28 -0800338# Args:
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800339# sources: List of input .proto files.
340# deps: List of other pw_proto_library dependencies.
341# inputs: Other files on which the protos depend (e.g. nanopb .options files).
342# prefix: A prefix to add to the source protos prior to compilation. For
343# example, a source called "foo.proto" with prefix = "nested" will be
344# compiled with protoc as "nested/foo.proto".
345# strip_prefix: Remove this prefix from the source protos. All source and
346# input files must be nested under this path.
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700347# python_package: Label of Python package to which to add the proto modules.
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700348#
Alexei Frolov942adf02019-12-11 17:07:28 -0800349template("pw_proto_library") {
350 assert(defined(invoker.sources) && invoker.sources != [],
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700351 "pw_proto_library requires .proto source files")
Alexei Frolov942adf02019-12-11 17:07:28 -0800352
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800353 if (defined(invoker.python_module_as_package)) {
354 _module_as_package = invoker.python_module_as_package
355
356 _must_be_one_source = invoker.sources
357 assert([ _must_be_one_source[0] ] == _must_be_one_source,
358 "'python_module_as_package' requires exactly one source file")
359 assert(_module_as_package != "",
360 "'python_module_as_package' cannot be be empty")
361 assert(string_split(_module_as_package, "/") == [ _module_as_package ],
362 "'python_module_as_package' cannot contain slashes")
363 assert(!defined(invoker.prefix),
364 "'prefix' cannot be provided with 'python_module_as_package'")
365 } else {
366 _module_as_package = ""
367 }
368
369 if (defined(invoker.strip_prefix)) {
370 _source_root = get_path_info(invoker.strip_prefix, "abspath")
371 } else {
372 _source_root = get_path_info(".", "abspath")
373 }
374
375 if (defined(invoker.prefix)) {
376 _prefix = invoker.prefix
377 } else {
378 _prefix = ""
379 }
380
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800381 _common = {
382 base_target = target_name
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800383
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800384 # This is the output directory for all files related to this proto library.
385 # Sources are mirrored to "$base_out_dir/sources" and protoc puts outputs in
386 # "$base_out_dir/$language" by default.
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800387 base_out_dir =
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700388 get_label_info(":$target_name($pw_protobuf_compiler_TOOLCHAIN)",
389 "target_gen_dir") + "/$target_name.proto_library"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800390
391 compile_dir = "$base_out_dir/sources"
392
393 # Refer to the source files as the are mirrored to the output directory.
394 sources = []
395 foreach(file, rebase_path(invoker.sources, _source_root)) {
396 sources += [ "$compile_dir/$_prefix/$file" ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800397 }
398 }
399
Wyatt Hepler91741472021-02-03 08:45:10 -0800400 _package_dir = ""
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800401 _source_names = []
Wyatt Hepler91741472021-02-03 08:45:10 -0800402
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800403 # Determine the Python package name to use for these protos. If there is no
404 # prefix, the first directory the sources are nested under is used.
405 foreach(source, rebase_path(invoker.sources, _source_root)) {
Wyatt Hepler91741472021-02-03 08:45:10 -0800406 _path_components = []
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800407 _path_components = string_split(source, "/")
Wyatt Hepler91741472021-02-03 08:45:10 -0800408
409 if (_package_dir == "") {
410 _package_dir = _path_components[0]
411 } else {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800412 assert(_prefix != "" || _path_components[0] == _package_dir,
413 "Unless 'prefix' is supplied, all .proto sources in a " +
414 "pw_proto_library must be in the same directory tree")
Wyatt Hepler91741472021-02-03 08:45:10 -0800415 }
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800416
417 _source_names +=
418 [ get_path_info(source, "dir") + "/" + get_path_info(source, "name") ]
Wyatt Hepler91741472021-02-03 08:45:10 -0800419 }
420
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800421 # If the 'prefix' was supplied, use that for the package directory.
422 if (_prefix != "") {
423 _prefix_path_components = string_split(_prefix, "/")
424 _package_dir = _prefix_path_components[0]
425 }
426
427 assert(_package_dir != "" && _package_dir != "." && _package_dir != "..",
428 "Either a 'prefix' must be specified or all sources must be nested " +
429 "under a common directory")
430
431 # Define an action that is never executed to prevent duplicate proto packages
432 # from being declared. The target name and the output file include only the
433 # package directory, so different targets that use the same proto package name
434 # will conflict.
435 action("pw_proto_library.$_package_dir") {
436 script = "$dir_pw_build/py/pw_build/nop.py"
Wyatt Hepler91741472021-02-03 08:45:10 -0800437 visibility = []
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800438
439 # Place an error message in the output path (which is never created). If the
440 # package name conflicts occur in different BUILD.gn files, this results in
441 # an otherwise cryptic Ninja error, rather than a GN error.
442 outputs = [ "$root_out_dir/ " +
443 "ERROR - Multiple pw_proto_library targets create the " +
444 "'$_package_dir' package. Change the package name by setting " +
445 "the \"prefix\" arg or move the protos to a different " +
446 "directory, then re-run gn gen." ]
Wyatt Hepler91741472021-02-03 08:45:10 -0800447 }
448
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800449 if (defined(invoker.deps)) {
450 _deps = invoker.deps
451 } else {
452 _deps = []
453 }
454
Alexei Frolove19ebb82020-05-14 17:21:20 -0700455 # For each proto target, create a file which collects the base directories of
456 # all of its dependencies to list as include paths to protoc.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800457 generated_file("$target_name._includes") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800458 # Collect metadata from the include path files of each dependency.
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700459
460 deps = []
461 foreach(dep, _deps) {
462 _base = get_label_info(dep, "label_no_toolchain")
463 deps += [ "$_base._includes(" + get_label_info(dep, "toolchain") + ")" ]
464 }
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800465
Alexei Frolove19ebb82020-05-14 17:21:20 -0700466 data_keys = [ "protoc_includes" ]
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800467 outputs = [ "${_common.base_out_dir}/includes.txt" ]
Alexei Frolove19ebb82020-05-14 17:21:20 -0700468
469 # Indicate this library's base directory for its dependents.
470 metadata = {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800471 protoc_includes = [ rebase_path(_common.compile_dir) ]
Alexei Frolove19ebb82020-05-14 17:21:20 -0700472 }
473 }
474
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800475 # Mirror the proto sources to the output directory with the prefix added.
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700476 if (current_toolchain == pw_protobuf_compiler_TOOLCHAIN) {
477 pw_mirror_tree("$target_name._sources") {
478 source_root = _source_root
479 sources = invoker.sources
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700480
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700481 if (defined(invoker.inputs)) {
482 sources += invoker.inputs
483 }
484
485 directory = "${_common.compile_dir}/$_prefix"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800486 }
Wyatt Heplerf6f74f42021-04-13 19:26:20 -0700487 } else {
488 not_needed(invoker, [ "inputs" ])
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700489 }
490
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700491 # Enumerate all of the protobuf generator targets.
Alexei Frolovc4b62ec2020-07-13 08:35:10 -0700492
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800493 _pw_pwpb_proto_library("$target_name.pwpb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700494 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800495 forward_variables_from(_common, "*")
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800496
497 deps = []
498 foreach(dep, _deps) {
499 _base = get_label_info(dep, "label_no_toolchain")
500 deps += [ "$_base.pwpb(" + get_label_info(dep, "toolchain") + ")" ]
501 }
502
503 outputs = []
504 foreach(name, _source_names) {
505 outputs += [ "$base_out_dir/pwpb/$_prefix/${name}.pwpb.h" ]
506 }
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700507 }
508
509 if (dir_pw_third_party_nanopb != "") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800510 _pw_nanopb_rpc_proto_library("$target_name.nanopb_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700511 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800512 forward_variables_from(_common, "*")
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800513
514 deps = []
515 foreach(dep, _deps) {
516 _lbl = get_label_info(dep, "label_no_toolchain")
517 deps += [ "$_lbl.nanopb_rpc(" + get_label_info(dep, "toolchain") + ")" ]
518 }
519
520 outputs = []
521 foreach(name, _source_names) {
522 outputs += [ "$base_out_dir/nanopb_rpc/$_prefix/${name}.rpc.pb.h" ]
523 }
Alexei Frolovc4b62ec2020-07-13 08:35:10 -0700524 }
525
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800526 _pw_nanopb_proto_library("$target_name.nanopb") {
527 forward_variables_from(invoker, _forwarded_vars)
528 forward_variables_from(_common, "*")
529
530 deps = []
531 foreach(dep, _deps) {
532 _base = get_label_info(dep, "label_no_toolchain")
533 deps += [ "$_base.nanopb(" + get_label_info(dep, "toolchain") + ")" ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800534 }
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800535
536 outputs = []
537 foreach(name, _source_names) {
538 outputs += [
539 "$base_out_dir/nanopb/$_prefix/${name}.pb.h",
540 "$base_out_dir/nanopb/$_prefix/${name}.pb.c",
541 ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800542 }
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700543 }
544 } else {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800545 pw_error("$target_name.nanopb_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700546 message =
547 "\$dir_pw_third_party_nanopb must be set to generate nanopb RPC code."
Alexei Frolov8185c822020-06-12 10:45:04 -0700548 }
Alexei Frolov942adf02019-12-11 17:07:28 -0800549
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800550 pw_error("$target_name.nanopb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700551 message =
552 "\$dir_pw_third_party_nanopb must be set to compile nanopb protobufs."
Alexei Frolov942adf02019-12-11 17:07:28 -0800553 }
554 }
555
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800556 _pw_raw_rpc_proto_library("$target_name.raw_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700557 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800558 forward_variables_from(_common, "*")
559
560 deps = []
561 foreach(dep, _deps) {
562 _base = get_label_info(dep, "label_no_toolchain")
563 deps += [ "$_base.raw_rpc(" + get_label_info(dep, "toolchain") + ")" ]
564 }
565
566 outputs = []
567 foreach(name, _source_names) {
568 outputs += [ "$base_out_dir/raw_rpc/$_prefix/${name}.raw_rpc.pb.h" ]
569 }
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700570 }
571
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800572 _pw_go_proto_library("$target_name.go") {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800573 sources = _common.sources
574
575 deps = []
576 foreach(dep, _deps) {
577 _base = get_label_info(dep, "label_no_toolchain")
578 deps += [ "$_base.go(" + get_label_info(dep, "toolchain") + ")" ]
579 }
580
581 forward_variables_from(_common, "*")
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700582 }
583
Alexei Frolov38cad0c2020-12-03 12:36:24 -0800584 _pw_python_proto_library("$target_name.python") {
Alexei Frolov38cad0c2020-12-03 12:36:24 -0800585 forward_variables_from(_common, "*")
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800586 forward_variables_from(invoker, [ "python_package" ])
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800587 module_as_package = _module_as_package
588
589 deps = []
590 foreach(dep, _deps) {
591 _base = get_label_info(dep, "label_no_toolchain")
592 deps += [ "$_base.python(" + get_label_info(dep, "toolchain") + ")" ]
593 }
594
595 if (module_as_package == "") {
596 _python_prefix = "$base_out_dir/python/$_prefix"
597 } else {
598 _python_prefix = "$base_out_dir/python/$module_as_package"
599 }
600
601 outputs = []
602 foreach(name, _source_names) {
603 outputs += [
604 "$_python_prefix/${name}_pb2.py",
605 "$_python_prefix/${name}_pb2.pyi",
606 ]
607 }
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800608 }
609
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700610 # All supported pw_protobuf generators.
611 _protobuf_generators = [
612 "pwpb",
613 "nanopb",
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700614 "nanopb_rpc",
Alexei Frolovc912ea72020-10-26 08:43:27 -0700615 "raw_rpc",
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700616 "go",
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800617 "python",
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700618 ]
619
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700620 # If the label matches the directory name, alias the subtargets to the
621 # directory (e.g. //foo:nanopb is an alias for //foo:foo.nanopb).
622 if (get_label_info(":$target_name", "name") ==
623 get_path_info(get_label_info(":$target_name", "dir"), "name")) {
Wyatt Hepler2c6c0ba2021-04-07 09:50:23 -0700624 foreach(_generator, _protobuf_generators - [ "python" ]) {
625 group(_generator) {
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700626 public_deps = [ ":${invoker.target_name}.$_generator" ]
627 }
628 }
Wyatt Hepler2c6c0ba2021-04-07 09:50:23 -0700629
630 pw_python_group("python") {
631 python_deps = [ ":${invoker.target_name}.python" ]
632 }
Wyatt Hepler4cdc3e72021-03-24 08:41:08 -0700633 }
634
Alexei Frolov942adf02019-12-11 17:07:28 -0800635 # If the user attempts to use the target directly instead of one of the
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700636 # generator targets, run a script which prints a nice error message.
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700637 pw_python_action(target_name) {
Alexei Frolov942adf02019-12-11 17:07:28 -0800638 script = string_join("/",
639 [
640 dir_pw_protobuf_compiler,
641 "py",
642 "pw_protobuf_compiler",
643 "proto_target_invalid.py",
644 ])
645 args = [
646 "--target",
647 target_name,
648 "--dir",
649 get_path_info(".", "abspath"),
650 "--root",
651 "//",
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700652 ] + _protobuf_generators
Alexei Frolov942adf02019-12-11 17:07:28 -0800653 stamp = true
654 }
655}