OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 # Compile a protocol buffer. | 5 # Compile a protocol buffer. |
6 # | 6 # |
7 # Protobuf parameters: | 7 # Protobuf parameters: |
8 # | 8 # |
| 9 # proto_in_dir (optional) |
| 10 # Specifies the path relative to the current BUILD.gn file where |
| 11 # proto files are located and the directory structure of |
| 12 # this proto library starts. |
| 13 # |
| 14 # This option can be calculated automatically but it will raise an |
| 15 # assertion error if any nested directories are found. |
| 16 # |
9 # proto_out_dir (optional) | 17 # proto_out_dir (optional) |
10 # Specifies the path suffix that output files are generated under. This | 18 # Specifies the path suffix that output files are generated under. |
11 # path will be appended to the root_gen_dir. | 19 # This path will be appended to |root_gen_dir|, but for python stubs |
12 # | 20 # it will be appended to |root_build_dir|/pyproto. |
13 # Targets that depend on the proto target will be able to include the | |
14 # resulting proto headers with an include like: | |
15 # #include "dir/for/my_proto_lib/foo.pb.h" | |
16 # If undefined, this defaults to matching the input directory for each | |
17 # .proto file (you should almost always use the default mode). | |
18 # | 21 # |
19 # generate_python (optional, default true) | 22 # generate_python (optional, default true) |
20 # Generate Python protobuf stubs. | 23 # Generate Python protobuf stubs. |
21 # | 24 # |
22 # generate_cc (optional, default true) | 25 # generate_cc (optional, default true) |
23 # Generate C++ protobuf stubs. | 26 # Generate C++ protobuf stubs. |
24 # | 27 # |
25 # cc_generator_options (optional) | 28 # cc_generator_options (optional) |
26 # List of extra flags passed to the protocol compiler. If you need to | 29 # List of extra flags passed to the protocol compiler. If you need to |
27 # add an EXPORT macro to a protobuf's C++ header, set the | 30 # add an EXPORT macro to a protobuf's C++ header, set the |
28 # 'cc_generator_options' variable with the value: | 31 # 'cc_generator_options' variable with the value: |
29 # 'dllexport_decl=FOO_EXPORT:' (note trailing colon). | 32 # 'dllexport_decl=FOO_EXPORT:' (note trailing colon). |
30 # | 33 # |
31 # It is likely you also need to #include a file for the above EXPORT | 34 # It is likely you also need to #include a file for the above EXPORT |
32 # macro to work (see cc_include) and set | 35 # macro to work (see cc_include) and set |
33 # component_build_force_source_set = true. | 36 # component_build_force_source_set = true. |
34 # | 37 # |
| 38 # cc_include (optional) |
| 39 # String listing an extra include that should be passed. |
| 40 # Example: cc_include = "foo/bar.h" |
| 41 # |
35 # generator_plugin_label (optional) | 42 # generator_plugin_label (optional) |
36 # GN label for plugin executable which generates custom cc stubs. | 43 # GN label for plugin executable which generates custom cc stubs. |
| 44 # Don't specify a toolchain, host toolchain is assumed. |
37 # | 45 # |
38 # generator_plugin_suffix (required if generator_plugin_label set) | 46 # generator_plugin_suffix (required if |generator_plugin_label| set) |
39 # Suffix (before extension) for generated .cc and .h files. | 47 # Suffix (before extension) for generated .cc and .h files. |
40 # | 48 # |
41 # generator_plugin_options (optional) | 49 # generator_plugin_options (optional) |
42 # Extra flags passed to the plugin. See cc_generator_options. | 50 # Extra flags passed to the plugin. See cc_generator_options. |
43 # | 51 # |
44 # json_converter (optional) | |
45 # The plugin executable to generate JSON converter. | |
46 # | |
47 # cc_include (optional) | |
48 # String listing an extra include that should be passed. | |
49 # Example: cc_include = "foo/bar.h" | |
50 # | |
51 # deps (optional) | 52 # deps (optional) |
52 # Additional dependencies. | 53 # Additional dependencies. |
53 # | 54 # |
54 # inputs (optional) | |
55 # Additional inputs for dependency checking. | |
56 # | |
57 # Parameters for compiling the generated code: | 55 # Parameters for compiling the generated code: |
58 # | 56 # |
59 # component_build_force_source_set (Default=false) | 57 # component_build_force_source_set (Default=false) |
60 # When set true the generated code will be compiled as a source set in | 58 # When set true the generated code will be compiled as a source set in |
61 # the component build. This does not affect static builds. If you are | 59 # the component build. This does not affect static builds. If you are |
62 # exporting symbols from a component, this is required to prevent those | 60 # exporting symbols from a component, this is required to prevent those |
63 # symbols from being stripped. If you're not using dllexports in | 61 # symbols from being stripped. If you're not using dllexports in |
64 # cc_generator_options, it's usually best to leave this false. | 62 # cc_generator_options, it's usually best to leave this false. |
65 # | 63 # |
66 # defines (optional) | 64 # defines (optional) |
67 # Defines to supply to the source set that compiles the generated source | 65 # Defines to supply to the source set that compiles the generated source |
68 # code. | 66 # code. |
69 # | 67 # |
70 # extra_configs (optional) | 68 # extra_configs (optional) |
71 # A list of config labels that will be appended to the configs applying | 69 # A list of config labels that will be appended to the configs applying |
72 # to the source set. | 70 # to the source set. |
73 # | 71 # |
74 # Example | 72 # Example: |
75 # proto_library("mylib") { | 73 # proto_library("mylib") { |
76 # sources = [ | 74 # sources = [ |
77 # "foo.proto", | 75 # "foo.proto", |
78 # ] | 76 # ] |
79 # } | 77 # } |
80 | 78 |
81 template("proto_library") { | 79 template("proto_library") { |
82 assert(defined(invoker.sources), "Need sources for proto_library") | 80 assert(defined(invoker.sources), "Need sources for proto_library") |
| 81 proto_sources = invoker.sources |
83 | 82 |
84 # Don't apply OS-specific sources filtering to the assignments later on. | 83 # Don't apply OS-specific sources filtering to the assignments later on. |
85 # Platform files should have gotten filtered out in the sources assignment | 84 # Platform files should have gotten filtered out in the sources assignment |
86 # when this template was invoked. If they weren't, it was on purpose and | 85 # when this template was invoked. If they weren't, it was on purpose and |
87 # this template shouldn't re-apply the filter. | 86 # this template shouldn't re-apply the filter. |
88 set_sources_assignment_filter([]) | 87 set_sources_assignment_filter([]) |
89 | 88 |
| 89 if (defined(invoker.generate_cc)) { |
| 90 generate_cc = invoker.generate_cc |
| 91 } else { |
| 92 generate_cc = true |
| 93 } |
| 94 |
| 95 if (defined(invoker.generate_python)) { |
| 96 generate_python = invoker.generate_python |
| 97 } else { |
| 98 generate_python = true |
| 99 } |
| 100 |
| 101 if (defined(invoker.generator_plugin_label)) { |
| 102 generator_plugin_label = invoker.generator_plugin_label |
| 103 generator_plugin_suffix = invoker.generator_plugin_suffix |
| 104 generate_with_plugin = true |
| 105 |
| 106 # Straightforward way to get the name of executable doesn't work because |
| 107 # |root_out_dir| and |root_build_dir| may differ in cross-compilation and |
| 108 # also Windows executables have .exe at the end. |
| 109 |
| 110 plugin_host_label = generator_plugin_label + "($host_toolchain)" |
| 111 plugin_path = get_label_info(plugin_host_label, "root_out_dir") + "/" + |
| 112 get_label_info(plugin_host_label, "name") |
| 113 if (host_os == "win") { |
| 114 plugin_path += ".exe" |
| 115 } |
| 116 plugin_path = rebase_path(plugin_path, root_build_dir) |
| 117 } else { |
| 118 generate_with_plugin = false |
| 119 } |
| 120 |
| 121 # TODO(kraynov): Remove (in the next CL) merge conflict temporary workaround. |
| 122 # This option along with |inputs| would be replaced by the following pattern: |
| 123 # source_set("some_python_plugin") { |
| 124 # sources = [ |
| 125 # "bar.py", |
| 126 # ... |
| 127 # ] |
| 128 # } |
| 129 # proto_library("some_proto_lib") { |
| 130 # generator_plugin_label = ":some_python_plugin" |
| 131 # generator_plugin_suffix = ".pb.foo" |
| 132 # generator_plugin_script = "bar.py" |
| 133 # } |
| 134 if (defined(invoker.json_converter)) { |
| 135 generator_plugin_suffix = "_json_converter" |
| 136 plugin_path = rebase_path(invoker.json_converter) |
| 137 invoker.generator_plugin_options = "output_dir=:" |
| 138 generate_with_plugin = true |
| 139 } |
| 140 |
| 141 if (defined(invoker.proto_in_dir)) { |
| 142 proto_in_dir = invoker.proto_in_dir |
| 143 has_nested_dirs = false |
| 144 foreach(proto_source, proto_sources) { |
| 145 if (get_path_info(proto_source, "dir") != proto_in_dir) { |
| 146 has_nested_dirs = true |
| 147 } |
| 148 } |
| 149 } else { |
| 150 proto_in_dir = get_path_info(proto_sources[0], "dir") |
| 151 has_nested_dirs = false |
| 152 |
| 153 # Sanity check, |proto_in_dir| should be defined to allow sub-directories. |
| 154 foreach(proto_source, proto_sources) { |
| 155 assert(get_path_info(proto_source, "dir") == proto_in_dir, |
| 156 "Please define |proto_in_dir| to allow nested directories.") |
| 157 } |
| 158 } |
| 159 |
| 160 # Avoid absolute path because of the assumption that |proto_in_dir| is |
| 161 # relative to the directory of current BUILD.gn file. |
| 162 proto_in_dir = rebase_path(proto_in_dir, ".") |
| 163 |
| 164 if (defined(invoker.proto_out_dir)) { |
| 165 proto_out_dir = invoker.proto_out_dir |
| 166 } else { |
| 167 # Absolute path to the directory of current BUILD.gn file excluding "//". |
| 168 proto_out_dir = rebase_path(".", "//") |
| 169 if (proto_in_dir != ".") { |
| 170 proto_out_dir += "/$proto_in_dir" |
| 171 } |
| 172 } |
| 173 |
| 174 # We need both absolute path to use in GN statements and a relative one |
| 175 # to pass to external script. |
| 176 if (generate_cc || generate_with_plugin) { |
| 177 cc_out_dir = "$root_gen_dir/" + proto_out_dir |
| 178 rel_cc_out_dir = rebase_path(cc_out_dir, root_build_dir) |
| 179 } |
| 180 if (generate_python) { |
| 181 py_out_dir = "$root_out_dir/pyproto/" + proto_out_dir |
| 182 rel_py_out_dir = rebase_path(py_out_dir, root_build_dir) |
| 183 } |
| 184 |
| 185 protos = rebase_path(invoker.sources, proto_in_dir) |
| 186 protogens = [] |
| 187 |
| 188 # List output files. |
| 189 foreach(proto, protos) { |
| 190 proto_dir = get_path_info(proto, "dir") |
| 191 proto_name = get_path_info(proto, "name") |
| 192 proto_path = proto_dir + "/" + proto_name |
| 193 |
| 194 if (generate_cc) { |
| 195 protogens += [ |
| 196 "$cc_out_dir/$proto_path.pb.h", |
| 197 "$cc_out_dir/$proto_path.pb.cc", |
| 198 ] |
| 199 } |
| 200 if (generate_python) { |
| 201 protogens += [ "$py_out_dir/${proto_path}_pb2.py" ] |
| 202 } |
| 203 if (generate_with_plugin) { |
| 204 # TODO(kraynov): Remove merge conflict temporary workaround. |
| 205 if (defined(invoker.json_converter)) { |
| 206 protogens += [ "$cc_out_dir/${proto_path}$generator_plugin_suffix.h" ] |
| 207 } else { |
| 208 protogens += [ |
| 209 "$cc_out_dir/${proto_path}$generator_plugin_suffix.h", |
| 210 "$cc_out_dir/${proto_path}$generator_plugin_suffix.cc", |
| 211 ] |
| 212 } |
| 213 } |
| 214 } |
| 215 |
90 action_name = "${target_name}_gen" | 216 action_name = "${target_name}_gen" |
91 source_set_name = target_name | 217 source_set_name = target_name |
92 action_foreach(action_name) { | 218 |
| 219 # Generate protobuf stubs. |
| 220 action(action_name) { |
93 visibility = [ ":$source_set_name" ] | 221 visibility = [ ":$source_set_name" ] |
94 | |
95 script = "//tools/protoc_wrapper/protoc_wrapper.py" | 222 script = "//tools/protoc_wrapper/protoc_wrapper.py" |
96 | 223 sources = proto_sources |
97 sources = invoker.sources | 224 outputs = get_path_info(protogens, "abspath") |
98 | 225 args = protos |
99 # Compute the output directory, both relative to the source root (for | 226 |
100 # declaring "outputs") and relative to the build dir (for passing to the | |
101 # script). | |
102 if (defined(invoker.proto_out_dir)) { | |
103 proto_out_dir = invoker.proto_out_dir | |
104 } else { | |
105 proto_out_dir = "{{source_root_relative_dir}}" | |
106 } | |
107 out_dir = "$root_gen_dir/" + proto_out_dir | |
108 rel_out_dir = rebase_path(out_dir, root_build_dir) | |
109 | |
110 outputs = [] | |
111 | |
112 inputs = [] | |
113 if (defined(invoker.inputs)) { | 227 if (defined(invoker.inputs)) { |
114 inputs += invoker.inputs | 228 inputs = invoker.inputs |
115 } | 229 } |
116 | 230 |
117 args = [] | 231 protoc_label = "//third_party/protobuf:protoc($host_toolchain)" |
118 if (defined(invoker.cc_include)) { | 232 protoc_out_dir = get_label_info(protoc_label, "root_out_dir") |
| 233 args += [ |
| 234 # Wrapper should never pick a system protoc. |
| 235 # Path should be rebased because |root_build_dir| for current toolchain |
| 236 # may be different from |root_out_dir| of protoc built on host toolchain. |
| 237 "--protoc", |
| 238 "./" + rebase_path(protoc_out_dir, root_build_dir) + "/protoc", |
| 239 "--proto-in-dir", |
| 240 rebase_path(proto_in_dir, root_build_dir), |
| 241 ] |
| 242 |
| 243 if (generate_cc) { |
119 args += [ | 244 args += [ |
120 "--include", | 245 "--cc-out-dir", |
121 invoker.cc_include, | 246 rel_cc_out_dir, |
122 "--protobuf", | 247 ] |
123 "$rel_out_dir/{{source_name_part}}.pb.h", | 248 if (defined(invoker.cc_generator_options)) { |
124 ] | 249 args += [ |
125 } | 250 "--cc-options", |
126 | 251 invoker.cc_generator_options, |
127 args += [ | 252 ] |
128 "--proto-in-dir", | 253 } |
129 "{{source_dir}}", | 254 if (defined(invoker.cc_include)) { |
130 "--proto-in-file", | 255 args += [ |
131 "{{source_file_part}}", | 256 "--include", |
132 | 257 invoker.cc_include, |
133 # TODO(brettw) support system protobuf compiler. | 258 ] |
134 "--use-system-protobuf=0", | 259 } |
135 ] | 260 } |
136 | 261 |
137 protoc_label = "//third_party/protobuf:protoc($host_toolchain)" | 262 if (generate_python) { |
138 args += [ | |
139 "--", | |
140 | |
141 # Prepend with "./" so this will never pick up the system one (normally | |
142 # when not cross-compiling, protoc's output directory will be the same | |
143 # as the build dir, so the relative location will be empty). | |
144 "./" + | |
145 rebase_path(get_label_info(protoc_label, "root_out_dir") + "/protoc", | |
146 root_build_dir), | |
147 ] | |
148 | |
149 if (!defined(invoker.generate_python) || invoker.generate_python) { | |
150 py_out_dir = "$root_out_dir/pyproto/" + proto_out_dir | |
151 rel_py_out_dir = rebase_path(py_out_dir, root_build_dir) | |
152 | |
153 outputs += [ "$py_out_dir/{{source_name_part}}_pb2.py" ] | |
154 args += [ | 263 args += [ |
155 "--python_out", | 264 "--py-out-dir", |
156 rel_py_out_dir, | 265 rel_py_out_dir, |
157 ] | 266 ] |
158 } | 267 } |
159 | 268 |
160 if (!defined(invoker.generate_cc) || invoker.generate_cc) { | 269 if (generate_with_plugin) { |
161 # If passed cc_generator_options should end in a colon, which will | |
162 # separate it from the directory when we concatenate them. The proto | |
163 # compiler understands this syntax. | |
164 if (defined(invoker.cc_generator_options)) { | |
165 cc_generator_options = invoker.cc_generator_options | |
166 } else { | |
167 cc_generator_options = "" | |
168 } | |
169 outputs += [ | |
170 "$out_dir/{{source_name_part}}.pb.cc", | |
171 "$out_dir/{{source_name_part}}.pb.h", | |
172 ] | |
173 args += [ | |
174 "--cpp_out", | |
175 "$cc_generator_options$rel_out_dir", # Separated by colon. | |
176 ] | |
177 } | |
178 | |
179 if (defined(invoker.generator_plugin_label)) { | |
180 generator_plugin_label = invoker.generator_plugin_label | |
181 generator_plugin_suffix = invoker.generator_plugin_suffix | |
182 if (defined(invoker.generator_plugin_options)) { | |
183 generator_plugin_options = invoker.generator_plugin_options | |
184 } else { | |
185 generator_plugin_options = "" | |
186 } | |
187 outputs += [ | |
188 "$out_dir/{{source_name_part}}$generator_plugin_suffix.cc", | |
189 "$out_dir/{{source_name_part}}$generator_plugin_suffix.h", | |
190 ] | |
191 | |
192 # Straightforward way to get the name of executable doesn't work because | |
193 # root_out_dir and root_build_dir may differ in cross-compilation and | |
194 # also Windows executables have .exe at the end. | |
195 | |
196 plugin_host_label = generator_plugin_label + "($host_toolchain)" | |
197 plugin_path = get_label_info(plugin_host_label, "root_out_dir") + "/" + | |
198 get_label_info(plugin_host_label, "name") | |
199 if (host_os == "win") { | |
200 plugin_path += ".exe" | |
201 } | |
202 | |
203 # Need "./" for script to find plugin binary (working dir is not on PATH). | |
204 args += [ | 270 args += [ |
205 "--plugin", | 271 "--plugin", |
206 "protoc-gen-plugin=./" + rebase_path(plugin_path, root_build_dir), | 272 plugin_path, |
207 "--plugin_out", | 273 "--plugin-out-dir", |
208 "$generator_plugin_options$rel_out_dir", # Separated by colon. | 274 rel_cc_out_dir, |
209 ] | 275 ] |
| 276 if (defined(invoker.generator_plugin_options)) { |
| 277 args += [ |
| 278 "--plugin-options", |
| 279 invoker.generator_plugin_options, |
| 280 ] |
| 281 } |
210 } | 282 } |
211 | 283 |
212 deps = [ | 284 deps = [ |
| 285 # System protoc is not used so it's necessary to build a chromium one. |
213 protoc_label, | 286 protoc_label, |
214 ] | 287 ] |
215 if (defined(plugin_host_label)) { | 288 if (defined(plugin_host_label)) { |
| 289 # Action depends on generator plugin but for host toolchain only. |
216 deps += [ plugin_host_label ] | 290 deps += [ plugin_host_label ] |
217 } | 291 } |
218 | |
219 # The deps may have steps that have to run before running protobuf. | |
220 if (defined(invoker.deps)) { | 292 if (defined(invoker.deps)) { |
| 293 # The deps may have steps that have to run before running protoc. |
221 deps += invoker.deps | 294 deps += invoker.deps |
222 } | 295 } |
223 | 296 } |
224 if (defined(invoker.json_converter)) { | 297 |
225 args += [ | 298 # Option to disable building a library in component build. |
226 "--plugin=protoc-gen-json_converter=" + | |
227 # It is required to use backslash on Windows for .bat files. | |
228 rebase_path(invoker.json_converter), | |
229 "--json_converter_out=output_dir=:$rel_out_dir", | |
230 ] | |
231 inputs += [ invoker.json_converter ] | |
232 outputs += [ "$out_dir/{{source_name_part}}_json_converter.h" ] | |
233 } | |
234 } | |
235 | |
236 if (defined(invoker.component_build_force_source_set) && | 299 if (defined(invoker.component_build_force_source_set) && |
237 invoker.component_build_force_source_set && is_component_build) { | 300 invoker.component_build_force_source_set && |
| 301 is_component_build) { |
238 link_target_type = "source_set" | 302 link_target_type = "source_set" |
239 } else { | 303 } else { |
240 link_target_type = "static_library" | 304 link_target_type = "static_library" |
241 } | 305 } |
| 306 |
| 307 # Generated files may include other generated headers. These includes always |
| 308 # use relative paths starting at |cc_out_dir|. |
| 309 # However there is no necessity to add an additional directory, if all protos |
| 310 # are located in the same directory which is in the search path by default. |
| 311 if (has_nested_dirs) { |
| 312 config_name = "${target_name}_config" |
| 313 config(config_name) { |
| 314 include_dirs = [ cc_out_dir ] |
| 315 } |
| 316 } |
| 317 |
| 318 # Build generated protobuf stubs as libary or source set. |
242 target(link_target_type, target_name) { | 319 target(link_target_type, target_name) { |
243 forward_variables_from(invoker, | 320 forward_variables_from(invoker, |
244 [ | 321 [ |
245 "visibility", | 322 "visibility", |
246 "defines", | 323 "defines", |
247 ]) | 324 ]) |
248 | 325 |
249 sources = get_target_outputs(":$action_name") | 326 sources = get_target_outputs(":$action_name") |
250 | 327 |
251 if (defined(invoker.extra_configs)) { | 328 if (defined(invoker.extra_configs)) { |
252 configs += invoker.extra_configs | 329 configs += invoker.extra_configs |
253 } | 330 } |
254 | 331 |
255 public_configs = [ "//third_party/protobuf:using_proto" ] | 332 public_configs = [ "//third_party/protobuf:using_proto" ] |
256 | 333 |
257 # If using built-in cc generator the resulting headers reference headers | 334 if (generate_cc || generate_with_plugin) { |
258 # within protobuf_lite, hence dependencies require those headers too. | 335 # Not necessary if all protos are located in the same directory. |
259 # In case of generator plugin such issues should be resolved by invoker. | 336 if (has_nested_dirs) { |
260 if (!defined(invoker.generate_cc) || invoker.generate_cc) { | 337 # It's not enough to set |include_dirs| for target since public imports |
261 public_deps = [ | 338 # expose corresponding includes to header files as well. |
262 "//third_party/protobuf:protobuf_lite", | 339 public_configs += [ ":$config_name" ] |
263 ] | 340 } |
| 341 |
| 342 # If using built-in cc generator, the resulting headers reference headers |
| 343 # within protobuf_lite. Hence, dependencies require those headers too. |
| 344 # If using generator plugin, extra deps should be resolved by the invoker. |
| 345 if (generate_cc) { |
| 346 public_deps = [ |
| 347 "//third_party/protobuf:protobuf_lite", |
| 348 ] |
| 349 } |
264 } | 350 } |
| 351 |
265 deps = [ | 352 deps = [ |
266 ":$action_name", | 353 ":$action_name", |
267 ] | 354 ] |
268 | 355 |
269 # This will link any libraries in the deps (the use of invoker.deps in the | 356 # This will link any libraries in the deps (the use of invoker.deps in the |
270 # action won't link it). | 357 # action won't link it). |
271 if (defined(invoker.deps)) { | 358 if (defined(invoker.deps)) { |
272 deps += invoker.deps | 359 deps += invoker.deps |
273 } | 360 } |
274 } | 361 } |
275 } | 362 } |
OLD | NEW |