Skip to content

Commit ee45177

Browse files
committed
cmd/go: use GOPATH order for compile -I and link -L options
Given GOPATH=p1:p2 and source code of just the right form, the go command could previously end up invoking the compiler with -I p2 -I p1 or the linker with -L p2 -L p1, so that compiled packages in p2 incorrectly shadowed packages in p1. If foo were in both p1 and p2 and the compilation of bar were such that the -I and -L options were inverted in this way, then GOPATH=p2 go install foo GOPATH=p1:p2 go install bar would get the p2 copy of foo instead of the (expected) p1 copy of foo. This manifested in real usage in a few different ways, but in all the root cause was that the -I or -L option sequence did not match GOPATH. Make it match GOPATH. Fixes #14176 (second report). Fixes #14192. Related but less common issue #14271 not fixed. Change-Id: I9c0f69042bb2bf92c9fc370535da2c60a1187d30 Reviewed-on: https://go-review.googlesource.com/19385 Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Russ Cox <[email protected]>
1 parent 558a213 commit ee45177

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/cmd/go/build.go

+18
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ var (
667667
goarch string
668668
goos string
669669
exeSuffix string
670+
gopath []string
670671
)
671672

672673
func init() {
@@ -675,6 +676,7 @@ func init() {
675676
if goos == "windows" {
676677
exeSuffix = ".exe"
677678
}
679+
gopath = filepath.SplitList(buildContext.GOPATH)
678680
}
679681

680682
// A builder holds global state about a build.
@@ -1684,6 +1686,22 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
16841686
inc = append(inc, flag, b.work)
16851687

16861688
// Finally, look in the installed package directories for each action.
1689+
// First add the package dirs corresponding to GOPATH entries
1690+
// in the original GOPATH order.
1691+
need := map[string]*build.Package{}
1692+
for _, a1 := range all {
1693+
if a1.p != nil && a1.pkgdir == a1.p.build.PkgRoot {
1694+
need[a1.p.build.Root] = a1.p.build
1695+
}
1696+
}
1697+
for _, root := range gopath {
1698+
if p := need[root]; p != nil && !incMap[p.PkgRoot] {
1699+
incMap[p.PkgRoot] = true
1700+
inc = append(inc, flag, p.PkgTargetRoot)
1701+
}
1702+
}
1703+
1704+
// Then add anything that's left.
16871705
for _, a1 := range all {
16881706
if a1.p == nil {
16891707
continue

src/cmd/go/go_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -2565,6 +2565,59 @@ func TestGoInstallShadowedGOPATH(t *testing.T) {
25652565
tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error")
25662566
}
25672567

2568+
func TestGoBuildGOPATHOrder(t *testing.T) {
2569+
// golang.org/issue/14176#issuecomment-179895769
2570+
// golang.org/issue/14192
2571+
// -I arguments to compiler could end up not in GOPATH order,
2572+
// leading to unexpected import resolution in the compiler.
2573+
// This is still not a complete fix (see golang.org/issue/14271 and next test)
2574+
// but it is clearly OK and enough to fix both of the two reported
2575+
// instances of the underlying problem. It will have to do for now.
2576+
2577+
tg := testgo(t)
2578+
defer tg.cleanup()
2579+
tg.makeTempdir()
2580+
tg.setenv("GOPATH", tg.path("p1")+string(filepath.ListSeparator)+tg.path("p2"))
2581+
2582+
tg.tempFile("p1/src/foo/foo.go", "package foo\n")
2583+
tg.tempFile("p2/src/baz/baz.go", "package baz\n")
2584+
tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
2585+
tg.tempFile("p1/src/bar/bar.go", `
2586+
package bar
2587+
import _ "baz"
2588+
import _ "foo"
2589+
`)
2590+
2591+
tg.run("install", "-x", "bar")
2592+
}
2593+
2594+
func TestGoBuildGOPATHOrderBroken(t *testing.T) {
2595+
// This test is known not to work.
2596+
// See golang.org/issue/14271.
2597+
t.Skip("golang.org/issue/14271")
2598+
2599+
tg := testgo(t)
2600+
defer tg.cleanup()
2601+
tg.makeTempdir()
2602+
2603+
tg.tempFile("p1/src/foo/foo.go", "package foo\n")
2604+
tg.tempFile("p2/src/baz/baz.go", "package baz\n")
2605+
tg.tempFile("p1/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/baz.a", "bad\n")
2606+
tg.tempFile("p2/pkg/"+runtime.GOOS+"_"+runtime.GOARCH+"/foo.a", "bad\n")
2607+
tg.tempFile("p1/src/bar/bar.go", `
2608+
package bar
2609+
import _ "baz"
2610+
import _ "foo"
2611+
`)
2612+
2613+
colon := string(filepath.ListSeparator)
2614+
tg.setenv("GOPATH", tg.path("p1")+colon+tg.path("p2"))
2615+
tg.run("install", "-x", "bar")
2616+
2617+
tg.setenv("GOPATH", tg.path("p2")+colon+tg.path("p1"))
2618+
tg.run("install", "-x", "bar")
2619+
}
2620+
25682621
func TestIssue11709(t *testing.T) {
25692622
tg := testgo(t)
25702623
defer tg.cleanup()

0 commit comments

Comments
 (0)