re PR go/66904 (cmd/go: "#cgo pkg-config:" comments do not work with gccgo)

PR go/66904
    cmd/go: fix "#cgo pkg-config:" comments with gccgo
    
    Copy of https://golang.org/cl/18790 by Michael Hudson-Doyle.
    
    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.
    
    Update golang/go#11739.
    GCC PR 66904.

    Reviewed-on: https://go-review.googlesource.com/19431

From-SVN: r233290
This commit is contained in:
Ian Lance Taylor 2016-02-10 18:30:27 +00:00
parent e03dd76578
commit 931f434a72
2 changed files with 80 additions and 4 deletions

View File

@ -1,4 +1,4 @@
4cec4c5db5b054c5536ec5c50ee7aebec83563bc
28a9dfbc3cda0bf7fd4f3fb1506c547f6cdf41a5
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -1445,6 +1445,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...)
}
@ -2620,12 +2623,64 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
objc := len(root.p.MFiles) > 0
readCgoFlags := func(flagsFile string) error {
flags, err := ioutil.ReadFile(flagsFile)
if err != nil {
return err
}
for _, line := range strings.Split(string(flags), "\n") {
if strings.HasPrefix(line, "_CGO_LDFLAGS=") {
cgoldflags = append(cgoldflags, strings.Fields(line[13:])...)
}
}
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
@ -2644,16 +2699,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)
}
}
}
@ -2663,10 +2725,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...)
@ -2695,6 +2763,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")