1
0
mirror of https://github.com/golang/go synced 2024-11-18 22:34:45 -07:00

cmd/go: set expected filename when building a local package with -o is pointing to a folder

In the local package build process, when -o is pointing to an existing folder, the object
the filename is generated from files listed on the command line like when the -o is
not pointing to a folder instead of using the `importPath` that is going to be `command-line-arguments`

Fixes #34535

Change-Id: I09a7609c17a2ccdd83da32f01247c0ef473dea1e
GitHub-Last-Rev: b3224226a3
GitHub-Pull-Request: golang/go#34562
Reviewed-on: https://go-review.googlesource.com/c/go/+/197544
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Jordi Martin 2019-10-04 11:56:26 +00:00 committed by Jay Conrod
parent 43a4c61e12
commit 3ce29b44bb
5 changed files with 77 additions and 34 deletions

View File

@ -1391,26 +1391,51 @@ var cgoSyscallExclude = map[string]bool{
var foldPath = make(map[string]string) var foldPath = make(map[string]string)
// DefaultExecName returns the default executable name // exeFromImportPath returns an executable name
// for a package with the import path importPath. // for a package using the import path.
// //
// The default executable name is the last element of the import path. // The executable name is the last element of the import path.
// In module-aware mode, an additional rule is used on import paths // In module-aware mode, an additional rule is used on import paths
// consisting of two or more path elements. If the last element is // consisting of two or more path elements. If the last element is
// a vN path element specifying the major version, then the // a vN path element specifying the major version, then the
// second last element of the import path is used instead. // second last element of the import path is used instead.
func DefaultExecName(importPath string) string { func (p *Package) exeFromImportPath() string {
_, elem := pathpkg.Split(importPath) _, elem := pathpkg.Split(p.ImportPath)
if cfg.ModulesEnabled { if cfg.ModulesEnabled {
// If this is example.com/mycmd/v2, it's more useful to // If this is example.com/mycmd/v2, it's more useful to
// install it as mycmd than as v2. See golang.org/issue/24667. // install it as mycmd than as v2. See golang.org/issue/24667.
if elem != importPath && isVersionElement(elem) { if elem != p.ImportPath && isVersionElement(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(importPath)) _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
} }
} }
return elem return elem
} }
// exeFromFiles returns an executable name for a package
// using the first element in GoFiles or CgoFiles collections without the prefix.
//
// Returns empty string in case of empty collection.
func (p *Package) exeFromFiles() string {
var src string
if len(p.GoFiles) > 0 {
src = p.GoFiles[0]
} else if len(p.CgoFiles) > 0 {
src = p.CgoFiles[0]
} else {
return ""
}
_, elem := filepath.Split(src)
return elem[:len(elem)-len(".go")]
}
// DefaultExecName returns the default executable name for a package
func (p *Package) DefaultExecName() string {
if p.Internal.CmdlineFiles {
return p.exeFromFiles()
}
return p.exeFromImportPath()
}
// load populates p using information from bp, err, which should // load populates p using information from bp, err, which should
// be the result of calling build.Context.Import. // be the result of calling build.Context.Import.
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
@ -1451,7 +1476,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
p.Error = &PackageError{Err: e} p.Error = &PackageError{Err: e}
return return
} }
elem := DefaultExecName(p.ImportPath) elem := p.DefaultExecName()
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH { if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
// Install cross-compiled binaries to subdirectories of bin. // Install cross-compiled binaries to subdirectories of bin.
@ -2140,11 +2165,8 @@ func GoFilesPackage(gofiles []string) *Package {
pkg.Match = gofiles pkg.Match = gofiles
if pkg.Name == "main" { if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0]) exe := pkg.DefaultExecName() + cfg.ExeSuffix
exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
if cfg.BuildO == "" {
cfg.BuildO = exe
}
if cfg.GOBIN != "" { if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe) pkg.Target = filepath.Join(cfg.GOBIN, exe)
} else if cfg.ModulesEnabled { } else if cfg.ModulesEnabled {

View File

@ -5,39 +5,49 @@ import (
"testing" "testing"
) )
func TestDefaultExecName(t *testing.T) { func TestPkgDefaultExecName(t *testing.T) {
oldModulesEnabled := cfg.ModulesEnabled oldModulesEnabled := cfg.ModulesEnabled
defer func() { cfg.ModulesEnabled = oldModulesEnabled }() defer func() { cfg.ModulesEnabled = oldModulesEnabled }()
for _, tt := range []struct { for _, tt := range []struct {
in string in string
files []string
wantMod string wantMod string
wantGopath string wantGopath string
}{ }{
{"example.com/mycmd", "mycmd", "mycmd"}, {"example.com/mycmd", []string{}, "mycmd", "mycmd"},
{"example.com/mycmd/v0", "v0", "v0"}, {"example.com/mycmd/v0", []string{}, "v0", "v0"},
{"example.com/mycmd/v1", "v1", "v1"}, {"example.com/mycmd/v1", []string{}, "v1", "v1"},
{"example.com/mycmd/v2", "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode. {"example.com/mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
{"example.com/mycmd/v3", "mycmd", "v3"}, // Semantic import versioning, use second last element in module mode. {"example.com/mycmd/v3", []string{}, "mycmd", "v3"}, // Semantic import versioning, use second last element in module mode.
{"mycmd", "mycmd", "mycmd"}, {"mycmd", []string{}, "mycmd", "mycmd"},
{"mycmd/v0", "v0", "v0"}, {"mycmd/v0", []string{}, "v0", "v0"},
{"mycmd/v1", "v1", "v1"}, {"mycmd/v1", []string{}, "v1", "v1"},
{"mycmd/v2", "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode. {"mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
{"v0", "v0", "v0"}, {"v0", []string{}, "v0", "v0"},
{"v1", "v1", "v1"}, {"v1", []string{}, "v1", "v1"},
{"v2", "v2", "v2"}, {"v2", []string{}, "v2", "v2"},
{"command-line-arguments", []string{"output.go", "foo.go"}, "output", "output"},
} { } {
{ {
cfg.ModulesEnabled = true cfg.ModulesEnabled = true
gotMod := DefaultExecName(tt.in) pkg := new(Package)
pkg.ImportPath = tt.in
pkg.GoFiles = tt.files
pkg.Internal.CmdlineFiles = len(tt.files) > 0
gotMod := pkg.DefaultExecName()
if gotMod != tt.wantMod { if gotMod != tt.wantMod {
t.Errorf("DefaultExecName(%q) in module mode = %v; want %v", tt.in, gotMod, tt.wantMod) t.Errorf("pkg.DefaultExecName with ImportPath = %q in module mode = %v; want %v", tt.in, gotMod, tt.wantMod)
} }
} }
{ {
cfg.ModulesEnabled = false cfg.ModulesEnabled = false
gotGopath := DefaultExecName(tt.in) pkg := new(Package)
pkg.ImportPath = tt.in
pkg.GoFiles = tt.files
pkg.Internal.CmdlineFiles = len(tt.files) > 0
gotGopath := pkg.DefaultExecName()
if gotGopath != tt.wantGopath { if gotGopath != tt.wantGopath {
t.Errorf("DefaultExecName(%q) in gopath mode = %v; want %v", tt.in, gotGopath, tt.wantGopath) t.Errorf("pkg.DefaultExecName with ImportPath = %q in gopath mode = %v; want %v", tt.in, gotGopath, tt.wantGopath)
} }
} }
} }

View File

@ -829,7 +829,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
if p.ImportPath == "command-line-arguments" { if p.ImportPath == "command-line-arguments" {
elem = p.Name elem = p.Name
} else { } else {
elem = load.DefaultExecName(p.ImportPath) elem = p.DefaultExecName()
} }
testBinary := elem + ".test" testBinary := elem + ".test"

View File

@ -329,7 +329,7 @@ func runBuild(cmd *base.Command, args []string) {
explicitO := len(cfg.BuildO) > 0 explicitO := len(cfg.BuildO) > 0
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" { if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
cfg.BuildO = load.DefaultExecName(pkgs[0].ImportPath) cfg.BuildO = pkgs[0].DefaultExecName()
cfg.BuildO += cfg.ExeSuffix cfg.BuildO += cfg.ExeSuffix
} }
@ -373,7 +373,8 @@ func runBuild(cmd *base.Command, args []string) {
if p.Name != "main" { if p.Name != "main" {
continue continue
} }
p.Target = filepath.Join(cfg.BuildO, load.DefaultExecName(p.ImportPath))
p.Target = filepath.Join(cfg.BuildO, p.DefaultExecName())
p.Target += cfg.ExeSuffix p.Target += cfg.ExeSuffix
p.Stale = true p.Stale = true
p.StaleReason = "build -o flag in use" p.StaleReason = "build -o flag in use"
@ -595,7 +596,7 @@ func InstallPackages(patterns []string, pkgs []*load.Package) {
if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
// Compute file 'go build' would have created. // Compute file 'go build' would have created.
// If it exists and is an executable file, remove it. // If it exists and is an executable file, remove it.
targ := load.DefaultExecName(pkgs[0].ImportPath) targ := pkgs[0].DefaultExecName()
targ += cfg.ExeSuffix targ += cfg.ExeSuffix
if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
fi, err := os.Stat(targ) fi, err := os.Stat(targ)

View File

@ -10,6 +10,11 @@ stderr 'no main packages'
! go build ./cmd/c1 ! go build ./cmd/c1
stderr 'already exists and is a directory' stderr 'already exists and is a directory'
# Verify build -o output correctly local packages
mkdir $WORK/local
go build -o $WORK/local ./exec.go
exists $WORK/local/exec$GOEXE
-- go.mod -- -- go.mod --
module exmod module exmod
@ -29,5 +34,10 @@ package pkg1
-- pkg2/pkg2.go -- -- pkg2/pkg2.go --
package pkg2 package pkg2
-- exec.go --
package main
func main() {}
-- c1$GOEXE/keep.txt -- -- c1$GOEXE/keep.txt --
Create c1 directory. Create c1 directory.