blob: 67c3a97a34e1593cd75646db5621473c9d83f022 [file] [log] [blame]
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +09001// Copyright 2015 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 main
16
17import (
18 "bytes"
19 "flag"
20 "fmt"
21 "os"
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +090022 "os/exec"
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090023 "path/filepath"
24 "runtime"
25 "runtime/pprof"
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090026 "text/template"
27 "time"
28
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090029 "github.com/golang/glog"
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090030 "github.com/google/kati"
31)
32
33const shellDateTimeformat = time.RFC3339
34
35var (
36 makefileFlag string
37 jobsFlag int
38
39 loadJSON string
40 saveJSON string
41 loadGOB string
42 saveGOB string
43 useCache bool
44
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +090045 m2n bool
46 goma bool
47
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090048 cpuprofile string
49 heapprofile string
50 memstats string
51 traceEventFile string
52 syntaxCheckOnlyFlag bool
53 queryFlag string
54 eagerCmdEvalFlag bool
55 generateNinja bool
Fumitoshi Ukaid4a016e2015-07-27 16:50:00 +090056 regenNinja bool
Fumitoshi Ukaib79b2902015-07-16 16:40:09 +090057 ninjaSuffix string
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090058 gomaDir string
Fumitoshi Ukaib92f0282015-07-21 14:05:51 +090059 detectAndroidEcho bool
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090060 shellDate string
61)
62
63func init() {
64 // TODO: Make this default and replace this by -d flag.
65 flag.StringVar(&makefileFlag, "f", "", "Use it as a makefile")
66 flag.IntVar(&jobsFlag, "j", 1, "Allow N jobs at once.")
67
68 flag.StringVar(&loadGOB, "load", "", "")
69 flag.StringVar(&saveGOB, "save", "", "")
70 flag.StringVar(&loadJSON, "load_json", "", "")
71 flag.StringVar(&saveJSON, "save_json", "", "")
72 flag.BoolVar(&useCache, "use_cache", false, "Use cache.")
73
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +090074 flag.BoolVar(&m2n, "m2n", false, "m2n mode")
75 flag.BoolVar(&goma, "goma", false, "ensure goma start")
76
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090077 flag.StringVar(&cpuprofile, "kati_cpuprofile", "", "write cpu profile to `file`")
78 flag.StringVar(&heapprofile, "kati_heapprofile", "", "write heap profile to `file`")
79 flag.StringVar(&memstats, "kati_memstats", "", "Show memstats with given templates")
80 flag.StringVar(&traceEventFile, "kati_trace_event", "", "write trace event to `file`")
81 flag.BoolVar(&syntaxCheckOnlyFlag, "c", false, "Syntax check only.")
82 flag.StringVar(&queryFlag, "query", "", "Show the target info")
83 flag.BoolVar(&eagerCmdEvalFlag, "eager_cmd_eval", false, "Eval commands first.")
84 flag.BoolVar(&generateNinja, "ninja", false, "Generate build.ninja.")
Fumitoshi Ukaid4a016e2015-07-27 16:50:00 +090085 flag.BoolVar(&regenNinja, "gen_regen_rule", false, "Generate regenerate build.ninja rule.")
Fumitoshi Ukaib79b2902015-07-16 16:40:09 +090086 flag.StringVar(&ninjaSuffix, "ninja_suffix", "", "suffix for ninja files.")
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090087 flag.StringVar(&gomaDir, "goma_dir", "", "If specified, use goma to build C/C++ files.")
Fumitoshi Ukaid1f8fb52015-07-31 17:04:23 +090088 // TODO(ukai): implement --regen
Fumitoshi Ukaib92f0282015-07-21 14:05:51 +090089 flag.BoolVar(&detectAndroidEcho, "detect_android_echo", false, "detect echo as ninja description.")
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090090
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090091 flag.StringVar(&shellDate, "shell_date", "", "specify $(shell date) time as "+shellDateTimeformat)
92
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090093 flag.BoolVar(&kati.StatsFlag, "kati_stats", false, "Show a bunch of statistics")
94 flag.BoolVar(&kati.PeriodicStatsFlag, "kati_periodic_stats", false, "Show a bunch of periodic statistics")
95 flag.BoolVar(&kati.EvalStatsFlag, "kati_eval_stats", false, "Show eval statistics")
96
97 flag.BoolVar(&kati.DryRunFlag, "n", false, "Only print the commands that would be executed")
98
99 // TODO: Make this default.
Fumitoshi Ukai0547db62015-07-29 16:20:59 +0900100 flag.BoolVar(&kati.UseFindEmulator, "use_find_emulator", false, "use find emulator")
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900101 flag.BoolVar(&kati.UseShellBuiltins, "use_shell_builtins", true, "Use shell builtins")
102 flag.StringVar(&kati.IgnoreOptionalInclude, "ignore_optional_include", "", "If specified, skip reading -include directives start with the specified path.")
103}
104
105func writeHeapProfile() {
106 f, err := os.Create(heapprofile)
107 if err != nil {
108 panic(err)
109 }
110 pprof.WriteHeapProfile(f)
111 f.Close()
112}
113
114type memStatsDumper struct {
115 *template.Template
116}
117
118func (t memStatsDumper) dump() {
119 var ms runtime.MemStats
120 runtime.ReadMemStats(&ms)
121 var buf bytes.Buffer
122 err := t.Template.Execute(&buf, ms)
123 fmt.Println(buf.String())
124 if err != nil {
125 panic(err)
126 }
127}
128
Fumitoshi Ukai43a8f492015-07-10 14:32:41 +0900129func load(req kati.LoadReq) (*kati.DepGraph, error) {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900130 if loadGOB != "" {
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +0900131 g, err := kati.GOB.Load(loadGOB)
Fumitoshi Ukai43a8f492015-07-10 14:32:41 +0900132 return g, err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900133 }
134 if loadJSON != "" {
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +0900135 g, err := kati.JSON.Load(loadJSON)
Fumitoshi Ukai43a8f492015-07-10 14:32:41 +0900136 return g, err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900137 }
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +0900138 g, err := kati.Load(req)
Fumitoshi Ukai43a8f492015-07-10 14:32:41 +0900139 return g, err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900140}
141
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900142func save(g *kati.DepGraph, targets []string) error {
143 var err error
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900144 if saveGOB != "" {
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900145 err = kati.GOB.Save(g, saveGOB, targets)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900146 }
147 if saveJSON != "" {
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900148 serr := kati.JSON.Save(g, saveJSON, targets)
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900149 if err == nil {
150 err = serr
151 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900152 }
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900153 return err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900154}
155
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900156func m2nsetup() {
157 fmt.Println("kati: m2n mode")
158 generateNinja = true
159 kati.IgnoreOptionalInclude = "out/%.P"
Fumitoshi Ukai0547db62015-07-29 16:20:59 +0900160 kati.UseFindEmulator = true
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900161}
162
163func gomasetup() {
Fumitoshi Ukai8a97a882015-07-14 13:46:55 +0900164 for _, k := range []string{"CC_WRAPPER", "CXX_WRAPPER", "JAVAC_WRAPPER"} {
165 v := os.Getenv(k)
166 if v != "" {
167 fmt.Printf("Note: %s=%s may confuse m2n --goma, unsetting", k, v)
168 os.Unsetenv(k)
169 }
170 }
171
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900172 if gomaDir == "" {
Fumitoshi Ukai3a8cca12015-07-10 14:28:29 +0900173 gomaDir = os.Getenv("GOMA_DIR")
174 if gomaDir == "" {
175 gomaDir = os.ExpandEnv("${HOME}/goma")
176 }
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900177 }
178 fmt.Printf("kati: setup goma: %s\n", gomaDir)
179 cmd := exec.Command(filepath.Join(gomaDir, "goma_ctl.py"), "ensure_start")
180 cmd.Stdout = os.Stdout
181 cmd.Stderr = os.Stderr
182 err := cmd.Run()
183 if err != nil {
184 fmt.Printf("goma failed to start: %v", err)
185 os.Exit(1)
186 }
187}
188
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900189func main() {
190 runtime.GOMAXPROCS(runtime.NumCPU())
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900191 m2ncmd := false
192 if filepath.Base(os.Args[0]) == "m2n" {
193 m2nsetup()
194 m2ncmd = true
195 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900196 flag.Parse()
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900197 args := flag.Args()
198 if m2n {
199 generateNinja = true
200 if !m2ncmd {
201 m2nsetup()
202 }
203 if len(args) > 1 {
204 fmt.Println("use only first argument as ONE_SHOT_MAKEFILE. ignore rest")
205 }
206 if len(args) > 0 {
207 err := os.Setenv("ONE_SHOT_MAKEFILE", filepath.Join(args[0], "Android.mk"))
208 if err != nil {
209 fmt.Println(err)
210 os.Exit(1)
211 }
212 fmt.Printf("ONE_SHOT_MAKEFILE=%s\n", os.ExpandEnv("${ONE_SHOT_MAKEFILE}"))
213 }
214 args = args[:0]
215 }
216 if goma {
217 gomasetup()
218 }
219 err := katiMain(args)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900220 if err != nil {
221 fmt.Println(err)
222 // http://www.gnu.org/software/make/manual/html_node/Running.html
223 os.Exit(2)
224 }
225}
226
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900227func katiMain(args []string) error {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900228 defer glog.Flush()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900229 if cpuprofile != "" {
230 f, err := os.Create(cpuprofile)
231 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900232 return err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900233 }
234 pprof.StartCPUProfile(f)
235 defer pprof.StopCPUProfile()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900236 }
237 if heapprofile != "" {
238 defer writeHeapProfile()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900239 }
240 defer kati.DumpStats()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900241 if memstats != "" {
242 ms := memStatsDumper{
243 Template: template.Must(template.New("memstats").Parse(memstats)),
244 }
245 ms.dump()
246 defer ms.dump()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900247 }
248 if traceEventFile != "" {
249 f, err := os.Create(traceEventFile)
250 if err != nil {
251 panic(err)
252 }
253 kati.TraceEventStart(f)
254 defer kati.TraceEventStop()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900255 }
256
257 if shellDate != "" {
258 if shellDate == "ref" {
259 shellDate = shellDateTimeformat[:20] // until Z, drop 07:00
260 }
261 t, err := time.Parse(shellDateTimeformat, shellDate)
262 if err != nil {
263 panic(err)
264 }
265 kati.ShellDateTimestamp = t
266 }
267
Fumitoshi Ukaid128d7a2015-06-27 01:00:01 +0900268 req := kati.FromCommandLine(args)
Fumitoshi Ukai87586e52015-06-25 17:49:35 +0900269 if makefileFlag != "" {
270 req.Makefile = makefileFlag
271 }
272 req.EnvironmentVars = os.Environ()
273 req.UseCache = useCache
Fumitoshi Ukai5c850402015-06-26 09:52:55 +0900274 req.EagerEvalCommand = eagerCmdEvalFlag
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900275
Fumitoshi Ukai43a8f492015-07-10 14:32:41 +0900276 g, err := load(req)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900277 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900278 return err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900279 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900280
Fumitoshi Ukai43a8f492015-07-10 14:32:41 +0900281 err = save(g, req.Targets)
282 if err != nil {
283 return err
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900284 }
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900285
286 if generateNinja {
Fumitoshi Ukaid4a016e2015-07-27 16:50:00 +0900287 var args []string
288 if regenNinja {
289 args = os.Args
290 }
Fumitoshi Ukaib79b2902015-07-16 16:40:09 +0900291 n := kati.NinjaGenerator{
Fumitoshi Ukaid4a016e2015-07-27 16:50:00 +0900292 Args: args,
293 Suffix: ninjaSuffix,
Fumitoshi Ukaib92f0282015-07-21 14:05:51 +0900294 GomaDir: gomaDir,
295 DetectAndroidEcho: detectAndroidEcho,
Fumitoshi Ukaib79b2902015-07-16 16:40:09 +0900296 }
Fumitoshi Ukaid4a016e2015-07-27 16:50:00 +0900297 return n.Save(g, "", req.Targets)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900298 }
299
300 if syntaxCheckOnlyFlag {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900301 return nil
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900302 }
303
304 if queryFlag != "" {
Fumitoshi Ukai3ec25b52015-06-25 15:39:35 +0900305 kati.Query(os.Stdout, queryFlag, g)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900306 return nil
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900307 }
308
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900309 execOpt := &kati.ExecutorOpt{
310 NumJobs: jobsFlag,
311 }
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +0900312 ex, err := kati.NewExecutor(execOpt)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900313 if err != nil {
314 return err
315 }
Fumitoshi Ukaie4574692015-07-16 16:55:51 +0900316 err = ex.Exec(g, req.Targets)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900317 if err != nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900318 return err
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900319 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900320 return nil
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900321}