blob: db61fba5c5246efd8fa0aa36995adcc725171b80 [file] [log] [blame]
Dan Willemsen1e704462016-08-21 15:17:17 -07001// Copyright 2017 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 "context"
Dan Willemsen051133b2017-07-14 11:29:29 -070019 "flag"
20 "fmt"
Dan Willemsen1e704462016-08-21 15:17:17 -070021 "os"
22 "path/filepath"
23 "strconv"
24 "strings"
25 "time"
26
27 "android/soong/ui/build"
28 "android/soong/ui/logger"
Nan Zhang17f27672018-12-12 16:01:49 -080029 "android/soong/ui/metrics"
Dan Willemsenb82471a2018-05-17 16:37:09 -070030 "android/soong/ui/status"
31 "android/soong/ui/terminal"
Dan Willemsend9f6fa22016-08-21 15:17:17 -070032 "android/soong/ui/tracer"
Dan Willemsen1e704462016-08-21 15:17:17 -070033)
34
Patrice Arrudaa5c25422019-04-09 18:49:49 -070035// A command represents an operation to be executed in the soong build
36// system.
37type command struct {
38 // the flag name (must have double dashes)
39 flag string
40
41 // description for the flag (to display when running help)
42 description string
43
Colin Crossc0b9f6b2019-09-23 12:44:54 -070044 // Forces the status output into dumb terminal mode.
45 forceDumbOutput bool
46
47 // Sets a prefix string to use for filenames of log files.
48 logsPrefix string
49
Patrice Arrudaa5c25422019-04-09 18:49:49 -070050 // Creates the build configuration based on the args and build context.
51 config func(ctx build.Context, args ...string) build.Config
52
53 // Returns what type of IO redirection this Command requires.
54 stdio func() terminal.StdioInterface
55
56 // run the command
57 run func(ctx build.Context, config build.Config, args []string, logsDir string)
58}
59
60const makeModeFlagName = "--make-mode"
61
62// list of supported commands (flags) supported by soong ui
63var commands []command = []command{
64 {
65 flag: makeModeFlagName,
66 description: "build the modules by the target name (i.e. soong_docs)",
67 config: func(ctx build.Context, args ...string) build.Config {
68 return build.NewConfig(ctx, args...)
69 },
Patrice Arrudab7b22822019-05-21 17:46:23 -070070 stdio: stdio,
71 run: make,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070072 }, {
Colin Crossc0b9f6b2019-09-23 12:44:54 -070073 flag: "--dumpvar-mode",
74 description: "print the value of the legacy make variable VAR to stdout",
75 forceDumbOutput: true,
76 logsPrefix: "dumpvars-",
77 config: dumpVarConfig,
78 stdio: customStdio,
79 run: dumpVar,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070080 }, {
Colin Crossc0b9f6b2019-09-23 12:44:54 -070081 flag: "--dumpvars-mode",
82 description: "dump the values of one or more legacy make variables, in shell syntax",
83 forceDumbOutput: true,
84 logsPrefix: "dumpvars-",
85 config: dumpVarConfig,
86 stdio: customStdio,
87 run: dumpVars,
Patrice Arrudab7b22822019-05-21 17:46:23 -070088 }, {
89 flag: "--build-mode",
90 description: "build modules based on the specified build action",
91 config: buildActionConfig,
92 stdio: stdio,
93 run: make,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070094 },
95}
96
97// indexList returns the index of first found s. -1 is return if s is not
98// found.
Dan Willemsen1e704462016-08-21 15:17:17 -070099func indexList(s string, list []string) int {
100 for i, l := range list {
101 if l == s {
102 return i
103 }
104 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700105 return -1
106}
107
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700108// inList returns true if one or more of s is in the list.
Dan Willemsen1e704462016-08-21 15:17:17 -0700109func inList(s string, list []string) bool {
110 return indexList(s, list) != -1
111}
112
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700113// Main execution of soong_ui. The command format is as follows:
114//
115// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
116//
117// Command is the type of soong_ui execution. Only one type of
118// execution is specified. The args are specific to the command.
Dan Willemsen1e704462016-08-21 15:17:17 -0700119func main() {
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700120 c, args := getCommand(os.Args)
121 if c == nil {
122 fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
123 os.Exit(1)
Dan Willemsenc35b3812018-07-16 19:59:10 -0700124 }
125
Colin Crossc0b9f6b2019-09-23 12:44:54 -0700126 output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput,
Colin Crosse0df1a32019-06-09 19:40:08 -0700127 build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700128
Colin Crosse0df1a32019-06-09 19:40:08 -0700129 log := logger.New(output)
Dan Willemsen1e704462016-08-21 15:17:17 -0700130 defer log.Cleanup()
131
Dan Willemsen1e704462016-08-21 15:17:17 -0700132 ctx, cancel := context.WithCancel(context.Background())
133 defer cancel()
134
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700135 trace := tracer.New(log)
136 defer trace.Close()
Dan Willemsen1e704462016-08-21 15:17:17 -0700137
Nan Zhang17f27672018-12-12 16:01:49 -0800138 met := metrics.New()
139
Dan Willemsenb82471a2018-05-17 16:37:09 -0700140 stat := &status.Status{}
141 defer stat.Finish()
Colin Crosse0df1a32019-06-09 19:40:08 -0700142 stat.AddOutput(output)
Dan Willemsenb82471a2018-05-17 16:37:09 -0700143 stat.AddOutput(trace.StatusTracer())
144
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700145 build.SetupSignals(log, cancel, func() {
146 trace.Close()
147 log.Cleanup()
Dan Willemsenb82471a2018-05-17 16:37:09 -0700148 stat.Finish()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700149 })
150
Dan Willemsen59339a22018-07-22 21:18:45 -0700151 buildCtx := build.Context{ContextImpl: &build.ContextImpl{
Dan Willemsenb82471a2018-05-17 16:37:09 -0700152 Context: ctx,
153 Logger: log,
Nan Zhang17f27672018-12-12 16:01:49 -0800154 Metrics: met,
Dan Willemsenb82471a2018-05-17 16:37:09 -0700155 Tracer: trace,
Colin Crosse0df1a32019-06-09 19:40:08 -0700156 Writer: output,
Dan Willemsenb82471a2018-05-17 16:37:09 -0700157 Status: stat,
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700158 }}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700159
160 config := c.config(buildCtx, args...)
Dan Willemsen1e704462016-08-21 15:17:17 -0700161
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700162 build.SetupOutDir(buildCtx, config)
Dan Willemsen8a073a82017-02-04 17:30:44 -0800163
Dan Willemsenb82471a2018-05-17 16:37:09 -0700164 logsDir := config.OutDir()
Dan Willemsen8a073a82017-02-04 17:30:44 -0800165 if config.Dist() {
Dan Willemsenb82471a2018-05-17 16:37:09 -0700166 logsDir = filepath.Join(config.DistDir(), "logs")
Dan Willemsen8a073a82017-02-04 17:30:44 -0800167 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700168
Dan Willemsenb82471a2018-05-17 16:37:09 -0700169 os.MkdirAll(logsDir, 0777)
Colin Crossc0b9f6b2019-09-23 12:44:54 -0700170 log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
171 trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
172 stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, c.logsPrefix+"verbose.log")))
173 stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
174 stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
Colin Cross7b624532019-06-21 15:08:30 -0700175 stat.AddOutput(status.NewCriticalPath(log))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700176
Colin Cross8b8bec32019-11-15 13:18:43 -0800177 buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
178 buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
179 config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
180
Colin Crossc0b9f6b2019-09-23 12:44:54 -0700181 defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics"))
Nan Zhangd50f53b2019-01-07 20:26:51 -0800182
Dan Willemsen1e704462016-08-21 15:17:17 -0700183 if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
184 if !strings.HasSuffix(start, "N") {
185 if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
186 log.Verbosef("Took %dms to start up.",
187 time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
Nan Zhang17f27672018-12-12 16:01:49 -0800188 buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
Dan Willemsen1e704462016-08-21 15:17:17 -0700189 }
190 }
Dan Willemsencae59bc2017-07-13 14:27:31 -0700191
192 if executable, err := os.Executable(); err == nil {
193 trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
194 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700195 }
196
Dan Willemsen6b783c82019-03-08 11:42:28 -0800197 // Fix up the source tree due to a repo bug where it doesn't remove
198 // linkfiles that have been removed
199 fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.bp")
200 fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.mk")
201
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700202 f := build.NewSourceFinder(buildCtx, config)
203 defer f.Shutdown()
204 build.FindSources(buildCtx, config, f)
205
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700206 c.run(buildCtx, config, args, logsDir)
Dan Willemsen051133b2017-07-14 11:29:29 -0700207}
208
Dan Willemsen6b783c82019-03-08 11:42:28 -0800209func fixBadDanglingLink(ctx build.Context, name string) {
210 _, err := os.Lstat(name)
211 if err != nil {
212 return
213 }
214 _, err = os.Stat(name)
215 if os.IsNotExist(err) {
216 err = os.Remove(name)
217 if err != nil {
218 ctx.Fatalf("Failed to remove dangling link %q: %v", name, err)
219 }
220 }
221}
222
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700223func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700224 flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
225 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700226 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
227 fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
228 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700229
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700230 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that prints the human-readable config banner")
231 fmt.Fprintln(ctx.Writer, "from the beginning of the build.")
232 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700233 flags.PrintDefaults()
234 }
235 abs := flags.Bool("abs", false, "Print the absolute path of the value")
236 flags.Parse(args)
237
238 if flags.NArg() != 1 {
239 flags.Usage()
240 os.Exit(1)
241 }
242
243 varName := flags.Arg(0)
244 if varName == "report_config" {
245 varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
246 if err != nil {
247 ctx.Fatal(err)
248 }
249
250 fmt.Println(build.Banner(varData))
251 } else {
252 varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
253 if err != nil {
254 ctx.Fatal(err)
255 }
256
257 if *abs {
258 var res []string
259 for _, path := range strings.Fields(varData[varName]) {
260 if abs, err := filepath.Abs(path); err == nil {
261 res = append(res, abs)
262 } else {
263 ctx.Fatalln("Failed to get absolute path of", path, err)
264 }
265 }
266 fmt.Println(strings.Join(res, " "))
267 } else {
268 fmt.Println(varData[varName])
269 }
270 }
271}
272
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700273func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700274 flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
275 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700276 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
277 fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
278 fmt.Fprintln(ctx.Writer, "shell syntax. The resulting output may be sourced directly into a shell to")
279 fmt.Fprintln(ctx.Writer, "set corresponding shell variables.")
280 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700281
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700282 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that dumps a variable containing the")
283 fmt.Fprintln(ctx.Writer, "human-readable config banner from the beginning of the build.")
284 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700285 flags.PrintDefaults()
286 }
287
288 varsStr := flags.String("vars", "", "Space-separated list of variables to dump")
289 absVarsStr := flags.String("abs-vars", "", "Space-separated list of variables to dump (using absolute paths)")
290
291 varPrefix := flags.String("var-prefix", "", "String to prepend to all variable names when dumping")
292 absVarPrefix := flags.String("abs-var-prefix", "", "String to prepent to all absolute path variable names when dumping")
293
294 flags.Parse(args)
295
296 if flags.NArg() != 0 {
297 flags.Usage()
298 os.Exit(1)
299 }
300
301 vars := strings.Fields(*varsStr)
302 absVars := strings.Fields(*absVarsStr)
303
304 allVars := append([]string{}, vars...)
305 allVars = append(allVars, absVars...)
306
307 if i := indexList("report_config", allVars); i != -1 {
308 allVars = append(allVars[:i], allVars[i+1:]...)
309 allVars = append(allVars, build.BannerVars...)
310 }
311
312 if len(allVars) == 0 {
313 return
314 }
315
316 varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
317 if err != nil {
318 ctx.Fatal(err)
319 }
320
321 for _, name := range vars {
322 if name == "report_config" {
323 fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
324 } else {
325 fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
326 }
327 }
328 for _, name := range absVars {
329 var res []string
330 for _, path := range strings.Fields(varData[name]) {
331 abs, err := filepath.Abs(path)
332 if err != nil {
333 ctx.Fatalln("Failed to get absolute path of", path, err)
334 }
335 res = append(res, abs)
336 }
337 fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
338 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700339}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700340
Patrice Arrudab7b22822019-05-21 17:46:23 -0700341func stdio() terminal.StdioInterface {
342 return terminal.StdioImpl{}
343}
344
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700345func customStdio() terminal.StdioInterface {
346 return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
347}
348
349// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
350func dumpVarConfig(ctx build.Context, args ...string) build.Config {
351 return build.NewConfig(ctx)
352}
353
Patrice Arrudab7b22822019-05-21 17:46:23 -0700354func buildActionConfig(ctx build.Context, args ...string) build.Config {
355 flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
356 flags.Usage = func() {
357 fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
358 fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
359 fmt.Fprintln(ctx.Writer, "action. The --dir flag is required to determine what is needed to")
360 fmt.Fprintln(ctx.Writer, "build in the source tree based on the build action. See below for")
361 fmt.Fprintln(ctx.Writer, "the list of acceptable build action flags.")
362 fmt.Fprintln(ctx.Writer, "")
363 flags.PrintDefaults()
364 }
365
366 buildActionFlags := []struct {
Dan Willemsence41e942019-07-29 23:39:30 -0700367 name string
368 description string
369 action build.BuildAction
370 set bool
Patrice Arrudab7b22822019-05-21 17:46:23 -0700371 }{{
Dan Willemsence41e942019-07-29 23:39:30 -0700372 name: "all-modules",
373 description: "Build action: build from the top of the source tree.",
374 action: build.BUILD_MODULES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700375 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700376 // This is redirecting to mma build command behaviour. Once it has soaked for a
377 // while, the build command is deleted from here once it has been removed from the
378 // envsetup.sh.
379 name: "modules-in-a-dir-no-deps",
380 description: "Build action: builds all of the modules in the current directory without their dependencies.",
381 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700382 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700383 // This is redirecting to mmma build command behaviour. Once it has soaked for a
384 // while, the build command is deleted from here once it has been removed from the
385 // envsetup.sh.
386 name: "modules-in-dirs-no-deps",
387 description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
388 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700389 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700390 name: "modules-in-a-dir",
391 description: "Build action: builds all of the modules in the current directory and their dependencies.",
392 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700393 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700394 name: "modules-in-dirs",
395 description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
396 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700397 }}
398 for i, flag := range buildActionFlags {
399 flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
400 }
401 dir := flags.String("dir", "", "Directory of the executed build command.")
402
403 // Only interested in the first two args which defines the build action and the directory.
404 // The remaining arguments are passed down to the config.
405 const numBuildActionFlags = 2
406 if len(args) < numBuildActionFlags {
407 flags.Usage()
408 ctx.Fatalln("Improper build action arguments.")
409 }
410 flags.Parse(args[0:numBuildActionFlags])
411
412 // The next block of code is to validate that exactly one build action is set and the dir flag
413 // is specified.
414 buildActionCount := 0
415 var buildAction build.BuildAction
Patrice Arrudab7b22822019-05-21 17:46:23 -0700416 for _, flag := range buildActionFlags {
417 if flag.set {
418 buildActionCount++
419 buildAction = flag.action
Patrice Arrudab7b22822019-05-21 17:46:23 -0700420 }
421 }
422 if buildActionCount != 1 {
423 ctx.Fatalln("Build action not defined.")
424 }
425 if *dir == "" {
426 ctx.Fatalln("-dir not specified.")
427 }
428
429 // Remove the build action flags from the args as they are not recognized by the config.
430 args = args[numBuildActionFlags:]
Dan Willemsence41e942019-07-29 23:39:30 -0700431 return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
Patrice Arrudab7b22822019-05-21 17:46:23 -0700432}
433
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700434func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
435 if config.IsVerbose() {
436 writer := ctx.Writer
Colin Cross097ed2a2019-06-08 21:48:58 -0700437 fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
438 fmt.Fprintln(writer, "! Instead, the verbose log is always written to a compressed file in the output dir:")
439 fmt.Fprintln(writer, "!")
440 fmt.Fprintf(writer, "! gzip -cd %s/verbose.log.gz | less -R\n", logsDir)
441 fmt.Fprintln(writer, "!")
442 fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
443 fmt.Fprintln(writer, "")
Dan Willemsenc6360832019-07-25 14:07:36 -0700444 select {
445 case <-time.After(5 * time.Second):
446 case <-ctx.Done():
447 return
448 }
449 }
450
451 if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
452 writer := ctx.Writer
Dan Willemsence41e942019-07-29 23:39:30 -0700453 fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
Dan Willemsenc6360832019-07-25 14:07:36 -0700454 fmt.Fprintln(writer, "!")
455 fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
456 fmt.Fprintln(writer, "!")
457 fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
458 fmt.Fprintln(writer, "")
Dan Willemsence41e942019-07-29 23:39:30 -0700459 ctx.Fatal("done")
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700460 }
461
462 toBuild := build.BuildAll
463 if config.Checkbuild() {
464 toBuild |= build.RunBuildTests
465 }
466 build.Build(ctx, config, toBuild)
467}
468
469// getCommand finds the appropriate command based on args[1] flag. args[0]
470// is the soong_ui filename.
471func getCommand(args []string) (*command, []string) {
472 if len(args) < 2 {
473 return nil, args
474 }
475
476 for _, c := range commands {
477 if c.flag == args[1] {
478 return &c, args[2:]
479 }
480
481 // special case for --make-mode: if soong_ui was called from
482 // build/make/core/main.mk, the makeparallel with --ninja
483 // option specified puts the -j<num> before --make-mode.
484 // TODO: Remove this hack once it has been fixed.
485 if c.flag == makeModeFlagName {
486 if inList(makeModeFlagName, args) {
487 return &c, args[1:]
488 }
489 }
490 }
491
492 // command not found
493 return nil, args
494}