From: Jordi Martin Date: Fri, 4 Oct 2019 11:56:26 +0000 (+0000) Subject: cmd/go: set expected filename when building a local package with -o is pointing to... X-Git-Tag: go1.14beta1~865 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=3ce29b44bb8eaecbd5000202564ad4f52ad1cf69;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Jay Conrod --- diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 205ecc596d..115bc29694 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -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 { diff --git a/src/cmd/go/internal/load/pkg_test.go b/src/cmd/go/internal/load/pkg_test.go index 9ddc20d050..1e59fb989c 100644 --- a/src/cmd/go/internal/load/pkg_test.go +++ b/src/cmd/go/internal/load/pkg_test.go @@ -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) } } } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 8141e31c99..fb011d4c03 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -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" diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 1fc47a36c7..54b049b68f 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -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) diff --git a/src/cmd/go/testdata/script/build_multi_main.txt b/src/cmd/go/testdata/script/build_multi_main.txt index 1d4926d979..8afd8b8a2e 100644 --- a/src/cmd/go/testdata/script/build_multi_main.txt +++ b/src/cmd/go/testdata/script/build_multi_main.txt @@ -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.