1
0
mirror of https://github.com/golang/go synced 2024-11-14 23:40:35 -07:00

cmd/cgo, cmd/go: add cgo -ldflags option, use it in cmd/go

This will automatically use a response file if ldflags is long,
avoiding "argument list too long" errors with a very large CGO_LDFLAGS.

Fixes #66456

Change-Id: I5f9ee86e03b4e6d6430f7f9d8357ef37a9c22465
Reviewed-on: https://go-review.googlesource.com/c/go/+/584655
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Commit-Queue: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Ian Lance Taylor 2024-05-09 15:19:38 -07:00 committed by Gopher Robot
parent f4494522dc
commit a32e94d43e
4 changed files with 65 additions and 7 deletions

View File

@ -529,6 +529,9 @@ The following options are available when running cgo directly:
Write out input file in Go syntax replacing C package
names with real values. Used to generate files in the
syscall package when bootstrapping a new target.
-ldflags flags
Flags to pass to the C linker. The cmd/go tool uses
this to pass in the flags in the CGO_LDFLAGS variable.
-objdir directory
Put all generated files in directory.
-srcdir directory

View File

@ -242,6 +242,8 @@ var objDir = flag.String("objdir", "", "object directory")
var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
var ldflags = flag.String("ldflags", "", "flags to pass to C linker")
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
@ -328,11 +330,11 @@ func main() {
os.Exit(2)
}
// Record CGO_LDFLAGS from the environment for external linking.
if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
args, err := splitQuoted(ldflags)
// Record linker flags for external linking.
if *ldflags != "" {
args, err := splitQuoted(*ldflags)
if err != nil {
fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
fatalf("bad -ldflags option: %q (%s)", *ldflags, err)
}
p.addToFlag("LDFLAGS", args)
}

View File

@ -2812,7 +2812,10 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
cgoflags = append(cgoflags, "-import_syscall=false")
}
// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
// cgoLDFLAGS, which includes p.CgoLDFLAGS, can be very long.
// Pass it to cgo on the command line, so that we use a
// response file if necessary.
//
// These flags are recorded in the generated _cgo_gotypes.go file
// using //go:cgo_ldflag directives, the compiler records them in the
// object file for the package, and then the Go linker passes them
@ -2820,12 +2823,16 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
// consists of the original $CGO_LDFLAGS (unchecked) and all the
// flags put together from source code (checked).
cgoenv := b.cCompilerEnv()
var ldflagsOption []string
if len(cgoLDFLAGS) > 0 {
flags := make([]string, len(cgoLDFLAGS))
for i, f := range cgoLDFLAGS {
flags[i] = strconv.Quote(f)
}
cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " "))
ldflagsOption = []string{"-ldflags=" + strings.Join(flags, " ")}
// Remove CGO_LDFLAGS from the environment.
cgoenv = append(cgoenv, "CGO_LDFLAGS=")
}
if cfg.BuildToolchainName == "gccgo" {
@ -2863,7 +2870,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
cgoflags = append(cgoflags, "-trimpath", strings.Join(trimpath, ";"))
}
if err := sh.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
if err := sh.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, ldflagsOption, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)

View File

@ -0,0 +1,46 @@
# Issue #66456
[!cgo] skip
[GOOS:windows] skip
[GOOS:plan9] skip
# Generate a file with a very long #cgo LDFLAGS line.
# This used to cause "go build" to fail with "argument list too long".
go generate
# Build with the generated file.
go build
-- go.mod --
module cgolongcmd
go 1.22
-- generate.go --
//go:build ignore
package main
import (
"fmt"
"log"
"os"
"bytes"
)
func main() {
var buf bytes.Buffer
buf.WriteString("package p\n")
buf.WriteString("// #cgo LDFLAGS:")
for i := range 10000 {
fmt.Fprintf(&buf, " -Wl,-rpath,/nonexistentpath/%d", i)
}
buf.WriteString("\n")
buf.WriteString(`import "C"`+"\n")
if err := os.WriteFile("generated.go", buf.Bytes(), 0o644); err != nil {
log.Fatal(err)
}
}
-- gen.go --
package p
//go:generate go run generate.go