blob: c877b28a8abc93e3b8a2af354e7c468923475bcb [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 Heplerd49f8fe2020-10-15 10:13:47 -070024
Wyatt Heplerd9336a42020-11-10 09:47:30 -080025# Variables forwarded from the public pw_proto_library template to the final
26# pw_source_set.
Wyatt Heplere0c4fdc2020-05-29 17:26:19 -070027_forwarded_vars = [
28 "testonly",
29 "visibility",
30]
31
Wyatt Heplerd9336a42020-11-10 09:47:30 -080032# Internal template that invokes protoc with a pw_python_action. This should not
33# be used outside of this file; use pw_proto_library instead.
34#
35# This creates the internal GN target $target_name.$language._gen that compiles
36# proto files with protoc.
37template("_pw_invoke_protoc") {
Wyatt Hepler752d7d32021-03-02 09:02:23 -080038 if (defined(invoker.out_dir)) {
39 _out_dir = invoker.out_dir
40 } else {
41 _out_dir = "${invoker.base_out_dir}/${invoker.language}"
42 if (defined(invoker.module_as_package) && invoker.module_as_package != "") {
43 assert(invoker.language == "python")
44 _out_dir = "$_out_dir/${invoker.module_as_package}"
45 }
46 }
47
48 _includes =
49 rebase_path(get_target_outputs(":${invoker.base_target}._includes"))
Wyatt Heplerd9336a42020-11-10 09:47:30 -080050
51 pw_python_action("$target_name._gen") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -080052 script =
53 "$dir_pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py"
54
Wyatt Hepler438caa02021-01-15 17:13:11 -080055 python_deps = [ "$dir_pw_protobuf_compiler/py" ]
56 if (defined(invoker.python_deps)) {
57 python_deps += invoker.python_deps
58 }
59
Wyatt Heplerd9336a42020-11-10 09:47:30 -080060 deps = [
Wyatt Hepler752d7d32021-03-02 09:02:23 -080061 ":${invoker.base_target}._includes",
62 ":${invoker.base_target}._sources",
63 ]
64
65 foreach(dep, invoker.deps) {
66 deps += [ get_label_info(dep, "label_no_toolchain") + "._gen" ]
67 }
68
Wyatt Heplerd9336a42020-11-10 09:47:30 -080069 args = [
70 "--language",
71 invoker.language,
Wyatt Heplerd9336a42020-11-10 09:47:30 -080072 "--include-file",
Wyatt Hepler752d7d32021-03-02 09:02:23 -080073 _includes[0],
74 "--compile-dir",
75 rebase_path(invoker.compile_dir),
Wyatt Heplerd9336a42020-11-10 09:47:30 -080076 "--out-dir",
Wyatt Hepler752d7d32021-03-02 09:02:23 -080077 rebase_path(_out_dir),
78 "--sources",
Wyatt Heplerd9336a42020-11-10 09:47:30 -080079 ] + rebase_path(invoker.sources)
80
Wyatt Heplerd9336a42020-11-10 09:47:30 -080081 if (defined(invoker.plugin)) {
Wyatt Hepler752d7d32021-03-02 09:02:23 -080082 inputs = [ invoker.plugin ]
Wyatt Heplerd9336a42020-11-10 09:47:30 -080083 args += [ "--plugin-path=" + rebase_path(invoker.plugin) ]
84 }
85
Wyatt Hepler752d7d32021-03-02 09:02:23 -080086 if (defined(invoker.outputs)) {
87 outputs = invoker.outputs
88 } else {
Wyatt Heplerd9336a42020-11-10 09:47:30 -080089 stamp = true
90 }
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -080091
92 if (defined(invoker.metadata)) {
93 metadata = invoker.metadata
94 } else {
95 metadata = {
96 protoc_outputs = rebase_path(outputs)
97 root = [ rebase_path(_out_dir) ]
98 }
99 }
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800100 }
101}
102
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700103# Generates pw_protobuf C++ code for proto files, creating a source_set of the
104# generated files. This is internal and should not be used outside of this file.
105# Use pw_proto_library instead.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700106template("_pw_pwpb_proto_library") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800107 _pw_invoke_protoc(target_name) {
108 forward_variables_from(invoker, "*", _forwarded_vars)
109 language = "pwpb"
110 plugin = "$dir_pw_protobuf/py/pw_protobuf/plugin.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800111 python_deps = [ "$dir_pw_protobuf/py" ]
Alexei Frolov942adf02019-12-11 17:07:28 -0800112 }
113
114 # Create a library with the generated source files.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800115 config("$target_name._include_path") {
116 include_dirs = [ "${invoker.base_out_dir}/pwpb" ]
117 visibility = [ ":*" ]
118 }
119
Alexei Frolovedd2f142020-06-09 19:11:27 -0700120 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800121 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800122 public_configs = [ ":$target_name._include_path" ]
123 deps = [ ":$target_name._gen($default_toolchain)" ]
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800124 public_deps = [ dir_pw_protobuf ] + invoker.deps
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800125 sources = invoker.outputs
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700126 public = filter_include(sources, [ "*.pwpb.h" ])
127 }
128}
129
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700130# Generates nanopb RPC code for proto files, creating a source_set of the
131# generated files. This is internal and should not be used outside of this file.
132# Use pw_proto_library instead.
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700133template("_pw_nanopb_rpc_proto_library") {
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700134 # Create a target which runs protoc configured with the nanopb_rpc plugin to
135 # generate the C++ proto RPC headers.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800136 _pw_invoke_protoc(target_name) {
137 forward_variables_from(invoker, "*", _forwarded_vars)
138 language = "nanopb_rpc"
139 plugin = "$dir_pw_rpc/py/pw_rpc/plugin_nanopb.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800140 python_deps = [ "$dir_pw_rpc/py" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700141 }
142
143 # Create a library with the generated source files.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800144 config("$target_name._include_path") {
145 include_dirs = [ "${invoker.base_out_dir}/nanopb_rpc" ]
146 visibility = [ ":*" ]
147 }
148
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700149 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800150 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800151 public_configs = [ ":$target_name._include_path" ]
152 deps = [ ":$target_name._gen($default_toolchain)" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700153 public_deps = [
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800154 ":${invoker.base_target}.nanopb",
Wyatt Heplercbd09c22020-09-15 11:17:24 -0700155 "$dir_pw_rpc:server",
Alexei Frolova4d71502020-10-14 12:43:14 -0700156 "$dir_pw_rpc/nanopb:method_union",
Alexei Frolovdd6fa5c2020-08-11 10:04:01 -0700157 "$dir_pw_third_party/nanopb",
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800158 ] + invoker.deps
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800159 public = invoker.outputs
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700160 }
161}
162
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700163# Generates nanopb code for proto files, creating a source_set of the generated
164# files. This is internal and should not be used outside of this file. Use
165# pw_proto_library instead.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700166template("_pw_nanopb_proto_library") {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800167 # When compiling with the Nanopb plugin, the nanopb.proto file is already
168 # compiled internally, so skip recompiling it with protoc.
169 if (rebase_path(invoker.sources, invoker.compile_dir) == [ "nanopb.proto" ]) {
170 group("$target_name._gen") {
171 deps = [ ":${invoker.base_target}._sources" ]
172 }
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700173
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800174 group("$target_name") {
175 deps = invoker.deps + [ ":$target_name._gen($default_toolchain)" ]
176 }
177 } else {
178 # Create a target which runs protoc configured with the nanopb plugin to
179 # generate the C proto sources.
180 _pw_invoke_protoc(target_name) {
181 forward_variables_from(invoker, "*", _forwarded_vars)
182 language = "nanopb"
183 plugin = "$dir_pw_third_party_nanopb/generator/protoc-gen-nanopb"
184 }
185
186 # Create a library with the generated source files.
187 config("$target_name._include_path") {
188 include_dirs = [ "${invoker.base_out_dir}/nanopb" ]
189 visibility = [ ":*" ]
190 }
191
192 pw_source_set(target_name) {
193 forward_variables_from(invoker, _forwarded_vars)
194 public_configs = [ ":$target_name._include_path" ]
195 deps = [ ":$target_name._gen($default_toolchain)" ]
196 public_deps = [ "$dir_pw_third_party/nanopb" ] + invoker.deps
197 sources = invoker.outputs
198 public = filter_include(sources, [ "*.pb.h" ])
199 }
Alexei Frolov942adf02019-12-11 17:07:28 -0800200 }
201}
202
Alexei Frolovc912ea72020-10-26 08:43:27 -0700203# Generates raw RPC code for proto files, creating a source_set of the generated
204# files. This is internal and should not be used outside of this file. Use
205# pw_proto_library instead.
Alexei Frolovc912ea72020-10-26 08:43:27 -0700206template("_pw_raw_rpc_proto_library") {
Alexei Frolovc912ea72020-10-26 08:43:27 -0700207 # Create a target which runs protoc configured with the nanopb_rpc plugin to
208 # generate the C++ proto RPC headers.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800209 _pw_invoke_protoc(target_name) {
210 forward_variables_from(invoker, "*", _forwarded_vars)
211 language = "raw_rpc"
212 plugin = "$dir_pw_rpc/py/pw_rpc/plugin_raw.py"
Wyatt Hepler438caa02021-01-15 17:13:11 -0800213 python_deps = [ "$dir_pw_rpc/py" ]
Alexei Frolovc912ea72020-10-26 08:43:27 -0700214 }
215
216 # Create a library with the generated source files.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800217 config("$target_name._include_path") {
218 include_dirs = [ "${invoker.base_out_dir}/raw_rpc" ]
219 visibility = [ ":*" ]
220 }
221
Alexei Frolovc912ea72020-10-26 08:43:27 -0700222 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800223 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800224 public_configs = [ ":$target_name._include_path" ]
225 deps = [ ":$target_name._gen($default_toolchain)" ]
Alexei Frolovc912ea72020-10-26 08:43:27 -0700226 public_deps = [
227 "$dir_pw_rpc:server",
228 "$dir_pw_rpc/raw:method_union",
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800229 ] + invoker.deps
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800230 public = invoker.outputs
Alexei Frolovc912ea72020-10-26 08:43:27 -0700231 }
232}
233
Alexei Frolovdef14712019-12-23 13:03:32 -0800234# Generates Go code for proto files, listing the proto output directory in the
235# metadata variable GOPATH. Internal use only.
Alexei Frolovdef14712019-12-23 13:03:32 -0800236template("_pw_go_proto_library") {
237 _proto_gopath = "$root_gen_dir/go"
Alexei Frolovdef14712019-12-23 13:03:32 -0800238
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800239 _pw_invoke_protoc(target_name) {
240 forward_variables_from(invoker, "*")
241 language = "go"
Alexei Frolovdef14712019-12-23 13:03:32 -0800242 metadata = {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800243 gopath = [ "GOPATH+=" + rebase_path(_proto_gopath) ]
Alexei Frolovc15a9882019-12-23 14:29:02 -0800244 external_deps = [
245 "github.com/golang/protobuf/proto",
246 "google.golang.org/grpc",
247 ]
Alexei Frolovdef14712019-12-23 13:03:32 -0800248 }
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800249
250 # Override the default "$base_out_dir/$language" output path.
251 out_dir = "$_proto_gopath/src"
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800252 }
253
254 group(target_name) {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800255 deps = invoker.deps + [ ":$target_name._gen($default_toolchain)" ]
Alexei Frolovdef14712019-12-23 13:03:32 -0800256 }
257}
258
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800259# Generates Python code for proto files, creating a pw_python_package containing
260# the generated files. This is internal and should not be used outside of this
261# file. Use pw_proto_library instead.
262template("_pw_python_proto_library") {
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800263 _pw_invoke_protoc(target_name) {
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800264 forward_variables_from(invoker, "*", _forwarded_vars + [ "python_package" ])
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800265 language = "python"
Wyatt Hepler4b921c12021-03-05 15:33:29 -0800266 python_deps = [ "$dir_pw_protobuf_compiler:protobuf_requirements" ]
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800267 }
268
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800269 if (defined(invoker.python_package) && invoker.python_package != "") {
270 # If nested in a Python package, write the package's name to a file so
271 # pw_python_package can check that the dependencies are correct.
272 write_file("${invoker.base_out_dir}/python_package.txt",
273 get_label_info(invoker.python_package, "label_no_toolchain"))
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800274
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800275 # If anyone attempts to depend on this Python package, print an error.
276 pw_error(target_name) {
277 _pkg = get_label_info(invoker.python_package, "label_no_toolchain")
278 message_lines = [
279 "This proto Python package is embedded in the $_pkg Python package.",
280 "It cannot be used directly; instead, depend on $_pkg.",
281 ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800282 }
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800283 foreach(subtarget, pw_python_package_subtargets) {
284 group("$target_name.$subtarget") {
285 deps = [ ":${invoker.target_name}" ]
286 }
287 }
288 } else {
289 write_file("${invoker.base_out_dir}/python_package.txt", "")
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800290
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800291 # Create a Python package with the generated source files.
292 pw_python_package(target_name) {
293 forward_variables_from(invoker, _forwarded_vars)
294 generate_setup = {
295 name = invoker._package_dir
296 version = "0.0.1" # TODO(hepler): Need to be able to set this verison.
297 }
298 sources = invoker.outputs
299 strip_prefix = "${invoker.base_out_dir}/python"
300 python_deps = invoker.deps
301 other_deps = [ ":$target_name._gen($default_toolchain)" ]
302 lint = false
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800303
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800304 _pw_module_as_package = invoker.module_as_package != ""
305 }
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800306 }
307}
308
Alexei Frolov942adf02019-12-11 17:07:28 -0800309# Generates protobuf code from .proto definitions for various languages.
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700310# For each supported generator, creates a sub-target named:
Alexei Frolov942adf02019-12-11 17:07:28 -0800311#
Alexei Frolov8e30d462020-10-22 13:54:36 -0700312# <target_name>.<generator>
Alexei Frolov942adf02019-12-11 17:07:28 -0800313#
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800314# pw_protobuf_library targets generate Python packages. As such, they must have
315# globally unique package names. The first directory of the prefix or the first
316# common directory of the sources is used as the Python package.
317#
Alexei Frolov942adf02019-12-11 17:07:28 -0800318# Args:
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800319# sources: List of input .proto files.
320# deps: List of other pw_proto_library dependencies.
321# inputs: Other files on which the protos depend (e.g. nanopb .options files).
322# prefix: A prefix to add to the source protos prior to compilation. For
323# example, a source called "foo.proto" with prefix = "nested" will be
324# compiled with protoc as "nested/foo.proto".
325# strip_prefix: Remove this prefix from the source protos. All source and
326# input files must be nested under this path.
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800327# python_package: Label of Python package in which to nest the proto modules.
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700328#
Alexei Frolov942adf02019-12-11 17:07:28 -0800329template("pw_proto_library") {
330 assert(defined(invoker.sources) && invoker.sources != [],
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700331 "pw_proto_library requires .proto source files")
Alexei Frolov942adf02019-12-11 17:07:28 -0800332
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800333 if (defined(invoker.python_module_as_package)) {
334 _module_as_package = invoker.python_module_as_package
335
336 _must_be_one_source = invoker.sources
337 assert([ _must_be_one_source[0] ] == _must_be_one_source,
338 "'python_module_as_package' requires exactly one source file")
339 assert(_module_as_package != "",
340 "'python_module_as_package' cannot be be empty")
341 assert(string_split(_module_as_package, "/") == [ _module_as_package ],
342 "'python_module_as_package' cannot contain slashes")
343 assert(!defined(invoker.prefix),
344 "'prefix' cannot be provided with 'python_module_as_package'")
345 } else {
346 _module_as_package = ""
347 }
348
349 if (defined(invoker.strip_prefix)) {
350 _source_root = get_path_info(invoker.strip_prefix, "abspath")
351 } else {
352 _source_root = get_path_info(".", "abspath")
353 }
354
355 if (defined(invoker.prefix)) {
356 _prefix = invoker.prefix
357 } else {
358 _prefix = ""
359 }
360
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800361 _common = {
362 base_target = target_name
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800363
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800364 # This is the output directory for all files related to this proto library.
365 # Sources are mirrored to "$base_out_dir/sources" and protoc puts outputs in
366 # "$base_out_dir/$language" by default.
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800367 base_out_dir =
368 get_label_info(":$target_name($default_toolchain)", "target_gen_dir") +
369 "/$target_name.proto_library"
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800370
371 compile_dir = "$base_out_dir/sources"
372
373 # Refer to the source files as the are mirrored to the output directory.
374 sources = []
375 foreach(file, rebase_path(invoker.sources, _source_root)) {
376 sources += [ "$compile_dir/$_prefix/$file" ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800377 }
378 }
379
Wyatt Hepler91741472021-02-03 08:45:10 -0800380 _package_dir = ""
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800381 _source_names = []
Wyatt Hepler91741472021-02-03 08:45:10 -0800382
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800383 # Determine the Python package name to use for these protos. If there is no
384 # prefix, the first directory the sources are nested under is used.
385 foreach(source, rebase_path(invoker.sources, _source_root)) {
Wyatt Hepler91741472021-02-03 08:45:10 -0800386 _path_components = []
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800387 _path_components = string_split(source, "/")
Wyatt Hepler91741472021-02-03 08:45:10 -0800388
389 if (_package_dir == "") {
390 _package_dir = _path_components[0]
391 } else {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800392 assert(_prefix != "" || _path_components[0] == _package_dir,
393 "Unless 'prefix' is supplied, all .proto sources in a " +
394 "pw_proto_library must be in the same directory tree")
Wyatt Hepler91741472021-02-03 08:45:10 -0800395 }
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800396
397 _source_names +=
398 [ get_path_info(source, "dir") + "/" + get_path_info(source, "name") ]
Wyatt Hepler91741472021-02-03 08:45:10 -0800399 }
400
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800401 # If the 'prefix' was supplied, use that for the package directory.
402 if (_prefix != "") {
403 _prefix_path_components = string_split(_prefix, "/")
404 _package_dir = _prefix_path_components[0]
405 }
406
407 assert(_package_dir != "" && _package_dir != "." && _package_dir != "..",
408 "Either a 'prefix' must be specified or all sources must be nested " +
409 "under a common directory")
410
411 # Define an action that is never executed to prevent duplicate proto packages
412 # from being declared. The target name and the output file include only the
413 # package directory, so different targets that use the same proto package name
414 # will conflict.
415 action("pw_proto_library.$_package_dir") {
416 script = "$dir_pw_build/py/pw_build/nop.py"
Wyatt Hepler91741472021-02-03 08:45:10 -0800417 visibility = []
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800418
419 # Place an error message in the output path (which is never created). If the
420 # package name conflicts occur in different BUILD.gn files, this results in
421 # an otherwise cryptic Ninja error, rather than a GN error.
422 outputs = [ "$root_out_dir/ " +
423 "ERROR - Multiple pw_proto_library targets create the " +
424 "'$_package_dir' package. Change the package name by setting " +
425 "the \"prefix\" arg or move the protos to a different " +
426 "directory, then re-run gn gen." ]
Wyatt Hepler91741472021-02-03 08:45:10 -0800427 }
428
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800429 if (defined(invoker.deps)) {
430 _deps = invoker.deps
431 } else {
432 _deps = []
433 }
434
Alexei Frolove19ebb82020-05-14 17:21:20 -0700435 # For each proto target, create a file which collects the base directories of
436 # all of its dependencies to list as include paths to protoc.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800437 generated_file("$target_name._includes") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800438 # Collect metadata from the include path files of each dependency.
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800439 deps = process_file_template(_deps, "{{source}}._includes")
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800440
Alexei Frolove19ebb82020-05-14 17:21:20 -0700441 data_keys = [ "protoc_includes" ]
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800442 outputs = [ "${_common.base_out_dir}/includes.txt" ]
Alexei Frolove19ebb82020-05-14 17:21:20 -0700443
444 # Indicate this library's base directory for its dependents.
445 metadata = {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800446 protoc_includes = [ rebase_path(_common.compile_dir) ]
Alexei Frolove19ebb82020-05-14 17:21:20 -0700447 }
448 }
449
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800450 # Mirror the proto sources to the output directory with the prefix added.
451 pw_mirror_tree("$target_name._sources") {
452 source_root = _source_root
453 sources = invoker.sources
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700454
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800455 if (defined(invoker.inputs)) {
456 sources += invoker.inputs
457 }
458
459 directory = "${_common.compile_dir}/$_prefix"
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700460 }
461
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700462 # Enumerate all of the protobuf generator targets.
Alexei Frolovc4b62ec2020-07-13 08:35:10 -0700463
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800464 _pw_pwpb_proto_library("$target_name.pwpb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700465 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800466 forward_variables_from(_common, "*")
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800467
468 deps = []
469 foreach(dep, _deps) {
470 _base = get_label_info(dep, "label_no_toolchain")
471 deps += [ "$_base.pwpb(" + get_label_info(dep, "toolchain") + ")" ]
472 }
473
474 outputs = []
475 foreach(name, _source_names) {
476 outputs += [ "$base_out_dir/pwpb/$_prefix/${name}.pwpb.h" ]
477 }
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700478 }
479
480 if (dir_pw_third_party_nanopb != "") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800481 _pw_nanopb_rpc_proto_library("$target_name.nanopb_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700482 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800483 forward_variables_from(_common, "*")
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800484
485 deps = []
486 foreach(dep, _deps) {
487 _lbl = get_label_info(dep, "label_no_toolchain")
488 deps += [ "$_lbl.nanopb_rpc(" + get_label_info(dep, "toolchain") + ")" ]
489 }
490
491 outputs = []
492 foreach(name, _source_names) {
493 outputs += [ "$base_out_dir/nanopb_rpc/$_prefix/${name}.rpc.pb.h" ]
494 }
Alexei Frolovc4b62ec2020-07-13 08:35:10 -0700495 }
496
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800497 _pw_nanopb_proto_library("$target_name.nanopb") {
498 forward_variables_from(invoker, _forwarded_vars)
499 forward_variables_from(_common, "*")
500
501 deps = []
502 foreach(dep, _deps) {
503 _base = get_label_info(dep, "label_no_toolchain")
504 deps += [ "$_base.nanopb(" + get_label_info(dep, "toolchain") + ")" ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800505 }
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800506
507 outputs = []
508 foreach(name, _source_names) {
509 outputs += [
510 "$base_out_dir/nanopb/$_prefix/${name}.pb.h",
511 "$base_out_dir/nanopb/$_prefix/${name}.pb.c",
512 ]
Wyatt Heplerd517afc2021-02-03 19:40:08 -0800513 }
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700514 }
515 } else {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800516 pw_error("$target_name.nanopb_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700517 message =
518 "\$dir_pw_third_party_nanopb must be set to generate nanopb RPC code."
Alexei Frolov8185c822020-06-12 10:45:04 -0700519 }
Alexei Frolov942adf02019-12-11 17:07:28 -0800520
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800521 pw_error("$target_name.nanopb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700522 message =
523 "\$dir_pw_third_party_nanopb must be set to compile nanopb protobufs."
Alexei Frolov942adf02019-12-11 17:07:28 -0800524 }
525 }
526
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800527 _pw_raw_rpc_proto_library("$target_name.raw_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700528 forward_variables_from(invoker, _forwarded_vars)
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800529 forward_variables_from(_common, "*")
530
531 deps = []
532 foreach(dep, _deps) {
533 _base = get_label_info(dep, "label_no_toolchain")
534 deps += [ "$_base.raw_rpc(" + get_label_info(dep, "toolchain") + ")" ]
535 }
536
537 outputs = []
538 foreach(name, _source_names) {
539 outputs += [ "$base_out_dir/raw_rpc/$_prefix/${name}.raw_rpc.pb.h" ]
540 }
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700541 }
542
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800543 _pw_go_proto_library("$target_name.go") {
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800544 sources = _common.sources
545
546 deps = []
547 foreach(dep, _deps) {
548 _base = get_label_info(dep, "label_no_toolchain")
549 deps += [ "$_base.go(" + get_label_info(dep, "toolchain") + ")" ]
550 }
551
552 forward_variables_from(_common, "*")
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700553 }
554
Alexei Frolov38cad0c2020-12-03 12:36:24 -0800555 _pw_python_proto_library("$target_name.python") {
Alexei Frolov38cad0c2020-12-03 12:36:24 -0800556 forward_variables_from(_common, "*")
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -0800557 forward_variables_from(invoker, [ "python_package" ])
Wyatt Hepler752d7d32021-03-02 09:02:23 -0800558 module_as_package = _module_as_package
559
560 deps = []
561 foreach(dep, _deps) {
562 _base = get_label_info(dep, "label_no_toolchain")
563 deps += [ "$_base.python(" + get_label_info(dep, "toolchain") + ")" ]
564 }
565
566 if (module_as_package == "") {
567 _python_prefix = "$base_out_dir/python/$_prefix"
568 } else {
569 _python_prefix = "$base_out_dir/python/$module_as_package"
570 }
571
572 outputs = []
573 foreach(name, _source_names) {
574 outputs += [
575 "$_python_prefix/${name}_pb2.py",
576 "$_python_prefix/${name}_pb2.pyi",
577 ]
578 }
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800579 }
580
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700581 # All supported pw_protobuf generators.
582 _protobuf_generators = [
583 "pwpb",
584 "nanopb",
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700585 "nanopb_rpc",
Alexei Frolovc912ea72020-10-26 08:43:27 -0700586 "raw_rpc",
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700587 "go",
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800588 "python",
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700589 ]
590
Alexei Frolov942adf02019-12-11 17:07:28 -0800591 # If the user attempts to use the target directly instead of one of the
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700592 # generator targets, run a script which prints a nice error message.
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700593 pw_python_action(target_name) {
Alexei Frolov942adf02019-12-11 17:07:28 -0800594 script = string_join("/",
595 [
596 dir_pw_protobuf_compiler,
597 "py",
598 "pw_protobuf_compiler",
599 "proto_target_invalid.py",
600 ])
601 args = [
602 "--target",
603 target_name,
604 "--dir",
605 get_path_info(".", "abspath"),
606 "--root",
607 "//",
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700608 ] + _protobuf_generators
Alexei Frolov942adf02019-12-11 17:07:28 -0800609 stamp = true
610 }
611}