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