blob: 932cfd715ca7bb18d176b58d4832991e395671df [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// 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
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package bootstrap
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "flag"
20 "fmt"
21 "io/ioutil"
22 "os"
Jamie Gennisc4ed7092014-11-09 11:58:40 -080023 "path/filepath"
Colin Cross5bdb4ca2015-04-14 17:22:19 -070024 "runtime"
Colin Cross63d5d4d2015-04-20 16:41:55 -070025 "runtime/pprof"
Colin Cross5bdb4ca2015-04-14 17:22:19 -070026
27 "github.com/google/blueprint"
28 "github.com/google/blueprint/deptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029)
30
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070031var (
Jamie Gennisc4ed7092014-11-09 11:58:40 -080032 outFile string
33 depFile string
34 checkFile string
35 manifestFile string
Colin Cross4572edd2015-05-13 14:36:24 -070036 docFile string
Jamie Gennisc4ed7092014-11-09 11:58:40 -080037 cpuprofile string
Dan Willemsen87ba2942015-06-23 17:21:00 -070038 runGoTests bool
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070039)
Jamie Gennis1bc967e2014-05-27 16:34:41 -070040
Jamie Gennis1bc967e2014-05-27 16:34:41 -070041func init() {
42 flag.StringVar(&outFile, "o", "build.ninja.in", "the Ninja file to output")
43 flag.StringVar(&depFile, "d", "", "the dependency file to output")
Jamie Genniscbc6f862014-06-05 20:00:22 -070044 flag.StringVar(&checkFile, "c", "", "the existing file to check against")
Jamie Gennisc4ed7092014-11-09 11:58:40 -080045 flag.StringVar(&manifestFile, "m", "", "the bootstrap manifest file")
Colin Cross4572edd2015-05-13 14:36:24 -070046 flag.StringVar(&docFile, "docs", "", "build documentation file to output")
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070047 flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
Dan Willemsen87ba2942015-06-23 17:21:00 -070048 flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
Jamie Gennis1bc967e2014-05-27 16:34:41 -070049}
50
Christopher Horvath3159cb72014-06-26 15:34:06 -070051func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070052 if !flag.Parsed() {
53 flag.Parse()
54 }
55
Colin Cross5bdb4ca2015-04-14 17:22:19 -070056 runtime.GOMAXPROCS(runtime.NumCPU())
57
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070058 if cpuprofile != "" {
59 f, err := os.Create(cpuprofile)
60 if err != nil {
61 fatalf("error opening cpuprofile: %s", err)
62 }
63 pprof.StartCPUProfile(f)
64 defer f.Close()
65 defer pprof.StopCPUProfile()
66 }
67
Jamie Gennis1bc967e2014-05-27 16:34:41 -070068 if flag.NArg() != 1 {
69 fatalf("no Blueprints file specified")
70 }
71
Dan Willemsen30a80c32015-06-24 19:21:21 -070072 generatingBootstrapper := false
73 if c, ok := config.(ConfigInterface); ok {
74 generatingBootstrapper = c.GeneratingBootstrapper()
75 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -070076
Dan Willemsen30a80c32015-06-24 19:21:21 -070077 bootstrapConfig := &Config{
78 generatingBootstrapper: generatingBootstrapper,
79 topLevelBlueprintsFile: flag.Arg(0),
Dan Willemsen87ba2942015-06-23 17:21:00 -070080 runGoTests: runGoTests,
Dan Willemsen30a80c32015-06-24 19:21:21 -070081 }
82
83 ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
84 ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig))
85 ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))
86
87 deps, errs := ctx.ParseBlueprintsFiles(bootstrapConfig.topLevelBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -070088 if len(errs) > 0 {
89 fatalErrors(errs)
90 }
91
Christopher Horvath3159cb72014-06-26 15:34:06 -070092 // Add extra ninja file dependencies
93 deps = append(deps, extraNinjaFileDeps...)
94
Colin Cross4572edd2015-05-13 14:36:24 -070095 errs = ctx.ResolveDependencies(config)
96 if len(errs) > 0 {
97 fatalErrors(errs)
98 }
99
100 if docFile != "" {
101 err := writeDocs(ctx, filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), docFile)
102 if err != nil {
103 fatalErrors([]error{err})
104 }
105 return
106 }
107
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700108 extraDeps, errs := ctx.PrepareBuildActions(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109 if len(errs) > 0 {
110 fatalErrors(errs)
111 }
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700112 deps = append(deps, extraDeps...)
113
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700114 buf := bytes.NewBuffer(nil)
115 err := ctx.WriteBuildFile(buf)
116 if err != nil {
117 fatalf("error generating Ninja file contents: %s", err)
118 }
119
Jamie Genniscbc6f862014-06-05 20:00:22 -0700120 const outFilePermissions = 0666
121 err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122 if err != nil {
123 fatalf("error writing %s: %s", outFile, err)
124 }
125
Jamie Genniscbc6f862014-06-05 20:00:22 -0700126 if checkFile != "" {
127 checkData, err := ioutil.ReadFile(checkFile)
128 if err != nil {
129 fatalf("error reading %s: %s", checkFile, err)
130 }
131
132 matches := buf.Len() == len(checkData)
Jamie Gennisa22f3e52014-06-11 16:24:23 -0700133 if matches {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700134 for i, value := range buf.Bytes() {
135 if value != checkData[i] {
136 matches = false
137 break
138 }
139 }
140 }
141
142 if matches {
143 // The new file content matches the check-file content, so we set
144 // the new file's mtime and atime to match that of the check-file.
145 checkFileInfo, err := os.Stat(checkFile)
146 if err != nil {
147 fatalf("error stat'ing %s: %s", checkFile, err)
148 }
149
150 time := checkFileInfo.ModTime()
151 err = os.Chtimes(outFile, time, time)
152 if err != nil {
153 fatalf("error setting timestamps for %s: %s", outFile, err)
154 }
155 }
156 }
157
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700158 if depFile != "" {
Jamie Gennisfbb27fe2014-10-14 04:30:17 -0400159 err := deptools.WriteDepFile(depFile, outFile, deps)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700160 if err != nil {
161 fatalf("error writing depfile: %s", err)
162 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700163 }
Jamie Gennisaf435562014-10-27 22:34:56 -0700164
Dan Willemsen30a80c32015-06-24 19:21:21 -0700165 srcDir := filepath.Dir(bootstrapConfig.topLevelBlueprintsFile)
166 err = removeAbandonedFiles(ctx, bootstrapConfig, srcDir, manifestFile)
Jamie Gennisaf435562014-10-27 22:34:56 -0700167 if err != nil {
168 fatalf("error removing abandoned files: %s", err)
169 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700170}
171
172func fatalf(format string, args ...interface{}) {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700173 fmt.Printf(format, args...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700174 os.Exit(1)
175}
176
177func fatalErrors(errs []error) {
178 for _, err := range errs {
179 switch err.(type) {
180 case *blueprint.Error:
Jamie Genniscbc6f862014-06-05 20:00:22 -0700181 _, _ = fmt.Printf("%s\n", err.Error())
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700182 default:
Jamie Genniscbc6f862014-06-05 20:00:22 -0700183 _, _ = fmt.Printf("internal error: %s\n", err)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700184 }
185 }
186 os.Exit(1)
187}