LEFT | RIGHT |
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 package main | |
6 | |
7 import ( | |
8 "bytes" | |
9 "container/heap" | |
10 "errors" | |
11 "fmt" | |
12 "go/build" | |
13 "io" | |
14 "io/ioutil" | |
15 "os" | |
16 "os/exec" | |
17 "path/filepath" | |
18 "regexp" | |
19 "runtime" | |
20 "strings" | |
21 "sync" | |
22 ) | |
23 | |
24 // Break init cycles | |
25 func init() { | |
26 cmdBuild.Run = runBuild | |
27 cmdInstall.Run = runInstall | |
28 } | |
29 | |
30 var cmdBuild = &Command{ | |
31 UsageLine: "build [-a] [-n] [-x] [-o output] [importpath... | gofiles...
]", | |
32 Short: "compile packages and dependencies", | |
33 Long: ` | |
34 Build compiles the packages named by the import paths, | |
35 along with their dependencies, but it does not install the results. | |
36 | |
37 If the arguments are a list of .go files, build treats them as a list | |
38 of source files specifying a single package. | |
39 | |
40 When the command line specifies a single main package, | |
41 build writes the resulting executable to output (default a.out). | |
42 Otherwise build compiles the packages but discards the results, | |
43 serving only as a check that the packages can be built. | |
44 | |
45 The -a flag forces rebuilding of packages that are already up-to-date. | |
46 The -n flag prints the commands but does not run them. | |
47 The -x flag prints the commands. | |
48 The -o flag specifies the output file name. | |
49 It is an error to use -o when the command line specifies multiple packages. | |
50 | |
51 For more about import paths, see 'go help importpath'. | |
52 | |
53 See also: go install, go get, go clean. | |
54 `, | |
55 } | |
56 | |
57 var buildA = cmdBuild.Flag.Bool("a", false, "") | |
58 var buildN = cmdBuild.Flag.Bool("n", false, "") | |
59 var buildX = cmdBuild.Flag.Bool("x", false, "") | |
60 var buildO = cmdBuild.Flag.String("o", "", "output file") | |
61 | |
62 func runBuild(cmd *Command, args []string) { | |
63 var b builder | |
64 b.init(*buildA, *buildN, *buildX) | |
65 | |
66 var pkgs []*Package | |
67 if len(args) > 0 && strings.HasSuffix(args[0], ".go") { | |
68 pkg := goFilesPackage(args, "") | |
69 pkgs = append(pkgs, pkg) | |
70 } else { | |
71 pkgs = packages(args) | |
72 } | |
73 | |
74 if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" { | |
75 *buildO = "a.out" | |
76 } | |
77 | |
78 if *buildO != "" { | |
79 if len(pkgs) > 1 { | |
80 fatalf("go build: cannot use -o with multiple packages") | |
81 } | |
82 p := pkgs[0] | |
83 p.target = "" // must build - not up to date | |
84 a := b.action(modeInstall, modeBuild, p) | |
85 a.target = *buildO | |
86 b.do(a) | |
87 return | |
88 } | |
89 | |
90 a := &action{} | |
91 for _, p := range packages(args) { | |
92 a.deps = append(a.deps, b.action(modeBuild, modeBuild, p)) | |
93 } | |
94 b.do(a) | |
95 } | |
96 | |
97 var cmdInstall = &Command{ | |
98 UsageLine: "install [-a] [-n] [-x] [importpath...]", | |
99 Short: "compile and install packages and dependencies", | |
100 Long: ` | |
101 Install compiles and installs the packages named by the import paths, | |
102 along with their dependencies. | |
103 | |
104 The -a flag forces reinstallation of packages that are already up-to-date. | |
105 The -n flag prints the commands but does not run them. | |
106 The -x flag prints the commands. | |
107 | |
108 For more about import paths, see 'go help importpath'. | |
109 | |
110 See also: go build, go get, go clean. | |
111 `, | |
112 } | |
113 | |
114 var installA = cmdInstall.Flag.Bool("a", false, "") | |
115 var installN = cmdInstall.Flag.Bool("n", false, "") | |
116 var installX = cmdInstall.Flag.Bool("x", false, "") | |
117 | |
118 func runInstall(cmd *Command, args []string) { | |
119 var b builder | |
120 b.init(*installA, *installN, *installX) | |
121 a := &action{} | |
122 for _, p := range packages(args) { | |
123 a.deps = append(a.deps, b.action(modeInstall, modeInstall, p)) | |
124 } | |
125 b.do(a) | |
126 } | |
127 | |
128 // A builder holds global state about a build. | |
129 // It does not hold per-package state, because eventually we will | |
130 // build packages in parallel, and the builder will be shared. | |
131 type builder struct { | |
132 work string // the temporary work directory (ends i
n filepath.Separator) | |
133 aflag bool // the -a flag | |
134 nflag bool // the -n flag | |
135 xflag bool // the -x flag | |
136 arch string // e.g., "6" | |
137 goroot string // the $GOROOT | |
138 goarch string // the $GOARCH | |
139 goos string // the $GOOS | |
140 gobin string // the $GOBIN | |
141 exe string // the executable suffix - "" or ".exe" | |
142 gcflags []string // additional flags for Go compiler | |
143 actionCache map[cacheKey]*action // a cache of already-constructed actio
ns | |
144 mkdirCache map[string]bool // a cache of created directories | |
145 | |
146 output sync.Mutex | |
147 scriptDir string // current directory in printed script | |
148 | |
149 exec sync.Mutex | |
150 readySema chan bool | |
151 ready actionQueue | |
152 } | |
153 | |
154 // An action represents a single action in the action graph. | |
155 type action struct { | |
156 p *Package // the package this action works on | |
157 deps []*action // actions that must happen before this one | |
158 triggers []*action // inverse of deps | |
159 cgo *action // action for cgo binary if needed | |
160 | |
161 f func(*builder, *action) error // the action itself (nil = no-
op) | |
162 ignoreFail bool // whether to run f even if dep
endencies fail | |
163 | |
164 // Generated files, directories. | |
165 link bool // target is executable, not just package | |
166 pkgdir string // the -I or -L argument to use when importing this packag
e | |
167 objdir string // directory for intermediate objects | |
168 objpkg string // the intermediate package .a file created during the act
ion | |
169 target string // goal of the action: the created package or executable | |
170 | |
171 // Execution state. | |
172 pending int // number of deps yet to complete | |
173 priority int // relative execution priority | |
174 failed bool // whether the action failed | |
175 } | |
176 | |
177 // cacheKey is the key for the action cache. | |
178 type cacheKey struct { | |
179 mode buildMode | |
180 p *Package | |
181 } | |
182 | |
183 // buildMode specifies the build mode: | |
184 // are we just building things or also installing the results? | |
185 type buildMode int | |
186 | |
187 const ( | |
188 modeBuild buildMode = iota | |
189 modeInstall | |
190 ) | |
191 | |
192 func (b *builder) init(aflag, nflag, xflag bool) { | |
193 var err error | |
194 b.aflag = aflag | |
195 b.nflag = nflag | |
196 b.xflag = xflag | |
197 b.actionCache = make(map[cacheKey]*action) | |
198 b.mkdirCache = make(map[string]bool) | |
199 b.goarch = build.DefaultContext.GOARCH | |
200 b.goos = build.DefaultContext.GOOS | |
201 b.goroot = build.Path[0].Path | |
202 b.gobin = build.Path[0].BinDir() | |
203 if b.goos == "windows" { | |
204 b.exe = ".exe" | |
205 } | |
206 b.gcflags = strings.Fields(os.Getenv("GCFLAGS")) | |
207 | |
208 b.arch, err = build.ArchChar(b.goarch) | |
209 if err != nil { | |
210 fatalf("%s", err) | |
211 } | |
212 | |
213 if nflag { | |
214 b.work = "$WORK" | |
215 } else { | |
216 b.work, err = ioutil.TempDir("", "go-build") | |
217 if err != nil { | |
218 fatalf("%s", err) | |
219 } | |
220 if b.xflag { | |
221 fmt.Printf("WORK=%s\n", b.work) | |
222 } | |
223 atexit(func() { os.RemoveAll(b.work) }) | |
224 } | |
225 } | |
226 | |
227 // goFilesPackage creates a package for building a collection of Go files | |
228 // (typically named on the command line). If target is given, the package | |
229 // target is target. Otherwise, the target is named p.a for | |
230 // package p or named after the first Go file for package main. | |
231 func goFilesPackage(gofiles []string, target string) *Package { | |
232 // TODO: Remove this restriction. | |
233 for _, f := range gofiles { | |
234 if !strings.HasSuffix(f, ".go") || strings.Contains(f, "/") || s
trings.Contains(f, string(filepath.Separator)) { | |
235 fatalf("named files must be in current directory and .go
files") | |
236 } | |
237 } | |
238 | |
239 // Synthesize fake "directory" that only shows those two files, | |
240 // to make it look like this is a standard package or | |
241 // command directory. | |
242 var dir []os.FileInfo | |
243 for _, file := range gofiles { | |
244 fi, err := os.Stat(file) | |
245 if err != nil { | |
246 fatalf("%s", err) | |
247 } | |
248 if fi.IsDir() { | |
249 fatalf("%s is a directory, should be a Go file", file) | |
250 } | |
251 dir = append(dir, fi) | |
252 } | |
253 ctxt := build.DefaultContext | |
254 ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dir, nil } | |
255 pwd, _ := os.Getwd() | |
256 pkg, err := scanPackage(&ctxt, &build.Tree{Path: "."}, "<command line>",
"<command line>", pwd) | |
257 if err != nil { | |
258 fatalf("%s", err) | |
259 } | |
260 if target != "" { | |
261 pkg.target = target | |
262 } else if pkg.Name == "main" { | |
263 pkg.target = gofiles[0][:len(gofiles[0])-len(".go")] | |
264 } else { | |
265 pkg.target = pkg.Name + ".a" | |
266 } | |
267 pkg.ImportPath = "_/" + pkg.target | |
268 return pkg | |
269 } | |
270 | |
271 // action returns the action for applying the given operation (mode) to the pack
age. | |
272 // depMode is the action to use when building dependencies. | |
273 func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
{ | |
274 key := cacheKey{mode, p} | |
275 a := b.actionCache[key] | |
276 if a != nil { | |
277 return a | |
278 } | |
279 | |
280 a = &action{p: p, pkgdir: p.t.PkgDir()} | |
281 if p.pkgdir != "" { // overrides p.t | |
282 a.pkgdir = p.pkgdir | |
283 } | |
284 | |
285 b.actionCache[key] = a | |
286 | |
287 for _, p1 := range p.imports { | |
288 a.deps = append(a.deps, b.action(depMode, depMode, p1)) | |
289 } | |
290 | |
291 if len(p.CgoFiles) > 0 { | |
292 p1, err := loadPackage("cmd/cgo") | |
293 if err != nil { | |
294 fatalf("load cmd/cgo: %v", err) | |
295 } | |
296 a.cgo = b.action(depMode, depMode, p1) | |
297 a.deps = append(a.deps, a.cgo) | |
298 } | |
299 | |
300 if p.Standard { | |
301 switch p.ImportPath { | |
302 case "builtin", "unsafe": | |
303 // Fake packages - nothing to build. | |
304 return a | |
305 } | |
306 } | |
307 | |
308 if !p.Stale && !b.aflag && p.target != "" { | |
309 // p.Stale==false implies that p.target is up-to-date. | |
310 // Record target name for use by actions depending on this one. | |
311 a.target = p.target | |
312 return a | |
313 } | |
314 | |
315 a.objdir = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+"/_ob
j")) + string(filepath.Separator) | |
316 a.objpkg = filepath.Join(b.work, filepath.FromSlash(a.p.ImportPath+".a")
) | |
317 a.link = p.Name == "main" | |
318 | |
319 switch mode { | |
320 case modeInstall: | |
321 a.f = (*builder).install | |
322 a.deps = []*action{b.action(modeBuild, depMode, p)} | |
323 a.target = a.p.target | |
324 case modeBuild: | |
325 a.f = (*builder).build | |
326 a.target = a.objpkg | |
327 if a.link { | |
328 // An executable file. | |
329 // Have to use something other than .a for the suffix. | |
330 // It is easier on Windows if we use .exe, so use .exe e
verywhere. | |
331 // (This is the name of a temporary file.) | |
332 a.target = a.objdir + "a.out" + b.exe | |
333 } | |
334 } | |
335 | |
336 return a | |
337 } | |
338 | |
339 // do runs the action graph rooted at root. | |
340 func (b *builder) do(root *action) { | |
341 // Build list of all actions, assigning depth-first post-order priority. | |
342 // The original implementation here was a true queue | |
343 // (using a channel) but it had the effect of getting | |
344 // distracted by low-level leaf actions to the detriment | |
345 // of completing higher-level actions. The order of | |
346 // work does not matter much to overall execution time, | |
347 // but when running "go test std" it is nice to see each test | |
348 // results as soon as possible. The priorities assigned | |
349 // ensure that, all else being equal, the execution prefers | |
350 // to do what it would have done first in a simple depth-first | |
351 // dependency order traversal. | |
352 all := map[*action]bool{} | |
353 priority := 0 | |
354 var walk func(*action) | |
355 walk = func(a *action) { | |
356 if all[a] { | |
357 return | |
358 } | |
359 all[a] = true | |
360 priority++ | |
361 for _, a1 := range a.deps { | |
362 walk(a1) | |
363 } | |
364 a.priority = priority | |
365 } | |
366 walk(root) | |
367 | |
368 b.readySema = make(chan bool, len(all)) | |
369 done := make(chan bool) | |
370 | |
371 // Initialize per-action execution state. | |
372 for a := range all { | |
373 for _, a1 := range a.deps { | |
374 a1.triggers = append(a1.triggers, a) | |
375 } | |
376 a.pending = len(a.deps) | |
377 if a.pending == 0 { | |
378 b.ready.push(a) | |
379 b.readySema <- true | |
380 } | |
381 } | |
382 | |
383 // Handle runs a single action and takes care of triggering | |
384 // any actions that are runnable as a result. | |
385 handle := func(a *action) { | |
386 var err error | |
387 if a.f != nil && (!a.failed || a.ignoreFail) { | |
388 err = a.f(b, a) | |
389 } | |
390 | |
391 // The actions run in parallel but all the updates to the | |
392 // shared work state are serialized through b.exec. | |
393 b.exec.Lock() | |
394 defer b.exec.Unlock() | |
395 | |
396 if err != nil { | |
397 if err == errPrintedOutput { | |
398 exitStatus = 2 | |
399 } else { | |
400 errorf("%s", err) | |
401 } | |
402 a.failed = true | |
403 } | |
404 | |
405 for _, a0 := range a.triggers { | |
406 if a.failed { | |
407 a0.failed = true | |
408 } | |
409 if a0.pending--; a0.pending == 0 { | |
410 b.ready.push(a0) | |
411 b.readySema <- true | |
412 } | |
413 } | |
414 | |
415 if a == root { | |
416 close(b.readySema) | |
417 done <- true | |
418 } | |
419 } | |
420 | |
421 // TODO: Turn this knob for parallelism. | |
422 for i := 0; i < 1; i++ { | |
423 go func() { | |
424 for _ = range b.readySema { | |
425 // Receiving a value from b.sema entitles | |
426 // us to take from the ready queue. | |
427 b.exec.Lock() | |
428 a := b.ready.pop() | |
429 b.exec.Unlock() | |
430 handle(a) | |
431 } | |
432 }() | |
433 } | |
434 | |
435 <-done | |
436 } | |
437 | |
438 // build is the action for building a single package or command. | |
439 func (b *builder) build(a *action) error { | |
440 if b.nflag { | |
441 // In -n mode, print a banner between packages. | |
442 // The banner is five lines so that when changes to | |
443 // different sections of the bootstrap script have to | |
444 // be merged, the banners give patch something | |
445 // to use to find its context. | |
446 fmt.Printf("\n#\n# %s\n#\n\n", a.p.ImportPath) | |
447 } | |
448 | |
449 // make build directory | |
450 obj := a.objdir | |
451 if err := b.mkdir(obj); err != nil { | |
452 return err | 1 return err |
453 } | 2 } |
454 | 3 |
455 » var gofiles, cfiles, sfiles, objects, cgoObjects []string | 4 » var gofiles, cfiles, sfiles, objects []string |
456 gofiles = append(gofiles, a.p.GoFiles...) | 5 gofiles = append(gofiles, a.p.GoFiles...) |
457 cfiles = append(cfiles, a.p.CFiles...) | 6 cfiles = append(cfiles, a.p.CFiles...) |
458 sfiles = append(sfiles, a.p.SFiles...) | 7 sfiles = append(sfiles, a.p.SFiles...) |
459 | |
460 // run cgo | |
461 if len(a.p.CgoFiles) > 0 { | |
462 // In a package using cgo, cgo compiles the C and assembly files
with gcc.·· | |
463 // There is one exception: runtime/cgo's job is to bridge the | |
464 // cgo and non-cgo worlds, so it necessarily has files in both. | |
465 // In that case gcc only gets the gcc_* files. | |
466 var gccfiles []string | |
467 println("std?", a.p.Standard, a.p.ImportPath) | |
468 if a.p.Standard && a.p.ImportPath == "runtime/cgo" { | |
469 filter := func(files, nongcc, gcc []string) ([]string, [
]string) { | |
470 for _, f := range files { | |
471 if strings.HasPrefix(f, "gcc_") { | |
472 gcc = append(gcc, f) | |
473 } else { | |
474 nongcc = append(nongcc, f) | |
475 } | |
476 } | |
477 return nongcc, gcc | |
478 } | |
479 cfiles, gccfiles = filter(cfiles, cfiles[:0], gccfiles) | |
480 sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles) | |
481 } else { | |
482 gccfiles = append(cfiles, sfiles...) | |
483 cfiles = nil | |
484 sfiles = nil | |
485 } | |
486 | |
487 outGo, outObj, err := b.cgo(a.p, a.cgo.target, obj, gccfiles) | |
488 if err != nil { | |
489 return err | |
490 } | |
491 cgoObjects = append(cgoObjects, outObj...) | |
492 gofiles = append(gofiles, outGo...) | |
493 } | |
494 | |
495 // prepare Go import path list | |
496 inc := []string{} | |
497 incMap := map[string]bool{} | |
498 | |
499 incMap[b.work] = true // handled later | |
500 incMap[build.Path[0].PkgDir()] = true // goroot | |
501 incMap[""] = true // ignore empty strings | |
502 | |
503 // build package directories of dependencies | |
504 for _, a1 := range a.deps { | |
505 if pkgdir := a1.pkgdir; !incMap[pkgdir] { | |
506 incMap[pkgdir] = true | |
507 inc = append(inc, "-I", pkgdir) | |
508 } | |
509 } | |
510 | |
511 // work directory | |
512 inc = append(inc, "-I", b.work) | |
513 | |
514 // then installed package directories of dependencies | |
515 for _, a1 := range a.deps { | |
516 if pkgdir := a1.p.t.PkgDir(); !incMap[pkgdir] { | |
517 incMap[pkgdir] = true | |
518 inc = append(inc, "-I", pkgdir) | |
519 } | |
520 } | |
521 | |
522 // compile Go | |
523 if len(gofiles) > 0 { | |
524 out := "_go_." + b.arch | |
525 gcargs := []string{"-p", a.p.ImportPath} | |
526 if a.p.Standard && a.p.ImportPath == "runtime" { | |
527 // runtime compiles with a special 6g flag to emit | |
528 // additional reflect type data. | |
529 gcargs = append(gcargs, "-+") | |
530 } | |
531 if err := b.gc(a.p, obj+out, gcargs, inc, gofiles); err != nil { | |
532 return err | |
533 } | |
534 objects = append(objects, out) | |
535 } | |
536 | |
537 // copy .h files named for goos or goarch or goos_goarch | |
538 // to names using GOOS and GOARCH. | |
539 // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h. | |
540 _goos_goarch := "_" + b.goos + "_" + b.goarch + ".h" | |
541 _goos := "_" + b.goos + ".h" | |
542 _goarch := "_" + b.goarch + ".h" | |
543 for _, file := range a.p.HFiles { | |
544 switch { | |
545 case strings.HasSuffix(file, _goos_goarch): | |
546 targ := file[:len(file)-len(_goos_goarch)] + "_GOOS_GOAR
CH.h" | |
547 if err := b.copyFile(obj+targ, filepath.Join(a.p.Dir, fi
le), 0666); err != nil { | |
548 return err | |
549 } | |
550 case strings.HasSuffix(file, _goarch): | |
551 targ := file[:len(file)-len(_goarch)] + "_GOARCH.h" | |
552 if err := b.copyFile(obj+targ, filepath.Join(a.p.Dir, fi
le), 0666); err != nil { | |
553 return err | |
554 } | |
555 case strings.HasSuffix(file, _goos): | |
556 targ := file[:len(file)-len(_goos)] + "_GOOS.h" | |
557 if err := b.copyFile(obj+targ, filepath.Join(a.p.Dir, fi
le), 0666); err != nil { | |
558 return err | |
559 } | |
560 } | |
561 } | |
562 | |
563 for _, file := range cfiles { | |
564 out := file[:len(file)-len(".c")] + "." + b.arch | |
565 if err := b.cc(a.p, obj, obj+out, file); err != nil { | |
566 return err | |
567 } | |
568 objects = append(objects, out) | |
569 } | |
570 | |
571 // assemble .s files | |
572 for _, file := range sfiles { | |
573 out := file[:len(file)-len(".s")] + "." + b.arch | |
574 if err := b.asm(a.p, obj, obj+out, file); err != nil { | |
575 return err | |
576 } | |
577 objects = append(objects, out) | |
578 } | |
579 | |
580 // NOTE(rsc): On Windows, it is critically important that the | |
581 // gcc-compiled objects (cgoObjects) be listed after the ordinary | |
582 // objects in the archive. I do not know why this is, and I am | |
583 // not sure I want to know. http://golang.org/issue/2601 | |
584 objects = append(objects, cgoObjects...) | |
585 | |
586 // pack into archive in obj directory | |
587 if err := b.gopack(a.p, obj, a.objpkg, objects); err != nil { | |
588 return err | |
589 } | |
590 | |
591 // link if needed. | |
592 if a.link { | |
593 // command. | |
594 // import paths for compiler are introduced by -I. | |
595 // for linker, they are introduced by -L. | |
596 for i := 0; i < len(inc); i += 2 { | |
597 inc[i] = "-L" | |
598 } | |
599 if err := b.ld(a.p, a.target, inc, a.objpkg); err != nil { | |
600 return err | |
601 } | |
602 } | |
603 | |
604 return nil | |
605 } | |
606 | |
607 // install is the action for installing a single package or executable. | |
608 func (b *builder) install(a *action) error { | |
609 a1 := a.deps[0] | |
610 perm := uint32(0666) | |
611 if a1.link { | |
612 perm = 0777 | |
613 } | |
614 | |
615 // make target directory | |
616 dir, _ := filepath.Split(a.target) | |
617 if dir != "" { | |
618 if err := b.mkdir(dir); err != nil { | |
619 return err | |
620 } | |
621 } | |
622 | |
623 return b.copyFile(a.target, a1.target, perm) | |
624 } | |
625 | |
626 // removeByRenaming removes file name by moving it to a tmp | |
627 // directory and deleting the target if possible. | |
628 func removeByRenaming(name string) error { | |
629 f, err := ioutil.TempFile("", "") | |
630 if err != nil { | |
631 return err | |
632 } | |
633 tmpname := f.Name() | |
634 f.Close() | |
635 err = os.Remove(tmpname) | |
636 if err != nil { | |
637 return err | |
638 } | |
639 err = os.Rename(name, tmpname) | |
640 if err != nil { | |
641 // assume name file does not exists, | |
642 // otherwise later code will fail. | |
643 return nil | |
644 } | |
645 err = os.Remove(tmpname) | |
646 if err != nil { | |
647 // TODO(brainman): file is locked and can't be deleted. | |
648 // We need to come up with a better way of doing it.· | |
649 } | |
650 return nil | |
651 } | |
652 | |
653 // copyFile is like 'cp src dst'. | |
654 func (b *builder) copyFile(dst, src string, perm uint32) error { | |
655 if b.nflag || b.xflag { | |
656 b.showcmd("", "cp %s %s", src, dst) | |
657 if b.nflag { | |
658 return nil | |
659 } | |
660 } | |
661 | |
662 sf, err := os.Open(src) | |
663 if err != nil { | |
664 return err | |
665 } | |
666 defer sf.Close() | |
667 os.Remove(dst) | |
668 df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) | |
669 if err != nil { | |
670 if runtime.GOOS != "windows" { | |
671 return err | |
672 } | |
673 // Windows does not allow to replace binary file | |
674 // while it is executing. We will cheat. | |
675 err = removeByRenaming(dst) | |
676 if err != nil { | |
677 return err | |
678 } | |
679 df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, p
erm) | |
680 if err != nil { | |
681 return err | |
682 } | |
683 } | |
684 _, err = io.Copy(df, sf) | |
685 df.Close() | |
686 if err != nil { | |
687 os.Remove(dst) | |
688 return err | |
689 } | |
690 return nil | |
691 } | |
692 | |
693 // fmtcmd formats a command in the manner of fmt.Sprintf but also: | |
694 // | |
695 // If dir is non-empty and the script is not in dir right now, | |
696 // fmtcmd inserts "cd dir\n" before the command. | |
697 // | |
698 // fmtcmd replaces the value of b.work with $WORK. | |
699 // fmtcmd replaces the value of b.goroot with $GOROOT. | |
700 // fmtcmd replaces the value of b.gobin with $GOBIN. | |
701 // | |
702 // fmtcmd replaces the name of the current directory with dot (.) | |
703 // but only when it is at the beginning of a space-separated token. | |
704 // | |
705 func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string
{ | |
706 cmd := fmt.Sprintf(format, args...) | |
707 if dir != "" { | |
708 cmd = strings.Replace(" "+cmd, " "+dir, " .", -1)[1:] | |
709 if b.scriptDir != dir { | |
710 b.scriptDir = dir | |
711 cmd = "cd " + dir + "\n" + cmd | |
712 } | |
713 } | |
714 cmd = strings.Replace(cmd, b.work, "$WORK", -1) | |
715 cmd = strings.Replace(cmd, b.gobin, "$GOBIN", -1) | |
716 cmd = strings.Replace(cmd, b.goroot, "$GOROOT", -1) | |
717 return cmd | |
718 } | |
719 | |
720 // showcmd prints the given command to standard output | |
721 // for the implementation of -n or -x. | |
722 func (b *builder) showcmd(dir string, format string, args ...interface{}) { | |
723 b.output.Lock() | |
724 defer b.output.Unlock() | |
725 fmt.Println(b.fmtcmd(dir, format, args...)) | |
726 } | |
727 | |
728 // showOutput prints "# desc" followed by the given output. | |
729 // The output is expected to contain references to 'dir', usually | |
730 // the source directory for the package that has failed to build. | |
731 // showOutput rewrites mentions of dir with a relative path to dir | |
732 // when the relative path is shorter. This is usually more pleasant. | |
733 // For example, if fmt doesn't compile and we are in src/pkg/html, | |
734 // the output is | |
735 // | |
736 // $ go build | |
737 // # fmt | |
738 // ../fmt/print.go:1090: undefined: asdf | |
739 // $ | |
740 // | |
741 // instead of | |
742 // | |
743 // $ go build | |
744 // # fmt | |
745 // /usr/gopher/go/src/pkg/fmt/print.go:1090: undefined: asdf | |
746 // $ | |
747 // | |
748 // showOutput also replaces references to the work directory with $WORK. | |
749 // | |
750 func (b *builder) showOutput(dir, desc, out string) { | |
751 prefix := "# " + desc | |
752 suffix := "\n" + out | |
753 pwd, _ := os.Getwd() | |
754 if reldir, err := filepath.Rel(pwd, dir); err == nil && len(reldir) < le
n(dir) { | |
755 suffix = strings.Replace(suffix, " "+dir, " "+reldir, -1) | |
756 suffix = strings.Replace(suffix, "\n"+dir, "\n"+reldir, -1) | |
757 } | |
758 suffix = strings.Replace(suffix, " "+b.work, " $WORK", -1) | |
759 | |
760 b.output.Lock() | |
761 defer b.output.Unlock() | |
762 fmt.Print(prefix, suffix) | |
763 } | |
764 | |
765 // errPrintedOutput is a special error indicating that a command failed | |
766 // but that it generated output as well, and that output has already | |
767 // been printed, so there's no point showing 'exit status 1' or whatever | |
768 // the wait status was. The main executor, builder.do, knows not to | |
769 // print this error. | |
770 var errPrintedOutput = errors.New("already printed output - no need to show erro
r") | |
771 | |
772 // run runs the command given by cmdline in the directory dir. | |
773 // If the commnd fails, run prints information about the failure | |
774 // and returns a non-nil error. | |
775 func (b *builder) run(dir string, desc string, cmdline ...string) error { | |
776 if b.nflag || b.xflag { | |
777 b.showcmd(dir, "%s", strings.Join(cmdline, " ")) | |
778 if b.nflag { | |
779 return nil | |
780 } | |
781 } | |
782 | |
783 var buf bytes.Buffer | |
784 cmd := exec.Command(cmdline[0], cmdline[1:]...) | |
785 cmd.Stdout = &buf | |
786 cmd.Stderr = &buf | |
787 cmd.Dir = dir | |
788 // TODO: cmd.Env | |
789 err := cmd.Run() | |
790 if buf.Len() > 0 { | |
791 out := buf.Bytes() | |
792 if out[len(out)-1] != '\n' { | |
793 out = append(out, '\n') | |
794 } | |
795 if desc == "" { | |
796 desc = b.fmtcmd(dir, "%s", strings.Join(cmdline, " ")) | |
797 } | |
798 b.showOutput(dir, desc, string(out)) | |
799 if err != nil { | |
800 err = errPrintedOutput | |
801 } | |
802 } | |
803 return err | |
804 } | |
805 | |
806 // mkdir makes the named directory. | |
807 func (b *builder) mkdir(dir string) error { | |
808 // We can be a little aggressive about being | |
809 // sure directories exist. Skip repeated calls. | |
810 if b.mkdirCache[dir] { | |
811 return nil | |
812 } | |
813 b.mkdirCache[dir] = true | |
814 | |
815 if b.nflag || b.xflag { | |
816 b.showcmd("", "mkdir -p %s", dir) | |
817 if b.nflag { | |
818 return nil | |
819 } | |
820 } | |
821 | |
822 if err := os.MkdirAll(dir, 0777); err != nil { | |
823 return err | |
824 } | |
825 return nil | |
826 } | |
827 | |
828 // mkAbs returns an absolute path corresponding to | |
829 // evaluating f in the directory dir. | |
830 // We always pass absolute paths of source files so that | |
831 // the error messages will include the full path to a file | |
832 // in need of attention. | |
833 func mkAbs(dir, f string) string { | |
834 // Leave absolute paths alone. | |
835 // Also, during -n mode we use the pseudo-directory $WORK | |
836 // instead of creating an actual work directory that won't be used. | |
837 // Leave paths beginning with $WORK alone too. | |
838 if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") { | |
839 return f | |
840 } | |
841 return filepath.Join(dir, f) | |
842 } | |
843 | |
844 // gc runs the Go compiler in a specific directory on a set of files | |
845 // to generate the named output file.· | |
846 func (b *builder) gc(p *Package, ofile string, gcargs, importArgs []string, gofi
les []string) error { | |
847 args := []string{b.arch + "g", "-o", ofile} | |
848 args = append(args, b.gcflags...) | |
849 args = append(args, gcargs...) | |
850 args = append(args, importArgs...) | |
851 for _, f := range gofiles { | |
852 args = append(args, mkAbs(p.Dir, f)) | |
853 } | |
854 return b.run(p.Dir, p.ImportPath, args...) | |
855 } | |
856 | |
857 // asm runs the assembler in a specific directory on a specific file | |
858 // to generate the named output file.· | |
859 func (b *builder) asm(p *Package, obj, ofile, sfile string) error { | |
860 sfile = mkAbs(p.Dir, sfile) | |
861 return b.run(p.Dir, p.ImportPath, b.arch+"a", "-I", obj, "-o", ofile, "-
DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile) | |
862 } | |
863 | |
864 // gopack runs the assembler in a specific directory to create | |
865 // an archive from a set of object files. | |
866 // typically it is run in the object directory. | |
867 func (b *builder) gopack(p *Package, objDir, afile string, ofiles []string) erro
r { | |
868 cmd := []string{"gopack", "grc"} | |
869 cmd = append(cmd, mkAbs(objDir, afile)) | |
870 for _, f := range ofiles { | |
871 cmd = append(cmd, mkAbs(objDir, f)) | |
872 } | |
873 return b.run(p.Dir, p.ImportPath, cmd...) | |
874 } | |
875 | |
876 // ld runs the linker to create a package starting at mainpkg. | |
877 func (b *builder) ld(p *Package, out string, importArgs []string, mainpkg string
) error { | |
878 return b.run(p.Dir, p.ImportPath, append(append([]string{b.arch + "l", "
-o", out}, importArgs...), mainpkg)...) | |
879 } | |
880 | |
881 // cc runs the gc-toolchain C compiler in a directory on a C file | |
882 // to produce an output file. | |
883 func (b *builder) cc(p *Package, objdir, ofile, cfile string) error { | |
884 inc := filepath.Join(b.goroot, "pkg", fmt.Sprintf("%s_%s", b.goos, b.goa
rch)) | |
885 cfile = mkAbs(p.Dir, cfile) | |
886 return b.run(p.Dir, p.ImportPath, b.arch+"c", "-FVw", "-I", objdir, "-I"
, inc, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile) | |
887 } | |
888 | |
889 // gcc runs the gcc C compiler to create an object from a single C file. | |
890 func (b *builder) gcc(p *Package, out string, flags []string, cfile string) erro
r { | |
891 cfile = mkAbs(p.Dir, cfile) | |
892 return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir, flags, "-o", out, "-c"
, cfile)...) | |
893 } | |
894 | |
895 // gccld runs the gcc linker to create an executable from a set of object files | |
896 func (b *builder) gccld(p *Package, out string, flags []string, obj []string) er
ror { | |
897 return b.run(p.Dir, p.ImportPath, append(b.gccCmd(p.Dir, flags, "-o", ou
t), obj...)...) | |
898 } | |
899 | |
900 // gccCmd returns a gcc command line ending with args | |
901 func (b *builder) gccCmd(objdir string, flags []string, args ...string) []string
{ | |
902 // TODO: HOST_CC? | |
903 a := []string{"gcc", "-I", objdir, "-g", "-O2"} | |
904 | |
905 // Definitely want -fPIC but on Windows gcc complains | |
906 // "-fPIC ignored for target (all code is position independent)" | |
907 if b.goos != "windows" { | |
908 a = append(a, "-fPIC") | |
909 } | |
910 switch b.arch { | |
911 case "8": | |
912 a = append(a, "-m32") | |
913 case "6": | |
914 a = append(a, "-m64") | |
915 } | |
916 a = append(a, flags...) | |
917 return append(a, args...) | |
918 } | |
919 | |
920 var cgoRe = regexp.MustCompile(`[/\\:]`) | |
921 | |
922 func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
outObj []string, err error) { | |
923 if b.goos != runtime.GOOS { | |
924 return nil, nil, errors.New("cannot use cgo when compiling for a
different operating system") | |
925 } | |
926 | |
927 outObj = append(outObj, "") // for importObj, at end of function | |
928 | |
929 // cgo | |
930 // TODO: CGOPKGPATH, CGO_FLAGS? | |
931 gofiles := []string{obj + "_cgo_gotypes.go"} | |
932 cfiles := []string{"_cgo_main.c", "_cgo_export.c"} | |
933 for _, fn := range p.CgoFiles { | |
934 f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_") | |
935 gofiles = append(gofiles, obj+f+"cgo1.go") | |
936 cfiles = append(cfiles, f+"cgo2.c") | |
937 } | |
938 defunC := obj + "_cgo_defun.c" | |
939 // TODO: make cgo not depend on $GOARCH? | |
940 // TODO: make cgo write to obj | |
941 cgoArgs := []string{cgoExe, "-objdir", obj} | |
942 if p.Standard && p.ImportPath == "runtime/cgo" { | |
943 cgoArgs = append(cgoArgs, "-import_runtime_cgo=false") | |
944 } | |
945 cgoArgs = append(cgoArgs, "--") | |
946 cgoArgs = append(cgoArgs, p.CgoFiles...) | |
947 if err := b.run(p.Dir, p.ImportPath, cgoArgs...); err != nil { | |
948 return nil, nil, err | |
949 } | |
950 outGo = append(outGo, gofiles...) | |
951 | |
952 // cc _cgo_defun.c | |
953 defunObj := obj + "_cgo_defun." + b.arch | |
954 if err := b.cc(p, obj, defunObj, defunC); err != nil { | |
955 return nil, nil, err | |
956 } | |
957 outObj = append(outObj, defunObj) | |
958 | |
959 // gcc | |
960 var linkobj []string | |
961 for _, cfile := range cfiles { | |
962 ofile := obj + cfile[:len(cfile)-1] + "o" | |
963 if err := b.gcc(p, ofile, p.info.CgoCFLAGS, obj+cfile); err != n
il { | |
964 return nil, nil, err | |
965 } | |
966 linkobj = append(linkobj, ofile) | |
967 if !strings.HasSuffix(ofile, "_cgo_main.o") { | |
968 outObj = append(outObj, ofile) | |
969 } | |
970 } | |
971 for _, file := range gccfiles { | |
972 ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") +
"o" | |
973 if err := b.gcc(p, ofile, p.info.CgoCFLAGS, file); err != nil { | |
974 return nil, nil, err | |
975 } | |
976 linkobj = append(linkobj, ofile) | |
977 outObj = append(outObj, ofile) | |
978 } | |
979 dynobj := obj + "_cgo_.o" | |
980 if err := b.gccld(p, dynobj, p.info.CgoLDFLAGS, linkobj); err != nil { | |
981 return nil, nil, err | |
982 } | |
983 | |
984 // cgo -dynimport | |
985 importC := obj + "_cgo_import.c" | |
986 if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport
", dynobj, "-dynout", importC); err != nil { | |
987 return nil, nil, err | |
988 } | |
989 | |
990 // cc _cgo_import.ARCH | |
991 importObj := obj + "_cgo_import." + b.arch | |
992 if err := b.cc(p, obj, importObj, importC); err != nil { | |
993 return nil, nil, err | |
994 } | |
995 | |
996 // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows | |
997 // must be processed before the gcc-generated objects. | |
998 // Put it first. We left room above. http://golang.org/issue/2601 | |
999 outObj[0] = importObj | |
1000 | |
1001 return outGo, outObj, nil | |
1002 } | |
1003 | |
1004 // An actionQueue is a priority queue of actions. | |
1005 type actionQueue []*action | |
1006 | |
1007 // Implement heap.Interface | |
1008 func (q *actionQueue) Len() int { return len(*q) } | |
1009 func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i]
} | |
1010 func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].pr
iority } | |
1011 func (q *actionQueue) Push(x interface{}) { *q = append(*q, x.(*action)) } | |
1012 func (q *actionQueue) Pop() interface{} { | |
1013 n := len(*q) - 1 | |
1014 x := (*q)[n] | |
1015 *q = (*q)[:n] | |
1016 return x | |
1017 } | |
1018 | |
1019 func (q *actionQueue) push(a *action) { | |
1020 heap.Push(q, a) | |
1021 } | |
1022 | |
1023 func (q *actionQueue) pop() *action { | |
1024 return heap.Pop(q).(*action) | |
1025 } | |
LEFT | RIGHT |