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