xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/rules/nogo.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1# Copyright 2018 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/private:context.bzl",
17    "go_context",
18)
19load(
20    "//go/private:go_toolchain.bzl",
21    "GO_TOOLCHAIN",
22)
23load(
24    "//go/private:providers.bzl",
25    "EXPORT_PATH",
26    "GoArchive",
27    "GoLibrary",
28    "get_archive",
29)
30load(
31    "//go/private/rules:transition.bzl",
32    "go_tool_transition",
33)
34
35def _nogo_impl(ctx):
36    if not ctx.attr.deps:
37        # If there aren't any analyzers to run, don't generate a binary.
38        # go_context will check for this condition.
39        return None
40
41    # Generate the source for the nogo binary.
42    go = go_context(ctx)
43    nogo_main = go.declare_file(go, path = "nogo_main.go")
44    nogo_args = ctx.actions.args()
45    nogo_args.add("gennogomain")
46    nogo_args.add("-output", nogo_main)
47    nogo_inputs = []
48    analyzer_archives = [get_archive(dep) for dep in ctx.attr.deps]
49    analyzer_importpaths = [archive.data.importpath for archive in analyzer_archives]
50    nogo_args.add_all(analyzer_importpaths, before_each = "-analyzer_importpath")
51    if ctx.file.config:
52        nogo_args.add("-config", ctx.file.config)
53        nogo_inputs.append(ctx.file.config)
54    ctx.actions.run(
55        inputs = nogo_inputs,
56        outputs = [nogo_main],
57        mnemonic = "GoGenNogo",
58        executable = go.toolchain._builder,
59        arguments = [nogo_args],
60    )
61
62    # Compile the nogo binary itself.
63    nogo_library = GoLibrary(
64        name = go.label.name + "~nogo",
65        label = go.label,
66        importpath = "nogomain",
67        importmap = "nogomain",
68        importpath_aliases = (),
69        pathtype = EXPORT_PATH,
70        is_main = True,
71        resolve = None,
72    )
73
74    nogo_source = go.library_to_source(go, struct(
75        srcs = [struct(files = [nogo_main])],
76        embed = [ctx.attr._nogo_srcs],
77        deps = analyzer_archives,
78    ), nogo_library, False)
79    _, executable, runfiles = go.binary(
80        go,
81        name = ctx.label.name,
82        source = nogo_source,
83    )
84    return [DefaultInfo(
85        files = depset([executable]),
86        runfiles = runfiles,
87        executable = executable,
88    )]
89
90_nogo = rule(
91    implementation = _nogo_impl,
92    attrs = {
93        "deps": attr.label_list(
94            providers = [GoArchive],
95        ),
96        "config": attr.label(
97            allow_single_file = True,
98        ),
99        "_nogo_srcs": attr.label(
100            default = "//go/tools/builders:nogo_srcs",
101        ),
102        "_cgo_context_data": attr.label(default = "//:cgo_context_data_proxy"),
103        "_go_config": attr.label(default = "//:go_config"),
104        "_stdlib": attr.label(default = "//:stdlib"),
105        "_allowlist_function_transition": attr.label(
106            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
107        ),
108    },
109    toolchains = [GO_TOOLCHAIN],
110    cfg = go_tool_transition,
111)
112
113def nogo(name, visibility = None, **kwargs):
114    actual_name = "%s_actual" % name
115    native.alias(
116        name = name,
117        actual = select({
118            "@io_bazel_rules_go//go/private:nogo_active": actual_name,
119            "//conditions:default": Label("//:default_nogo"),
120        }),
121        visibility = visibility,
122    )
123
124    # With --use_top_level_targets_for_symlinks, which is enabled by default in
125    # Bazel 6.0.0, self-transitioning top-level targets prevent the bazel-bin
126    # convenience symlink from being created. Since nogo targets are of this
127    # type, their presence would trigger this behavior. Work around this by
128    # excluding them from wildcards - they are still transitively built as a
129    # tool dependency of every Go target.
130    kwargs.setdefault("tags", [])
131    if "manual" not in kwargs["tags"]:
132        kwargs["tags"].append("manual")
133
134    _nogo(
135        name = actual_name,
136        visibility = visibility,
137        **kwargs
138    )
139
140def nogo_wrapper(**kwargs):
141    if kwargs.get("vet"):
142        kwargs["deps"] = kwargs.get("deps", []) + [
143            "@org_golang_x_tools//go/analysis/passes/atomic:go_default_library",
144            "@org_golang_x_tools//go/analysis/passes/bools:go_default_library",
145            "@org_golang_x_tools//go/analysis/passes/buildtag:go_default_library",
146            "@org_golang_x_tools//go/analysis/passes/nilfunc:go_default_library",
147            "@org_golang_x_tools//go/analysis/passes/printf:go_default_library",
148        ]
149        kwargs = {k: v for k, v in kwargs.items() if k != "vet"}
150    nogo(**kwargs)
151