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.
5 // Action graph creation (planning).
23 "cmd/go/internal/base"
24 "cmd/go/internal/cache"
26 "cmd/go/internal/load"
27 "cmd/internal/buildid"
30 // A Builder holds global state about a build.
31 // It does not hold per-package state, because we
32 // build packages in parallel, and the builder is shared.
34 WorkDir
string // the temporary work directory (ends in filepath.Separator)
35 actionCache
map[cacheKey
]*Action
// a cache of already-constructed actions
36 mkdirCache
map[string]bool // a cache of created directories
37 flagCache
map[[2]string]bool // a cache of supported compiler flags
38 Print
func(args
...interface{}) (int, error
)
40 ComputeStaleOnly
bool // compute staleness for go list; no actual build
42 objdirSeq
int // counter for NewObjdir
46 scriptDir
string // current directory in printed script
53 toolIDCache
map[string]string // tool name -> tool ID
54 buildIDCache
map[string]string // file name -> build ID
57 // NOTE: Much of Action would not need to be exported if not for test.
58 // Maybe test functionality should move into this package too?
60 // An Action represents a single action in the action graph.
62 Mode
string // description of action operation
63 Package
*load
.Package
// the package this action works on
64 Deps
[]*Action
// actions that must happen before this one
65 Func
func(*Builder
, *Action
) error
// the action itself (nil = no-op)
66 IgnoreFail
bool // whether to run f even if dependencies fail
67 TestOutput
*bytes
.Buffer
// test output buffer
68 Args
[]string // additional args for runProgram
70 triggers
[]*Action
// inverse of deps
72 buggyInstall
bool // is this a buggy install (see -linkshared)?
74 TryCache
func(*Builder
, *Action
) bool // callback for cache bypass
76 // Generated files, directories.
77 Objdir
string // directory for intermediate objects
78 Target
string // goal of the action: the created package or executable
79 built
string // the actual created package or executable
80 actionID cache
.ActionID
// cache ID of action input
81 buildID
string // build ID of action output
83 needVet
bool // Mode=="build": need to fill in vet config
84 vetCfg
*vetConfig
// vet config
85 output
[]byte // output redirect buffer (nil means use b.Print)
88 pending
int // number of deps yet to complete
89 priority
int // relative execution priority
90 Failed
bool // whether the action failed
93 // BuildActionID returns the action ID section of a's build ID.
94 func (a
*Action
) BuildActionID() string { return actionID(a
.buildID
) }
96 // BuildContentID returns the content ID section of a's build ID.
97 func (a
*Action
) BuildContentID() string { return contentID(a
.buildID
) }
99 // BuildID returns a's build ID.
100 func (a
*Action
) BuildID() string { return a
.buildID
}
102 // BuiltTarget returns the actual file that was built. This differs
103 // from Target when the result was cached.
104 func (a
*Action
) BuiltTarget() string { return a
.built
}
106 // An actionQueue is a priority queue of actions.
107 type actionQueue
[]*Action
109 // Implement heap.Interface
110 func (q
*actionQueue
) Len() int { return len(*q
) }
111 func (q
*actionQueue
) Swap(i
, j
int) { (*q
)[i
], (*q
)[j
] = (*q
)[j
], (*q
)[i
] }
112 func (q
*actionQueue
) Less(i
, j
int) bool { return (*q
)[i
].priority
< (*q
)[j
].priority
}
113 func (q
*actionQueue
) Push(x
interface{}) { *q
= append(*q
, x
.(*Action
)) }
114 func (q
*actionQueue
) Pop() interface{} {
121 func (q
*actionQueue
) push(a
*Action
) {
125 func (q
*actionQueue
) pop() *Action
{
126 return heap
.Pop(q
).(*Action
)
129 type actionJSON
struct {
133 Deps
[]int `json:",omitempty"`
134 IgnoreFail
bool `json:",omitempty"`
135 Args
[]string `json:",omitempty"`
136 Link
bool `json:",omitempty"`
137 Objdir
string `json:",omitempty"`
138 Target
string `json:",omitempty"`
139 Priority
int `json:",omitempty"`
140 Failed
bool `json:",omitempty"`
141 Built
string `json:",omitempty"`
144 // cacheKey is the key for the action cache.
145 type cacheKey
struct {
150 func actionGraphJSON(a
*Action
) string {
152 var inWorkq
= make(map[*Action
]int)
154 add
:= func(a
*Action
) {
155 if _
, ok
:= inWorkq
[a
]; ok
{
158 inWorkq
[a
] = len(workq
)
159 workq
= append(workq
, a
)
163 for i
:= 0; i
< len(workq
); i
++ {
164 for _
, dep
:= range workq
[i
].Deps
{
169 var list
[]*actionJSON
170 for id
, a
:= range workq
{
174 IgnoreFail
: a
.IgnoreFail
,
179 Priority
: a
.priority
,
182 if a
.Package
!= nil {
183 // TODO(rsc): Make this a unique key for a.Package somehow.
184 aj
.Package
= a
.Package
.ImportPath
186 for _
, a1
:= range a
.Deps
{
187 aj
.Deps
= append(aj
.Deps
, inWorkq
[a1
])
189 list
= append(list
, aj
)
192 js
, err
:= json
.MarshalIndent(list
, "", "\t")
194 fmt
.Fprintf(os
.Stderr
, "go: writing debug action graph: %v\n", err
)
200 // BuildMode specifies the build mode:
201 // are we just building things or also installing the results?
205 ModeBuild BuildMode
= iota
210 func (b
*Builder
) Init() {
212 b
.Print
= func(a
...interface{}) (int, error
) {
213 return fmt
.Fprint(os
.Stderr
, a
...)
215 b
.actionCache
= make(map[cacheKey
]*Action
)
216 b
.mkdirCache
= make(map[string]bool)
217 b
.toolIDCache
= make(map[string]string)
218 b
.buildIDCache
= make(map[string]string)
223 b
.WorkDir
, err
= ioutil
.TempDir(os
.Getenv("GOTMPDIR"), "go-build")
225 base
.Fatalf("%s", err
)
227 if cfg
.BuildX || cfg
.BuildWork
{
228 fmt
.Fprintf(os
.Stderr
, "WORK=%s\n", b
.WorkDir
)
232 base
.AtExit(func() { os
.RemoveAll(workdir
) })
236 if _
, ok
:= cfg
.OSArchSupportsCgo
[cfg
.Goos
+"/"+cfg
.Goarch
]; !ok
&& cfg
.BuildContext
.Compiler
== "gc" {
237 fmt
.Fprintf(os
.Stderr
, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", cfg
.Goos
, cfg
.Goarch
)
240 for _
, tag
:= range cfg
.BuildContext
.BuildTags
{
241 if strings
.Contains(tag
, ",") {
242 fmt
.Fprintf(os
.Stderr
, "cmd/go: -tags space-separated list contains comma\n")
248 // NewObjdir returns the name of a fresh object directory under b.WorkDir.
249 // It is up to the caller to call b.Mkdir on the result at an appropriate time.
250 // The result ends in a slash, so that file names in that directory
251 // can be constructed with direct string addition.
253 // NewObjdir must be called only from a single goroutine at a time,
254 // so it is safe to call during action graph construction, but it must not
255 // be called during action graph execution.
256 func (b
*Builder
) NewObjdir() string {
258 return filepath
.Join(b
.WorkDir
, fmt
.Sprintf("b%03d", b
.objdirSeq
)) + string(filepath
.Separator
)
261 // readpkglist returns the list of packages that were built into the shared library
262 // at shlibpath. For the native toolchain this list is stored, newline separated, in
263 // an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
264 // .go_export section.
265 func readpkglist(shlibpath
string) (pkgs
[]*load
.Package
) {
266 var stk load
.ImportStack
267 if cfg
.BuildToolchainName
== "gccgo" {
269 if f
, err
:= elf
.Open(shlibpath
); err
== nil {
270 sect
:= f
.Section(".go_export")
271 data
, _
= sect
.Data()
272 } else if f
, err
:= xcoff
.Open(shlibpath
); err
== nil {
273 data
= f
.CSect(".go_export")
275 scanner
:= bufio
.NewScanner(bytes
.NewBuffer(data
))
278 if strings
.HasPrefix(t
, "pkgpath ") {
279 t
= strings
.TrimPrefix(t
, "pkgpath ")
280 t
= strings
.TrimSuffix(t
, ";")
281 pkgs
= append(pkgs
, load
.LoadPackage(t
, &stk
))
285 pkglistbytes
, err
:= buildid
.ReadELFNote(shlibpath
, "Go\x00\x00", 1)
287 base
.Fatalf("readELFNote failed: %v", err
)
289 scanner
:= bufio
.NewScanner(bytes
.NewBuffer(pkglistbytes
))
292 pkgs
= append(pkgs
, load
.LoadPackage(t
, &stk
))
298 // cacheAction looks up {mode, p} in the cache and returns the resulting action.
299 // If the cache has no such action, f() is recorded and returned.
300 // TODO(rsc): Change the second key from *load.Package to interface{},
301 // to make the caching in linkShared less awkward?
302 func (b
*Builder
) cacheAction(mode
string, p
*load
.Package
, f
func() *Action
) *Action
{
303 a
:= b
.actionCache
[cacheKey
{mode
, p
}]
306 b
.actionCache
[cacheKey
{mode
, p
}] = a
311 // AutoAction returns the "right" action for go build or go install of p.
312 func (b
*Builder
) AutoAction(mode
, depMode BuildMode
, p
*load
.Package
) *Action
{
313 if p
.Name
== "main" {
314 return b
.LinkAction(mode
, depMode
, p
)
316 return b
.CompileAction(mode
, depMode
, p
)
319 // CompileAction returns the action for compiling and possibly installing
320 // (according to mode) the given package. The resulting action is only
321 // for building packages (archives), never for linking executables.
322 // depMode is the action (build or install) to use when building dependencies.
323 // To turn package main into an executable, call b.Link instead.
324 func (b
*Builder
) CompileAction(mode
, depMode BuildMode
, p
*load
.Package
) *Action
{
325 if mode
!= ModeBuild
&& p
.Internal
.Local
&& p
.Target
== "" {
326 // Imported via local path. No permanent target.
329 if mode
!= ModeBuild
&& p
.Name
== "main" {
330 // We never install the .a file for a main package.
334 // Construct package build action.
335 a
:= b
.cacheAction("build", p
, func() *Action
{
339 Func
: (*Builder
).build
,
340 Objdir
: b
.NewObjdir(),
343 for _
, p1
:= range p
.Internal
.Imports
{
344 a
.Deps
= append(a
.Deps
, b
.CompileAction(depMode
, depMode
, p1
))
348 switch p
.ImportPath
{
349 case "builtin", "unsafe":
350 // Fake packages - nothing to build.
351 a
.Mode
= "built-in package"
356 // gccgo standard library is "fake" too.
357 if cfg
.BuildToolchainName
== "gccgo" {
358 // the target name is needed for cgo.
359 a
.Mode
= "gccgo stdlib"
369 // Construct install action.
370 if mode
== ModeInstall || mode
== ModeBuggyInstall
{
371 a
= b
.installAction(a
, mode
)
377 // VetAction returns the action for running go vet on package p.
378 // It depends on the action for compiling p.
379 // If the caller may be causing p to be installed, it is up to the caller
380 // to make sure that the install depends on (runs after) vet.
381 func (b
*Builder
) VetAction(mode
, depMode BuildMode
, p
*load
.Package
) *Action
{
382 // Construct vet action.
383 a
:= b
.cacheAction("vet", p
, func() *Action
{
384 a1
:= b
.CompileAction(mode
, depMode
, p
)
386 // vet expects to be able to import "fmt".
387 var stk load
.ImportStack
389 p1
:= load
.LoadPackage("fmt", &stk
)
391 aFmt
:= b
.CompileAction(ModeBuild
, depMode
, p1
)
396 Deps
: []*Action
{a1
, aFmt
},
400 // Built-in packages like unsafe.
404 a
.Func
= (*Builder
).vet
411 // LinkAction returns the action for linking p into an executable
412 // and possibly installing the result (according to mode).
413 // depMode is the action (build or install) to use when compiling dependencies.
414 func (b
*Builder
) LinkAction(mode
, depMode BuildMode
, p
*load
.Package
) *Action
{
415 // Construct link action.
416 a
:= b
.cacheAction("link", p
, func() *Action
{
422 a1
:= b
.CompileAction(ModeBuild
, depMode
, p
)
423 a
.Func
= (*Builder
).link
424 a
.Deps
= []*Action
{a1
}
427 // An executable file. (This is the name of a temporary file.)
428 // Because we run the temporary file in 'go run' and 'go test',
429 // the name will show up in ps listings. If the caller has specified
430 // a name, use that instead of a.out. The binary is generated
431 // in an otherwise empty subdirectory named exe to avoid
432 // naming conflicts. The only possible conflict is if we were
433 // to create a top-level package named exe.
435 if p
.Internal
.ExeName
!= "" {
436 name
= p
.Internal
.ExeName
437 } else if (cfg
.Goos
== "darwin" || cfg
.Goos
== "windows") && cfg
.BuildBuildmode
== "c-shared" && p
.Target
!= "" {
438 // On OS X, the linker output name gets recorded in the
439 // shared library's LC_ID_DYLIB load command.
440 // The code invoking the linker knows to pass only the final
441 // path element. Arrange that the path element matches what
442 // we'll install it as; otherwise the library is only loadable as "a.out".
443 // On Windows, DLL file name is recorded in PE file
444 // export section, so do like on OS X.
445 _
, name
= filepath
.Split(p
.Target
)
447 a
.Target
= a
.Objdir
+ filepath
.Join("exe", name
) + cfg
.ExeSuffix
449 b
.addTransitiveLinkDeps(a
, a1
, "")
451 // Sequence the build of the main package (a1) strictly after the build
452 // of all other dependencies that go into the link. It is likely to be after
453 // them anyway, but just make sure. This is required by the build ID-based
454 // shortcut in (*Builder).useCache(a1), which will call b.linkActionID(a).
455 // In order for that linkActionID call to compute the right action ID, all the
456 // dependencies of a (except a1) must have completed building and have
457 // recorded their build IDs.
458 a1
.Deps
= append(a1
.Deps
, &Action
{Mode
: "nop", Deps
: a
.Deps
[1:]})
462 if mode
== ModeInstall || mode
== ModeBuggyInstall
{
463 a
= b
.installAction(a
, mode
)
469 // installAction returns the action for installing the result of a1.
470 func (b
*Builder
) installAction(a1
*Action
, mode BuildMode
) *Action
{
471 // Because we overwrite the build action with the install action below,
472 // a1 may already be an install action fetched from the "build" cache key,
473 // and the caller just doesn't realize.
474 if strings
.HasSuffix(a1
.Mode
, "-install") {
475 if a1
.buggyInstall
&& mode
== ModeInstall
{
476 // Congratulations! The buggy install is now a proper install.
477 a1
.buggyInstall
= false
482 // If there's no actual action to build a1,
483 // there's nothing to install either.
484 // This happens if a1 corresponds to reusing an already-built object.
490 return b
.cacheAction(a1
.Mode
+"-install", p
, func() *Action
{
491 // The install deletes the temporary build result,
492 // so we need all other actions, both past and future,
493 // that attempt to depend on the build to depend instead
496 // Make a private copy of a1 (the build action),
497 // no longer accessible to any other rules.
498 buildAction
:= new(Action
)
501 // Overwrite a1 with the install action.
502 // This takes care of updating past actions that
503 // point at a1 for the build action; now they will
504 // point at a1 and get the install action.
505 // We also leave a1 in the action cache as the result
506 // for "build", so that actions not yet created that
507 // try to depend on the build will instead depend
510 Mode
: buildAction
.Mode
+ "-install",
511 Func
: BuildInstallFunc
,
513 Objdir
: buildAction
.Objdir
,
514 Deps
: []*Action
{buildAction
},
518 buggyInstall
: mode
== ModeBuggyInstall
,
521 b
.addInstallHeaderAction(a1
)
526 // addTransitiveLinkDeps adds to the link action a all packages
527 // that are transitive dependencies of a1.Deps.
528 // That is, if a is a link of package main, a1 is the compile of package main
529 // and a1.Deps is the actions for building packages directly imported by
530 // package main (what the compiler needs). The linker needs all packages
531 // transitively imported by the whole program; addTransitiveLinkDeps
532 // makes sure those are present in a.Deps.
533 // If shlib is non-empty, then a corresponds to the build and installation of shlib,
534 // so any rebuild of shlib should not be added as a dependency.
535 func (b
*Builder
) addTransitiveLinkDeps(a
, a1
*Action
, shlib
string) {
536 // Expand Deps to include all built packages, for the linker.
537 // Use breadth-first search to find rebuilt-for-test packages
538 // before the standard ones.
539 // TODO(rsc): Eliminate the standard ones from the action graph,
540 // which will require doing a little bit more rebuilding.
541 workq
:= []*Action
{a1
}
542 haveDep
:= map[string]bool{}
543 if a1
.Package
!= nil {
544 haveDep
[a1
.Package
.ImportPath
] = true
546 for i
:= 0; i
< len(workq
); i
++ {
548 for _
, a2
:= range a1
.Deps
{
549 // TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles.
550 if a2
.Package
== nil ||
(a2
.Mode
!= "build-install" && a2
.Mode
!= "build") || haveDep
[a2
.Package
.ImportPath
] {
553 haveDep
[a2
.Package
.ImportPath
] = true
554 a
.Deps
= append(a
.Deps
, a2
)
555 if a2
.Mode
== "build-install" {
556 a2
= a2
.Deps
[0] // walk children of "build" action
558 workq
= append(workq
, a2
)
562 // If this is go build -linkshared, then the link depends on the shared libraries
563 // in addition to the packages themselves. (The compile steps do not.)
564 if cfg
.BuildLinkshared
{
565 haveShlib
:= map[string]bool{shlib
: true}
566 for _
, a1
:= range a
.Deps
{
568 if p1
== nil || p1
.Shlib
== "" || haveShlib
[filepath
.Base(p1
.Shlib
)] {
571 haveShlib
[filepath
.Base(p1
.Shlib
)] = true
572 // TODO(rsc): The use of ModeInstall here is suspect, but if we only do ModeBuild,
573 // we'll end up building an overall library or executable that depends at runtime
574 // on other libraries that are out-of-date, which is clearly not good either.
575 // We call it ModeBuggyInstall to make clear that this is not right.
576 a
.Deps
= append(a
.Deps
, b
.linkSharedAction(ModeBuggyInstall
, ModeBuggyInstall
, p1
.Shlib
, nil))
581 // addInstallHeaderAction adds an install header action to a, if needed.
582 // The action a should be an install action as generated by either
583 // b.CompileAction or b.LinkAction with mode=ModeInstall,
584 // and so a.Deps[0] is the corresponding build action.
585 func (b
*Builder
) addInstallHeaderAction(a
*Action
) {
586 // Install header for cgo in c-archive and c-shared modes.
588 if p
.UsesCgo() && (cfg
.BuildBuildmode
== "c-archive" || cfg
.BuildBuildmode
== "c-shared") {
589 hdrTarget
:= a
.Target
[:len(a
.Target
)-len(filepath
.Ext(a
.Target
))] + ".h"
590 if cfg
.BuildContext
.Compiler
== "gccgo" && cfg
.BuildO
== "" {
591 // For the header file, remove the "lib"
592 // added by go/build, so we generate pkg.h
593 // rather than libpkg.h.
594 dir
, file
:= filepath
.Split(hdrTarget
)
595 file
= strings
.TrimPrefix(file
, "lib")
596 hdrTarget
= filepath
.Join(dir
, file
)
599 Mode
: "install header",
601 Deps
: []*Action
{a
.Deps
[0]},
602 Func
: (*Builder
).installHeader
,
603 Objdir
: a
.Deps
[0].Objdir
,
606 a
.Deps
= append(a
.Deps
, ah
)
610 // buildmodeShared takes the "go build" action a1 into the building of a shared library of a1.Deps.
611 // That is, the input a1 represents "go build pkgs" and the result represents "go build -buidmode=shared pkgs".
612 func (b
*Builder
) buildmodeShared(mode
, depMode BuildMode
, args
[]string, pkgs
[]*load
.Package
, a1
*Action
) *Action
{
613 name
, err
:= libname(args
, pkgs
)
615 base
.Fatalf("%v", err
)
617 return b
.linkSharedAction(mode
, depMode
, name
, a1
)
620 // linkSharedAction takes a grouping action a1 corresponding to a list of built packages
621 // and returns an action that links them together into a shared library with the name shlib.
622 // If a1 is nil, shlib should be an absolute path to an existing shared library,
623 // and then linkSharedAction reads that library to find out the package list.
624 func (b
*Builder
) linkSharedAction(mode
, depMode BuildMode
, shlib
string, a1
*Action
) *Action
{
626 shlib
= filepath
.Base(shlib
)
627 a
:= b
.cacheAction("build-shlib "+shlib
, nil, func() *Action
{
629 // TODO(rsc): Need to find some other place to store config,
630 // not in pkg directory. See golang.org/issue/22196.
631 pkgs
:= readpkglist(fullShlib
)
633 Mode
: "shlib packages",
635 for _
, p
:= range pkgs
{
636 a1
.Deps
= append(a1
.Deps
, b
.CompileAction(mode
, depMode
, p
))
640 // Fake package to hold ldflags.
641 // As usual shared libraries are a kludgy, abstraction-violating special case:
642 // we let them use the flags specified for the command-line arguments.
644 p
.Internal
.CmdlinePkg
= true
645 p
.Internal
.Ldflags
= load
.BuildLdflags
.For(p
)
646 p
.Internal
.Gccgoflags
= load
.BuildGccgoflags
.For(p
)
648 // Add implicit dependencies to pkgs list.
649 // Currently buildmode=shared forces external linking mode, and
650 // external linking mode forces an import of runtime/cgo (and
651 // math on arm). So if it was not passed on the command line and
652 // it is not present in another shared library, add it here.
653 // TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
654 // TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
655 // TODO(rsc): We don't add standard library imports for gccgo
656 // because they are all always linked in anyhow.
657 // Maybe load.LinkerDeps should be used and updated.
659 Mode
: "go build -buildmode=shared",
661 Objdir
: b
.NewObjdir(),
662 Func
: (*Builder
).linkShared
,
665 a
.Target
= filepath
.Join(a
.Objdir
, shlib
)
666 if cfg
.BuildToolchainName
!= "gccgo" {
667 add
:= func(a1
*Action
, pkg
string, force
bool) {
668 for _
, a2
:= range a1
.Deps
{
669 if a2
.Package
!= nil && a2
.Package
.ImportPath
== pkg
{
673 var stk load
.ImportStack
674 p
:= load
.LoadPackage(pkg
, &stk
)
676 base
.Fatalf("load %s: %v", pkg
, p
.Error
)
678 // Assume that if pkg (runtime/cgo or math)
679 // is already accounted for in a different shared library,
680 // then that shared library also contains runtime,
681 // so that anything we do will depend on that library,
682 // so we don't need to include pkg in our shared library.
683 if force || p
.Shlib
== "" || filepath
.Base(p
.Shlib
) == pkg
{
684 a1
.Deps
= append(a1
.Deps
, b
.CompileAction(depMode
, depMode
, p
))
687 add(a1
, "runtime/cgo", false)
688 if cfg
.Goarch
== "arm" {
689 add(a1
, "math", false)
692 // The linker step still needs all the usual linker deps.
693 // (For example, the linker always opens runtime.a.)
694 for _
, dep
:= range load
.LinkerDeps(nil) {
698 b
.addTransitiveLinkDeps(a
, a1
, shlib
)
703 if (mode
== ModeInstall || mode
== ModeBuggyInstall
) && a
.Func
!= nil {
706 a
= b
.cacheAction("install-shlib "+shlib
, nil, func() *Action
{
707 // Determine the eventual install target.
708 // The install target is root/pkg/shlib, where root is the source root
709 // in which all the packages lie.
710 // TODO(rsc): Perhaps this cross-root check should apply to the full
711 // transitive package dependency list, not just the ones named
712 // on the command line?
713 pkgDir
:= a1
.Deps
[0].Package
.Internal
.Build
.PkgTargetRoot
714 for _
, a2
:= range a1
.Deps
{
715 if dir
:= a2
.Package
.Internal
.Build
.PkgTargetRoot
; dir
!= pkgDir
{
716 base
.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s",
717 a1
.Deps
[0].Package
.ImportPath
,
718 a2
.Package
.ImportPath
,
723 // TODO(rsc): Find out and explain here why gccgo is different.
724 if cfg
.BuildToolchainName
== "gccgo" {
725 pkgDir
= filepath
.Join(pkgDir
, "shlibs")
727 target
:= filepath
.Join(pkgDir
, shlib
)
730 Mode
: "go install -buildmode=shared",
731 Objdir
: buildAction
.Objdir
,
732 Func
: BuildInstallFunc
,
733 Deps
: []*Action
{buildAction
},
736 for _
, a2
:= range buildAction
.Deps
[0].Deps
{
741 a
.Deps
= append(a
.Deps
, &Action
{
744 Func
: (*Builder
).installShlibname
,
745 Target
: strings
.TrimSuffix(p
.Target
, ".a") + ".shlibname",
746 Deps
: []*Action
{a
.Deps
[0]},