1 // Copyright 2012 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.
22 // pathf is fmt.Sprintf for generating paths
23 // (on windows it turns / into \ after the printf).
24 func pathf(format string, args ...interface{}) string {
25 return filepath.Clean(fmt.Sprintf(format, args...))
28 // filter returns a slice containing the elements x from list for which f(x) == true.
29 func filter(list []string, f func(string) bool) []string {
31 for _, x := range list {
39 // uniq returns a sorted slice containing the unique elements of list.
40 func uniq(list []string) []string {
41 out := make([]string, len(list))
45 for _, x := range out {
46 if len(keep) == 0 || keep[len(keep)-1] != x {
47 keep = append(keep, x)
53 // splitlines returns a slice with the result of splitting
54 // the input p after each \n.
55 func splitlines(p string) []string {
56 return strings.SplitAfter(p, "\n")
59 // splitfields replaces the vector v with the result of splitting
60 // the input p into non-empty fields containing no spaces.
61 func splitfields(p string) []string {
62 return strings.Fields(p)
71 var outputLock sync.Mutex
73 // run runs the command line cmd in dir.
74 // If mode has ShowOutput set, run collects cmd's output and returns it as a string;
75 // otherwise, run prints cmd's output to standard output after the command finishes.
76 // If mode has CheckExit set and the command fails, run calls fatal.
77 // If mode has Background set, this command is being run as a
78 // Background job. Only bgrun should use the Background mode,
80 func run(dir string, mode int, cmd ...string) string {
82 errprintf("run: %s\n", strings.Join(cmd, " "))
85 xcmd := exec.Command(cmd[0], cmd[1:]...)
90 // If we want to show command output and this is not
91 // a background command, assume it's the only thing
92 // running, so we can just let it write directly stdout/stderr
93 // as it runs without fear of mixing the output with some
94 // other command's output. Not buffering lets the output
95 // appear as it is printed instead of once the command exits.
96 // This is most important for the invocation of 'go1.4 build -v bootstrap/...'.
97 if mode&(Background|ShowOutput) == ShowOutput {
98 xcmd.Stdout = os.Stdout
99 xcmd.Stderr = os.Stderr
102 data, err = xcmd.CombinedOutput()
104 if err != nil && mode&CheckExit != 0 {
107 xprintf("%s\n", data)
110 if mode&Background != 0 {
113 fatal("FAILED: %v", strings.Join(cmd, " "))
115 if mode&ShowOutput != 0 {
117 os.Stdout.Write(data)
121 errprintf("run: %s DONE\n", strings.Join(cmd, " "))
126 var maxbg = 4 /* maximum number of jobs to run at once */
129 bgwork = make(chan func(), 1e5)
130 bgdone = make(chan struct{}, 1e5)
132 bgdied sync.WaitGroup
136 dying = make(chan bool)
142 for i := 0; i < maxbg; i++ {
152 // Stop if we're dying.
153 if atomic.LoadInt32(&nfatal) > 0 {
160 // bgrun is like run but runs the command in the background.
161 // CheckExit|ShowOutput mode is implied (since output cannot be returned).
162 func bgrun(dir string, cmd ...string) {
164 run(dir, CheckExit|ShowOutput|Background, cmd...)
168 // bgwait waits for pending bgruns to finish.
169 // bgwait must be called from only a single goroutine at a time.
171 var wg sync.WaitGroup
173 done := make(chan bool)
174 for i := 0; i < maxbg; i++ {
178 // Hold up bg goroutine until either the wait finishes
179 // or the program starts dying due to a call to fatal.
190 // xgetwd returns the current directory.
191 func xgetwd() string {
192 wd, err := os.Getwd()
199 // xrealwd returns the 'real' name for the given path.
200 // real is defined as what xgetwd returns in that directory.
201 func xrealwd(path string) string {
203 if err := os.Chdir(path); err != nil {
204 fatal("chdir %s: %v", path, err)
207 if err := os.Chdir(old); err != nil {
208 fatal("chdir %s: %v", old, err)
213 // isdir reports whether p names an existing directory.
214 func isdir(p string) bool {
215 fi, err := os.Stat(p)
216 return err == nil && fi.IsDir()
219 // isfile reports whether p names an existing file.
220 func isfile(p string) bool {
221 fi, err := os.Stat(p)
222 return err == nil && fi.Mode().IsRegular()
225 // mtime returns the modification time of the file p.
226 func mtime(p string) time.Time {
227 fi, err := os.Stat(p)
234 // isabs reports whether p is an absolute path.
235 func isabs(p string) bool {
236 return filepath.IsAbs(p)
239 // readfile returns the content of the named file.
240 func readfile(file string) string {
241 data, err := ioutil.ReadFile(file)
248 // writefile writes b to the named file, creating it if needed. if
249 // exec is non-zero, marks the file as executable.
250 func writefile(b, file string, exec int) {
251 mode := os.FileMode(0666)
255 err := ioutil.WriteFile(file, []byte(b), mode)
261 // xmkdir creates the directory p.
262 func xmkdir(p string) {
263 err := os.Mkdir(p, 0777)
269 // xmkdirall creates the directory p and its parents, as needed.
270 func xmkdirall(p string) {
271 err := os.MkdirAll(p, 0777)
277 // xremove removes the file p.
278 func xremove(p string) {
280 errprintf("rm %s\n", p)
285 // xremoveall removes the file or directory tree rooted at p.
286 func xremoveall(p string) {
288 errprintf("rm -r %s\n", p)
293 // xreaddir replaces dst with a list of the names of the files and subdirectories in dir.
294 // The names are relative to dir; they are not full paths.
295 func xreaddir(dir string) []string {
296 f, err := os.Open(dir)
301 names, err := f.Readdirnames(-1)
303 fatal("reading %s: %v", dir, err)
308 // xreaddir replaces dst with a list of the names of the files in dir.
309 // The names are relative to dir; they are not full paths.
310 func xreaddirfiles(dir string) []string {
311 f, err := os.Open(dir)
316 infos, err := f.Readdir(-1)
318 fatal("reading %s: %v", dir, err)
321 for _, fi := range infos {
323 names = append(names, fi.Name())
329 // xworkdir creates a new temporary directory to hold object files
330 // and returns the name of that directory.
331 func xworkdir() string {
332 name, err := ioutil.TempDir("", "go-tool-dist-")
339 // fatal prints an error message to standard error and exits.
340 func fatal(format string, args ...interface{}) {
341 fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
343 // Wait for background goroutines to finish,
344 // so that exit handler that removes the work directory
345 // is not fighting with active writes or open files.
346 if atomic.AddInt32(&nfatal, 1) == 1 {
349 for i := 0; i < maxbg; i++ {
350 bgwork <- func() {} // wake up workers so they notice nfatal > 0
359 // xexit exits the process with return code n.
361 for i := len(atexits) - 1; i >= 0; i-- {
367 // xatexit schedules the exit-handler f to be run when the program exits.
368 func xatexit(f func()) {
369 atexits = append(atexits, f)
372 // xprintf prints a message to standard output.
373 func xprintf(format string, args ...interface{}) {
374 fmt.Printf(format, args...)
377 // errprintf prints a message to standard output.
378 func errprintf(format string, args ...interface{}) {
379 fmt.Fprintf(os.Stderr, format, args...)
382 // main takes care of OS-specific startup and dispatches to xmain.
384 os.Setenv("TERM", "dumb") // disable escape codes in clang errors
386 slash = string(filepath.Separator)
388 gohostos = runtime.GOOS
391 // Even on 64-bit platform, darwin uname -m prints i386.
392 if strings.Contains(run("", CheckExit, "sysctl", "machdep.cpu.extfeatures"), "EM64T") {
396 // Even on 64-bit platform, solaris uname -m prints i86pc.
397 out := run("", CheckExit, "isainfo", "-n")
398 if strings.Contains(out, "amd64") {
401 if strings.Contains(out, "i386") {
405 gohostarch = os.Getenv("objtype")
406 if gohostarch == "" {
407 fatal("$objtype is unset")
415 if gohostarch == "" {
416 // Default Unix system.
417 out := run("", CheckExit, "uname", "-m")
419 case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
421 case strings.Contains(out, "86"):
423 case strings.Contains(out, "arm"):
425 case strings.Contains(out, "ppc64le"):
426 gohostarch = "ppc64le"
427 case strings.Contains(out, "ppc64"):
429 case gohostos == "darwin":
430 if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM_") {
434 fatal("unknown architecture: %s", out)
438 if gohostarch == "arm" {
443 // The OS X 10.6 linker does not support external linking mode.
444 // See golang.org/issue/5130.
446 // OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
447 // It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
448 // See golang.org/issue/5822.
450 // Roughly, OS X 10.N shows up as uname release (N+4),
451 // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
452 if gohostos == "darwin" {
453 rel := run("", CheckExit, "uname", "-r")
454 if i := strings.Index(rel, "."); i >= 0 {
457 osx, _ := strconv.Atoi(rel)
459 goextlinkenabled = "0"
471 // xsamefile reports whether f1 and f2 are the same file (or dir)
472 func xsamefile(f1, f2 string) bool {
473 fi1, err1 := os.Stat(f1)
474 fi2, err2 := os.Stat(f2)
475 if err1 != nil || err2 != nil {
478 return os.SameFile(fi1, fi2)
481 func cpuid(info *[4]uint32, ax uint32)
483 func cansse2() bool {
484 if gohostarch != "386" && gohostarch != "amd64" {
490 return info[3]&(1<<26) != 0 // SSE2
493 func xgetgoarm() string {
495 // NaCl guarantees VFPv3 and is always cross-compiled.
498 if goos == "darwin" {
499 // Assume all darwin/arm devices are have VFPv3. This
500 // port is also mostly cross-compiled, so it makes little
501 // sense to auto-detect the setting.
504 if gohostarch != "arm" || goos != gohostos {
505 // Conservative default for cross-compilation.
508 if goos == "freebsd" {
509 // FreeBSD has broken VFP support.
513 // All other arm platforms that we support
517 cpuinfo := readfile("/proc/cpuinfo")
519 for _, line := range splitlines(cpuinfo) {
520 line := strings.SplitN(line, ":", 2)
524 if strings.TrimSpace(line[0]) != "Features" {
527 features := splitfields(line[1])
528 sort.Strings(features) // so vfpv3 sorts after vfp
530 // Infer GOARM value from the vfp features available
531 // on this host. Values of GOARM detected are:
532 // 5: no vfp support was found
533 // 6: vfp (v1) support was detected, but no higher
534 // 7: vfpv3 support was detected.
535 // This matches the assertions in runtime.checkarm.
536 for _, f := range features {