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