• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Protocol Buffers - Google's data interchange format
2# Copyright 2024 Google Inc.  All rights reserved.
3#
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file or at
6# https://developers.google.com/open-source/licenses/bsd
7#
8"""Implementation of the proto_lang_toolchain rule."""
9
10load("@proto_bazel_features//:features.bzl", "bazel_features")
11load("//bazel/common:proto_common.bzl", "proto_common")
12load("//bazel/common:proto_info.bzl", "ProtoInfo")
13load("//bazel/common:proto_lang_toolchain_info.bzl", "ProtoLangToolchainInfo")
14load("//bazel/private:toolchain_helpers.bzl", "toolchains")
15
16def _rule_impl(ctx):
17    provided_proto_sources = depset(transitive = [bp[ProtoInfo]._transitive_proto_sources for bp in ctx.attr.blacklisted_protos]).to_list()
18
19    flag = ctx.attr.command_line
20    if flag.find("$(PLUGIN_OUT)") > -1:
21        fail("in attribute 'command_line': Placeholder '$(PLUGIN_OUT)' is not supported.")
22    flag = flag.replace("$(OUT)", "%s")
23
24    plugin = None
25    if ctx.attr.plugin != None:
26        plugin = ctx.attr.plugin[DefaultInfo].files_to_run
27
28    if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION:
29        proto_compiler = ctx.toolchains[toolchains.PROTO_TOOLCHAIN].proto.proto_compiler
30        protoc_opts = ctx.toolchains[toolchains.PROTO_TOOLCHAIN].proto.protoc_opts
31    else:
32        proto_compiler = ctx.attr._proto_compiler.files_to_run
33        protoc_opts = ctx.fragments.proto.experimental_protoc_opts
34
35    if ctx.attr.protoc_minimal_do_not_use:
36        proto_compiler = ctx.attr.protoc_minimal_do_not_use.files_to_run
37
38    proto_lang_toolchain_info = ProtoLangToolchainInfo(
39        out_replacement_format_flag = flag,
40        output_files = ctx.attr.output_files,
41        plugin_format_flag = ctx.attr.plugin_format_flag,
42        plugin = plugin,
43        runtime = ctx.attr.runtime,
44        provided_proto_sources = provided_proto_sources,
45        proto_compiler = proto_compiler,
46        protoc_opts = protoc_opts,
47        progress_message = ctx.attr.progress_message,
48        mnemonic = ctx.attr.mnemonic,
49        allowlist_different_package = ctx.attr.allowlist_different_package,
50        toolchain_type = ctx.attr.toolchain_type.label if ctx.attr.toolchain_type else None,
51    )
52    return [
53        DefaultInfo(files = depset(), runfiles = ctx.runfiles()),
54        platform_common.ToolchainInfo(proto = proto_lang_toolchain_info),
55        # TODO: remove when --incompatible_enable_proto_toolchains is flipped and removed
56        proto_lang_toolchain_info,
57    ]
58
59proto_lang_toolchain = rule(
60    _rule_impl,
61    doc = """
62<p>If using Bazel, please load the rule from <a href="https://github.com/bazelbuild/rules_proto">
63https://github.com/bazelbuild/rules_proto</a>.
64
65<p>Specifies how a LANG_proto_library rule (e.g., <code>java_proto_library</code>) should invoke the
66proto-compiler.
67Some LANG_proto_library rules allow specifying which toolchain to use using command-line flags;
68consult their documentation.
69
70<p>Normally you should not write those kind of rules unless you want to
71tune your Java compiler.
72
73<p>There's no compiler. The proto-compiler is taken from the proto_library rule we attach to. It is
74passed as a command-line flag to Blaze.
75Several features require a proto-compiler to be invoked on the proto_library rule itself.
76It's beneficial to enforce the compiler that LANG_proto_library uses is the same as the one
77<code>proto_library</code> does.
78
79<h4>Examples</h4>
80
81<p>A simple example would be:
82<pre><code class="lang-starlark">
83proto_lang_toolchain(
84    name = "javalite_toolchain",
85    command_line = "--javalite_out=shared,immutable:$(OUT)",
86    plugin = ":javalite_plugin",
87    runtime = ":protobuf_lite",
88)
89</code></pre>
90    """,
91    attrs = {
92        "progress_message": attr.string(default = "Generating proto_library %{label}", doc = """
93This value will be set as the progress message on protoc action."""),
94        "mnemonic": attr.string(default = "GenProto", doc = """
95This value will be set as the mnemonic on protoc action."""),
96        "command_line": attr.string(mandatory = True, doc = """
97This value will be passed to proto-compiler to generate the code. Only include the parts
98specific to this code-generator/plugin (e.g., do not include -I parameters)
99<ul>
100  <li><code>$(OUT)</code> is LANG_proto_library-specific. The rules are expected to define
101      how they interpret this variable. For Java, for example, $(OUT) will be replaced with
102      the src-jar filename to create.</li>
103</ul>"""),
104        "output_files": attr.string(values = ["single", "multiple", "legacy"], default = "legacy", doc = """
105Controls how <code>$(OUT)</code> in <code>command_line</code> is formatted, either by
106a path to a single file or output directory in case of multiple files.
107Possible values are: "single", "multiple"."""),
108        "plugin_format_flag": attr.string(doc = """
109If provided, this value will be passed to proto-compiler to use the plugin.
110The value must contain a single %s which is replaced with plugin executable.
111<code>--plugin=protoc-gen-PLUGIN=&lt;executable&gt;.</code>"""),
112        "plugin": attr.label(
113            executable = True,
114            cfg = "exec",
115            doc = """
116If provided, will be made available to the action that calls the proto-compiler, and will be
117passed to the proto-compiler:
118<code>--plugin=protoc-gen-PLUGIN=&lt;executable&gt;.</code>""",
119        ),
120        "runtime": attr.label(doc = """
121A language-specific library that the generated code is compiled against.
122The exact behavior is LANG_proto_library-specific.
123Java, for example, should compile against the runtime."""),
124        "blacklisted_protos": attr.label_list(
125            providers = [ProtoInfo],
126            doc = """
127No code will be generated for files in the <code>srcs</code> attribute of
128<code>blacklisted_protos</code>.
129This is used for .proto files that are already linked into proto runtimes, such as
130<code>any.proto</code>.""",
131        ),
132        # TODO: add doc
133        "allowlist_different_package": attr.label(
134            cfg = "exec",
135            providers = [bazel_features.globals.PackageSpecificationInfo] if bazel_features.globals.PackageSpecificationInfo else [],
136        ),
137        # TODO: add doc
138        "toolchain_type": attr.label(),
139        # DO NOT USE. For Protobuf incremental changes only: b/305068148.
140        "protoc_minimal_do_not_use": attr.label(
141            cfg = "exec",
142            executable = True,
143        ),
144    } | ({} if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION else {
145        "_proto_compiler": attr.label(
146            cfg = "exec",
147            executable = True,
148            allow_files = True,
149            default = configuration_field("proto", "proto_compiler"),
150        ),
151    }),
152    provides = [ProtoLangToolchainInfo],
153    fragments = ["proto"],
154    toolchains = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN),  # Used to obtain protoc
155)
156