From 079dfdcac0448168e22a72baa61b9ab5de8ce54e Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 23 Aug 2023 16:32:46 -0400 Subject: [PATCH] cmd/go: error out of linking package main if cgo is required but not enabled Fixes #46330. Fixes #62123. Updates #31544. Change-Id: I023aa2bdb5a24e126a0de5192a077e8cf1a0a67c Reviewed-on: https://go-review.googlesource.com/c/go/+/522239 Run-TryBot: Bryan Mills Auto-Submit: Bryan Mills Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot --- src/cmd/go/internal/load/pkg.go | 49 +++++++++++-------- src/cmd/go/internal/load/test.go | 6 ++- src/cmd/go/internal/work/action.go | 6 ++- .../script/test_android_issue62123.txt | 19 +++++++ 4 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 src/cmd/go/testdata/script/test_android_issue62123.txt diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 0abc09186de..1adc9220ba5 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -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) } } @@ -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. @@ -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, @@ -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, diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index e9ed0d332bc..de2caa31280 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -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 { diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go index d4d0a71e750..7bde857bcc8 100644 --- a/src/cmd/go/internal/work/action.go +++ b/src/cmd/go/internal/work/action.go @@ -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) } } diff --git a/src/cmd/go/testdata/script/test_android_issue62123.txt b/src/cmd/go/testdata/script/test_android_issue62123.txt new file mode 100644 index 00000000000..2f46a6b44bf --- /dev/null +++ b/src/cmd/go/testdata/script/test_android_issue62123.txt @@ -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'