]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: set expected filename when building a local package with -o is pointing to...
authorJordi Martin <jordimartin@gmail.com>
Fri, 4 Oct 2019 11:56:26 +0000 (11:56 +0000)
committerJay Conrod <jayconrod@google.com>
Fri, 4 Oct 2019 17:30:40 +0000 (17:30 +0000)
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: Jay Conrod <jayconrod@google.com>
src/cmd/go/internal/load/pkg.go
src/cmd/go/internal/load/pkg_test.go
src/cmd/go/internal/test/test.go
src/cmd/go/internal/work/build.go
src/cmd/go/testdata/script/build_multi_main.txt

index 205ecc596d0f34050aea0775bfc7f4dc0a109d15..115bc29694f2fd8f7781d818f08defc0c344a153 100644 (file)
@@ -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 {
index 9ddc20d0500ee37b8ea737a5300320a79c097fa6..1e59fb989c59c29f8ad68e6df9fe5f6740757870 100644 (file)
@@ -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)
                        }
                }
        }
index 8141e31c991aeebcb2b9cf119bd606aff622daa2..fb011d4c03f18f2ed50938c86372cf27789eb0f3 100644 (file)
@@ -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"
 
index 1fc47a36c745b20d98dad125c0dadab37220a1fc..54b049b68fe0db94cc9d955d65e78e020fad05ae 100644 (file)
@@ -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)
index 1d4926d979095b8b370bfb76a27895f6f63b8537..8afd8b8a2e11af607e639cb2a8eb41982265164b 100644 (file)
@@ -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.