mirror of
https://github.com/golang/go
synced 2024-11-13 17:00:22 -07:00
cmd/go: add undocumented -debug-actiongraph flag to dump action graph
This will be useful for debugging but is intentionally undocumented and not guaranteed to persist in any particular form. Change-Id: I60710a1e94cfc2ce31fe91fc268c51985060f8df Reviewed-on: https://go-review.googlesource.com/69330 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
966c459fa4
commit
0174858c71
@ -37,6 +37,8 @@ var (
|
||||
BuildV bool // -v flag
|
||||
BuildWork bool // -work flag
|
||||
BuildX bool // -x flag
|
||||
|
||||
DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable)
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -111,7 +111,7 @@ func runRun(cmd *base.Command, args []string) {
|
||||
}
|
||||
p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
|
||||
a1 := b.Action(work.ModeBuild, work.ModeBuild, p)
|
||||
a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
|
||||
a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
|
||||
b.Do(a)
|
||||
}
|
||||
|
||||
|
@ -522,7 +522,7 @@ func runTest(cmd *base.Command, args []string) {
|
||||
}
|
||||
sort.Strings(all)
|
||||
|
||||
a := &work.Action{}
|
||||
a := &work.Action{Mode: "go test -i"}
|
||||
for _, p := range load.PackagesForBuild(all) {
|
||||
a.Deps = append(a.Deps, b.Action(work.ModeInstall, work.ModeInstall, p))
|
||||
}
|
||||
@ -599,7 +599,7 @@ func runTest(cmd *base.Command, args []string) {
|
||||
}
|
||||
|
||||
// Ultimately the goal is to print the output.
|
||||
root := &work.Action{Deps: prints}
|
||||
root := &work.Action{Mode: "go test", Deps: prints}
|
||||
|
||||
// Force the printing of results to happen in order,
|
||||
// one at a time.
|
||||
@ -652,8 +652,8 @@ var windowsBadWords = []string{
|
||||
func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) {
|
||||
if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||
build := b.Action(work.ModeBuild, work.ModeBuild, p)
|
||||
run := &work.Action{Package: p, Deps: []*work.Action{build}}
|
||||
print := &work.Action{Func: builderNoTest, Package: p, Deps: []*work.Action{run}}
|
||||
run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}}
|
||||
print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}}
|
||||
return build, run, print, nil
|
||||
}
|
||||
|
||||
@ -945,6 +945,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
}
|
||||
}
|
||||
buildAction = &work.Action{
|
||||
Mode: "test build",
|
||||
Func: work.BuildInstallFunc,
|
||||
Deps: []*work.Action{buildAction},
|
||||
Package: pmain,
|
||||
@ -953,22 +954,25 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
|
||||
runAction = buildAction // make sure runAction != nil even if not running test
|
||||
}
|
||||
if testC {
|
||||
printAction = &work.Action{Package: p, Deps: []*work.Action{runAction}} // nop
|
||||
printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}} // nop
|
||||
} else {
|
||||
// run test
|
||||
runAction = &work.Action{
|
||||
Mode: "test run",
|
||||
Func: builderRunTest,
|
||||
Deps: []*work.Action{buildAction},
|
||||
Package: p,
|
||||
IgnoreFail: true,
|
||||
}
|
||||
cleanAction := &work.Action{
|
||||
Mode: "test clean",
|
||||
Func: builderCleanTest,
|
||||
Deps: []*work.Action{runAction},
|
||||
Package: p,
|
||||
Objdir: testDir,
|
||||
}
|
||||
printAction = &work.Action{
|
||||
Mode: "test print",
|
||||
Func: builderPrintTest,
|
||||
Deps: []*work.Action{cleanAction},
|
||||
Package: p,
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"bytes"
|
||||
"container/heap"
|
||||
"debug/elf"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
@ -223,6 +224,9 @@ func AddBuildFlags(cmd *base.Command) {
|
||||
cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildContext.BuildTags), "tags", "")
|
||||
cmd.Flag.Var((*base.StringsFlag)(&cfg.BuildToolexec), "toolexec", "")
|
||||
cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
|
||||
|
||||
// Undocumented, unstable debugging flags.
|
||||
cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
|
||||
}
|
||||
|
||||
// fileExtSplit expects a filename and returns the name
|
||||
@ -471,7 +475,7 @@ func runBuild(cmd *base.Command, args []string) {
|
||||
a = b.libaction(libName, pkgs, ModeBuild, depMode)
|
||||
}
|
||||
} else {
|
||||
a = &Action{}
|
||||
a = &Action{Mode: "go build"}
|
||||
for _, p := range pkgs {
|
||||
a.Deps = append(a.Deps, b.Action(ModeBuild, depMode, p))
|
||||
}
|
||||
@ -589,7 +593,7 @@ func InstallPackages(args []string, forGet bool) {
|
||||
a = b.libaction(libName, pkgs, ModeInstall, ModeInstall)
|
||||
}
|
||||
} else {
|
||||
a = &Action{}
|
||||
a = &Action{Mode: "go install"}
|
||||
var tools []*Action
|
||||
for _, p := range pkgs {
|
||||
// During 'go get', don't attempt (and fail) to install packages with only tests.
|
||||
@ -611,6 +615,7 @@ func InstallPackages(args []string, forGet bool) {
|
||||
}
|
||||
if len(tools) > 0 {
|
||||
a = &Action{
|
||||
Mode: "go install (tools)",
|
||||
Deps: tools,
|
||||
}
|
||||
}
|
||||
@ -672,6 +677,7 @@ type Builder struct {
|
||||
|
||||
// An Action represents a single action in the action graph.
|
||||
type Action struct {
|
||||
Mode string // description of action operation
|
||||
Package *load.Package // the package this action works on
|
||||
Deps []*Action // actions that must happen before this one
|
||||
Func func(*Builder, *Action) error // the action itself (nil = no-op)
|
||||
@ -692,6 +698,21 @@ type Action struct {
|
||||
Failed bool // whether the action failed
|
||||
}
|
||||
|
||||
type actionJSON struct {
|
||||
ID int
|
||||
Mode string
|
||||
Package string
|
||||
Deps []int `json:",omitempty"`
|
||||
IgnoreFail bool `json:",omitempty"`
|
||||
Args []string `json:",omitempty"`
|
||||
Link bool `json:",omitempty"`
|
||||
Objdir string `json:",omitempty"`
|
||||
Target string `json:",omitempty"`
|
||||
Priority int `json:",omitempty"`
|
||||
Failed bool `json:",omitempty"`
|
||||
Pkgfile string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// cacheKey is the key for the action cache.
|
||||
type cacheKey struct {
|
||||
mode BuildMode
|
||||
@ -699,6 +720,57 @@ type cacheKey struct {
|
||||
shlib string
|
||||
}
|
||||
|
||||
func actionGraphJSON(a *Action) string {
|
||||
var workq []*Action
|
||||
var inWorkq = make(map[*Action]int)
|
||||
|
||||
add := func(a *Action) {
|
||||
if _, ok := inWorkq[a]; ok {
|
||||
return
|
||||
}
|
||||
inWorkq[a] = len(workq)
|
||||
workq = append(workq, a)
|
||||
}
|
||||
add(a)
|
||||
|
||||
for i := 0; i < len(workq); i++ {
|
||||
for _, dep := range workq[i].Deps {
|
||||
add(dep)
|
||||
}
|
||||
}
|
||||
|
||||
var list []*actionJSON
|
||||
for id, a := range workq {
|
||||
aj := &actionJSON{
|
||||
Mode: a.Mode,
|
||||
ID: id,
|
||||
IgnoreFail: a.IgnoreFail,
|
||||
Args: a.Args,
|
||||
Link: a.Link,
|
||||
Objdir: a.Objdir,
|
||||
Target: a.Target,
|
||||
Failed: a.Failed,
|
||||
Priority: a.priority,
|
||||
}
|
||||
if a.Package != nil {
|
||||
// TODO(rsc): Make this a unique key for a.Package somehow.
|
||||
aj.Package = a.Package.ImportPath
|
||||
aj.Pkgfile = a.Package.Internal.Pkgfile
|
||||
}
|
||||
for _, a1 := range a.Deps {
|
||||
aj.Deps = append(aj.Deps, inWorkq[a1])
|
||||
}
|
||||
list = append(list, aj)
|
||||
}
|
||||
|
||||
js, err := json.MarshalIndent(list, "", "\t")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err)
|
||||
return ""
|
||||
}
|
||||
return string(js)
|
||||
}
|
||||
|
||||
// BuildMode specifies the build mode:
|
||||
// are we just building things or also installing the results?
|
||||
type BuildMode int
|
||||
@ -827,7 +899,7 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
|
||||
return a
|
||||
}
|
||||
|
||||
a = &Action{Package: p}
|
||||
a = &Action{Mode: "???", Package: p}
|
||||
b.actionCache[key] = a
|
||||
|
||||
for _, p1 := range p.Internal.Imports {
|
||||
@ -854,11 +926,13 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
|
||||
switch p.ImportPath {
|
||||
case "builtin", "unsafe":
|
||||
// Fake packages - nothing to build.
|
||||
a.Mode = "built-in package"
|
||||
return a
|
||||
}
|
||||
// gccgo standard library is "fake" too.
|
||||
if cfg.BuildToolchainName == "gccgo" {
|
||||
// the target name is needed for cgo.
|
||||
a.Mode = "gccgo stdlib"
|
||||
a.Target = p.Internal.Target
|
||||
return a
|
||||
}
|
||||
@ -867,6 +941,7 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
|
||||
if !p.Stale && p.Internal.Target != "" {
|
||||
// p.Stale==false implies that p.Internal.Target is up-to-date.
|
||||
// Record target name for use by actions depending on this one.
|
||||
a.Mode = "use installed"
|
||||
a.Target = p.Internal.Target
|
||||
p.Internal.Pkgfile = a.Target
|
||||
return a
|
||||
@ -938,7 +1013,7 @@ func (b *Builder) action1(mode BuildMode, depMode BuildMode, p *load.Package, lo
|
||||
}
|
||||
|
||||
func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode BuildMode) *Action {
|
||||
a := &Action{}
|
||||
a := &Action{Mode: "libaction???"}
|
||||
switch mode {
|
||||
default:
|
||||
base.Fatalf("unrecognized mode %v", mode)
|
||||
@ -1046,7 +1121,7 @@ func (b *Builder) libaction(libname string, pkgs []*load.Package, mode, depMode
|
||||
if p.Internal.Target == "" {
|
||||
continue
|
||||
}
|
||||
shlibnameaction := &Action{}
|
||||
shlibnameaction := &Action{Mode: "shlibname"}
|
||||
shlibnameaction.Func = (*Builder).installShlibname
|
||||
shlibnameaction.Target = p.Internal.Target[:len(p.Internal.Target)-2] + ".shlibname"
|
||||
a.Deps = append(a.Deps, shlibnameaction)
|
||||
@ -1095,6 +1170,14 @@ func (b *Builder) Do(root *Action) {
|
||||
a.priority = i
|
||||
}
|
||||
|
||||
if cfg.DebugActiongraph != "" {
|
||||
js := actionGraphJSON(root)
|
||||
if err := ioutil.WriteFile(cfg.DebugActiongraph, []byte(js), 0666); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err)
|
||||
base.SetExitStatus(1)
|
||||
}
|
||||
}
|
||||
|
||||
b.readySema = make(chan bool, len(all))
|
||||
|
||||
// Initialize per-action execution state.
|
||||
@ -3040,7 +3123,7 @@ func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg string,
|
||||
}
|
||||
|
||||
func (tools gccgoToolchain) ldShared(b *Builder, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
|
||||
fakeRoot := &Action{}
|
||||
fakeRoot := &Action{Mode: "gccgo ldshared"}
|
||||
fakeRoot.Deps = toplevelactions
|
||||
return tools.link(b, fakeRoot, out, importcfg, allactions, "", nil, "shared", out)
|
||||
}
|
||||
@ -3673,7 +3756,7 @@ func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
|
||||
|
||||
p := load.GoFilesPackage(srcs)
|
||||
|
||||
if _, _, e := BuildToolchain.gc(b, &Action{Package: p, Objdir: objdir}, "", nil, false, srcs); e != nil {
|
||||
if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, false, srcs); e != nil {
|
||||
return "32", nil
|
||||
}
|
||||
return "64", nil
|
||||
|
Loading…
Reference in New Issue
Block a user