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 # cc_include (optional) | |
45 # String listing an extra include that should be passed. | |
46 # Example: cc_include = "foo/bar.h" | |
47 # | |
48 # deps (optional) | 52 # deps (optional) |
49 # Additional dependencies. | 53 # Additional dependencies. |
50 # | 54 # |
51 # Parameters for compiling the generated code: | 55 # Parameters for compiling the generated code: |
52 # | 56 # |
53 # component_build_force_source_set (Default=false) | 57 # component_build_force_source_set (Default=false) |
54 # 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 |
55 # 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 |
56 # exporting symbols from a component, this is required to prevent those | 60 # exporting symbols from a component, this is required to prevent those |
57 # symbols from being stripped. If you're not using dllexports in | 61 # symbols from being stripped. If you're not using dllexports in |
58 # cc_generator_options, it's usually best to leave this false. | 62 # cc_generator_options, it's usually best to leave this false. |
59 # | 63 # |
60 # defines (optional) | 64 # defines (optional) |
61 # 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 |
62 # code. | 66 # code. |
63 # | 67 # |
64 # extra_configs (optional) | 68 # extra_configs (optional) |
65 # 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 |
66 # to the source set. | 70 # to the source set. |
67 # | 71 # |
68 # Example | 72 # Example: |
69 # proto_library("mylib") { | 73 # proto_library("mylib") { |
70 # sources = [ | 74 # sources = [ |
71 # "foo.proto", | 75 # "foo.proto", |
72 # ] | 76 # ] |
73 # } | 77 # } |
74 | 78 |
75 template("proto_library") { | 79 template("proto_library") { |
76 assert(defined(invoker.sources), "Need sources for proto_library") | 80 assert(defined(invoker.sources), "Need sources for proto_library") |
81 proto_sources = invoker.sources | |
77 | 82 |
78 # 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. |
79 # Platform files should have gotten filtered out in the sources assignment | 84 # Platform files should have gotten filtered out in the sources assignment |
80 # 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 |
81 # this template shouldn't re-apply the filter. | 86 # this template shouldn't re-apply the filter. |
82 set_sources_assignment_filter([]) | 87 set_sources_assignment_filter([]) |
83 | 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 if (defined(invoker.proto_in_dir)) { | |
122 proto_in_dir = invoker.proto_in_dir | |
123 } else { | |
124 proto_in_dir = get_path_info(proto_sources[0], "dir") | |
125 | |
126 # Sanity check, |proto_in_dir| should be defined to allow sub-directories. | |
127 foreach(proto_source, proto_sources) { | |
128 assert(get_path_info(proto_source, "dir") == proto_in_dir, | |
129 "Please define |proto_in_dir| to allow nested directories.") | |
130 } | |
131 } | |
132 | |
133 # Avoid absolute path because of the assumption that |proto_in_dir| is | |
134 # relative to the directory of current BUILD.gn file. | |
135 proto_in_dir = rebase_path(proto_in_dir, ".") | |
136 | |
137 if (defined(invoker.proto_out_dir)) { | |
138 proto_out_dir = invoker.proto_out_dir | |
139 } else { | |
140 # Absolute path to the directory of current BUILD.gn file excluding "//". | |
141 proto_out_dir = rebase_path(".", "//") | |
142 if (proto_in_dir != ".") { | |
143 proto_out_dir += "/$proto_in_dir" | |
144 } | |
145 } | |
146 | |
147 # We need both absolute path to use in GN statements and a relative one | |
148 # to pass to external script. | |
149 if (generate_cc || generate_with_plugin) { | |
150 cc_out_dir = "$root_gen_dir/" + proto_out_dir | |
151 rel_cc_out_dir = rebase_path(cc_out_dir, root_build_dir) | |
152 } | |
153 if (generate_python) { | |
154 py_out_dir = "$root_out_dir/pyproto/" + proto_out_dir | |
155 rel_py_out_dir = rebase_path(py_out_dir, root_build_dir) | |
156 } | |
157 | |
158 protos = rebase_path(invoker.sources, proto_in_dir) | |
159 protogens = [] | |
160 | |
161 # List output files. | |
162 foreach(proto, protos) { | |
163 proto_dir = get_path_info(proto, "dir") | |
164 proto_name = get_path_info(proto, "name") | |
165 proto_path = proto_dir + "/" + proto_name | |
166 | |
167 if (generate_cc) { | |
168 protogens += [ | |
169 "$cc_out_dir/$proto_path.pb.h", | |
170 "$cc_out_dir/$proto_path.pb.cc", | |
171 ] | |
172 } | |
173 if (generate_python) { | |
174 protogens += [ "$py_out_dir/${proto_path}_pb2.py" ] | |
175 } | |
176 if (generate_with_plugin) { | |
177 protogens += [ | |
178 "$cc_out_dir/${proto_path}$generator_plugin_suffix.h", | |
179 "$cc_out_dir/${proto_path}$generator_plugin_suffix.cc", | |
180 ] | |
181 } | |
182 } | |
183 | |
84 action_name = "${target_name}_gen" | 184 action_name = "${target_name}_gen" |
85 source_set_name = target_name | 185 source_set_name = target_name |
86 action_foreach(action_name) { | 186 |
187 # Generate protobuf stubs. | |
188 action(action_name) { | |
87 visibility = [ ":$source_set_name" ] | 189 visibility = [ ":$source_set_name" ] |
190 script = "//tools/protoc_wrapper/protoc_wrapper.py" | |
191 sources = proto_sources | |
192 outputs = get_path_info(protogens, "abspath") | |
193 args = protos | |
88 | 194 |
89 script = "//tools/protoc_wrapper/protoc_wrapper.py" | 195 protoc_label = "//third_party/protobuf:protoc($host_toolchain)" |
196 protoc_out_dir = get_label_info(protoc_label, "root_out_dir") | |
197 args += [ | |
198 # Wrapper should never pick a system protoc. | |
199 # Path should be rebased because |root_build_dir| for current toolchain | |
200 # may be different from |root_out_dir| of protoc built on host toolchain. | |
201 "--protoc", | |
202 "./" + rebase_path(protoc_out_dir, root_build_dir) + "/protoc", | |
203 "--proto-in-dir", | |
204 rebase_path(proto_in_dir, root_build_dir), | |
205 ] | |
90 | 206 |
91 sources = invoker.sources | 207 if (generate_cc) { |
92 | |
93 # Compute the output directory, both relative to the source root (for | |
94 # declaring "outputs") and relative to the build dir (for passing to the | |
95 # script). | |
96 if (defined(invoker.proto_out_dir)) { | |
97 proto_out_dir = invoker.proto_out_dir | |
98 } else { | |
99 proto_out_dir = "{{source_root_relative_dir}}" | |
100 } | |
101 out_dir = "$root_gen_dir/" + proto_out_dir | |
102 rel_out_dir = rebase_path(out_dir, root_build_dir) | |
103 | |
104 outputs = [] | |
105 | |
106 args = [] | |
107 if (defined(invoker.cc_include)) { | |
108 args += [ | 208 args += [ |
109 "--include", | 209 "--cc-out-dir", |
110 invoker.cc_include, | 210 rel_cc_out_dir, |
111 "--protobuf", | |
112 "$rel_out_dir/{{source_name_part}}.pb.h", | |
113 ] | 211 ] |
212 if (defined(invoker.cc_generator_options)) { | |
213 args += [ | |
214 "--cc-options", | |
215 invoker.cc_generator_options, | |
216 ] | |
217 } | |
218 if (defined(invoker.cc_include)) { | |
219 args += [ | |
220 "--include", | |
221 invoker.cc_include, | |
222 ] | |
223 } | |
114 } | 224 } |
115 | 225 |
116 args += [ | 226 if (generate_python) { |
117 "--proto-in-dir", | |
118 "{{source_dir}}", | |
119 "--proto-in-file", | |
120 "{{source_file_part}}", | |
121 | |
122 # TODO(brettw) support system protobuf compiler. | |
123 "--use-system-protobuf=0", | |
124 ] | |
125 | |
126 protoc_label = "//third_party/protobuf:protoc($host_toolchain)" | |
127 args += [ | |
128 "--", | |
129 | |
130 # Prepend with "./" so this will never pick up the system one (normally | |
131 # when not cross-compiling, protoc's output directory will be the same | |
132 # as the build dir, so the relative location will be empty). | |
133 "./" + | |
134 rebase_path(get_label_info(protoc_label, "root_out_dir") + "/protoc", | |
135 root_build_dir), | |
136 ] | |
137 | |
138 if (!defined(invoker.generate_python) || invoker.generate_python) { | |
139 py_out_dir = "$root_out_dir/pyproto/" + proto_out_dir | |
140 rel_py_out_dir = rebase_path(py_out_dir, root_build_dir) | |
141 | |
142 outputs += [ "$py_out_dir/{{source_name_part}}_pb2.py" ] | |
143 args += [ | 227 args += [ |
144 "--python_out", | 228 "--py-out-dir", |
145 rel_py_out_dir, | 229 rel_py_out_dir, |
146 ] | 230 ] |
147 } | 231 } |
148 | 232 |
149 if (!defined(invoker.generate_cc) || invoker.generate_cc) { | 233 if (generate_with_plugin) { |
150 # If passed cc_generator_options should end in a colon, which will | |
151 # separate it from the directory when we concatenate them. The proto | |
152 # compiler understands this syntax. | |
153 if (defined(invoker.cc_generator_options)) { | |
154 cc_generator_options = invoker.cc_generator_options | |
155 } else { | |
156 cc_generator_options = "" | |
157 } | |
158 outputs += [ | |
159 "$out_dir/{{source_name_part}}.pb.cc", | |
160 "$out_dir/{{source_name_part}}.pb.h", | |
161 ] | |
162 args += [ | |
163 "--cpp_out", | |
164 "$cc_generator_options$rel_out_dir", # Separated by colon. | |
165 ] | |
166 } | |
167 | |
168 if (defined(invoker.generator_plugin_label)) { | |
169 generator_plugin_label = invoker.generator_plugin_label | |
170 generator_plugin_suffix = invoker.generator_plugin_suffix | |
171 if (defined(invoker.generator_plugin_options)) { | |
172 generator_plugin_options = invoker.generator_plugin_options | |
173 } else { | |
174 generator_plugin_options = "" | |
175 } | |
176 outputs += [ | |
177 "$out_dir/{{source_name_part}}$generator_plugin_suffix.cc", | |
178 "$out_dir/{{source_name_part}}$generator_plugin_suffix.h", | |
179 ] | |
180 | |
181 # Straightforward way to get the name of executable doesn't work because | |
182 # root_out_dir and root_build_dir may differ in cross-compilation and | |
183 # also Windows executables have .exe at the end. | |
184 | |
185 plugin_host_label = generator_plugin_label + "($host_toolchain)" | |
186 plugin_path = get_label_info(plugin_host_label, "root_out_dir") + "/" + | |
187 get_label_info(plugin_host_label, "name") | |
188 if (host_os == "win") { | |
189 plugin_path += ".exe" | |
190 } | |
191 | |
192 # Need "./" for script to find plugin binary (working dir is not on PATH). | |
193 args += [ | 234 args += [ |
194 "--plugin", | 235 "--plugin", |
195 "protoc-gen-plugin=./" + rebase_path(plugin_path, root_build_dir), | 236 plugin_path, |
196 "--plugin_out", | 237 "--plugin-out-dir", |
197 "$generator_plugin_options$rel_out_dir", # Separated by colon. | 238 rel_cc_out_dir, |
198 ] | 239 ] |
240 if (defined(invoker.generator_plugin_options)) { | |
241 args += [ | |
242 "--plugin-options", | |
243 invoker.generator_plugin_options, | |
244 ] | |
245 } | |
199 } | 246 } |
200 | 247 |
201 deps = [ | 248 deps = [ |
249 # System protoc is not used so it's necessary to build a chromium one. | |
202 protoc_label, | 250 protoc_label, |
203 ] | 251 ] |
204 if (defined(plugin_host_label)) { | 252 if (defined(plugin_host_label)) { |
253 # Action depends on generator plugin but for host toolchain only. | |
205 deps += [ plugin_host_label ] | 254 deps += [ plugin_host_label ] |
206 } | 255 } |
207 | |
208 # The deps may have steps that have to run before running protobuf. | |
209 if (defined(invoker.deps)) { | 256 if (defined(invoker.deps)) { |
257 # The deps may have steps that have to run before running protoc. | |
210 deps += invoker.deps | 258 deps += invoker.deps |
211 } | 259 } |
212 } | 260 } |
213 | 261 |
262 # Option to disable building a library in component build. | |
214 if (defined(invoker.component_build_force_source_set) && | 263 if (defined(invoker.component_build_force_source_set) && |
215 invoker.component_build_force_source_set && | 264 invoker.component_build_force_source_set && |
216 is_component_build) { | 265 is_component_build) { |
217 link_target_type = "source_set" | 266 link_target_type = "source_set" |
218 } else { | 267 } else { |
219 link_target_type = "static_library" | 268 link_target_type = "static_library" |
220 } | 269 } |
270 | |
271 # Build generated protobuf stubs as libary or source set. | |
221 target(link_target_type, target_name) { | 272 target(link_target_type, target_name) { |
222 forward_variables_from(invoker, | 273 forward_variables_from(invoker, |
223 [ | 274 [ |
224 "visibility", | 275 "visibility", |
225 "defines", | 276 "defines", |
226 ]) | 277 ]) |
227 | 278 |
228 sources = get_target_outputs(":$action_name") | 279 sources = get_target_outputs(":$action_name") |
229 | 280 |
230 if (defined(invoker.extra_configs)) { | 281 if (defined(invoker.extra_configs)) { |
231 configs += invoker.extra_configs | 282 configs += invoker.extra_configs |
232 } | 283 } |
233 | 284 |
234 public_configs = [ "//third_party/protobuf:using_proto" ] | 285 public_configs = [ "//third_party/protobuf:using_proto" ] |
235 | 286 |
236 # If using built-in cc generator the resulting headers reference headers | 287 include_dirs = [] |
237 # within protobuf_lite, hence dependencies require those headers too. | 288 if (generate_cc) { |
238 # In case of generator plugin such issues should be resolved by invoker. | 289 include_dirs += [ cc_out_dir ] |
brettw
2016/08/16 22:08:10
Does this include directory need to be applied to
kraynov
2016/08/17 00:40:34
Thank you! This case now fortified by unit test.
| |
239 if (!defined(invoker.generate_cc) || invoker.generate_cc) { | 290 |
291 # If using built-in cc generator, the resulting headers reference headers | |
292 # within protobuf_lite. Hence, dependencies require those headers too. | |
293 # If using generator plugin, extra deps should be resolved by the invoker. | |
240 public_deps = [ | 294 public_deps = [ |
241 "//third_party/protobuf:protobuf_lite", | 295 "//third_party/protobuf:protobuf_lite", |
242 ] | 296 ] |
243 } | 297 } |
298 if (generate_with_plugin) { | |
299 include_dirs += [ cc_out_dir ] | |
300 } | |
301 | |
244 deps = [ | 302 deps = [ |
245 ":$action_name", | 303 ":$action_name", |
246 ] | 304 ] |
247 | 305 |
248 # This will link any libraries in the deps (the use of invoker.deps in the | 306 # This will link any libraries in the deps (the use of invoker.deps in the |
249 # action won't link it). | 307 # action won't link it). |
250 if (defined(invoker.deps)) { | 308 if (defined(invoker.deps)) { |
251 deps += invoker.deps | 309 deps += invoker.deps |
252 } | 310 } |
253 } | 311 } |
254 } | 312 } |
OLD | NEW |