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