• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1load("@bazel_skylib//lib:versions.bzl", "versions")
2load("@rules_cc//cc:defs.bzl", "objc_library")
3load("@rules_python//python:defs.bzl", "py_library")
4load("//bazel/common:proto_info.bzl", "ProtoInfo")
5
6def _GetPath(ctx, path):
7    if ctx.label.workspace_root:
8        return ctx.label.workspace_root + "/" + path
9    else:
10        return path
11
12def _IsNewExternal(ctx):
13    # Bazel 0.4.4 and older have genfiles paths that look like:
14    #   bazel-out/local-fastbuild/genfiles/external/repo/foo
15    # After the exec root rearrangement, they look like:
16    #   ../repo/bazel-out/local-fastbuild/genfiles/foo
17    return ctx.label.workspace_root.startswith("../")
18
19def _GenDir(ctx):
20    if _IsNewExternal(ctx):
21        # We are using the fact that Bazel 0.4.4+ provides repository-relative paths
22        # for ctx.genfiles_dir.
23        return ctx.genfiles_dir.path + (
24            "/" + ctx.attr.includes[0] if ctx.attr.includes and ctx.attr.includes[0] else ""
25        )
26
27    # This means that we're either in the old version OR the new version in the local repo.
28    # Either way, appending the source path to the genfiles dir works.
29    return ctx.var["GENDIR"] + "/" + _SourceDir(ctx)
30
31def _SourceDir(ctx):
32    if not ctx.attr.includes:
33        return ctx.label.workspace_root
34    if not ctx.attr.includes[0]:
35        return _GetPath(ctx, ctx.label.package)
36    if not ctx.label.package:
37        return _GetPath(ctx, ctx.attr.includes[0])
38    return _GetPath(ctx, ctx.label.package + "/" + ctx.attr.includes[0])
39
40def _ObjcBase(srcs):
41    return [
42        "".join([token.capitalize() for token in src[:-len(".proto")].split("_")])
43        for src in srcs
44    ]
45
46def _ObjcHdrs(srcs):
47    return [src + ".pbobjc.h" for src in _ObjcBase(srcs)]
48
49def _ObjcSrcs(srcs):
50    return [src + ".pbobjc.m" for src in _ObjcBase(srcs)]
51
52def _ObjcOuts(srcs, out_type):
53    if out_type == "hdrs":
54        return _ObjcHdrs(srcs)
55    if out_type == "srcs":
56        return _ObjcSrcs(srcs)
57    return _ObjcHdrs(srcs) + _ObjcSrcs(srcs)
58
59def _PyOuts(srcs, use_grpc_plugin = False):
60    ret = [s[:-len(".proto")] + "_pb2.py" for s in srcs]
61    if use_grpc_plugin:
62        ret += [s[:-len(".proto")] + "_pb2_grpc.py" for s in srcs]
63    return ret
64
65def _RubyOuts(srcs):
66    return [s[:-len(".proto")] + "_pb.rb" for s in srcs]
67
68def _CsharpOuts(srcs):
69    return [
70        "".join([token.capitalize() for token in src[:-len(".proto")].split("_")]) + ".cs"
71        for src in srcs
72    ]
73
74ProtoGenInfo = provider(
75    fields = ["srcs", "import_flags", "deps"],
76)
77
78def _proto_gen_impl(ctx):
79    """General implementation for generating protos"""
80    srcs = ctx.files.srcs
81    langs = ctx.attr.langs or []
82    out_type = ctx.attr.out_type
83    enable_editions = ctx.attr.enable_editions
84    deps = depset(direct = ctx.files.srcs)
85    source_dir = _SourceDir(ctx)
86    gen_dir = _GenDir(ctx).rstrip("/")
87    import_flags = []
88
89    if source_dir:
90        has_sources = any([src.is_source for src in srcs])
91        if has_sources:
92            import_flags += ["-I" + source_dir]
93    else:
94        import_flags += ["-I."]
95
96    has_generated = any([not src.is_source for src in srcs])
97    if has_generated:
98        import_flags += ["-I" + gen_dir]
99
100    if ctx.attr.includes:
101        for include in ctx.attr.includes:
102            import_flags += ["-I" + _GetPath(ctx, include)]
103
104    import_flags = depset(direct = import_flags)
105
106    for dep in ctx.attr.deps:
107        dep_proto = dep[ProtoGenInfo]
108        if type(dep_proto.import_flags) == "list":
109            import_flags = depset(
110                transitive = [import_flags],
111                direct = dep_proto.import_flags,
112            )
113        else:
114            import_flags = depset(
115                transitive = [import_flags, dep_proto.import_flags],
116            )
117        if type(dep_proto.deps) == "list":
118            deps = depset(transitive = [deps], direct = dep_proto.deps)
119        else:
120            deps = depset(transitive = [deps, dep_proto.deps])
121
122    if not langs and not ctx.executable.plugin:
123        return [
124            ProtoGenInfo(
125                srcs = srcs,
126                import_flags = import_flags,
127                deps = deps,
128            ),
129        ]
130
131    generated_files = []
132    for src in srcs:
133        args = []
134        if enable_editions:
135            args.append("--experimental_editions")
136
137        in_gen_dir = src.root.path == gen_dir
138        if in_gen_dir:
139            import_flags_real = []
140            for f in import_flags.to_list():
141                path = f.replace("-I", "")
142                import_flags_real.append("-I$(realpath -s %s)" % path)
143
144        use_grpc_plugin = (ctx.attr.plugin_language == "grpc" and ctx.attr.plugin)
145        path_tpl = "$(realpath %s)" if in_gen_dir else "%s"
146
147        outs = []
148        for lang in langs:
149            if lang == "csharp":
150                outs.extend(_CsharpOuts([src.basename]))
151            elif lang == "objc":
152                outs.extend(_ObjcOuts([src.basename], out_type = out_type))
153            elif lang == "python":
154                outs.extend(_PyOuts([src.basename], use_grpc_plugin = use_grpc_plugin))
155            elif lang == "ruby":
156                outs.extend(_RubyOuts([src.basename]))
157
158            # Otherwise, rely on user-supplied outs.
159            args += [("--%s_out=" + path_tpl) % (lang, gen_dir)]
160
161        if ctx.attr.outs:
162            outs.extend(ctx.attr.outs)
163        outs = [ctx.actions.declare_file(out, sibling = src) for out in outs]
164        generated_files.extend(outs)
165
166        inputs = [src] + deps.to_list()
167        tools = [ctx.executable.protoc]
168        if ctx.executable.plugin:
169            plugin = ctx.executable.plugin
170            lang = ctx.attr.plugin_language
171            if not lang and plugin.basename.startswith("protoc-gen-"):
172                lang = plugin.basename[len("protoc-gen-"):]
173            if not lang:
174                fail("cannot infer the target language of plugin", "plugin_language")
175
176            outdir = "." if in_gen_dir else gen_dir
177
178            if ctx.attr.plugin_options:
179                outdir = ",".join(ctx.attr.plugin_options) + ":" + outdir
180            args += [("--plugin=protoc-gen-%s=" + path_tpl) % (lang, plugin.path)]
181            args += ["--%s_out=%s" % (lang, outdir)]
182            tools.append(plugin)
183
184        if not in_gen_dir:
185            ctx.actions.run(
186                inputs = inputs,
187                tools = tools,
188                outputs = outs,
189                arguments = args + import_flags.to_list() + [src.path],
190                executable = ctx.executable.protoc,
191                mnemonic = "ProtoCompile",
192                use_default_shell_env = True,
193            )
194        else:
195            for out in outs:
196                orig_command = " ".join(
197                    ["$(realpath %s)" % ctx.executable.protoc.path] + args +
198                    import_flags_real + [src.basename],
199                )
200                command = ";".join([
201                    'CMD="%s"' % orig_command,
202                    "cd %s" % src.dirname,
203                    "${CMD}",
204                    "cd -",
205                ])
206                generated_out = "/".join([gen_dir, out.basename])
207                if generated_out != out.path:
208                    command += ";mv %s %s" % (generated_out, out.path)
209                ctx.actions.run_shell(
210                    inputs = inputs,
211                    outputs = [out],
212                    command = command,
213                    mnemonic = "ProtoCompile",
214                    tools = tools,
215                    use_default_shell_env = True,
216                )
217
218    return [
219        ProtoGenInfo(
220            srcs = srcs,
221            import_flags = import_flags,
222            deps = deps,
223        ),
224        DefaultInfo(files = depset(generated_files)),
225    ]
226
227"""Generates codes from Protocol Buffers definitions.
228
229This rule helps you to implement Skylark macros specific to the target
230language. You should prefer more specific `cc_proto_library `,
231`py_proto_library` and others unless you are adding such wrapper macros.
232
233Args:
234  srcs: Protocol Buffers definition files (.proto) to run the protocol compiler
235    against.
236  deps: a list of dependency labels; must be other proto libraries.
237  enable_editions: if true, sets the --experimental_editions flag.
238  includes: a list of include paths to .proto files.
239  protoc: the label of the protocol compiler to generate the sources.
240  plugin: the label of the protocol compiler plugin to be passed to the protocol
241    compiler.
242  plugin_language: the language of the generated sources
243  plugin_options: a list of options to be passed to the plugin
244  langs: generates sources in addition to the ones from the plugin for each
245    specified language.
246  outs: a list of labels of the expected outputs from the protocol compiler.
247  out_type: only generated a single type of source file for languages that have
248    split sources (e.g. *.h and *.cc in C++)
249"""
250_proto_gen = rule(
251    attrs = {
252        "srcs": attr.label_list(allow_files = True),
253        "deps": attr.label_list(providers = [ProtoGenInfo]),
254        "enable_editions": attr.bool(),
255        "includes": attr.string_list(),
256        "protoc": attr.label(
257            cfg = "exec",
258            executable = True,
259            allow_single_file = True,
260            mandatory = True,
261        ),
262        "plugin": attr.label(
263            cfg = "exec",
264            allow_files = True,
265            executable = True,
266        ),
267        "plugin_language": attr.string(),
268        "plugin_options": attr.string_list(),
269        "langs": attr.string_list(),
270        "outs": attr.string_list(),
271        "out_type": attr.string(
272            default = "all",
273        ),
274    },
275    implementation = _proto_gen_impl,
276)
277
278def _internal_gen_well_known_protos_java_impl(ctx):
279    args = ctx.actions.args()
280
281    deps = [d[ProtoInfo] for d in ctx.attr.deps]
282
283    srcjar = ctx.actions.declare_file("{}.srcjar".format(ctx.attr.name))
284    if ctx.attr.javalite:
285        java_out = "lite:%s" % srcjar.path
286    else:
287        java_out = srcjar
288
289    args.add("--java_out", java_out)
290
291    descriptors = depset(
292        transitive = [dep.transitive_descriptor_sets for dep in deps],
293    )
294    args.add_joined(
295        "--descriptor_set_in",
296        descriptors,
297        join_with = ctx.configuration.host_path_separator,
298    )
299
300    for dep in deps:
301        if "." == dep.proto_source_root:
302            args.add_all([src.path for src in dep.direct_sources])
303        else:
304            source_root = dep.proto_source_root
305            offset = len(source_root) + 1  # + '/'.
306            args.add_all([src.path[offset:] for src in dep.direct_sources])
307
308    ctx.actions.run(
309        executable = ctx.executable._protoc,
310        inputs = descriptors,
311        outputs = [srcjar],
312        arguments = [args],
313        mnemonic = "ProtoCompile",
314        use_default_shell_env = True,
315    )
316
317    return [
318        DefaultInfo(
319            files = depset([srcjar]),
320        ),
321    ]
322
323internal_gen_well_known_protos_java = rule(
324    implementation = _internal_gen_well_known_protos_java_impl,
325    attrs = {
326        "deps": attr.label_list(
327            mandatory = True,
328            providers = [ProtoInfo],
329        ),
330        "javalite": attr.bool(
331            default = False,
332        ),
333        "_protoc": attr.label(
334            executable = True,
335            cfg = "exec",
336            default = "//:protoc",
337        ),
338    },
339)
340
341def _internal_gen_kt_protos(ctx):
342    args = ctx.actions.args()
343
344    deps = [d[ProtoInfo] for d in ctx.attr.deps]
345
346    srcjar = ctx.actions.declare_file("{}.srcjar".format(ctx.attr.name))
347    if ctx.attr.lite:
348        out = "lite:%s" % srcjar.path
349    else:
350        out = srcjar
351
352    args.add("--kotlin_out", out)
353
354    descriptors = depset(
355        transitive = [dep.transitive_descriptor_sets for dep in deps],
356    )
357    args.add_joined(
358        "--descriptor_set_in",
359        descriptors,
360        join_with = ctx.configuration.host_path_separator,
361    )
362
363    for dep in deps:
364        if "." == dep.proto_source_root:
365            args.add_all([src.path for src in dep.direct_sources])
366        else:
367            source_root = dep.proto_source_root
368            offset = len(source_root) + 1  # + '/'.
369            args.add_all([src.path[offset:] for src in dep.direct_sources])
370
371    ctx.actions.run(
372        executable = ctx.executable._protoc,
373        inputs = descriptors,
374        outputs = [srcjar],
375        arguments = [args],
376        mnemonic = "ProtoCompile",
377        use_default_shell_env = True,
378    )
379
380    return [
381        DefaultInfo(
382            files = depset([srcjar]),
383        ),
384    ]
385
386internal_gen_kt_protos = rule(
387    implementation = _internal_gen_kt_protos,
388    attrs = {
389        "deps": attr.label_list(
390            mandatory = True,
391            providers = [ProtoInfo],
392        ),
393        "lite": attr.bool(
394            default = False,
395        ),
396        "_protoc": attr.label(
397            executable = True,
398            cfg = "exec",
399            default = "//:protoc",
400        ),
401    },
402)
403
404def internal_objc_proto_library(
405        name,
406        srcs = [],
407        deps = [],
408        outs = [],
409        proto_deps = [],
410        includes = ["."],
411        default_runtime = Label("//:protobuf_objc"),
412        protoc = Label("//:protoc"),
413        testonly = None,
414        visibility = ["//visibility:public"],
415        **kwargs):
416    """Bazel rule to create a Objective-C protobuf library from proto sources
417
418    NOTE: the rule is only an internal workaround to generate protos. The
419    interface may change and the rule may be removed when bazel has introduced
420    the native rule.
421
422    Args:
423      name: the name of the objc_proto_library.
424      srcs: the .proto files to compile.
425      deps: a list of dependency labels; must be objc_proto_library.
426      outs: a list of expected output files.
427      proto_deps: a list of proto file dependencies that don't have a
428        objc_proto_library rule.
429      includes: a string indicating the include path of the .proto files.
430      default_runtime: the Objective-C Protobuf runtime
431      protoc: the label of the protocol compiler to generate the sources.
432      testonly: common rule attribute (see:
433          https://bazel.build/reference/be/common-definitions#common-attributes)
434      visibility: the visibility of the generated files.
435      **kwargs: other keyword arguments that are passed to py_library.
436
437    """
438    full_deps = [d + "_genproto" for d in deps]
439
440    if proto_deps:
441        _proto_gen(
442            name = name + "_deps_genproto",
443            testonly = testonly,
444            srcs = proto_deps,
445            protoc = protoc,
446            includes = includes,
447        )
448        full_deps.append(":%s_deps_genproto" % name)
449
450    # Note: we need to run the protoc build twice to get separate targets for
451    # the generated header and the source files.
452    _proto_gen(
453        name = name + "_genproto_hdrs",
454        srcs = srcs,
455        deps = full_deps,
456        langs = ["objc"],
457        out_type = "hdrs",
458        includes = includes,
459        protoc = protoc,
460        testonly = testonly,
461        visibility = visibility,
462        tags = ["manual"],
463    )
464
465    _proto_gen(
466        name = name + "_genproto",
467        srcs = srcs,
468        deps = full_deps,
469        langs = ["objc"],
470        out_type = "srcs",
471        includes = includes,
472        protoc = protoc,
473        testonly = testonly,
474        visibility = visibility,
475        tags = ["manual"],
476    )
477
478    objc_library(
479        name = name,
480        hdrs = [name + "_genproto_hdrs"],
481        non_arc_srcs = [name + "_genproto"],
482        deps = [default_runtime],
483        includes = includes,
484        testonly = testonly,
485        visibility = visibility,
486        # Don't auto-expand these targets until target_compatible_with
487        # works.  See https://github.com/bazelbuild/bazel/issues/12897.
488        tags = ["manual"],
489        target_compatible_with = ["@platforms//os:osx"],
490        **kwargs
491    )
492
493def internal_ruby_proto_library(
494        name,
495        ruby_library,
496        srcs = [],
497        deps = [],
498        includes = ["."],
499        default_runtime = "@com_google_protobuf//ruby:protobuf",
500        protoc = "@com_google_protobuf//:protoc",
501        testonly = None,
502        visibility = ["//visibility:public"],
503        **kwargs):
504    """Bazel rule to create a Ruby protobuf library from proto source files
505
506    NOTE: the rule is only an internal workaround to generate protos. The
507    interface may change and the rule may be removed when bazel has introduced
508    the native rule.
509
510    Args:
511      name: the name of the ruby_proto_library.
512      ruby_library: the ruby library rules to use.
513      srcs: the .proto files to compile.
514      deps: a list of dependency labels; must be a internal_ruby_proto_library.
515      includes: a string indicating the include path of the .proto files.
516      default_runtime: the RubyProtobuf runtime
517      protoc: the label of the protocol compiler to generate the sources.
518      testonly: common rule attribute (see:
519          https://bazel.build/reference/be/common-definitions#common-attributes)
520      visibility: the visibility of the generated files.
521      **kwargs: other keyword arguments that are passed to ruby_library.
522
523    """
524
525    # Note: we need to run the protoc build twice to get separate targets for
526    # the generated header and the source files.
527    _proto_gen(
528        name = name + "_genproto",
529        srcs = srcs,
530        deps = [s + "_genproto" for s in deps],
531        langs = ["ruby"],
532        includes = includes,
533        protoc = protoc,
534        testonly = testonly,
535        visibility = visibility,
536        tags = ["manual"],
537    )
538
539    deps = []
540    if default_runtime:
541        deps.append(default_runtime)
542    ruby_library(
543        name = name,
544        srcs = [name + "_genproto"],
545        deps = deps,
546        testonly = testonly,
547        visibility = visibility,
548        includes = includes,
549        **kwargs
550    )
551
552# When canonical labels are in use, use additional "@" prefix
553_canonical_label_prefix = "@" if str(Label("//:protoc")).startswith("@@") else ""
554
555def _to_label(label_str):
556    """Converts a string to a label using the repository of the calling thread"""
557    if type(label_str) == type(Label("//:foo")):
558        return label_str
559    return Label(_canonical_label_prefix + native.repository_name() + "//" + native.package_name() + ":foo").relative(label_str)
560
561def internal_py_proto_library(
562        name,
563        srcs = [],
564        deps = [],
565        py_libs = [],
566        py_extra_srcs = [],
567        include = None,
568        default_runtime = Label("//:protobuf_python"),
569        protoc = Label("//:protoc"),
570        use_grpc_plugin = False,
571        testonly = None,
572        **kargs):
573    """Bazel rule to create a Python protobuf library from proto source files
574
575    NOTE: the rule is only an internal workaround to generate protos. The
576    interface may change and the rule may be removed when bazel has introduced
577    the native rule.
578
579    Args:
580      name: the name of the py_proto_library.
581      srcs: the .proto files of the py_proto_library.
582      deps: a list of dependency labels; must be py_proto_library.
583      py_libs: a list of other py_library targets depended by the generated
584          py_library.
585      py_extra_srcs: extra source files that will be added to the output
586          py_library. This attribute is used for internal bootstrapping.
587      include: a string indicating the include path of the .proto files.
588      default_runtime: the implicitly default runtime which will be depended on by
589          the generated py_library target.
590      protoc: the label of the protocol compiler to generate the sources.
591      use_grpc_plugin: a flag to indicate whether to call the Python C++ plugin
592          when processing the proto files.
593      testonly: common rule attribute (see:
594          https://bazel.build/reference/be/common-definitions#common-attributes)
595      **kargs: other keyword arguments that are passed to py_library.
596
597    """
598    includes = []
599    if include != None:
600        includes = [include]
601
602    grpc_python_plugin = None
603    if use_grpc_plugin:
604        grpc_python_plugin = "//external:grpc_python_plugin"
605        # Note: Generated grpc code depends on Python grpc module. This dependency
606        # is not explicitly listed in py_libs. Instead, host system is assumed to
607        # have grpc installed.
608
609    _proto_gen(
610        name = name + "_genproto",
611        testonly = testonly,
612        srcs = srcs,
613        deps = [s + "_genproto" for s in deps],
614        includes = includes,
615        protoc = protoc,
616        langs = ["python"],
617        visibility = ["//visibility:public"],
618        plugin = grpc_python_plugin,
619        plugin_language = "grpc",
620    )
621
622    if default_runtime:
623        # Resolve non-local labels
624        labels = [_to_label(lib) for lib in py_libs + deps]
625        if not _to_label(default_runtime) in labels:
626            py_libs = py_libs + [default_runtime]
627
628    py_library(
629        name = name,
630        testonly = testonly,
631        srcs = [name + "_genproto"] + py_extra_srcs,
632        deps = py_libs + deps,
633        imports = includes,
634        **kargs
635    )
636
637def py_proto_library(
638        *args,
639        **kwargs):
640    """Deprecated alias for use before Bazel 5.3.
641
642    Args:
643      *args: the name of the py_proto_library.
644      **kwargs: other keyword arguments that are passed to py_library.
645
646    Deprecated:
647      This is provided for backwards compatibility only.  Bazel 5.3 will
648      introduce support for py_proto_library, which should be used instead.
649    """
650    print("The py_proto_library macro is deprecated and will be removed in the "
651        + "30.x release. switch to the rule defined by rules_python or the one "
652        + "in bazel/py_proto_library.bzl.")
653    internal_py_proto_library(*args, **kwargs)
654
655def _source_proto_library(
656        name,
657        srcs = [],
658        deps = [],
659        proto_deps = [],
660        outs = [],
661        lang = None,
662        includes = ["."],
663        protoc = Label("//:protoc"),
664        testonly = None,
665        visibility = ["//visibility:public"],
666        enable_editions = False,
667        **kwargs):
668    """Bazel rule to create generated protobuf code from proto source files for
669    languages not well supported by Bazel yet.  This will output the generated
670    code as-is without any compilation.  This is most useful for interpreted
671    languages that don't require it.
672
673    NOTE: the rule is only an internal workaround to generate protos. The
674    interface may change and the rule may be removed when bazel has introduced
675    the native rule.
676
677    Args:
678      name: the name of the unsupported_proto_library.
679      srcs: the .proto files to compile.  Note, that for languages where out
680        needs to be provided, only a single source file is allowed.
681      deps: a list of dependency labels; must be unsupported_proto_library.
682      proto_deps: a list of proto file dependencies that don't have a
683        unsupported_proto_library rule.
684      lang: the language to (optionally) generate code for.
685      outs: a list of expected output files.  This is only required for
686        languages where we can't predict the outputs.
687      includes: strings indicating the include path of the .proto files.
688      protoc: the label of the protocol compiler to generate the sources.
689      testonly: common rule attribute (see:
690          https://bazel.build/reference/be/common-definitions#common-attributes)
691      visibility: the visibility of the generated files.
692      **kwargs: other keyword arguments that are passed to py_library.
693
694    """
695    if outs and len(srcs) != 1:
696        fail("Custom outputs only allowed for single proto targets.")
697
698    langs = []
699    if lang != None:
700        langs = [lang]
701
702    full_deps = [d + "_genproto" for d in deps]
703
704    if proto_deps:
705        _proto_gen(
706            name = name + "_deps_genproto",
707            testonly = testonly,
708            srcs = proto_deps,
709            protoc = protoc,
710            includes = includes,
711            enable_editions = enable_editions,
712        )
713        full_deps.append(":%s_deps_genproto" % name)
714
715    _proto_gen(
716        name = name + "_genproto",
717        srcs = srcs,
718        deps = full_deps,
719        langs = langs,
720        outs = outs,
721        includes = includes,
722        protoc = protoc,
723        testonly = testonly,
724        visibility = visibility,
725        enable_editions = enable_editions,
726    )
727
728    native.filegroup(
729        name = name,
730        srcs = [":%s_genproto" % name],
731        testonly = testonly,
732        visibility = visibility,
733        **kwargs
734    )
735
736def internal_csharp_proto_library(**kwargs):
737    """Bazel rule to create a C# protobuf library from proto source files
738
739    NOTE: the rule is only an internal workaround to generate protos. The
740    interface may change and the rule may be removed when bazel has introduced
741    the native rule.
742
743    Args:
744      **kwargs: arguments that are passed to unsupported_proto_library.
745
746    """
747
748    _source_proto_library(
749        lang = "csharp",
750        **kwargs
751    )
752
753def internal_php_proto_library(**kwargs):
754    """Bazel rule to create a PHP protobuf library from proto source files
755
756    NOTE: the rule is only an internal workaround to generate protos. The
757    interface may change and the rule may be removed when bazel has introduced
758    the native rule.
759
760    Args:
761      **kwargs: arguments that are passed to unsupported_proto_library.
762
763    """
764    if not kwargs.get("outs"):
765        fail("Unable to predict the outputs for php_proto_library.  Please specify them via `outs`.")
766
767    _source_proto_library(
768        lang = "php",
769        **kwargs
770    )
771
772def check_protobuf_required_bazel_version():
773    """For WORKSPACE files, to check the installed version of bazel.
774
775    This ensures bazel supports our approach to proto_library() depending on a
776    copied filegroup. (Fixed in bazel 0.5.4)
777    """
778    versions.check(minimum_bazel_version = "0.5.4")
779