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