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