| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // The makefuchsia.go script builds a GOROOT in the out/ build directory |
| // using sources from third_party/go. |
| package main |
| |
| import ( |
| "bytes" |
| "flag" |
| "fmt" |
| "log" |
| "os" |
| "os/exec" |
| "path/filepath" |
| "strings" |
| "time" |
| ) |
| |
| var ( |
| cc = flag.String("cc", "", "Path to C compiler") |
| cxx = flag.String("cxx", "", "Path to C++ compiler") |
| gocache = flag.String("gocache", "", "Path to GOCACHE") |
| goroot = flag.String("goroot", "", "Path to the output GOROOT") |
| gorootBootstrap = flag.String("goroot-bootstrap", "", "Path to go root used for bootstrap") |
| sysroot = flag.String("sysroot", "", "Path to sysroot") |
| |
| depfilePath = flag.String("depfile", "", "depfile to write into") |
| stampPath = flag.String("stamp-file", "", "Path of a file to create upon completion") |
| ) |
| |
| func absOrPanic(path string) string { |
| abs, err := filepath.Abs(path) |
| if err != nil { |
| log.Fatalf("Failed to make %s absolute: %s", path, err) |
| } |
| return abs |
| } |
| |
| func main() { |
| log.SetFlags(log.Lshortfile) |
| flag.Parse() |
| |
| // Provide the narrowest possible PATH. |
| var path []string |
| for _, bin := range []string{ |
| // make.bash uses bash in its shebang. |
| "bash", |
| // make.bash uses rm. |
| "rm", |
| // make.bash uses uname, which we do not vendor. |
| "uname", |
| } { |
| binPath, err := exec.LookPath(bin) |
| if err != nil { |
| log.Fatalf("exec.LookPath(%s): %s", bin, err) |
| } |
| path = append(path, filepath.Dir(binPath)) |
| } |
| |
| // Make all paths in ENV absolute since we will switch CWD. |
| cc := absOrPanic(*cc) |
| cxx := absOrPanic(*cxx) |
| gocache := absOrPanic(*gocache) |
| gorootBootstrap := absOrPanic(*gorootBootstrap) |
| sysroot := absOrPanic(*sysroot) |
| |
| cmd := exec.Cmd{ |
| Path: "make.bash", |
| Env: []string{ |
| fmt.Sprintf("CC=%s", cc), |
| fmt.Sprintf("CXX=%s", cxx), |
| fmt.Sprintf("CGO_CFLAGS=--sysroot=%s", sysroot), |
| fmt.Sprintf("CGO_CPPFLAGS=--sysroot=%s", sysroot), |
| fmt.Sprintf("CGO_CXXFLAGS=--sysroot=%s", sysroot), |
| fmt.Sprintf("CGO_LDFLAGS=--sysroot=%s", sysroot), |
| fmt.Sprintf("GOCACHE=%s", gocache), |
| fmt.Sprintf("GOROOT_BOOTSTRAP=%s", gorootBootstrap), |
| fmt.Sprintf("PATH=%s", strings.Join(path, ":")), |
| // At the time of writing, we are in the process of upgrading from go1.17 |
| // to go1.18, and go1.18 invokes git in order to embed version information |
| // into built binaries. Unfortunately we have a number of build targets |
| // that declare the git index as an input, and git likes to refresh the |
| // index on certain operations. Setting this environment variable |
| // suppresses the index refresh behavior, and should allow us to upgrade |
| // to go1.18 without breaking build convergence. See also |
| // https://fxbug.dev/42175708 for this issue popping up elsewhere. While this |
| // cmd does not directly invoke `go`, it runs a script that itself invokes |
| // `go` (see //third_party/go/src/make.bash). |
| "GIT_OPTIONAL_LOCKS=0", |
| }, |
| Dir: filepath.Join(*goroot, "src"), |
| } |
| if tmp, ok := os.LookupEnv("TMPDIR"); ok { |
| cmd.Env = append(cmd.Env, "TMPDIR="+tmp) |
| } |
| if out, err := cmd.CombinedOutput(); err != nil { |
| log.Fatalf("%s failed: %s:\n%s", cmd.Args, err, out) |
| } |
| |
| var buf bytes.Buffer |
| buf.WriteString(*stampPath) |
| buf.WriteByte(':') |
| if err := filepath.Walk(*goroot, func(path string, info os.FileInfo, err error) error { |
| if err != nil { |
| return err |
| } |
| if !info.IsDir() { |
| buf.WriteByte(' ') |
| buf.WriteString(path) |
| } |
| return nil |
| }); err != nil { |
| log.Fatalf("filepath.Walk(%s, _): %s", *goroot, err) |
| } |
| |
| buf.WriteByte('\n') |
| |
| if err := os.WriteFile(*depfilePath, buf.Bytes(), os.ModePerm); err != nil { |
| log.Fatalf("os.WriteFile(%s, _, os.ModePerm): %s", *depfilePath, err) |
| } |
| |
| f, err := os.OpenFile(*stampPath, os.O_CREATE|os.O_TRUNC, os.ModePerm) |
| if err != nil { |
| log.Fatalf("os.OpenFile(%s, os.O_CREATE|os.O_TRUNC, os.ModePerm): %s", *stampPath, err) |
| } |
| if err := f.Close(); err != nil { |
| log.Fatalf("%s.Close(): %s", f.Name(), err) |
| } |
| now := time.Now() |
| if err := os.Chtimes(*stampPath, now, now); err != nil { |
| log.Fatalf("os.Chtimes(%[1]s, %[2]s, %[2]s): %[3]s", *stampPath, now, err) |
| } |
| } |