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