1*9bb1b549SSpandan Das# Copyright 2017 The Bazel Authors. All rights reserved. 2*9bb1b549SSpandan Das# 3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License"); 4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License. 5*9bb1b549SSpandan Das# You may obtain a copy of the License at 6*9bb1b549SSpandan Das# 7*9bb1b549SSpandan Das# http://www.apache.org/licenses/LICENSE-2.0 8*9bb1b549SSpandan Das# 9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software 10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS, 11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and 13*9bb1b549SSpandan Das# limitations under the License. 14*9bb1b549SSpandan Das 15*9bb1b549SSpandan Das# Modes are documented in go/modes.rst#compilation-modes 16*9bb1b549SSpandan Das 17*9bb1b549SSpandan DasLINKMODE_NORMAL = "normal" 18*9bb1b549SSpandan Das 19*9bb1b549SSpandan DasLINKMODE_SHARED = "shared" 20*9bb1b549SSpandan Das 21*9bb1b549SSpandan DasLINKMODE_PIE = "pie" 22*9bb1b549SSpandan Das 23*9bb1b549SSpandan DasLINKMODE_PLUGIN = "plugin" 24*9bb1b549SSpandan Das 25*9bb1b549SSpandan DasLINKMODE_C_SHARED = "c-shared" 26*9bb1b549SSpandan Das 27*9bb1b549SSpandan DasLINKMODE_C_ARCHIVE = "c-archive" 28*9bb1b549SSpandan Das 29*9bb1b549SSpandan DasLINKMODES = [LINKMODE_NORMAL, LINKMODE_PLUGIN, LINKMODE_C_SHARED, LINKMODE_C_ARCHIVE, LINKMODE_PIE] 30*9bb1b549SSpandan Das 31*9bb1b549SSpandan Das# All link modes that produce executables to be run with bazel run. 32*9bb1b549SSpandan DasLINKMODES_EXECUTABLE = [LINKMODE_NORMAL, LINKMODE_PIE] 33*9bb1b549SSpandan Das 34*9bb1b549SSpandan Das# All link modes that require external linking and thus a cgo context. 35*9bb1b549SSpandan DasLINKMODES_REQUIRING_EXTERNAL_LINKING = [ 36*9bb1b549SSpandan Das LINKMODE_PLUGIN, 37*9bb1b549SSpandan Das LINKMODE_C_ARCHIVE, 38*9bb1b549SSpandan Das LINKMODE_C_SHARED, 39*9bb1b549SSpandan Das] 40*9bb1b549SSpandan Das 41*9bb1b549SSpandan Dasdef mode_string(mode): 42*9bb1b549SSpandan Das result = [mode.goos, mode.goarch] 43*9bb1b549SSpandan Das if mode.static: 44*9bb1b549SSpandan Das result.append("static") 45*9bb1b549SSpandan Das if mode.race: 46*9bb1b549SSpandan Das result.append("race") 47*9bb1b549SSpandan Das if mode.msan: 48*9bb1b549SSpandan Das result.append("msan") 49*9bb1b549SSpandan Das if mode.pure: 50*9bb1b549SSpandan Das result.append("pure") 51*9bb1b549SSpandan Das if mode.debug: 52*9bb1b549SSpandan Das result.append("debug") 53*9bb1b549SSpandan Das if mode.strip: 54*9bb1b549SSpandan Das result.append("stripped") 55*9bb1b549SSpandan Das if not result or not mode.link == LINKMODE_NORMAL: 56*9bb1b549SSpandan Das result.append(mode.link) 57*9bb1b549SSpandan Das if mode.gc_goopts: 58*9bb1b549SSpandan Das result.extend(mode.gc_goopts) 59*9bb1b549SSpandan Das return "_".join(result) 60*9bb1b549SSpandan Das 61*9bb1b549SSpandan Dasdef _ternary(*values): 62*9bb1b549SSpandan Das for v in values: 63*9bb1b549SSpandan Das if v == None: 64*9bb1b549SSpandan Das continue 65*9bb1b549SSpandan Das if type(v) == "bool": 66*9bb1b549SSpandan Das return v 67*9bb1b549SSpandan Das if type(v) != "string": 68*9bb1b549SSpandan Das fail("Invalid value type {}".format(type(v))) 69*9bb1b549SSpandan Das v = v.lower() 70*9bb1b549SSpandan Das if v == "on": 71*9bb1b549SSpandan Das return True 72*9bb1b549SSpandan Das if v == "off": 73*9bb1b549SSpandan Das return False 74*9bb1b549SSpandan Das if v == "auto": 75*9bb1b549SSpandan Das continue 76*9bb1b549SSpandan Das fail("Invalid value {}".format(v)) 77*9bb1b549SSpandan Das fail("_ternary failed to produce a final result from {}".format(values)) 78*9bb1b549SSpandan Das 79*9bb1b549SSpandan Dasdef get_mode(ctx, go_toolchain, cgo_context_info, go_config_info): 80*9bb1b549SSpandan Das static = _ternary(go_config_info.static if go_config_info else "off") 81*9bb1b549SSpandan Das pure = _ternary( 82*9bb1b549SSpandan Das "on" if not cgo_context_info else "auto", 83*9bb1b549SSpandan Das go_config_info.pure if go_config_info else "off", 84*9bb1b549SSpandan Das ) 85*9bb1b549SSpandan Das race = _ternary(go_config_info.race if go_config_info else "off") 86*9bb1b549SSpandan Das msan = _ternary(go_config_info.msan if go_config_info else "off") 87*9bb1b549SSpandan Das strip = go_config_info.strip if go_config_info else False 88*9bb1b549SSpandan Das stamp = go_config_info.stamp if go_config_info else False 89*9bb1b549SSpandan Das debug = go_config_info.debug if go_config_info else False 90*9bb1b549SSpandan Das linkmode = go_config_info.linkmode if go_config_info else LINKMODE_NORMAL 91*9bb1b549SSpandan Das cover_format = go_config_info and go_config_info.cover_format 92*9bb1b549SSpandan Das amd64 = go_config_info.amd64 if go_config_info else None 93*9bb1b549SSpandan Das goos = go_toolchain.default_goos if getattr(ctx.attr, "goos", "auto") == "auto" else ctx.attr.goos 94*9bb1b549SSpandan Das goarch = go_toolchain.default_goarch if getattr(ctx.attr, "goarch", "auto") == "auto" else ctx.attr.goarch 95*9bb1b549SSpandan Das gc_goopts = go_config_info.gc_goopts if go_config_info else [] 96*9bb1b549SSpandan Das 97*9bb1b549SSpandan Das # TODO(jayconrod): check for more invalid and contradictory settings. 98*9bb1b549SSpandan Das if pure and race: 99*9bb1b549SSpandan Das 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*9bb1b549SSpandan Das if pure and msan: 101*9bb1b549SSpandan Das 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*9bb1b549SSpandan Das if pure and linkmode in LINKMODES_REQUIRING_EXTERNAL_LINKING: 103*9bb1b549SSpandan Das 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*9bb1b549SSpandan Das "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*9bb1b549SSpandan Das 106*9bb1b549SSpandan Das gc_linkopts = list(go_config_info.gc_linkopts) if go_config_info else [] 107*9bb1b549SSpandan Das tags = list(go_config_info.tags) if go_config_info else [] 108*9bb1b549SSpandan Das if "gotags" in ctx.var: 109*9bb1b549SSpandan Das tags.extend(ctx.var["gotags"].split(",")) 110*9bb1b549SSpandan Das if cgo_context_info: 111*9bb1b549SSpandan Das tags.extend(cgo_context_info.tags) 112*9bb1b549SSpandan Das if race: 113*9bb1b549SSpandan Das tags.append("race") 114*9bb1b549SSpandan Das if msan: 115*9bb1b549SSpandan Das tags.append("msan") 116*9bb1b549SSpandan Das 117*9bb1b549SSpandan Das return struct( 118*9bb1b549SSpandan Das static = static, 119*9bb1b549SSpandan Das race = race, 120*9bb1b549SSpandan Das msan = msan, 121*9bb1b549SSpandan Das pure = pure, 122*9bb1b549SSpandan Das link = linkmode, 123*9bb1b549SSpandan Das gc_linkopts = gc_linkopts, 124*9bb1b549SSpandan Das strip = strip, 125*9bb1b549SSpandan Das stamp = stamp, 126*9bb1b549SSpandan Das debug = debug, 127*9bb1b549SSpandan Das goos = goos, 128*9bb1b549SSpandan Das goarch = goarch, 129*9bb1b549SSpandan Das tags = tags, 130*9bb1b549SSpandan Das cover_format = cover_format, 131*9bb1b549SSpandan Das amd64 = amd64, 132*9bb1b549SSpandan Das gc_goopts = gc_goopts, 133*9bb1b549SSpandan Das ) 134*9bb1b549SSpandan Das 135*9bb1b549SSpandan Dasdef installsuffix(mode): 136*9bb1b549SSpandan Das s = mode.goos + "_" + mode.goarch 137*9bb1b549SSpandan Das if mode.race: 138*9bb1b549SSpandan Das s += "_race" 139*9bb1b549SSpandan Das elif mode.msan: 140*9bb1b549SSpandan Das s += "_msan" 141*9bb1b549SSpandan Das return s 142*9bb1b549SSpandan Das 143*9bb1b549SSpandan Dasdef mode_tags_equivalent(l, r): 144*9bb1b549SSpandan Das # Returns whether two modes are equivalent for Go build tags. For example, 145*9bb1b549SSpandan Das # goos and goarch must match, but static doesn't matter. 146*9bb1b549SSpandan Das return (l.goos == r.goos and 147*9bb1b549SSpandan Das l.goarch == r.goarch and 148*9bb1b549SSpandan Das l.race == r.race and 149*9bb1b549SSpandan Das l.msan == r.msan) 150*9bb1b549SSpandan Das 151*9bb1b549SSpandan Das# Ported from https://github.com/golang/go/blob/master/src/cmd/go/internal/work/init.go#L76 152*9bb1b549SSpandan Das_LINK_C_ARCHIVE_PLATFORMS = { 153*9bb1b549SSpandan Das "darwin/arm64": None, 154*9bb1b549SSpandan Das "ios/arm64": None, 155*9bb1b549SSpandan Das} 156*9bb1b549SSpandan Das 157*9bb1b549SSpandan Das_LINK_C_ARCHIVE_GOOS = { 158*9bb1b549SSpandan Das "dragonfly": None, 159*9bb1b549SSpandan Das "freebsd": None, 160*9bb1b549SSpandan Das "linux": None, 161*9bb1b549SSpandan Das "netbsd": None, 162*9bb1b549SSpandan Das "openbsd": None, 163*9bb1b549SSpandan Das "solaris": None, 164*9bb1b549SSpandan Das} 165*9bb1b549SSpandan Das 166*9bb1b549SSpandan Das_LINK_C_SHARED_GOOS = [ 167*9bb1b549SSpandan Das "android", 168*9bb1b549SSpandan Das "freebsd", 169*9bb1b549SSpandan Das "linux", 170*9bb1b549SSpandan Das] 171*9bb1b549SSpandan Das 172*9bb1b549SSpandan Das_LINK_PLUGIN_PLATFORMS = { 173*9bb1b549SSpandan Das "linux/amd64": None, 174*9bb1b549SSpandan Das "linux/arm": None, 175*9bb1b549SSpandan Das "linux/arm64": None, 176*9bb1b549SSpandan Das "linux/386": None, 177*9bb1b549SSpandan Das "linux/s390x": None, 178*9bb1b549SSpandan Das "linux/ppc64le": None, 179*9bb1b549SSpandan Das "android/amd64": None, 180*9bb1b549SSpandan Das "android/arm": None, 181*9bb1b549SSpandan Das "android/arm64": None, 182*9bb1b549SSpandan Das "android/386": None, 183*9bb1b549SSpandan Das "darwin/amd64": None, 184*9bb1b549SSpandan Das "darwin/arm64": None, 185*9bb1b549SSpandan Das "ios/arm": None, 186*9bb1b549SSpandan Das "ios/arm64": None, 187*9bb1b549SSpandan Das} 188*9bb1b549SSpandan Das 189*9bb1b549SSpandan Das_LINK_PIE_PLATFORMS = { 190*9bb1b549SSpandan Das "linux/amd64": None, 191*9bb1b549SSpandan Das "linux/arm": None, 192*9bb1b549SSpandan Das "linux/arm64": None, 193*9bb1b549SSpandan Das "linux/386": None, 194*9bb1b549SSpandan Das "linux/s390x": None, 195*9bb1b549SSpandan Das "linux/ppc64le": None, 196*9bb1b549SSpandan Das "android/amd64": None, 197*9bb1b549SSpandan Das "android/arm": None, 198*9bb1b549SSpandan Das "android/arm64": None, 199*9bb1b549SSpandan Das "android/386": None, 200*9bb1b549SSpandan Das "freebsd/amd64": None, 201*9bb1b549SSpandan Das} 202*9bb1b549SSpandan Das 203*9bb1b549SSpandan Dasdef link_mode_args(mode): 204*9bb1b549SSpandan Das # based on buildModeInit in cmd/go/internal/work/init.go 205*9bb1b549SSpandan Das platform = mode.goos + "/" + mode.goarch 206*9bb1b549SSpandan Das args = [] 207*9bb1b549SSpandan Das if mode.link == LINKMODE_C_ARCHIVE: 208*9bb1b549SSpandan Das if (platform in _LINK_C_ARCHIVE_PLATFORMS or 209*9bb1b549SSpandan Das mode.goos in _LINK_C_ARCHIVE_GOOS and platform != "linux/ppc64"): 210*9bb1b549SSpandan Das args.append("-shared") 211*9bb1b549SSpandan Das elif mode.link == LINKMODE_C_SHARED: 212*9bb1b549SSpandan Das if mode.goos in _LINK_C_SHARED_GOOS: 213*9bb1b549SSpandan Das args.append("-shared") 214*9bb1b549SSpandan Das elif mode.link == LINKMODE_PLUGIN: 215*9bb1b549SSpandan Das if platform in _LINK_PLUGIN_PLATFORMS: 216*9bb1b549SSpandan Das args.append("-dynlink") 217*9bb1b549SSpandan Das elif mode.link == LINKMODE_PIE: 218*9bb1b549SSpandan Das if platform in _LINK_PIE_PLATFORMS: 219*9bb1b549SSpandan Das args.append("-shared") 220*9bb1b549SSpandan Das return args 221*9bb1b549SSpandan Das 222*9bb1b549SSpandan Dasdef extldflags_from_cc_toolchain(go): 223*9bb1b549SSpandan Das if not go.cgo_tools: 224*9bb1b549SSpandan Das return [] 225*9bb1b549SSpandan Das elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED): 226*9bb1b549SSpandan Das return go.cgo_tools.ld_dynamic_lib_options 227*9bb1b549SSpandan Das else: 228*9bb1b549SSpandan Das # NOTE: in c-archive mode, -extldflags are ignored by the linker. 229*9bb1b549SSpandan Das # However, we still need to set them for cgo, which links a binary 230*9bb1b549SSpandan Das # in each package. We use the executable options for this. 231*9bb1b549SSpandan Das return go.cgo_tools.ld_executable_options 232*9bb1b549SSpandan Das 233*9bb1b549SSpandan Dasdef extld_from_cc_toolchain(go): 234*9bb1b549SSpandan Das if not go.cgo_tools: 235*9bb1b549SSpandan Das return [] 236*9bb1b549SSpandan Das elif go.mode.link in (LINKMODE_SHARED, LINKMODE_PLUGIN, LINKMODE_C_SHARED, LINKMODE_PIE): 237*9bb1b549SSpandan Das return ["-extld", go.cgo_tools.ld_dynamic_lib_path] 238*9bb1b549SSpandan Das elif go.mode.link == LINKMODE_C_ARCHIVE: 239*9bb1b549SSpandan Das if go.mode.goos in ["darwin", "ios"]: 240*9bb1b549SSpandan Das # TODO(jayconrod): on macOS, set -extar. At this time, wrapped_ar is 241*9bb1b549SSpandan Das # a bash script without a shebang line, so we can't execute it. We 242*9bb1b549SSpandan Das # use /usr/bin/ar (the default) instead. 243*9bb1b549SSpandan Das return [] 244*9bb1b549SSpandan Das else: 245*9bb1b549SSpandan Das return ["-extar", go.cgo_tools.ld_static_lib_path] 246*9bb1b549SSpandan Das else: 247*9bb1b549SSpandan Das # NOTE: In c-archive mode, we should probably set -extar. However, 248*9bb1b549SSpandan Das # on macOS, Bazel returns wrapped_ar, which is not executable. 249*9bb1b549SSpandan Das # /usr/bin/ar (the default) should be visible though, and we have a 250*9bb1b549SSpandan Das # hack in link.go to strip out non-reproducible stuff. 251*9bb1b549SSpandan Das return ["-extld", go.cgo_tools.ld_executable_path] 252