github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/work/action.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Action graph creation (planning). 6 7 package work 8 9 import ( 10 "bufio" 11 "bytes" 12 "container/heap" 13 "context" 14 "debug/elf" 15 "encoding/json" 16 "fmt" 17 "os" 18 "path/filepath" 19 "strings" 20 "sync" 21 "time" 22 23 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 24 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cache" 25 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 26 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/load" 27 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/robustio" 28 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/trace" 29 "github.com/bir3/gocompiler/src/cmd/internal/buildid" 30 ) 31 32 // A Builder holds global state about a build. 33 // It does not hold per-package state, because we 34 // build packages in parallel, and the builder is shared. 35 type Builder struct { 36 WorkDir string // the temporary work directory (ends in filepath.Separator) 37 actionCache map[cacheKey]*Action // a cache of already-constructed actions 38 mkdirCache map[string]bool // a cache of created directories 39 flagCache map[[2]string]bool // a cache of supported compiler flags 40 gccCompilerIDCache map[string]cache.ActionID // cache for gccCompilerID 41 Print func(args ...any) (int, error) 42 43 IsCmdList bool // running as part of go list; set p.Stale and additional fields below 44 NeedError bool // list needs p.Error 45 NeedExport bool // list needs p.Export 46 NeedCompiledGoFiles bool // list needs p.CompiledGoFiles 47 AllowErrors bool // errors don't immediately exit the program 48 49 objdirSeq int // counter for NewObjdir 50 pkgSeq int 51 52 output sync.Mutex 53 scriptDir string // current directory in printed script 54 55 exec sync.Mutex 56 readySema chan bool 57 ready actionQueue 58 59 id sync.Mutex 60 toolIDCache map[string]string // tool name -> tool ID 61 buildIDCache map[string]string // file name -> build ID 62 } 63 64 // NOTE: Much of Action would not need to be exported if not for test. 65 // Maybe test functionality should move into this package too? 66 67 // An Actor runs an action. 68 type Actor interface { 69 Act(*Builder, context.Context, *Action) error 70 } 71 72 // An ActorFunc is an Actor that calls the function. 73 type ActorFunc func(*Builder, context.Context, *Action) error 74 75 func (f ActorFunc) Act(b *Builder, ctx context.Context, a *Action) error { 76 return f(b, ctx, a) 77 } 78 79 // An Action represents a single action in the action graph. 80 type Action struct { 81 Mode string // description of action operation 82 Package *load.Package // the package this action works on 83 Deps []*Action // actions that must happen before this one 84 Actor Actor // the action itself (nil = no-op) 85 IgnoreFail bool // whether to run f even if dependencies fail 86 TestOutput *bytes.Buffer // test output buffer 87 Args []string // additional args for runProgram 88 89 triggers []*Action // inverse of deps 90 91 buggyInstall bool // is this a buggy install (see -linkshared)? 92 93 TryCache func(*Builder, *Action) bool // callback for cache bypass 94 95 // Generated files, directories. 96 Objdir string // directory for intermediate objects 97 Target string // goal of the action: the created package or executable 98 built string // the actual created package or executable 99 actionID cache.ActionID // cache ID of action input 100 buildID string // build ID of action output 101 102 VetxOnly bool // Mode=="vet": only being called to supply info about dependencies 103 needVet bool // Mode=="build": need to fill in vet config 104 needBuild bool // Mode=="build": need to do actual build (can be false if needVet is true) 105 vetCfg *vetConfig // vet config 106 output []byte // output redirect buffer (nil means use b.Print) 107 108 // Execution state. 109 pending int // number of deps yet to complete 110 priority int // relative execution priority 111 Failed bool // whether the action failed 112 json *actionJSON // action graph information 113 nonGoOverlay map[string]string // map from non-.go source files to copied files in objdir. Nil if no overlay is used. 114 traceSpan *trace.Span 115 } 116 117 // BuildActionID returns the action ID section of a's build ID. 118 func (a *Action) BuildActionID() string { return actionID(a.buildID) } 119 120 // BuildContentID returns the content ID section of a's build ID. 121 func (a *Action) BuildContentID() string { return contentID(a.buildID) } 122 123 // BuildID returns a's build ID. 124 func (a *Action) BuildID() string { return a.buildID } 125 126 // BuiltTarget returns the actual file that was built. This differs 127 // from Target when the result was cached. 128 func (a *Action) BuiltTarget() string { return a.built } 129 130 // An actionQueue is a priority queue of actions. 131 type actionQueue []*Action 132 133 // Implement heap.Interface 134 func (q *actionQueue) Len() int { return len(*q) } 135 func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] } 136 func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority } 137 func (q *actionQueue) Push(x any) { *q = append(*q, x.(*Action)) } 138 func (q *actionQueue) Pop() any { 139 n := len(*q) - 1 140 x := (*q)[n] 141 *q = (*q)[:n] 142 return x 143 } 144 145 func (q *actionQueue) push(a *Action) { 146 if a.json != nil { 147 a.json.TimeReady = time.Now() 148 } 149 heap.Push(q, a) 150 } 151 152 func (q *actionQueue) pop() *Action { 153 return heap.Pop(q).(*Action) 154 } 155 156 type actionJSON struct { 157 ID int 158 Mode string 159 Package string 160 Deps []int `json:",omitempty"` 161 IgnoreFail bool `json:",omitempty"` 162 Args []string `json:",omitempty"` 163 Link bool `json:",omitempty"` 164 Objdir string `json:",omitempty"` 165 Target string `json:",omitempty"` 166 Priority int `json:",omitempty"` 167 Failed bool `json:",omitempty"` 168 Built string `json:",omitempty"` 169 VetxOnly bool `json:",omitempty"` 170 NeedVet bool `json:",omitempty"` 171 NeedBuild bool `json:",omitempty"` 172 ActionID string `json:",omitempty"` 173 BuildID string `json:",omitempty"` 174 TimeReady time.Time `json:",omitempty"` 175 TimeStart time.Time `json:",omitempty"` 176 TimeDone time.Time `json:",omitempty"` 177 178 Cmd []string // `json:",omitempty"` 179 CmdReal time.Duration `json:",omitempty"` 180 CmdUser time.Duration `json:",omitempty"` 181 CmdSys time.Duration `json:",omitempty"` 182 } 183 184 // cacheKey is the key for the action cache. 185 type cacheKey struct { 186 mode string 187 p *load.Package 188 } 189 190 func actionGraphJSON(a *Action) string { 191 var workq []*Action 192 var inWorkq = make(map[*Action]int) 193 194 add := func(a *Action) { 195 if _, ok := inWorkq[a]; ok { 196 return 197 } 198 inWorkq[a] = len(workq) 199 workq = append(workq, a) 200 } 201 add(a) 202 203 for i := 0; i < len(workq); i++ { 204 for _, dep := range workq[i].Deps { 205 add(dep) 206 } 207 } 208 209 var list []*actionJSON 210 for id, a := range workq { 211 if a.json == nil { 212 a.json = &actionJSON{ 213 Mode: a.Mode, 214 ID: id, 215 IgnoreFail: a.IgnoreFail, 216 Args: a.Args, 217 Objdir: a.Objdir, 218 Target: a.Target, 219 Failed: a.Failed, 220 Priority: a.priority, 221 Built: a.built, 222 VetxOnly: a.VetxOnly, 223 NeedBuild: a.needBuild, 224 NeedVet: a.needVet, 225 } 226 if a.Package != nil { 227 // TODO(rsc): Make this a unique key for a.Package somehow. 228 a.json.Package = a.Package.ImportPath 229 } 230 for _, a1 := range a.Deps { 231 a.json.Deps = append(a.json.Deps, inWorkq[a1]) 232 } 233 } 234 list = append(list, a.json) 235 } 236 237 js, err := json.MarshalIndent(list, "", "\t") 238 if err != nil { 239 fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err) 240 return "" 241 } 242 return string(js) 243 } 244 245 // BuildMode specifies the build mode: 246 // are we just building things or also installing the results? 247 type BuildMode int 248 249 const ( 250 ModeBuild BuildMode = iota 251 ModeInstall 252 ModeBuggyInstall 253 254 ModeVetOnly = 1 << 8 255 ) 256 257 // NewBuilder returns a new Builder ready for use. 258 // 259 // If workDir is the empty string, NewBuilder creates a WorkDir if needed 260 // and arranges for it to be removed in case of an unclean exit. 261 // The caller must Close the builder explicitly to clean up the WorkDir 262 // before a clean exit. 263 func NewBuilder(workDir string) *Builder { 264 b := new(Builder) 265 266 b.Print = func(a ...any) (int, error) { 267 return fmt.Fprint(os.Stderr, a...) 268 } 269 b.actionCache = make(map[cacheKey]*Action) 270 b.mkdirCache = make(map[string]bool) 271 b.toolIDCache = make(map[string]string) 272 b.buildIDCache = make(map[string]string) 273 274 if workDir != "" { 275 b.WorkDir = workDir 276 } else if cfg.BuildN { 277 b.WorkDir = "$WORK" 278 } else { 279 if !buildInitStarted { 280 panic("internal error: NewBuilder called before BuildInit") 281 } 282 tmp, err := os.MkdirTemp(cfg.Getenv("GOTMPDIR"), "go-build") 283 if err != nil { 284 base.Fatalf("go: creating work dir: %v", err) 285 } 286 if !filepath.IsAbs(tmp) { 287 abs, err := filepath.Abs(tmp) 288 if err != nil { 289 os.RemoveAll(tmp) 290 base.Fatalf("go: creating work dir: %v", err) 291 } 292 tmp = abs 293 } 294 b.WorkDir = tmp 295 builderWorkDirs.Store(b, b.WorkDir) 296 if cfg.BuildX || cfg.BuildWork { 297 fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir) 298 } 299 } 300 301 if err := CheckGOOSARCHPair(cfg.Goos, cfg.Goarch); err != nil { 302 fmt.Fprintf(os.Stderr, "go: %v\n", err) 303 base.SetExitStatus(2) 304 base.Exit() 305 } 306 307 for _, tag := range cfg.BuildContext.BuildTags { 308 if strings.Contains(tag, ",") { 309 fmt.Fprintf(os.Stderr, "go: -tags space-separated list contains comma\n") 310 base.SetExitStatus(2) 311 base.Exit() 312 } 313 } 314 315 return b 316 } 317 318 var builderWorkDirs sync.Map // *Builder → WorkDir 319 320 func (b *Builder) Close() error { 321 wd, ok := builderWorkDirs.Load(b) 322 if !ok { 323 return nil 324 } 325 defer builderWorkDirs.Delete(b) 326 327 if b.WorkDir != wd.(string) { 328 base.Errorf("go: internal error: Builder WorkDir unexpectedly changed from %s to %s", wd, b.WorkDir) 329 } 330 331 if !cfg.BuildWork { 332 if err := robustio.RemoveAll(b.WorkDir); err != nil { 333 return err 334 } 335 } 336 b.WorkDir = "" 337 return nil 338 } 339 340 func closeBuilders() { 341 leakedBuilders := 0 342 builderWorkDirs.Range(func(bi, _ any) bool { 343 leakedBuilders++ 344 if err := bi.(*Builder).Close(); err != nil { 345 base.Errorf("go: %v", err) 346 } 347 return true 348 }) 349 350 if leakedBuilders > 0 && base.GetExitStatus() == 0 { 351 fmt.Fprintf(os.Stderr, "go: internal error: Builder leaked on successful exit\n") 352 base.SetExitStatus(1) 353 } 354 } 355 356 func CheckGOOSARCHPair(goos, goarch string) error { 357 if _, ok := cfg.OSArchSupportsCgo[goos+"/"+goarch]; !ok && cfg.BuildContext.Compiler == "gc" { 358 return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch) 359 } 360 return nil 361 } 362 363 // NewObjdir returns the name of a fresh object directory under b.WorkDir. 364 // It is up to the caller to call b.Mkdir on the result at an appropriate time. 365 // The result ends in a slash, so that file names in that directory 366 // can be constructed with direct string addition. 367 // 368 // NewObjdir must be called only from a single goroutine at a time, 369 // so it is safe to call during action graph construction, but it must not 370 // be called during action graph execution. 371 func (b *Builder) NewObjdir() string { 372 b.objdirSeq++ 373 return filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)) + string(filepath.Separator) 374 } 375 376 // readpkglist returns the list of packages that were built into the shared library 377 // at shlibpath. For the native toolchain this list is stored, newline separated, in 378 // an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the 379 // .go_export section. 380 func readpkglist(shlibpath string) (pkgs []*load.Package) { 381 var stk load.ImportStack 382 if cfg.BuildToolchainName == "gccgo" { 383 f, _ := elf.Open(shlibpath) 384 sect := f.Section(".go_export") 385 data, _ := sect.Data() 386 scanner := bufio.NewScanner(bytes.NewBuffer(data)) 387 for scanner.Scan() { 388 t := scanner.Text() 389 var found bool 390 if t, found = strings.CutPrefix(t, "pkgpath "); found { 391 t = strings.TrimSuffix(t, ";") 392 pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd(), nil, &stk, nil, 0)) 393 } 394 } 395 } else { 396 pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1) 397 if err != nil { 398 base.Fatalf("readELFNote failed: %v", err) 399 } 400 scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) 401 for scanner.Scan() { 402 t := scanner.Text() 403 pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd(), nil, &stk, nil, 0)) 404 } 405 } 406 return 407 } 408 409 // cacheAction looks up {mode, p} in the cache and returns the resulting action. 410 // If the cache has no such action, f() is recorded and returned. 411 // TODO(rsc): Change the second key from *load.Package to interface{}, 412 // to make the caching in linkShared less awkward? 413 func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *Action { 414 a := b.actionCache[cacheKey{mode, p}] 415 if a == nil { 416 a = f() 417 b.actionCache[cacheKey{mode, p}] = a 418 } 419 return a 420 } 421 422 // AutoAction returns the "right" action for go build or go install of p. 423 func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action { 424 if p.Name == "main" { 425 return b.LinkAction(mode, depMode, p) 426 } 427 return b.CompileAction(mode, depMode, p) 428 } 429 430 // CompileAction returns the action for compiling and possibly installing 431 // (according to mode) the given package. The resulting action is only 432 // for building packages (archives), never for linking executables. 433 // depMode is the action (build or install) to use when building dependencies. 434 // To turn package main into an executable, call b.Link instead. 435 func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action { 436 vetOnly := mode&ModeVetOnly != 0 437 mode &^= ModeVetOnly 438 439 if mode != ModeBuild && p.Target == "" { 440 // No permanent target. 441 mode = ModeBuild 442 } 443 if mode != ModeBuild && p.Name == "main" { 444 // We never install the .a file for a main package. 445 mode = ModeBuild 446 } 447 448 // Construct package build action. 449 a := b.cacheAction("build", p, func() *Action { 450 a := &Action{ 451 Mode: "build", 452 Package: p, 453 Actor: ActorFunc((*Builder).build), 454 Objdir: b.NewObjdir(), 455 } 456 457 if p.Error == nil || !p.Error.IsImportCycle { 458 for _, p1 := range p.Internal.Imports { 459 a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1)) 460 } 461 } 462 463 if p.Standard { 464 switch p.ImportPath { 465 case "builtin", "unsafe": 466 // Fake packages - nothing to build. 467 a.Mode = "built-in package" 468 a.Actor = nil 469 return a 470 } 471 472 // gccgo standard library is "fake" too. 473 if cfg.BuildToolchainName == "gccgo" { 474 // the target name is needed for cgo. 475 a.Mode = "gccgo stdlib" 476 a.Target = p.Target 477 a.Actor = nil 478 return a 479 } 480 } 481 482 return a 483 }) 484 485 // Find the build action; the cache entry may have been replaced 486 // by the install action during (*Builder).installAction. 487 buildAction := a 488 switch buildAction.Mode { 489 case "build", "built-in package", "gccgo stdlib": 490 // ok 491 case "build-install": 492 buildAction = a.Deps[0] 493 default: 494 panic("lost build action: " + buildAction.Mode) 495 } 496 buildAction.needBuild = buildAction.needBuild || !vetOnly 497 498 // Construct install action. 499 if mode == ModeInstall || mode == ModeBuggyInstall { 500 a = b.installAction(a, mode) 501 } 502 503 return a 504 } 505 506 // VetAction returns the action for running go vet on package p. 507 // It depends on the action for compiling p. 508 // If the caller may be causing p to be installed, it is up to the caller 509 // to make sure that the install depends on (runs after) vet. 510 func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { 511 a := b.vetAction(mode, depMode, p) 512 a.VetxOnly = false 513 return a 514 } 515 516 func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { 517 // Construct vet action. 518 a := b.cacheAction("vet", p, func() *Action { 519 a1 := b.CompileAction(mode|ModeVetOnly, depMode, p) 520 521 // vet expects to be able to import "fmt". 522 var stk load.ImportStack 523 stk.Push("vet") 524 p1 := load.LoadImportWithFlags("fmt", p.Dir, p, &stk, nil, 0) 525 stk.Pop() 526 aFmt := b.CompileAction(ModeBuild, depMode, p1) 527 528 var deps []*Action 529 if a1.buggyInstall { 530 // (*Builder).vet expects deps[0] to be the package 531 // and deps[1] to be "fmt". If we see buggyInstall 532 // here then a1 is an install of a shared library, 533 // and the real package is a1.Deps[0]. 534 deps = []*Action{a1.Deps[0], aFmt, a1} 535 } else { 536 deps = []*Action{a1, aFmt} 537 } 538 for _, p1 := range p.Internal.Imports { 539 deps = append(deps, b.vetAction(mode, depMode, p1)) 540 } 541 542 a := &Action{ 543 Mode: "vet", 544 Package: p, 545 Deps: deps, 546 Objdir: a1.Objdir, 547 VetxOnly: true, 548 IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems) 549 } 550 if a1.Actor == nil { 551 // Built-in packages like unsafe. 552 return a 553 } 554 deps[0].needVet = true 555 a.Actor = ActorFunc((*Builder).vet) 556 return a 557 }) 558 return a 559 } 560 561 // LinkAction returns the action for linking p into an executable 562 // and possibly installing the result (according to mode). 563 // depMode is the action (build or install) to use when compiling dependencies. 564 func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action { 565 // Construct link action. 566 a := b.cacheAction("link", p, func() *Action { 567 a := &Action{ 568 Mode: "link", 569 Package: p, 570 } 571 572 a1 := b.CompileAction(ModeBuild, depMode, p) 573 a.Actor = ActorFunc((*Builder).link) 574 a.Deps = []*Action{a1} 575 a.Objdir = a1.Objdir 576 577 // An executable file. (This is the name of a temporary file.) 578 // Because we run the temporary file in 'go run' and 'go test', 579 // the name will show up in ps listings. If the caller has specified 580 // a name, use that instead of a.out. The binary is generated 581 // in an otherwise empty subdirectory named exe to avoid 582 // naming conflicts. The only possible conflict is if we were 583 // to create a top-level package named exe. 584 name := "a.out" 585 if p.Internal.ExeName != "" { 586 name = p.Internal.ExeName 587 } else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" { 588 // On OS X, the linker output name gets recorded in the 589 // shared library's LC_ID_DYLIB load command. 590 // The code invoking the linker knows to pass only the final 591 // path element. Arrange that the path element matches what 592 // we'll install it as; otherwise the library is only loadable as "a.out". 593 // On Windows, DLL file name is recorded in PE file 594 // export section, so do like on OS X. 595 _, name = filepath.Split(p.Target) 596 } 597 a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix 598 a.built = a.Target 599 b.addTransitiveLinkDeps(a, a1, "") 600 601 // Sequence the build of the main package (a1) strictly after the build 602 // of all other dependencies that go into the link. It is likely to be after 603 // them anyway, but just make sure. This is required by the build ID-based 604 // shortcut in (*Builder).useCache(a1), which will call b.linkActionID(a). 605 // In order for that linkActionID call to compute the right action ID, all the 606 // dependencies of a (except a1) must have completed building and have 607 // recorded their build IDs. 608 a1.Deps = append(a1.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]}) 609 return a 610 }) 611 612 if mode == ModeInstall || mode == ModeBuggyInstall { 613 a = b.installAction(a, mode) 614 } 615 616 return a 617 } 618 619 // installAction returns the action for installing the result of a1. 620 func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action { 621 // Because we overwrite the build action with the install action below, 622 // a1 may already be an install action fetched from the "build" cache key, 623 // and the caller just doesn't realize. 624 if strings.HasSuffix(a1.Mode, "-install") { 625 if a1.buggyInstall && mode == ModeInstall { 626 // Congratulations! The buggy install is now a proper install. 627 a1.buggyInstall = false 628 } 629 return a1 630 } 631 632 // If there's no actual action to build a1, 633 // there's nothing to install either. 634 // This happens if a1 corresponds to reusing an already-built object. 635 if a1.Actor == nil { 636 return a1 637 } 638 639 p := a1.Package 640 return b.cacheAction(a1.Mode+"-install", p, func() *Action { 641 // The install deletes the temporary build result, 642 // so we need all other actions, both past and future, 643 // that attempt to depend on the build to depend instead 644 // on the install. 645 646 // Make a private copy of a1 (the build action), 647 // no longer accessible to any other rules. 648 buildAction := new(Action) 649 *buildAction = *a1 650 651 // Overwrite a1 with the install action. 652 // This takes care of updating past actions that 653 // point at a1 for the build action; now they will 654 // point at a1 and get the install action. 655 // We also leave a1 in the action cache as the result 656 // for "build", so that actions not yet created that 657 // try to depend on the build will instead depend 658 // on the install. 659 *a1 = Action{ 660 Mode: buildAction.Mode + "-install", 661 Actor: ActorFunc(BuildInstallFunc), 662 Package: p, 663 Objdir: buildAction.Objdir, 664 Deps: []*Action{buildAction}, 665 Target: p.Target, 666 built: p.Target, 667 668 buggyInstall: mode == ModeBuggyInstall, 669 } 670 671 b.addInstallHeaderAction(a1) 672 return a1 673 }) 674 } 675 676 // addTransitiveLinkDeps adds to the link action a all packages 677 // that are transitive dependencies of a1.Deps. 678 // That is, if a is a link of package main, a1 is the compile of package main 679 // and a1.Deps is the actions for building packages directly imported by 680 // package main (what the compiler needs). The linker needs all packages 681 // transitively imported by the whole program; addTransitiveLinkDeps 682 // makes sure those are present in a.Deps. 683 // If shlib is non-empty, then a corresponds to the build and installation of shlib, 684 // so any rebuild of shlib should not be added as a dependency. 685 func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) { 686 // Expand Deps to include all built packages, for the linker. 687 // Use breadth-first search to find rebuilt-for-test packages 688 // before the standard ones. 689 // TODO(rsc): Eliminate the standard ones from the action graph, 690 // which will require doing a little bit more rebuilding. 691 workq := []*Action{a1} 692 haveDep := map[string]bool{} 693 if a1.Package != nil { 694 haveDep[a1.Package.ImportPath] = true 695 } 696 for i := 0; i < len(workq); i++ { 697 a1 := workq[i] 698 for _, a2 := range a1.Deps { 699 // TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles. 700 if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] { 701 continue 702 } 703 haveDep[a2.Package.ImportPath] = true 704 a.Deps = append(a.Deps, a2) 705 if a2.Mode == "build-install" { 706 a2 = a2.Deps[0] // walk children of "build" action 707 } 708 workq = append(workq, a2) 709 } 710 } 711 712 // If this is go build -linkshared, then the link depends on the shared libraries 713 // in addition to the packages themselves. (The compile steps do not.) 714 if cfg.BuildLinkshared { 715 haveShlib := map[string]bool{shlib: true} 716 for _, a1 := range a.Deps { 717 p1 := a1.Package 718 if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] { 719 continue 720 } 721 haveShlib[filepath.Base(p1.Shlib)] = true 722 // TODO(rsc): The use of ModeInstall here is suspect, but if we only do ModeBuild, 723 // we'll end up building an overall library or executable that depends at runtime 724 // on other libraries that are out-of-date, which is clearly not good either. 725 // We call it ModeBuggyInstall to make clear that this is not right. 726 a.Deps = append(a.Deps, b.linkSharedAction(ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil)) 727 } 728 } 729 } 730 731 // addInstallHeaderAction adds an install header action to a, if needed. 732 // The action a should be an install action as generated by either 733 // b.CompileAction or b.LinkAction with mode=ModeInstall, 734 // and so a.Deps[0] is the corresponding build action. 735 func (b *Builder) addInstallHeaderAction(a *Action) { 736 // Install header for cgo in c-archive and c-shared modes. 737 p := a.Package 738 if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { 739 hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h" 740 if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" { 741 // For the header file, remove the "lib" 742 // added by go/build, so we generate pkg.h 743 // rather than libpkg.h. 744 dir, file := filepath.Split(hdrTarget) 745 file = strings.TrimPrefix(file, "lib") 746 hdrTarget = filepath.Join(dir, file) 747 } 748 ah := &Action{ 749 Mode: "install header", 750 Package: a.Package, 751 Deps: []*Action{a.Deps[0]}, 752 Actor: ActorFunc((*Builder).installHeader), 753 Objdir: a.Deps[0].Objdir, 754 Target: hdrTarget, 755 } 756 a.Deps = append(a.Deps, ah) 757 } 758 } 759 760 // buildmodeShared takes the "go build" action a1 into the building of a shared library of a1.Deps. 761 // That is, the input a1 represents "go build pkgs" and the result represents "go build -buildmode=shared pkgs". 762 func (b *Builder) buildmodeShared(mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action { 763 name, err := libname(args, pkgs) 764 if err != nil { 765 base.Fatalf("%v", err) 766 } 767 return b.linkSharedAction(mode, depMode, name, a1) 768 } 769 770 // linkSharedAction takes a grouping action a1 corresponding to a list of built packages 771 // and returns an action that links them together into a shared library with the name shlib. 772 // If a1 is nil, shlib should be an absolute path to an existing shared library, 773 // and then linkSharedAction reads that library to find out the package list. 774 func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Action) *Action { 775 fullShlib := shlib 776 shlib = filepath.Base(shlib) 777 a := b.cacheAction("build-shlib "+shlib, nil, func() *Action { 778 if a1 == nil { 779 // TODO(rsc): Need to find some other place to store config, 780 // not in pkg directory. See golang.org/issue/22196. 781 pkgs := readpkglist(fullShlib) 782 a1 = &Action{ 783 Mode: "shlib packages", 784 } 785 for _, p := range pkgs { 786 a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p)) 787 } 788 } 789 790 // Fake package to hold ldflags. 791 // As usual shared libraries are a kludgy, abstraction-violating special case: 792 // we let them use the flags specified for the command-line arguments. 793 p := &load.Package{} 794 p.Internal.CmdlinePkg = true 795 p.Internal.Ldflags = load.BuildLdflags.For(p) 796 p.Internal.Gccgoflags = load.BuildGccgoflags.For(p) 797 798 // Add implicit dependencies to pkgs list. 799 // Currently buildmode=shared forces external linking mode, and 800 // external linking mode forces an import of runtime/cgo (and 801 // math on arm). So if it was not passed on the command line and 802 // it is not present in another shared library, add it here. 803 // TODO(rsc): Maybe this should only happen if "runtime" is in the original package set. 804 // TODO(rsc): This should probably be changed to use load.LinkerDeps(p). 805 // TODO(rsc): We don't add standard library imports for gccgo 806 // because they are all always linked in anyhow. 807 // Maybe load.LinkerDeps should be used and updated. 808 a := &Action{ 809 Mode: "go build -buildmode=shared", 810 Package: p, 811 Objdir: b.NewObjdir(), 812 Actor: ActorFunc((*Builder).linkShared), 813 Deps: []*Action{a1}, 814 } 815 a.Target = filepath.Join(a.Objdir, shlib) 816 if cfg.BuildToolchainName != "gccgo" { 817 add := func(a1 *Action, pkg string, force bool) { 818 for _, a2 := range a1.Deps { 819 if a2.Package != nil && a2.Package.ImportPath == pkg { 820 return 821 } 822 } 823 var stk load.ImportStack 824 p := load.LoadImportWithFlags(pkg, base.Cwd(), nil, &stk, nil, 0) 825 if p.Error != nil { 826 base.Fatalf("load %s: %v", pkg, p.Error) 827 } 828 // Assume that if pkg (runtime/cgo or math) 829 // is already accounted for in a different shared library, 830 // then that shared library also contains runtime, 831 // so that anything we do will depend on that library, 832 // so we don't need to include pkg in our shared library. 833 if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg { 834 a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p)) 835 } 836 } 837 add(a1, "runtime/cgo", false) 838 if cfg.Goarch == "arm" { 839 add(a1, "math", false) 840 } 841 842 // The linker step still needs all the usual linker deps. 843 // (For example, the linker always opens runtime.a.) 844 for _, dep := range load.LinkerDeps(nil) { 845 add(a, dep, true) 846 } 847 } 848 b.addTransitiveLinkDeps(a, a1, shlib) 849 return a 850 }) 851 852 // Install result. 853 if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Actor != nil { 854 buildAction := a 855 856 a = b.cacheAction("install-shlib "+shlib, nil, func() *Action { 857 // Determine the eventual install target. 858 // The install target is root/pkg/shlib, where root is the source root 859 // in which all the packages lie. 860 // TODO(rsc): Perhaps this cross-root check should apply to the full 861 // transitive package dependency list, not just the ones named 862 // on the command line? 863 pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot 864 for _, a2 := range a1.Deps { 865 if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir { 866 base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s", 867 a1.Deps[0].Package.ImportPath, 868 a2.Package.ImportPath, 869 pkgDir, 870 dir) 871 } 872 } 873 // TODO(rsc): Find out and explain here why gccgo is different. 874 if cfg.BuildToolchainName == "gccgo" { 875 pkgDir = filepath.Join(pkgDir, "shlibs") 876 } 877 target := filepath.Join(pkgDir, shlib) 878 879 a := &Action{ 880 Mode: "go install -buildmode=shared", 881 Objdir: buildAction.Objdir, 882 Actor: ActorFunc(BuildInstallFunc), 883 Deps: []*Action{buildAction}, 884 Target: target, 885 } 886 for _, a2 := range buildAction.Deps[0].Deps { 887 p := a2.Package 888 pkgTargetRoot := p.Internal.Build.PkgTargetRoot 889 if pkgTargetRoot == "" { 890 continue 891 } 892 a.Deps = append(a.Deps, &Action{ 893 Mode: "shlibname", 894 Package: p, 895 Actor: ActorFunc((*Builder).installShlibname), 896 Target: filepath.Join(pkgTargetRoot, p.ImportPath+".shlibname"), 897 Deps: []*Action{a.Deps[0]}, 898 }) 899 } 900 return a 901 }) 902 } 903 904 return a 905 }