]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo, cmd/go: add cgo -ldflags option, use it in cmd/go
authorIan Lance Taylor <iant@golang.org>
Thu, 9 May 2024 22:19:38 +0000 (15:19 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 13 May 2024 17:12:16 +0000 (17:12 +0000)
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>

src/cmd/cgo/doc.go
src/cmd/cgo/main.go
src/cmd/go/internal/work/exec.go
src/cmd/go/testdata/script/cgo_long_cmd.txt [new file with mode: 0644]

index 1c5d4b060d4fabf2d2d1139fdac23caf7b59f31e..3d4789fafb77eca87158ae25147aea77646be095 100644 (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
index a9095dee3d7ae761b793cef6319f7e345ad4c972..a19743fe6188262b876bc2293490f59209d05e6c 100644 (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)
        }
index a3d1533899431c90b3047fb15b4ddf947a9a6f61..29cce25132997c435b8d9fc56e40a787fe3236cb 100644 (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...)
diff --git a/src/cmd/go/testdata/script/cgo_long_cmd.txt b/src/cmd/go/testdata/script/cgo_long_cmd.txt
new file mode 100644 (file)
index 0000000..36b9133
--- /dev/null
@@ -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