xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/context.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das# Copyright 2017 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das#
3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das# You may obtain a copy of the License at
6*9bb1b549SSpandan Das#
7*9bb1b549SSpandan Das#    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das#
9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das# limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Dasload(
16*9bb1b549SSpandan Das    "@bazel_tools//tools/cpp:toolchain_utils.bzl",
17*9bb1b549SSpandan Das    "find_cpp_toolchain",
18*9bb1b549SSpandan Das)
19*9bb1b549SSpandan Dasload(
20*9bb1b549SSpandan Das    "@bazel_tools//tools/build_defs/cc:action_names.bzl",
21*9bb1b549SSpandan Das    "CPP_COMPILE_ACTION_NAME",
22*9bb1b549SSpandan Das    "CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME",
23*9bb1b549SSpandan Das    "CPP_LINK_EXECUTABLE_ACTION_NAME",
24*9bb1b549SSpandan Das    "CPP_LINK_STATIC_LIBRARY_ACTION_NAME",
25*9bb1b549SSpandan Das    "C_COMPILE_ACTION_NAME",
26*9bb1b549SSpandan Das    "OBJCPP_COMPILE_ACTION_NAME",
27*9bb1b549SSpandan Das    "OBJC_COMPILE_ACTION_NAME",
28*9bb1b549SSpandan Das)
29*9bb1b549SSpandan Dasload(
30*9bb1b549SSpandan Das    ":go_toolchain.bzl",
31*9bb1b549SSpandan Das    "GO_TOOLCHAIN",
32*9bb1b549SSpandan Das)
33*9bb1b549SSpandan Dasload(
34*9bb1b549SSpandan Das    ":providers.bzl",
35*9bb1b549SSpandan Das    "CgoContextInfo",
36*9bb1b549SSpandan Das    "EXPLICIT_PATH",
37*9bb1b549SSpandan Das    "EXPORT_PATH",
38*9bb1b549SSpandan Das    "GoArchive",
39*9bb1b549SSpandan Das    "GoConfigInfo",
40*9bb1b549SSpandan Das    "GoContextInfo",
41*9bb1b549SSpandan Das    "GoLibrary",
42*9bb1b549SSpandan Das    "GoSource",
43*9bb1b549SSpandan Das    "GoStdLib",
44*9bb1b549SSpandan Das    "INFERRED_PATH",
45*9bb1b549SSpandan Das    "get_source",
46*9bb1b549SSpandan Das)
47*9bb1b549SSpandan Dasload(
48*9bb1b549SSpandan Das    ":mode.bzl",
49*9bb1b549SSpandan Das    "get_mode",
50*9bb1b549SSpandan Das    "installsuffix",
51*9bb1b549SSpandan Das)
52*9bb1b549SSpandan Dasload(
53*9bb1b549SSpandan Das    ":common.bzl",
54*9bb1b549SSpandan Das    "COVERAGE_OPTIONS_DENYLIST",
55*9bb1b549SSpandan Das    "as_iterable",
56*9bb1b549SSpandan Das    "goos_to_extension",
57*9bb1b549SSpandan Das    "goos_to_shared_extension",
58*9bb1b549SSpandan Das    "is_struct",
59*9bb1b549SSpandan Das)
60*9bb1b549SSpandan Dasload(
61*9bb1b549SSpandan Das    "//go/platform:apple.bzl",
62*9bb1b549SSpandan Das    "apple_ensure_options",
63*9bb1b549SSpandan Das)
64*9bb1b549SSpandan Dasload(
65*9bb1b549SSpandan Das    "@bazel_skylib//rules:common_settings.bzl",
66*9bb1b549SSpandan Das    "BuildSettingInfo",
67*9bb1b549SSpandan Das)
68*9bb1b549SSpandan Dasload(
69*9bb1b549SSpandan Das    "//go/private/rules:transition.bzl",
70*9bb1b549SSpandan Das    "request_nogo_transition",
71*9bb1b549SSpandan Das)
72*9bb1b549SSpandan Das
73*9bb1b549SSpandan Das# cgo requires a gcc/clang style compiler.
74*9bb1b549SSpandan Das# We use a denylist instead of an allowlist:
75*9bb1b549SSpandan Das# - Bazel's auto-detected toolchains used to set the compiler name to "compiler"
76*9bb1b549SSpandan Das#   for gcc (fixed in 6.0.0), which defeats the purpose of an allowlist.
77*9bb1b549SSpandan Das# - The compiler name field is free-form and user-defined, so we would have to
78*9bb1b549SSpandan Das#   provide a way to override this list.
79*9bb1b549SSpandan Das# TODO: Convert to a denylist once we can assume Bazel 6.0.0 or later and have a
80*9bb1b549SSpandan Das#       way for users to extend the list.
81*9bb1b549SSpandan Das_UNSUPPORTED_C_COMPILERS = {
82*9bb1b549SSpandan Das    "msvc-cl": None,
83*9bb1b549SSpandan Das    "clang-cl": None,
84*9bb1b549SSpandan Das}
85*9bb1b549SSpandan Das
86*9bb1b549SSpandan Das_COMPILER_OPTIONS_DENYLIST = dict({
87*9bb1b549SSpandan Das    # cgo parses the error messages from the compiler.  It can't handle colors.
88*9bb1b549SSpandan Das    # Ignore both variants of the diagnostics color flag.
89*9bb1b549SSpandan Das    "-fcolor-diagnostics": None,
90*9bb1b549SSpandan Das    "-fdiagnostics-color": None,
91*9bb1b549SSpandan Das
92*9bb1b549SSpandan Das    # cgo also wants to see all the errors when it is testing the compiler.
93*9bb1b549SSpandan Das    # fmax-errors limits that and causes build failures.
94*9bb1b549SSpandan Das    "-fmax-errors=": None,
95*9bb1b549SSpandan Das    "-Wall": None,
96*9bb1b549SSpandan Das
97*9bb1b549SSpandan Das    # Symbols are needed by Go, so keep them
98*9bb1b549SSpandan Das    "-g0": None,
99*9bb1b549SSpandan Das
100*9bb1b549SSpandan Das    # Don't compile generated cgo code with coverage. If we do an internal
101*9bb1b549SSpandan Das    # link, we may have undefined references to coverage functions.
102*9bb1b549SSpandan Das    "--coverage": None,
103*9bb1b549SSpandan Das    "-ftest-coverage": None,
104*9bb1b549SSpandan Das    "-fprofile-arcs": None,
105*9bb1b549SSpandan Das    "-fprofile-instr-generate": None,
106*9bb1b549SSpandan Das    "-fcoverage-mapping": None,
107*9bb1b549SSpandan Das}, **COVERAGE_OPTIONS_DENYLIST)
108*9bb1b549SSpandan Das
109*9bb1b549SSpandan Das_LINKER_OPTIONS_DENYLIST = {
110*9bb1b549SSpandan Das    "-Wl,--gc-sections": None,
111*9bb1b549SSpandan Das}
112*9bb1b549SSpandan Das
113*9bb1b549SSpandan Das_UNSUPPORTED_FEATURES = [
114*9bb1b549SSpandan Das    # These toolchain features require special rule support and will thus break
115*9bb1b549SSpandan Das    # with CGo.
116*9bb1b549SSpandan Das    # Taken from https://github.com/bazelbuild/rules_rust/blob/521e649ff44e9711fe3c45b0ec1e792f7e1d361e/rust/private/utils.bzl#L20.
117*9bb1b549SSpandan Das    "thin_lto",
118*9bb1b549SSpandan Das    "module_maps",
119*9bb1b549SSpandan Das    "use_header_modules",
120*9bb1b549SSpandan Das    "fdo_instrument",
121*9bb1b549SSpandan Das    "fdo_optimize",
122*9bb1b549SSpandan Das]
123*9bb1b549SSpandan Das
124*9bb1b549SSpandan Dasdef _match_option(option, pattern):
125*9bb1b549SSpandan Das    if pattern.endswith("="):
126*9bb1b549SSpandan Das        return option.startswith(pattern)
127*9bb1b549SSpandan Das    else:
128*9bb1b549SSpandan Das        return option == pattern
129*9bb1b549SSpandan Das
130*9bb1b549SSpandan Dasdef _filter_options(options, denylist):
131*9bb1b549SSpandan Das    return [
132*9bb1b549SSpandan Das        option
133*9bb1b549SSpandan Das        for option in options
134*9bb1b549SSpandan Das        if not any([_match_option(option, pattern) for pattern in denylist])
135*9bb1b549SSpandan Das    ]
136*9bb1b549SSpandan Das
137*9bb1b549SSpandan Dasdef _child_name(go, path, ext, name):
138*9bb1b549SSpandan Das    if not name:
139*9bb1b549SSpandan Das        name = go.label.name
140*9bb1b549SSpandan Das        if path or not ext:
141*9bb1b549SSpandan Das            # The '_' avoids collisions with another file matching the label name.
142*9bb1b549SSpandan Das            # For example, hello and hello/testmain.go.
143*9bb1b549SSpandan Das            name += "_"
144*9bb1b549SSpandan Das    if path:
145*9bb1b549SSpandan Das        name += "/" + path
146*9bb1b549SSpandan Das    if ext:
147*9bb1b549SSpandan Das        name += ext
148*9bb1b549SSpandan Das    return name
149*9bb1b549SSpandan Das
150*9bb1b549SSpandan Dasdef _declare_file(go, path = "", ext = "", name = ""):
151*9bb1b549SSpandan Das    return go.actions.declare_file(_child_name(go, path, ext, name))
152*9bb1b549SSpandan Das
153*9bb1b549SSpandan Dasdef _declare_directory(go, path = "", ext = "", name = ""):
154*9bb1b549SSpandan Das    return go.actions.declare_directory(_child_name(go, path, ext, name))
155*9bb1b549SSpandan Das
156*9bb1b549SSpandan Dasdef _new_args(go):
157*9bb1b549SSpandan Das    # TODO(jayconrod): print warning.
158*9bb1b549SSpandan Das    return go.builder_args(go)
159*9bb1b549SSpandan Das
160*9bb1b549SSpandan Dasdef _builder_args(go, command = None):
161*9bb1b549SSpandan Das    args = go.actions.args()
162*9bb1b549SSpandan Das    args.use_param_file("-param=%s")
163*9bb1b549SSpandan Das    args.set_param_file_format("shell")
164*9bb1b549SSpandan Das    if command:
165*9bb1b549SSpandan Das        args.add(command)
166*9bb1b549SSpandan Das    args.add("-sdk", go.sdk.root_file.dirname)
167*9bb1b549SSpandan Das    args.add("-installsuffix", installsuffix(go.mode))
168*9bb1b549SSpandan Das    args.add_joined("-tags", go.tags, join_with = ",")
169*9bb1b549SSpandan Das    return args
170*9bb1b549SSpandan Das
171*9bb1b549SSpandan Dasdef _tool_args(go):
172*9bb1b549SSpandan Das    args = go.actions.args()
173*9bb1b549SSpandan Das    args.use_param_file("-param=%s")
174*9bb1b549SSpandan Das    args.set_param_file_format("shell")
175*9bb1b549SSpandan Das    return args
176*9bb1b549SSpandan Das
177*9bb1b549SSpandan Dasdef _new_library(go, name = None, importpath = None, resolver = None, importable = True, testfilter = None, is_main = False, **kwargs):
178*9bb1b549SSpandan Das    if not importpath:
179*9bb1b549SSpandan Das        importpath = go.importpath
180*9bb1b549SSpandan Das        importmap = go.importmap
181*9bb1b549SSpandan Das    else:
182*9bb1b549SSpandan Das        importmap = importpath
183*9bb1b549SSpandan Das    pathtype = go.pathtype
184*9bb1b549SSpandan Das    if not importable and pathtype == EXPLICIT_PATH:
185*9bb1b549SSpandan Das        pathtype = EXPORT_PATH
186*9bb1b549SSpandan Das
187*9bb1b549SSpandan Das    return GoLibrary(
188*9bb1b549SSpandan Das        name = go.label.name if not name else name,
189*9bb1b549SSpandan Das        label = go.label,
190*9bb1b549SSpandan Das        importpath = importpath,
191*9bb1b549SSpandan Das        importmap = importmap,
192*9bb1b549SSpandan Das        importpath_aliases = go.importpath_aliases,
193*9bb1b549SSpandan Das        pathtype = pathtype,
194*9bb1b549SSpandan Das        resolve = resolver,
195*9bb1b549SSpandan Das        testfilter = testfilter,
196*9bb1b549SSpandan Das        is_main = is_main,
197*9bb1b549SSpandan Das        **kwargs
198*9bb1b549SSpandan Das    )
199*9bb1b549SSpandan Das
200*9bb1b549SSpandan Dasdef _merge_embed(source, embed):
201*9bb1b549SSpandan Das    s = get_source(embed)
202*9bb1b549SSpandan Das    source["srcs"] = s.srcs + source["srcs"]
203*9bb1b549SSpandan Das    source["orig_srcs"] = s.orig_srcs + source["orig_srcs"]
204*9bb1b549SSpandan Das    source["orig_src_map"].update(s.orig_src_map)
205*9bb1b549SSpandan Das    source["embedsrcs"] = source["embedsrcs"] + s.embedsrcs
206*9bb1b549SSpandan Das    source["cover"] = source["cover"] + s.cover
207*9bb1b549SSpandan Das    source["deps"] = source["deps"] + s.deps
208*9bb1b549SSpandan Das    source["x_defs"].update(s.x_defs)
209*9bb1b549SSpandan Das    source["gc_goopts"] = source["gc_goopts"] + s.gc_goopts
210*9bb1b549SSpandan Das    source["runfiles"] = source["runfiles"].merge(s.runfiles)
211*9bb1b549SSpandan Das    if s.cgo and source["cgo"]:
212*9bb1b549SSpandan Das        fail("multiple libraries with cgo enabled")
213*9bb1b549SSpandan Das    source["cgo"] = source["cgo"] or s.cgo
214*9bb1b549SSpandan Das    source["cdeps"] = source["cdeps"] or s.cdeps
215*9bb1b549SSpandan Das    source["cppopts"] = source["cppopts"] or s.cppopts
216*9bb1b549SSpandan Das    source["copts"] = source["copts"] or s.copts
217*9bb1b549SSpandan Das    source["cxxopts"] = source["cxxopts"] or s.cxxopts
218*9bb1b549SSpandan Das    source["clinkopts"] = source["clinkopts"] or s.clinkopts
219*9bb1b549SSpandan Das    source["cgo_deps"] = source["cgo_deps"] + s.cgo_deps
220*9bb1b549SSpandan Das    source["cgo_exports"] = source["cgo_exports"] + s.cgo_exports
221*9bb1b549SSpandan Das
222*9bb1b549SSpandan Dasdef _dedup_deps(deps):
223*9bb1b549SSpandan Das    """Returns a list of deps without duplicate import paths.
224*9bb1b549SSpandan Das
225*9bb1b549SSpandan Das    Earlier targets take precedence over later targets. This is intended to
226*9bb1b549SSpandan Das    allow an embedding library to override the dependencies of its
227*9bb1b549SSpandan Das    embedded libraries.
228*9bb1b549SSpandan Das
229*9bb1b549SSpandan Das    Args:
230*9bb1b549SSpandan Das      deps: an iterable containing either Targets or GoArchives.
231*9bb1b549SSpandan Das    """
232*9bb1b549SSpandan Das    deduped_deps = []
233*9bb1b549SSpandan Das    importpaths = {}
234*9bb1b549SSpandan Das    for dep in deps:
235*9bb1b549SSpandan Das        if hasattr(dep, "data") and hasattr(dep.data, "importpath"):
236*9bb1b549SSpandan Das            importpath = dep.data.importpath
237*9bb1b549SSpandan Das        else:
238*9bb1b549SSpandan Das            importpath = dep[GoLibrary].importpath
239*9bb1b549SSpandan Das        if importpath in importpaths:
240*9bb1b549SSpandan Das            continue
241*9bb1b549SSpandan Das        importpaths[importpath] = None
242*9bb1b549SSpandan Das        deduped_deps.append(dep)
243*9bb1b549SSpandan Das    return deduped_deps
244*9bb1b549SSpandan Das
245*9bb1b549SSpandan Dasdef _library_to_source(go, attr, library, coverage_instrumented):
246*9bb1b549SSpandan Das    #TODO: stop collapsing a depset in this line...
247*9bb1b549SSpandan Das    attr_srcs = [f for t in getattr(attr, "srcs", []) for f in as_iterable(t.files)]
248*9bb1b549SSpandan Das    generated_srcs = getattr(library, "srcs", [])
249*9bb1b549SSpandan Das    srcs = attr_srcs + generated_srcs
250*9bb1b549SSpandan Das    embedsrcs = [f for t in getattr(attr, "embedsrcs", []) for f in as_iterable(t.files)]
251*9bb1b549SSpandan Das    source = {
252*9bb1b549SSpandan Das        "library": library,
253*9bb1b549SSpandan Das        "mode": go.mode,
254*9bb1b549SSpandan Das        "srcs": srcs,
255*9bb1b549SSpandan Das        "orig_srcs": srcs,
256*9bb1b549SSpandan Das        "orig_src_map": {},
257*9bb1b549SSpandan Das        "cover": [],
258*9bb1b549SSpandan Das        "embedsrcs": embedsrcs,
259*9bb1b549SSpandan Das        "x_defs": {},
260*9bb1b549SSpandan Das        "deps": getattr(attr, "deps", []),
261*9bb1b549SSpandan Das        "gc_goopts": _expand_opts(go, "gc_goopts", getattr(attr, "gc_goopts", [])),
262*9bb1b549SSpandan Das        "runfiles": _collect_runfiles(go, getattr(attr, "data", []), getattr(attr, "deps", [])),
263*9bb1b549SSpandan Das        "cgo": getattr(attr, "cgo", False),
264*9bb1b549SSpandan Das        "cdeps": getattr(attr, "cdeps", []),
265*9bb1b549SSpandan Das        "cppopts": _expand_opts(go, "cppopts", getattr(attr, "cppopts", [])),
266*9bb1b549SSpandan Das        "copts": _expand_opts(go, "copts", getattr(attr, "copts", [])),
267*9bb1b549SSpandan Das        "cxxopts": _expand_opts(go, "cxxopts", getattr(attr, "cxxopts", [])),
268*9bb1b549SSpandan Das        "clinkopts": _expand_opts(go, "clinkopts", getattr(attr, "clinkopts", [])),
269*9bb1b549SSpandan Das        "cgo_deps": [],
270*9bb1b549SSpandan Das        "cgo_exports": [],
271*9bb1b549SSpandan Das        "cc_info": None,
272*9bb1b549SSpandan Das    }
273*9bb1b549SSpandan Das    if coverage_instrumented:
274*9bb1b549SSpandan Das        source["cover"] = attr_srcs
275*9bb1b549SSpandan Das    for dep in source["deps"]:
276*9bb1b549SSpandan Das        _check_binary_dep(go, dep, "deps")
277*9bb1b549SSpandan Das    for e in getattr(attr, "embed", []):
278*9bb1b549SSpandan Das        _check_binary_dep(go, e, "embed")
279*9bb1b549SSpandan Das        _merge_embed(source, e)
280*9bb1b549SSpandan Das    source["deps"] = _dedup_deps(source["deps"])
281*9bb1b549SSpandan Das    x_defs = source["x_defs"]
282*9bb1b549SSpandan Das    for k, v in getattr(attr, "x_defs", {}).items():
283*9bb1b549SSpandan Das        v = _expand_location(go, attr, v)
284*9bb1b549SSpandan Das        if "." not in k:
285*9bb1b549SSpandan Das            k = "{}.{}".format(library.importmap, k)
286*9bb1b549SSpandan Das        x_defs[k] = v
287*9bb1b549SSpandan Das    source["x_defs"] = x_defs
288*9bb1b549SSpandan Das    if not source["cgo"]:
289*9bb1b549SSpandan Das        for k in ("cdeps", "cppopts", "copts", "cxxopts", "clinkopts"):
290*9bb1b549SSpandan Das            if getattr(attr, k, None):
291*9bb1b549SSpandan Das                fail(k + " set without cgo = True")
292*9bb1b549SSpandan Das        for f in source["srcs"]:
293*9bb1b549SSpandan Das            # This check won't report directory sources that contain C/C++
294*9bb1b549SSpandan Das            # sources. compilepkg will catch these instead.
295*9bb1b549SSpandan Das            if f.extension in ("c", "cc", "cxx", "cpp", "hh", "hpp", "hxx"):
296*9bb1b549SSpandan Das                fail("source {} has C/C++ extension, but cgo was not enabled (set 'cgo = True')".format(f.path))
297*9bb1b549SSpandan Das    if library.resolve:
298*9bb1b549SSpandan Das        library.resolve(go, attr, source, _merge_embed)
299*9bb1b549SSpandan Das    source["cc_info"] = _collect_cc_infos(source["deps"], source["cdeps"])
300*9bb1b549SSpandan Das    return GoSource(**source)
301*9bb1b549SSpandan Das
302*9bb1b549SSpandan Dasdef _collect_runfiles(go, data, deps):
303*9bb1b549SSpandan Das    """Builds a set of runfiles from the deps and data attributes.
304*9bb1b549SSpandan Das
305*9bb1b549SSpandan Das    srcs and their runfiles are not included."""
306*9bb1b549SSpandan Das    files = depset(transitive = [t[DefaultInfo].files for t in data])
307*9bb1b549SSpandan Das    runfiles = go._ctx.runfiles(transitive_files = files)
308*9bb1b549SSpandan Das    for t in data:
309*9bb1b549SSpandan Das        runfiles = runfiles.merge(t[DefaultInfo].data_runfiles)
310*9bb1b549SSpandan Das    for t in deps:
311*9bb1b549SSpandan Das        runfiles = runfiles.merge(get_source(t).runfiles)
312*9bb1b549SSpandan Das    return runfiles
313*9bb1b549SSpandan Das
314*9bb1b549SSpandan Dasdef _collect_cc_infos(deps, cdeps):
315*9bb1b549SSpandan Das    cc_infos = []
316*9bb1b549SSpandan Das    for dep in cdeps:
317*9bb1b549SSpandan Das        if CcInfo in dep:
318*9bb1b549SSpandan Das            cc_infos.append(dep[CcInfo])
319*9bb1b549SSpandan Das    for dep in deps:
320*9bb1b549SSpandan Das        # dep may be a struct, which doesn't support indexing by providers.
321*9bb1b549SSpandan Das        if is_struct(dep):
322*9bb1b549SSpandan Das            continue
323*9bb1b549SSpandan Das        if GoSource in dep:
324*9bb1b549SSpandan Das            cc_infos.append(dep[GoSource].cc_info)
325*9bb1b549SSpandan Das    return cc_common.merge_cc_infos(cc_infos = cc_infos)
326*9bb1b549SSpandan Das
327*9bb1b549SSpandan Dasdef _check_binary_dep(go, dep, edge):
328*9bb1b549SSpandan Das    """Checks that this rule doesn't depend on a go_binary or go_test.
329*9bb1b549SSpandan Das
330*9bb1b549SSpandan Das    go_binary and go_test may return provides with useful information for other
331*9bb1b549SSpandan Das    rules (like go_path), but go_binary and go_test may not depend on other
332*9bb1b549SSpandan Das    go_binary and go_binary targets. Their dependencies may be built in
333*9bb1b549SSpandan Das    different modes, resulting in conflicts and opaque errors.
334*9bb1b549SSpandan Das    """
335*9bb1b549SSpandan Das    if (type(dep) == "Target" and
336*9bb1b549SSpandan Das        DefaultInfo in dep and
337*9bb1b549SSpandan Das        getattr(dep[DefaultInfo], "files_to_run", None) and
338*9bb1b549SSpandan Das        dep[DefaultInfo].files_to_run.executable):
339*9bb1b549SSpandan Das        fail("rule {rule} depends on executable {dep} via {edge}. This is not safe for cross-compilation. Depend on go_library instead.".format(
340*9bb1b549SSpandan Das            rule = str(go.label),
341*9bb1b549SSpandan Das            dep = str(dep.label),
342*9bb1b549SSpandan Das            edge = edge,
343*9bb1b549SSpandan Das        ))
344*9bb1b549SSpandan Das
345*9bb1b549SSpandan Dasdef _check_importpaths(ctx):
346*9bb1b549SSpandan Das    paths = []
347*9bb1b549SSpandan Das    p = getattr(ctx.attr, "importpath", "")
348*9bb1b549SSpandan Das    if p:
349*9bb1b549SSpandan Das        paths.append(p)
350*9bb1b549SSpandan Das    p = getattr(ctx.attr, "importmap", "")
351*9bb1b549SSpandan Das    if p:
352*9bb1b549SSpandan Das        paths.append(p)
353*9bb1b549SSpandan Das    paths.extend(getattr(ctx.attr, "importpath_aliases", ()))
354*9bb1b549SSpandan Das
355*9bb1b549SSpandan Das    for p in paths:
356*9bb1b549SSpandan Das        if ":" in p:
357*9bb1b549SSpandan Das            fail("import path '%s' contains invalid character :" % p)
358*9bb1b549SSpandan Das
359*9bb1b549SSpandan Dasdef _infer_importpath(ctx):
360*9bb1b549SSpandan Das    DEFAULT_LIB = "go_default_library"
361*9bb1b549SSpandan Das    VENDOR_PREFIX = "/vendor/"
362*9bb1b549SSpandan Das
363*9bb1b549SSpandan Das    # Check if paths were explicitly set, either in this rule or in an
364*9bb1b549SSpandan Das    # embedded rule.
365*9bb1b549SSpandan Das    attr_importpath = getattr(ctx.attr, "importpath", "")
366*9bb1b549SSpandan Das    attr_importmap = getattr(ctx.attr, "importmap", "")
367*9bb1b549SSpandan Das    embed_importpath = ""
368*9bb1b549SSpandan Das    embed_importmap = ""
369*9bb1b549SSpandan Das    for embed in getattr(ctx.attr, "embed", []):
370*9bb1b549SSpandan Das        if GoLibrary not in embed:
371*9bb1b549SSpandan Das            continue
372*9bb1b549SSpandan Das        lib = embed[GoLibrary]
373*9bb1b549SSpandan Das        if lib.pathtype == EXPLICIT_PATH:
374*9bb1b549SSpandan Das            embed_importpath = lib.importpath
375*9bb1b549SSpandan Das            embed_importmap = lib.importmap
376*9bb1b549SSpandan Das            break
377*9bb1b549SSpandan Das
378*9bb1b549SSpandan Das    importpath = attr_importpath or embed_importpath
379*9bb1b549SSpandan Das    importmap = attr_importmap or embed_importmap or importpath
380*9bb1b549SSpandan Das    if importpath:
381*9bb1b549SSpandan Das        return importpath, importmap, EXPLICIT_PATH
382*9bb1b549SSpandan Das
383*9bb1b549SSpandan Das    # Guess an import path based on the directory structure
384*9bb1b549SSpandan Das    # This should only really be relied on for binaries
385*9bb1b549SSpandan Das    importpath = ctx.label.package
386*9bb1b549SSpandan Das    if ctx.label.name != DEFAULT_LIB and not importpath.endswith(ctx.label.name):
387*9bb1b549SSpandan Das        importpath += "/" + ctx.label.name
388*9bb1b549SSpandan Das    if importpath.rfind(VENDOR_PREFIX) != -1:
389*9bb1b549SSpandan Das        importpath = importpath[len(VENDOR_PREFIX) + importpath.rfind(VENDOR_PREFIX):]
390*9bb1b549SSpandan Das    if importpath.startswith("/"):
391*9bb1b549SSpandan Das        importpath = importpath[1:]
392*9bb1b549SSpandan Das    return importpath, importpath, INFERRED_PATH
393*9bb1b549SSpandan Das
394*9bb1b549SSpandan Dasdef go_context(ctx, attr = None):
395*9bb1b549SSpandan Das    """Returns an API used to build Go code.
396*9bb1b549SSpandan Das
397*9bb1b549SSpandan Das    See /go/toolchains.rst#go-context
398*9bb1b549SSpandan Das    """
399*9bb1b549SSpandan Das    if not attr:
400*9bb1b549SSpandan Das        attr = ctx.attr
401*9bb1b549SSpandan Das    toolchain = ctx.toolchains[GO_TOOLCHAIN]
402*9bb1b549SSpandan Das    cgo_context_info = None
403*9bb1b549SSpandan Das    go_config_info = None
404*9bb1b549SSpandan Das    stdlib = None
405*9bb1b549SSpandan Das    coverdata = None
406*9bb1b549SSpandan Das    nogo = None
407*9bb1b549SSpandan Das    if hasattr(attr, "_go_context_data"):
408*9bb1b549SSpandan Das        go_context_data = _flatten_possibly_transitioned_attr(attr._go_context_data)
409*9bb1b549SSpandan Das        if CgoContextInfo in go_context_data:
410*9bb1b549SSpandan Das            cgo_context_info = go_context_data[CgoContextInfo]
411*9bb1b549SSpandan Das        go_config_info = go_context_data[GoConfigInfo]
412*9bb1b549SSpandan Das        stdlib = go_context_data[GoStdLib]
413*9bb1b549SSpandan Das        coverdata = go_context_data[GoContextInfo].coverdata
414*9bb1b549SSpandan Das        nogo = go_context_data[GoContextInfo].nogo
415*9bb1b549SSpandan Das    if getattr(attr, "_cgo_context_data", None) and CgoContextInfo in attr._cgo_context_data:
416*9bb1b549SSpandan Das        cgo_context_info = attr._cgo_context_data[CgoContextInfo]
417*9bb1b549SSpandan Das    if getattr(attr, "cgo_context_data", None) and CgoContextInfo in attr.cgo_context_data:
418*9bb1b549SSpandan Das        cgo_context_info = attr.cgo_context_data[CgoContextInfo]
419*9bb1b549SSpandan Das    if hasattr(attr, "_go_config"):
420*9bb1b549SSpandan Das        go_config_info = attr._go_config[GoConfigInfo]
421*9bb1b549SSpandan Das    if hasattr(attr, "_stdlib"):
422*9bb1b549SSpandan Das        stdlib = _flatten_possibly_transitioned_attr(attr._stdlib)[GoStdLib]
423*9bb1b549SSpandan Das
424*9bb1b549SSpandan Das    mode = get_mode(ctx, toolchain, cgo_context_info, go_config_info)
425*9bb1b549SSpandan Das    tags = mode.tags
426*9bb1b549SSpandan Das    binary = toolchain.sdk.go
427*9bb1b549SSpandan Das
428*9bb1b549SSpandan Das    if stdlib:
429*9bb1b549SSpandan Das        goroot = stdlib.root_file.dirname
430*9bb1b549SSpandan Das    else:
431*9bb1b549SSpandan Das        goroot = toolchain.sdk.root_file.dirname
432*9bb1b549SSpandan Das
433*9bb1b549SSpandan Das    env = {
434*9bb1b549SSpandan Das        "GOARCH": mode.goarch,
435*9bb1b549SSpandan Das        "GOOS": mode.goos,
436*9bb1b549SSpandan Das        "GOEXPERIMENT": ",".join(toolchain.sdk.experiments),
437*9bb1b549SSpandan Das        "GOROOT": goroot,
438*9bb1b549SSpandan Das        "GOROOT_FINAL": "GOROOT",
439*9bb1b549SSpandan Das        "CGO_ENABLED": "0" if mode.pure else "1",
440*9bb1b549SSpandan Das
441*9bb1b549SSpandan Das        # If we use --action_env=GOPATH, or in other cases where environment
442*9bb1b549SSpandan Das        # variables are passed through to this builder, the SDK build will try
443*9bb1b549SSpandan Das        # to write to that GOPATH (e.g. for x/net/nettest). This will fail if
444*9bb1b549SSpandan Das        # the GOPATH is on a read-only mount, and is generally a bad idea.
445*9bb1b549SSpandan Das        # Explicitly clear this environment variable to ensure that doesn't
446*9bb1b549SSpandan Das        # happen. See #2291 for more information.
447*9bb1b549SSpandan Das        "GOPATH": "",
448*9bb1b549SSpandan Das    }
449*9bb1b549SSpandan Das
450*9bb1b549SSpandan Das    # The level of support is determined by the platform constraints in
451*9bb1b549SSpandan Das    # //go/constraints/amd64.
452*9bb1b549SSpandan Das    # See https://github.com/golang/go/wiki/MinimumRequirements#amd64
453*9bb1b549SSpandan Das    if mode.amd64:
454*9bb1b549SSpandan Das        env["GOAMD64"] = mode.amd64
455*9bb1b549SSpandan Das    if not cgo_context_info:
456*9bb1b549SSpandan Das        crosstool = []
457*9bb1b549SSpandan Das        cgo_tools = None
458*9bb1b549SSpandan Das    else:
459*9bb1b549SSpandan Das        env.update(cgo_context_info.env)
460*9bb1b549SSpandan Das        crosstool = cgo_context_info.crosstool
461*9bb1b549SSpandan Das
462*9bb1b549SSpandan Das        # Add C toolchain directories to PATH.
463*9bb1b549SSpandan Das        # On ARM, go tool link uses some features of gcc to complete its work,
464*9bb1b549SSpandan Das        # so PATH is needed on ARM.
465*9bb1b549SSpandan Das        path_set = {}
466*9bb1b549SSpandan Das        if "PATH" in env:
467*9bb1b549SSpandan Das            for p in env["PATH"].split(ctx.configuration.host_path_separator):
468*9bb1b549SSpandan Das                path_set[p] = None
469*9bb1b549SSpandan Das        cgo_tools = cgo_context_info.cgo_tools
470*9bb1b549SSpandan Das        tool_paths = [
471*9bb1b549SSpandan Das            cgo_tools.c_compiler_path,
472*9bb1b549SSpandan Das            cgo_tools.ld_executable_path,
473*9bb1b549SSpandan Das            cgo_tools.ld_static_lib_path,
474*9bb1b549SSpandan Das            cgo_tools.ld_dynamic_lib_path,
475*9bb1b549SSpandan Das        ]
476*9bb1b549SSpandan Das        for tool_path in tool_paths:
477*9bb1b549SSpandan Das            tool_dir, _, _ = tool_path.rpartition("/")
478*9bb1b549SSpandan Das            path_set[tool_dir] = None
479*9bb1b549SSpandan Das        paths = sorted(path_set.keys())
480*9bb1b549SSpandan Das        if ctx.configuration.host_path_separator == ":":
481*9bb1b549SSpandan Das            # HACK: ":" is a proxy for a UNIX-like host.
482*9bb1b549SSpandan Das            # The tools returned above may be bash scripts that reference commands
483*9bb1b549SSpandan Das            # in directories we might not otherwise include. For example,
484*9bb1b549SSpandan Das            # on macOS, wrapped_ar calls dirname.
485*9bb1b549SSpandan Das            if "/bin" not in path_set:
486*9bb1b549SSpandan Das                paths.append("/bin")
487*9bb1b549SSpandan Das            if "/usr/bin" not in path_set:
488*9bb1b549SSpandan Das                paths.append("/usr/bin")
489*9bb1b549SSpandan Das        env["PATH"] = ctx.configuration.host_path_separator.join(paths)
490*9bb1b549SSpandan Das
491*9bb1b549SSpandan Das    # TODO(jayconrod): remove this. It's way too broad. Everything should
492*9bb1b549SSpandan Das    # depend on more specific lists.
493*9bb1b549SSpandan Das    sdk_files = ([toolchain.sdk.go] +
494*9bb1b549SSpandan Das                 toolchain.sdk.srcs +
495*9bb1b549SSpandan Das                 toolchain.sdk.headers +
496*9bb1b549SSpandan Das                 toolchain.sdk.libs +
497*9bb1b549SSpandan Das                 toolchain.sdk.tools)
498*9bb1b549SSpandan Das
499*9bb1b549SSpandan Das    _check_importpaths(ctx)
500*9bb1b549SSpandan Das    importpath, importmap, pathtype = _infer_importpath(ctx)
501*9bb1b549SSpandan Das    importpath_aliases = tuple(getattr(attr, "importpath_aliases", ()))
502*9bb1b549SSpandan Das
503*9bb1b549SSpandan Das    return struct(
504*9bb1b549SSpandan Das        # Fields
505*9bb1b549SSpandan Das        toolchain = toolchain,
506*9bb1b549SSpandan Das        sdk = toolchain.sdk,
507*9bb1b549SSpandan Das        mode = mode,
508*9bb1b549SSpandan Das        root = goroot,
509*9bb1b549SSpandan Das        go = binary,
510*9bb1b549SSpandan Das        stdlib = stdlib,
511*9bb1b549SSpandan Das        sdk_root = toolchain.sdk.root_file,
512*9bb1b549SSpandan Das        sdk_files = sdk_files,
513*9bb1b549SSpandan Das        sdk_tools = toolchain.sdk.tools,
514*9bb1b549SSpandan Das        actions = ctx.actions,
515*9bb1b549SSpandan Das        exe_extension = goos_to_extension(mode.goos),
516*9bb1b549SSpandan Das        shared_extension = goos_to_shared_extension(mode.goos),
517*9bb1b549SSpandan Das        crosstool = crosstool,
518*9bb1b549SSpandan Das        package_list = toolchain.sdk.package_list,
519*9bb1b549SSpandan Das        importpath = importpath,
520*9bb1b549SSpandan Das        importmap = importmap,
521*9bb1b549SSpandan Das        importpath_aliases = importpath_aliases,
522*9bb1b549SSpandan Das        pathtype = pathtype,
523*9bb1b549SSpandan Das        cgo_tools = cgo_tools,
524*9bb1b549SSpandan Das        nogo = nogo,
525*9bb1b549SSpandan Das        coverdata = coverdata,
526*9bb1b549SSpandan Das        coverage_enabled = ctx.configuration.coverage_enabled,
527*9bb1b549SSpandan Das        coverage_instrumented = ctx.coverage_instrumented(),
528*9bb1b549SSpandan Das        env = env,
529*9bb1b549SSpandan Das        tags = tags,
530*9bb1b549SSpandan Das        stamp = mode.stamp,
531*9bb1b549SSpandan Das        label = ctx.label,
532*9bb1b549SSpandan Das        cover_format = mode.cover_format,
533*9bb1b549SSpandan Das        # Action generators
534*9bb1b549SSpandan Das        archive = toolchain.actions.archive,
535*9bb1b549SSpandan Das        binary = toolchain.actions.binary,
536*9bb1b549SSpandan Das        link = toolchain.actions.link,
537*9bb1b549SSpandan Das
538*9bb1b549SSpandan Das        # Helpers
539*9bb1b549SSpandan Das        args = _new_args,  # deprecated
540*9bb1b549SSpandan Das        builder_args = _builder_args,
541*9bb1b549SSpandan Das        tool_args = _tool_args,
542*9bb1b549SSpandan Das        new_library = _new_library,
543*9bb1b549SSpandan Das        library_to_source = _library_to_source,
544*9bb1b549SSpandan Das        declare_file = _declare_file,
545*9bb1b549SSpandan Das        declare_directory = _declare_directory,
546*9bb1b549SSpandan Das
547*9bb1b549SSpandan Das        # Private
548*9bb1b549SSpandan Das        # TODO: All uses of this should be removed
549*9bb1b549SSpandan Das        _ctx = ctx,
550*9bb1b549SSpandan Das    )
551*9bb1b549SSpandan Das
552*9bb1b549SSpandan Dasdef _go_context_data_impl(ctx):
553*9bb1b549SSpandan Das    if "race" in ctx.features:
554*9bb1b549SSpandan Das        print("WARNING: --features=race is no longer supported. Use --@io_bazel_rules_go//go/config:race instead.")
555*9bb1b549SSpandan Das    if "msan" in ctx.features:
556*9bb1b549SSpandan Das        print("WARNING: --features=msan is no longer supported. Use --@io_bazel_rules_go//go/config:msan instead.")
557*9bb1b549SSpandan Das    nogo = ctx.files.nogo[0] if ctx.files.nogo else None
558*9bb1b549SSpandan Das    providers = [
559*9bb1b549SSpandan Das        GoContextInfo(
560*9bb1b549SSpandan Das            coverdata = ctx.attr.coverdata[GoArchive],
561*9bb1b549SSpandan Das            nogo = nogo,
562*9bb1b549SSpandan Das        ),
563*9bb1b549SSpandan Das        ctx.attr.stdlib[GoStdLib],
564*9bb1b549SSpandan Das        ctx.attr.go_config[GoConfigInfo],
565*9bb1b549SSpandan Das    ]
566*9bb1b549SSpandan Das    if ctx.attr.cgo_context_data and CgoContextInfo in ctx.attr.cgo_context_data:
567*9bb1b549SSpandan Das        providers.append(ctx.attr.cgo_context_data[CgoContextInfo])
568*9bb1b549SSpandan Das    return providers
569*9bb1b549SSpandan Das
570*9bb1b549SSpandan Dasgo_context_data = rule(
571*9bb1b549SSpandan Das    _go_context_data_impl,
572*9bb1b549SSpandan Das    attrs = {
573*9bb1b549SSpandan Das        "cgo_context_data": attr.label(),
574*9bb1b549SSpandan Das        "coverdata": attr.label(
575*9bb1b549SSpandan Das            mandatory = True,
576*9bb1b549SSpandan Das            providers = [GoArchive],
577*9bb1b549SSpandan Das        ),
578*9bb1b549SSpandan Das        "go_config": attr.label(
579*9bb1b549SSpandan Das            mandatory = True,
580*9bb1b549SSpandan Das            providers = [GoConfigInfo],
581*9bb1b549SSpandan Das        ),
582*9bb1b549SSpandan Das        "nogo": attr.label(
583*9bb1b549SSpandan Das            mandatory = True,
584*9bb1b549SSpandan Das            cfg = "exec",
585*9bb1b549SSpandan Das        ),
586*9bb1b549SSpandan Das        "stdlib": attr.label(
587*9bb1b549SSpandan Das            mandatory = True,
588*9bb1b549SSpandan Das            providers = [GoStdLib],
589*9bb1b549SSpandan Das        ),
590*9bb1b549SSpandan Das        "_allowlist_function_transition": attr.label(
591*9bb1b549SSpandan Das            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
592*9bb1b549SSpandan Das        ),
593*9bb1b549SSpandan Das    },
594*9bb1b549SSpandan Das    doc = """go_context_data gathers information about the build configuration.
595*9bb1b549SSpandan Das    It is a common dependency of all Go targets.""",
596*9bb1b549SSpandan Das    toolchains = [GO_TOOLCHAIN],
597*9bb1b549SSpandan Das    cfg = request_nogo_transition,
598*9bb1b549SSpandan Das)
599*9bb1b549SSpandan Das
600*9bb1b549SSpandan Dasdef _cgo_context_data_impl(ctx):
601*9bb1b549SSpandan Das    # TODO(jayconrod): find a way to get a list of files that comprise the
602*9bb1b549SSpandan Das    # toolchain (to be inputs into actions that need it).
603*9bb1b549SSpandan Das    # ctx.files._cc_toolchain won't work when cc toolchain resolution
604*9bb1b549SSpandan Das    # is switched on.
605*9bb1b549SSpandan Das    cc_toolchain = find_cpp_toolchain(ctx)
606*9bb1b549SSpandan Das    if cc_toolchain.compiler in _UNSUPPORTED_C_COMPILERS:
607*9bb1b549SSpandan Das        return []
608*9bb1b549SSpandan Das
609*9bb1b549SSpandan Das    feature_configuration = cc_common.configure_features(
610*9bb1b549SSpandan Das        ctx = ctx,
611*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
612*9bb1b549SSpandan Das        requested_features = ctx.features,
613*9bb1b549SSpandan Das        unsupported_features = ctx.disabled_features + _UNSUPPORTED_FEATURES,
614*9bb1b549SSpandan Das    )
615*9bb1b549SSpandan Das
616*9bb1b549SSpandan Das    # TODO(jayconrod): keep the environment separate for different actions.
617*9bb1b549SSpandan Das    env = {}
618*9bb1b549SSpandan Das
619*9bb1b549SSpandan Das    c_compile_variables = cc_common.create_compile_variables(
620*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
621*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
622*9bb1b549SSpandan Das    )
623*9bb1b549SSpandan Das    c_compiler_path = cc_common.get_tool_for_action(
624*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
625*9bb1b549SSpandan Das        action_name = C_COMPILE_ACTION_NAME,
626*9bb1b549SSpandan Das    )
627*9bb1b549SSpandan Das    c_compile_options = _filter_options(
628*9bb1b549SSpandan Das        cc_common.get_memory_inefficient_command_line(
629*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
630*9bb1b549SSpandan Das            action_name = C_COMPILE_ACTION_NAME,
631*9bb1b549SSpandan Das            variables = c_compile_variables,
632*9bb1b549SSpandan Das        ) + ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts,
633*9bb1b549SSpandan Das        _COMPILER_OPTIONS_DENYLIST,
634*9bb1b549SSpandan Das    )
635*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
636*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
637*9bb1b549SSpandan Das        action_name = C_COMPILE_ACTION_NAME,
638*9bb1b549SSpandan Das        variables = c_compile_variables,
639*9bb1b549SSpandan Das    ))
640*9bb1b549SSpandan Das
641*9bb1b549SSpandan Das    cxx_compile_variables = cc_common.create_compile_variables(
642*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
643*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
644*9bb1b549SSpandan Das    )
645*9bb1b549SSpandan Das    cxx_compile_options = _filter_options(
646*9bb1b549SSpandan Das        cc_common.get_memory_inefficient_command_line(
647*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
648*9bb1b549SSpandan Das            action_name = CPP_COMPILE_ACTION_NAME,
649*9bb1b549SSpandan Das            variables = cxx_compile_variables,
650*9bb1b549SSpandan Das        ) + ctx.fragments.cpp.copts + ctx.fragments.cpp.cxxopts,
651*9bb1b549SSpandan Das        _COMPILER_OPTIONS_DENYLIST,
652*9bb1b549SSpandan Das    )
653*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
654*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
655*9bb1b549SSpandan Das        action_name = CPP_COMPILE_ACTION_NAME,
656*9bb1b549SSpandan Das        variables = cxx_compile_variables,
657*9bb1b549SSpandan Das    ))
658*9bb1b549SSpandan Das
659*9bb1b549SSpandan Das    objc_compile_variables = cc_common.create_compile_variables(
660*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
661*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
662*9bb1b549SSpandan Das    )
663*9bb1b549SSpandan Das    objc_compile_options = _filter_options(
664*9bb1b549SSpandan Das        cc_common.get_memory_inefficient_command_line(
665*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
666*9bb1b549SSpandan Das            action_name = OBJC_COMPILE_ACTION_NAME,
667*9bb1b549SSpandan Das            variables = objc_compile_variables,
668*9bb1b549SSpandan Das        ),
669*9bb1b549SSpandan Das        _COMPILER_OPTIONS_DENYLIST,
670*9bb1b549SSpandan Das    )
671*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
672*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
673*9bb1b549SSpandan Das        action_name = OBJC_COMPILE_ACTION_NAME,
674*9bb1b549SSpandan Das        variables = objc_compile_variables,
675*9bb1b549SSpandan Das    ))
676*9bb1b549SSpandan Das
677*9bb1b549SSpandan Das    objcxx_compile_variables = cc_common.create_compile_variables(
678*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
679*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
680*9bb1b549SSpandan Das    )
681*9bb1b549SSpandan Das    objcxx_compile_options = _filter_options(
682*9bb1b549SSpandan Das        cc_common.get_memory_inefficient_command_line(
683*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
684*9bb1b549SSpandan Das            action_name = OBJCPP_COMPILE_ACTION_NAME,
685*9bb1b549SSpandan Das            variables = objcxx_compile_variables,
686*9bb1b549SSpandan Das        ),
687*9bb1b549SSpandan Das        _COMPILER_OPTIONS_DENYLIST,
688*9bb1b549SSpandan Das    )
689*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
690*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
691*9bb1b549SSpandan Das        action_name = OBJCPP_COMPILE_ACTION_NAME,
692*9bb1b549SSpandan Das        variables = objcxx_compile_variables,
693*9bb1b549SSpandan Das    ))
694*9bb1b549SSpandan Das
695*9bb1b549SSpandan Das    ld_executable_variables = cc_common.create_link_variables(
696*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
697*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
698*9bb1b549SSpandan Das        is_linking_dynamic_library = False,
699*9bb1b549SSpandan Das    )
700*9bb1b549SSpandan Das    ld_executable_path = cc_common.get_tool_for_action(
701*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
702*9bb1b549SSpandan Das        action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
703*9bb1b549SSpandan Das    )
704*9bb1b549SSpandan Das    ld_executable_options = _filter_options(
705*9bb1b549SSpandan Das        cc_common.get_memory_inefficient_command_line(
706*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
707*9bb1b549SSpandan Das            action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
708*9bb1b549SSpandan Das            variables = ld_executable_variables,
709*9bb1b549SSpandan Das        ) + ctx.fragments.cpp.linkopts,
710*9bb1b549SSpandan Das        _LINKER_OPTIONS_DENYLIST,
711*9bb1b549SSpandan Das    )
712*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
713*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
714*9bb1b549SSpandan Das        action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
715*9bb1b549SSpandan Das        variables = ld_executable_variables,
716*9bb1b549SSpandan Das    ))
717*9bb1b549SSpandan Das
718*9bb1b549SSpandan Das    # We don't collect options for static libraries. Go always links with
719*9bb1b549SSpandan Das    # "ar" in "c-archive" mode. We can set the ar executable path with
720*9bb1b549SSpandan Das    # -extar, but the options are hard-coded to something like -q -c -s.
721*9bb1b549SSpandan Das    ld_static_lib_variables = cc_common.create_link_variables(
722*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
723*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
724*9bb1b549SSpandan Das        is_linking_dynamic_library = False,
725*9bb1b549SSpandan Das    )
726*9bb1b549SSpandan Das    ld_static_lib_path = cc_common.get_tool_for_action(
727*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
728*9bb1b549SSpandan Das        action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
729*9bb1b549SSpandan Das    )
730*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
731*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
732*9bb1b549SSpandan Das        action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
733*9bb1b549SSpandan Das        variables = ld_static_lib_variables,
734*9bb1b549SSpandan Das    ))
735*9bb1b549SSpandan Das
736*9bb1b549SSpandan Das    ld_dynamic_lib_variables = cc_common.create_link_variables(
737*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
738*9bb1b549SSpandan Das        cc_toolchain = cc_toolchain,
739*9bb1b549SSpandan Das        is_linking_dynamic_library = True,
740*9bb1b549SSpandan Das    )
741*9bb1b549SSpandan Das    ld_dynamic_lib_path = cc_common.get_tool_for_action(
742*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
743*9bb1b549SSpandan Das        action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
744*9bb1b549SSpandan Das    )
745*9bb1b549SSpandan Das    ld_dynamic_lib_options = _filter_options(
746*9bb1b549SSpandan Das        cc_common.get_memory_inefficient_command_line(
747*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
748*9bb1b549SSpandan Das            action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
749*9bb1b549SSpandan Das            variables = ld_dynamic_lib_variables,
750*9bb1b549SSpandan Das        ) + ctx.fragments.cpp.linkopts,
751*9bb1b549SSpandan Das        _LINKER_OPTIONS_DENYLIST,
752*9bb1b549SSpandan Das    )
753*9bb1b549SSpandan Das
754*9bb1b549SSpandan Das    env.update(cc_common.get_environment_variables(
755*9bb1b549SSpandan Das        feature_configuration = feature_configuration,
756*9bb1b549SSpandan Das        action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
757*9bb1b549SSpandan Das        variables = ld_dynamic_lib_variables,
758*9bb1b549SSpandan Das    ))
759*9bb1b549SSpandan Das
760*9bb1b549SSpandan Das    tags = []
761*9bb1b549SSpandan Das    if "gotags" in ctx.var:
762*9bb1b549SSpandan Das        tags = ctx.var["gotags"].split(",")
763*9bb1b549SSpandan Das    apple_ensure_options(
764*9bb1b549SSpandan Das        ctx,
765*9bb1b549SSpandan Das        env,
766*9bb1b549SSpandan Das        tags,
767*9bb1b549SSpandan Das        (c_compile_options, cxx_compile_options, objc_compile_options, objcxx_compile_options),
768*9bb1b549SSpandan Das        (ld_executable_options, ld_dynamic_lib_options),
769*9bb1b549SSpandan Das        cc_toolchain.target_gnu_system_name,
770*9bb1b549SSpandan Das    )
771*9bb1b549SSpandan Das
772*9bb1b549SSpandan Das    return [CgoContextInfo(
773*9bb1b549SSpandan Das        crosstool = cc_toolchain.all_files.to_list(),
774*9bb1b549SSpandan Das        tags = tags,
775*9bb1b549SSpandan Das        env = env,
776*9bb1b549SSpandan Das        cgo_tools = struct(
777*9bb1b549SSpandan Das            cc_toolchain = cc_toolchain,
778*9bb1b549SSpandan Das            feature_configuration = feature_configuration,
779*9bb1b549SSpandan Das            c_compiler_path = c_compiler_path,
780*9bb1b549SSpandan Das            c_compile_options = c_compile_options,
781*9bb1b549SSpandan Das            cxx_compile_options = cxx_compile_options,
782*9bb1b549SSpandan Das            objc_compile_options = objc_compile_options,
783*9bb1b549SSpandan Das            objcxx_compile_options = objcxx_compile_options,
784*9bb1b549SSpandan Das            ld_executable_path = ld_executable_path,
785*9bb1b549SSpandan Das            ld_executable_options = ld_executable_options,
786*9bb1b549SSpandan Das            ld_static_lib_path = ld_static_lib_path,
787*9bb1b549SSpandan Das            ld_dynamic_lib_path = ld_dynamic_lib_path,
788*9bb1b549SSpandan Das            ld_dynamic_lib_options = ld_dynamic_lib_options,
789*9bb1b549SSpandan Das        ),
790*9bb1b549SSpandan Das    )]
791*9bb1b549SSpandan Das
792*9bb1b549SSpandan Dascgo_context_data = rule(
793*9bb1b549SSpandan Das    implementation = _cgo_context_data_impl,
794*9bb1b549SSpandan Das    attrs = {
795*9bb1b549SSpandan Das        "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
796*9bb1b549SSpandan Das        "_xcode_config": attr.label(
797*9bb1b549SSpandan Das            default = "@bazel_tools//tools/osx:current_xcode_config",
798*9bb1b549SSpandan Das        ),
799*9bb1b549SSpandan Das    },
800*9bb1b549SSpandan Das    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
801*9bb1b549SSpandan Das    fragments = ["apple", "cpp"],
802*9bb1b549SSpandan Das    doc = """Collects information about the C/C++ toolchain. The C/C++ toolchain
803*9bb1b549SSpandan Das    is needed to build cgo code, but is generally optional. Rules can't have
804*9bb1b549SSpandan Das    optional toolchains, so instead, we have an optional dependency on this
805*9bb1b549SSpandan Das    rule.""",
806*9bb1b549SSpandan Das)
807*9bb1b549SSpandan Das
808*9bb1b549SSpandan Dasdef _cgo_context_data_proxy_impl(ctx):
809*9bb1b549SSpandan Das    if ctx.attr.actual and CgoContextInfo in ctx.attr.actual:
810*9bb1b549SSpandan Das        return [ctx.attr.actual[CgoContextInfo]]
811*9bb1b549SSpandan Das    return []
812*9bb1b549SSpandan Das
813*9bb1b549SSpandan Dascgo_context_data_proxy = rule(
814*9bb1b549SSpandan Das    implementation = _cgo_context_data_proxy_impl,
815*9bb1b549SSpandan Das    attrs = {
816*9bb1b549SSpandan Das        "actual": attr.label(),
817*9bb1b549SSpandan Das    },
818*9bb1b549SSpandan Das    doc = """Conditionally depends on cgo_context_data and forwards it provider.
819*9bb1b549SSpandan Das
820*9bb1b549SSpandan Das    Useful in situations where select cannot be used, like attribute defaults.
821*9bb1b549SSpandan Das    """,
822*9bb1b549SSpandan Das)
823*9bb1b549SSpandan Das
824*9bb1b549SSpandan Dasdef _go_config_impl(ctx):
825*9bb1b549SSpandan Das    return [GoConfigInfo(
826*9bb1b549SSpandan Das        static = ctx.attr.static[BuildSettingInfo].value,
827*9bb1b549SSpandan Das        race = ctx.attr.race[BuildSettingInfo].value,
828*9bb1b549SSpandan Das        msan = ctx.attr.msan[BuildSettingInfo].value,
829*9bb1b549SSpandan Das        pure = ctx.attr.pure[BuildSettingInfo].value,
830*9bb1b549SSpandan Das        strip = ctx.attr.strip,
831*9bb1b549SSpandan Das        debug = ctx.attr.debug[BuildSettingInfo].value,
832*9bb1b549SSpandan Das        linkmode = ctx.attr.linkmode[BuildSettingInfo].value,
833*9bb1b549SSpandan Das        gc_linkopts = ctx.attr.gc_linkopts[BuildSettingInfo].value,
834*9bb1b549SSpandan Das        tags = ctx.attr.gotags[BuildSettingInfo].value,
835*9bb1b549SSpandan Das        stamp = ctx.attr.stamp,
836*9bb1b549SSpandan Das        cover_format = ctx.attr.cover_format[BuildSettingInfo].value,
837*9bb1b549SSpandan Das        gc_goopts = ctx.attr.gc_goopts[BuildSettingInfo].value,
838*9bb1b549SSpandan Das        amd64 = ctx.attr.amd64,
839*9bb1b549SSpandan Das    )]
840*9bb1b549SSpandan Das
841*9bb1b549SSpandan Dasgo_config = rule(
842*9bb1b549SSpandan Das    implementation = _go_config_impl,
843*9bb1b549SSpandan Das    attrs = {
844*9bb1b549SSpandan Das        "static": attr.label(
845*9bb1b549SSpandan Das            mandatory = True,
846*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
847*9bb1b549SSpandan Das        ),
848*9bb1b549SSpandan Das        "race": attr.label(
849*9bb1b549SSpandan Das            mandatory = True,
850*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
851*9bb1b549SSpandan Das        ),
852*9bb1b549SSpandan Das        "msan": attr.label(
853*9bb1b549SSpandan Das            mandatory = True,
854*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
855*9bb1b549SSpandan Das        ),
856*9bb1b549SSpandan Das        "pure": attr.label(
857*9bb1b549SSpandan Das            mandatory = True,
858*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
859*9bb1b549SSpandan Das        ),
860*9bb1b549SSpandan Das        "strip": attr.bool(mandatory = True),
861*9bb1b549SSpandan Das        "debug": attr.label(
862*9bb1b549SSpandan Das            mandatory = True,
863*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
864*9bb1b549SSpandan Das        ),
865*9bb1b549SSpandan Das        "linkmode": attr.label(
866*9bb1b549SSpandan Das            mandatory = True,
867*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
868*9bb1b549SSpandan Das        ),
869*9bb1b549SSpandan Das        "gc_linkopts": attr.label(
870*9bb1b549SSpandan Das            mandatory = True,
871*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
872*9bb1b549SSpandan Das        ),
873*9bb1b549SSpandan Das        "gotags": attr.label(
874*9bb1b549SSpandan Das            mandatory = True,
875*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
876*9bb1b549SSpandan Das        ),
877*9bb1b549SSpandan Das        "stamp": attr.bool(mandatory = True),
878*9bb1b549SSpandan Das        "cover_format": attr.label(
879*9bb1b549SSpandan Das            mandatory = True,
880*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
881*9bb1b549SSpandan Das        ),
882*9bb1b549SSpandan Das        "gc_goopts": attr.label(
883*9bb1b549SSpandan Das            mandatory = True,
884*9bb1b549SSpandan Das            providers = [BuildSettingInfo],
885*9bb1b549SSpandan Das        ),
886*9bb1b549SSpandan Das        "amd64": attr.string(),
887*9bb1b549SSpandan Das    },
888*9bb1b549SSpandan Das    provides = [GoConfigInfo],
889*9bb1b549SSpandan Das    doc = """Collects information about build settings in the current
890*9bb1b549SSpandan Das    configuration. Rules may depend on this instead of depending on all
891*9bb1b549SSpandan Das    the build settings directly.""",
892*9bb1b549SSpandan Das)
893*9bb1b549SSpandan Das
894*9bb1b549SSpandan Dasdef _expand_opts(go, attribute_name, opts):
895*9bb1b549SSpandan Das    return [go._ctx.expand_make_variables(attribute_name, opt, {}) for opt in opts]
896*9bb1b549SSpandan Das
897*9bb1b549SSpandan Dasdef _expand_location(go, attr, s):
898*9bb1b549SSpandan Das    return go._ctx.expand_location(s, getattr(attr, "data", []))
899*9bb1b549SSpandan Das
900*9bb1b549SSpandan Das_LIST_TYPE = type([])
901*9bb1b549SSpandan Das
902*9bb1b549SSpandan Das# Used to get attribute values which may have been transitioned.
903*9bb1b549SSpandan Das# Transitioned attributes end up as lists.
904*9bb1b549SSpandan Das# We never use split-transitions, so we always expect exactly one element in those lists.
905*9bb1b549SSpandan Das# But if the attribute wasn't transitioned, it won't be a list.
906*9bb1b549SSpandan Dasdef _flatten_possibly_transitioned_attr(maybe_list):
907*9bb1b549SSpandan Das    if type(maybe_list) == _LIST_TYPE:
908*9bb1b549SSpandan Das        if len(maybe_list) == 1:
909*9bb1b549SSpandan Das            return maybe_list[0]
910*9bb1b549SSpandan Das        else:
911*9bb1b549SSpandan Das            fail("Expected exactly one element in list but got {}".format(maybe_list))
912*9bb1b549SSpandan Das    return maybe_list
913