aboutsummaryrefslogtreecommitdiff
path: root/go/private/mode.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'go/private/mode.bzl')
-rw-r--r--go/private/mode.bzl251
1 files changed, 251 insertions, 0 deletions
diff --git a/go/private/mode.bzl b/go/private/mode.bzl
new file mode 100644
index 00000000..83ccd045
--- /dev/null
+++ b/go/private/mode.bzl
@@ -0,0 +1,251 @@
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Modes are documented in go/modes.rst#compilation-modes
+
+LINKMODE_NORMAL = "normal"
+
+LINKMODE_SHARED = "shared"
+
+LINKMODE_PIE = "pie"
+
+LINKMODE_PLUGIN = "plugin"
+
+LINKMODE_C_SHARED = "c-shared"
+
+LINKMODE_C_ARCHIVE = "c-archive"
+
+LINKMODES = [LINKMODE_NORMAL, LINKMODE_PLUGIN, LINKMODE_C_SHARED, LINKMODE_C_ARCHIVE, LINKMODE_PIE]
+
+# All link modes that produce executables to be run with bazel run.
+LINKMODES_EXECUTABLE = [LINKMODE_NORMAL, LINKMODE_PIE]
+
+# All link modes that require external linking and thus a cgo context.
+LINKMODES_REQUIRING_EXTERNAL_LINKING = [
+ LINKMODE_PLUGIN,
+ LINKMODE_C_ARCHIVE,
+ LINKMODE_C_SHARED,
+]
+
+def mode_string(mode):
+ result = [mode.goos, mode.goarch]
+ if mode.static:
+ result.append("static")
+ if mode.race:
+ result.append("race")
+ if mode.msan:
+ result.append("msan")
+ if mode.pure:
+ result.append("pure")
+ if mode.debug:
+ result.append("debug")
+ if mode.strip:
+ result.append("stripped")
+ if not result or not mode.link == LINKMODE_NORMAL:
+ result.append(mode.link)
+ if mode.gc_goopts:
+ result.extend(mode.gc_goopts)
+ return "_".join(result)
+
+def _ternary(*values):
+ for v in values:
+ if v == None:
+ continue
+ if type(v) == "bool":
+ return v
+ if type(v) != "string":
+ fail("Invalid value type {}".format(type(v)))
+ v = v.lower()
+ if v == "on":
+ return True
+ if v == "off":
+ return False
+ if v == "auto":
+ continue
+ fail("Invalid value {}".format(v))
+ fail("_ternary failed to produce a final result from {}".format(values))
+
+def get_mode(ctx, go_toolchain, cgo_context_info, go_config_info):
+ static = _ternary(go_config_info.static if go_config_info else "off")
+ pure = _ternary(
+ "on" if not cgo_context_info else "auto",
+ go_config_info.pure if go_config_info else "off",
+ )
+ race = _ternary(go_config_info.race if go_config_info else "off")
+ msan = _ternary(go_config_info.msan if go_config_info else "off")
+ strip = go_config_info.strip if go_config_info else False
+ stamp = go_config_info.stamp if go_config_info else False
+ debug = go_config_info.debug if go_config_info else False
+ linkmode = go_config_info.linkmode if go_config_info else LINKMODE_NORMAL
+ cover_format = go_config_info and go_config_info.cover_format
+ amd64 = go_config_info.amd64 if go_config_info else None
+ goos = go_toolchain.default_goos if getattr(ctx.attr, "goos", "auto") == "auto" else ctx.attr.goos
+ goarch = go_toolchain.default_goarch if getattr(ctx.attr, "goarch", "auto") == "auto" else ctx.attr.goarch
+ gc_goopts = go_config_info.gc_goopts if go_config_info else []
+
+ # TODO(jayconrod): check for more invalid and contradictory settings.
+ if pure and race:
+ 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.")
+ if pure and msan:
+ 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.")
+ if pure and linkmode in LINKMODES_REQUIRING_EXTERNAL_LINKING:
+ 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 " +
+ "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))
+
+ gc_linkopts = list(go_config_info.gc_linkopts) if go_config_info else []
+ tags = list(go_config_info.tags) if go_config_info else []
+ if "gotags" in ctx.var:
+ tags.extend(ctx.var["gotags"].split(","))
+ if cgo_context_info:
+ tags.extend(cgo_context_info.tags)
+ if race:
+ tags.append("race")
+ if msan:
+ tags.append("msan")
+
+ return struct(
+ static = static,
+ race = race,
+ msan = msan,
+ pure = pure,
+ link = linkmode,
+ gc_linkopts = gc_linkopts,
+ strip = strip,
+ stamp = stamp,
+ debug = debug,
+ goos = goos,
+ goarch = goarch,
+ tags = tags,
+ cover_format = cover_format,
+ amd64 = amd64,
+ gc_goopts = gc_goopts,
+ )
+
+def installsuffix(mode):
+ s = mode.goos + "_" + mode.goarch
+ if mode.race:
+ s += "_race"
+ elif mode.msan:
+ s += "_msan"
+ return s
+
+def mode_tags_equivalent(l, r):
+ # Returns whether two modes are equivalent for Go build tags. For example,
+ # goos and goarch must match, but static doesn't matter.
+ return (l.goos == r.goos and
+ l.goarch == r.goarch and
+ l.race == r.race and
+ l.msan == r.msan)
+
+# Ported from https://github.com/golang/go/blob/master/src/cmd/go/internal/work/init.go#L76
+_LINK_C_ARCHIVE_PLATFORMS = {
+ "darwin/arm64": None,
+ "ios/arm64": None,
+}
+
+_LINK_C_ARCHIVE_GOOS = {
+ "dragonfly": None,
+ "freebsd": None,
+ "linux": None,
+ "netbsd": None,
+ "openbsd": None,
+ "solaris": None,
+}
+
+_LINK_C_SHARED_GOOS = [
+ "android",
+ "freebsd",
+ "linux",
+]
+
+_LINK_PLUGIN_PLATFORMS = {
+ "linux/amd64": None,
+ "linux/arm": None,
+ "linux/arm64": None,
+ "linux/386": None,
+ "linux/s390x": None,
+ "linux/ppc64le": None,
+ "android/amd64": None,
+ "android/arm": None,
+ "android/arm64": None,
+ "android/386": None,
+ "darwin/amd64": None,
+ "darwin/arm64": None,
+ "ios/arm": None,
+ "ios/arm64": None,
+}
+
+_LINK_PIE_PLATFORMS = {
+ "linux/amd64": None,
+ "linux/arm": None,
+ "linux/arm64": None,
+ "linux/386": None,
+ "linux/s390x": None,
+ "linux/ppc64le": None,
+ "android/amd64": None,
+ "android/arm": None,
+ "android/arm64": None,
+ "android/386": None,
+ "freebsd/amd64": None,
+}
+
+def link_mode_args(mode):
+ # based on buildModeInit in cmd/go/internal/work/init.go
+ platform = mode.goos + "/" + mode.goarch
+ args = []
+ if mode.link == LINKMODE_C_ARCHIVE:
+ if (platform in _LINK_C_ARCHIVE_PLATFORMS or
+ mode.goos in _LINK_C_ARCHIVE_GOOS and platform != "linux/ppc64"):
+ args.append("-shared")
+ elif mode.link == LINKMODE_C_SHARED:
+ if mode.goos in _LINK_C_SHARED_GOOS:
+ args.append("-shared")
+ elif mode.link == LINKMODE_PLUGIN:
+ if platform in _LINK_PLUGIN_PLATFORMS:
+ args.append("-dynlink")
+ elif mode.link == LINKMODE_PIE:
+ if platform in _LINK_PIE_PLATFORMS:
+ args.append("-shared")
+ return args
+
+def extldflags_from_cc_toolchain(go):
+ if not go.cgo_tools:
+ return []
+ elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED):
+ return go.cgo_tools.ld_dynamic_lib_options
+ else:
+ # NOTE: in c-archive mode, -extldflags are ignored by the linker.
+ # However, we still need to set them for cgo, which links a binary
+ # in each package. We use the executable options for this.
+ return go.cgo_tools.ld_executable_options
+
+def extld_from_cc_toolchain(go):
+ if not go.cgo_tools:
+ return []
+ elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED, LINKMODE_PIE):
+ return ["-extld", go.cgo_tools.ld_dynamic_lib_path]
+ elif go.mode.link == LINKMODE_C_ARCHIVE:
+ if go.mode.goos in ["darwin", "ios"]:
+ # TODO(jayconrod): on macOS, set -extar. At this time, wrapped_ar is
+ # a bash script without a shebang line, so we can't execute it. We
+ # use /usr/bin/ar (the default) instead.
+ return []
+ else:
+ return ["-extar", go.cgo_tools.ld_static_lib_path]
+ else:
+ # NOTE: In c-archive mode, we should probably set -extar. However,
+ # on macOS, Bazel returns wrapped_ar, which is not executable.
+ # /usr/bin/ar (the default) should be visible though, and we have a
+ # hack in link.go to strip out non-reproducible stuff.
+ return ["-extld", go.cgo_tools.ld_executable_path]