blob: f674a6c6da6389079c378ca0c342fd549ec3c7be [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001# -*- mode: python; -*- PYTHON-PREPROCESSING-REQUIRED
2
3def _GetPath(ctx, path):
4 if ctx.label.workspace_root:
5 return ctx.label.workspace_root + '/' + path
6 else:
7 return path
8
9def _GenDir(ctx):
10 if not ctx.attr.includes:
11 return ctx.label.workspace_root
12 if not ctx.attr.includes[0]:
13 return _GetPath(ctx, ctx.label.package)
14 if not ctx.label.package:
15 return _GetPath(ctx, ctx.attr.includes[0])
16 return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
17
18def _CcOuts(srcs):
19 return [s[:-len(".proto")] + ".pb.h" for s in srcs] + \
20 [s[:-len(".proto")] + ".pb.cc" for s in srcs]
21
22def _PyOuts(srcs):
23 return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
24
25def _RelativeOutputPath(path, include):
26 if include == None:
27 return path
28
29 if not path.startswith(include):
30 fail("Include path %s isn't part of the path %s." % (include, path))
31
32 if include and include[-1] != '/':
33 include = include + '/'
34
35 path = path[len(include):]
36
37 if not path.startswith(PACKAGE_NAME):
38 fail("The package %s is not within the path %s" % (PACKAGE_NAME, path))
39
40 if not PACKAGE_NAME:
41 return path
42
43 return path[len(PACKAGE_NAME)+1:]
44
45def _proto_gen_impl(ctx):
46 """General implementation for generating protos"""
47 srcs = ctx.files.srcs
48 deps = []
49 deps += ctx.files.srcs
50 gen_dir = _GenDir(ctx)
51 if gen_dir:
52 import_flags = ["-I" + gen_dir]
53 else:
54 import_flags = ["-I."]
55
56 for dep in ctx.attr.deps:
57 import_flags += dep.proto.import_flags
58 deps += dep.proto.deps
59
60 args = []
61 if ctx.attr.gen_cc:
62 args += ["--cpp_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
63 if ctx.attr.gen_py:
64 args += ["--python_out=" + ctx.var["GENDIR"] + "/" + gen_dir]
65
66 if args:
67 ctx.action(
68 inputs=srcs + deps,
69 outputs=ctx.outputs.outs,
70 arguments=args + import_flags + [s.path for s in srcs],
71 executable=ctx.executable.protoc,
72 )
73
74 return struct(
75 proto=struct(
76 srcs=srcs,
77 import_flags=import_flags,
78 deps=deps,
79 ),
80 )
81
82_proto_gen = rule(
83 attrs = {
84 "srcs": attr.label_list(allow_files = True),
85 "deps": attr.label_list(providers = ["proto"]),
86 "includes": attr.string_list(),
87 "protoc": attr.label(
88 cfg = HOST_CFG,
89 executable = True,
90 single_file = True,
91 mandatory = True,
92 ),
93 "gen_cc": attr.bool(),
94 "gen_py": attr.bool(),
95 "outs": attr.output_list(),
96 },
97 output_to_genfiles = True,
98 implementation = _proto_gen_impl,
99)
100
101def cc_proto_library(
102 name,
103 srcs=[],
104 deps=[],
105 cc_libs=[],
106 include=None,
107 protoc="//google/protobuf:protoc",
108 internal_bootstrap_hack=False,
109 default_runtime="//google/protobuf:protobuf",
110 **kargs):
111 """Bazel rule to create a C++ protobuf library from proto source files
112
113 NOTE: the rule is only an internal workaround to generate protos. The
114 interface may change and the rule may be removed when bazel has introduced
115 the native rule.
116
117 Args:
118 name: the name of the cc_proto_library.
119 srcs: the .proto files of the cc_proto_library.
120 deps: a list of dependency labels; must be cc_proto_library.
121 cc_libs: a list of other cc_library targets depended by the generated
122 cc_library.
123 include: a string indicating the include path of the .proto files.
124 protoc: the label of the protocol compiler to generate the sources.
125 internal_bootstrap_hack: a flag indicate the cc_proto_library is used only
126 for bootstraping. When it is set to True, no files will be generated.
127 The rule will simply be a provider for .proto files, so that other
128 cc_proto_library can depend on it.
129 default_runtime: the implicitly default runtime which will be depended on by
130 the generated cc_library target.
131 **kargs: other keyword arguments that are passed to cc_library.
132
133 """
134
135 includes = []
136 if include != None:
137 includes = [include]
138
139 if internal_bootstrap_hack:
140 # For pre-checked-in generated files, we add the internal_bootstrap_hack
141 # which will skip the codegen action.
142 _proto_gen(
143 name=name + "_genproto",
144 srcs=srcs,
145 deps=[s + "_genproto" for s in deps],
146 includes=includes,
147 protoc=protoc,
148 visibility=["//visibility:public"],
149 )
150 # An empty cc_library to make rule dependency consistent.
151 native.cc_library(
152 name=name,
153 **kargs)
154 return
155
156 outs = _CcOuts(srcs)
157 _proto_gen(
158 name=name + "_genproto",
159 srcs=srcs,
160 deps=[s + "_genproto" for s in deps],
161 includes=includes,
162 protoc=protoc,
163 gen_cc=1,
164 outs=outs,
165 visibility=["//visibility:public"],
166 )
167
168 if default_runtime and not default_runtime in cc_libs:
169 cc_libs += [default_runtime]
170
171 native.cc_library(
172 name=name,
173 srcs=outs,
174 deps=cc_libs + deps,
175 includes=includes,
176 **kargs)
177
178
179def internal_copied_filegroup(
180 name,
181 srcs,
182 include,
183 **kargs):
184 """Bazel rule to fix sources file to workaround with python path issues.
185
186 Args:
187 name: the name of the internal_copied_filegroup rule, which will be the
188 name of the generated filegroup.
189 srcs: the source files to be copied.
190 include: the expected import root of the source.
191 **kargs: extra arguments that will be passed into the filegroup.
192 """
193 outs = [_RelativeOutputPath(s, include) for s in srcs]
194
195 native.genrule(
196 name=name+"_genrule",
197 srcs=srcs,
198 outs=outs,
199 cmd=" && ".join(["cp $(location %s) $(location %s)" %
200 (s, _RelativeOutputPath(s, include))
201 for s in srcs]))
202
203 native.filegroup(
204 name=name,
205 srcs=outs,
206 **kargs)
207
208
209def py_proto_library(
210 name,
211 srcs=[],
212 deps=[],
213 py_libs=[],
214 py_extra_srcs=[],
215 include=None,
216 default_runtime="//google/protobuf:protobuf_python",
217 protoc="//google/protobuf:protoc",
218 **kargs):
219 """Bazel rule to create a Python protobuf library from proto source files
220
221 NOTE: the rule is only an internal workaround to generate protos. The
222 interface may change and the rule may be removed when bazel has introduced
223 the native rule.
224
225 Args:
226 name: the name of the py_proto_library.
227 srcs: the .proto files of the py_proto_library.
228 deps: a list of dependency labels; must be py_proto_library.
229 py_libs: a list of other py_library targets depended by the generated
230 py_library.
231 py_extra_srcs: extra source files that will be added to the output
232 py_library. This attribute is used for internal bootstrapping.
233 include: a string indicating the include path of the .proto files.
234 default_runtime: the implicitly default runtime which will be depended on by
235 the generated py_library target.
236 protoc: the label of the protocol compiler to generate the sources.
237 **kargs: other keyword arguments that are passed to cc_library.
238
239 """
240 outs = _PyOuts(srcs)
241
242 includes = []
243 if include != None:
244 includes = [include]
245
246 _proto_gen(
247 name=name + "_genproto",
248 srcs=srcs,
249 deps=[s + "_genproto" for s in deps],
250 includes=includes,
251 protoc=protoc,
252 gen_py=1,
253 outs=outs,
254 visibility=["//visibility:public"],
255 )
256
257 if include != None:
258 # Copy the output files to the desired location to make the import work.
259 internal_copied_filegroup_name=name + "_internal_copied_filegroup"
260 internal_copied_filegroup(
261 name=internal_copied_filegroup_name,
262 srcs=outs,
263 include=include)
264 outs=[internal_copied_filegroup_name]
265
266 if default_runtime and not default_runtime in py_libs + deps:
267 py_libs += [default_runtime]
268
269 native.py_library(
270 name=name,
271 srcs=outs+py_extra_srcs,
272 deps=py_libs+deps,
273 **kargs)
274
275def internal_protobuf_py_tests(
276 name,
277 modules=[],
278 **kargs):
279 """Bazel rules to create batch tests for protobuf internal.
280
281 Args:
282 name: the name of the rule.
283 modules: a list of modules for tests. The macro will create a py_test for
284 each of the parameter with the source "google/protobuf/%s.py"
285 kargs: extra parameters that will be passed into the py_test.
286
287 """
288 for m in modules:
289 s = _RelativeOutputPath(
290 "python/google/protobuf/internal/%s.py" % m, "python")
291 native.py_test(
292 name="py_%s" % m,
293 srcs=[s],
294 main=s,
295 **kargs)