Home | History | Annotate | Download | only in protobuf
      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):
     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 
     49 def _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 
    114 def 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 
    203 def 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 
    227 def 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 
    285 def 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