Home | History | Annotate | Download | only in bootstrap
      1 // Copyright 2014 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package bootstrap
     16 
     17 import (
     18 	"bytes"
     19 	"flag"
     20 	"fmt"
     21 	"io/ioutil"
     22 	"os"
     23 	"path/filepath"
     24 	"runtime"
     25 	"runtime/debug"
     26 	"runtime/pprof"
     27 	"runtime/trace"
     28 
     29 	"github.com/google/blueprint"
     30 	"github.com/google/blueprint/deptools"
     31 )
     32 
     33 var (
     34 	outFile    string
     35 	depFile    string
     36 	docFile    string
     37 	cpuprofile string
     38 	memprofile string
     39 	traceFile  string
     40 	runGoTests bool
     41 	noGC       bool
     42 
     43 	BuildDir string
     44 	SrcDir   string
     45 )
     46 
     47 func init() {
     48 	flag.StringVar(&outFile, "o", "build.ninja.in", "the Ninja file to output")
     49 	flag.StringVar(&BuildDir, "b", ".", "the build output directory")
     50 	flag.StringVar(&depFile, "d", "", "the dependency file to output")
     51 	flag.StringVar(&docFile, "docs", "", "build documentation file to output")
     52 	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
     53 	flag.StringVar(&traceFile, "trace", "", "write trace to file")
     54 	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to file")
     55 	flag.BoolVar(&noGC, "nogc", false, "turn off GC for debugging")
     56 	flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
     57 }
     58 
     59 func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
     60 	if !flag.Parsed() {
     61 		flag.Parse()
     62 	}
     63 
     64 	runtime.GOMAXPROCS(runtime.NumCPU())
     65 
     66 	if noGC {
     67 		debug.SetGCPercent(-1)
     68 	}
     69 
     70 	if cpuprofile != "" {
     71 		f, err := os.Create(cpuprofile)
     72 		if err != nil {
     73 			fatalf("error opening cpuprofile: %s", err)
     74 		}
     75 		pprof.StartCPUProfile(f)
     76 		defer f.Close()
     77 		defer pprof.StopCPUProfile()
     78 	}
     79 
     80 	if traceFile != "" {
     81 		f, err := os.Create(traceFile)
     82 		if err != nil {
     83 			fatalf("error opening trace: %s", err)
     84 		}
     85 		trace.Start(f)
     86 		defer f.Close()
     87 		defer trace.Stop()
     88 	}
     89 
     90 	if flag.NArg() != 1 {
     91 		fatalf("no Blueprints file specified")
     92 	}
     93 
     94 	SrcDir = filepath.Dir(flag.Arg(0))
     95 
     96 	stage := StageMain
     97 	if c, ok := config.(ConfigInterface); ok {
     98 		if c.GeneratingBootstrapper() {
     99 			stage = StageBootstrap
    100 		}
    101 		if c.GeneratingPrimaryBuilder() {
    102 			stage = StagePrimary
    103 		}
    104 	}
    105 
    106 	bootstrapConfig := &Config{
    107 		stage: stage,
    108 		topLevelBlueprintsFile: flag.Arg(0),
    109 		runGoTests:             runGoTests,
    110 	}
    111 
    112 	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
    113 	ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
    114 	ctx.RegisterModuleType("bootstrap_core_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StageBootstrap))
    115 	ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StagePrimary))
    116 	ctx.RegisterModuleType("blueprint_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StageMain))
    117 	ctx.RegisterTopDownMutator("bootstrap_stage", propagateStageBootstrap)
    118 	ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))
    119 
    120 	ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))
    121 
    122 	deps, errs := ctx.ParseBlueprintsFiles(bootstrapConfig.topLevelBlueprintsFile)
    123 	if len(errs) > 0 {
    124 		fatalErrors(errs)
    125 	}
    126 
    127 	// Add extra ninja file dependencies
    128 	deps = append(deps, extraNinjaFileDeps...)
    129 
    130 	errs = ctx.ResolveDependencies(config)
    131 	if len(errs) > 0 {
    132 		fatalErrors(errs)
    133 	}
    134 
    135 	if docFile != "" {
    136 		err := writeDocs(ctx, filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), docFile)
    137 		if err != nil {
    138 			fatalErrors([]error{err})
    139 		}
    140 		return
    141 	}
    142 
    143 	extraDeps, errs := ctx.PrepareBuildActions(config)
    144 	if len(errs) > 0 {
    145 		fatalErrors(errs)
    146 	}
    147 	deps = append(deps, extraDeps...)
    148 
    149 	buf := bytes.NewBuffer(nil)
    150 	err := ctx.WriteBuildFile(buf)
    151 	if err != nil {
    152 		fatalf("error generating Ninja file contents: %s", err)
    153 	}
    154 
    155 	const outFilePermissions = 0666
    156 	err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions)
    157 	if err != nil {
    158 		fatalf("error writing %s: %s", outFile, err)
    159 	}
    160 
    161 	if depFile != "" {
    162 		err := deptools.WriteDepFile(depFile, outFile, deps)
    163 		if err != nil {
    164 			fatalf("error writing depfile: %s", err)
    165 		}
    166 	}
    167 
    168 	if c, ok := config.(ConfigRemoveAbandonedFiles); !ok || c.RemoveAbandonedFiles() {
    169 		err := removeAbandonedFiles(ctx, bootstrapConfig, SrcDir)
    170 		if err != nil {
    171 			fatalf("error removing abandoned files: %s", err)
    172 		}
    173 	}
    174 
    175 	if memprofile != "" {
    176 		f, err := os.Create(memprofile)
    177 		if err != nil {
    178 			fatalf("error opening memprofile: %s", err)
    179 		}
    180 		defer f.Close()
    181 		pprof.WriteHeapProfile(f)
    182 	}
    183 }
    184 
    185 func fatalf(format string, args ...interface{}) {
    186 	fmt.Printf(format, args...)
    187 	fmt.Print("\n")
    188 	os.Exit(1)
    189 }
    190 
    191 func fatalErrors(errs []error) {
    192 	red := "\x1b[31m"
    193 	unred := "\x1b[0m"
    194 
    195 	for _, err := range errs {
    196 		switch err := err.(type) {
    197 		case *blueprint.BlueprintError,
    198 			*blueprint.ModuleError,
    199 			*blueprint.PropertyError:
    200 			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
    201 		default:
    202 			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
    203 		}
    204 	}
    205 	os.Exit(1)
    206 }
    207