// mustLinkExternal is a copy of internal/platform.MustLinkExternal,
// duplicated here to avoid version skew in the MustLinkExternal function
// during bootstrapping.
-func mustLinkExternal(goos, goarch string) bool {
+func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
+ if cgoEnabled {
+ switch goarch {
+ case "loong64",
+ "mips", "mipsle", "mips64", "mips64le",
+ "riscv64":
+ // Internally linking cgo is incomplete on some architectures.
+ // https://golang.org/issue/14449
+ return true
+ case "arm64":
+ if goos == "windows" {
+ // windows/arm64 internal linking is not implemented.
+ return true
+ }
+ case "ppc64":
+ // Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
+ return true
+ }
+
+ switch goos {
+ case "android":
+ return true
+ case "dragonfly":
+ // It seems that on Dragonfly thread local storage is
+ // set up by the dynamic linker, so internal cgo linking
+ // doesn't work. Test case is "go test runtime/cgo".
+ return true
+ }
+ }
+
switch goos {
case "android":
if goarch != "arm64" {
// to switch between the host and target configurations when cross-compiling.
func toolenv() []string {
var env []string
- if !mustLinkExternal(goos, goarch) {
+ if !mustLinkExternal(goos, goarch, false) {
// Unless the platform requires external linking,
// we disable cgo to get static binaries for cmd/go and cmd/pprof,
// so that they work on systems without the same dynamic libraries
func TestMustLinkExternal(t *testing.T) {
for _, goos := range okgoos {
for _, goarch := range okgoarch {
- got := mustLinkExternal(goos, goarch)
- want := platform.MustLinkExternal(goos, goarch)
- if got != want {
- t.Errorf("mustLinkExternal(%q, %q) = %v; want %v", goos, goarch, got, want)
+ for _, cgoEnabled := range []bool{true, false} {
+ got := mustLinkExternal(goos, goarch, cgoEnabled)
+ want := platform.MustLinkExternal(goos, goarch, cgoEnabled)
+ if got != want {
+ t.Errorf("mustLinkExternal(%q, %q, %v) = %v; want %v", goos, goarch, cgoEnabled, got, want)
+ }
}
}
}
// linker's build id, which will cause our build id to not
// match the next time the tool is built.
// Rely on the external build id instead.
- if !platform.MustLinkExternal(cfg.Goos, cfg.Goarch) {
+ if !platform.MustLinkExternal(cfg.Goos, cfg.Goarch, false) {
ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID)
}
}
package ld
import (
- "cmd/internal/sys"
"fmt"
"internal/buildcfg"
"internal/platform"
}()
}
- if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH) {
+ if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH, false) {
return true, fmt.Sprintf("%s/%s requires external linking", buildcfg.GOOS, buildcfg.GOARCH)
}
return true, "asan"
}
- // Internally linking cgo is incomplete on some architectures.
- // https://golang.org/issue/14449
- if iscgo && ctxt.Arch.InFamily(sys.Loong64, sys.MIPS64, sys.MIPS, sys.RISCV64) {
+ if iscgo && platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH, true) {
return true, buildcfg.GOARCH + " does not support internal cgo"
}
- if iscgo && (buildcfg.GOOS == "android" || buildcfg.GOOS == "dragonfly") {
- // It seems that on Dragonfly thread local storage is
- // set up by the dynamic linker, so internal cgo linking
- // doesn't work. Test case is "go test runtime/cgo".
- return true, buildcfg.GOOS + " does not support internal cgo"
- }
- if iscgo && buildcfg.GOOS == "windows" && buildcfg.GOARCH == "arm64" {
- // windows/arm64 internal linking is not implemented.
- return true, buildcfg.GOOS + "/" + buildcfg.GOARCH + " does not support internal cgo"
- }
- if iscgo && ctxt.Arch == sys.ArchPPC64 {
- // Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
- return true, buildcfg.GOOS + " does not support internal cgo"
- }
// Some build modes require work the internal linker cannot do (yet).
switch ctxt.BuildMode {
case BuildModeCShared:
return true, "buildmode=c-shared"
case BuildModePIE:
- switch buildcfg.GOOS + "/" + buildcfg.GOARCH {
- case "android/arm64":
- case "linux/amd64", "linux/arm64", "linux/ppc64le":
- case "windows/386", "windows/amd64", "windows/arm", "windows/arm64":
- case "darwin/amd64", "darwin/arm64":
- default:
+ if !platform.InternalLinkPIESupported(buildcfg.GOOS, buildcfg.GOARCH) {
// Internal linking does not support TLS_IE.
return true, "buildmode=pie"
}
}
// External linking may bring in C symbols with unknown size. Skip.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
t.Parallel()
func TestRuntimeTypeAttrInternal(t *testing.T) {
testenv.MustHaveGoBuild(t)
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
// TODO: maybe there is some way to tell the external linker not to put
// those symbols in the executable's symbol table? Prefix the symbol name
// with "." or "L" to pretend it is a label?
- if !testenv.CanInternalLink() {
+ if !testenv.CanInternalLink(false) {
return
}
// When external linking, symbols may be defined externally, so we allow
// undefined symbols and let external linker resolve. Skip the test.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
t.Parallel()
func TestIssue33979(t *testing.T) {
testenv.MustHaveGoBuild(t)
testenv.MustHaveCGO(t)
- testenv.MustInternalLink(t)
-
- // Skip test on platforms that do not support cgo internal linking.
- switch runtime.GOARCH {
- case "loong64":
- t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
- case "mips", "mipsle", "mips64", "mips64le":
- t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
- }
- if runtime.GOOS == "aix" ||
- runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
- t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
- }
+ testenv.MustInternalLink(t, true)
t.Parallel()
// Test internal linking mode.
- if runtime.GOARCH == "ppc64" || (runtime.GOARCH == "arm64" && runtime.GOOS == "windows") || !testenv.CanInternalLink() {
- return // internal linking cgo is not supported
+ if !testenv.CanInternalLink(true) {
+ continue
}
cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2 -linkmode=internal", "-o", exe, src)
out, err = cmd.CombinedOutput()
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build cgo
-
package main
import (
- "runtime"
+ "internal/testenv"
"testing"
)
-func canInternalLink() bool {
- switch runtime.GOOS {
- case "aix":
- return false
- case "dragonfly":
- return false
- case "freebsd":
- switch runtime.GOARCH {
- case "arm64", "riscv64":
- return false
- }
- case "linux":
- switch runtime.GOARCH {
- case "arm64", "loong64", "mips64", "mips64le", "mips", "mipsle", "ppc64", "ppc64le", "riscv64":
- return false
- }
- case "openbsd":
- switch runtime.GOARCH {
- case "arm64", "mips64":
- return false
- }
- case "windows":
- switch runtime.GOARCH {
- case "arm64":
- return false
- }
- }
- return true
-}
-
func TestInternalLinkerCgoExec(t *testing.T) {
- if !canInternalLink() {
- t.Skip("skipping; internal linking is not supported")
- }
+ testenv.MustHaveCGO(t)
+ testenv.MustInternalLink(t, true)
testGoExec(t, true, false)
}
func TestExternalLinkerCgoExec(t *testing.T) {
+ testenv.MustHaveCGO(t)
testGoExec(t, true, true)
}
func TestCgoLib(t *testing.T) {
+ testenv.MustHaveCGO(t)
testGoLib(t, true)
}
}
}
-// MustLinkExternal reports whether goos/goarch requires external linking.
-func MustLinkExternal(goos, goarch string) bool {
+// MustLinkExternal reports whether goos/goarch requires external linking
+// with or without cgo dependencies.
+func MustLinkExternal(goos, goarch string, withCgo bool) bool {
+ if withCgo {
+ switch goarch {
+ case "loong64",
+ "mips", "mipsle", "mips64", "mips64le",
+ "riscv64":
+ // Internally linking cgo is incomplete on some architectures.
+ // https://go.dev/issue/14449
+ return true
+ case "arm64":
+ if goos == "windows" {
+ // windows/arm64 internal linking is not implemented.
+ return true
+ }
+ case "ppc64":
+ // Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
+ // https://go.dev/issue/8912
+ return true
+ }
+
+ switch goos {
+ case "android":
+ return true
+ case "dragonfly":
+ // It seems that on Dragonfly thread local storage is
+ // set up by the dynamic linker, so internal cgo linking
+ // doesn't work. Test case is "go test runtime/cgo".
+ return true
+ }
+ }
+
switch goos {
case "android":
if goarch != "arm64" {
func InternalLinkPIESupported(goos, goarch string) bool {
switch goos + "/" + goarch {
- case "darwin/amd64", "darwin/arm64",
+ case "android/arm64",
+ "darwin/amd64", "darwin/arm64",
"linux/amd64", "linux/arm64", "linux/ppc64le",
- "android/arm64",
- "windows-amd64", "windows-386", "windows-arm":
+ "windows/386", "windows/amd64", "windows/arm", "windows/arm64":
return true
}
return false
// CanInternalLink reports whether the current system can link programs with
// internal linking.
-func CanInternalLink() bool {
- return !platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH)
+func CanInternalLink(withCgo bool) bool {
+ return !platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, withCgo)
}
// MustInternalLink checks that the current system can link programs with internal
// linking.
// If not, MustInternalLink calls t.Skip with an explanation.
-func MustInternalLink(t testing.TB) {
- if !CanInternalLink() {
+func MustInternalLink(t testing.TB, withCgo bool) {
+ if !CanInternalLink(withCgo) {
+ if withCgo && CanInternalLink(false) {
+ t.Skipf("skipping test: internal linking on %s/%s is not supported with cgo", runtime.GOOS, runtime.GOARCH)
+ }
t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH)
}
}
// This test runs with cgo disabled. External linking needs cgo, so
// it doesn't work if external linking is required.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
if runtime.GOOS == "windows" {
t.Skipf("skipping test on %q", runtime.GOOS)
func testDeadlock(t *testing.T, name string) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
output := runTestProg(t, "testprog", name)
want := "fatal error: all goroutines are asleep - deadlock!\n"
func TestGoexitDeadlock(t *testing.T) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
output := runTestProg(t, "testprog", "GoexitDeadlock")
want := "no goroutines (main called runtime.Goexit) - deadlock!"
func TestGoexitCrash(t *testing.T) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
output := runTestProg(t, "testprog", "GoexitExit")
want := "no goroutines (main called runtime.Goexit) - deadlock!"
func TestGoexitInPanic(t *testing.T) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
// see issue 8774: this code used to trigger an infinite recursion
output := runTestProg(t, "testprog", "GoexitInPanic")
func TestRecoveredPanicAfterGoexit(t *testing.T) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit")
want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
t.Parallel()
output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit")
func TestRecoverBeforePanicAfterGoexit2(t *testing.T) {
// External linking brings in cgo, causing deadlock detection not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
t.Parallel()
output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit2")
// Faketime is advanced in checkdead. External linking brings in cgo,
// causing checkdead not working.
- testenv.MustInternalLink(t)
+ testenv.MustInternalLink(t, false)
t.Parallel()