Skip to content

Commit

Permalink
cmd/go: error out of linking package main if cgo is required but not …
Browse files Browse the repository at this point in the history
…enabled

Fixes golang#46330.
Fixes golang#62123.
Updates golang#31544.

Change-Id: I023aa2bdb5a24e126a0de5192a077e8cf1a0a67c
Reviewed-on: https://go-review.googlesource.com/c/go/+/522239
Run-TryBot: Bryan Mills <[email protected]>
Auto-Submit: Bryan Mills <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
Bryan C. Mills authored and gopherbot committed Aug 23, 2023
1 parent 2763146 commit 079dfdc
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 23 deletions.
49 changes: 28 additions & 21 deletions src/cmd/go/internal/load/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -1920,7 +1920,12 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *

// The linker loads implicit dependencies.
if p.Name == "main" && !p.Internal.ForceLibrary {
for _, dep := range LinkerDeps(p) {
ldDeps, err := LinkerDeps(p)
if err != nil {
setError(err)
return
}
for _, dep := range ldDeps {
addImport(dep, false)
}
}
Expand Down Expand Up @@ -2556,12 +2561,15 @@ func SafeArg(name string) bool {
}

// LinkerDeps returns the list of linker-induced dependencies for main package p.
func LinkerDeps(p *Package) []string {
func LinkerDeps(p *Package) ([]string, error) {
// Everything links runtime.
deps := []string{"runtime"}

// External linking mode forces an import of runtime/cgo.
if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" {
if what := externalLinkingReason(p); what != "" && cfg.BuildContext.Compiler != "gccgo" {
if !cfg.BuildContext.CgoEnabled {
return nil, fmt.Errorf("%s requires external (cgo) linking, but cgo is not enabled", what)
}
deps = append(deps, "runtime/cgo")
}
// On ARM with GOARM=5, it forces an import of math, for soft floating point.
Expand All @@ -2585,30 +2593,27 @@ func LinkerDeps(p *Package) []string {
deps = append(deps, "runtime/coverage")
}

return deps
return deps, nil
}

// externalLinkingForced reports whether external linking is being
// forced even for programs that do not use cgo.
func externalLinkingForced(p *Package) bool {
if !cfg.BuildContext.CgoEnabled {
return false
}

// externalLinkingForced reports the reason external linking is required
// even for programs that do not use cgo, or the empty string if external
// linking is not required.
func externalLinkingReason(p *Package) (what string) {
// Some targets must use external linking even inside GOROOT.
if platform.MustLinkExternal(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH, false) {
return true
if platform.MustLinkExternal(cfg.Goos, cfg.Goarch, false) {
return cfg.Goos + "/" + cfg.Goarch
}

// Some build modes always require external linking.
switch cfg.BuildBuildmode {
case "c-shared", "plugin":
return true
return "-buildmode=" + cfg.BuildBuildmode
}

// Using -linkshared always requires external linking.
if cfg.BuildLinkshared {
return true
return "-linkshared"
}

// Decide whether we are building a PIE,
Expand All @@ -2623,27 +2628,29 @@ func externalLinkingForced(p *Package) bool {
// that does not support PIE with internal linking mode,
// then we must use external linking.
if isPIE && !platform.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH) {
return true
if cfg.BuildBuildmode == "pie" {
return "-buildmode=pie"
}
return "default PIE binary"
}

// Using -ldflags=-linkmode=external forces external linking.
// If there are multiple -linkmode options, the last one wins.
linkmodeExternal := false
if p != nil {
ldflags := BuildLdflags.For(p)
for i := len(ldflags) - 1; i >= 0; i-- {
a := ldflags[i]
if a == "-linkmode=external" ||
a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
linkmodeExternal = true
break
return a
} else if a == "-linkmode=internal" ||
a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "internal" {
break
return ""
}
}
}
return linkmodeExternal

return ""
}

// mkAbs rewrites list, which must be paths relative to p.Dir,
Expand Down
6 changes: 5 additions & 1 deletion src/cmd/go/internal/load/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,11 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
// Also the linker introduces implicit dependencies reported by LinkerDeps.
stk.Push("testmain")
deps := TestMainDeps // cap==len, so safe for append
for _, d := range LinkerDeps(p) {
ldDeps, err := LinkerDeps(p)
if err != nil && pmain.Error == nil {
pmain.Error = &PackageError{Err: err}
}
for _, d := range ldDeps {
deps = append(deps, d)
}
for _, dep := range deps {
Expand Down
6 changes: 5 additions & 1 deletion src/cmd/go/internal/work/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -853,7 +853,11 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac

// The linker step still needs all the usual linker deps.
// (For example, the linker always opens runtime.a.)
for _, dep := range load.LinkerDeps(nil) {
ldDeps, err := load.LinkerDeps(nil)
if err != nil {
base.Error(err)
}
for _, dep := range ldDeps {
add(a, dep, true)
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/cmd/go/testdata/script/test_android_issue62123.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
env GOOS=android GOARCH=amd64 CGO_ENABLED=0

! go build -o $devnull cmd/buildid
stderr 'android/amd64 requires external \(cgo\) linking, but cgo is not enabled'
! stderr 'cannot find runtime/cgo'

! go test -c -o $devnull os
stderr '# os\nandroid/amd64 requires external \(cgo\) linking, but cgo is not enabled'
! stderr 'cannot find runtime/cgo'

env GOOS=ios GOARCH=arm64 CGO_ENABLED=0

! go build -o $devnull cmd/buildid
stderr 'ios/arm64 requires external \(cgo\) linking, but cgo is not enabled'
! stderr 'cannot find runtime/cgo'

! go test -c -o $devnull os
stderr '# os\nios/arm64 requires external \(cgo\) linking, but cgo is not enabled'
! stderr 'cannot find runtime/cgo'

0 comments on commit 079dfdc

Please sign in to comment.