github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/dist/utils.go (about) 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. 4 5 package main 6 7 import ( 8 "bytes" 9 "flag" 10 "fmt" 11 "io" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "sort" 17 "strconv" 18 "strings" 19 "sync" 20 "time" 21 22 "github.com/zxy12/go_duplicate_112_new/src/zdebug" 23 ) 24 25 // pathf is fmt.Sprintf for generating paths 26 // (on windows it turns / into \ after the printf). 27 func pathf(format string, args ...interface{}) string { 28 return filepath.Clean(fmt.Sprintf(format, args...)) 29 } 30 31 // filter returns a slice containing the elements x from list for which f(x) == true. 32 func filter(list []string, f func(string) bool) []string { 33 var out []string 34 for _, x := range list { 35 if f(x) { 36 out = append(out, x) 37 } 38 } 39 return out 40 } 41 42 // uniq returns a sorted slice containing the unique elements of list. 43 func uniq(list []string) []string { 44 out := make([]string, len(list)) 45 copy(out, list) 46 sort.Strings(out) 47 keep := out[:0] 48 for _, x := range out { 49 if len(keep) == 0 || keep[len(keep)-1] != x { 50 keep = append(keep, x) 51 } 52 } 53 return keep 54 } 55 56 const ( 57 CheckExit = 1 << iota 58 ShowOutput 59 Background 60 ) 61 62 var outputLock sync.Mutex 63 64 // run runs the command line cmd in dir. 65 // If mode has ShowOutput set and Background unset, run passes cmd's output to 66 // stdout/stderr directly. Otherwise, run returns cmd's output as a string. 67 // If mode has CheckExit set and the command fails, run calls fatalf. 68 // If mode has Background set, this command is being run as a 69 // Background job. Only bgrun should use the Background mode, 70 // not other callers. 71 func run(dir string, mode int, cmd ...string) string { 72 if vflag > 1 { 73 errprintf("run: %s\n", strings.Join(cmd, " ")) 74 } 75 76 zdebug.T("%v,dir=%v,mode=%v", cmd, dir, mode) 77 xcmd := exec.Command(cmd[0], cmd[1:]...) 78 xcmd.Dir = dir 79 var data []byte 80 var err error 81 82 // If we want to show command output and this is not 83 // a background command, assume it's the only thing 84 // running, so we can just let it write directly stdout/stderr 85 // as it runs without fear of mixing the output with some 86 // other command's output. Not buffering lets the output 87 // appear as it is printed instead of once the command exits. 88 // This is most important for the invocation of 'go1.4 build -v bootstrap/...'. 89 if mode&(Background|ShowOutput) == ShowOutput { 90 xcmd.Stdout = os.Stdout 91 xcmd.Stderr = os.Stderr 92 err = xcmd.Run() 93 } else { 94 data, err = xcmd.CombinedOutput() 95 } 96 if err != nil && mode&CheckExit != 0 { 97 outputLock.Lock() 98 if len(data) > 0 { 99 xprintf("%s\n", data) 100 } 101 outputLock.Unlock() 102 if mode&Background != 0 { 103 // Prevent fatalf from waiting on our own goroutine's 104 // bghelper to exit: 105 bghelpers.Done() 106 } 107 fatalf("FAILED: %v: %v", strings.Join(cmd, " "), err) 108 } 109 if mode&ShowOutput != 0 { 110 outputLock.Lock() 111 os.Stdout.Write(data) 112 outputLock.Unlock() 113 } 114 if vflag > 2 { 115 errprintf("run: %s DONE\n", strings.Join(cmd, " ")) 116 } 117 return string(data) 118 } 119 120 var maxbg = 4 /* maximum number of jobs to run at once */ 121 122 var ( 123 bgwork = make(chan func(), 1e5) 124 125 bghelpers sync.WaitGroup 126 127 dieOnce sync.Once // guards close of dying 128 dying = make(chan struct{}) 129 ) 130 131 func bginit() { 132 bghelpers.Add(maxbg) 133 for i := 0; i < maxbg; i++ { 134 go bghelper() 135 } 136 } 137 138 func bghelper() { 139 defer bghelpers.Done() 140 for { 141 select { 142 case <-dying: 143 return 144 case w := <-bgwork: 145 // Dying takes precedence over doing more work. 146 select { 147 case <-dying: 148 return 149 default: 150 w() 151 } 152 } 153 } 154 } 155 156 // bgrun is like run but runs the command in the background. 157 // CheckExit|ShowOutput mode is implied (since output cannot be returned). 158 // bgrun adds 1 to wg immediately, and calls Done when the work completes. 159 func bgrun(wg *sync.WaitGroup, dir string, cmd ...string) { 160 wg.Add(1) 161 bgwork <- func() { 162 defer wg.Done() 163 zdebug.T("bgrun[%v]", cmd) 164 run(dir, CheckExit|ShowOutput|Background, cmd...) 165 } 166 } 167 168 // bgwait waits for pending bgruns to finish. 169 // bgwait must be called from only a single goroutine at a time. 170 func bgwait(wg *sync.WaitGroup) { 171 done := make(chan struct{}) 172 go func() { 173 wg.Wait() 174 close(done) 175 }() 176 select { 177 case <-done: 178 case <-dying: 179 } 180 } 181 182 // xgetwd returns the current directory. 183 func xgetwd() string { 184 wd, err := os.Getwd() 185 if err != nil { 186 fatalf("%s", err) 187 } 188 return wd 189 } 190 191 // xrealwd returns the 'real' name for the given path. 192 // real is defined as what xgetwd returns in that directory. 193 func xrealwd(path string) string { 194 old := xgetwd() 195 if err := os.Chdir(path); err != nil { 196 fatalf("chdir %s: %v", path, err) 197 } 198 real := xgetwd() 199 if err := os.Chdir(old); err != nil { 200 fatalf("chdir %s: %v", old, err) 201 } 202 return real 203 } 204 205 // isdir reports whether p names an existing directory. 206 func isdir(p string) bool { 207 fi, err := os.Stat(p) 208 return err == nil && fi.IsDir() 209 } 210 211 // isfile reports whether p names an existing file. 212 func isfile(p string) bool { 213 fi, err := os.Stat(p) 214 return err == nil && fi.Mode().IsRegular() 215 } 216 217 // mtime returns the modification time of the file p. 218 func mtime(p string) time.Time { 219 fi, err := os.Stat(p) 220 if err != nil { 221 return time.Time{} 222 } 223 return fi.ModTime() 224 } 225 226 // readfile returns the content of the named file. 227 func readfile(file string) string { 228 data, err := ioutil.ReadFile(file) 229 if err != nil { 230 fatalf("%v", err) 231 } 232 return string(data) 233 } 234 235 const ( 236 writeExec = 1 << iota 237 writeSkipSame 238 ) 239 240 // writefile writes text to the named file, creating it if needed. 241 // if exec is non-zero, marks the file as executable. 242 // If the file already exists and has the expected content, 243 // it is not rewritten, to avoid changing the time stamp. 244 func writefile(text, file string, flag int) { 245 new := []byte(text) 246 if flag&writeSkipSame != 0 { 247 old, err := ioutil.ReadFile(file) 248 if err == nil && bytes.Equal(old, new) { 249 return 250 } 251 } 252 mode := os.FileMode(0666) 253 if flag&writeExec != 0 { 254 mode = 0777 255 } 256 err := ioutil.WriteFile(file, new, mode) 257 if err != nil { 258 fatalf("%v", err) 259 } 260 } 261 262 // xmkdir creates the directory p. 263 func xmkdir(p string) { 264 err := os.Mkdir(p, 0777) 265 if err != nil { 266 fatalf("%v", err) 267 } 268 } 269 270 // xmkdirall creates the directory p and its parents, as needed. 271 func xmkdirall(p string) { 272 err := os.MkdirAll(p, 0777) 273 if err != nil { 274 fatalf("%v", err) 275 } 276 } 277 278 // xremove removes the file p. 279 func xremove(p string) { 280 if vflag > 2 { 281 errprintf("rm %s\n", p) 282 } 283 os.Remove(p) 284 } 285 286 // xremoveall removes the file or directory tree rooted at p. 287 func xremoveall(p string, nolog ...int) { 288 if nolog == nil { 289 290 } 291 292 if vflag > 2 { 293 errprintf("rm -r %s\n", p) 294 } 295 os.RemoveAll(p) 296 } 297 298 // xreaddir replaces dst with a list of the names of the files and subdirectories in dir. 299 // The names are relative to dir; they are not full paths. 300 func xreaddir(dir string) []string { 301 f, err := os.Open(dir) 302 if err != nil { 303 fatalf("%v", err) 304 } 305 defer f.Close() 306 names, err := f.Readdirnames(-1) 307 if err != nil { 308 fatalf("reading %s: %v", dir, err) 309 } 310 return names 311 } 312 313 // xreaddir replaces dst with a list of the names of the files in dir. 314 // The names are relative to dir; they are not full paths. 315 func xreaddirfiles(dir string) []string { 316 f, err := os.Open(dir) 317 if err != nil { 318 fatalf("%v", err) 319 } 320 defer f.Close() 321 infos, err := f.Readdir(-1) 322 if err != nil { 323 fatalf("reading %s: %v", dir, err) 324 } 325 var names []string 326 for _, fi := range infos { 327 if !fi.IsDir() { 328 names = append(names, fi.Name()) 329 } 330 } 331 // xprintf("bootstrapDir:%v,names%+v\n", dir, names) 332 return names 333 } 334 335 // xworkdir creates a new temporary directory to hold object files 336 // and returns the name of that directory. 337 func xworkdir() string { 338 name, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-tool-dist-") 339 if err != nil { 340 fatalf("%v", err) 341 } 342 return name 343 } 344 345 // fatalf prints an error message to standard error and exits. 346 func fatalf(format string, args ...interface{}) { 347 fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...)) 348 349 dieOnce.Do(func() { close(dying) }) 350 351 // Wait for background goroutines to finish, 352 // so that exit handler that removes the work directory 353 // is not fighting with active writes or open files. 354 bghelpers.Wait() 355 356 xexit(2) 357 } 358 359 var atexits []func() 360 361 // xexit exits the process with return code n. 362 func xexit(n int) { 363 for i := len(atexits) - 1; i >= 0; i-- { 364 atexits[i]() 365 } 366 os.Exit(n) 367 } 368 369 // xatexit schedules the exit-handler f to be run when the program exits. 370 func xatexit(f func()) { 371 atexits = append(atexits, f) 372 } 373 374 // xprintf prints a message to standard output. 375 func xprintf(format string, args ...interface{}) { 376 fmt.Printf(format, args...) 377 } 378 379 // errprintf prints a message to standard output. 380 func errprintf(format string, args ...interface{}) { 381 fmt.Fprintf(os.Stderr, format, args...) 382 } 383 384 // xsamefile reports whether f1 and f2 are the same file (or dir) 385 func xsamefile(f1, f2 string) bool { 386 fi1, err1 := os.Stat(f1) 387 fi2, err2 := os.Stat(f2) 388 if err1 != nil || err2 != nil { 389 return f1 == f2 390 } 391 return os.SameFile(fi1, fi2) 392 } 393 394 func xgetgoarm() string { 395 if goos == "nacl" { 396 // NaCl guarantees VFPv3 and is always cross-compiled. 397 return "7" 398 } 399 if goos == "darwin" || goos == "android" { 400 // Assume all darwin/arm and android devices have VFPv3. 401 // These ports are also mostly cross-compiled, so it makes little 402 // sense to auto-detect the setting. 403 return "7" 404 } 405 if gohostarch != "arm" || goos != gohostos { 406 // Conservative default for cross-compilation. 407 return "5" 408 } 409 if goos == "freebsd" { 410 // FreeBSD has broken VFP support. 411 return "5" 412 } 413 414 // Try to exec ourselves in a mode to detect VFP support. 415 // Seeing how far it gets determines which instructions failed. 416 // The test is OS-agnostic. 417 out := run("", 0, os.Args[0], "-check-goarm") 418 v1ok := strings.Contains(out, "VFPv1 OK.") 419 v3ok := strings.Contains(out, "VFPv3 OK.") 420 421 if v1ok && v3ok { 422 return "7" 423 } 424 if v1ok { 425 return "6" 426 } 427 return "5" 428 } 429 430 func min(a, b int) int { 431 if a < b { 432 return a 433 } 434 return b 435 } 436 437 // elfIsLittleEndian detects if the ELF file is little endian. 438 func elfIsLittleEndian(fn string) bool { 439 // read the ELF file header to determine the endianness without using the 440 // debug/elf package. 441 file, err := os.Open(fn) 442 if err != nil { 443 fatalf("failed to open file to determine endianness: %v", err) 444 } 445 defer file.Close() 446 var hdr [16]byte 447 if _, err := io.ReadFull(file, hdr[:]); err != nil { 448 fatalf("failed to read ELF header to determine endianness: %v", err) 449 } 450 // hdr[5] is EI_DATA byte, 1 is ELFDATA2LSB and 2 is ELFDATA2MSB 451 switch hdr[5] { 452 default: 453 fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5]) 454 case 1: 455 return true 456 case 2: 457 return false 458 } 459 panic("unreachable") 460 } 461 462 // count is a flag.Value that is like a flag.Bool and a flag.Int. 463 // If used as -name, it increments the count, but -name=x sets the count. 464 // Used for verbose flag -v. 465 type count int 466 467 func (c *count) String() string { 468 return fmt.Sprint(int(*c)) 469 } 470 471 func (c *count) Set(s string) error { 472 switch s { 473 case "true": 474 *c++ 475 case "false": 476 *c = 0 477 default: 478 n, err := strconv.Atoi(s) 479 if err != nil { 480 return fmt.Errorf("invalid count %q", s) 481 } 482 *c = count(n) 483 } 484 return nil 485 } 486 487 func (c *count) IsBoolFlag() bool { 488 return true 489 } 490 491 func xflagparse(maxargs int) { 492 flag.Var((*count)(&vflag), "v", "verbosity") 493 flag.Parse() 494 if maxargs >= 0 && flag.NArg() > maxargs { 495 flag.Usage() 496 } 497 } 498 499 // Remove trailing spaces. 500 func chomp(s string) string { 501 return strings.TrimRight(s, " \t\r\n") 502 } 503 504 // find reports the first index of p in l[0:n], or else -1. 505 func find(p string, l []string) int { 506 for i, s := range l { 507 if p == s { 508 return i 509 } 510 } 511 return -1 512 } 513 514 // rmworkdir deletes the work directory. 515 func rmworkdir() { 516 if vflag > 1 { 517 errprintf("rm -rf %s\n", workdir) 518 } 519 xremoveall(workdir, 1) 520 } 521 522 // compilerEnv returns a map from "goos/goarch" to the 523 // compiler setting to use for that platform. 524 // The entry for key "" covers any goos/goarch not explicitly set in the map. 525 // For example, compilerEnv("CC", "gcc") returns the C compiler settings 526 // read from $CC, defaulting to gcc. 527 // 528 // The result is a map because additional environment variables 529 // can be set to change the compiler based on goos/goarch settings. 530 // The following applies to all envNames but CC is assumed to simplify 531 // the presentation. 532 // 533 // If no environment variables are set, we use def for all goos/goarch. 534 // $CC, if set, applies to all goos/goarch but is overridden by the following. 535 // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch, 536 // but is overridden by the following. 537 // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch. 538 // $CC_FOR_goos_goarch, if set, applies only to goos/goarch. 539 func compilerEnv(envName, def string) map[string]string { 540 m := map[string]string{"": def} 541 542 if env := os.Getenv(envName); env != "" { 543 m[""] = env 544 } 545 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" { 546 if gohostos != goos || gohostarch != goarch { 547 m[gohostos+"/"+gohostarch] = m[""] 548 } 549 m[""] = env 550 } 551 552 for _, goos := range okgoos { 553 for _, goarch := range okgoarch { 554 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" { 555 m[goos+"/"+goarch] = env 556 } 557 } 558 } 559 560 return m 561 } 562 563 // xinit handles initialization of the various global state, like goroot and goarch. 564 func xinit() { 565 b := os.Getenv("GOROOT") 566 if b == "" { 567 fatalf("$GOROOT must be set") 568 } 569 goroot = filepath.Clean(b) 570 571 b = os.Getenv("GOROOT_FINAL") 572 if b == "" { 573 b = goroot 574 } 575 goroot_final = b 576 577 b = os.Getenv("GOBIN") 578 if b == "" { 579 b = pathf("%s/bin", goroot) 580 } 581 gobin = b 582 583 b = os.Getenv("GOOS") 584 if b == "" { 585 b = gohostos 586 } 587 goos = b 588 if find(goos, okgoos) < 0 { 589 fatalf("unknown $GOOS %s", goos) 590 } 591 592 b = os.Getenv("GOARM") 593 if b == "" { 594 b = xgetgoarm() 595 } 596 goarm = b 597 598 b = os.Getenv("GO386") 599 if b == "" { 600 if cansse2() { 601 b = "sse2" 602 } else { 603 b = "387" 604 } 605 } 606 go386 = b 607 608 b = os.Getenv("GOMIPS") 609 if b == "" { 610 b = "hardfloat" 611 } 612 gomips = b 613 614 b = os.Getenv("GOMIPS64") 615 if b == "" { 616 b = "hardfloat" 617 } 618 gomips64 = b 619 620 if p := pathf("%s/src/all.bash", goroot); !isfile(p) { 621 fatalf("$GOROOT is not set correctly or not exported\n"+ 622 "\tGOROOT=%s\n"+ 623 "\t%s does not exist", goroot, p) 624 } 625 626 b = os.Getenv("GOHOSTARCH") 627 if b != "" { 628 gohostarch = b 629 } 630 if find(gohostarch, okgoarch) < 0 { 631 fatalf("unknown $GOHOSTARCH %s", gohostarch) 632 } 633 634 b = os.Getenv("GOARCH") 635 if b == "" { 636 b = gohostarch 637 } 638 goarch = b 639 if find(goarch, okgoarch) < 0 { 640 fatalf("unknown $GOARCH %s", goarch) 641 } 642 643 b = os.Getenv("GO_EXTLINK_ENABLED") 644 if b != "" { 645 if b != "0" && b != "1" { 646 fatalf("unknown $GO_EXTLINK_ENABLED %s", b) 647 } 648 goextlinkenabled = b 649 } 650 651 gogcflags = os.Getenv("BOOT_GO_GCFLAGS") 652 653 cc, cxx := "gcc", "g++" 654 if defaultclang { 655 cc, cxx = "clang", "clang++" 656 } 657 defaultcc = compilerEnv("CC", cc) 658 defaultcxx = compilerEnv("CXX", cxx) 659 660 defaultcflags = os.Getenv("CFLAGS") 661 defaultldflags = os.Getenv("LDFLAGS") 662 663 b = os.Getenv("PKG_CONFIG") 664 if b == "" { 665 b = "pkg-config" 666 } 667 defaultpkgconfig = b 668 669 // For tools being invoked but also for os.ExpandEnv. 670 os.Setenv("GO386", go386) 671 os.Setenv("GOARCH", goarch) 672 os.Setenv("GOARM", goarm) 673 os.Setenv("GOHOSTARCH", gohostarch) 674 os.Setenv("GOHOSTOS", gohostos) 675 os.Setenv("GOOS", goos) 676 os.Setenv("GOMIPS", gomips) 677 os.Setenv("GOMIPS64", gomips64) 678 os.Setenv("GOROOT", goroot) 679 os.Setenv("GOROOT_FINAL", goroot_final) 680 681 // Use a build cache separate from the default user one. 682 // Also one that will be wiped out during startup, so that 683 // make.bash really does start from a clean slate. 684 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot)) 685 686 // Make the environment more predictable. 687 os.Setenv("LANG", "C") 688 os.Setenv("LANGUAGE", "en_US.UTF8") 689 690 workdir = xworkdir() 691 xatexit(rmworkdir) 692 693 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) 694 } 695 696 func goInstall(goBinary string, args ...string) { 697 installCmd := []string{goBinary, "install", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags} 698 if vflag > 0 { 699 installCmd = append(installCmd, "-v") 700 } 701 702 // Force only one process at a time on vx32 emulation. 703 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" { 704 installCmd = append(installCmd, "-p=1") 705 } 706 707 run(goroot, ShowOutput|CheckExit, append(installCmd, args...)...) 708 } 709 710 func checkNotStale(goBinary string, targets ...string) { 711 out := run(goroot, CheckExit, 712 append([]string{ 713 goBinary, 714 "list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags, 715 "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}", 716 }, targets...)...) 717 if strings.Contains(out, "\tSTALE ") { 718 os.Setenv("GODEBUG", "gocachehash=1") 719 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} { 720 if strings.Contains(out, "STALE "+target) { 721 run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target) 722 break 723 } 724 } 725 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out) 726 } 727 } 728 729 // compilerEnvLookup returns the compiler settings for goos/goarch in map m. 730 func compilerEnvLookup(m map[string]string, goos, goarch string) string { 731 if cc := m[goos+"/"+goarch]; cc != "" { 732 return cc 733 } 734 return m[""] 735 } 736 737 // copy copies the file src to dst, via memory (so only good for small files). 738 func copyfile(dst, src string, flag int) { 739 740 if vflag > 1 { 741 errprintf("cp %s %s\n", src, dst) 742 } 743 writefile(readfile(src), dst, flag) 744 } 745 746 // shouldbuild reports whether we should build this file. 747 // It applies the same rules that are used with context tags 748 // in package go/build, except it's less picky about the order 749 // of GOOS and GOARCH. 750 // We also allow the special tag cmd_go_bootstrap. 751 // See ../go/bootstrap.go and package go/build. 752 func shouldbuild(file, dir string) bool { 753 // Check file name for GOOS or GOARCH. 754 name := filepath.Base(file) 755 excluded := func(list []string, ok string) bool { 756 for _, x := range list { 757 if x == ok || ok == "android" && x == "linux" { 758 continue 759 } 760 i := strings.Index(name, x) 761 if i <= 0 || name[i-1] != '_' { 762 continue 763 } 764 i += len(x) 765 if i == len(name) || name[i] == '.' || name[i] == '_' { 766 return true 767 } 768 } 769 return false 770 } 771 if excluded(okgoos, goos) || excluded(okgoarch, goarch) { 772 return false 773 } 774 775 // Omit test files. 776 if strings.Contains(name, "_test") { 777 return false 778 } 779 780 // Check file contents for // +build lines. 781 for _, p := range strings.Split(readfile(file), "\n") { 782 p = strings.TrimSpace(p) 783 if p == "" { 784 continue 785 } 786 code := p 787 i := strings.Index(code, "//") 788 if i > 0 { 789 code = strings.TrimSpace(code[:i]) 790 } 791 if code == "package documentation" { 792 return false 793 } 794 if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" { 795 return false 796 } 797 if !strings.HasPrefix(p, "//") { 798 break 799 } 800 if !strings.Contains(p, "+build") { 801 continue 802 } 803 fields := strings.Fields(p[2:]) 804 if len(fields) < 1 || fields[0] != "+build" { 805 continue 806 } 807 for _, p := range fields[1:] { 808 if matchfield(p) { 809 goto fieldmatch 810 } 811 } 812 return false 813 fieldmatch: 814 } 815 816 return true 817 } 818 819 // dopack copies the package src to dst, 820 // appending the files listed in extra. 821 // The archive format is the traditional Unix ar format. 822 func dopack(dst, src string, extra []string) { 823 bdst := bytes.NewBufferString(readfile(src)) 824 for _, file := range extra { 825 b := readfile(file) 826 // find last path element for archive member name 827 i := strings.LastIndex(file, "/") + 1 828 j := strings.LastIndex(file, `\`) + 1 829 if i < j { 830 i = j 831 } 832 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b)) 833 bdst.WriteString(b) 834 if len(b)&1 != 0 { 835 bdst.WriteByte(0) 836 } 837 } 838 writefile(bdst.String(), dst, 0) 839 } 840 841 // matchfield reports whether the field (x,y,z) matches this build. 842 // all the elements in the field must be satisfied. 843 func matchfield(f string) bool { 844 for _, tag := range strings.Split(f, ",") { 845 if !matchtag(tag) { 846 return false 847 } 848 } 849 return true 850 } 851 852 // matchtag reports whether the tag (x or !x) matches this build. 853 func matchtag(tag string) bool { 854 if tag == "" { 855 return false 856 } 857 if tag[0] == '!' { 858 if len(tag) == 1 || tag[1] == '!' { 859 return false 860 } 861 return !matchtag(tag[1:]) 862 } 863 return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") 864 }