blob: d4c0d4daf5139f0e71aaf7025dfdc812164b51e7 [file] [log] [blame]
// 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 (
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() {
// Provide the narrowest possible PATH.
var path []string
for _, bin := range []string{
// make.bash uses bash in its shebang.
// make.bash uses rm.
// make.bash uses uname, which we do not vendor.
} {
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
// 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).
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
if err := filepath.Walk(*goroot, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
if !info.IsDir() {
buf.WriteByte(' ')
return nil
}); err != nil {
log.Fatalf("filepath.Walk(%s, _): %s", *goroot, err)
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)