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
15template("proto_library") {
16  assert(defined(invoker.sources))
17  proto_sources = invoker.sources
18
19  # All the proto imports should be relative to the project root.
20  proto_in_dir = "//"
21  if (defined(invoker.proto_in_dir)) {
22    proto_in_dir = invoker.proto_in_dir
23  }
24  assert(defined(invoker.proto_out_dir),
25         "proto_out_dir must be explicitly defined")
26  proto_out_dir = invoker.proto_out_dir
27
28  # We don't support generate_python in the standalone build, but still must
29  # check that the caller sets this to false. This is because when building in
30  # the chromium tree, chromium's proto_library.gni in chrome (!= this) defaults
31  # generate_python = true.
32  assert(defined(invoker.generate_python) && !invoker.generate_python)
33
34  # If false will not generate the default .pb.{cc,h} files. Used for custom
35  # codegen plugins.
36  generate_cc = true
37  if (defined(invoker.generate_cc)) {
38    generate_cc = invoker.generate_cc
39  }
40
41  if (defined(invoker.generator_plugin_label)) {
42    plugin_host_label = invoker.generator_plugin_label + "($host_toolchain)"
43    plugin_path = get_label_info(plugin_host_label, "root_out_dir") + "/" +
44                  get_label_info(plugin_host_label, "name")
45    generate_with_plugin = true
46  } else if (defined(invoker.generator_plugin_script)) {
47    plugin_path = invoker.generator_plugin_script
48    generate_with_plugin = true
49  } else {
50    generate_with_plugin = false
51  }
52
53  if (generate_with_plugin) {
54    if (defined(invoker.generator_plugin_suffix)) {
55      generator_plugin_suffixes = [
56        "${invoker.generator_plugin_suffix}.h",
57        "${invoker.generator_plugin_suffix}.cc",
58      ]
59    } else {
60      generator_plugin_suffixes = invoker.generator_plugin_suffixes
61    }
62  }
63
64  cc_out_dir = "$root_gen_dir/" + proto_out_dir
65  rel_cc_out_dir = rebase_path(cc_out_dir, root_build_dir)
66
67  protos = rebase_path(proto_sources, proto_in_dir)
68  protogens = []
69
70  foreach(proto, protos) {
71    proto_dir = get_path_info(proto, "dir")
72    proto_name = get_path_info(proto, "name")
73    proto_path = proto_dir + "/" + proto_name
74
75    if (generate_cc) {
76      protogens += [
77        "$cc_out_dir/$proto_path.pb.h",
78        "$cc_out_dir/$proto_path.pb.cc",
79      ]
80    }
81    if (generate_with_plugin) {
82      foreach(suffix, generator_plugin_suffixes) {
83        protogens += [ "$cc_out_dir/${proto_path}${suffix}" ]
84      }
85    }
86  }
87
88  config_name = "${target_name}_config"
89  action_name = "${target_name}_gen"
90  source_set_name = target_name
91
92  config(config_name) {
93    include_dirs = [ cc_out_dir ]
94  }
95
96  # The XXX_gen action that generates the .pb.{cc,h} files.
97  action(action_name) {
98    visibility = [ ":$source_set_name" ]
99    script = "//gn/standalone/build_tool_wrapper.py"
100    sources = proto_sources
101    outputs = get_path_info(protogens, "abspath")
102
103    protoc_label = "//buildtools:protoc($host_toolchain)"
104    protoc_path = get_label_info(protoc_label, "root_out_dir") + "/protoc"
105    args = [
106      # Path should be rebased because |root_build_dir| for current toolchain
107      # may be different from |root_out_dir| of protoc built on host toolchain.
108      "./" + rebase_path(protoc_path, root_build_dir),
109      "--proto_path",
110      rebase_path(proto_in_dir, root_build_dir),
111    ]
112    if (generate_cc) {
113      args += [
114        "--cpp_out",
115        rel_cc_out_dir,
116      ]
117    }
118
119    if (generate_with_plugin) {
120      plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
121      plugin_out_args = ""
122      if (defined(invoker.generator_plugin_options)) {
123        plugin_out_args += invoker.generator_plugin_options
124      }
125      plugin_out_args += ":$rel_cc_out_dir"
126
127      args += [
128        "--plugin=protoc-gen-plugin=$plugin_path_rebased",
129        "--plugin_out=$plugin_out_args",
130      ]
131    }
132
133    args += rebase_path(proto_sources, root_build_dir)
134
135    inputs = [
136      protoc_path,
137    ]
138
139    deps = [
140      protoc_label,
141    ]
142    if (generate_with_plugin) {
143      inputs += [ plugin_path ]
144      if (defined(plugin_host_label)) {
145        # Action depends on native generator plugin but for host toolchain only.
146        deps += [ plugin_host_label ]
147      }
148    }
149
150    if (defined(invoker.deps)) {
151      deps += invoker.deps
152    }
153  }  # action "${target_name}_gen"
154
155  # The source_set that builds the generated .pb.cc files.
156  source_set(target_name) {
157    forward_variables_from(invoker,
158                           [
159                             "defines",
160                             "include_dirs",
161                             "public_configs",
162                             "testonly",
163                             "visibility",
164                           ])
165
166    sources = get_target_outputs(":$action_name")
167
168    configs -= [ "//gn/standalone:extra_warnings" ]
169    if (defined(invoker.extra_configs)) {
170      configs += invoker.extra_configs
171    }
172
173    if (!defined(invoker.public_configs)) {
174      public_configs = []
175    }
176
177    public_configs += [
178      "//buildtools:protobuf_gen_config",
179      ":$config_name",
180    ]
181
182    # Use protobuf_full only for tests.
183    if (defined(invoker.use_protobuf_full) &&
184        invoker.use_protobuf_full == true) {
185      deps = [
186        "//buildtools:protobuf_full",
187      ]
188    } else {
189      deps = [
190        "//buildtools:protobuf_lite",
191      ]
192    }
193
194    deps += [ ":$action_name" ]
195    if (defined(invoker.deps)) {
196      deps += invoker.deps
197    }
198  }  # source_set(target_name)
199}  # template
200