mirror of https://github.com/golang/go.git
cmd/go: make gccgo -buildmode=shared and -linkshared work again
After CL 69831, addTransitiveLinkDeps ensures that all dependencies of a link appear in Deps. We no longer need to traverse through all actions to find them. And the old scheme of looking through all the actions and assuming we would see shared library actions before libraries they depend on no longer works. Now that we have complete deps, change to a simpler scheme in which we find the shared libraries in the deps, and then use that to sort the deps into archives and shared libraries. Fixes #22224 Change-Id: I14fcc773ac59b6f5c2965cc04d4ed962442cc89e Reviewed-on: https://go-review.googlesource.com/87497 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
8554fd6e7d
commit
9745eed4fd
|
|
@ -351,10 +351,10 @@ func readNotes(f *elf.File) ([]*note, error) {
|
||||||
|
|
||||||
func dynStrings(t *testing.T, path string, flag elf.DynTag) []string {
|
func dynStrings(t *testing.T, path string, flag elf.DynTag) []string {
|
||||||
f, err := elf.Open(path)
|
f, err := elf.Open(path)
|
||||||
defer f.Close()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("elf.Open(%q) failed: %v", path, err)
|
t.Fatalf("elf.Open(%q) failed: %v", path, err)
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
dynstrings, err := f.DynString(flag)
|
dynstrings, err := f.DynString(flag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err)
|
t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err)
|
||||||
|
|
@ -598,7 +598,6 @@ func TestThreeGopathShlibs(t *testing.T) {
|
||||||
// If gccgo is not available or not new enough call t.Skip. Otherwise,
|
// If gccgo is not available or not new enough call t.Skip. Otherwise,
|
||||||
// return a build.Context that is set up for gccgo.
|
// return a build.Context that is set up for gccgo.
|
||||||
func prepGccgo(t *testing.T) build.Context {
|
func prepGccgo(t *testing.T) build.Context {
|
||||||
t.Skip("golang.org/issue/22472")
|
|
||||||
gccgoName := os.Getenv("GCCGO")
|
gccgoName := os.Getenv("GCCGO")
|
||||||
if gccgoName == "" {
|
if gccgoName == "" {
|
||||||
gccgoName = "gccgo"
|
gccgoName = "gccgo"
|
||||||
|
|
@ -648,8 +647,6 @@ func TestGoPathShlibGccgo(t *testing.T) {
|
||||||
// library with gccgo, another GOPATH package that depends on the first and an
|
// library with gccgo, another GOPATH package that depends on the first and an
|
||||||
// executable that links the second library.
|
// executable that links the second library.
|
||||||
func TestTwoGopathShlibsGccgo(t *testing.T) {
|
func TestTwoGopathShlibsGccgo(t *testing.T) {
|
||||||
t.Skip("golang.org/issue/22224")
|
|
||||||
|
|
||||||
gccgoContext := prepGccgo(t)
|
gccgoContext := prepGccgo(t)
|
||||||
|
|
||||||
libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
|
libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
|
||||||
|
|
|
||||||
|
|
@ -647,11 +647,9 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac
|
||||||
// it is not present in another shared library, add it here.
|
// it is not present in another shared library, add it here.
|
||||||
// TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
|
// TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
|
||||||
// TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
|
// TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
|
||||||
// TODO(rsc): Find out and explain here why gccgo is excluded.
|
// TODO(rsc): We don't add standard library imports for gccgo
|
||||||
// If the answer is that gccgo is different in implicit linker deps, maybe
|
// because they are all always linked in anyhow.
|
||||||
// load.LinkerDeps should be used and updated.
|
// Maybe load.LinkerDeps should be used and updated.
|
||||||
// Link packages into a shared library.
|
|
||||||
|
|
||||||
a := &Action{
|
a := &Action{
|
||||||
Mode: "go build -buildmode=shared",
|
Mode: "go build -buildmode=shared",
|
||||||
Package: p,
|
Package: p,
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,6 @@ func (gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string)
|
||||||
func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
|
func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
|
||||||
// gccgo needs explicit linking with all package dependencies,
|
// gccgo needs explicit linking with all package dependencies,
|
||||||
// and all LDFLAGS from cgo dependencies.
|
// and all LDFLAGS from cgo dependencies.
|
||||||
apackagePathsSeen := make(map[string]bool)
|
|
||||||
afiles := []string{}
|
afiles := []string{}
|
||||||
shlibs := []string{}
|
shlibs := []string{}
|
||||||
ldflags := b.gccArchArgs()
|
ldflags := b.gccArchArgs()
|
||||||
|
|
@ -261,56 +260,57 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string
|
||||||
return newArchive, nil
|
return newArchive, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
actionsSeen := make(map[*Action]bool)
|
// If using -linkshared, find the shared library deps.
|
||||||
// Make a pre-order depth-first traversal of the action graph, taking note of
|
haveShlib := make(map[string]bool)
|
||||||
// whether a shared library action has been seen on the way to an action (the
|
targetBase := filepath.Base(root.Target)
|
||||||
// construction of the graph means that if any path to a node passes through
|
if cfg.BuildLinkshared {
|
||||||
// a shared library action, they all do).
|
for _, a := range root.Deps {
|
||||||
var walk func(a *Action, seenShlib bool)
|
p := a.Package
|
||||||
var err error
|
if p == nil || p.Shlib == "" {
|
||||||
walk = func(a *Action, seenShlib bool) {
|
continue
|
||||||
if actionsSeen[a] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
actionsSeen[a] = true
|
|
||||||
if a.Package != nil && !seenShlib {
|
|
||||||
if a.Package.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'
|
// The .a we are linking into this .so
|
||||||
// rather than the 'build' location (which may not exist any
|
// will have its Shlib set to this .so.
|
||||||
// more). We still need to traverse the dependencies of the
|
// Don't start thinking we want to link
|
||||||
// build action though so saying
|
// this .so into itself.
|
||||||
// if apackagePathsSeen[a.Package.ImportPath] { return }
|
base := filepath.Base(p.Shlib)
|
||||||
// doesn't work.
|
if base != targetBase {
|
||||||
if !apackagePathsSeen[a.Package.ImportPath] {
|
haveShlib[base] = true
|
||||||
apackagePathsSeen[a.Package.ImportPath] = true
|
|
||||||
target := a.built
|
|
||||||
if len(a.Package.CgoFiles) > 0 || a.Package.UsesSwig() {
|
|
||||||
target, err = readAndRemoveCgoFlags(target)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
afiles = append(afiles, target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(a.Target, ".so") {
|
|
||||||
shlibs = append(shlibs, a.Target)
|
|
||||||
seenShlib = true
|
|
||||||
}
|
|
||||||
for _, a1 := range a.Deps {
|
|
||||||
walk(a1, seenShlib)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, a1 := range root.Deps {
|
|
||||||
walk(a1, false)
|
// Arrange the deps into afiles and shlibs.
|
||||||
if err != nil {
|
addedShlib := make(map[string]bool)
|
||||||
return err
|
for _, a := range root.Deps {
|
||||||
|
p := a.Package
|
||||||
|
if p != nil && p.Shlib != "" && haveShlib[filepath.Base(p.Shlib)] {
|
||||||
|
// This is a package linked into a shared
|
||||||
|
// library that we will put into shlibs.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if haveShlib[filepath.Base(a.Target)] {
|
||||||
|
// This is a shared library we want to link againt.
|
||||||
|
if !addedShlib[a.Target] {
|
||||||
|
shlibs = append(shlibs, a.Target)
|
||||||
|
addedShlib[a.Target] = true
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != nil {
|
||||||
|
target := a.built
|
||||||
|
if p.UsesCgo() || p.UsesSwig() {
|
||||||
|
var err error
|
||||||
|
target, err = readAndRemoveCgoFlags(target)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afiles = append(afiles, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -457,9 +457,7 @@ func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
|
func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
|
||||||
fakeRoot := *root
|
return tools.link(b, root, out, importcfg, allactions, "shared", out)
|
||||||
fakeRoot.Deps = toplevelactions
|
|
||||||
return tools.link(b, &fakeRoot, out, importcfg, allactions, "shared", out)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
|
func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue