• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2009-2024, Google LLC
2# 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"""The implementation of the `java_proto_library` rule and its aspect."""
8
9load("@rules_java//java/common:java_info.bzl", "JavaInfo")
10load("//bazel/common:proto_common.bzl", "proto_common")
11load("//bazel/common:proto_info.bzl", "ProtoInfo")
12load("//bazel/private:java_proto_support.bzl", "JavaProtoAspectInfo", "java_compile_for_protos", "java_info_merge_for_protos")
13load("//bazel/private:toolchain_helpers.bzl", "toolchains")
14
15_JAVA_PROTO_TOOLCHAIN = Label("//bazel/private:java_toolchain_type")
16
17def _filter_provider(provider, *attrs):
18    return [dep[provider] for attr in attrs for dep in attr if provider in dep]
19
20def _bazel_java_proto_aspect_impl(target, ctx):
21    """Generates and compiles Java code for a proto_library.
22
23    The function runs protobuf compiler on the `proto_library` target using
24    `proto_lang_toolchain` specified by `--proto_toolchain_for_java` flag.
25    This generates a source jar.
26
27    After that the source jar is compiled, respecting `deps` and `exports` of
28    the `proto_library`.
29
30    Args:
31      target: (Target) The `proto_library` target (any target providing `ProtoInfo`.
32      ctx: (RuleContext) The rule context.
33
34    Returns:
35      ([JavaInfo, JavaProtoAspectInfo]) A JavaInfo describing compiled Java
36      version of`proto_library` and `JavaProtoAspectInfo` with all source and
37      runtime jars.
38    """
39
40    proto_toolchain_info = toolchains.find_toolchain(ctx, "_aspect_java_proto_toolchain", _JAVA_PROTO_TOOLCHAIN)
41    source_jar = None
42    if proto_common.experimental_should_generate_code(target[ProtoInfo], proto_toolchain_info, "java_proto_library", target.label):
43        # Generate source jar using proto compiler.
44        source_jar = ctx.actions.declare_file(ctx.label.name + "-speed-src.jar")
45        proto_common.compile(
46            ctx.actions,
47            target[ProtoInfo],
48            proto_toolchain_info,
49            [source_jar],
50            experimental_output_files = "single",
51        )
52
53    # Compile Java sources (or just merge if there aren't any)
54    deps = _filter_provider(JavaInfo, ctx.rule.attr.deps)
55    exports = _filter_provider(JavaInfo, ctx.rule.attr.exports)
56    if source_jar and proto_toolchain_info.runtime:
57        deps.append(proto_toolchain_info.runtime[JavaInfo])
58    java_info, jars = java_compile_for_protos(
59        ctx,
60        "-speed.jar",
61        source_jar,
62        deps,
63        exports,
64    )
65
66    transitive_jars = [dep[JavaProtoAspectInfo].jars for dep in ctx.rule.attr.deps if JavaProtoAspectInfo in dep]
67    return [
68        java_info,
69        JavaProtoAspectInfo(jars = depset(jars, transitive = transitive_jars)),
70    ]
71
72bazel_java_proto_aspect = aspect(
73    implementation = _bazel_java_proto_aspect_impl,
74    attrs = toolchains.if_legacy_toolchain({
75        "_aspect_java_proto_toolchain": attr.label(
76            default = configuration_field(fragment = "proto", name = "proto_toolchain_for_java"),
77        ),
78    }),
79    toolchains = ["@bazel_tools//tools/jdk:toolchain_type"] + toolchains.use_toolchain(_JAVA_PROTO_TOOLCHAIN),
80    attr_aspects = ["deps", "exports"],
81    required_providers = [ProtoInfo],
82    provides = [JavaInfo, JavaProtoAspectInfo],
83    fragments = ["java"],
84)
85
86def bazel_java_proto_library_rule(ctx):
87    """Merges results of `java_proto_aspect` in `deps`.
88
89    Args:
90      ctx: (RuleContext) The rule context.
91    Returns:
92      ([JavaInfo, DefaultInfo, OutputGroupInfo])
93    """
94    proto_toolchain = toolchains.find_toolchain(ctx, "_aspect_java_proto_toolchain", _JAVA_PROTO_TOOLCHAIN)
95    for dep in ctx.attr.deps:
96        proto_common.check_collocated(ctx.label, dep[ProtoInfo], proto_toolchain)
97
98    java_info = java_info_merge_for_protos([dep[JavaInfo] for dep in ctx.attr.deps], merge_java_outputs = False)
99
100    transitive_src_and_runtime_jars = depset(transitive = [dep[JavaProtoAspectInfo].jars for dep in ctx.attr.deps])
101    transitive_runtime_jars = depset(transitive = [java_info.transitive_runtime_jars])
102
103    return [
104        java_info,
105        DefaultInfo(
106            files = transitive_src_and_runtime_jars,
107            runfiles = ctx.runfiles(transitive_files = transitive_runtime_jars),
108        ),
109        OutputGroupInfo(default = depset()),
110    ]
111
112java_proto_library = rule(
113    implementation = bazel_java_proto_library_rule,
114    doc = """
115<p>
116<code>java_proto_library</code> generates Java code from <code>.proto</code> files.
117</p>
118
119<p>
120<code>deps</code> must point to <a href="protocol-buffer.html#proto_library"><code>proto_library
121</code></a> rules.
122</p>
123
124<p>
125Example:
126</p>
127
128<pre class="code">
129<code class="lang-starlark">
130java_library(
131    name = "lib",
132    runtime_deps = [":foo_java_proto"],
133)
134
135java_proto_library(
136    name = "foo_java_proto",
137    deps = [":foo_proto"],
138)
139
140proto_library(
141    name = "foo_proto",
142)
143</code>
144</pre>
145    """,
146    attrs = {
147        "deps": attr.label_list(
148            providers = [ProtoInfo],
149            aspects = [bazel_java_proto_aspect],
150            doc = """
151The list of <a href="protocol-buffer.html#proto_library"><code>proto_library</code></a>
152rules to generate Java code for.
153            """,
154        ),
155        # buildifier: disable=attr-license (calling attr.license())
156        "licenses": attr.license() if hasattr(attr, "license") else attr.string_list(),
157        "distribs": attr.string_list(),
158    } | toolchains.if_legacy_toolchain({
159        "_aspect_java_proto_toolchain": attr.label(
160            default = configuration_field(fragment = "proto", name = "proto_toolchain_for_java"),
161        ),
162    }),  # buildifier: disable=attr-licenses (attribute called licenses)
163    provides = [JavaInfo],
164    toolchains = toolchains.use_toolchain(_JAVA_PROTO_TOOLCHAIN),
165)
166