xref: /aosp_15_r20/external/bazelbuild-rules_go/proto/def.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1# Copyright 2017 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15load(
16    "//go:def.bzl",
17    "GoLibrary",
18    "GoSource",
19    "go_context",
20)
21load(
22    "@bazel_skylib//lib:types.bzl",
23    "types",
24)
25load(
26    "//proto:compiler.bzl",
27    "GoProtoCompiler",
28    "proto_path",
29)
30load(
31    "//go/private:go_toolchain.bzl",
32    "GO_TOOLCHAIN",
33)
34load(
35    "//go/private:providers.bzl",
36    "INFERRED_PATH",
37)
38load(
39    "//go/private/rules:transition.bzl",
40    "non_go_tool_transition",
41)
42load(
43    "@rules_proto//proto:defs.bzl",
44    "ProtoInfo",
45)
46
47GoProtoImports = provider()
48
49def get_imports(attr):
50    proto_deps = []
51
52    # ctx.attr.proto is a one-element array since there is a Starlark transition attached to it.
53    if hasattr(attr, "proto") and attr.proto and types.is_list(attr.proto) and ProtoInfo in attr.proto[0]:
54        proto_deps = [attr.proto[0]]
55    elif hasattr(attr, "protos"):
56        proto_deps = [d for d in attr.protos if ProtoInfo in d]
57    else:
58        proto_deps = []
59
60    direct = dict()
61    for dep in proto_deps:
62        for src in dep[ProtoInfo].check_deps_sources.to_list():
63            direct["{}={}".format(proto_path(src, dep[ProtoInfo]), attr.importpath)] = True
64
65    deps = getattr(attr, "deps", []) + getattr(attr, "embed", [])
66    transitive = [
67        dep[GoProtoImports].imports
68        for dep in deps
69        if GoProtoImports in dep
70    ]
71    return depset(direct = direct.keys(), transitive = transitive)
72
73def _go_proto_aspect_impl(_target, ctx):
74    imports = get_imports(ctx.rule.attr)
75    return [GoProtoImports(imports = imports)]
76
77_go_proto_aspect = aspect(
78    _go_proto_aspect_impl,
79    attr_aspects = [
80        "deps",
81        "embed",
82    ],
83)
84
85def _proto_library_to_source(_go, attr, source, merge):
86    if attr.compiler:
87        compilers = [attr.compiler]
88    else:
89        compilers = attr.compilers
90    for compiler in compilers:
91        if GoSource in compiler:
92            merge(source, compiler[GoSource])
93
94def _go_proto_library_impl(ctx):
95    go = go_context(ctx)
96    if go.pathtype == INFERRED_PATH:
97        fail("importpath must be specified in this library or one of its embedded libraries")
98    if ctx.attr.compiler:
99        #TODO: print("DEPRECATED: compiler attribute on {}, use compilers instead".format(ctx.label))
100        compilers = [ctx.attr.compiler]
101    else:
102        compilers = ctx.attr.compilers
103
104    if ctx.attr.proto:
105        #TODO: print("DEPRECATED: proto attribute on {}, use protos instead".format(ctx.label))
106        if ctx.attr.protos:
107            fail("Either proto or protos (non-empty) argument must be specified, but not both")
108
109        # ctx.attr.proto is a one-element array since there is a Starlark transition attached to it.
110        proto_deps = [ctx.attr.proto[0]]
111    else:
112        if not ctx.attr.protos:
113            fail("Either proto or protos (non-empty) argument must be specified")
114        proto_deps = ctx.attr.protos
115
116    go_srcs = []
117    valid_archive = False
118
119    for c in compilers:
120        compiler = c[GoProtoCompiler]
121        if compiler.valid_archive:
122            valid_archive = True
123        go_srcs.extend(compiler.compile(
124            go,
125            compiler = compiler,
126            protos = [d[ProtoInfo] for d in proto_deps],
127            imports = get_imports(ctx.attr),
128            importpath = go.importpath,
129        ))
130    library = go.new_library(
131        go,
132        resolver = _proto_library_to_source,
133        srcs = go_srcs,
134    )
135    source = go.library_to_source(go, ctx.attr, library, False)
136    providers = [library, source]
137    output_groups = {
138        "go_generated_srcs": go_srcs,
139    }
140    if valid_archive:
141        archive = go.archive(go, source)
142        output_groups["compilation_outputs"] = [archive.data.file]
143        providers.extend([
144            archive,
145            DefaultInfo(
146                files = depset([archive.data.file]),
147                runfiles = archive.runfiles,
148            ),
149        ])
150    return providers + [OutputGroupInfo(**output_groups)]
151
152go_proto_library = rule(
153    implementation = _go_proto_library_impl,
154    attrs = {
155        "proto": attr.label(
156            cfg = non_go_tool_transition,
157            providers = [ProtoInfo],
158        ),
159        "protos": attr.label_list(
160            cfg = non_go_tool_transition,
161            providers = [ProtoInfo],
162            default = [],
163        ),
164        "deps": attr.label_list(
165            providers = [GoLibrary],
166            aspects = [_go_proto_aspect],
167        ),
168        "importpath": attr.string(),
169        "importmap": attr.string(),
170        "importpath_aliases": attr.string_list(),  # experimental, undocumented
171        "embed": attr.label_list(providers = [GoLibrary]),
172        "gc_goopts": attr.string_list(),
173        "compiler": attr.label(providers = [GoProtoCompiler]),
174        "compilers": attr.label_list(
175            providers = [GoProtoCompiler],
176            default = ["//proto:go_proto"],
177        ),
178        "_go_context_data": attr.label(
179            default = "//:go_context_data",
180        ),
181        "_allowlist_function_transition": attr.label(
182            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
183        ),
184    },
185    toolchains = [GO_TOOLCHAIN],
186)
187# go_proto_library is a rule that takes a proto_library (in the proto
188# attribute) and produces a go library for it.
189
190def go_grpc_library(**kwargs):
191    # TODO: Deprecate once gazelle generates just go_proto_library
192    go_proto_library(compilers = [Label("//proto:go_grpc")], **kwargs)
193
194def proto_register_toolchains():
195    print("You no longer need to call proto_register_toolchains(), it does nothing")
196