Skip to content

Commit 3ce29b4

Browse files
jmartin82Jay Conrod
authored andcommitted
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 golang#34535 Change-Id: I09a7609c17a2ccdd83da32f01247c0ef473dea1e GitHub-Last-Rev: b322422 GitHub-Pull-Request: golang#34562 Reviewed-on: https://go-review.googlesource.com/c/go/+/197544 Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent 43a4c61 commit 3ce29b4

5 files changed

Lines changed: 77 additions & 34 deletions

File tree

src/cmd/go/internal/load/pkg.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,26 +1391,51 @@ var cgoSyscallExclude = map[string]bool{
13911391

13921392
var foldPath = make(map[string]string)
13931393

1394-
// DefaultExecName returns the default executable name
1395-
// for a package with the import path importPath.
1394+
// exeFromImportPath returns an executable name
1395+
// for a package using the import path.
13961396
//
1397-
// The default executable name is the last element of the import path.
1397+
// The executable name is the last element of the import path.
13981398
// In module-aware mode, an additional rule is used on import paths
13991399
// consisting of two or more path elements. If the last element is
14001400
// a vN path element specifying the major version, then the
14011401
// second last element of the import path is used instead.
1402-
func DefaultExecName(importPath string) string {
1403-
_, elem := pathpkg.Split(importPath)
1402+
func (p *Package) exeFromImportPath() string {
1403+
_, elem := pathpkg.Split(p.ImportPath)
14041404
if cfg.ModulesEnabled {
14051405
// If this is example.com/mycmd/v2, it's more useful to
14061406
// install it as mycmd than as v2. See golang.org/issue/24667.
1407-
if elem != importPath && isVersionElement(elem) {
1408-
_, elem = pathpkg.Split(pathpkg.Dir(importPath))
1407+
if elem != p.ImportPath && isVersionElement(elem) {
1408+
_, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
14091409
}
14101410
}
14111411
return elem
14121412
}
14131413

1414+
// exeFromFiles returns an executable name for a package
1415+
// using the first element in GoFiles or CgoFiles collections without the prefix.
1416+
//
1417+
// Returns empty string in case of empty collection.
1418+
func (p *Package) exeFromFiles() string {
1419+
var src string
1420+
if len(p.GoFiles) > 0 {
1421+
src = p.GoFiles[0]
1422+
} else if len(p.CgoFiles) > 0 {
1423+
src = p.CgoFiles[0]
1424+
} else {
1425+
return ""
1426+
}
1427+
_, elem := filepath.Split(src)
1428+
return elem[:len(elem)-len(".go")]
1429+
}
1430+
1431+
// DefaultExecName returns the default executable name for a package
1432+
func (p *Package) DefaultExecName() string {
1433+
if p.Internal.CmdlineFiles {
1434+
return p.exeFromFiles()
1435+
}
1436+
return p.exeFromImportPath()
1437+
}
1438+
14141439
// load populates p using information from bp, err, which should
14151440
// be the result of calling build.Context.Import.
14161441
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) {
14511476
p.Error = &PackageError{Err: e}
14521477
return
14531478
}
1454-
elem := DefaultExecName(p.ImportPath)
1479+
elem := p.DefaultExecName()
14551480
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
14561481
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
14571482
// Install cross-compiled binaries to subdirectories of bin.
@@ -2140,11 +2165,8 @@ func GoFilesPackage(gofiles []string) *Package {
21402165
pkg.Match = gofiles
21412166

21422167
if pkg.Name == "main" {
2143-
_, elem := filepath.Split(gofiles[0])
2144-
exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
2145-
if cfg.BuildO == "" {
2146-
cfg.BuildO = exe
2147-
}
2168+
exe := pkg.DefaultExecName() + cfg.ExeSuffix
2169+
21482170
if cfg.GOBIN != "" {
21492171
pkg.Target = filepath.Join(cfg.GOBIN, exe)
21502172
} else if cfg.ModulesEnabled {

src/cmd/go/internal/load/pkg_test.go

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,49 @@ import (
55
"testing"
66
)
77

8-
func TestDefaultExecName(t *testing.T) {
8+
func TestPkgDefaultExecName(t *testing.T) {
99
oldModulesEnabled := cfg.ModulesEnabled
1010
defer func() { cfg.ModulesEnabled = oldModulesEnabled }()
1111
for _, tt := range []struct {
1212
in string
13+
files []string
1314
wantMod string
1415
wantGopath string
1516
}{
16-
{"example.com/mycmd", "mycmd", "mycmd"},
17-
{"example.com/mycmd/v0", "v0", "v0"},
18-
{"example.com/mycmd/v1", "v1", "v1"},
19-
{"example.com/mycmd/v2", "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
20-
{"example.com/mycmd/v3", "mycmd", "v3"}, // Semantic import versioning, use second last element in module mode.
21-
{"mycmd", "mycmd", "mycmd"},
22-
{"mycmd/v0", "v0", "v0"},
23-
{"mycmd/v1", "v1", "v1"},
24-
{"mycmd/v2", "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
25-
{"v0", "v0", "v0"},
26-
{"v1", "v1", "v1"},
27-
{"v2", "v2", "v2"},
17+
{"example.com/mycmd", []string{}, "mycmd", "mycmd"},
18+
{"example.com/mycmd/v0", []string{}, "v0", "v0"},
19+
{"example.com/mycmd/v1", []string{}, "v1", "v1"},
20+
{"example.com/mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
21+
{"example.com/mycmd/v3", []string{}, "mycmd", "v3"}, // Semantic import versioning, use second last element in module mode.
22+
{"mycmd", []string{}, "mycmd", "mycmd"},
23+
{"mycmd/v0", []string{}, "v0", "v0"},
24+
{"mycmd/v1", []string{}, "v1", "v1"},
25+
{"mycmd/v2", []string{}, "mycmd", "v2"}, // Semantic import versioning, use second last element in module mode.
26+
{"v0", []string{}, "v0", "v0"},
27+
{"v1", []string{}, "v1", "v1"},
28+
{"v2", []string{}, "v2", "v2"},
29+
{"command-line-arguments", []string{"output.go", "foo.go"}, "output", "output"},
2830
} {
2931
{
3032
cfg.ModulesEnabled = true
31-
gotMod := DefaultExecName(tt.in)
33+
pkg := new(Package)
34+
pkg.ImportPath = tt.in
35+
pkg.GoFiles = tt.files
36+
pkg.Internal.CmdlineFiles = len(tt.files) > 0
37+
gotMod := pkg.DefaultExecName()
3238
if gotMod != tt.wantMod {
33-
t.Errorf("DefaultExecName(%q) in module mode = %v; want %v", tt.in, gotMod, tt.wantMod)
39+
t.Errorf("pkg.DefaultExecName with ImportPath = %q in module mode = %v; want %v", tt.in, gotMod, tt.wantMod)
3440
}
3541
}
3642
{
3743
cfg.ModulesEnabled = false
38-
gotGopath := DefaultExecName(tt.in)
44+
pkg := new(Package)
45+
pkg.ImportPath = tt.in
46+
pkg.GoFiles = tt.files
47+
pkg.Internal.CmdlineFiles = len(tt.files) > 0
48+
gotGopath := pkg.DefaultExecName()
3949
if gotGopath != tt.wantGopath {
40-
t.Errorf("DefaultExecName(%q) in gopath mode = %v; want %v", tt.in, gotGopath, tt.wantGopath)
50+
t.Errorf("pkg.DefaultExecName with ImportPath = %q in gopath mode = %v; want %v", tt.in, gotGopath, tt.wantGopath)
4151
}
4252
}
4353
}

src/cmd/go/internal/test/test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
829829
if p.ImportPath == "command-line-arguments" {
830830
elem = p.Name
831831
} else {
832-
elem = load.DefaultExecName(p.ImportPath)
832+
elem = p.DefaultExecName()
833833
}
834834
testBinary := elem + ".test"
835835

src/cmd/go/internal/work/build.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ func runBuild(cmd *base.Command, args []string) {
329329
explicitO := len(cfg.BuildO) > 0
330330

331331
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
332-
cfg.BuildO = load.DefaultExecName(pkgs[0].ImportPath)
332+
cfg.BuildO = pkgs[0].DefaultExecName()
333333
cfg.BuildO += cfg.ExeSuffix
334334
}
335335

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

src/cmd/go/testdata/script/build_multi_main.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ stderr 'no main packages'
1010
! go build ./cmd/c1
1111
stderr 'already exists and is a directory'
1212

13+
# Verify build -o output correctly local packages
14+
mkdir $WORK/local
15+
go build -o $WORK/local ./exec.go
16+
exists $WORK/local/exec$GOEXE
17+
1318
-- go.mod --
1419
module exmod
1520

@@ -29,5 +34,10 @@ package pkg1
2934
-- pkg2/pkg2.go --
3035
package pkg2
3136

37+
-- exec.go --
38+
package main
39+
40+
func main() {}
41+
3242
-- c1$GOEXE/keep.txt --
3343
Create c1 directory.

0 commit comments

Comments
 (0)