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/pprof"
     26 
     27 	"github.com/google/blueprint"
     28 	"github.com/google/blueprint/deptools"
     29 )
     30 
     31 var (
     32 	outFile          string
     33 	depFile          string
     34 	timestampFile    string
     35 	timestampDepFile string
     36 	manifestFile     string
     37 	docFile          string
     38 	cpuprofile       string
     39 	runGoTests       bool
     40 
     41 	BuildDir string
     42 )
     43 
     44 func init() {
     45 	flag.StringVar(&outFile, "o", "build.ninja.in", "the Ninja file to output")
     46 	flag.StringVar(&BuildDir, "b", ".", "the build output directory")
     47 	flag.StringVar(&depFile, "d", "", "the dependency file to output")
     48 	flag.StringVar(&timestampFile, "timestamp", "", "file to write before the output file")
     49 	flag.StringVar(&timestampDepFile, "timestampdep", "", "the dependency file for the timestamp file")
     50 	flag.StringVar(&manifestFile, "m", "", "the bootstrap manifest file")
     51 	flag.StringVar(&docFile, "docs", "", "build documentation file to output")
     52 	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
     53 	flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
     54 }
     55 
     56 func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
     57 	if !flag.Parsed() {
     58 		flag.Parse()
     59 	}
     60 
     61 	runtime.GOMAXPROCS(runtime.NumCPU())
     62 
     63 	if cpuprofile != "" {
     64 		f, err := os.Create(cpuprofile)
     65 		if err != nil {
     66 			fatalf("error opening cpuprofile: %s", err)
     67 		}
     68 		pprof.StartCPUProfile(f)
     69 		defer f.Close()
     70 		defer pprof.StopCPUProfile()
     71 	}
     72 
     73 	if flag.NArg() != 1 {
     74 		fatalf("no Blueprints file specified")
     75 	}
     76 
     77 	stage := StageMain
     78 	if c, ok := config.(ConfigInterface); ok {
     79 		if c.GeneratingBootstrapper() {
     80 			stage = StageBootstrap
     81 		}
     82 		if c.GeneratingPrimaryBuilder() {
     83 			stage = StagePrimary
     84 		}
     85 	}
     86 
     87 	bootstrapConfig := &Config{
     88 		stage: stage,
     89 		topLevelBlueprintsFile: flag.Arg(0),
     90 		runGoTests:             runGoTests,
     91 	}
     92 
     93 	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
     94 	ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
     95 	ctx.RegisterModuleType("bootstrap_core_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StageBootstrap))
     96 	ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, StagePrimary))
     97 	ctx.RegisterTopDownMutator("bootstrap_stage", propagateStageBootstrap)
     98 	ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))
     99 
    100 	deps, errs := ctx.ParseBlueprintsFiles(bootstrapConfig.topLevelBlueprintsFile)
    101 	if len(errs) > 0 {
    102 		fatalErrors(errs)
    103 	}
    104 
    105 	// Add extra ninja file dependencies
    106 	deps = append(deps, extraNinjaFileDeps...)
    107 
    108 	errs = ctx.ResolveDependencies(config)
    109 	if len(errs) > 0 {
    110 		fatalErrors(errs)
    111 	}
    112 
    113 	if docFile != "" {
    114 		err := writeDocs(ctx, filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), docFile)
    115 		if err != nil {
    116 			fatalErrors([]error{err})
    117 		}
    118 		return
    119 	}
    120 
    121 	extraDeps, errs := ctx.PrepareBuildActions(config)
    122 	if len(errs) > 0 {
    123 		fatalErrors(errs)
    124 	}
    125 	deps = append(deps, extraDeps...)
    126 
    127 	buf := bytes.NewBuffer(nil)
    128 	err := ctx.WriteBuildFile(buf)
    129 	if err != nil {
    130 		fatalf("error generating Ninja file contents: %s", err)
    131 	}
    132 
    133 	const outFilePermissions = 0666
    134 	if timestampFile != "" {
    135 		err := ioutil.WriteFile(timestampFile, []byte{}, outFilePermissions)
    136 		if err != nil {
    137 			fatalf("error writing %s: %s", timestampFile, err)
    138 		}
    139 
    140 		if timestampDepFile != "" {
    141 			err := deptools.WriteDepFile(timestampDepFile, timestampFile, deps)
    142 			if err != nil {
    143 				fatalf("error writing depfile: %s", err)
    144 			}
    145 		}
    146 	}
    147 
    148 	err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions)
    149 	if err != nil {
    150 		fatalf("error writing %s: %s", outFile, err)
    151 	}
    152 
    153 	if depFile != "" {
    154 		err := deptools.WriteDepFile(depFile, outFile, deps)
    155 		if err != nil {
    156 			fatalf("error writing depfile: %s", err)
    157 		}
    158 		err = deptools.WriteDepFile(depFile+".timestamp", outFile+".timestamp", deps)
    159 		if err != nil {
    160 			fatalf("error writing depfile: %s", err)
    161 		}
    162 	}
    163 
    164 	if c, ok := config.(ConfigRemoveAbandonedFiles); !ok || c.RemoveAbandonedFiles() {
    165 		srcDir := filepath.Dir(bootstrapConfig.topLevelBlueprintsFile)
    166 		err := removeAbandonedFiles(ctx, bootstrapConfig, srcDir, manifestFile)
    167 		if err != nil {
    168 			fatalf("error removing abandoned files: %s", err)
    169 		}
    170 	}
    171 }
    172 
    173 func fatalf(format string, args ...interface{}) {
    174 	fmt.Printf(format, args...)
    175 	fmt.Print("\n")
    176 	os.Exit(1)
    177 }
    178 
    179 func fatalErrors(errs []error) {
    180 	red := "\x1b[31m"
    181 	unred := "\x1b[0m"
    182 
    183 	for _, err := range errs {
    184 		switch err := err.(type) {
    185 		case *blueprint.Error:
    186 			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
    187 		default:
    188 			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
    189 		}
    190 	}
    191 	os.Exit(1)
    192 }
    193