• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  proto_sources = invoker.sources
26
27  # All the proto imports should be relative to the project root.
28  proto_in_dir = "//"
29  if (defined(invoker.proto_in_dir)) {
30    proto_in_dir = invoker.proto_in_dir
31  }
32  assert(defined(invoker.proto_out_dir),
33         "proto_out_dir must be explicitly defined")
34  proto_out_dir = invoker.proto_out_dir
35
36  # We don't support generate_python in the standalone build, but still must
37  # check that the caller sets this to false. This is because when building in
38  # the chromium tree, chromium's proto_library.gni in chrome (!= this) defaults
39  # generate_python = true.
40  assert(defined(invoker.generate_python) && !invoker.generate_python)
41
42  import_dirs = []
43  if (defined(invoker.import_dirs)) {
44    import_dirs = invoker.import_dirs
45  }
46
47  # If false will not generate the default .pb.{cc,h} files. Used for custom
48  # codegen plugins.
49  generate_cc = true
50  if (defined(invoker.generate_cc)) {
51    generate_cc = invoker.generate_cc
52  }
53
54  generate_descriptor = ""
55  if (defined(invoker.generate_descriptor)) {
56    generate_descriptor = invoker.generate_descriptor
57
58    # Include imports to descriptor by default, but use exclude_imports to omit
59    # them if needed.
60    if (defined(invoker.exclude_imports)) {
61      exclude_imports = invoker.exclude_imports
62    } else {
63      exclude_imports = false
64    }
65  }
66
67  if (defined(invoker.generator_plugin_label)) {
68    plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)"
69    plugin_path =
70        get_label_info(plugin_host_label, "root_out_dir") + "/" +
71        get_label_info(plugin_host_label, "name") + _host_executable_suffix
72    generate_with_plugin = true
73  } else if (defined(invoker.generator_plugin_script)) {
74    plugin_path = invoker.generator_plugin_script
75    generate_with_plugin = true
76  } else {
77    generate_with_plugin = false
78  }
79
80  if (generate_with_plugin) {
81    if (defined(invoker.generator_plugin_suffix)) {
82      generator_plugin_suffixes = [
83        "${invoker.generator_plugin_suffix}.h",
84        "${invoker.generator_plugin_suffix}.cc",
85      ]
86    } else {
87      generator_plugin_suffixes = invoker.generator_plugin_suffixes
88    }
89  }
90
91  out_dir = "$root_gen_dir/" + proto_out_dir
92  rel_out_dir = rebase_path(out_dir, root_build_dir)
93
94  # Prevent unused errors when generating descriptor only.
95  if (generate_descriptor != "") {
96    not_needed([ "rel_out_dir" ])
97  }
98
99  protos = rebase_path(proto_sources, proto_in_dir)
100  protogens = []
101
102  if (generate_descriptor != "") {
103    protogens += [ "$out_dir/${generate_descriptor}" ]
104  }
105
106  foreach(proto, protos) {
107    proto_dir = get_path_info(proto, "dir")
108    proto_name = get_path_info(proto, "name")
109    proto_path = proto_dir + "/" + proto_name
110
111    # Prevent unused errors when generating descriptor only.
112    if (generate_descriptor != "") {
113      not_needed([ "proto_path" ])
114    }
115
116    if (generate_cc) {
117      protogens += [
118        "$out_dir/$proto_path.pb.h",
119        "$out_dir/$proto_path.pb.cc",
120      ]
121    }
122    if (generate_with_plugin) {
123      foreach(suffix, generator_plugin_suffixes) {
124        protogens += [ "$out_dir/${proto_path}${suffix}" ]
125      }
126    }
127  }
128
129  config_name = "${target_name}_config"
130  if (generate_descriptor == "") {
131    action_name = "${target_name}_gen"
132    source_set_name = target_name
133  } else {
134    action_name = target_name
135  }
136
137  config(config_name) {
138    include_dirs = [ out_dir ]
139  }
140
141  # The XXX_gen action that generates the .pb.{cc,h} files.
142  action(action_name) {
143    if (generate_descriptor == "") {
144      visibility = [ ":$source_set_name" ]
145    }
146    sources = proto_sources
147    outputs = get_path_info(protogens, "abspath")
148
149    if (perfetto_use_system_protobuf) {
150      protoc_rebased_path = "protoc" + _host_executable_suffix  # from PATH
151    } else {
152      protoc_label = "//gn:protoc($host_toolchain)"
153      protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" +
154                    _host_executable_suffix
155      protoc_rebased_path = "./" + rebase_path(protoc_path, root_build_dir)
156    }
157    script = "//gn/standalone/protoc.py"
158    args = [
159      # Path should be rebased because |root_build_dir| for current toolchain
160      # may be different from |root_out_dir| of protoc built on host toolchain.
161      protoc_rebased_path,
162      "--proto_path",
163      rebase_path(proto_in_dir, root_build_dir),
164    ]
165
166    foreach(path, import_dirs) {
167      args += [
168        "--proto_path",
169        rebase_path(path, root_build_dir),
170      ]
171    }
172
173    metadata = {
174      proto_import_dirs = import_dirs
175    }
176
177    if (generate_cc) {
178      cc_generator_options_ = ""
179      if (defined(invoker.cc_generator_options)) {
180        cc_generator_options_ = invoker.cc_generator_options
181      }
182      args += [
183        "--cpp_out",
184        cc_generator_options_ + rel_out_dir,
185      ]
186    }
187    if (generate_descriptor != "") {
188      depfile = "$root_gen_dir/$generate_descriptor.d"
189
190      if (!exclude_imports) {
191        args += [ "--include_imports" ]
192      }
193      args += [
194        "--descriptor_set_out",
195        rebase_path("$root_gen_dir/$generate_descriptor", root_build_dir),
196        "--dependency_out",
197        rebase_path(depfile, root_build_dir),
198      ]
199    }
200
201    if (generate_with_plugin) {
202      plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
203      plugin_out_args = ""
204      if (defined(invoker.generator_plugin_options)) {
205        plugin_out_args += invoker.generator_plugin_options
206      }
207      plugin_out_args += ":$rel_out_dir"
208
209      args += [
210        "--plugin=protoc-gen-plugin=$plugin_path_rebased",
211        "--plugin_out=$plugin_out_args",
212      ]
213    }
214
215    args += rebase_path(proto_sources, root_build_dir)
216
217    if (!perfetto_use_system_protobuf) {
218      inputs = [ protoc_path ]
219      deps = [ protoc_label ]
220    } else {
221      inputs = []
222      deps = []
223    }
224
225    # TODO(hjd): Avoid adding to deps here this.
226    # When we generate BUILD files we need find the transitive proto,
227    # dependencies, so also add link_deps to actual deps so they show up
228    # in gn desc.
229    if (defined(invoker.link_deps)) {
230      deps += invoker.link_deps
231    }
232    if (generate_with_plugin) {
233      inputs += [ plugin_path ]
234      if (defined(plugin_host_label)) {
235        # Action depends on native generator plugin but for host toolchain only.
236        deps += [ plugin_host_label ]
237      }
238    }
239
240    if (defined(invoker.deps)) {
241      deps += invoker.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    }  # source_set(source_set_name)
303  }
304}  # template
305