зеркало из https://github.com/golang/build.git
286 строки
7.3 KiB
Go
286 строки
7.3 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// racebuild builds the race runtime (syso files) on all supported OSes using gomote.
|
|
// Usage:
|
|
// $ racebuild -rev <llvm_revision> -goroot <path_to_go_repo>
|
|
package main
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
var (
|
|
flagGoroot = flag.String("goroot", "", "path to Go repository to update (required)")
|
|
flagRev = flag.String("rev", "", "llvm compiler-rt git revision from http://llvm.org/git/compiler-rt.git (required)")
|
|
)
|
|
|
|
// TODO: use buildlet package instead of calling out to gomote.
|
|
var platforms = []*Platform{
|
|
&Platform{
|
|
OS: "freebsd",
|
|
Arch: "amd64",
|
|
Type: "freebsd-amd64-race",
|
|
Script: `#!/usr/bin/env bash
|
|
set -e
|
|
git clone https://go.googlesource.com/go
|
|
git clone http://llvm.org/git/compiler-rt.git
|
|
(cd compiler-rt && git checkout $REV)
|
|
(cd compiler-rt/lib/tsan/go && CC=clang ./buildgo.sh)
|
|
cp compiler-rt/lib/tsan/go/race_freebsd_amd64.syso go/src/runtime/race
|
|
(cd go/src && ./race.bash)
|
|
`,
|
|
},
|
|
&Platform{
|
|
OS: "darwin",
|
|
Arch: "amd64",
|
|
Type: "darwin-amd64-10_10",
|
|
Script: `#!/usr/bin/env bash
|
|
set -e
|
|
git clone https://go.googlesource.com/go
|
|
git clone http://llvm.org/git/compiler-rt.git
|
|
(cd compiler-rt && git checkout $REV)
|
|
(cd compiler-rt/lib/tsan/go && CC=clang ./buildgo.sh)
|
|
cp compiler-rt/lib/tsan/go/race_darwin_amd64.syso go/src/runtime/race
|
|
(cd go/src && ./race.bash)
|
|
`,
|
|
},
|
|
&Platform{
|
|
OS: "linux",
|
|
Arch: "amd64",
|
|
Type: "linux-amd64-race",
|
|
Script: `#!/usr/bin/env bash
|
|
set -e
|
|
apt-get update
|
|
apt-get install -y git g++
|
|
git clone https://go.googlesource.com/go
|
|
git clone http://llvm.org/git/compiler-rt.git
|
|
(cd compiler-rt && git checkout $REV)
|
|
(cd compiler-rt/lib/tsan/go && ./buildgo.sh)
|
|
cp compiler-rt/lib/tsan/go/race_linux_amd64.syso go/src/runtime/race
|
|
(cd go/src && ./race.bash)
|
|
`,
|
|
},
|
|
&Platform{
|
|
OS: "windows",
|
|
Arch: "amd64",
|
|
Type: "windows-amd64-race",
|
|
Script: `
|
|
git clone https://go.googlesource.com/go
|
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
|
git clone http://llvm.org/git/compiler-rt.git
|
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
|
cd compiler-rt
|
|
git checkout %REV%
|
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
|
cd ..
|
|
cd compiler-rt/lib/tsan/go
|
|
call build.bat
|
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
|
cd ../../../..
|
|
xcopy compiler-rt\lib\tsan\go\race_windows_amd64.syso go\src\runtime\race\race_windows_amd64.syso /Y
|
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
|
cd go/src
|
|
call race.bat
|
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
|
`,
|
|
},
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if *flagRev == "" || *flagGoroot == "" {
|
|
flag.PrintDefaults()
|
|
os.Exit(1)
|
|
}
|
|
|
|
// Update revision in the README file.
|
|
// Do this early to check goroot correctness.
|
|
readmeFile := filepath.Join(*flagGoroot, "src", "runtime", "race", "README")
|
|
readme, err := ioutil.ReadFile(readmeFile)
|
|
if err != nil {
|
|
log.Fatalf("bad -goroot? %v", err)
|
|
}
|
|
readmeRev := regexp.MustCompile("Current runtime is built on rev ([0-9,a-z]+)\\.").FindSubmatchIndex(readme)
|
|
if readmeRev == nil {
|
|
log.Fatalf("failed to find current revision in src/runtime/race/README")
|
|
}
|
|
readme = bytes.Replace(readme, readme[readmeRev[2]:readmeRev[3]], []byte(*flagRev), -1)
|
|
if err := ioutil.WriteFile(readmeFile, readme, 0640); err != nil {
|
|
log.Fatalf("failed to write README file: %v", err)
|
|
}
|
|
|
|
// Start build on all platforms in parallel.
|
|
var wg sync.WaitGroup
|
|
wg.Add(len(platforms))
|
|
for _, p := range platforms {
|
|
p := p
|
|
go func() {
|
|
defer wg.Done()
|
|
p.Err = p.Build()
|
|
if p.Err != nil {
|
|
p.Err = fmt.Errorf("failed: %v", p.Err)
|
|
log.Printf("%v: %v", p.Name, p.Err)
|
|
}
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
|
|
// Duplicate results, they can get lost in the log.
|
|
ok := true
|
|
log.Printf("---")
|
|
for _, p := range platforms {
|
|
if p.Err == nil {
|
|
log.Printf("%v: ok", p.Name)
|
|
continue
|
|
}
|
|
ok = false
|
|
log.Printf("%v: %v", p.Name, p.Err)
|
|
}
|
|
if !ok {
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
type Platform struct {
|
|
OS string
|
|
Arch string
|
|
Name string // something for logging
|
|
Type string // gomote instance type
|
|
Inst string // actual gomote instance name
|
|
Err error
|
|
Log *os.File
|
|
Script string
|
|
}
|
|
|
|
func (p *Platform) Build() error {
|
|
p.Name = fmt.Sprintf("%v-%v", p.OS, p.Arch)
|
|
|
|
// Open log file.
|
|
var err error
|
|
p.Log, err = ioutil.TempFile("", p.Name)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create log file: %v", err)
|
|
}
|
|
defer p.Log.Close()
|
|
log.Printf("%v: logging to %v", p.Name, p.Log.Name())
|
|
|
|
// Create gomote instance (or reuse an existing instance for debugging).
|
|
if p.Inst == "" {
|
|
// Creation sometimes fails with transient errors like:
|
|
// "buildlet didn't come up at http://10.240.0.13 in 3m0s".
|
|
var createErr error
|
|
for i := 0; i < 10; i++ {
|
|
inst, err := p.Gomote("create", p.Type)
|
|
if err != nil {
|
|
log.Printf("%v: instance creation failed, retrying", p.Name)
|
|
createErr = err
|
|
continue
|
|
}
|
|
p.Inst = strings.Trim(string(inst), " \t\n")
|
|
break
|
|
}
|
|
if p.Inst == "" {
|
|
return createErr
|
|
}
|
|
}
|
|
defer p.Gomote("destroy", p.Inst)
|
|
log.Printf("%s: using instance %v", p.Name, p.Inst)
|
|
|
|
// put14
|
|
if _, err := p.Gomote("put14", p.Inst); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Execute the script.
|
|
script, err := ioutil.TempFile("", "racebuild")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create temp file: %v", err)
|
|
}
|
|
defer func() {
|
|
script.Close()
|
|
os.Remove(script.Name())
|
|
}()
|
|
if _, err := script.Write([]byte(p.Script)); err != nil {
|
|
return fmt.Errorf("failed to write temp file: %v", err)
|
|
}
|
|
script.Close()
|
|
targetName := "script.bash"
|
|
if p.OS == "windows" {
|
|
targetName = "script.bat"
|
|
}
|
|
if _, err := p.Gomote("put", "-mode=0700", p.Inst, script.Name(), targetName); err != nil {
|
|
return err
|
|
}
|
|
if _, err := p.Gomote("run", "-e=REV="+*flagRev, p.Inst, targetName); err != nil {
|
|
return err
|
|
}
|
|
|
|
// The script is supposed to leave updated runtime at that path. Copy it out.
|
|
syso := fmt.Sprintf("race_%v_%s.syso", p.OS, p.Arch)
|
|
targz, err := p.Gomote("gettar", "-dir=go/src/runtime/race/"+syso, p.Inst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Untar the runtime and write it to goroot.
|
|
if err := p.WriteSyso(filepath.Join(*flagGoroot, "src", "runtime", "race", syso), targz); err != nil {
|
|
return fmt.Errorf("%v", err)
|
|
}
|
|
|
|
log.Printf("%v: build completed", p.Name)
|
|
return nil
|
|
}
|
|
|
|
func (p *Platform) WriteSyso(sysof string, targz []byte) error {
|
|
// Ungzip.
|
|
gzipr, err := gzip.NewReader(bytes.NewReader(targz))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read gzip archive: %v", err)
|
|
}
|
|
defer gzipr.Close()
|
|
tr := tar.NewReader(gzipr)
|
|
if _, err := tr.Next(); err != nil {
|
|
return fmt.Errorf("failed to read tar archive: %v", err)
|
|
}
|
|
|
|
// Copy the file.
|
|
syso, err := os.Create(sysof)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open race runtime: %v", err)
|
|
}
|
|
defer syso.Close()
|
|
if _, err := io.Copy(syso, tr); err != nil {
|
|
return fmt.Errorf("failed to write race runtime: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *Platform) Gomote(args ...string) ([]byte, error) {
|
|
log.Printf("%v: gomote %v", p.Name, args)
|
|
fmt.Fprintf(p.Log, "$ gomote %v\n", args)
|
|
output, err := exec.Command("gomote", args...).CombinedOutput()
|
|
if err != nil || args[0] != "gettar" {
|
|
p.Log.Write(output)
|
|
}
|
|
fmt.Fprintf(p.Log, "\n\n")
|
|
if err != nil {
|
|
err = fmt.Errorf("gomote %v failed: %v", args, err)
|
|
}
|
|
return output, err
|
|
}
|