mirror of
https://github.com/golang/go
synced 2024-11-18 19:54:44 -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:
parent
43a4c61e12
commit
3ce29b44bb
@ -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
src/cmd/go/testdata/script/build_multi_main.txt
vendored
10
src/cmd/go/testdata/script/build_multi_main.txt
vendored
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user