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