blob: 8d0a55e54c646c6337b69e305b0c50913f6d979c [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")
Alexei Frolova4c0aee2020-12-01 13:48:48 -080019import("$dir_pw_build/python.gni")
Wyatt Hepler51ded742020-10-19 14:45:27 -070020import("$dir_pw_build/python_action.gni")
Alexei Frolovedd2f142020-06-09 19:11:27 -070021import("$dir_pw_build/target_types.gni")
Alexei Frolovdd6fa5c2020-08-11 10:04:01 -070022import("$dir_pw_third_party/nanopb/nanopb.gni")
Wyatt Heplerd49f8fe2020-10-15 10:13:47 -070023
Wyatt Heplerd9336a42020-11-10 09:47:30 -080024# Variables forwarded from the public pw_proto_library template to the final
25# pw_source_set.
Wyatt Heplere0c4fdc2020-05-29 17:26:19 -070026_forwarded_vars = [
27 "testonly",
28 "visibility",
29]
30
Wyatt Heplerd9336a42020-11-10 09:47:30 -080031# Internal template that invokes protoc with a pw_python_action. This should not
32# be used outside of this file; use pw_proto_library instead.
33#
34# This creates the internal GN target $target_name.$language._gen that compiles
35# proto files with protoc.
36template("_pw_invoke_protoc") {
37 _output = rebase_path(get_target_outputs(":${invoker.base_target}._metadata"))
38
39 pw_python_action("$target_name._gen") {
40 forward_variables_from(invoker, [ "metadata" ])
41 script =
42 "$dir_pw_protobuf_compiler/py/pw_protobuf_compiler/generate_protos.py"
43
44 deps = [
45 ":${invoker.base_target}._metadata",
46 ":${invoker.base_target}._inputs",
47 ] + invoker.deps
48
49 args = [
50 "--language",
51 invoker.language,
52 "--module-path",
53 rebase_path("."),
54 "--include-file",
55 _output[0],
56 "--out-dir",
57 rebase_path(invoker.gen_dir),
58 ] + rebase_path(invoker.sources)
59
60 inputs = invoker.sources
61
62 if (defined(invoker.plugin)) {
63 inputs += [ invoker.plugin ]
64 args += [ "--plugin-path=" + rebase_path(invoker.plugin) ]
65 }
66
67 if (defined(invoker.include_paths)) {
68 args += [
69 "--include-paths",
70 string_join(";", rebase_path(invoker.include_paths)),
71 ]
72 }
73
74 outputs = []
75 foreach(extension, invoker.output_extensions) {
76 foreach(proto,
77 rebase_path(invoker.sources, get_path_info(".", "abspath"))) {
78 _output = string_replace(proto, ".proto", extension)
79 outputs += [ "${invoker.gen_dir}/$_output" ]
80 }
81 }
82
83 if (outputs == []) {
84 stamp = true
85 }
86
87 visibility = [ ":*" ]
88 }
89}
90
Alexei Frolovf39cd8b2020-04-13 17:59:20 -070091# Generates pw_protobuf C++ code for proto files, creating a source_set of the
92# generated files. This is internal and should not be used outside of this file.
93# Use pw_proto_library instead.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -070094template("_pw_pwpb_proto_library") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -080095 _pw_invoke_protoc(target_name) {
96 forward_variables_from(invoker, "*", _forwarded_vars)
97 language = "pwpb"
98 plugin = "$dir_pw_protobuf/py/pw_protobuf/plugin.py"
99 deps += [ "$dir_pw_protobuf/py" ]
100 output_extensions = [ ".pwpb.h" ]
Alexei Frolov942adf02019-12-11 17:07:28 -0800101 }
102
103 # Create a library with the generated source files.
Alexei Frolovedd2f142020-06-09 19:11:27 -0700104 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800105 forward_variables_from(invoker, _forwarded_vars)
106 public_configs = [ ":${invoker.base_target}._include_path" ]
107 deps = [ ":$target_name._gen" ]
108 public_deps = [ dir_pw_protobuf ] + invoker.deps
109 sources = get_target_outputs(":$target_name._gen")
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700110 public = filter_include(sources, [ "*.pwpb.h" ])
111 }
112}
113
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700114# Generates nanopb RPC code for proto files, creating a source_set of the
115# generated files. This is internal and should not be used outside of this file.
116# Use pw_proto_library instead.
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700117template("_pw_nanopb_rpc_proto_library") {
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700118 # Create a target which runs protoc configured with the nanopb_rpc plugin to
119 # generate the C++ proto RPC headers.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800120 _pw_invoke_protoc(target_name) {
121 forward_variables_from(invoker, "*", _forwarded_vars)
122 language = "nanopb_rpc"
123 plugin = "$dir_pw_rpc/py/pw_rpc/plugin_nanopb.py"
124 deps += [ "$dir_pw_rpc/py" ]
125 include_paths = [ "$dir_pw_third_party_nanopb/generator/proto" ]
126 output_extensions = [ ".rpc.pb.h" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700127 }
128
129 # Create a library with the generated source files.
130 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800131 forward_variables_from(invoker, _forwarded_vars)
132 public_configs = [ ":${invoker.base_target}._include_path" ]
133 deps = [ ":$target_name._gen" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700134 public_deps = [
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800135 ":${invoker.base_target}.nanopb",
Wyatt Heplercbd09c22020-09-15 11:17:24 -0700136 "$dir_pw_rpc:server",
Alexei Frolova4d71502020-10-14 12:43:14 -0700137 "$dir_pw_rpc/nanopb:method_union",
Alexei Frolovdd6fa5c2020-08-11 10:04:01 -0700138 "$dir_pw_third_party/nanopb",
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800139 ] + invoker.deps
140 public = get_target_outputs(":$target_name._gen")
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700141 }
142}
143
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700144# Generates nanopb code for proto files, creating a source_set of the generated
145# files. This is internal and should not be used outside of this file. Use
146# pw_proto_library instead.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700147template("_pw_nanopb_proto_library") {
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700148 # Create a target which runs protoc configured with the nanopb plugin to
149 # generate the C proto sources.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800150 _pw_invoke_protoc(target_name) {
151 forward_variables_from(invoker, "*", _forwarded_vars)
152 language = "nanopb"
153 plugin = "$dir_pw_third_party_nanopb/generator/protoc-gen-nanopb"
154 include_paths = [ "$dir_pw_third_party_nanopb/generator/proto" ]
155 output_extensions = [
156 ".pb.h",
157 ".pb.c",
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700158 ]
159 }
160
161 # Create a library with the generated source files.
Alexei Frolovedd2f142020-06-09 19:11:27 -0700162 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800163 forward_variables_from(invoker, _forwarded_vars)
164 public_configs = [ ":${invoker.base_target}._include_path" ]
165 deps = [ ":$target_name._gen" ]
166 public_deps = [ "$dir_pw_third_party/nanopb" ] + invoker.deps
167 sources = get_target_outputs(":$target_name._gen")
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700168 public = filter_include(sources, [ "*.pb.h" ])
Alexei Frolov942adf02019-12-11 17:07:28 -0800169 }
170}
171
Alexei Frolovc912ea72020-10-26 08:43:27 -0700172# Generates raw RPC code for proto files, creating a source_set of the generated
173# files. This is internal and should not be used outside of this file. Use
174# pw_proto_library instead.
Alexei Frolovc912ea72020-10-26 08:43:27 -0700175template("_pw_raw_rpc_proto_library") {
Alexei Frolovc912ea72020-10-26 08:43:27 -0700176 # Create a target which runs protoc configured with the nanopb_rpc plugin to
177 # generate the C++ proto RPC headers.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800178 _pw_invoke_protoc(target_name) {
179 forward_variables_from(invoker, "*", _forwarded_vars)
180 language = "raw_rpc"
181 plugin = "$dir_pw_rpc/py/pw_rpc/plugin_raw.py"
182 deps += [ "$dir_pw_rpc/py" ]
183 output_extensions = [ ".raw_rpc.pb.h" ]
Alexei Frolovc912ea72020-10-26 08:43:27 -0700184 }
185
186 # Create a library with the generated source files.
187 pw_source_set(target_name) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800188 forward_variables_from(invoker, _forwarded_vars)
189 public_configs = [ ":${invoker.base_target}._include_path" ]
190 deps = [ ":$target_name._gen" ]
Alexei Frolovc912ea72020-10-26 08:43:27 -0700191 public_deps = [
192 "$dir_pw_rpc:server",
193 "$dir_pw_rpc/raw:method_union",
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800194 ] + invoker.deps
195 public = get_target_outputs(":$target_name._gen")
Alexei Frolovc912ea72020-10-26 08:43:27 -0700196 }
197}
198
Alexei Frolovdef14712019-12-23 13:03:32 -0800199# Generates Go code for proto files, listing the proto output directory in the
200# metadata variable GOPATH. Internal use only.
Alexei Frolovdef14712019-12-23 13:03:32 -0800201template("_pw_go_proto_library") {
202 _proto_gopath = "$root_gen_dir/go"
Alexei Frolovdef14712019-12-23 13:03:32 -0800203
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800204 _pw_invoke_protoc(target_name) {
205 forward_variables_from(invoker, "*")
206 language = "go"
Alexei Frolovdef14712019-12-23 13:03:32 -0800207 metadata = {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800208 gopath = [ "GOPATH+=" + rebase_path(_proto_gopath) ]
Alexei Frolovc15a9882019-12-23 14:29:02 -0800209 external_deps = [
210 "github.com/golang/protobuf/proto",
211 "google.golang.org/grpc",
212 ]
Alexei Frolovdef14712019-12-23 13:03:32 -0800213 }
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800214 output_extensions = [] # Don't enumerate the generated .go files.
215 gen_dir = "$_proto_gopath/src"
216 }
217
218 group(target_name) {
219 deps = [ ":$target_name._gen" ]
Alexei Frolovdef14712019-12-23 13:03:32 -0800220 }
221}
222
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800223# Generates Python code for proto files, creating a pw_python_package containing
224# the generated files. This is internal and should not be used outside of this
225# file. Use pw_proto_library instead.
226template("_pw_python_proto_library") {
227 _target = target_name
228 _package_dir = ""
229
230 foreach(_rebased_proto_path, rebase_path(invoker.sources, ".")) {
231 _path_components = []
232 _path_components = string_split(_rebased_proto_path, "/")
233
234 assert(_path_components != [ _rebased_proto_path ] &&
235 _path_components[0] != "..",
236 "Sources in a pw_proto_library must live in subdirectories " +
237 "of where it is defined")
238
239 if (_package_dir == "") {
240 _package_dir = _path_components[0]
241 } else {
242 assert(_path_components[0] == _package_dir,
243 "All .proto sources in a pw_proto_library must live " +
244 "in the same directory tree")
245 }
246 }
247
248 _pw_invoke_protoc(target_name) {
249 forward_variables_from(invoker, "*", _forwarded_vars)
250 language = "python"
251 output_extensions = [ "_pb2.py" ]
252 }
253
254 _setup_py = "${invoker.gen_dir}/setup.py"
255
256 # Create the setup and init files for the Python package.
257 pw_python_action(target_name + "._package_gen") {
258 script = "$dir_pw_protobuf_compiler/py/pw_protobuf_compiler/generate_python_package.py"
259 args = [
260 "--setup",
261 rebase_path(_setup_py),
262 "--package",
263 _package_dir,
264 ] + rebase_path(get_path_info(invoker.sources, "dir"), ".")
265 public_deps = [ ":$_target._gen" ]
266 stamp = true
267 }
268
269 # Create a Python package with the generated source files.
270 pw_python_package(target_name) {
271 forward_variables_from(invoker, _forwarded_vars)
272 setup = [ _setup_py ]
273 sources = get_target_outputs(":$target_name._gen")
274 python_deps = invoker.deps
275 other_deps = [ ":$_target._package_gen" ]
276 _pw_generated = true
277 }
278}
279
280declare_args() {
281 # Temporary build arg to allow projects to update their proto libraries to be
282 # Python-compatible.
283 pw_protobuf_compiler_DISABLE_PYTHON = false
284}
285
Alexei Frolov942adf02019-12-11 17:07:28 -0800286# Generates protobuf code from .proto definitions for various languages.
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700287# For each supported generator, creates a sub-target named:
Alexei Frolov942adf02019-12-11 17:07:28 -0800288#
Alexei Frolov8e30d462020-10-22 13:54:36 -0700289# <target_name>.<generator>
Alexei Frolov942adf02019-12-11 17:07:28 -0800290#
Alexei Frolov942adf02019-12-11 17:07:28 -0800291# Args:
292# sources: List of input .proto files.
293# deps: List of other pw_proto_library dependencies.
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700294# inputs: Other files on which the protos depend (e.g. nanopb .options files).
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700295#
Alexei Frolov942adf02019-12-11 17:07:28 -0800296template("pw_proto_library") {
297 assert(defined(invoker.sources) && invoker.sources != [],
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700298 "pw_proto_library requires .proto source files")
Alexei Frolov942adf02019-12-11 17:07:28 -0800299
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800300 _common = {
301 base_target = target_name
302 gen_dir = "$target_gen_dir/protos"
303 sources = invoker.sources
304 }
305
306 if (defined(invoker.deps)) {
307 _deps = invoker.deps
308 } else {
309 _deps = []
310 }
311
Alexei Frolove19ebb82020-05-14 17:21:20 -0700312 # For each proto target, create a file which collects the base directories of
313 # all of its dependencies to list as include paths to protoc.
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800314 generated_file("$target_name._metadata") {
315 # Collect metadata from the include path files of each dependency.
316 deps = process_file_template(_deps, "{{source}}._metadata")
317
Alexei Frolove19ebb82020-05-14 17:21:20 -0700318 data_keys = [ "protoc_includes" ]
Wyatt Hepler7c61caf2020-11-24 11:29:05 -0800319 outputs = [ "$target_gen_dir/${_common.base_target}_includes.txt" ]
Alexei Frolove19ebb82020-05-14 17:21:20 -0700320
321 # Indicate this library's base directory for its dependents.
322 metadata = {
Alexei Frolovf79d2272020-06-18 13:37:38 -0700323 protoc_includes = [ rebase_path(".") ]
Alexei Frolove19ebb82020-05-14 17:21:20 -0700324 }
325 }
326
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800327 # Toss any additional inputs into an input group dependency.
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700328 if (defined(invoker.inputs)) {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800329 pw_input_group("$target_name._inputs") {
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700330 inputs = invoker.inputs
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800331 visibility = [ ":*" ]
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700332 }
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800333 } else {
334 group("$target_name._inputs") {
335 visibility = [ ":*" ]
336 }
Alexei Frolov05d8ef22020-06-08 10:32:29 -0700337 }
338
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800339 # Create a config with the generated proto directory, which is used for C++.
340 config("$target_name._include_path") {
341 include_dirs = [ _common.gen_dir ]
342 visibility = [ ":*" ]
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700343 }
344
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700345 # Enumerate all of the protobuf generator targets.
Alexei Frolovc4b62ec2020-07-13 08:35:10 -0700346
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800347 _pw_pwpb_proto_library("$target_name.pwpb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700348 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800349 forward_variables_from(_common, "*")
350 deps = process_file_template(_deps, "{{source}}.pwpb")
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700351 }
352
353 if (dir_pw_third_party_nanopb != "") {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800354 _pw_nanopb_rpc_proto_library("$target_name.nanopb_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700355 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800356 forward_variables_from(_common, "*")
357 deps = process_file_template(_deps, "{{source}}.nanopb_rpc")
Alexei Frolovc4b62ec2020-07-13 08:35:10 -0700358 }
359
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800360 _pw_nanopb_proto_library("$target_name.nanopb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700361 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800362 forward_variables_from(_common, "*")
363 deps = process_file_template(_deps, "{{source}}.nanopb")
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700364 }
365 } else {
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800366 pw_error("$target_name.nanopb_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700367 message =
368 "\$dir_pw_third_party_nanopb must be set to generate nanopb RPC code."
Alexei Frolov8185c822020-06-12 10:45:04 -0700369 }
Alexei Frolov942adf02019-12-11 17:07:28 -0800370
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800371 pw_error("$target_name.nanopb") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700372 message =
373 "\$dir_pw_third_party_nanopb must be set to compile nanopb protobufs."
Alexei Frolov942adf02019-12-11 17:07:28 -0800374 }
375 }
376
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800377 _pw_raw_rpc_proto_library("$target_name.raw_rpc") {
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700378 forward_variables_from(invoker, _forwarded_vars)
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800379 forward_variables_from(_common, "*", [ "deps" ])
380 deps = process_file_template(_deps, "{{source}}.raw_rpc")
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700381 }
382
Wyatt Heplerd9336a42020-11-10 09:47:30 -0800383 _pw_go_proto_library("$target_name.go") {
384 sources = invoker.sources
385 deps = process_file_template(_deps, "{{source}}.go")
386 base_target = _common.base_target
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700387 }
388
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800389 if (!pw_protobuf_compiler_DISABLE_PYTHON) {
390 _pw_python_proto_library("$target_name.python") {
391 sources = invoker.sources
392 forward_variables_from(_common, "*")
393 deps = process_file_template(_deps, "{{source}}.python")
394 base_target = _common.base_target
395 }
396 }
397
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700398 # All supported pw_protobuf generators.
399 _protobuf_generators = [
400 "pwpb",
401 "nanopb",
Alexei Frolov79b7cb02020-07-06 13:51:43 -0700402 "nanopb_rpc",
Alexei Frolovc912ea72020-10-26 08:43:27 -0700403 "raw_rpc",
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700404 "go",
Alexei Frolova4c0aee2020-12-01 13:48:48 -0800405 "python",
Wyatt Heplerb4b73a62020-05-27 15:17:27 -0700406 ]
407
Alexei Frolov942adf02019-12-11 17:07:28 -0800408 # If the user attempts to use the target directly instead of one of the
Alexei Frolovf39cd8b2020-04-13 17:59:20 -0700409 # generator targets, run a script which prints a nice error message.
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700410 pw_python_action(target_name) {
Alexei Frolov942adf02019-12-11 17:07:28 -0800411 script = string_join("/",
412 [
413 dir_pw_protobuf_compiler,
414 "py",
415 "pw_protobuf_compiler",
416 "proto_target_invalid.py",
417 ])
418 args = [
419 "--target",
420 target_name,
421 "--dir",
422 get_path_info(".", "abspath"),
423 "--root",
424 "//",
Alexei Frolovb499d3f2020-10-28 13:00:08 -0700425 ] + _protobuf_generators
Alexei Frolov942adf02019-12-11 17:07:28 -0800426 stamp = true
427 }
428}