xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/actions/stdlib.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1# Copyright 2019 The Bazel Go Rules 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:common.bzl",
17    "COVERAGE_OPTIONS_DENYLIST",
18)
19load(
20    "//go/private:providers.bzl",
21    "GoStdLib",
22)
23load(
24    "//go/private:mode.bzl",
25    "LINKMODE_NORMAL",
26    "extldflags_from_cc_toolchain",
27    "link_mode_args",
28)
29load("//go/private:sdk.bzl", "parse_version")
30load("//go/private/actions:utils.bzl", "quote_opts")
31
32def emit_stdlib(go):
33    """Returns a standard library for the target configuration.
34
35    If the precompiled standard library is suitable, it will be returned.
36    Otherwise, the standard library will be compiled for the target.
37
38    Returns:
39        A list of providers containing GoLibrary and GoSource. GoSource.stdlib
40        will point to a new GoStdLib.
41    """
42    library = go.new_library(go, resolver = _stdlib_library_to_source)
43    source = go.library_to_source(go, {}, library, False)
44    return [source, library]
45
46def _stdlib_library_to_source(go, _attr, source, _merge):
47    if _should_use_sdk_stdlib(go):
48        source["stdlib"] = _sdk_stdlib(go)
49    else:
50        source["stdlib"] = _build_stdlib(go)
51
52def _should_use_sdk_stdlib(go):
53    version = parse_version(go.sdk.version)
54    if version and version[0] <= 1 and version[1] <= 19 and go.sdk.experiments:
55        # The precompiled stdlib shipped with 1.19 or below doesn't have experiments
56        return False
57    return (go.sdk.libs and  # go.sdk.libs is non-empty if sdk ships with precompiled .a files
58            go.mode.goos == go.sdk.goos and
59            go.mode.goarch == go.sdk.goarch and
60            not go.mode.race and  # TODO(jayconrod): use precompiled race
61            not go.mode.msan and
62            not go.mode.pure and
63            not go.mode.gc_goopts and
64            go.mode.link == LINKMODE_NORMAL)
65
66def _build_stdlib_list_json(go):
67    out = go.declare_file(go, "stdlib.pkg.json")
68    args = go.builder_args(go, "stdliblist")
69    args.add("-sdk", go.sdk.root_file.dirname)
70    args.add("-out", out)
71
72    inputs = go.sdk_files
73    if not go.mode.pure:
74        inputs += go.crosstool
75
76    go.actions.run(
77        inputs = inputs,
78        outputs = [out],
79        mnemonic = "GoStdlibList",
80        executable = go.toolchain._builder,
81        arguments = [args],
82        env = _build_env(go),
83    )
84    return out
85
86def _build_env(go):
87    env = go.env
88
89    if go.mode.pure:
90        env.update({"CGO_ENABLED": "0"})
91        return env
92
93    # NOTE(#2545): avoid unnecessary dynamic link
94    # go std library doesn't use C++, so should not have -lstdc++
95    # Also drop coverage flags as nothing in the stdlib is compiled with
96    # coverage - we disable it for all CGo code anyway.
97    ldflags = [
98        option
99        for option in extldflags_from_cc_toolchain(go)
100        if option not in ("-lstdc++", "-lc++") and option not in COVERAGE_OPTIONS_DENYLIST
101    ]
102    env.update({
103        "CGO_ENABLED": "1",
104        "CC": go.cgo_tools.c_compiler_path,
105        "CGO_CFLAGS": " ".join(go.cgo_tools.c_compile_options),
106        "CGO_LDFLAGS": " ".join(ldflags),
107    })
108
109    return env
110
111def _sdk_stdlib(go):
112    return GoStdLib(
113        _list_json = _build_stdlib_list_json(go),
114        libs = go.sdk.libs,
115        root_file = go.sdk.root_file,
116    )
117
118def _build_stdlib(go):
119    pkg = go.declare_directory(go, path = "pkg")
120    args = go.builder_args(go, "stdlib")
121    args.add("-out", pkg.dirname)
122    if go.mode.race:
123        args.add("-race")
124    args.add("-package", "std")
125    if not go.mode.pure:
126        args.add("-package", "runtime/cgo")
127    args.add_all(link_mode_args(go.mode))
128
129    args.add("-gcflags", quote_opts(go.mode.gc_goopts))
130
131    inputs = (go.sdk.srcs +
132              go.sdk.headers +
133              go.sdk.tools +
134              [go.sdk.go, go.sdk.package_list, go.sdk.root_file] +
135              go.crosstool)
136    outputs = [pkg]
137    go.actions.run(
138        inputs = inputs,
139        outputs = outputs,
140        mnemonic = "GoStdlib",
141        executable = go.toolchain._builder,
142        arguments = [args],
143        env = _build_env(go),
144    )
145    return GoStdLib(
146        _list_json = _build_stdlib_list_json(go),
147        libs = [pkg],
148        root_file = pkg,
149    )
150