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.
23 // Initialization for any invocation.
25 // The usual variables.
41 goextlinkenabled string
42 gogcflags string // For running built compiler
50 defaultcc map[string]string
51 defaultcxx map[string]string
52 defaultpkgconfig string
59 vflag int // verbosity
62 // The known architectures.
63 var okgoarch = []string{
81 // The known operating systems.
82 var okgoos = []string{
100 // find reports the first index of p in l[0:n], or else -1.
101 func find(p string, l []string) int {
102 for i, s := range l {
110 // xinit handles initialization of the various global state, like goroot and goarch.
112 b := os.Getenv("GOROOT")
114 fatalf("$GOROOT must be set")
116 goroot = filepath.Clean(b)
117 gorootBin = pathf("%s/bin", goroot)
119 // Don't run just 'go' because the build infrastructure
120 // runs cmd/dist inside go/bin often, and on Windows
121 // it will be found in the current directory and refuse to exec.
122 // All exec calls rewrite "go" into gorootBinGo.
123 gorootBinGo = pathf("%s/bin/go", goroot)
125 b = os.Getenv("GOROOT_FINAL")
131 b = os.Getenv("GOOS")
136 if find(goos, okgoos) < 0 {
137 fatalf("unknown $GOOS %s", goos)
140 b = os.Getenv("GOARM")
146 b = os.Getenv("GO386")
152 b = os.Getenv("GOAMD64")
158 b = os.Getenv("GOMIPS")
164 b = os.Getenv("GOMIPS64")
170 b = os.Getenv("GOPPC64")
176 if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
177 fatalf("$GOROOT is not set correctly or not exported\n"+
179 "\t%s does not exist", goroot, p)
182 b = os.Getenv("GOHOSTARCH")
186 if find(gohostarch, okgoarch) < 0 {
187 fatalf("unknown $GOHOSTARCH %s", gohostarch)
190 b = os.Getenv("GOARCH")
195 if find(goarch, okgoarch) < 0 {
196 fatalf("unknown $GOARCH %s", goarch)
199 b = os.Getenv("GO_EXTLINK_ENABLED")
201 if b != "0" && b != "1" {
202 fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
207 goexperiment = os.Getenv("GOEXPERIMENT")
208 // TODO(mdempsky): Validate known experiments?
210 gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
211 goldflags = os.Getenv("BOOT_GO_LDFLAGS")
213 cc, cxx := "gcc", "g++"
215 cc, cxx = "clang", "clang++"
217 defaultcc = compilerEnv("CC", cc)
218 defaultcxx = compilerEnv("CXX", cxx)
220 b = os.Getenv("PKG_CONFIG")
226 defaultldso = os.Getenv("GO_LDSO")
228 // For tools being invoked but also for os.ExpandEnv.
229 os.Setenv("GO386", go386)
230 os.Setenv("GOAMD64", goamd64)
231 os.Setenv("GOARCH", goarch)
232 os.Setenv("GOARM", goarm)
233 os.Setenv("GOHOSTARCH", gohostarch)
234 os.Setenv("GOHOSTOS", gohostos)
235 os.Setenv("GOOS", goos)
236 os.Setenv("GOMIPS", gomips)
237 os.Setenv("GOMIPS64", gomips64)
238 os.Setenv("GOPPC64", goppc64)
239 os.Setenv("GOROOT", goroot)
240 os.Setenv("GOROOT_FINAL", goroot_final)
242 // Use a build cache separate from the default user one.
243 // Also one that will be wiped out during startup, so that
244 // make.bash really does start from a clean slate.
245 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
247 // Set GOBIN to GOROOT/bin. The meaning of GOBIN has drifted over time
248 // (see https://go.dev/issue/3269, https://go.dev/cl/183058,
249 // https://go.dev/issue/31576). Since we want binaries installed by 'dist' to
250 // always go to GOROOT/bin anyway.
251 os.Setenv("GOBIN", gorootBin)
253 // Make the environment more predictable.
254 os.Setenv("LANG", "C")
255 os.Setenv("LANGUAGE", "en_US.UTF8")
256 os.Unsetenv("GO111MODULE")
257 os.Setenv("GOENV", "off")
258 os.Unsetenv("GOFLAGS")
259 os.Setenv("GOWORK", "off")
262 if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap"), 0666); err != nil {
263 fatalf("cannot write stub go.mod: %s", err)
267 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
270 // compilerEnv returns a map from "goos/goarch" to the
271 // compiler setting to use for that platform.
272 // The entry for key "" covers any goos/goarch not explicitly set in the map.
273 // For example, compilerEnv("CC", "gcc") returns the C compiler settings
274 // read from $CC, defaulting to gcc.
276 // The result is a map because additional environment variables
277 // can be set to change the compiler based on goos/goarch settings.
278 // The following applies to all envNames but CC is assumed to simplify
281 // If no environment variables are set, we use def for all goos/goarch.
282 // $CC, if set, applies to all goos/goarch but is overridden by the following.
283 // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch,
284 // but is overridden by the following.
285 // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch.
286 // $CC_FOR_goos_goarch, if set, applies only to goos/goarch.
287 func compilerEnv(envName, def string) map[string]string {
288 m := map[string]string{"": def}
290 if env := os.Getenv(envName); env != "" {
293 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
294 if gohostos != goos || gohostarch != goarch {
295 m[gohostos+"/"+gohostarch] = m[""]
300 for _, goos := range okgoos {
301 for _, goarch := range okgoarch {
302 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
303 m[goos+"/"+goarch] = env
311 // compilerEnvLookup returns the compiler settings for goos/goarch in map m.
312 func compilerEnvLookup(m map[string]string, goos, goarch string) string {
313 if cc := m[goos+"/"+goarch]; cc != "" {
319 // rmworkdir deletes the work directory.
322 errprintf("rm -rf %s\n", workdir)
327 // Remove trailing spaces.
328 func chomp(s string) string {
329 return strings.TrimRight(s, " \t\r\n")
332 // findgoversion determines the Go version to use in the version string.
333 func findgoversion() string {
334 // The $GOROOT/VERSION file takes priority, for distributions
335 // without the source repo.
336 path := pathf("%s/VERSION", goroot)
338 b := chomp(readfile(path))
339 // Commands such as "dist version > VERSION" will cause
340 // the shell to create an empty VERSION file and set dist's
341 // stdout to its fd. dist in turn looks at VERSION and uses
342 // its content if available, which is empty at this point.
343 // Only use the VERSION file if it is non-empty.
345 // Some builders cross-compile the toolchain on linux-amd64
346 // and then copy the toolchain to the target builder (say, linux-arm)
347 // for use there. But on non-release (devel) branches, the compiler
348 // used on linux-amd64 will be an amd64 binary, and the compiler
349 // shipped to linux-arm will be an arm binary, so they will have different
350 // content IDs (they are binaries for different architectures) and so the
351 // packages compiled by the running-on-amd64 compiler will appear
352 // stale relative to the running-on-arm compiler. Avoid this by setting
353 // the version string to something that doesn't begin with devel.
354 // Then the version string will be used in place of the content ID,
355 // and the packages will look up-to-date.
356 // TODO(rsc): Really the builders could be writing out a better VERSION file instead,
357 // but it is easier to change cmd/dist than to try to make changes to
358 // the builder while Brad is away.
359 if strings.HasPrefix(b, "devel") {
360 if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") {
361 fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType)
362 b = "builder " + hostType
369 // The $GOROOT/VERSION.cache file is a cache to avoid invoking
370 // git every time we run this command. Unlike VERSION, it gets
371 // deleted by the clean command.
372 path = pathf("%s/VERSION.cache", goroot)
374 return chomp(readfile(path))
377 // Show a nicer error message if this isn't a Git repo.
379 fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
382 // Otherwise, use Git.
384 // Include 1.x base version, hash, and date in the version.
386 // Note that we lightly parse internal/goversion/goversion.go to
387 // obtain the base version. We can't just import the package,
388 // because cmd/dist is built with a bootstrap GOROOT which could
389 // be an entirely different version of Go. We assume
390 // that the file contains "const Version = <Integer>".
391 goversionSource := readfile(pathf("%s/src/internal/goversion/goversion.go", goroot))
392 m := regexp.MustCompile(`(?m)^const Version = (\d+)`).FindStringSubmatch(goversionSource)
394 fatalf("internal/goversion/goversion.go does not contain 'const Version = ...'")
396 version := fmt.Sprintf("devel go1.%s-", m[1])
397 version += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format:%h %cd", "HEAD"))
400 writefile(version, path, 0)
405 // isGitRepo reports whether the working directory is inside a Git repository.
406 func isGitRepo() bool {
407 // NB: simply checking the exit code of `git rev-parse --git-dir` would
408 // suffice here, but that requires deviating from the infrastructure
409 // provided by `run`.
410 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
411 if !filepath.IsAbs(gitDir) {
412 gitDir = filepath.Join(goroot, gitDir)
418 * Initial tree setup.
421 // The old tools that no longer live in $GOBIN or $GOROOT/bin.
422 var oldtool = []string{
423 "5a", "5c", "5g", "5l",
424 "6a", "6c", "6g", "6l",
425 "8a", "8c", "8g", "8l",
426 "9a", "9c", "9g", "9l",
445 // Unreleased directories (relative to $GOROOT) that should
446 // not be in release branches.
447 var unreleased = []string{
454 // setup sets up the tree for the initial build.
456 // Create bin directory.
457 if p := pathf("%s/bin", goroot); !isdir(p) {
461 // Create package directory.
462 if p := pathf("%s/pkg", goroot); !isdir(p) {
466 goosGoarch := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
468 xremoveall(goosGoarch)
470 xmkdirall(goosGoarch)
472 if files := xreaddir(goosGoarch); len(files) == 0 {
477 if goos != gohostos || goarch != gohostarch {
478 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
485 // Create object directory.
486 // We used to use it for C objects.
487 // Now we use it for the build cache, to separate dist's cache
488 // from any other cache the user might have, and for the location
489 // to build the bootstrap versions of the standard library.
490 obj := pathf("%s/pkg/obj", goroot)
494 xatexit(func() { xremove(obj) })
496 // Create build cache directory.
497 objGobuild := pathf("%s/pkg/obj/go-build", goroot)
499 xremoveall(objGobuild)
501 xmkdirall(objGobuild)
502 xatexit(func() { xremoveall(objGobuild) })
504 // Create directory for bootstrap versions of standard library .a files.
505 objGoBootstrap := pathf("%s/pkg/obj/go-bootstrap", goroot)
507 xremoveall(objGoBootstrap)
509 xmkdirall(objGoBootstrap)
510 xatexit(func() { xremoveall(objGoBootstrap) })
512 // Create tool directory.
513 // We keep it in pkg/, just like the object directory above.
519 // Remove tool binaries from before the tool/gohostos_gohostarch
520 xremoveall(pathf("%s/bin/tool", goroot))
522 // Remove old pre-tool binaries.
523 for _, old := range oldtool {
524 xremove(pathf("%s/bin/%s", goroot, old))
527 // For release, make sure excluded things are excluded.
528 goversion := findgoversion()
529 if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
530 for _, dir := range unreleased {
531 if p := pathf("%s/%s", goroot, dir); isdir(p) {
532 fatalf("%s should not exist in release build", p)
542 // deptab lists changes to the default dependencies for a given prefix.
543 // deps ending in /* read the whole directory; deps beginning with -
544 // exclude files with that prefix.
545 // Note that this table applies only to the build of cmd/go,
546 // after the main compiler bootstrap.
547 var deptab = []struct {
548 prefix string // prefix of target
549 dep []string // dependency tweaks for targets with that prefix
551 {"cmd/go/internal/cfg", []string{
555 {"runtime/internal/sys", []string{
558 {"go/build", []string{
561 {"time/tzdata", []string{
566 // depsuffix records the allowed suffixes for source files.
567 var depsuffix = []string{
572 // gentab records how to generate some trivial files.
573 var gentab = []struct {
575 gen func(string, string)
577 {"zdefaultcc.go", mkzdefaultcc},
578 {"zosarch.go", mkzosarch},
579 {"zversion.go", mkzversion},
581 {"zzipdata.go", mktzdata},
583 // not generated anymore, but delete the file if we see it
591 // installed maps from a dir name (as given to install) to a chan
592 // closed when the dir's package is installed.
593 var installed = make(map[string]chan struct{})
594 var installedMu sync.Mutex
596 func install(dir string) {
600 func startInstall(dir string) chan struct{} {
604 ch = make(chan struct{})
606 go runInstall(dir, ch)
612 // runInstall installs the library, package, or binary associated with dir,
613 // which is relative to $GOROOT/src.
614 func runInstall(pkg string, ch chan struct{}) {
615 if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" {
616 fatalf("go_bootstrap cannot depend on cgo package %s", pkg)
626 if goos != gohostos || goarch != gohostarch {
627 errprintf("%s (%s/%s)\n", pkg, goos, goarch)
629 errprintf("%s\n", pkg)
633 workdir := pathf("%s/%s", workdir, pkg)
638 for _, name := range clean {
643 // dir = full path to pkg.
644 dir := pathf("%s/src/%s", goroot, pkg)
645 name := filepath.Base(dir)
647 // ispkg predicts whether the package should be linked as a binary, based
648 // on the name. There should be no "main" packages in vendor, since
649 // 'go mod vendor' will only copy imported packages there.
650 ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/")
652 // Start final link command line.
653 // Note: code below knows that link.p[targ] is the target.
660 // Go library (package).
662 link = []string{"pack", packagefile(pkg)}
664 xmkdirall(filepath.Dir(link[targ]))
669 elem = "go_bootstrap"
671 link = []string{pathf("%s/link", tooldir)}
672 if goos == "android" {
673 link = append(link, "-buildmode=pie")
676 link = append(link, goldflags)
678 link = append(link, "-extld="+compilerEnvLookup(defaultcc, goos, goarch))
679 link = append(link, "-L="+pathf("%s/pkg/obj/go-bootstrap/%s_%s", goroot, goos, goarch))
680 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe))
683 ttarg := mtime(link[targ])
685 // Gather files that are sources for this target.
686 // Everything in that directory, and any target-specific
688 files := xreaddir(dir)
690 // Remove files beginning with . or _,
691 // which are likely to be editor temporary files.
692 // This is the same heuristic build.ScanDir uses.
693 // There do exist real C files beginning with _,
694 // so limit that check to just Go files.
695 files = filter(files, func(p string) bool {
696 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
699 for _, dt := range deptab {
700 if pkg == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(pkg, dt.prefix) {
701 for _, p := range dt.dep {
703 files = append(files, p)
709 // Convert to absolute paths.
710 for i, p := range files {
711 if !filepath.IsAbs(p) {
712 files[i] = pathf("%s/%s", dir, p)
716 // Is the target up-to-date?
717 var gofiles, sfiles, missing []string
719 files = filter(files, func(p string) bool {
720 for _, suf := range depsuffix {
721 if strings.HasSuffix(p, suf) {
728 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) {
731 if strings.HasSuffix(p, ".go") {
732 gofiles = append(gofiles, p)
733 } else if strings.HasSuffix(p, ".s") {
734 sfiles = append(sfiles, p)
740 missing = append(missing, p)
745 // If there are no files to compile, we're done.
754 // For package runtime, copy some files into the work space.
755 if pkg == "runtime" {
756 xmkdirall(pathf("%s/pkg/include", goroot))
757 // For use by assembly and C files.
758 copyfile(pathf("%s/pkg/include/textflag.h", goroot),
759 pathf("%s/src/runtime/textflag.h", goroot), 0)
760 copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
761 pathf("%s/src/runtime/funcdata.h", goroot), 0)
762 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
763 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
764 copyfile(pathf("%s/pkg/include/asm_amd64.h", goroot),
765 pathf("%s/src/runtime/asm_amd64.h", goroot), 0)
768 // Generate any missing files; regenerate existing ones.
769 for _, p := range files {
770 elem := filepath.Base(p)
771 for _, gt := range gentab {
775 if strings.HasPrefix(elem, gt.nameprefix) {
777 errprintf("generate %s\n", p)
780 // Do not add generated file to clean list.
781 // In runtime, we want to be able to
782 // build the package with the go tool,
783 // and it assumes these generated files already
784 // exist (it does not know how to build them).
785 // The 'clean' command can remove
786 // the generated files.
790 // Did not rebuild p.
791 if find(p, missing) >= 0 {
792 fatalf("missing file %s", p)
797 // Resolve imported packages to actual package paths.
798 // Make sure they're installed.
799 importMap := make(map[string]string)
800 for _, p := range gofiles {
801 for _, imp := range readimports(p) {
803 fatalf("%s imports C", p)
805 importMap[imp] = resolveVendor(imp, dir)
808 sortedImports := make([]string, 0, len(importMap))
809 for imp := range importMap {
810 sortedImports = append(sortedImports, imp)
812 sort.Strings(sortedImports)
814 for _, dep := range importMap {
816 fatalf("%s imports C", pkg)
820 for _, dep := range importMap {
824 if goos != gohostos || goarch != gohostarch {
825 // We've generated the right files; the go command can do the build.
827 errprintf("skip build for cross-compile %s\n", pkg)
833 pathf("%s/asm", tooldir),
835 "-I", pathf("%s/pkg/include", goroot),
836 "-D", "GOOS_" + goos,
837 "-D", "GOARCH_" + goarch,
838 "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
841 if goarch == "mips" || goarch == "mipsle" {
842 // Define GOMIPS_value from gomips.
843 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
845 if goarch == "mips64" || goarch == "mips64le" {
846 // Define GOMIPS64_value from gomips64.
847 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
849 if goarch == "ppc64" || goarch == "ppc64le" {
850 // We treat each powerpc version as a superset of functionality.
853 asmArgs = append(asmArgs, "-D", "GOPPC64_power10")
856 asmArgs = append(asmArgs, "-D", "GOPPC64_power9")
858 default: // This should always be power8.
859 asmArgs = append(asmArgs, "-D", "GOPPC64_power8")
862 goasmh := pathf("%s/go_asm.h", workdir)
863 if IsRuntimePackagePath(pkg) {
864 asmArgs = append(asmArgs, "-compiling-runtime")
867 // Collect symabis from assembly code.
870 symabis = pathf("%s/symabis", workdir)
871 var wg sync.WaitGroup
872 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
873 asmabis = append(asmabis, sfiles...)
874 if err := os.WriteFile(goasmh, nil, 0666); err != nil {
875 fatalf("cannot write empty go_asm.h: %s", err)
877 bgrun(&wg, dir, asmabis...)
881 // Build an importcfg file for the compiler.
882 buf := &bytes.Buffer{}
883 for _, imp := range sortedImports {
887 dep := importMap[imp]
889 fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
891 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
893 importcfg := pathf("%s/importcfg", workdir)
894 if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
895 fatalf("cannot write importcfg file: %v", err)
899 // The next loop will compile individual non-Go files.
900 // Hand the Go files to the compiler en masse.
901 // For packages containing assembly, this writes go_asm.h, which
902 // the assembly files will need.
904 if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
907 b := pathf("%s/_go_.a", workdir)
908 clean = append(clean, b)
910 link = append(link, b)
916 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg}
918 compile = append(compile, strings.Fields(gogcflags)...)
920 if pkg == "runtime" {
921 compile = append(compile, "-+")
924 compile = append(compile, "-asmhdr", goasmh)
927 compile = append(compile, "-symabis", symabis)
929 if goos == "android" {
930 compile = append(compile, "-shared")
933 compile = append(compile, gofiles...)
934 var wg sync.WaitGroup
935 // We use bgrun and immediately wait for it instead of calling run() synchronously.
936 // This executes all jobs through the bgwork channel and allows the process
937 // to exit cleanly in case an error occurs.
938 bgrun(&wg, dir, compile...)
941 // Compile the files.
942 for _, p := range sfiles {
943 // Assembly file for a Go package.
944 compile := asmArgs[:len(asmArgs):len(asmArgs)]
947 b := pathf("%s/%s", workdir, filepath.Base(p))
949 // Change the last character of the output file (which was c or s).
950 b = b[:len(b)-1] + "o"
951 compile = append(compile, "-o", b, p)
952 bgrun(&wg, dir, compile...)
954 link = append(link, b)
956 clean = append(clean, b)
963 dopack(link[targ], archive, link[targ+1:])
967 // Remove target before writing it.
969 bgrun(&wg, "", link...)
973 // packagefile returns the path to a compiled .a file for the given package
974 // path. Paths may need to be resolved with resolveVendor first.
975 func packagefile(pkg string) string {
976 return pathf("%s/pkg/obj/go-bootstrap/%s_%s/%s.a", goroot, goos, goarch, pkg)
979 // unixOS is the set of GOOS values matched by the "unix" build tag.
980 // This is the same list as in go/build/syslist.go and
981 // cmd/go/internal/imports/build.go.
982 var unixOS = map[string]bool{
997 // matchtag reports whether the tag matches this build.
998 func matchtag(tag string) bool {
1000 case "gc", "cmd_go_bootstrap", "go1.1":
1003 return goos == "linux" || goos == "android"
1005 return goos == "solaris" || goos == "illumos"
1007 return goos == "darwin" || goos == "ios"
1017 // shouldbuild reports whether we should build this file.
1018 // It applies the same rules that are used with context tags
1019 // in package go/build, except it's less picky about the order
1020 // of GOOS and GOARCH.
1021 // We also allow the special tag cmd_go_bootstrap.
1022 // See ../go/bootstrap.go and package go/build.
1023 func shouldbuild(file, pkg string) bool {
1024 // Check file name for GOOS or GOARCH.
1025 name := filepath.Base(file)
1026 excluded := func(list []string, ok string) bool {
1027 for _, x := range list {
1028 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") || (ok == "ios" && x == "darwin") {
1031 i := strings.Index(name, x)
1032 if i <= 0 || name[i-1] != '_' {
1036 if i == len(name) || name[i] == '.' || name[i] == '_' {
1042 if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
1047 if strings.Contains(name, "_test") {
1051 // Check file contents for //go:build lines.
1052 for _, p := range strings.Split(readfile(file), "\n") {
1053 p = strings.TrimSpace(p)
1058 i := strings.Index(code, "//")
1060 code = strings.TrimSpace(code[:i])
1062 if code == "package documentation" {
1065 if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" {
1068 if !strings.HasPrefix(p, "//") {
1071 if strings.HasPrefix(p, "//go:build ") {
1072 matched, err := matchexpr(p[len("//go:build "):])
1074 errprintf("%s: %v", file, err)
1083 // copy copies the file src to dst, via memory (so only good for small files).
1084 func copyfile(dst, src string, flag int) {
1086 errprintf("cp %s %s\n", src, dst)
1088 writefile(readfile(src), dst, flag)
1091 // dopack copies the package src to dst,
1092 // appending the files listed in extra.
1093 // The archive format is the traditional Unix ar format.
1094 func dopack(dst, src string, extra []string) {
1095 bdst := bytes.NewBufferString(readfile(src))
1096 for _, file := range extra {
1098 // find last path element for archive member name
1099 i := strings.LastIndex(file, "/") + 1
1100 j := strings.LastIndex(file, `\`) + 1
1104 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1110 writefile(bdst.String(), dst, 0)
1113 var runtimegen = []string{
1118 // cleanlist is a list of packages with generated files and commands.
1119 var cleanlist = []string{
1120 "runtime/internal/sys",
1122 "cmd/go/internal/cfg",
1127 for _, name := range cleanlist {
1128 path := pathf("%s/src/%s", goroot, name)
1129 // Remove generated files.
1130 for _, elem := range xreaddir(path) {
1131 for _, gt := range gentab {
1132 if strings.HasPrefix(elem, gt.nameprefix) {
1133 xremove(pathf("%s/%s", path, elem))
1137 // Remove generated binary named for directory.
1138 if strings.HasPrefix(name, "cmd/") {
1139 xremove(pathf("%s/%s", path, name[4:]))
1143 // remove runtimegen files.
1144 path := pathf("%s/src/runtime", goroot)
1145 for _, elem := range runtimegen {
1146 xremove(pathf("%s/%s", path, elem))
1150 // Remove object tree.
1151 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1153 // Remove installed packages and tools.
1154 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1155 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1156 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
1157 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
1160 // Remove cached version info.
1161 xremove(pathf("%s/VERSION.cache", goroot))
1166 * command implementations
1169 // The env command prints the default environment.
1171 path := flag.Bool("p", false, "emit updated PATH")
1172 plan9 := flag.Bool("9", gohostos == "plan9", "emit plan 9 syntax")
1173 windows := flag.Bool("w", gohostos == "windows", "emit windows syntax")
1176 format := "%s=\"%s\"\n"
1179 format = "%s='%s'\n"
1181 format = "set %s=%s\r\n"
1184 xprintf(format, "GO111MODULE", "")
1185 xprintf(format, "GOARCH", goarch)
1186 xprintf(format, "GOBIN", gorootBin)
1187 xprintf(format, "GOCACHE", os.Getenv("GOCACHE"))
1188 xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
1189 xprintf(format, "GOENV", "off")
1190 xprintf(format, "GOFLAGS", "")
1191 xprintf(format, "GOHOSTARCH", gohostarch)
1192 xprintf(format, "GOHOSTOS", gohostos)
1193 xprintf(format, "GOOS", goos)
1194 xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
1195 xprintf(format, "GOROOT", goroot)
1196 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
1197 xprintf(format, "GOTOOLDIR", tooldir)
1198 if goarch == "arm" {
1199 xprintf(format, "GOARM", goarm)
1201 if goarch == "386" {
1202 xprintf(format, "GO386", go386)
1204 if goarch == "amd64" {
1205 xprintf(format, "GOAMD64", goamd64)
1207 if goarch == "mips" || goarch == "mipsle" {
1208 xprintf(format, "GOMIPS", gomips)
1210 if goarch == "mips64" || goarch == "mips64le" {
1211 xprintf(format, "GOMIPS64", gomips64)
1213 if goarch == "ppc64" || goarch == "ppc64le" {
1214 xprintf(format, "GOPPC64", goppc64)
1216 xprintf(format, "GOWORK", "off")
1220 if gohostos == "windows" {
1223 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gorootBin, sep, os.Getenv("PATH")))
1228 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
1229 timeLogMu sync.Mutex
1230 timeLogFile *os.File
1231 timeLogStart time.Time
1234 func timelog(op, name string) {
1235 if !timeLogEnabled {
1239 defer timeLogMu.Unlock()
1240 if timeLogFile == nil {
1241 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
1245 buf := make([]byte, 100)
1247 s := string(buf[:n])
1248 if i := strings.Index(s, "\n"); i >= 0 {
1251 i := strings.Index(s, " start")
1253 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBUILDTIMELOGFILE"))
1255 t, err := time.Parse(time.UnixDate, s[:i])
1257 log.Fatalf("cannot parse time log line %q: %v", s, err)
1263 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
1266 var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"}
1268 // The bootstrap command runs a build from scratch,
1269 // stopping at having installed the go_bootstrap command.
1271 // WARNING: This command runs after cmd/dist is built with the Go bootstrap toolchain.
1272 // It rebuilds and installs cmd/dist with the new toolchain, so other
1273 // commands (like "go tool dist test" in run.bash) can rely on bug fixes
1274 // made since the Go bootstrap version, but this function cannot.
1275 func cmdbootstrap() {
1276 timelog("start", "dist bootstrap")
1277 defer timelog("end", "dist bootstrap")
1279 var noBanner, noClean bool
1281 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1282 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
1283 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
1284 flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning")
1289 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n")
1292 // Set GOPATH to an internal directory. We shouldn't actually
1293 // need to store files here, since the toolchain won't
1294 // depend on modules outside of vendor directories, but if
1295 // GOPATH points somewhere else (e.g., to GOROOT), the
1296 // go tool may complain.
1297 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot))
1299 // Disable GOEXPERIMENT when building toolchain1 and
1300 // go_bootstrap. We don't need any experiments for the
1301 // bootstrap toolchain, and this lets us avoid duplicating the
1302 // GOEXPERIMENT-related build logic from cmd/go here. If the
1303 // bootstrap toolchain is < Go 1.17, it will ignore this
1304 // anyway since GOEXPERIMENT is baked in; otherwise it will
1305 // pick it up from the environment we set here. Once we're
1306 // using toolchain1 with dist as the build system, we need to
1307 // override this to keep the experiments assumed by the
1308 // toolchain and by dist consistent. Once go_bootstrap takes
1309 // over the build process, we'll set this back to the original
1311 os.Setenv("GOEXPERIMENT", "none")
1314 // cmd/buildid is used in debug mode.
1315 toolchain = append(toolchain, "cmd/buildid")
1318 if isdir(pathf("%s/src/pkg", goroot)) {
1320 "The Go package sources have moved to $GOROOT/src.\n"+
1321 "*** %s still exists. ***\n"+
1322 "It probably contains stale files that may confuse the build.\n"+
1323 "Please (check what's there and) remove it and try again.\n"+
1324 "See https://golang.org/s/go14nopkg\n",
1325 pathf("%s/src/pkg", goroot))
1334 timelog("build", "toolchain1")
1336 bootstrapBuildTools()
1338 // Remember old content of $GOROOT/bin for comparison below.
1339 oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
1341 // For the main bootstrap, building for host os/arch.
1346 os.Setenv("GOHOSTARCH", gohostarch)
1347 os.Setenv("GOHOSTOS", gohostos)
1348 os.Setenv("GOARCH", goarch)
1349 os.Setenv("GOOS", goos)
1351 timelog("build", "go_bootstrap")
1352 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
1353 install("runtime") // dependency not visible in sources; also sets up textflag.h
1354 install("time/tzdata") // no dependency in sources; creates generated file
1360 gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now
1362 goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now
1363 goBootstrap := pathf("%s/go_bootstrap", tooldir)
1364 cmdGo := pathf("%s/go", gorootBin)
1366 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1367 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
1370 // To recap, so far we have built the new toolchain
1371 // (cmd/asm, cmd/cgo, cmd/compile, cmd/link)
1372 // using the Go bootstrap toolchain and go command.
1373 // Then we built the new go command (as go_bootstrap)
1374 // using the new toolchain and our own build logic (above).
1376 // toolchain1 = mk(new toolchain, go1.17 toolchain, go1.17 cmd/go)
1377 // go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)
1379 // The toolchain1 we built earlier is built from the new sources,
1380 // but because it was built using cmd/go it has no build IDs.
1381 // The eventually installed toolchain needs build IDs, so we need
1382 // to do another round:
1384 // toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)
1386 timelog("build", "toolchain2")
1390 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
1391 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
1392 // Now that cmd/go is in charge of the build process, enable GOEXPERIMENT.
1393 os.Setenv("GOEXPERIMENT", goexperiment)
1394 goInstall(goBootstrap, toolchain...)
1396 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1397 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
1400 // Toolchain2 should be semantically equivalent to toolchain1,
1401 // but it was built using the newly built compiler instead of the Go bootstrap compiler,
1402 // so it should at the least run faster. Also, toolchain1 had no build IDs
1403 // in the binaries, while toolchain2 does. In non-release builds, the
1404 // toolchain's build IDs feed into constructing the build IDs of built targets,
1405 // so in non-release builds, everything now looks out-of-date due to
1406 // toolchain2 having build IDs - that is, due to the go command seeing
1407 // that there are new compilers. In release builds, the toolchain's reported
1408 // version is used in place of the build ID, and the go command does not
1409 // see that change from toolchain1 to toolchain2, so in release builds,
1410 // nothing looks out of date.
1411 // To keep the behavior the same in both non-release and release builds,
1412 // we force-install everything here.
1414 // toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)
1416 timelog("build", "toolchain3")
1420 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1421 goInstall(goBootstrap, append([]string{"-a"}, toolchain...)...)
1423 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1424 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
1427 if goos == oldgoos && goarch == oldgoarch {
1428 // Common case - not setting up for cross-compilation.
1429 timelog("build", "toolchain")
1433 xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
1435 // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH.
1436 // Finish GOHOSTOS/GOHOSTARCH installation and then
1437 // run GOOS/GOARCH installation.
1438 timelog("build", "host toolchain")
1442 xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch)
1443 goInstall(goBootstrap, "std", "cmd")
1444 checkNotStale(goBootstrap, "std", "cmd")
1445 checkNotStale(cmdGo, "std", "cmd")
1447 timelog("build", "target toolchain")
1453 os.Setenv("GOOS", goos)
1454 os.Setenv("GOARCH", goarch)
1455 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
1456 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
1458 targets := []string{"std", "cmd"}
1459 goInstall(goBootstrap, targets...)
1460 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
1461 checkNotStale(goBootstrap, targets...)
1462 checkNotStale(cmdGo, targets...)
1464 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1465 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
1466 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
1469 // Check that there are no new files in $GOROOT/bin other than
1470 // go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling).
1471 binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
1472 ok := map[string]bool{}
1473 for _, f := range oldBinFiles {
1476 for _, f := range binFiles {
1477 elem := strings.TrimSuffix(filepath.Base(f), ".exe")
1478 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
1479 fatalf("unexpected new file in $GOROOT/bin: %s", elem)
1483 // Remove go_bootstrap now that we're done.
1484 xremove(pathf("%s/go_bootstrap", tooldir))
1486 if goos == "android" {
1487 // Make sure the exec wrapper will sync a fresh $GOROOT to the device.
1488 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
1491 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
1492 oldcc := os.Getenv("CC")
1493 os.Setenv("GOOS", gohostos)
1494 os.Setenv("GOARCH", gohostarch)
1495 os.Setenv("CC", compilerEnvLookup(defaultcc, gohostos, gohostarch))
1496 goCmd(cmdGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath)
1497 // Restore environment.
1498 // TODO(elias.naur): support environment variables in goCmd?
1499 os.Setenv("GOOS", goos)
1500 os.Setenv("GOARCH", goarch)
1501 os.Setenv("CC", oldcc)
1504 // Print trailing banner unless instructed otherwise.
1510 func wrapperPathFor(goos, goarch string) string {
1512 case goos == "android":
1513 if gohostos != "android" {
1514 return pathf("%s/misc/android/go_android_exec.go", goroot)
1517 if gohostos != "ios" {
1518 return pathf("%s/misc/ios/go_ios_exec.go", goroot)
1524 func goInstall(goBinary string, args ...string) {
1525 goCmd(goBinary, "install", args...)
1528 func appendCompilerFlags(args []string) []string {
1529 if gogcflags != "" {
1530 args = append(args, "-gcflags=all="+gogcflags)
1532 if goldflags != "" {
1533 args = append(args, "-ldflags=all="+goldflags)
1538 func goCmd(goBinary string, cmd string, args ...string) {
1539 goCmd := []string{goBinary, cmd}
1541 goCmd = append(goCmd, "-tags=noopt")
1543 goCmd = appendCompilerFlags(goCmd)
1545 goCmd = append(goCmd, "-v")
1548 // Force only one process at a time on vx32 emulation.
1549 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
1550 goCmd = append(goCmd, "-p=1")
1553 run(workdir, ShowOutput|CheckExit, append(goCmd, args...)...)
1556 func checkNotStale(goBinary string, targets ...string) {
1557 goCmd := []string{goBinary, "list"}
1559 goCmd = append(goCmd, "-tags=noopt")
1561 goCmd = appendCompilerFlags(goCmd)
1562 goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}")
1564 out := run(workdir, CheckExit, append(goCmd, targets...)...)
1565 if strings.Contains(out, "\tSTALE ") {
1566 os.Setenv("GODEBUG", "gocachehash=1")
1567 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
1568 if strings.Contains(out, "STALE "+target) {
1569 run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
1573 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v (consider rerunning with GOMAXPROCS=1 GODEBUG=gocachehash=1):\n%s", goBinary, gogcflags, goldflags, targets, out)
1577 // Cannot use go/build directly because cmd/dist for a new release
1578 // builds against an old release's go/build, which may be out of sync.
1579 // To reduce duplication, we generate the list for go/build from this.
1581 // We list all supported platforms in this list, so that this is the
1582 // single point of truth for supported platforms. This list is used
1583 // by 'go tool dist list'.
1584 var cgoEnabled = map[string]bool{
1586 "darwin/amd64": true,
1587 "darwin/arm64": true,
1588 "dragonfly/amd64": true,
1589 "freebsd/386": true,
1590 "freebsd/amd64": true,
1591 "freebsd/arm": true,
1592 "freebsd/arm64": true,
1593 "freebsd/riscv64": true,
1594 "illumos/amd64": true,
1596 "linux/amd64": true,
1598 "linux/arm64": true,
1599 "linux/loong64": true,
1600 "linux/ppc64": false,
1601 "linux/ppc64le": true,
1603 "linux/mipsle": true,
1604 "linux/mips64": true,
1605 "linux/mips64le": true,
1606 "linux/riscv64": true,
1607 "linux/s390x": true,
1608 "linux/sparc64": true,
1609 "android/386": true,
1610 "android/amd64": true,
1611 "android/arm": true,
1612 "android/arm64": true,
1617 "netbsd/amd64": true,
1619 "netbsd/arm64": true,
1620 "openbsd/386": true,
1621 "openbsd/amd64": true,
1622 "openbsd/arm": true,
1623 "openbsd/arm64": true,
1624 "openbsd/mips64": true,
1626 "plan9/amd64": false,
1628 "solaris/amd64": true,
1629 "windows/386": true,
1630 "windows/amd64": true,
1631 "windows/arm": false,
1632 "windows/arm64": true,
1635 // List of platforms which are supported but not complete yet. These get
1636 // filtered out of cgoEnabled for 'dist list'. See golang.org/issue/28944
1637 var incomplete = map[string]bool{
1638 "linux/sparc64": true,
1641 // List of platforms which are first class ports. See golang.org/issue/38874.
1642 var firstClass = map[string]bool{
1643 "darwin/amd64": true,
1644 "darwin/arm64": true,
1646 "linux/amd64": true,
1648 "linux/arm64": true,
1649 "windows/386": true,
1650 "windows/amd64": true,
1653 func needCC() bool {
1654 switch os.Getenv("CGO_ENABLED") {
1660 return cgoEnabled[gohostos+"/"+gohostarch]
1667 cc, err := quotedSplit(defaultcc[""])
1669 fatalf("split CC: %v", err)
1671 var ccHelp = append(cc, "--help")
1673 if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil {
1675 if len(output) > 0 {
1676 outputHdr = "\nCommand output:\n\n"
1678 fatalf("cannot invoke C compiler %q: %v\n\n"+
1679 "Go needs a system C compiler for use with cgo.\n"+
1680 "To set a C compiler, set CC=the-compiler.\n"+
1681 "To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output)
1685 func defaulttarg() string {
1686 // xgetwd might return a path with symlinks fully resolved, and if
1687 // there happens to be symlinks in goroot, then the hasprefix test
1688 // will never succeed. Instead, we use xrealwd to get a canonical
1689 // goroot/src before the comparison to avoid this problem.
1691 src := pathf("%s/src/", goroot)
1692 real_src := xrealwd(src)
1693 if !strings.HasPrefix(pwd, real_src) {
1694 fatalf("current directory %s is not under %s", pwd, real_src)
1696 pwd = pwd[len(real_src):]
1697 // guard against xrealwd returning the directory without the trailing /
1698 pwd = strings.TrimPrefix(pwd, "/")
1703 // Install installs the list of packages named on the command line.
1707 if flag.NArg() == 0 {
1708 install(defaulttarg())
1711 for _, arg := range flag.Args() {
1716 // Clean deletes temporary objects.
1722 // Banner prints the 'now you've installed Go' banner.
1733 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1734 xprintf("Installed commands in %s\n", gorootBin)
1736 if !xsamefile(goroot_final, goroot) {
1737 // If the files are to be moved, don't check that gobin
1738 // is on PATH; assume they know what they are doing.
1739 } else if gohostos == "plan9" {
1740 // Check that GOROOT/bin is bound before /bin.
1741 pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
1742 ns := fmt.Sprintf("/proc/%s/ns", pid)
1743 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) {
1744 xprintf("*** You need to bind %s before /bin.\n", gorootBin)
1747 // Check that GOROOT/bin appears in $PATH.
1749 if gohostos == "windows" {
1752 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gorootBin+pathsep) {
1753 xprintf("*** You need to add %s to your PATH.\n", gorootBin)
1757 if !xsamefile(goroot_final, goroot) {
1759 "The binaries expect %s to be copied or moved to %s\n",
1760 goroot, goroot_final)
1764 // Version prints the Go version.
1767 xprintf("%s\n", findgoversion())
1770 // cmdlist lists all supported platforms.
1772 jsonFlag := flag.Bool("json", false, "produce JSON output")
1776 for p := range cgoEnabled {
1780 plats = append(plats, p)
1785 for _, p := range plats {
1791 type jsonResult struct {
1797 var results []jsonResult
1798 for _, p := range plats {
1799 fields := strings.Split(p, "/")
1800 results = append(results, jsonResult{
1803 CgoSupported: cgoEnabled[p],
1804 FirstClass: firstClass[p]})
1806 out, err := json.MarshalIndent(results, "", "\t")
1808 fatalf("json marshal error: %v", err)
1810 if _, err := os.Stdout.Write(out); err != nil {
1811 fatalf("write failed: %v", err)
1815 // IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
1816 // belongs to the collection of "runtime-related" packages, including
1817 // "runtime" itself, "reflect", "syscall", and the
1818 // "runtime/internal/*" packages.
1820 // Keep in sync with cmd/internal/objabi/path.go:IsRuntimePackagePath.
1821 func IsRuntimePackagePath(pkgpath string) bool {
1830 case "internal/bytealg":
1833 rval = strings.HasPrefix(pkgpath, "runtime/internal")
1839 for _, gcflag := range strings.Split(gogcflags, " ") {
1840 if gcflag == "-N" || gcflag == "-l" {