xref: /aosp_15_r20/external/perfetto/gn/standalone/proto_library.gni (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1# Copyright (C) 2017 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://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,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import("../perfetto.gni")
16
17if (host_os == "win") {
18  _host_executable_suffix = ".exe"
19} else {
20  _host_executable_suffix = ""
21}
22
23template("proto_library") {
24  assert(defined(invoker.sources))
25
26  # This is used in chromium build.
27  not_needed(invoker, [ "proto_deps" ])
28
29  proto_sources = invoker.sources
30
31  # All the proto imports should be relative to the project root.
32  proto_in_dir = "//"
33  if (defined(invoker.proto_in_dir)) {
34    proto_in_dir = invoker.proto_in_dir
35  }
36  assert(defined(invoker.proto_out_dir),
37         "proto_out_dir must be explicitly defined")
38  proto_out_dir = invoker.proto_out_dir
39
40  # We don't support generate_python in the standalone build, but still must
41  # check that the caller sets this to false. This is because when building in
42  # the chromium tree, chromium's proto_library.gni in chrome (!= this) defaults
43  # generate_python = true.
44  assert(defined(invoker.generate_python) && !invoker.generate_python)
45
46  import_dirs = []
47  if (defined(invoker.import_dirs)) {
48    import_dirs = invoker.import_dirs
49  }
50
51  # If false will not generate the default .pb.{cc,h} files. Used for custom
52  # codegen plugins.
53  generate_cc = true
54  if (defined(invoker.generate_cc)) {
55    generate_cc = invoker.generate_cc
56  }
57
58  generate_descriptor = ""
59  if (defined(invoker.generate_descriptor)) {
60    generate_descriptor = invoker.generate_descriptor
61
62    # Include imports to descriptor by default, but use exclude_imports to omit
63    # them if needed.
64    if (defined(invoker.exclude_imports)) {
65      exclude_imports = invoker.exclude_imports
66    } else {
67      exclude_imports = false
68    }
69  }
70
71  if (defined(invoker.generator_plugin_label)) {
72    plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)"
73    plugin_path =
74        get_label_info(plugin_host_label, "root_out_dir") + "/" +
75        get_label_info(plugin_host_label, "name") + _host_executable_suffix
76    generate_with_plugin = true
77  } else if (defined(invoker.generator_plugin_script)) {
78    plugin_path = invoker.generator_plugin_script
79    generate_with_plugin = true
80  } else {
81    generate_with_plugin = false
82  }
83
84  if (generate_with_plugin) {
85    if (defined(invoker.generator_plugin_suffix)) {
86      generator_plugin_suffixes = [
87        "${invoker.generator_plugin_suffix}.h",
88        "${invoker.generator_plugin_suffix}.cc",
89      ]
90    } else {
91      generator_plugin_suffixes = invoker.generator_plugin_suffixes
92    }
93  }
94
95  out_dir = "$root_gen_dir/" + proto_out_dir
96  rel_out_dir = rebase_path(out_dir, root_build_dir)
97
98  # Prevent unused errors when generating descriptor only.
99  if (generate_descriptor != "") {
100    not_needed([ "rel_out_dir" ])
101  }
102
103  protos = rebase_path(proto_sources, proto_in_dir)
104  protogens = []
105
106  if (generate_descriptor != "") {
107    protogens += [ "$out_dir/${generate_descriptor}" ]
108  }
109
110  foreach(proto, protos) {
111    proto_dir = get_path_info(proto, "dir")
112    proto_name = get_path_info(proto, "name")
113    proto_path = proto_dir + "/" + proto_name
114
115    # Prevent unused errors when generating descriptor only.
116    if (generate_descriptor != "") {
117      not_needed([ "proto_path" ])
118    }
119
120    if (generate_cc) {
121      protogens += [
122        "$out_dir/$proto_path.pb.h",
123        "$out_dir/$proto_path.pb.cc",
124      ]
125    }
126    if (generate_with_plugin) {
127      foreach(suffix, generator_plugin_suffixes) {
128        protogens += [ "$out_dir/${proto_path}${suffix}" ]
129      }
130    }
131  }
132
133  config_name = "${target_name}_config"
134  if (generate_descriptor == "") {
135    action_name = "${target_name}_gen"
136    source_set_name = target_name
137  } else {
138    action_name = target_name
139  }
140
141  config(config_name) {
142    include_dirs = [ out_dir ]
143  }
144
145  # The XXX_gen action that generates the .pb.{cc,h} files.
146  action(action_name) {
147    if (generate_descriptor == "") {
148      visibility = [ ":$source_set_name" ]
149    }
150    sources = proto_sources
151    outputs = get_path_info(protogens, "abspath")
152
153    if (perfetto_use_system_protobuf) {
154      protoc_rebased_path = "protoc" + _host_executable_suffix  # from PATH
155    } else {
156      protoc_label = "//gn:protoc($host_toolchain)"
157      protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" +
158                    _host_executable_suffix
159      protoc_rebased_path = "./" + rebase_path(protoc_path, root_build_dir)
160    }
161    script = "//gn/standalone/protoc.py"
162    args = [
163      # Path should be rebased because |root_build_dir| for current toolchain
164      # may be different from |root_out_dir| of protoc built on host toolchain.
165      protoc_rebased_path,
166      "--proto_path",
167      rebase_path(proto_in_dir, root_build_dir),
168    ]
169
170    foreach(path, import_dirs) {
171      args += [
172        "--proto_path",
173        rebase_path(path, root_build_dir),
174      ]
175    }
176
177    metadata = {
178      proto_import_dirs = import_dirs
179    }
180
181    if (generate_cc) {
182      cc_generator_options_ = ""
183      if (defined(invoker.cc_generator_options)) {
184        cc_generator_options_ = invoker.cc_generator_options
185      }
186      args += [
187        "--cpp_out",
188        cc_generator_options_ + rel_out_dir,
189      ]
190    }
191    if (generate_descriptor != "") {
192      depfile = "$root_gen_dir/$generate_descriptor.d"
193
194      if (!exclude_imports) {
195        args += [ "--include_imports" ]
196      }
197      args += [
198        "--descriptor_set_out",
199        rebase_path("$root_gen_dir/$generate_descriptor", root_build_dir),
200        "--dependency_out",
201        rebase_path(depfile, root_build_dir),
202      ]
203    }
204
205    if (generate_with_plugin) {
206      plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
207      plugin_out_args = ""
208      if (defined(invoker.generator_plugin_options)) {
209        plugin_out_args += invoker.generator_plugin_options
210      }
211      plugin_out_args += ":$rel_out_dir"
212
213      args += [
214        "--plugin=protoc-gen-plugin=$plugin_path_rebased",
215        "--plugin_out=$plugin_out_args",
216      ]
217    }
218
219    args += rebase_path(proto_sources, root_build_dir)
220
221    if (!perfetto_use_system_protobuf) {
222      inputs = [ protoc_path ]
223      deps = [ protoc_label ]
224    } else {
225      inputs = []
226      deps = []
227    }
228
229    if (generate_with_plugin) {
230      inputs += [ plugin_path ]
231      if (defined(plugin_host_label)) {
232        # Action depends on native generator plugin but for host toolchain only.
233        deps += [ plugin_host_label ]
234      }
235    }
236
237    if (generate_descriptor != "") {
238      deps += invoker.deps
239    }
240    if (defined(invoker.link_deps)) {
241      deps += invoker.link_deps
242    }
243  }  # action(action_name)
244
245  # The source_set that builds the generated .pb.cc files.
246  if (generate_descriptor == "") {
247    source_set(source_set_name) {
248      forward_variables_from(invoker,
249                             [
250                               "defines",
251                               "include_dirs",
252                               "public_configs",
253                               "testonly",
254                               "visibility",
255                             ])
256
257      sources = get_target_outputs(":$action_name")
258
259      configs -= [ "//gn/standalone:extra_warnings" ]
260      if (defined(invoker.extra_configs)) {
261        configs += invoker.extra_configs
262      }
263
264      if (!defined(invoker.public_configs)) {
265        public_configs = []
266      }
267
268      public_configs += [ ":$config_name" ]
269
270      # Only include the protobuf_gen_config when generating .pb.cc files.
271      # Note that |generate_cc| is false for .{pbzero,ipc,gen etc.}.cc
272      if (generate_cc) {
273        public_configs += [ "//gn:protobuf_gen_config" ]
274      }
275
276      # By default, propagate the config for |include_dirs| to dependent
277      # targets, so that public imports can be resolved to corresponding header
278      # files. In some cases, the embedder target handles include directory
279      # propagation itself, e.g. via a common config.
280      propagate_imports_configs = !defined(invoker.propagate_imports_configs) ||
281                                  invoker.propagate_imports_configs
282      if (propagate_imports_configs) {
283        public_configs += [ ":$config_name" ]
284      } else {
285        configs += [ ":$config_name" ]
286      }
287
288      # Use protobuf_full only for tests.
289      if (defined(invoker.use_protobuf_full) &&
290          invoker.use_protobuf_full == true) {
291        deps = [ "//gn:protobuf_full" ]
292      } else if (generate_cc) {
293        deps = [ "//gn:protobuf_lite" ]
294      } else {
295        deps = []
296      }
297
298      deps += [ ":$action_name" ]
299      if (defined(invoker.deps)) {
300        deps += invoker.deps
301      }
302      if (defined(invoker.link_deps)) {
303        deps += invoker.link_deps
304      }
305    }  # source_set(source_set_name)
306  }
307}  # template
308