1# Copyright 2017 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
15# Modes are documented in go/modes.rst#compilation-modes
16
17LINKMODE_NORMAL = "normal"
18
19LINKMODE_SHARED = "shared"
20
21LINKMODE_PIE = "pie"
22
23LINKMODE_PLUGIN = "plugin"
24
25LINKMODE_C_SHARED = "c-shared"
26
27LINKMODE_C_ARCHIVE = "c-archive"
28
29LINKMODES = [LINKMODE_NORMAL, LINKMODE_PLUGIN, LINKMODE_C_SHARED, LINKMODE_C_ARCHIVE, LINKMODE_PIE]
30
31# All link modes that produce executables to be run with bazel run.
32LINKMODES_EXECUTABLE = [LINKMODE_NORMAL, LINKMODE_PIE]
33
34# All link modes that require external linking and thus a cgo context.
35LINKMODES_REQUIRING_EXTERNAL_LINKING = [
36 LINKMODE_PLUGIN,
37 LINKMODE_C_ARCHIVE,
38 LINKMODE_C_SHARED,
39]
40
41def mode_string(mode):
42 result = [mode.goos, mode.goarch]
43 if mode.static:
44 result.append("static")
45 if mode.race:
46 result.append("race")
47 if mode.msan:
48 result.append("msan")
49 if mode.pure:
50 result.append("pure")
51 if mode.debug:
52 result.append("debug")
53 if mode.strip:
54 result.append("stripped")
55 if not result or not mode.link == LINKMODE_NORMAL:
56 result.append(mode.link)
57 if mode.gc_goopts:
58 result.extend(mode.gc_goopts)
59 return "_".join(result)
60
61def _ternary(*values):
62 for v in values:
63 if v == None:
64 continue
65 if type(v) == "bool":
66 return v
67 if type(v) != "string":
68 fail("Invalid value type {}".format(type(v)))
69 v = v.lower()
70 if v == "on":
71 return True
72 if v == "off":
73 return False
74 if v == "auto":
75 continue
76 fail("Invalid value {}".format(v))
77 fail("_ternary failed to produce a final result from {}".format(values))
78
79def get_mode(ctx, go_toolchain, cgo_context_info, go_config_info):
80 static = _ternary(go_config_info.static if go_config_info else "off")
81 if getattr(ctx.attr, "pure", None) == "off" and not cgo_context_info:
82 fail("{} has pure explicitly set to off, but no C++ toolchain could be found for its platform".format(ctx.label))
83 pure = _ternary(
84 "on" if not cgo_context_info else "auto",
85 go_config_info.pure if go_config_info else "off",
86 )
87 race = _ternary(go_config_info.race if go_config_info else "off")
88 msan = _ternary(go_config_info.msan if go_config_info else "off")
89 strip = go_config_info.strip if go_config_info else False
90 stamp = go_config_info.stamp if go_config_info else False
91 debug = go_config_info.debug if go_config_info else False
92 linkmode = go_config_info.linkmode if go_config_info else LINKMODE_NORMAL
93 cover_format = go_config_info and go_config_info.cover_format
94 amd64 = go_config_info.amd64 if go_config_info else None
95 arm = go_config_info.arm if go_config_info else None
96 goos = go_toolchain.default_goos if getattr(ctx.attr, "goos", "auto") == "auto" else ctx.attr.goos
97 goarch = go_toolchain.default_goarch if getattr(ctx.attr, "goarch", "auto") == "auto" else ctx.attr.goarch
98 gc_goopts = go_config_info.gc_goopts if go_config_info else []
99 pgoprofile = None
100 if go_config_info:
101 if len(go_config_info.pgoprofile.files.to_list()) > 2:
102 fail("providing more than one pprof file to pgoprofile is not supported")
103 elif len(go_config_info.pgoprofile.files.to_list()) == 1:
104 pgoprofile = go_config_info.pgoprofile.files.to_list()[0]
105
106 # TODO(jayconrod): check for more invalid and contradictory settings.
107 if pure and race:
108 fail("race instrumentation can't be enabled when cgo is disabled. Check that pure is not set to \"off\" and a C/C++ toolchain is configured.")
109 if pure and msan:
110 fail("msan instrumentation can't be enabled when cgo is disabled. Check that pure is not set to \"off\" and a C/C++ toolchain is configured.")
111 if pure and linkmode in LINKMODES_REQUIRING_EXTERNAL_LINKING:
112 fail(("linkmode '{}' can't be used when cgo is disabled. Check that pure is not set to \"off\" and that a C/C++ toolchain is configured for " +
113 "your current platform. If you defined a custom platform, make sure that it has the @io_bazel_rules_go//go/toolchain:cgo_on constraint value.").format(linkmode))
114
115 gc_linkopts = list(go_config_info.gc_linkopts) if go_config_info else []
116 tags = list(go_config_info.tags) if go_config_info else []
117 if "gotags" in ctx.var:
118 tags.extend(ctx.var["gotags"].split(","))
119 if cgo_context_info:
120 tags.extend(cgo_context_info.tags)
121 if race:
122 tags.append("race")
123 if msan:
124 tags.append("msan")
125
126 return struct(
127 static = static,
128 race = race,
129 msan = msan,
130 pure = pure,
131 link = linkmode,
132 gc_linkopts = gc_linkopts,
133 strip = strip,
134 stamp = stamp,
135 debug = debug,
136 goos = goos,
137 goarch = goarch,
138 tags = tags,
139 cover_format = cover_format,
140 amd64 = amd64,
141 arm = arm,
142 gc_goopts = gc_goopts,
143 pgoprofile = pgoprofile,
144 )
145
146def installsuffix(mode):
147 s = mode.goos + "_" + mode.goarch
148 if mode.race:
149 s += "_race"
150 elif mode.msan:
151 s += "_msan"
152 return s
153
154def mode_tags_equivalent(l, r):
155 # Returns whether two modes are equivalent for Go build tags. For example,
156 # goos and goarch must match, but static doesn't matter.
157 return (l.goos == r.goos and
158 l.goarch == r.goarch and
159 l.race == r.race and
160 l.msan == r.msan)
161
162# Ported from https://github.com/golang/go/blob/master/src/cmd/go/internal/work/init.go#L76
163_LINK_C_ARCHIVE_PLATFORMS = {
164 "darwin/arm64": None,
165 "ios/arm64": None,
166}
167
168_LINK_C_ARCHIVE_GOOS = {
169 "dragonfly": None,
170 "freebsd": None,
171 "linux": None,
172 "netbsd": None,
173 "openbsd": None,
174 "solaris": None,
175}
176
177_LINK_C_SHARED_GOOS = [
178 "android",
179 "freebsd",
180 "linux",
181]
182
183_LINK_PLUGIN_PLATFORMS = {
184 "linux/amd64": None,
185 "linux/arm": None,
186 "linux/arm64": None,
187 "linux/386": None,
188 "linux/s390x": None,
189 "linux/ppc64le": None,
190 "android/amd64": None,
191 "android/arm": None,
192 "android/arm64": None,
193 "android/386": None,
194 "darwin/amd64": None,
195 "darwin/arm64": None,
196 "ios/arm": None,
197 "ios/arm64": None,
198}
199
200_LINK_PIE_PLATFORMS = {
201 "linux/amd64": None,
202 "linux/arm": None,
203 "linux/arm64": None,
204 "linux/386": None,
205 "linux/s390x": None,
206 "linux/ppc64le": None,
207 "android/amd64": None,
208 "android/arm": None,
209 "android/arm64": None,
210 "android/386": None,
211 "freebsd/amd64": None,
212}
213
214def link_mode_args(mode):
215 # based on buildModeInit in cmd/go/internal/work/init.go
216 platform = mode.goos + "/" + mode.goarch
217 args = []
218 if mode.link == LINKMODE_C_ARCHIVE:
219 if (platform in _LINK_C_ARCHIVE_PLATFORMS or
220 mode.goos in _LINK_C_ARCHIVE_GOOS and platform != "linux/ppc64"):
221 args.append("-shared")
222 elif mode.link == LINKMODE_C_SHARED:
223 if mode.goos in _LINK_C_SHARED_GOOS:
224 args.append("-shared")
225 elif mode.link == LINKMODE_PLUGIN:
226 if platform in _LINK_PLUGIN_PLATFORMS:
227 args.append("-dynlink")
228 elif mode.link == LINKMODE_PIE:
229 if platform in _LINK_PIE_PLATFORMS:
230 args.append("-shared")
231 return args
232
233def extldflags_from_cc_toolchain(go):
234 if not go.cgo_tools:
235 return []
236 elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED):
237 return go.cgo_tools.ld_dynamic_lib_options
238 else:
239 # NOTE: in c-archive mode, -extldflags are ignored by the linker.
240 # However, we still need to set them for cgo, which links a binary
241 # in each package. We use the executable options for this.
242 return go.cgo_tools.ld_executable_options
243
244def extld_from_cc_toolchain(go):
245 if not go.cgo_tools:
246 return []
247 elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED, LINKMODE_PIE):
248 return ["-extld", go.cgo_tools.ld_dynamic_lib_path]
249 elif go.mode.link == LINKMODE_C_ARCHIVE:
250 if go.mode.goos in ["darwin", "ios"]:
251 # TODO(jayconrod): on macOS, set -extar. At this time, wrapped_ar is
252 # a bash script without a shebang line, so we can't execute it. We
253 # use /usr/bin/ar (the default) instead.
254 return []
255 else:
256 return ["-extar", go.cgo_tools.ld_static_lib_path]
257 else:
258 # NOTE: In c-archive mode, we should probably set -extar. However,
259 # on macOS, Bazel returns wrapped_ar, which is not executable.
260 # /usr/bin/ar (the default) should be visible though, and we have a
261 # hack in link.go to strip out non-reproducible stuff.
262 return ["-extld", go.cgo_tools.ld_executable_path]
View as plain text