xref: /aosp_15_r20/external/bazelbuild-rules_go/go/private/mode.bzl (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
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    pure = _ternary(
82        "on" if not cgo_context_info else "auto",
83        go_config_info.pure if go_config_info else "off",
84    )
85    race = _ternary(go_config_info.race if go_config_info else "off")
86    msan = _ternary(go_config_info.msan if go_config_info else "off")
87    strip = go_config_info.strip if go_config_info else False
88    stamp = go_config_info.stamp if go_config_info else False
89    debug = go_config_info.debug if go_config_info else False
90    linkmode = go_config_info.linkmode if go_config_info else LINKMODE_NORMAL
91    cover_format = go_config_info and go_config_info.cover_format
92    amd64 = go_config_info.amd64 if go_config_info else None
93    goos = go_toolchain.default_goos if getattr(ctx.attr, "goos", "auto") == "auto" else ctx.attr.goos
94    goarch = go_toolchain.default_goarch if getattr(ctx.attr, "goarch", "auto") == "auto" else ctx.attr.goarch
95    gc_goopts = go_config_info.gc_goopts if go_config_info else []
96
97    # TODO(jayconrod): check for more invalid and contradictory settings.
98    if pure and race:
99        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.")
100    if pure and msan:
101        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.")
102    if pure and linkmode in LINKMODES_REQUIRING_EXTERNAL_LINKING:
103        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 " +
104              "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))
105
106    gc_linkopts = list(go_config_info.gc_linkopts) if go_config_info else []
107    tags = list(go_config_info.tags) if go_config_info else []
108    if "gotags" in ctx.var:
109        tags.extend(ctx.var["gotags"].split(","))
110    if cgo_context_info:
111        tags.extend(cgo_context_info.tags)
112    if race:
113        tags.append("race")
114    if msan:
115        tags.append("msan")
116
117    return struct(
118        static = static,
119        race = race,
120        msan = msan,
121        pure = pure,
122        link = linkmode,
123        gc_linkopts = gc_linkopts,
124        strip = strip,
125        stamp = stamp,
126        debug = debug,
127        goos = goos,
128        goarch = goarch,
129        tags = tags,
130        cover_format = cover_format,
131        amd64 = amd64,
132        gc_goopts = gc_goopts,
133    )
134
135def installsuffix(mode):
136    s = mode.goos + "_" + mode.goarch
137    if mode.race:
138        s += "_race"
139    elif mode.msan:
140        s += "_msan"
141    return s
142
143def mode_tags_equivalent(l, r):
144    # Returns whether two modes are equivalent for Go build tags. For example,
145    # goos and goarch must match, but static doesn't matter.
146    return (l.goos == r.goos and
147            l.goarch == r.goarch and
148            l.race == r.race and
149            l.msan == r.msan)
150
151# Ported from https://github.com/golang/go/blob/master/src/cmd/go/internal/work/init.go#L76
152_LINK_C_ARCHIVE_PLATFORMS = {
153    "darwin/arm64": None,
154    "ios/arm64": None,
155}
156
157_LINK_C_ARCHIVE_GOOS = {
158    "dragonfly": None,
159    "freebsd": None,
160    "linux": None,
161    "netbsd": None,
162    "openbsd": None,
163    "solaris": None,
164}
165
166_LINK_C_SHARED_GOOS = [
167    "android",
168    "freebsd",
169    "linux",
170]
171
172_LINK_PLUGIN_PLATFORMS = {
173    "linux/amd64": None,
174    "linux/arm": None,
175    "linux/arm64": None,
176    "linux/386": None,
177    "linux/s390x": None,
178    "linux/ppc64le": None,
179    "android/amd64": None,
180    "android/arm": None,
181    "android/arm64": None,
182    "android/386": None,
183    "darwin/amd64": None,
184    "darwin/arm64": None,
185    "ios/arm": None,
186    "ios/arm64": None,
187}
188
189_LINK_PIE_PLATFORMS = {
190    "linux/amd64": None,
191    "linux/arm": None,
192    "linux/arm64": None,
193    "linux/386": None,
194    "linux/s390x": None,
195    "linux/ppc64le": None,
196    "android/amd64": None,
197    "android/arm": None,
198    "android/arm64": None,
199    "android/386": None,
200    "freebsd/amd64": None,
201}
202
203def link_mode_args(mode):
204    # based on buildModeInit in cmd/go/internal/work/init.go
205    platform = mode.goos + "/" + mode.goarch
206    args = []
207    if mode.link == LINKMODE_C_ARCHIVE:
208        if (platform in _LINK_C_ARCHIVE_PLATFORMS or
209            mode.goos in _LINK_C_ARCHIVE_GOOS and platform != "linux/ppc64"):
210            args.append("-shared")
211    elif mode.link == LINKMODE_C_SHARED:
212        if mode.goos in _LINK_C_SHARED_GOOS:
213            args.append("-shared")
214    elif mode.link == LINKMODE_PLUGIN:
215        if platform in _LINK_PLUGIN_PLATFORMS:
216            args.append("-dynlink")
217    elif mode.link == LINKMODE_PIE:
218        if platform in _LINK_PIE_PLATFORMS:
219            args.append("-shared")
220    return args
221
222def extldflags_from_cc_toolchain(go):
223    if not go.cgo_tools:
224        return []
225    elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED):
226        return go.cgo_tools.ld_dynamic_lib_options
227    else:
228        # NOTE: in c-archive mode, -extldflags are ignored by the linker.
229        # However, we still need to set them for cgo, which links a binary
230        # in each package. We use the executable options for this.
231        return go.cgo_tools.ld_executable_options
232
233def extld_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, LINKMODE_PIE):
237        return ["-extld", go.cgo_tools.ld_dynamic_lib_path]
238    elif go.mode.link == LINKMODE_C_ARCHIVE:
239        if go.mode.goos in ["darwin", "ios"]:
240            # TODO(jayconrod): on macOS, set -extar. At this time, wrapped_ar is
241            # a bash script without a shebang line, so we can't execute it. We
242            # use /usr/bin/ar (the default) instead.
243            return []
244        else:
245            return ["-extar", go.cgo_tools.ld_static_lib_path]
246    else:
247        # NOTE: In c-archive mode, we should probably set -extar. However,
248        # on macOS, Bazel returns wrapped_ar, which is not executable.
249        # /usr/bin/ar (the default) should be visible though, and we have a
250        # hack in link.go to strip out non-reproducible stuff.
251        return ["-extld", go.cgo_tools.ld_executable_path]
252