Commit 746edd45 authored by Hana Kim's avatar Hana Kim Committed by Andrew Bonventre

[release-branch.go1.12] cmd/go: fix the default build output name for versioned binaries

`go build` has chosen the last element of the package import path
as the default output name when -o option is given. That caused
the output of a package build when the module root is the major
version component such as 'v2'.

A similar issue involving `go install` was fixed in
https://golang.org/cl/128900. This CL refactors the logic added
with the change and makes it available as
internal/load.DefaultExecName.

This CL makes 'go test' to choose the right default test binary
name when the tested package is in the module root. (E.g.,
instead of v2.test, choose pkg.test for the test of 'path/pkg/v2')

Fixes #27283
Fixes #30266

Change-Id: I6905754f0906db46e3ce069552715f45356913ae
Reviewed-on: https://go-review.googlesource.com/c/go/+/140863Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
(cherry picked from commit bf94fc3a)
Reviewed-on: https://go-review.googlesource.com/c/go/+/167384
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent ad8ebb9e
......@@ -1178,6 +1178,44 @@ var cgoSyscallExclude = map[string]bool{
var foldPath = make(map[string]string)
// DefaultExecName returns the default executable name of the given
// package.
func DefaultExecName(p *Package) string {
_, elem := filepath.Split(p.ImportPath)
if cfg.ModulesEnabled {
// NOTE(rsc): Using p.ImportPath instead of p.Dir
// makes sure we install a package in the root of a
// cached module directory as that package name
// not name@v1.2.3.
// Using p.ImportPath instead of p.Dir
// is probably correct all the time,
// even for non-module-enabled code,
// but I'm not brave enough to change the
// non-module behavior this late in the
// release cycle. Maybe for Go 1.12.
// See golang.org/issue/26869.
_, elem = pathpkg.Split(p.ImportPath)
// If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
// See golang.org/issue/24667.
isVersion := func(v string) bool {
if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
return false
}
for i := 2; i < len(v); i++ {
if c := v[i]; c < '0' || '9' < c {
return false
}
}
return true
}
if isVersion(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
}
}
return elem
}
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
......@@ -1218,38 +1256,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.Error = &PackageError{Err: e}
return
}
_, elem := filepath.Split(p.Dir)
if cfg.ModulesEnabled {
// NOTE(rsc): Using p.ImportPath instead of p.Dir
// makes sure we install a package in the root of a
// cached module directory as that package name
// not name@v1.2.3.
// Using p.ImportPath instead of p.Dir
// is probably correct all the time,
// even for non-module-enabled code,
// but I'm not brave enough to change the
// non-module behavior this late in the
// release cycle. Maybe for Go 1.12.
// See golang.org/issue/26869.
_, elem = pathpkg.Split(p.ImportPath)
// If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
// See golang.org/issue/24667.
isVersion := func(v string) bool {
if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
return false
}
for i := 2; i < len(v); i++ {
if c := v[i]; c < '0' || '9' < c {
return false
}
}
return true
}
if isVersion(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
}
}
elem := DefaultExecName(p)
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
// Install cross-compiled binaries to subdirectories of bin.
......
......@@ -805,7 +805,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
if p.ImportPath == "command-line-arguments" {
elem = p.Name
} else {
_, elem = path.Split(p.ImportPath)
elem = load.DefaultExecName(p)
}
testBinary := elem + ".test"
......
......@@ -10,7 +10,6 @@ import (
"go/build"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strings"
......@@ -285,7 +284,7 @@ func runBuild(cmd *base.Command, args []string) {
pkgs := load.PackagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
_, cfg.BuildO = path.Split(pkgs[0].ImportPath)
cfg.BuildO = load.DefaultExecName(pkgs[0])
cfg.BuildO += cfg.ExeSuffix
}
......
......@@ -13,3 +13,9 @@ import "rsc.io/quote"
func main() {
println(quote.Hello())
}
-- fortune_test.go --
package main
import "testing"
func TestFortuneV2(t *testing.T) {}
env GO111MODULE=on
go get -m rsc.io/fortune/v2
# The default executable name shouldn't be v2$exe
go build rsc.io/fortune/v2
! exists v2$exe
exists fortune$exe
# The default test binary name shouldn't be v2.test$exe
go test -c rsc.io/fortune/v2
! exists v2.test$exe
exists fortune.test$exe
-- go.mod --
module scratch
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment