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