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, 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 44def _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 109def 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 198def 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 222def 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 252def 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 310def 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