Commit 3ce29b44 authored by Jordi Martin's avatar Jordi Martin Committed by Jay Conrod

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: b3224226a3914aa2573e47a6daff9fd5a48ca225
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: default avatarJay Conrod <jayconrod@google.com>
parent 43a4c61e
......@@ -1391,26 +1391,51 @@ var cgoSyscallExclude = map[string]bool{
var foldPath = make(map[string]string)
// DefaultExecName returns the default executable name
// for a package with the import path importPath.
// exeFromImportPath returns an executable name
// 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
// consisting of two or more path elements. If the last element is
// a vN path element specifying the major version, then the
// second last element of the import path is used instead.
func DefaultExecName(importPath string) string {
_, elem := pathpkg.Split(importPath)
func (p *Package) exeFromImportPath() string {
_, elem := pathpkg.Split(p.ImportPath)
if cfg.ModulesEnabled {
// If this is example.com/mycmd/v2, it's more useful to
// install it as mycmd than as v2. See golang.org/issue/24667.
if elem != importPath && isVersionElement(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(importPath))
if elem != p.ImportPath && isVersionElement(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
}
}
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
// be the result of calling build.Context.Import.
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}
return
}
elem := DefaultExecName(p.ImportPath)
elem := p.DefaultExecName()
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.
......@@ -2140,11 +2165,8 @@ func GoFilesPackage(gofiles []string) *Package {
pkg.Match = gofiles
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
if cfg.BuildO == "" {
cfg.BuildO = exe
}
exe := pkg.DefaultExecName() + cfg.ExeSuffix
if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe)
} else if cfg.ModulesEnabled {
......
......@@ -5,39 +5,49 @@ import (
"testing"
)
func TestDefaultExecName(t *testing.T) {
func TestPkgDefaultExecName(t *testing.T) {
oldModulesEnabled := cfg.ModulesEnabled
defer func() { cfg.ModulesEnabled = oldModulesEnabled }()
for _, tt := range []struct {
in string
files []string
wantMod string
wantGopath string
}{
{"example.com/mycmd", "mycmd", "mycmd"},
{"example.com/mycmd/v0", "v0", "v0"},
{"example.com/mycmd/v1", "v1", "v1"},
{"example.com/mycmd/v2", "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.
{"mycmd", "mycmd", "mycmd"},
{"mycmd/v0", "v0", "v0"},
{"mycmd/v1", "v1", "v1"},
{"mycmd/v2", "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
{"v0", "v0", "v0"},
{"v1", "v1", "v1"},
{"v2", "v2", "v2"},
{"example.com/mycmd", []string{}, "mycmd", "mycmd"},
{"example.com/mycmd/v0", []string{}, "v0", "v0"},
{"example.com/mycmd/v1", []string{}, "v1", "v1"},
{"example.com/mycmd/v2", []string{}, "mycmd", "v2"}, // 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", []string{}, "mycmd", "mycmd"},
{"mycmd/v0", []string{}, "v0", "v0"},
{"mycmd/v1", []string{}, "v1", "v1"},
{"mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
{"v0", []string{}, "v0", "v0"},
{"v1", []string{}, "v1", "v1"},
{"v2", []string{}, "v2", "v2"},
{"command-line-arguments", []string{"output.go", "foo.go"}, "output", "output"},
} {
{
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 {
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
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 {
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)
}
}
}
......
......@@ -829,7 +829,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
if p.ImportPath == "command-line-arguments" {
elem = p.Name
} else {
elem = load.DefaultExecName(p.ImportPath)
elem = p.DefaultExecName()
}
testBinary := elem + ".test"
......
......@@ -329,7 +329,7 @@ func runBuild(cmd *base.Command, args []string) {
explicitO := len(cfg.BuildO) > 0
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
}
......@@ -373,7 +373,8 @@ func runBuild(cmd *base.Command, args []string) {
if p.Name != "main" {
continue
}
p.Target = filepath.Join(cfg.BuildO, load.DefaultExecName(p.ImportPath))
p.Target = filepath.Join(cfg.BuildO, p.DefaultExecName())
p.Target += cfg.ExeSuffix
p.Stale = true
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" {
// Compute file 'go build' would have created.
// If it exists and is an executable file, remove it.
targ := load.DefaultExecName(pkgs[0].ImportPath)
targ := pkgs[0].DefaultExecName()
targ += cfg.ExeSuffix
if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
fi, err := os.Stat(targ)
......
......@@ -10,6 +10,11 @@ stderr 'no main packages'
! go build ./cmd/c1
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 --
module exmod
......@@ -29,5 +34,10 @@ package pkg1
-- pkg2/pkg2.go --
package pkg2
-- exec.go --
package main
func main() {}
-- c1$GOEXE/keep.txt --
Create c1 directory.
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