Commit d9e6835b authored by Russ Cox's avatar Russ Cox

cmd/go: break a few dependencies

This CL makes a few naming changes to break dependencies
between different parts of the go command, to make it easier
to split into different packages.

This is the first CL in a long sequence of changes to break up the
go command from one package into a plausible group of packages.

This sequence is concerned only with moving code, not changing
or cleaning up code. There will still be more cleanup after this sequence.

The entire sequence will be submitted together: it is not a goal
for the tree to build at every step.

For #18653.

Change-Id: I69a98b9ea48e61b1e1cda95273d29860b525415f
Reviewed-on: https://go-review.googlesource.com/36129Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
parent 78074f68
...@@ -143,6 +143,7 @@ func init() { ...@@ -143,6 +143,7 @@ func init() {
cmdInstall.Run = runInstall cmdInstall.Run = runInstall
cmdBuild.Flag.BoolVar(&buildI, "i", false, "") cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
cmdBuild.Flag.StringVar(&buildO, "o", "", "output file")
addBuildFlags(cmdBuild) addBuildFlags(cmdBuild)
addBuildFlags(cmdInstall) addBuildFlags(cmdInstall)
...@@ -155,21 +156,24 @@ var buildP = runtime.NumCPU() // -p flag ...@@ -155,21 +156,24 @@ var buildP = runtime.NumCPU() // -p flag
var buildV bool // -v flag var buildV bool // -v flag
var buildX bool // -x flag var buildX bool // -x flag
var buildI bool // -i flag var buildI bool // -i flag
var buildO = cmdBuild.Flag.String("o", "", "output file") var buildO string // -o flag
var buildWork bool // -work flag var buildWork bool // -work flag
var buildAsmflags []string // -asmflags flag var buildAsmflags []string // -asmflags flag
var buildGcflags []string // -gcflags flag var buildGcflags []string // -gcflags flag
var buildLdflags []string // -ldflags flag var buildLdflags []string // -ldflags flag
var buildGccgoflags []string // -gccgoflags flag var buildGccgoflags []string // -gccgoflags flag
var buildRace bool // -race flag var buildRace bool // -race flag
var buildMSan bool // -msan flag var buildMSan bool // -msan flag
var buildToolExec []string // -toolexec flag var buildToolExec []string // -toolexec flag
var buildBuildmode string // -buildmode flag var buildBuildmode string // -buildmode flag
var buildLinkshared bool // -linkshared flag var buildLinkshared bool // -linkshared flag
var buildPkgdir string // -pkgdir flag var buildPkgdir string // -pkgdir flag
var buildContext = build.Default var buildContext = build.Default
var buildToolchain toolchain = noToolchain{} var buildToolchain toolchain = noToolchain{}
var buildToolchainName string
var buildToolchainCompiler string
var buildToolchainLinker string
var ldBuildmode string var ldBuildmode string
// buildCompiler implements flag.Var. // buildCompiler implements flag.Var.
...@@ -186,6 +190,9 @@ func (c buildCompiler) Set(value string) error { ...@@ -186,6 +190,9 @@ func (c buildCompiler) Set(value string) error {
default: default:
return fmt.Errorf("unknown compiler %q", value) return fmt.Errorf("unknown compiler %q", value)
} }
buildToolchainName = value
buildToolchainCompiler = buildToolchain.compiler()
buildToolchainLinker = buildToolchain.linker()
buildContext.Compiler = value buildContext.Compiler = value
return nil return nil
} }
...@@ -196,10 +203,8 @@ func (c buildCompiler) String() string { ...@@ -196,10 +203,8 @@ func (c buildCompiler) String() string {
func init() { func init() {
switch build.Default.Compiler { switch build.Default.Compiler {
case "gc": case "gc", "gccgo":
buildToolchain = gcToolchain{} buildCompiler{}.Set(build.Default.Compiler)
case "gccgo":
buildToolchain = gccgoToolchain{}
} }
} }
...@@ -321,7 +326,7 @@ func pkgsNotMain(pkgs []*Package) (res []*Package) { ...@@ -321,7 +326,7 @@ func pkgsNotMain(pkgs []*Package) (res []*Package) {
var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs } var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
func buildModeInit() { func buildModeInit() {
_, gccgo := buildToolchain.(gccgoToolchain) gccgo := buildToolchainName == "gccgo"
var codegenArg string var codegenArg string
platform := goos + "/" + goarch platform := goos + "/" + goarch
switch buildBuildmode { switch buildBuildmode {
...@@ -402,7 +407,7 @@ func buildModeInit() { ...@@ -402,7 +407,7 @@ func buildModeInit() {
} }
codegenArg = "-dynlink" codegenArg = "-dynlink"
} }
if *buildO != "" { if buildO != "" {
fatalf("-buildmode=shared and -o not supported together") fatalf("-buildmode=shared and -o not supported together")
} }
ldBuildmode = "shared" ldBuildmode = "shared"
...@@ -464,14 +469,14 @@ func runBuild(cmd *Command, args []string) { ...@@ -464,14 +469,14 @@ func runBuild(cmd *Command, args []string) {
pkgs := packagesForBuild(args) pkgs := packagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" { if len(pkgs) == 1 && pkgs[0].Name == "main" && buildO == "" {
_, *buildO = path.Split(pkgs[0].ImportPath) _, buildO = path.Split(pkgs[0].ImportPath)
*buildO += exeSuffix buildO += exeSuffix
} }
// Special case -o /dev/null by not writing at all. // Special case -o /dev/null by not writing at all.
if *buildO == os.DevNull { if buildO == os.DevNull {
*buildO = "" buildO = ""
} }
// sanity check some often mis-used options // sanity check some often mis-used options
...@@ -494,14 +499,14 @@ func runBuild(cmd *Command, args []string) { ...@@ -494,14 +499,14 @@ func runBuild(cmd *Command, args []string) {
depMode = modeInstall depMode = modeInstall
} }
if *buildO != "" { if buildO != "" {
if len(pkgs) > 1 { if len(pkgs) > 1 {
fatalf("go build: cannot use -o with multiple packages") fatalf("go build: cannot use -o with multiple packages")
} else if len(pkgs) == 0 { } else if len(pkgs) == 0 {
fatalf("no packages to build") fatalf("no packages to build")
} }
p := pkgs[0] p := pkgs[0]
p.target = *buildO p.target = buildO
p.Stale = true // must build - not up to date p.Stale = true // must build - not up to date
p.StaleReason = "build -o flag in use" p.StaleReason = "build -o flag in use"
a := b.action(modeInstall, depMode, p) a := b.action(modeInstall, depMode, p)
...@@ -874,8 +879,8 @@ func goFilesPackage(gofiles []string) *Package { ...@@ -874,8 +879,8 @@ func goFilesPackage(gofiles []string) *Package {
if pkg.Name == "main" { if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0]) _, elem := filepath.Split(gofiles[0])
exe := elem[:len(elem)-len(".go")] + exeSuffix exe := elem[:len(elem)-len(".go")] + exeSuffix
if *buildO == "" { if buildO == "" {
*buildO = exe buildO = exe
} }
if gobin != "" { if gobin != "" {
pkg.target = filepath.Join(gobin, exe) pkg.target = filepath.Join(gobin, exe)
...@@ -896,7 +901,7 @@ func goFilesPackage(gofiles []string) *Package { ...@@ -896,7 +901,7 @@ func goFilesPackage(gofiles []string) *Package {
// .go_export section. // .go_export section.
func readpkglist(shlibpath string) (pkgs []*Package) { func readpkglist(shlibpath string) (pkgs []*Package) {
var stk importStack var stk importStack
if _, gccgo := buildToolchain.(gccgoToolchain); gccgo { if buildToolchainName == "gccgo" {
f, _ := elf.Open(shlibpath) f, _ := elf.Open(shlibpath)
sect := f.Section(".go_export") sect := f.Section(".go_export")
data, _ := sect.Data() data, _ := sect.Data()
...@@ -1010,7 +1015,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha ...@@ -1010,7 +1015,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
return a return a
} }
// gccgo standard library is "fake" too. // gccgo standard library is "fake" too.
if _, ok := buildToolchain.(gccgoToolchain); ok { if buildToolchainName == "gccgo" {
// the target name is needed for cgo. // the target name is needed for cgo.
a.target = p.target a.target = p.target
return a return a
...@@ -1114,7 +1119,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build ...@@ -1114,7 +1119,7 @@ func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode build
// external linking mode forces an import of runtime/cgo (and // external linking mode forces an import of runtime/cgo (and
// math on arm). So if it was not passed on the command line and // math on arm). So if it was not passed on the command line and
// it is not present in another shared library, add it here. // it is not present in another shared library, add it here.
_, gccgo := buildToolchain.(gccgoToolchain) gccgo := buildToolchainName == "gccgo"
if !gccgo { if !gccgo {
seencgo := false seencgo := false
for _, p := range pkgs { for _, p := range pkgs {
...@@ -1490,7 +1495,7 @@ func (b *builder) build(a *action) (err error) { ...@@ -1490,7 +1495,7 @@ func (b *builder) build(a *action) (err error) {
if err != nil { if err != nil {
return err return err
} }
if _, ok := buildToolchain.(gccgoToolchain); ok { if buildToolchainName == "gccgo" {
cgoObjects = append(cgoObjects, filepath.Join(a.objdir, "_cgo_flags")) cgoObjects = append(cgoObjects, filepath.Join(a.objdir, "_cgo_flags"))
} }
cgoObjects = append(cgoObjects, outObj...) cgoObjects = append(cgoObjects, outObj...)
...@@ -3324,7 +3329,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil ...@@ -3324,7 +3329,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")} cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
} }
if _, ok := buildToolchain.(gccgoToolchain); ok { if buildToolchainName == "gccgo" {
switch goarch { switch goarch {
case "386", "amd64": case "386", "amd64":
cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack") cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
...@@ -3396,8 +3401,8 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil ...@@ -3396,8 +3401,8 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
outObj = append(outObj, ofile) outObj = append(outObj, ofile)
} }
switch buildToolchain.(type) { switch buildToolchainName {
case gcToolchain: case "gc":
importGo := obj + "_cgo_import.go" importGo := obj + "_cgo_import.go"
if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil { if err := b.dynimport(p, obj, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
return nil, nil, err return nil, nil, err
...@@ -3410,7 +3415,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil ...@@ -3410,7 +3415,7 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
} }
outObj = []string{ofile} outObj = []string{ofile}
case gccgoToolchain: case "gccgo":
defunC := obj + "_cgo_defun.c" defunC := obj + "_cgo_defun.c"
defunObj := obj + "_cgo_defun.o" defunObj := obj + "_cgo_defun.o"
if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
...@@ -3684,7 +3689,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b ...@@ -3684,7 +3689,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
gccExt = "cxx" gccExt = "cxx"
} }
_, gccgo := buildToolchain.(gccgoToolchain) gccgo := buildToolchainName == "gccgo"
// swig // swig
args := []string{ args := []string{
......
...@@ -74,33 +74,37 @@ func (c *Command) Runnable() bool { ...@@ -74,33 +74,37 @@ func (c *Command) Runnable() bool {
// Commands lists the available commands and help topics. // Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'. // The order here is the order in which they are printed by 'go help'.
var commands = []*Command{ var commands []*Command
cmdBuild,
cmdClean, func init() {
cmdDoc, commands = []*Command{
cmdEnv, cmdBuild,
cmdBug, cmdClean,
cmdFix, cmdDoc,
cmdFmt, cmdEnv,
cmdGenerate, cmdBug,
cmdGet, cmdFix,
cmdInstall, cmdFmt,
cmdList, cmdGenerate,
cmdRun, cmdGet,
cmdTest, cmdInstall,
cmdTool, cmdList,
cmdVersion, cmdRun,
cmdVet, cmdTest,
cmdTool,
helpC, cmdVersion,
helpBuildmode, cmdVet,
helpFileType,
helpGopath, helpC,
helpEnvironment, helpBuildmode,
helpImportPath, helpFileType,
helpPackages, helpGopath,
helpTestflag, helpEnvironment,
helpTestfunc, helpImportPath,
helpPackages,
helpTestflag,
helpTestfunc,
}
} }
var exitStatus = 0 var exitStatus = 0
...@@ -307,7 +311,13 @@ func printUsage(w io.Writer) { ...@@ -307,7 +311,13 @@ func printUsage(w io.Writer) {
bw.Flush() bw.Flush()
} }
func usage() { var usage func()
func init() {
usage = mainUsage
}
func mainUsage() {
// special case "go test -h" // special case "go test -h"
if len(os.Args) > 1 && os.Args[1] == "test" { if len(os.Args) > 1 && os.Args[1] == "test" {
os.Stderr.WriteString(testUsage + "\n\n" + os.Stderr.WriteString(testUsage + "\n\n" +
......
...@@ -1124,7 +1124,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package ...@@ -1124,7 +1124,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if p.BinaryOnly { if p.BinaryOnly {
// For binary-only package, use build ID from supplied package binary. // For binary-only package, use build ID from supplied package binary.
buildID, err := readBuildID(p) buildID, err := readBuildID(p.Name, p.Target)
if err == nil { if err == nil {
p.buildID = buildID p.buildID = buildID
} }
...@@ -1495,7 +1495,7 @@ func isStale(p *Package) (bool, string) { ...@@ -1495,7 +1495,7 @@ func isStale(p *Package) (bool, string) {
// It also catches changes in toolchain, like when flipping between // It also catches changes in toolchain, like when flipping between
// two versions of Go compiling a single GOPATH. // two versions of Go compiling a single GOPATH.
// See issue 8290 and issue 10702. // See issue 8290 and issue 10702.
targetBuildID, err := readBuildID(p) targetBuildID, err := readBuildID(p.Name, p.Target)
if err == nil && targetBuildID != p.buildID { if err == nil && targetBuildID != p.buildID {
return true, "build ID mismatch" return true, "build ID mismatch"
} }
...@@ -1559,10 +1559,10 @@ func isStale(p *Package) (bool, string) { ...@@ -1559,10 +1559,10 @@ func isStale(p *Package) (bool, string) {
// Excluding $GOROOT used to also fix issue 4106, but that's now // Excluding $GOROOT used to also fix issue 4106, but that's now
// taken care of above (at least when the installed Go is a released version). // taken care of above (at least when the installed Go is a released version).
if p.Root != goroot { if p.Root != goroot {
if olderThan(buildToolchain.compiler()) { if olderThan(buildToolchainCompiler) {
return true, "newer compiler" return true, "newer compiler"
} }
if p.build.IsCommand() && olderThan(buildToolchain.linker()) { if p.build.IsCommand() && olderThan(buildToolchainLinker) {
return true, "newer linker" return true, "newer linker"
} }
} }
...@@ -1865,20 +1865,20 @@ var ( ...@@ -1865,20 +1865,20 @@ var (
// readBuildID reads the build ID from an archive or binary. // readBuildID reads the build ID from an archive or binary.
// It only supports the gc toolchain. // It only supports the gc toolchain.
// Other toolchain maintainers should adjust this function. // Other toolchain maintainers should adjust this function.
func readBuildID(p *Package) (id string, err error) { func readBuildID(name, target string) (id string, err error) {
if buildToolchain != (gcToolchain{}) { if buildToolchainName != "gc" {
return "", errBuildIDToolchain return "", errBuildIDToolchain
} }
// For commands, read build ID directly from binary. // For commands, read build ID directly from binary.
if p.Name == "main" { if name == "main" {
return ReadBuildIDFromBinary(p.Target) return ReadBuildIDFromBinary(target)
} }
// Otherwise, we expect to have an archive (.a) file, // Otherwise, we expect to have an archive (.a) file,
// and we can read the build ID from the Go export data. // and we can read the build ID from the Go export data.
if !strings.HasSuffix(p.Target, ".a") { if !strings.HasSuffix(target, ".a") {
return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDUnknown} return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDUnknown}
} }
// Read just enough of the target to fetch the build ID. // Read just enough of the target to fetch the build ID.
...@@ -1891,7 +1891,7 @@ func readBuildID(p *Package) (id string, err error) { ...@@ -1891,7 +1891,7 @@ func readBuildID(p *Package) (id string, err error) {
// //
// The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none). // The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none).
// Reading the first 1024 bytes should be plenty. // Reading the first 1024 bytes should be plenty.
f, err := os.Open(p.Target) f, err := os.Open(target)
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -1904,7 +1904,7 @@ func readBuildID(p *Package) (id string, err error) { ...@@ -1904,7 +1904,7 @@ func readBuildID(p *Package) (id string, err error) {
} }
bad := func() (string, error) { bad := func() (string, error) {
return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDMalformed} return "", &os.PathError{Op: "parse", Path: target, Err: errBuildIDMalformed}
} }
// Archive header. // Archive header.
......
...@@ -545,7 +545,7 @@ func runTest(cmd *Command, args []string) { ...@@ -545,7 +545,7 @@ func runTest(cmd *Command, args []string) {
// Prepare build + run + print actions for all packages being tested. // Prepare build + run + print actions for all packages being tested.
for _, p := range pkgs { for _, p := range pkgs {
buildTest, runTest, printTest, err := b.test(p) buildTest, runTest, printTest, err := builderTest(&b, p)
if err != nil { if err != nil {
str := err.Error() str := err.Error()
if strings.HasPrefix(str, "\n") { if strings.HasPrefix(str, "\n") {
...@@ -652,11 +652,11 @@ var windowsBadWords = []string{ ...@@ -652,11 +652,11 @@ var windowsBadWords = []string{
"update", "update",
} }
func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { func builderTest(b *builder, p *Package) (buildAction, runAction, printAction *action, err error) {
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
build := b.action(modeBuild, modeBuild, p) build := b.action(modeBuild, modeBuild, p)
run := &action{p: p, deps: []*action{build}} run := &action{p: p, deps: []*action{build}}
print := &action{f: (*builder).notest, p: p, deps: []*action{run}} print := &action{f: builderNoTest, p: p, deps: []*action{run}}
return build, run, print, nil return build, run, print, nil
} }
...@@ -991,18 +991,18 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, ...@@ -991,18 +991,18 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
} else { } else {
// run test // run test
runAction = &action{ runAction = &action{
f: (*builder).runTest, f: builderRunTest,
deps: []*action{buildAction}, deps: []*action{buildAction},
p: p, p: p,
ignoreFail: true, ignoreFail: true,
} }
cleanAction := &action{ cleanAction := &action{
f: (*builder).cleanTest, f: builderCleanTest,
deps: []*action{runAction}, deps: []*action{runAction},
p: p, p: p,
} }
printAction = &action{ printAction = &action{
f: (*builder).printTest, f: builderPrintTest,
deps: []*action{cleanAction}, deps: []*action{cleanAction},
p: p, p: p,
} }
...@@ -1101,8 +1101,8 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar { ...@@ -1101,8 +1101,8 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
var noTestsToRun = []byte("\ntesting: warning: no tests to run\n") var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
// runTest is the action for running a test binary. // builderRunTest is the action for running a test binary.
func (b *builder) runTest(a *action) error { func builderRunTest(b *builder, a *action) error {
args := stringList(findExecCmd(), a.deps[0].target, testArgs) args := stringList(findExecCmd(), a.deps[0].target, testArgs)
a.testOutput = new(bytes.Buffer) a.testOutput = new(bytes.Buffer)
...@@ -1233,8 +1233,8 @@ func coveragePercentage(out []byte) string { ...@@ -1233,8 +1233,8 @@ func coveragePercentage(out []byte) string {
return fmt.Sprintf("\tcoverage: %s", matches[1]) return fmt.Sprintf("\tcoverage: %s", matches[1])
} }
// cleanTest is the action for cleaning up after a test. // builderCleanTest is the action for cleaning up after a test.
func (b *builder) cleanTest(a *action) error { func builderCleanTest(b *builder, a *action) error {
if buildWork { if buildWork {
return nil return nil
} }
...@@ -1244,8 +1244,8 @@ func (b *builder) cleanTest(a *action) error { ...@@ -1244,8 +1244,8 @@ func (b *builder) cleanTest(a *action) error {
return nil return nil
} }
// printTest is the action for printing a test result. // builderPrintTest is the action for printing a test result.
func (b *builder) printTest(a *action) error { func builderPrintTest(b *builder, a *action) error {
clean := a.deps[0] clean := a.deps[0]
run := clean.deps[0] run := clean.deps[0]
os.Stdout.Write(run.testOutput.Bytes()) os.Stdout.Write(run.testOutput.Bytes())
...@@ -1253,8 +1253,8 @@ func (b *builder) printTest(a *action) error { ...@@ -1253,8 +1253,8 @@ func (b *builder) printTest(a *action) error {
return nil return nil
} }
// notest is the action for testing a package with no test files. // builderNoTest is the action for testing a package with no test files.
func (b *builder) notest(a *action) error { func builderNoTest(b *builder, a *action) error {
fmt.Printf("? \t%s\t[no test files]\n", a.p.ImportPath) fmt.Printf("? \t%s\t[no test files]\n", a.p.ImportPath)
return nil return nil
} }
......
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