• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
15package bootstrap
16
17import (
18	"bufio"
19	"fmt"
20	"io"
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)
31
32type Args struct {
33	ModuleListFile string
34	OutFile        string
35
36	EmptyNinjaFile bool
37
38	NoGC       bool
39	Cpuprofile string
40	Memprofile string
41	TraceFile  string
42}
43
44// Returns the list of dependencies the emitted Ninja files has. These can be
45// written to the .d file for the output so that it is correctly rebuilt when
46// needed in case Blueprint is itself invoked from Ninja
47func RunBlueprint(args Args, stopBefore StopBefore, ctx *blueprint.Context, config interface{}) []string {
48	runtime.GOMAXPROCS(runtime.NumCPU())
49
50	if args.NoGC {
51		debug.SetGCPercent(-1)
52	}
53
54	if args.Cpuprofile != "" {
55		f, err := os.Create(joinPath(ctx.SrcDir(), args.Cpuprofile))
56		if err != nil {
57			fatalf("error opening cpuprofile: %s", err)
58		}
59		pprof.StartCPUProfile(f)
60		defer f.Close()
61		defer pprof.StopCPUProfile()
62	}
63
64	if args.TraceFile != "" {
65		f, err := os.Create(joinPath(ctx.SrcDir(), args.TraceFile))
66		if err != nil {
67			fatalf("error opening trace: %s", err)
68		}
69		trace.Start(f)
70		defer f.Close()
71		defer trace.Stop()
72	}
73
74	srcDir := "."
75
76	ninjaDeps := make([]string, 0)
77
78	if args.ModuleListFile != "" {
79		ctx.SetModuleListFile(args.ModuleListFile)
80		ninjaDeps = append(ninjaDeps, args.ModuleListFile)
81	} else {
82		fatalf("-l <moduleListFile> is required and must be nonempty")
83	}
84	ctx.BeginEvent("list_modules")
85	filesToParse, err := ctx.ListModulePaths(srcDir)
86	ctx.EndEvent("list_modules")
87	if err != nil {
88		fatalf("could not enumerate files: %v\n", err.Error())
89	}
90
91	ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
92	ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory())
93	ctx.RegisterModuleType("blueprint_go_binary", newGoBinaryModuleFactory())
94	ctx.RegisterSingletonType("bootstrap", newSingletonFactory())
95	blueprint.RegisterPackageIncludesModuleType(ctx)
96
97	ctx.BeginEvent("parse_bp")
98	blueprintFiles, errs := ctx.ParseFileList(".", filesToParse, config)
99	if len(errs) > 0 {
100		fatalErrors(errs)
101	}
102	ctx.EndEvent("parse_bp")
103
104	// Add extra ninja file dependencies
105	ninjaDeps = append(ninjaDeps, blueprintFiles...)
106
107	extraDeps, errs := ctx.ResolveDependencies(config)
108	if len(errs) > 0 {
109		fatalErrors(errs)
110	}
111	ninjaDeps = append(ninjaDeps, extraDeps...)
112
113	if stopBefore == StopBeforePrepareBuildActions {
114		return ninjaDeps
115	}
116
117	extraDeps, errs = ctx.PrepareBuildActions(config)
118	if len(errs) > 0 {
119		fatalErrors(errs)
120	}
121	ninjaDeps = append(ninjaDeps, extraDeps...)
122
123	if stopBefore == StopBeforeWriteNinja {
124		return ninjaDeps
125	}
126
127	const outFilePermissions = 0666
128	var out io.StringWriter
129	var f *os.File
130	var buf *bufio.Writer
131
132	ctx.BeginEvent("write_files")
133	defer ctx.EndEvent("write_files")
134	if args.EmptyNinjaFile {
135		if err := ioutil.WriteFile(joinPath(ctx.SrcDir(), args.OutFile), []byte(nil), outFilePermissions); err != nil {
136			fatalf("error writing empty Ninja file: %s", err)
137		}
138	}
139
140	if !args.EmptyNinjaFile {
141		f, err = os.OpenFile(joinPath(ctx.SrcDir(), args.OutFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, outFilePermissions)
142		if err != nil {
143			fatalf("error opening Ninja file: %s", err)
144		}
145		buf = bufio.NewWriterSize(f, 16*1024*1024)
146		out = buf
147	} else {
148		out = ioutil.Discard.(io.StringWriter)
149	}
150
151	err = ctx.WriteBuildFile(out)
152	if err != nil {
153		fatalf("error writing Ninja file contents: %s", err)
154	}
155
156	if buf != nil {
157		err = buf.Flush()
158		if err != nil {
159			fatalf("error flushing Ninja file contents: %s", err)
160		}
161	}
162
163	if f != nil {
164		err = f.Close()
165		if err != nil {
166			fatalf("error closing Ninja file: %s", err)
167		}
168	}
169
170	if args.Memprofile != "" {
171		f, err := os.Create(joinPath(ctx.SrcDir(), args.Memprofile))
172		if err != nil {
173			fatalf("error opening memprofile: %s", err)
174		}
175		defer f.Close()
176		pprof.WriteHeapProfile(f)
177	}
178
179	return ninjaDeps
180}
181
182func fatalf(format string, args ...interface{}) {
183	fmt.Printf(format, args...)
184	fmt.Print("\n")
185	os.Exit(1)
186}
187
188func fatalErrors(errs []error) {
189	red := "\x1b[31m"
190	unred := "\x1b[0m"
191
192	for _, err := range errs {
193		switch err := err.(type) {
194		case *blueprint.BlueprintError,
195			*blueprint.ModuleError,
196			*blueprint.PropertyError:
197			fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
198		default:
199			fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
200		}
201	}
202	os.Exit(1)
203}
204
205func joinPath(base, path string) string {
206	if filepath.IsAbs(path) {
207		return path
208	}
209	return filepath.Join(base, path)
210}
211