]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: support -buildmode=shared with gccgo
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Mon, 11 May 2015 01:39:28 +0000 (13:39 +1200)
committerIan Lance Taylor <iant@golang.org>
Tue, 16 Jun 2015 01:43:29 +0000 (01:43 +0000)
Change-Id: Id93b8ab42fa311ce32209734ec9a0813f8736e25
Reviewed-on: https://go-review.googlesource.com/9914
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>

misc/cgo/testshared/shared_test.go
src/cmd/go/build.go
src/cmd/go/pkg.go

index 09b159d7734deb08ee06a47cd94a44c8776c809c..ae977c00637deef4f598a11c56cd21923f7f0dc0 100644 (file)
@@ -20,6 +20,7 @@ import (
        "os"
        "os/exec"
        "path/filepath"
+       "regexp"
        "strings"
        "testing"
        "time"
@@ -274,13 +275,17 @@ func dynStrings(path string, flag elf.DynTag) []string {
        return dynstrings
 }
 
-func AssertIsLinkedTo(t *testing.T, path, lib string) {
+func AssertIsLinkedToRegexp(t *testing.T, path string, re *regexp.Regexp) {
        for _, dynstring := range dynStrings(path, elf.DT_NEEDED) {
-               if dynstring == lib {
+               if re.MatchString(dynstring) {
                        return
                }
        }
-       t.Errorf("%s is not linked to %s", path, lib)
+       t.Errorf("%s is not linked to anything matching %v", path, re)
+}
+
+func AssertIsLinkedTo(t *testing.T, path, lib string) {
+       AssertIsLinkedToRegexp(t, path, regexp.MustCompile(regexp.QuoteMeta(lib)))
 }
 
 func AssertHasRPath(t *testing.T, path, dir string) {
@@ -306,7 +311,7 @@ func TestTrivialExecutable(t *testing.T) {
 
 // Build a GOPATH package into a shared library that links against the goroot runtime
 // and an executable that links against both.
-func TestGOPathShlib(t *testing.T) {
+func TestGopathShlib(t *testing.T) {
        goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
        AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdep.so"), soname)
        goCmd(t, "install", "-linkshared", "exe")
@@ -437,13 +442,85 @@ func TestNotes(t *testing.T) {
 // Build a GOPATH package (dep) into a shared library that links against the goroot
 // runtime, another package (dep2) that links against the first, and and an
 // executable that links against dep2.
-func TestTwoGOPathShlibs(t *testing.T) {
+func TestTwoGopathShlibs(t *testing.T) {
        goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
        goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2")
        goCmd(t, "install", "-linkshared", "exe2")
        run(t, "executable linked to GOPATH library", "./bin/exe2")
 }
 
+// Build a GOPATH package into a shared library with gccgo and an executable that
+// links against it.
+func TestGoPathShlibGccgo(t *testing.T) {
+       gccgoName := os.Getenv("GCCGO")
+       if gccgoName == "" {
+               gccgoName = "gccgo"
+       }
+       _, err := exec.LookPath(gccgoName)
+       if err != nil {
+               t.Skip("gccgo not found")
+       }
+
+       libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
+
+       gccgoContext := build.Default
+       gccgoContext.InstallSuffix = suffix + "_fPIC"
+       gccgoContext.Compiler = "gccgo"
+       gccgoContext.GOPATH = os.Getenv("GOPATH")
+       depP, err := gccgoContext.Import("dep", ".", build.ImportComment)
+       if err != nil {
+               t.Fatalf("import failed: %v", err)
+       }
+       gccgoInstallDir := filepath.Join(depP.PkgTargetRoot, "shlibs")
+       goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep")
+       AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep.so"), libgoRE)
+       goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe")
+       AssertIsLinkedToRegexp(t, "./bin/exe", libgoRE)
+       AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
+       AssertHasRPath(t, "./bin/exe", gccgoInstallDir)
+       // And check it runs.
+       run(t, "gccgo-built", "./bin/exe")
+}
+
+// The gccgo version of TestTwoGopathShlibs: build a GOPATH package into a shared
+// library with gccgo, another GOPATH package that depends on the first and an
+// executable that links the second library.
+func TestTwoGopathShlibsGccgo(t *testing.T) {
+       gccgoName := os.Getenv("GCCGO")
+       if gccgoName == "" {
+               gccgoName = "gccgo"
+       }
+       _, err := exec.LookPath(gccgoName)
+       if err != nil {
+               t.Skip("gccgo not found")
+       }
+
+       libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
+
+       gccgoContext := build.Default
+       gccgoContext.InstallSuffix = suffix + "_fPIC"
+       gccgoContext.Compiler = "gccgo"
+       gccgoContext.GOPATH = os.Getenv("GOPATH")
+       depP, err := gccgoContext.Import("dep", ".", build.ImportComment)
+       if err != nil {
+               t.Fatalf("import failed: %v", err)
+       }
+       gccgoInstallDir := filepath.Join(depP.PkgTargetRoot, "shlibs")
+       goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep")
+       goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep2")
+       goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe2")
+
+       AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep.so"), libgoRE)
+       AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep2.so"), libgoRE)
+       AssertIsLinkedTo(t, filepath.Join(gccgoInstallDir, "libdep2.so"), "libdep.so")
+       AssertIsLinkedToRegexp(t, "./bin/exe2", libgoRE)
+       AssertIsLinkedTo(t, "./bin/exe2", "libdep2")
+       AssertIsLinkedTo(t, "./bin/exe2", "libdep.so")
+
+       // And check it runs.
+       run(t, "gccgo-built", "./bin/exe2")
+}
+
 // Testing rebuilding of shared libraries when they are stale is a bit more
 // complicated that it seems like it should be. First, we make everything "old": but
 // only a few seconds old, or it might be older than 6g (or the runtime source) and
index 4c8f3192171e64f714b88440396edd4ada28b943..07b4c307947725bf8f2710b3078b07efbb38d0a3 100644 (file)
@@ -8,6 +8,7 @@ import (
        "bufio"
        "bytes"
        "container/heap"
+       "debug/elf"
        "errors"
        "flag"
        "fmt"
@@ -752,19 +753,37 @@ func goFilesPackage(gofiles []string) *Package {
        return pkg
 }
 
-func readpkglist(shlibpath string) []*Package {
-       pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1)
-       if err != nil {
-               fatalf("readELFNote failed: %v", err)
-       }
-       scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
-       var pkgs []*Package
+// readpkglist returns the list of packages that were built into the shared library
+// at shlibpath. For the native toolchain this list is stored, newline separated, in
+// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
+// .go_export section.
+func readpkglist(shlibpath string) (pkgs []*Package) {
        var stk importStack
-       for scanner.Scan() {
-               t := scanner.Text()
-               pkgs = append(pkgs, loadPackage(t, &stk))
+       if _, gccgo := buildToolchain.(gccgoToolchain); gccgo {
+               f, _ := elf.Open(shlibpath)
+               sect := f.Section(".go_export")
+               data, _ := sect.Data()
+               scanner := bufio.NewScanner(bytes.NewBuffer(data))
+               for scanner.Scan() {
+                       t := scanner.Text()
+                       if strings.HasPrefix(t, "pkgpath ") {
+                               t = strings.TrimPrefix(t, "pkgpath ")
+                               t = strings.TrimSuffix(t, ";")
+                               pkgs = append(pkgs, loadPackage(t, &stk))
+                       }
+               }
+       } else {
+               pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1)
+               if err != nil {
+                       fatalf("readELFNote failed: %v", err)
+               }
+               scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
+               for scanner.Scan() {
+                       t := scanner.Text()
+                       pkgs = append(pkgs, loadPackage(t, &stk))
+               }
        }
-       return pkgs
+       return
 }
 
 // action returns the action for applying the given operation (mode) to the package.
@@ -914,23 +933,26 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                // was not passed on the command line and it is not present in
                // another shared library, add it here.
                seencgo := false
-               for _, p := range pkgs {
-                       seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
-               }
-               if !seencgo {
-                       var stk importStack
-                       p := loadPackage("runtime/cgo", &stk)
-                       if p.Error != nil {
-                               fatalf("load runtime/cgo: %v", p.Error)
+               _, gccgo := buildToolchain.(gccgoToolchain)
+               if !gccgo {
+                       for _, p := range pkgs {
+                               seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
                        }
-                       computeStale(p)
-                       // If runtime/cgo is in another shared library, then that's
-                       // also the shared library that contains runtime, so
-                       // something will depend on it and so runtime/cgo's staleness
-                       // will be checked when processing that library.
-                       if p.Shlib == "" || p.Shlib == libname {
-                               pkgs = append([]*Package{}, pkgs...)
-                               pkgs = append(pkgs, p)
+                       if !seencgo {
+                               var stk importStack
+                               p := loadPackage("runtime/cgo", &stk)
+                               if p.Error != nil {
+                                       fatalf("load runtime/cgo: %v", p.Error)
+                               }
+                               computeStale(p)
+                               // If runtime/cgo is in another shared library, then that's
+                               // also the shared library that contains runtime, so
+                               // something will depend on it and so runtime/cgo's staleness
+                               // will be checked when processing that library.
+                               if p.Shlib == "" || p.Shlib == libname {
+                                       pkgs = append([]*Package{}, pkgs...)
+                                       pkgs = append(pkgs, p)
+                               }
                        }
                }
 
@@ -938,6 +960,9 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
                var libdir string
                for _, p := range pkgs {
                        plibdir := p.build.PkgTargetRoot
+                       if gccgo {
+                               plibdir = filepath.Join(plibdir, "shlibs")
+                       }
                        if libdir == "" {
                                libdir = plibdir
                        } else if libdir != plibdir {
@@ -1429,7 +1454,7 @@ func (b *builder) build(a *action) (err error) {
                // linker needs the whole dependency tree.
                all := actionList(a)
                all = all[:len(all)-1] // drop a
-               if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil {
+               if err := buildToolchain.ld(b, a, a.target, all, a.objpkg, objects); err != nil {
                        return err
                }
        }
@@ -1477,68 +1502,10 @@ func (b *builder) installShlibname(a *action) error {
        return nil
 }
 
-// setextld sets the appropriate linker flags for the specified compiler.
-func setextld(ldflags []string, compiler []string) []string {
-       for _, f := range ldflags {
-               if f == "-extld" || strings.HasPrefix(f, "-extld=") {
-                       // don't override -extld if supplied
-                       return ldflags
-               }
-       }
-       ldflags = append(ldflags, "-extld="+compiler[0])
-       if len(compiler) > 1 {
-               extldflags := false
-               add := strings.Join(compiler[1:], " ")
-               for i, f := range ldflags {
-                       if f == "-extldflags" && i+1 < len(ldflags) {
-                               ldflags[i+1] = add + " " + ldflags[i+1]
-                               extldflags = true
-                               break
-                       } else if strings.HasPrefix(f, "-extldflags=") {
-                               ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
-                               extldflags = true
-                               break
-                       }
-               }
-               if !extldflags {
-                       ldflags = append(ldflags, "-extldflags="+add)
-               }
-       }
-       return ldflags
-}
-
 func (b *builder) linkShared(a *action) (err error) {
-       // TODO(mwhudson): obvious copy pasting from gcToolchain.ld, should make a few
-       // changes to that function and then call it. And support gccgo.
        allactions := actionList(a)
-       importArgs := b.includeArgs("-L", allactions[:len(allactions)-1])
-       ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
-       ldflags = append(ldflags, "-buildmode=shared")
-       ldflags = append(ldflags, buildLdflags...)
-       cxx := a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0)
-       for _, a := range allactions {
-               if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
-                       cxx = true
-               }
-       }
-       // If the user has not specified the -extld option, then specify the
-       // appropriate linker. In case of C++ code, use the compiler named
-       // by the CXX environment variable or defaultCXX if CXX is not set.
-       // Else, use the CC environment variable and defaultCC as fallback.
-       var compiler []string
-       if cxx {
-               compiler = envList("CXX", defaultCXX)
-       } else {
-               compiler = envList("CC", defaultCC)
-       }
-       ldflags = setextld(ldflags, compiler)
-       for _, d := range a.deps {
-               if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries
-                       continue
-               }
-               ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
-       }
-       return b.run(".", a.target, nil, buildToolExec, tool("link"), "-o", a.target, importArgs, ldflags)
+       allactions = allactions[:len(allactions)-1]
+       return buildToolchain.ldShared(b, a.deps, a.target, allactions)
 }
 
 // install is the action for installing a single package or executable.
@@ -2062,8 +2029,10 @@ type toolchain interface {
        // an archive from a set of object files.
        // typically it is run in the object directory.
        pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
-       // ld runs the linker to create a package starting at mainpkg.
-       ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
+       // ld runs the linker to create an executable starting at mainpkg.
+       ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error
+       // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions
+       ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error
 
        compiler() string
        linker() string
@@ -2103,7 +2072,11 @@ func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
        return noCompiler()
 }
 
-func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (noToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+       return noCompiler()
+}
+
+func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
        return noCompiler()
 }
 
@@ -2326,9 +2299,39 @@ func packInternal(b *builder, afile string, ofiles []string) error {
        return dst.Close()
 }
 
-func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+// setextld sets the appropriate linker flags for the specified compiler.
+func setextld(ldflags []string, compiler []string) []string {
+       for _, f := range ldflags {
+               if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+                       // don't override -extld if supplied
+                       return ldflags
+               }
+       }
+       ldflags = append(ldflags, "-extld="+compiler[0])
+       if len(compiler) > 1 {
+               extldflags := false
+               add := strings.Join(compiler[1:], " ")
+               for i, f := range ldflags {
+                       if f == "-extldflags" && i+1 < len(ldflags) {
+                               ldflags[i+1] = add + " " + ldflags[i+1]
+                               extldflags = true
+                               break
+                       } else if strings.HasPrefix(f, "-extldflags=") {
+                               ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+                               extldflags = true
+                               break
+                       }
+               }
+               if !extldflags {
+                       ldflags = append(ldflags, "-extldflags="+add)
+               }
+       }
+       return ldflags
+}
+
+func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
        importArgs := b.includeArgs("-L", allactions)
-       cxx := len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0
+       cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
        for _, a := range allactions {
                if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
                        cxx = true
@@ -2338,7 +2341,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
        if buildContext.InstallSuffix != "" {
                ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
        }
-       if p.omitDWARF {
+       if root.p.omitDWARF {
                ldflags = append(ldflags, "-w")
        }
 
@@ -2354,11 +2357,42 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
        }
        ldflags = setextld(ldflags, compiler)
        ldflags = append(ldflags, "-buildmode="+ldBuildmode)
-       if p.buildID != "" {
-               ldflags = append(ldflags, "-buildid="+p.buildID)
+       if root.p.buildID != "" {
+               ldflags = append(ldflags, "-buildid="+root.p.buildID)
        }
        ldflags = append(ldflags, buildLdflags...)
-       return b.run(".", p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
+       return b.run(".", root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
+}
+
+func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
+       importArgs := b.includeArgs("-L", allactions)
+       ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
+       ldflags = append(ldflags, "-buildmode=shared")
+       ldflags = append(ldflags, buildLdflags...)
+       cxx := false
+       for _, a := range allactions {
+               if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
+                       cxx = true
+               }
+       }
+       // If the user has not specified the -extld option, then specify the
+       // appropriate linker. In case of C++ code, use the compiler named
+       // by the CXX environment variable or defaultCXX if CXX is not set.
+       // Else, use the CC environment variable and defaultCC as fallback.
+       var compiler []string
+       if cxx {
+               compiler = envList("CXX", defaultCXX)
+       } else {
+               compiler = envList("CC", defaultCC)
+       }
+       ldflags = setextld(ldflags, compiler)
+       for _, d := range toplevelactions {
+               if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries
+                       continue
+               }
+               ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
+       }
+       return b.run(".", out, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags)
 }
 
 func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -2432,26 +2466,42 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
        return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
 }
 
-func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
        // gccgo needs explicit linking with all package dependencies,
        // and all LDFLAGS from cgo dependencies.
        apackagesSeen := make(map[*Package]bool)
        afiles := []string{}
+       shlibs := []string{}
        xfiles := []string{}
        ldflags := b.gccArchArgs()
        cgoldflags := []string{}
        usesCgo := false
-       cxx := len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0
-       objc := len(p.MFiles) > 0
-
-       // Prefer the output of an install action to the output of a build action,
-       // because the install action will delete the output of the build action.
-       // Iterate over the list backward (reverse dependency order) so that we
-       // always see the install before the build.
-       for i := len(allactions) - 1; i >= 0; i-- {
-               a := allactions[i]
-               if !a.p.Standard {
-                       if a.p != nil && !apackagesSeen[a.p] {
+       cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
+       objc := len(root.p.MFiles) > 0
+
+       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)
+       walk = func(a *action, seenShlib bool) {
+               if actionsSeen[a] {
+                       return
+               }
+               actionsSeen[a] = true
+               if a.p != nil && !seenShlib {
+                       if a.p.Standard {
+                               return
+                       }
+                       // We record the target of the first time we see a .a file
+                       // for a package to make sure that we prefer the 'install'
+                       // rather than the 'build' location (which may not exist any
+                       // more). We still need to traverse the dependencies of the
+                       // build action though so saying
+                       // if apackagesSeen[a.p] { return }
+                       // doesn't work.
+                       if !apackagesSeen[a.p] {
                                apackagesSeen[a.p] = true
                                if a.p.fake && a.p.external {
                                        // external _tests, if present must come before
@@ -2466,6 +2516,16 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
                                }
                        }
                }
+               if strings.HasSuffix(a.target, ".so") {
+                       shlibs = append(shlibs, a.target)
+                       seenShlib = true
+               }
+               for _, a1 := range a.deps {
+                       walk(a1, seenShlib)
+               }
+       }
+       for _, a1 := range root.deps {
+               walk(a1, false)
        }
        afiles = append(xfiles, afiles...)
 
@@ -2474,6 +2534,9 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
                // The go tool can dig up runtime/cgo from GOROOT and
                // think that it should use its CgoLDFLAGS, but gccgo
                // doesn't use runtime/cgo.
+               if a.p == nil {
+                       continue
+               }
                if !a.p.Standard {
                        cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
                }
@@ -2505,10 +2568,20 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
 
        ldflags = append(ldflags, cgoldflags...)
        ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
-       ldflags = append(ldflags, p.CgoLDFLAGS...)
+       ldflags = append(ldflags, root.p.CgoLDFLAGS...)
 
        ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
 
+       for _, shlib := range shlibs {
+               ldflags = append(
+                       ldflags,
+                       "-L"+filepath.Dir(shlib),
+                       "-Wl,-rpath="+filepath.Dir(shlib),
+                       "-l"+strings.TrimSuffix(
+                               strings.TrimPrefix(filepath.Base(shlib), "lib"),
+                               ".so"))
+       }
+
        var realOut string
        switch ldBuildmode {
        case "exe":
@@ -2556,20 +2629,43 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
                }
        }
 
-       if err := b.run(".", p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
+       if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
                return err
        }
 
        switch ldBuildmode {
        case "c-archive":
-               if err := b.run(".", p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
+               if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
                        return err
                }
        }
-
        return nil
 }
 
+func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
+       args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"}
+       for _, a := range toplevelactions {
+               args = append(args, a.target)
+       }
+       args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
+       shlibs := []string{}
+       for _, a := range allactions {
+               if strings.HasSuffix(a.target, ".so") {
+                       shlibs = append(shlibs, a.target)
+               }
+       }
+       for _, shlib := range shlibs {
+               args = append(
+                       args,
+                       "-L"+filepath.Dir(shlib),
+                       "-Wl,-rpath="+filepath.Dir(shlib),
+                       "-l"+strings.TrimSuffix(
+                               strings.TrimPrefix(filepath.Base(shlib), "lib"),
+                               ".so"))
+       }
+       return b.run(".", out, nil, tools.linker(), args, buildGccgoflags)
+}
+
 func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
        inc := filepath.Join(goroot, "pkg", "include")
        cfile = mkAbs(p.Dir, cfile)
index d04f5bc97b15d956229a10569bbe3cbf9fa8f1b8..cf3e8b38aafb9c9cf0b5531476c5e4c176a58d9f 100644 (file)
@@ -530,7 +530,12 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
                        shlib, err := ioutil.ReadFile(shlibnamefile)
                        if err == nil {
                                libname := strings.TrimSpace(string(shlib))
-                               p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
+                               if buildContext.Compiler == "gccgo" {
+                                       p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname)
+                               } else {
+                                       p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
+
+                               }
                        } else if !os.IsNotExist(err) {
                                fatalf("unexpected error reading %s: %v", shlibnamefile, err)
                        }