1# Copyright 2019 the V8 project authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import("//build_overrides/build.gni")
6
7# This file should not be pulled in chromium builds.
8assert(!build_with_chromium)
9
10template("proto_library") {
11  assert(defined(invoker.sources))
12  proto_sources = invoker.sources
13
14  if (host_os == "win") {
15    host_executable_suffix = ".exe"
16  } else {
17    host_executable_suffix = ""
18  }
19
20  # All the proto imports should be relative to the project root.
21  proto_in_dir = "//"
22  if (defined(invoker.proto_in_dir)) {
23    proto_in_dir = invoker.proto_in_dir
24  }
25  assert(defined(invoker.proto_out_dir),
26         "proto_out_dir must be explicitly defined")
27  proto_out_dir = invoker.proto_out_dir
28
29  # We don't support generate_python in the standalone build, but still must
30  # check that the caller sets this to false. This is because when building in
31  # the chromium tree, chromium's proto_library.gni in chrome (!= this) defaults
32  # generate_python = true.
33  assert(defined(invoker.generate_python) && !invoker.generate_python)
34
35  # If false will not generate the default .pb.{cc,h} files. Used for custom
36  # codegen plugins.
37  generate_cc = true
38  if (defined(invoker.generate_cc)) {
39    generate_cc = invoker.generate_cc
40  }
41
42  generate_descriptor = ""
43  if (defined(invoker.generate_descriptor)) {
44    generate_descriptor = invoker.generate_descriptor
45  }
46
47  if (defined(invoker.generator_plugin_label)) {
48    plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)"
49    plugin_path =
50        get_label_info(plugin_host_label, "root_out_dir") + "/" +
51        get_label_info(plugin_host_label, "name") + host_executable_suffix
52    generate_with_plugin = true
53  } else if (defined(invoker.generator_plugin_script)) {
54    plugin_path = invoker.generator_plugin_script
55    generate_with_plugin = true
56  } else {
57    generate_with_plugin = false
58  }
59
60  if (generate_with_plugin) {
61    if (defined(invoker.generator_plugin_suffix)) {
62      generator_plugin_suffixes = [
63        "${invoker.generator_plugin_suffix}.h",
64        "${invoker.generator_plugin_suffix}.cc",
65      ]
66    } else {
67      generator_plugin_suffixes = invoker.generator_plugin_suffixes
68    }
69  }
70
71  cc_out_dir = "$root_gen_dir/" + proto_out_dir
72  rel_cc_out_dir = rebase_path(cc_out_dir, root_build_dir)
73
74  protos = rebase_path(proto_sources, proto_in_dir)
75  protogens = []
76
77  if (generate_descriptor != "") {
78    protogens += [ "$root_gen_dir/" + generate_descriptor ]
79  }
80
81  foreach(proto, protos) {
82    proto_dir = get_path_info(proto, "dir")
83    proto_name = get_path_info(proto, "name")
84    proto_path = proto_dir + "/" + proto_name
85
86    if (generate_cc) {
87      protogens += [
88        "$cc_out_dir/$proto_path.pb.h",
89        "$cc_out_dir/$proto_path.pb.cc",
90      ]
91    }
92    if (generate_with_plugin) {
93      foreach(suffix, generator_plugin_suffixes) {
94        protogens += [ "$cc_out_dir/${proto_path}${suffix}" ]
95      }
96    }
97  }
98
99  config_name = "${target_name}_config"
100  action_name = "${target_name}_gen"
101  source_set_name = target_name
102
103  config(config_name) {
104    include_dirs = [ cc_out_dir ]
105  }
106
107  # The XXX_gen action that generates the .pb.{cc,h} files.
108  action(action_name) {
109    visibility = [ ":$source_set_name" ]
110    script = "//build/gn_run_binary.py"
111    sources = proto_sources
112    outputs = get_path_info(protogens, "abspath")
113
114    protoc_label = "//:protoc($host_toolchain)"
115    protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc" +
116                  host_executable_suffix
117    args = [
118      # Path should be rebased because |root_build_dir| for current toolchain
119      # may be different from |root_out_dir| of protoc built on host toolchain.
120      "./" + rebase_path(protoc_path, root_build_dir),
121      "--proto_path",
122      rebase_path(proto_in_dir, root_build_dir),
123    ]
124    if (generate_cc) {
125      cc_generator_options_ = ""
126      if (defined(invoker.cc_generator_options)) {
127        cc_generator_options_ = invoker.cc_generator_options
128      }
129      args += [
130        "--cpp_out",
131        cc_generator_options_ + rel_cc_out_dir,
132      ]
133    }
134    if (generate_descriptor != "") {
135      args += [
136        "--include_imports",
137        "--descriptor_set_out",
138        rebase_path("$root_gen_dir/" + generate_descriptor, root_build_dir),
139      ]
140    }
141
142    if (defined(invoker.import_dirs)) {
143      foreach(path, invoker.import_dirs) {
144        args += [ "--import-dir=" + rebase_path(path, root_build_dir) ]
145      }
146    }
147
148    if (generate_with_plugin) {
149      plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
150      plugin_out_args = ""
151      if (defined(invoker.generator_plugin_options)) {
152        plugin_out_args += invoker.generator_plugin_options
153      }
154      plugin_out_args += ":$rel_cc_out_dir"
155
156      args += [
157        "--plugin=protoc-gen-plugin=$plugin_path_rebased",
158        "--plugin_out=$plugin_out_args",
159      ]
160    }
161
162    args += rebase_path(proto_sources, root_build_dir)
163
164    inputs = [ protoc_path ]
165
166    deps = [ protoc_label ]
167    if (generate_with_plugin) {
168      inputs += [ plugin_path ]
169      if (defined(plugin_host_label)) {
170        # Action depends on native generator plugin but for host toolchain only.
171        deps += [ plugin_host_label ]
172      }
173    }
174
175    if (defined(invoker.proto_deps)) {
176      deps += invoker.proto_deps
177    }
178    if (defined(invoker.deps)) {
179      deps += invoker.deps
180    }
181  }  # action "${target_name}_gen"
182
183  # The source_set that builds the generated .pb.cc files.
184  source_set(target_name) {
185    forward_variables_from(invoker,
186                           [
187                             "defines",
188                             "include_dirs",
189                             "public_configs",
190                             "testonly",
191                             "visibility",
192                           ])
193
194    sources = get_target_outputs(":$action_name")
195
196    # configs -= [ "//gn/standalone:extra_warnings" ]
197    if (defined(invoker.extra_configs)) {
198      configs += invoker.extra_configs
199    }
200
201    if (!defined(invoker.public_configs)) {
202      public_configs = []
203    }
204
205    public_configs += [ "//:protobuf_gen_config" ]
206
207    propagate_imports_configs = !defined(invoker.propagate_imports_configs) ||
208                                invoker.propagate_imports_configs
209    if (propagate_imports_configs) {
210      public_configs += [ ":$config_name" ]
211    } else {
212      # Embedder handles include directory propagation to dependents.
213      configs += [ ":$config_name" ]
214    }
215
216    # Use protobuf_full only for tests.
217    if (defined(invoker.use_protobuf_full) &&
218        invoker.use_protobuf_full == true) {
219      deps = [ "//:protobuf_full" ]
220    } else {
221      deps = [ "//:protobuf_lite" ]
222    }
223
224    deps += [ ":$action_name" ]
225    if (defined(invoker.deps)) {
226      deps += invoker.deps
227    }
228    if (defined(invoker.link_deps)) {
229      deps += invoker.link_deps
230    }
231  }  # source_set(target_name)
232}  # template
233