Skip to content

Commit a32e94d

Browse files
ianlancetaylorgopherbot
authored andcommitted
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 <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Commit-Queue: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
1 parent f449452 commit a32e94d

File tree

4 files changed

+65
-7
lines changed

4 files changed

+65
-7
lines changed

src/cmd/cgo/doc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ The following options are available when running cgo directly:
529529
Write out input file in Go syntax replacing C package
530530
names with real values. Used to generate files in the
531531
syscall package when bootstrapping a new target.
532+
-ldflags flags
533+
Flags to pass to the C linker. The cmd/go tool uses
534+
this to pass in the flags in the CGO_LDFLAGS variable.
532535
-objdir directory
533536
Put all generated files in directory.
534537
-srcdir directory

src/cmd/cgo/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ var objDir = flag.String("objdir", "", "object directory")
242242
var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
243243
var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
244244

245+
var ldflags = flag.String("ldflags", "", "flags to pass to C linker")
246+
245247
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
246248
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
247249
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
@@ -328,11 +330,11 @@ func main() {
328330
os.Exit(2)
329331
}
330332

331-
// Record CGO_LDFLAGS from the environment for external linking.
332-
if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
333-
args, err := splitQuoted(ldflags)
333+
// Record linker flags for external linking.
334+
if *ldflags != "" {
335+
args, err := splitQuoted(*ldflags)
334336
if err != nil {
335-
fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
337+
fatalf("bad -ldflags option: %q (%s)", *ldflags, err)
336338
}
337339
p.addToFlag("LDFLAGS", args)
338340
}

src/cmd/go/internal/work/exec.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,20 +2812,27 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
28122812
cgoflags = append(cgoflags, "-import_syscall=false")
28132813
}
28142814

2815-
// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
2815+
// cgoLDFLAGS, which includes p.CgoLDFLAGS, can be very long.
2816+
// Pass it to cgo on the command line, so that we use a
2817+
// response file if necessary.
2818+
//
28162819
// These flags are recorded in the generated _cgo_gotypes.go file
28172820
// using //go:cgo_ldflag directives, the compiler records them in the
28182821
// object file for the package, and then the Go linker passes them
28192822
// along to the host linker. At this point in the code, cgoLDFLAGS
28202823
// consists of the original $CGO_LDFLAGS (unchecked) and all the
28212824
// flags put together from source code (checked).
28222825
cgoenv := b.cCompilerEnv()
2826+
var ldflagsOption []string
28232827
if len(cgoLDFLAGS) > 0 {
28242828
flags := make([]string, len(cgoLDFLAGS))
28252829
for i, f := range cgoLDFLAGS {
28262830
flags[i] = strconv.Quote(f)
28272831
}
2828-
cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " "))
2832+
ldflagsOption = []string{"-ldflags=" + strings.Join(flags, " ")}
2833+
2834+
// Remove CGO_LDFLAGS from the environment.
2835+
cgoenv = append(cgoenv, "CGO_LDFLAGS=")
28292836
}
28302837

28312838
if cfg.BuildToolchainName == "gccgo" {
@@ -2863,7 +2870,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
28632870
cgoflags = append(cgoflags, "-trimpath", strings.Join(trimpath, ";"))
28642871
}
28652872

2866-
if err := sh.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
2873+
if err := sh.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, ldflagsOption, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
28672874
return nil, nil, err
28682875
}
28692876
outGo = append(outGo, gofiles...)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Issue #66456
2+
3+
[!cgo] skip
4+
[GOOS:windows] skip
5+
[GOOS:plan9] skip
6+
7+
# Generate a file with a very long #cgo LDFLAGS line.
8+
# This used to cause "go build" to fail with "argument list too long".
9+
go generate
10+
11+
# Build with the generated file.
12+
go build
13+
14+
-- go.mod --
15+
module cgolongcmd
16+
17+
go 1.22
18+
-- generate.go --
19+
//go:build ignore
20+
21+
package main
22+
23+
import (
24+
"fmt"
25+
"log"
26+
"os"
27+
"bytes"
28+
)
29+
30+
func main() {
31+
var buf bytes.Buffer
32+
buf.WriteString("package p\n")
33+
buf.WriteString("// #cgo LDFLAGS:")
34+
for i := range 10000 {
35+
fmt.Fprintf(&buf, " -Wl,-rpath,/nonexistentpath/%d", i)
36+
}
37+
buf.WriteString("\n")
38+
buf.WriteString(`import "C"`+"\n")
39+
if err := os.WriteFile("generated.go", buf.Bytes(), 0o644); err != nil {
40+
log.Fatal(err)
41+
}
42+
}
43+
-- gen.go --
44+
package p
45+
46+
//go:generate go run generate.go

0 commit comments

Comments
 (0)