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