OLD | NEW |
1 # -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED | |
2 | |
3 def _GetPath(ctx, path): | 1 def _GetPath(ctx, path): |
4 if ctx.label.workspace_root: | 2 if ctx.label.workspace_root: |
5 return ctx.label.workspace_root + '/' + path | 3 return ctx.label.workspace_root + '/' + path |
6 else: | 4 else: |
7 return path | 5 return path |
8 | 6 |
9 def _GenDir(ctx): | 7 def _GenDir(ctx): |
10 if not ctx.attr.includes: | 8 if not ctx.attr.includes: |
11 return ctx.label.workspace_root | 9 return ctx.label.workspace_root |
12 if not ctx.attr.includes[0]: | 10 if not ctx.attr.includes[0]: |
13 return _GetPath(ctx, ctx.label.package) | 11 return _GetPath(ctx, ctx.label.package) |
14 if not ctx.label.package: | 12 if not ctx.label.package: |
15 return _GetPath(ctx, ctx.attr.includes[0]) | 13 return _GetPath(ctx, ctx.attr.includes[0]) |
16 return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0]) | 14 return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0]) |
17 | 15 |
| 16 def _CcHdrs(srcs, use_grpc_plugin=False): |
| 17 ret = [s[:-len(".proto")] + ".pb.h" for s in srcs] |
| 18 if use_grpc_plugin: |
| 19 ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs] |
| 20 return ret |
| 21 |
| 22 def _CcSrcs(srcs, use_grpc_plugin=False): |
| 23 ret = [s[:-len(".proto")] + ".pb.cc" for s in srcs] |
| 24 if use_grpc_plugin: |
| 25 ret += [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs] |
| 26 return ret |
| 27 |
18 def _CcOuts(srcs, use_grpc_plugin=False): | 28 def _CcOuts(srcs, use_grpc_plugin=False): |
19 ret = [s[:-len(".proto")] + ".pb.h" for s in srcs] + \ | 29 return _CcHdrs(srcs, use_grpc_plugin) + _CcSrcs(srcs, use_grpc_plugin) |
20 [s[:-len(".proto")] + ".pb.cc" for s in srcs] | |
21 if use_grpc_plugin: | |
22 ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs] + \ | |
23 [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs] | |
24 return ret | |
25 | 30 |
26 def _PyOuts(srcs): | 31 def _PyOuts(srcs): |
27 return [s[:-len(".proto")] + "_pb2.py" for s in srcs] | 32 return [s[:-len(".proto")] + "_pb2.py" for s in srcs] |
28 | 33 |
29 def _RelativeOutputPath(path, include): | 34 def _RelativeOutputPath(path, include, dest=""): |
30 if include == None: | 35 if include == None: |
31 return path | 36 return path |
32 | 37 |
33 if not path.startswith(include): | 38 if not path.startswith(include): |
34 fail("Include path %s isn't part of the path %s." % (include, path)) | 39 fail("Include path %s isn't part of the path %s." % (include, path)) |
35 | 40 |
36 if include and include[-1] != '/': | 41 if include and include[-1] != '/': |
37 include = include + '/' | 42 include = include + '/' |
| 43 if dest and dest[-1] != '/': |
| 44 dest = dest + '/' |
38 | 45 |
39 path = path[len(include):] | 46 path = path[len(include):] |
40 | 47 return dest + path |
41 if not path.startswith(PACKAGE_NAME): | |
42 fail("The package %s is not within the path %s" % (PACKAGE_NAME, path)) | |
43 | |
44 if not PACKAGE_NAME: | |
45 return path | |
46 | |
47 return path[len(PACKAGE_NAME)+1:] | |
48 | 48 |
49 def _proto_gen_impl(ctx): | 49 def _proto_gen_impl(ctx): |
50 """General implementation for generating protos""" | 50 """General implementation for generating protos""" |
51 srcs = ctx.files.srcs | 51 srcs = ctx.files.srcs |
52 deps = [] | 52 deps = [] |
53 deps += ctx.files.srcs | 53 deps += ctx.files.srcs |
54 gen_dir = _GenDir(ctx) | 54 gen_dir = _GenDir(ctx) |
55 if gen_dir: | 55 if gen_dir: |
56 import_flags = ["-I" + gen_dir] | 56 import_flags = ["-I" + gen_dir, "-I" + ctx.var["GENDIR"] + "/" + gen_dir] |
57 else: | 57 else: |
58 import_flags = ["-I."] | 58 import_flags = ["-I."] |
59 | 59 |
60 for dep in ctx.attr.deps: | 60 for dep in ctx.attr.deps: |
61 import_flags += dep.proto.import_flags | 61 import_flags += dep.proto.import_flags |
62 deps += dep.proto.deps | 62 deps += dep.proto.deps |
63 | 63 |
64 args = [] | 64 args = [] |
65 if ctx.attr.gen_cc: | 65 if ctx.attr.gen_cc: |
66 args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir] | 66 args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir] |
67 if ctx.attr.gen_py: | 67 if ctx.attr.gen_py: |
68 args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir] | 68 args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir] |
69 | 69 |
70 if ctx.executable.grpc_cpp_plugin: | 70 inputs = srcs + deps |
71 args += ["--plugin=protoc-gen-grpc=" + ctx.executable.grpc_cpp_plugin.path] | 71 if ctx.executable.plugin: |
72 args += ["--grpc_out=" + ctx.var["GENDIR"] + "/" + gen_dir] | 72 plugin = ctx.executable.plugin |
| 73 lang = ctx.attr.plugin_language |
| 74 if not lang and plugin.basename.startswith('protoc-gen-'): |
| 75 lang = plugin.basename[len('protoc-gen-'):] |
| 76 if not lang: |
| 77 fail("cannot infer the target language of plugin", "plugin_language") |
| 78 |
| 79 outdir = ctx.var["GENDIR"] + "/" + gen_dir |
| 80 if ctx.attr.plugin_options: |
| 81 outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir |
| 82 args += ["--plugin=protoc-gen-%s=%s" % (lang, plugin.path)] |
| 83 args += ["--%s_out=%s" % (lang, outdir)] |
| 84 inputs += [plugin] |
73 | 85 |
74 if args: | 86 if args: |
75 ctx.action( | 87 ctx.action( |
76 inputs=srcs + deps, | 88 inputs=inputs, |
77 outputs=ctx.outputs.outs, | 89 outputs=ctx.outputs.outs, |
78 arguments=args + import_flags + [s.path for s in srcs], | 90 arguments=args + import_flags + [s.path for s in srcs], |
79 executable=ctx.executable.protoc, | 91 executable=ctx.executable.protoc, |
| 92 mnemonic="ProtoCompile", |
80 ) | 93 ) |
81 | 94 |
82 return struct( | 95 return struct( |
83 proto=struct( | 96 proto=struct( |
84 srcs=srcs, | 97 srcs=srcs, |
85 import_flags=import_flags, | 98 import_flags=import_flags, |
86 deps=deps, | 99 deps=deps, |
87 ), | 100 ), |
88 ) | 101 ) |
89 | 102 |
90 _proto_gen = rule( | 103 proto_gen = rule( |
91 attrs = { | 104 attrs = { |
92 "srcs": attr.label_list(allow_files = True), | 105 "srcs": attr.label_list(allow_files = True), |
93 "deps": attr.label_list(providers = ["proto"]), | 106 "deps": attr.label_list(providers = ["proto"]), |
94 "includes": attr.string_list(), | 107 "includes": attr.string_list(), |
95 "protoc": attr.label( | 108 "protoc": attr.label( |
96 cfg = HOST_CFG, | 109 cfg = "host", |
97 executable = True, | 110 executable = True, |
98 single_file = True, | 111 single_file = True, |
99 mandatory = True, | 112 mandatory = True, |
100 ), | 113 ), |
101 "grpc_cpp_plugin": attr.label( | 114 "plugin": attr.label( |
102 cfg = HOST_CFG, | 115 cfg = "host", |
| 116 allow_files = True, |
103 executable = True, | 117 executable = True, |
104 single_file = True, | |
105 ), | 118 ), |
| 119 "plugin_language": attr.string(), |
| 120 "plugin_options": attr.string_list(), |
106 "gen_cc": attr.bool(), | 121 "gen_cc": attr.bool(), |
107 "gen_py": attr.bool(), | 122 "gen_py": attr.bool(), |
108 "outs": attr.output_list(), | 123 "outs": attr.output_list(), |
109 }, | 124 }, |
110 output_to_genfiles = True, | 125 output_to_genfiles = True, |
111 implementation = _proto_gen_impl, | 126 implementation = _proto_gen_impl, |
112 ) | 127 ) |
| 128 """Generates codes from Protocol Buffers definitions. |
| 129 |
| 130 This rule helps you to implement Skylark macros specific to the target |
| 131 language. You should prefer more specific `cc_proto_library `, |
| 132 `py_proto_library` and others unless you are adding such wrapper macros. |
| 133 |
| 134 Args: |
| 135 srcs: Protocol Buffers definition files (.proto) to run the protocol compiler |
| 136 against. |
| 137 deps: a list of dependency labels; must be other proto libraries. |
| 138 includes: a list of include paths to .proto files. |
| 139 protoc: the label of the protocol compiler to generate the sources. |
| 140 plugin: the label of the protocol compiler plugin to be passed to the protocol |
| 141 compiler. |
| 142 plugin_language: the language of the generated sources |
| 143 plugin_options: a list of options to be passed to the plugin |
| 144 gen_cc: generates C++ sources in addition to the ones from the plugin. |
| 145 gen_py: generates Python sources in addition to the ones from the plugin. |
| 146 outs: a list of labels of the expected outputs from the protocol compiler. |
| 147 """ |
113 | 148 |
114 def cc_proto_library( | 149 def cc_proto_library( |
115 name, | 150 name, |
116 srcs=[], | 151 srcs=[], |
117 deps=[], | 152 deps=[], |
118 cc_libs=[], | 153 cc_libs=[], |
119 include=None, | 154 include=None, |
120 protoc="//:protoc", | 155 protoc="//:protoc", |
121 internal_bootstrap_hack=False, | 156 internal_bootstrap_hack=False, |
122 use_grpc_plugin=False, | 157 use_grpc_plugin=False, |
(...skipping 25 matching lines...) Expand all Loading... |
148 | 183 |
149 """ | 184 """ |
150 | 185 |
151 includes = [] | 186 includes = [] |
152 if include != None: | 187 if include != None: |
153 includes = [include] | 188 includes = [include] |
154 | 189 |
155 if internal_bootstrap_hack: | 190 if internal_bootstrap_hack: |
156 # For pre-checked-in generated files, we add the internal_bootstrap_hack | 191 # For pre-checked-in generated files, we add the internal_bootstrap_hack |
157 # which will skip the codegen action. | 192 # which will skip the codegen action. |
158 _proto_gen( | 193 proto_gen( |
159 name=name + "_genproto", | 194 name=name + "_genproto", |
160 srcs=srcs, | 195 srcs=srcs, |
161 deps=[s + "_genproto" for s in deps], | 196 deps=[s + "_genproto" for s in deps], |
162 includes=includes, | 197 includes=includes, |
163 protoc=protoc, | 198 protoc=protoc, |
164 visibility=["//visibility:public"], | 199 visibility=["//visibility:public"], |
165 ) | 200 ) |
166 # An empty cc_library to make rule dependency consistent. | 201 # An empty cc_library to make rule dependency consistent. |
167 native.cc_library( | 202 native.cc_library( |
168 name=name, | 203 name=name, |
169 **kargs) | 204 **kargs) |
170 return | 205 return |
171 | 206 |
172 grpc_cpp_plugin = None | 207 grpc_cpp_plugin = None |
173 if use_grpc_plugin: | 208 if use_grpc_plugin: |
174 grpc_cpp_plugin = "//external:grpc_cpp_plugin" | 209 grpc_cpp_plugin = "//external:grpc_cpp_plugin" |
175 | 210 |
176 outs = _CcOuts(srcs, use_grpc_plugin) | 211 gen_srcs = _CcSrcs(srcs, use_grpc_plugin) |
| 212 gen_hdrs = _CcHdrs(srcs, use_grpc_plugin) |
| 213 outs = gen_srcs + gen_hdrs |
177 | 214 |
178 _proto_gen( | 215 proto_gen( |
179 name=name + "_genproto", | 216 name=name + "_genproto", |
180 srcs=srcs, | 217 srcs=srcs, |
181 deps=[s + "_genproto" for s in deps], | 218 deps=[s + "_genproto" for s in deps], |
182 includes=includes, | 219 includes=includes, |
183 protoc=protoc, | 220 protoc=protoc, |
184 grpc_cpp_plugin=grpc_cpp_plugin, | 221 plugin=grpc_cpp_plugin, |
| 222 plugin_language="grpc", |
185 gen_cc=1, | 223 gen_cc=1, |
186 outs=outs, | 224 outs=outs, |
187 visibility=["//visibility:public"], | 225 visibility=["//visibility:public"], |
188 ) | 226 ) |
189 | 227 |
190 if default_runtime and not default_runtime in cc_libs: | 228 if default_runtime and not default_runtime in cc_libs: |
191 cc_libs += [default_runtime] | 229 cc_libs += [default_runtime] |
192 if use_grpc_plugin: | 230 if use_grpc_plugin: |
193 cc_libs += ["//external:grpc_lib"] | 231 cc_libs += ["//external:grpc_lib"] |
194 | 232 |
195 native.cc_library( | 233 native.cc_library( |
196 name=name, | 234 name=name, |
197 srcs=outs, | 235 srcs=gen_srcs, |
| 236 hdrs=gen_hdrs, |
198 deps=cc_libs + deps, | 237 deps=cc_libs + deps, |
199 includes=includes, | 238 includes=includes, |
200 **kargs) | 239 **kargs) |
201 | 240 |
202 | |
203 def internal_gen_well_known_protos_java(srcs): | 241 def internal_gen_well_known_protos_java(srcs): |
204 """Bazel rule to generate the gen_well_known_protos_java genrule | 242 """Bazel rule to generate the gen_well_known_protos_java genrule |
205 | 243 |
206 Args: | 244 Args: |
207 srcs: the well known protos | 245 srcs: the well known protos |
208 """ | 246 """ |
209 root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root | 247 root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root |
210 if root == "": | 248 if root == "": |
211 include = " -Isrc " | 249 include = " -Isrc " |
212 else: | 250 else: |
213 include = " -I%s/src " % root | 251 include = " -I%s/src " % root |
214 native.genrule( | 252 native.genrule( |
215 name = "gen_well_known_protos_java", | 253 name = "gen_well_known_protos_java", |
216 srcs = srcs, | 254 srcs = srcs, |
217 outs = [ | 255 outs = [ |
218 "wellknown.srcjar", | 256 "wellknown.srcjar", |
219 ], | 257 ], |
220 cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" + | 258 cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" + |
221 " %s $(SRCS) " % include + | 259 " %s $(SRCS) " % include + |
222 " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar", | 260 " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar", |
223 tools = [":protoc"], | 261 tools = [":protoc"], |
224 ) | 262 ) |
225 | 263 |
| 264 def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs): |
| 265 """Macro to copy files to a different directory and then create a filegroup. |
| 266 |
| 267 This is used by the //:protobuf_python py_proto_library target to work around |
| 268 an issue caused by Python source files that are part of the same Python |
| 269 package being in separate directories. |
| 270 |
| 271 Args: |
| 272 srcs: The source files to copy and add to the filegroup. |
| 273 strip_prefix: Path to the root of the files to copy. |
| 274 dest: The directory to copy the source files into. |
| 275 **kwargs: extra arguments that will be passesd to the filegroup. |
| 276 """ |
| 277 outs = [_RelativeOutputPath(s, strip_prefix, dest) for s in srcs] |
| 278 |
| 279 native.genrule( |
| 280 name = name + "_genrule", |
| 281 srcs = srcs, |
| 282 outs = outs, |
| 283 cmd = " && ".join( |
| 284 ["cp $(location %s) $(location %s)" % |
| 285 (s, _RelativeOutputPath(s, strip_prefix, dest)) for s in srcs]), |
| 286 ) |
| 287 |
| 288 native.filegroup( |
| 289 name = name, |
| 290 srcs = outs, |
| 291 **kwargs) |
226 | 292 |
227 def py_proto_library( | 293 def py_proto_library( |
228 name, | 294 name, |
229 srcs=[], | 295 srcs=[], |
230 deps=[], | 296 deps=[], |
231 py_libs=[], | 297 py_libs=[], |
232 py_extra_srcs=[], | 298 py_extra_srcs=[], |
233 include=None, | 299 include=None, |
234 default_runtime="//:protobuf_python", | 300 default_runtime="//:protobuf_python", |
235 protoc="//:protoc", | 301 protoc="//:protoc", |
| 302 use_grpc_plugin=False, |
236 **kargs): | 303 **kargs): |
237 """Bazel rule to create a Python protobuf library from proto source files | 304 """Bazel rule to create a Python protobuf library from proto source files |
238 | 305 |
239 NOTE: the rule is only an internal workaround to generate protos. The | 306 NOTE: the rule is only an internal workaround to generate protos. The |
240 interface may change and the rule may be removed when bazel has introduced | 307 interface may change and the rule may be removed when bazel has introduced |
241 the native rule. | 308 the native rule. |
242 | 309 |
243 Args: | 310 Args: |
244 name: the name of the py_proto_library. | 311 name: the name of the py_proto_library. |
245 srcs: the .proto files of the py_proto_library. | 312 srcs: the .proto files of the py_proto_library. |
246 deps: a list of dependency labels; must be py_proto_library. | 313 deps: a list of dependency labels; must be py_proto_library. |
247 py_libs: a list of other py_library targets depended by the generated | 314 py_libs: a list of other py_library targets depended by the generated |
248 py_library. | 315 py_library. |
249 py_extra_srcs: extra source files that will be added to the output | 316 py_extra_srcs: extra source files that will be added to the output |
250 py_library. This attribute is used for internal bootstrapping. | 317 py_library. This attribute is used for internal bootstrapping. |
251 include: a string indicating the include path of the .proto files. | 318 include: a string indicating the include path of the .proto files. |
252 default_runtime: the implicitly default runtime which will be depended on by | 319 default_runtime: the implicitly default runtime which will be depended on by |
253 the generated py_library target. | 320 the generated py_library target. |
254 protoc: the label of the protocol compiler to generate the sources. | 321 protoc: the label of the protocol compiler to generate the sources. |
| 322 use_grpc_plugin: a flag to indicate whether to call the Python C++ plugin |
| 323 when processing the proto files. |
255 **kargs: other keyword arguments that are passed to cc_library. | 324 **kargs: other keyword arguments that are passed to cc_library. |
256 | 325 |
257 """ | 326 """ |
258 outs = _PyOuts(srcs) | 327 outs = _PyOuts(srcs) |
259 | 328 |
260 includes = [] | 329 includes = [] |
261 if include != None: | 330 if include != None: |
262 includes = [include] | 331 includes = [include] |
263 | 332 |
264 _proto_gen( | 333 grpc_python_plugin = None |
| 334 if use_grpc_plugin: |
| 335 grpc_python_plugin = "//external:grpc_python_plugin" |
| 336 # Note: Generated grpc code depends on Python grpc module. This dependency |
| 337 # is not explicitly listed in py_libs. Instead, host system is assumed to |
| 338 # have grpc installed. |
| 339 |
| 340 proto_gen( |
265 name=name + "_genproto", | 341 name=name + "_genproto", |
266 srcs=srcs, | 342 srcs=srcs, |
267 deps=[s + "_genproto" for s in deps], | 343 deps=[s + "_genproto" for s in deps], |
268 includes=includes, | 344 includes=includes, |
269 protoc=protoc, | 345 protoc=protoc, |
270 gen_py=1, | 346 gen_py=1, |
271 outs=outs, | 347 outs=outs, |
272 visibility=["//visibility:public"], | 348 visibility=["//visibility:public"], |
| 349 plugin=grpc_python_plugin, |
| 350 plugin_language="grpc" |
273 ) | 351 ) |
274 | 352 |
275 if default_runtime and not default_runtime in py_libs + deps: | 353 if default_runtime and not default_runtime in py_libs + deps: |
276 py_libs += [default_runtime] | 354 py_libs += [default_runtime] |
277 | 355 |
278 native.py_library( | 356 native.py_library( |
279 name=name, | 357 name=name, |
280 srcs=outs+py_extra_srcs, | 358 srcs=outs+py_extra_srcs, |
281 deps=py_libs+deps, | 359 deps=py_libs+deps, |
282 imports=includes, | 360 imports=includes, |
(...skipping 12 matching lines...) Expand all Loading... |
295 kargs: extra parameters that will be passed into the py_test. | 373 kargs: extra parameters that will be passed into the py_test. |
296 | 374 |
297 """ | 375 """ |
298 for m in modules: | 376 for m in modules: |
299 s = "python/google/protobuf/internal/%s.py" % m | 377 s = "python/google/protobuf/internal/%s.py" % m |
300 native.py_test( | 378 native.py_test( |
301 name="py_%s" % m, | 379 name="py_%s" % m, |
302 srcs=[s], | 380 srcs=[s], |
303 main=s, | 381 main=s, |
304 **kargs) | 382 **kargs) |
OLD | NEW |