}
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))
}
}
// 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.
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
}
}
}
buildAction = &work.Action{
+ Mode: "test build",
Func: work.BuildInstallFunc,
Deps: []*work.Action{buildAction},
Package: pmain,
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,
"bytes"
"container/heap"
"debug/elf"
+ "encoding/json"
"errors"
"flag"
"fmt"
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
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))
}
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.
}
if len(tools) > 0 {
a = &Action{
+ Mode: "go install (tools)",
Deps: tools,
}
}
// 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)
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
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
return a
}
- a = &Action{Package: p}
+ a = &Action{Mode: "???", Package: p}
b.actionCache[key] = a
for _, p1 := range p.Internal.Imports {
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
}
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
}
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)
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)
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.
}
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)
}
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