]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: fix "#cgo pkg-config:" comments with gccgo
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Thu, 21 Jan 2016 01:53:55 +0000 (14:53 +1300)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Thu, 14 Apr 2016 20:18:56 +0000 (20:18 +0000)
The unique difficulty of #cgo pkg-config is that the linker flags are recorded
when the package is compiled but (obviously) must be used when the package is
linked into an executable -- so the flags need to be stored on disk somewhere.
As it happens cgo already writes out a _cgo_flags file: nothing uses it
currently, but this change adds it to the lib$pkg.a file when compiling a
package, reads it out when linking (and passes a version of the .a file with
_cgo_flags stripped out of it to the linker). It's all fairly ugly but it works
and I can't really think of any way of reducing the essential level of
ugliness.

Fixes #11739

Change-Id: I35621878014e1e107eda77a5b0b23d0240ec5750
Reviewed-on: https://go-review.googlesource.com/18790
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/go/build.go

index 01b32c30ed0513cfcee7f4d0554beb4f8b8b673e..6b9da26ae8f2ef4af38cb5ca0870802295bf99b2 100644 (file)
@@ -1424,6 +1424,9 @@ func (b *builder) build(a *action) (err error) {
                if err != nil {
                        return err
                }
+               if _, ok := buildToolchain.(gccgoToolchain); ok {
+                       cgoObjects = append(cgoObjects, filepath.Join(a.objdir, "_cgo_flags"))
+               }
                cgoObjects = append(cgoObjects, outObj...)
                gofiles = append(gofiles, outGo...)
        }
@@ -2610,12 +2613,73 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
        objc := len(root.p.MFiles) > 0
        fortran := len(root.p.FFiles) > 0
 
+       readCgoFlags := func(flagsFile string) error {
+               flags, err := ioutil.ReadFile(flagsFile)
+               if err != nil {
+                       return err
+               }
+               const ldflagsPrefix = "_CGO_LDFLAGS="
+               for _, line := range strings.Split(string(flags), "\n") {
+                       if strings.HasPrefix(line, ldflagsPrefix) {
+                               newFlags := strings.Fields(line[len(ldflagsPrefix):])
+                               for _, flag := range newFlags {
+                                       // Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
+                                       // but they don't mean anything to the linker so filter
+                                       // them out.
+                                       if flag != "-g" && !strings.HasPrefix(flag, "-O") {
+                                               cgoldflags = append(cgoldflags, flag)
+                                       }
+                               }
+                       }
+               }
+               return nil
+       }
+
+       readAndRemoveCgoFlags := func(archive string) (string, error) {
+               newa, err := ioutil.TempFile(b.work, filepath.Base(archive))
+               if err != nil {
+                       return "", err
+               }
+               olda, err := os.Open(archive)
+               if err != nil {
+                       return "", err
+               }
+               _, err = io.Copy(newa, olda)
+               if err != nil {
+                       return "", err
+               }
+               err = olda.Close()
+               if err != nil {
+                       return "", err
+               }
+               err = newa.Close()
+               if err != nil {
+                       return "", err
+               }
+
+               newarchive := newa.Name()
+               err = b.run(b.work, root.p.ImportPath, nil, "ar", "x", newarchive, "_cgo_flags")
+               if err != nil {
+                       return "", err
+               }
+               err = b.run(".", root.p.ImportPath, nil, "ar", "d", newarchive, "_cgo_flags")
+               if err != nil {
+                       return "", err
+               }
+               err = readCgoFlags(filepath.Join(b.work, "_cgo_flags"))
+               if err != nil {
+                       return "", err
+               }
+               return newarchive, nil
+       }
+
        actionsSeen := make(map[*action]bool)
        // Make a pre-order depth-first traversal of the action graph, taking note of
        // whether a shared library action has been seen on the way to an action (the
        // construction of the graph means that if any path to a node passes through
        // a shared library action, they all do).
        var walk func(a *action, seenShlib bool)
+       var err error
        walk = func(a *action, seenShlib bool) {
                if actionsSeen[a] {
                        return
@@ -2634,16 +2698,23 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                        // doesn't work.
                        if !apackagesSeen[a.p] {
                                apackagesSeen[a.p] = true
+                               target := a.target
+                               if len(a.p.CgoFiles) > 0 {
+                                       target, err = readAndRemoveCgoFlags(target)
+                                       if err != nil {
+                                               return
+                                       }
+                               }
                                if a.p.fake && a.p.external {
                                        // external _tests, if present must come before
                                        // internal _tests. Store these on a separate list
                                        // and place them at the head after this loop.
-                                       xfiles = append(xfiles, a.target)
+                                       xfiles = append(xfiles, target)
                                } else if a.p.fake {
                                        // move _test files to the top of the link order
-                                       afiles = append([]string{a.target}, afiles...)
+                                       afiles = append([]string{target}, afiles...)
                                } else {
-                                       afiles = append(afiles, a.target)
+                                       afiles = append(afiles, target)
                                }
                        }
                }
@@ -2653,10 +2724,16 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                }
                for _, a1 := range a.deps {
                        walk(a1, seenShlib)
+                       if err != nil {
+                               return
+                       }
                }
        }
        for _, a1 := range root.deps {
                walk(a1, false)
+               if err != nil {
+                       return err
+               }
        }
        afiles = append(xfiles, afiles...)
 
@@ -2688,6 +2765,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
                }
        }
 
+       for i, o := range ofiles {
+               if filepath.Base(o) == "_cgo_flags" {
+                       readCgoFlags(o)
+                       ofiles = append(ofiles[:i], ofiles[i+1:]...)
+                       break
+               }
+       }
+
        ldflags = append(ldflags, "-Wl,--whole-archive")
        ldflags = append(ldflags, afiles...)
        ldflags = append(ldflags, "-Wl,--no-whole-archive")