blob: 19c240a78c00a0956dc7c273a958dbaf706c0600 [file] [log] [blame]
# 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]
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)
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
# 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.")
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,
strip = strip,
stamp = stamp,
debug = debug,
goos = goos,
goarch = goarch,
tags = tags,
cover_format = cover_format,
amd64 = amd64,
)
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]