• 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    if (generate_cc) {
174      cc_generator_options_ = ""
175      if (defined(invoker.cc_generator_options)) {
176        cc_generator_options_ = invoker.cc_generator_options
177      }
178      args += [
179        "--cpp_out",
180        cc_generator_options_ + rel_out_dir,
181      ]
182    }
183    if (generate_descriptor != "") {
184      depfile = "$root_gen_dir/$generate_descriptor.d"
185
186      if (!exclude_imports) {
187        args += [ "--include_imports" ]
188      }
189      args += [
190        "--descriptor_set_out",
191        rebase_path("$root_gen_dir/$generate_descriptor", root_build_dir),
192        "--dependency_out",
193        rebase_path(depfile, root_build_dir),
194      ]
195    }
196
197    if (generate_with_plugin) {
198      plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
199      plugin_out_args = ""
200      if (defined(invoker.generator_plugin_options)) {
201        plugin_out_args += invoker.generator_plugin_options
202      }
203      plugin_out_args += ":$rel_out_dir"
204
205      args += [
206        "--plugin=protoc-gen-plugin=$plugin_path_rebased",
207        "--plugin_out=$plugin_out_args",
208      ]
209    }
210
211    args += rebase_path(proto_sources, root_build_dir)
212
213    if (!perfetto_use_system_protobuf) {
214      inputs = [ protoc_path ]
215      deps = [ protoc_label ]
216    } else {
217      inputs = []
218      deps = []
219    }
220
221    # TODO(hjd): Avoid adding to deps here this.
222    # When we generate BUILD files we need find the transitive proto,
223    # dependencies, so also add link_deps to actual deps so they show up
224    # in gn desc.
225    if (defined(invoker.link_deps)) {
226      deps += invoker.link_deps
227    }
228    if (generate_with_plugin) {
229      inputs += [ plugin_path ]
230      if (defined(plugin_host_label)) {
231        # Action depends on native generator plugin but for host toolchain only.
232        deps += [ plugin_host_label ]
233      }
234    }
235
236    if (defined(invoker.deps)) {
237      deps += invoker.deps
238    }
239  }  # action(action_name)
240
241  # The source_set that builds the generated .pb.cc files.
242  if (generate_descriptor == "") {
243    source_set(source_set_name) {
244      forward_variables_from(invoker,
245                             [
246                               "defines",
247                               "include_dirs",
248                               "public_configs",
249                               "testonly",
250                               "visibility",
251                             ])
252
253      sources = get_target_outputs(":$action_name")
254
255      configs -= [ "//gn/standalone:extra_warnings" ]
256      if (defined(invoker.extra_configs)) {
257        configs += invoker.extra_configs
258      }
259
260      if (!defined(invoker.public_configs)) {
261        public_configs = []
262      }
263
264      public_configs += [ ":$config_name" ]
265
266      # Only include the protobuf_gen_config when generating .pb.cc files.
267      # Note that |generate_cc| is false for .{pbzero,ipc,gen etc.}.cc
268      if (generate_cc) {
269        public_configs += [ "//gn:protobuf_gen_config" ]
270      }
271
272      # By default, propagate the config for |include_dirs| to dependent
273      # targets, so that public imports can be resolved to corresponding header
274      # files. In some cases, the embedder target handles include directory
275      # propagation itself, e.g. via a common config.
276      propagate_imports_configs = !defined(invoker.propagate_imports_configs) ||
277                                  invoker.propagate_imports_configs
278      if (propagate_imports_configs) {
279        public_configs += [ ":$config_name" ]
280      } else {
281        configs += [ ":$config_name" ]
282      }
283
284      # Use protobuf_full only for tests.
285      if (defined(invoker.use_protobuf_full) &&
286          invoker.use_protobuf_full == true) {
287        deps = [ "//gn:protobuf_full" ]
288      } else if (generate_cc) {
289        deps = [ "//gn:protobuf_lite" ]
290      } else {
291        deps = []
292      }
293
294      deps += [ ":$action_name" ]
295      if (defined(invoker.deps)) {
296        deps += invoker.deps
297      }
298    }  # source_set(source_set_name)
299  }
300}  # template
301