blob: 2d3156a462f229fd10965cc28862560152dd5e38 [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"
Liz Kammera7541782022-02-07 13:38:52 -050025 "syscall"
Dan Willemsen1e704462016-08-21 15:17:17 -070026 "time"
27
Lukacs T. Berki7d613bf2021-03-02 10:09:41 +010028 "android/soong/shared"
Dan Willemsen1e704462016-08-21 15:17:17 -070029 "android/soong/ui/build"
30 "android/soong/ui/logger"
Nan Zhang17f27672018-12-12 16:01:49 -080031 "android/soong/ui/metrics"
Lukacs T. Berkif656b842021-08-11 11:10:28 +020032 "android/soong/ui/signal"
Dan Willemsenb82471a2018-05-17 16:37:09 -070033 "android/soong/ui/status"
34 "android/soong/ui/terminal"
Dan Willemsend9f6fa22016-08-21 15:17:17 -070035 "android/soong/ui/tracer"
Dan Willemsen1e704462016-08-21 15:17:17 -070036)
37
Patrice Arrudaa5c25422019-04-09 18:49:49 -070038// A command represents an operation to be executed in the soong build
39// system.
40type command struct {
Patrice Arrudaf445ba12020-07-28 17:49:01 +000041 // The flag name (must have double dashes).
Patrice Arrudaa5c25422019-04-09 18:49:49 -070042 flag string
43
Patrice Arrudaf445ba12020-07-28 17:49:01 +000044 // Description for the flag (to display when running help).
Patrice Arrudaa5c25422019-04-09 18:49:49 -070045 description string
46
Patrice Arrudaf445ba12020-07-28 17:49:01 +000047 // Stream the build status output into the simple terminal mode.
48 simpleOutput bool
Colin Crossc0b9f6b2019-09-23 12:44:54 -070049
50 // Sets a prefix string to use for filenames of log files.
51 logsPrefix string
52
Patrice Arrudaa5c25422019-04-09 18:49:49 -070053 // Creates the build configuration based on the args and build context.
54 config func(ctx build.Context, args ...string) build.Config
55
56 // Returns what type of IO redirection this Command requires.
57 stdio func() terminal.StdioInterface
58
59 // run the command
MarkDacek6614d9c2022-12-07 21:57:38 +000060 run func(ctx build.Context, config build.Config, args []string)
Patrice Arrudaa5c25422019-04-09 18:49:49 -070061}
62
Patrice Arrudaa5c25422019-04-09 18:49:49 -070063// list of supported commands (flags) supported by soong ui
Usta6feae382021-12-13 12:31:50 -050064var commands = []command{
Patrice Arrudaa5c25422019-04-09 18:49:49 -070065 {
Anton Hansson5a7861a2021-06-04 10:09:01 +010066 flag: "--make-mode",
Patrice Arrudaa5c25422019-04-09 18:49:49 -070067 description: "build the modules by the target name (i.e. soong_docs)",
Usta Shrestha59417a12022-08-05 17:14:49 -040068 config: build.NewConfig,
69 stdio: stdio,
70 run: runMake,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070071 }, {
Patrice Arrudaf445ba12020-07-28 17:49:01 +000072 flag: "--dumpvar-mode",
73 description: "print the value of the legacy make variable VAR to stdout",
74 simpleOutput: true,
75 logsPrefix: "dumpvars-",
76 config: dumpVarConfig,
77 stdio: customStdio,
78 run: dumpVar,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070079 }, {
Patrice Arrudaf445ba12020-07-28 17:49:01 +000080 flag: "--dumpvars-mode",
81 description: "dump the values of one or more legacy make variables, in shell syntax",
82 simpleOutput: true,
83 logsPrefix: "dumpvars-",
84 config: dumpVarConfig,
85 stdio: customStdio,
86 run: dumpVars,
Patrice Arrudab7b22822019-05-21 17:46:23 -070087 }, {
88 flag: "--build-mode",
89 description: "build modules based on the specified build action",
90 config: buildActionConfig,
91 stdio: stdio,
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +010092 run: runMake,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070093 },
94}
95
96// indexList returns the index of first found s. -1 is return if s is not
97// found.
Dan Willemsen1e704462016-08-21 15:17:17 -070098func indexList(s string, list []string) int {
99 for i, l := range list {
100 if l == s {
101 return i
102 }
103 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700104 return -1
105}
106
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700107// inList returns true if one or more of s is in the list.
Dan Willemsen1e704462016-08-21 15:17:17 -0700108func inList(s string, list []string) bool {
109 return indexList(s, list) != -1
110}
111
Jason Wucc166a72022-12-19 11:53:12 -0500112func deleteStaleMetrics(metricsFilePathSlice []string) error {
113 for _, metricsFilePath := range metricsFilePathSlice {
114 if err := os.Remove(metricsFilePath); err != nil && !os.IsNotExist(err) {
115 return fmt.Errorf("Failed to remove %s\nError message: %w", metricsFilePath, err)
116 }
117 }
118 return nil
119}
120
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700121// Main execution of soong_ui. The command format is as follows:
122//
Usta Shrestha59417a12022-08-05 17:14:49 -0400123// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700124//
125// Command is the type of soong_ui execution. Only one type of
126// execution is specified. The args are specific to the command.
Dan Willemsen1e704462016-08-21 15:17:17 -0700127func main() {
Lukacs T. Berki7d613bf2021-03-02 10:09:41 +0100128 shared.ReexecWithDelveMaybe(os.Getenv("SOONG_UI_DELVE"), shared.ResolveDelveBinary())
129
Patrice Arruda73c790f2020-07-13 23:01:18 +0000130 buildStarted := time.Now()
Patrice Arruda219eef32020-06-01 17:29:30 +0000131
Liz Kammer0e7993e2020-10-15 11:07:13 -0700132 c, args, err := getCommand(os.Args)
133 if err != nil {
134 fmt.Fprintf(os.Stderr, "Error parsing `soong` args: %s.\n", err)
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700135 os.Exit(1)
Dan Willemsenc35b3812018-07-16 19:59:10 -0700136 }
137
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800138 // Create a terminal output that mimics Ninja's.
Patrice Arrudaf445ba12020-07-28 17:49:01 +0000139 output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.simpleOutput,
Colin Cross3c0fe0e2021-02-10 13:11:18 -0800140 build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"),
141 build.OsEnvironment().IsEnvTrue("SOONG_UI_ANSI_OUTPUT"))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700142
Liz Kammerf2a80c62022-10-21 10:42:35 -0400143 // Create and start a new metric record.
144 met := metrics.New()
145 met.SetBuildDateTime(buildStarted)
146 met.SetBuildCommand(os.Args)
147
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800148 // Attach a new logger instance to the terminal output.
Liz Kammerf2a80c62022-10-21 10:42:35 -0400149 log := logger.NewWithMetrics(output, met)
Dan Willemsen1e704462016-08-21 15:17:17 -0700150 defer log.Cleanup()
151
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800152 // Create a context to simplify the program termination process.
Dan Willemsen1e704462016-08-21 15:17:17 -0700153 ctx, cancel := context.WithCancel(context.Background())
154 defer cancel()
155
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800156 // Create a new trace file writer, making it log events to the log instance.
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700157 trace := tracer.New(log)
Dan Willemsen1e704462016-08-21 15:17:17 -0700158
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800159 // Create a new Status instance, which manages action counts and event output channels.
Dan Willemsenb82471a2018-05-17 16:37:09 -0700160 stat := &status.Status{}
Jeongik Cha036b5a32023-03-22 17:31:48 +0900161
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800162 // Hook up the terminal output and tracer to Status.
Colin Crosse0df1a32019-06-09 19:40:08 -0700163 stat.AddOutput(output)
Dan Willemsenb82471a2018-05-17 16:37:09 -0700164 stat.AddOutput(trace.StatusTracer())
165
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800166 // Set up a cleanup procedure in case the normal termination process doesn't work.
Lukacs T. Berkif656b842021-08-11 11:10:28 +0200167 signal.SetupSignals(log, cancel, func() {
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700168 trace.Close()
169 log.Cleanup()
Dan Willemsenb82471a2018-05-17 16:37:09 -0700170 stat.Finish()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700171 })
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900172 criticalPath := status.NewCriticalPath()
Dan Willemsen59339a22018-07-22 21:18:45 -0700173 buildCtx := build.Context{ContextImpl: &build.ContextImpl{
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900174 Context: ctx,
175 Logger: log,
176 Metrics: met,
177 Tracer: trace,
178 Writer: output,
179 Status: stat,
180 CriticalPath: criticalPath,
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700181 }}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700182
LaMont Jones9a912862023-11-06 22:11:08 +0000183 freshConfig := func() build.Config {
184 config := c.config(buildCtx, args...)
185 config.SetLogsPrefix(c.logsPrefix)
186 return config
187 }
188 config := freshConfig()
MarkDacek6614d9c2022-12-07 21:57:38 +0000189 logsDir := config.LogsDir()
190 buildStarted = config.BuildStartedTimeOrDefault(buildStarted)
Kousik Kumar7b7dca42022-01-14 00:22:32 -0500191
MarkDacek6614d9c2022-12-07 21:57:38 +0000192 buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
193 soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
194 rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
Jason Wud1254402023-03-01 20:26:30 -0500195 soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
Yu Liuf2615e92024-05-16 23:15:49 +0000196 buildTraceFile := filepath.Join(logsDir, c.logsPrefix+"build.trace.gz")
MarkDacek00e31522023-01-06 22:15:24 +0000197
MarkDacek6614d9c2022-12-07 21:57:38 +0000198 metricsFiles := []string{
Colin Cross8d411ff2023-12-07 10:31:24 -0800199 buildErrorFile, // build error strings
200 rbeMetricsFile, // high level metrics related to remote build execution.
201 soongMetricsFile, // high level metrics related to this build system.
202 soongBuildMetricsFile, // high level metrics related to soong build
Yu Liuf2615e92024-05-16 23:15:49 +0000203 buildTraceFile,
MarkDacek6614d9c2022-12-07 21:57:38 +0000204 }
205
Yu Liuf2615e92024-05-16 23:15:49 +0000206 defer func() {
207 stat.Finish()
208 criticalPath.WriteToMetrics(met)
209 met.Dump(soongMetricsFile)
210 if !config.SkipMetricsUpload() {
211 build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...)
212 }
213 }()
214
215 // This has to come after the metrics uploading function, so that
216 // build.trace.gz is closed and ready for upload.
217 defer trace.Close()
218
MarkDacek6614d9c2022-12-07 21:57:38 +0000219 os.MkdirAll(logsDir, 0777)
220
221 log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
222
223 trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
224
Joe Onorato010c6b62023-07-14 16:32:53 -0700225 log.Verbose("Command Line: ")
226 for i, arg := range os.Args {
227 log.Verbosef(" [%d] %s", i, arg)
228 }
229
LaMont Jones9a912862023-11-06 22:11:08 +0000230 // We need to call preProductConfigSetup before we can do product config, which is how we get
231 // PRODUCT_CONFIG_RELEASE_MAPS set for the final product config for the build.
232 // When product config uses a declarative language, we won't need to rerun product config.
233 preProductConfigSetup(buildCtx, config)
234 if build.SetProductReleaseConfigMaps(buildCtx, config) {
235 log.Verbose("Product release config maps found\n")
236 config = freshConfig()
237 }
238
Jason Wu51d0ad72023-02-08 18:00:33 -0500239 c.run(buildCtx, config, args)
MarkDacek6614d9c2022-12-07 21:57:38 +0000240}
241
LaMont Jones9a912862023-11-06 22:11:08 +0000242// This function must not modify config, since product config may cause us to recreate the config,
243// and we won't call this function a second time.
244func preProductConfigSetup(buildCtx build.Context, config build.Config) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000245 log := buildCtx.ContextImpl.Logger
246 logsPrefix := config.GetLogsPrefix()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700247 build.SetupOutDir(buildCtx, config)
Patrice Arruda83842d72020-12-08 19:42:08 +0000248 logsDir := config.LogsDir()
Dan Willemsen1e704462016-08-21 15:17:17 -0700249
Patrice Arruda40564022020-12-10 00:42:58 +0000250 // Common list of metric file definition.
MarkDacek6614d9c2022-12-07 21:57:38 +0000251 buildErrorFile := filepath.Join(logsDir, logsPrefix+"build_error")
252 rbeMetricsFile := filepath.Join(logsDir, logsPrefix+"rbe_metrics.pb")
253 soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
254 bp2buildMetricsFile := filepath.Join(logsDir, logsPrefix+"bp2build_metrics.pb")
255 soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
Patrice Arruda40564022020-12-10 00:42:58 +0000256
Jason Wucc166a72022-12-19 11:53:12 -0500257 //Delete the stale metrics files
MarkDacek39825ea2023-10-26 19:59:27 +0000258 staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
Jason Wucc166a72022-12-19 11:53:12 -0500259 if err := deleteStaleMetrics(staleFileSlice); err != nil {
260 log.Fatalln(err)
261 }
262
Kousik Kumara0a44a82020-10-08 02:33:29 -0400263 build.PrintOutDirWarning(buildCtx, config)
Patrice Arruda219eef32020-06-01 17:29:30 +0000264
MarkDacek6614d9c2022-12-07 21:57:38 +0000265 stat := buildCtx.Status
266 stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, logsPrefix+"verbose.log")))
267 stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, logsPrefix+"error.log")))
Patrice Arruda219eef32020-06-01 17:29:30 +0000268 stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900269 stat.AddOutput(status.NewCriticalPathLogger(log, buildCtx.CriticalPath))
MarkDacek6614d9c2022-12-07 21:57:38 +0000270 stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, logsPrefix+"build_progress.pb")))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700271
Colin Cross8b8bec32019-11-15 13:18:43 -0800272 buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
273 buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
274 config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
275
Liz Kammer4ae119c2022-02-09 10:54:05 -0500276 setMaxFiles(buildCtx)
Liz Kammera7541782022-02-07 13:38:52 -0500277
MarkDacek6614d9c2022-12-07 21:57:38 +0000278 defer build.CheckProdCreds(buildCtx, config)
Nan Zhangd50f53b2019-01-07 20:26:51 -0800279
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800280 // Read the time at the starting point.
Dan Willemsen1e704462016-08-21 15:17:17 -0700281 if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800282 // soong_ui.bash uses the date command's %N (nanosec) flag when getting the start time,
283 // which Darwin doesn't support. Check if it was executed properly before parsing the value.
Dan Willemsen1e704462016-08-21 15:17:17 -0700284 if !strings.HasSuffix(start, "N") {
285 if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
286 log.Verbosef("Took %dms to start up.",
287 time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
Nan Zhang17f27672018-12-12 16:01:49 -0800288 buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
Dan Willemsen1e704462016-08-21 15:17:17 -0700289 }
290 }
Dan Willemsencae59bc2017-07-13 14:27:31 -0700291
292 if executable, err := os.Executable(); err == nil {
MarkDacek6614d9c2022-12-07 21:57:38 +0000293 buildCtx.ContextImpl.Tracer.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
Dan Willemsencae59bc2017-07-13 14:27:31 -0700294 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700295 }
296
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800297 // Create a source finder.
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700298 f := build.NewSourceFinder(buildCtx, config)
299 defer f.Shutdown()
300 build.FindSources(buildCtx, config, f)
Dan Willemsen051133b2017-07-14 11:29:29 -0700301}
302
MarkDacek6614d9c2022-12-07 21:57:38 +0000303func dumpVar(ctx build.Context, config build.Config, args []string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700304 flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400305 flags.SetOutput(ctx.Writer)
306
Dan Willemsen051133b2017-07-14 11:29:29 -0700307 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700308 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
309 fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
310 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700311
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700312 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that prints the human-readable config banner")
313 fmt.Fprintln(ctx.Writer, "from the beginning of the build.")
314 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700315 flags.PrintDefaults()
316 }
317 abs := flags.Bool("abs", false, "Print the absolute path of the value")
318 flags.Parse(args)
319
320 if flags.NArg() != 1 {
321 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400322 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700323 }
324
325 varName := flags.Arg(0)
326 if varName == "report_config" {
327 varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
328 if err != nil {
329 ctx.Fatal(err)
330 }
331
332 fmt.Println(build.Banner(varData))
333 } else {
334 varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
335 if err != nil {
336 ctx.Fatal(err)
337 }
338
339 if *abs {
340 var res []string
341 for _, path := range strings.Fields(varData[varName]) {
342 if abs, err := filepath.Abs(path); err == nil {
343 res = append(res, abs)
344 } else {
345 ctx.Fatalln("Failed to get absolute path of", path, err)
346 }
347 }
348 fmt.Println(strings.Join(res, " "))
349 } else {
350 fmt.Println(varData[varName])
351 }
352 }
353}
354
MarkDacek6614d9c2022-12-07 21:57:38 +0000355func dumpVars(ctx build.Context, config build.Config, args []string) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000356
Dan Willemsen051133b2017-07-14 11:29:29 -0700357 flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400358 flags.SetOutput(ctx.Writer)
359
Dan Willemsen051133b2017-07-14 11:29:29 -0700360 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700361 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
362 fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
363 fmt.Fprintln(ctx.Writer, "shell syntax. The resulting output may be sourced directly into a shell to")
364 fmt.Fprintln(ctx.Writer, "set corresponding shell variables.")
365 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700366
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700367 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that dumps a variable containing the")
368 fmt.Fprintln(ctx.Writer, "human-readable config banner from the beginning of the build.")
369 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700370 flags.PrintDefaults()
371 }
372
373 varsStr := flags.String("vars", "", "Space-separated list of variables to dump")
374 absVarsStr := flags.String("abs-vars", "", "Space-separated list of variables to dump (using absolute paths)")
375
376 varPrefix := flags.String("var-prefix", "", "String to prepend to all variable names when dumping")
377 absVarPrefix := flags.String("abs-var-prefix", "", "String to prepent to all absolute path variable names when dumping")
378
379 flags.Parse(args)
380
381 if flags.NArg() != 0 {
382 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400383 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700384 }
385
386 vars := strings.Fields(*varsStr)
387 absVars := strings.Fields(*absVarsStr)
388
389 allVars := append([]string{}, vars...)
390 allVars = append(allVars, absVars...)
391
392 if i := indexList("report_config", allVars); i != -1 {
393 allVars = append(allVars[:i], allVars[i+1:]...)
394 allVars = append(allVars, build.BannerVars...)
395 }
396
397 if len(allVars) == 0 {
398 return
399 }
400
401 varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
402 if err != nil {
403 ctx.Fatal(err)
404 }
405
406 for _, name := range vars {
407 if name == "report_config" {
408 fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
409 } else {
410 fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
411 }
412 }
413 for _, name := range absVars {
414 var res []string
415 for _, path := range strings.Fields(varData[name]) {
416 abs, err := filepath.Abs(path)
417 if err != nil {
418 ctx.Fatalln("Failed to get absolute path of", path, err)
419 }
420 res = append(res, abs)
421 }
422 fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
423 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700424}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700425
Patrice Arrudab7b22822019-05-21 17:46:23 -0700426func stdio() terminal.StdioInterface {
427 return terminal.StdioImpl{}
428}
429
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800430// dumpvar and dumpvars use stdout to output variable values, so use stderr instead of stdout when
431// reporting events to keep stdout clean from noise.
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700432func customStdio() terminal.StdioInterface {
433 return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
434}
435
436// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
437func dumpVarConfig(ctx build.Context, args ...string) build.Config {
438 return build.NewConfig(ctx)
439}
440
Patrice Arrudab7b22822019-05-21 17:46:23 -0700441func buildActionConfig(ctx build.Context, args ...string) build.Config {
442 flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400443 flags.SetOutput(ctx.Writer)
444
Patrice Arrudab7b22822019-05-21 17:46:23 -0700445 flags.Usage = func() {
446 fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
447 fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
448 fmt.Fprintln(ctx.Writer, "action. The --dir flag is required to determine what is needed to")
449 fmt.Fprintln(ctx.Writer, "build in the source tree based on the build action. See below for")
450 fmt.Fprintln(ctx.Writer, "the list of acceptable build action flags.")
451 fmt.Fprintln(ctx.Writer, "")
452 flags.PrintDefaults()
453 }
454
455 buildActionFlags := []struct {
Dan Willemsence41e942019-07-29 23:39:30 -0700456 name string
457 description string
458 action build.BuildAction
459 set bool
Patrice Arrudab7b22822019-05-21 17:46:23 -0700460 }{{
Dan Willemsence41e942019-07-29 23:39:30 -0700461 name: "all-modules",
462 description: "Build action: build from the top of the source tree.",
463 action: build.BUILD_MODULES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700464 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700465 // This is redirecting to mma build command behaviour. Once it has soaked for a
466 // while, the build command is deleted from here once it has been removed from the
467 // envsetup.sh.
468 name: "modules-in-a-dir-no-deps",
469 description: "Build action: builds all of the modules in the current directory without their dependencies.",
470 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700471 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700472 // This is redirecting to mmma build command behaviour. Once it has soaked for a
473 // while, the build command is deleted from here once it has been removed from the
474 // envsetup.sh.
475 name: "modules-in-dirs-no-deps",
476 description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
477 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700478 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700479 name: "modules-in-a-dir",
480 description: "Build action: builds all of the modules in the current directory and their dependencies.",
481 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700482 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700483 name: "modules-in-dirs",
484 description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
485 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700486 }}
487 for i, flag := range buildActionFlags {
488 flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
489 }
490 dir := flags.String("dir", "", "Directory of the executed build command.")
491
492 // Only interested in the first two args which defines the build action and the directory.
493 // The remaining arguments are passed down to the config.
494 const numBuildActionFlags = 2
495 if len(args) < numBuildActionFlags {
496 flags.Usage()
Usta Shrestha675564d2022-08-09 18:03:23 -0400497 ctx.Fatalln("Improper build action arguments: too few arguments")
Patrice Arrudab7b22822019-05-21 17:46:23 -0700498 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400499 parseError := flags.Parse(args[0:numBuildActionFlags])
Patrice Arrudab7b22822019-05-21 17:46:23 -0700500
501 // The next block of code is to validate that exactly one build action is set and the dir flag
502 // is specified.
Usta Shrestha675564d2022-08-09 18:03:23 -0400503 buildActionFound := false
Patrice Arrudab7b22822019-05-21 17:46:23 -0700504 var buildAction build.BuildAction
Usta Shrestha675564d2022-08-09 18:03:23 -0400505 for _, f := range buildActionFlags {
506 if f.set {
507 if buildActionFound {
508 if parseError == nil {
509 //otherwise Parse() already called Usage()
510 flags.Usage()
511 }
512 ctx.Fatalf("Build action already specified, omit: --%s\n", f.name)
513 }
514 buildActionFound = true
515 buildAction = f.action
Patrice Arrudab7b22822019-05-21 17:46:23 -0700516 }
517 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400518 if !buildActionFound {
519 if parseError == nil {
520 //otherwise Parse() already called Usage()
521 flags.Usage()
522 }
Patrice Arrudab7b22822019-05-21 17:46:23 -0700523 ctx.Fatalln("Build action not defined.")
524 }
525 if *dir == "" {
526 ctx.Fatalln("-dir not specified.")
527 }
528
529 // Remove the build action flags from the args as they are not recognized by the config.
530 args = args[numBuildActionFlags:]
Dan Willemsence41e942019-07-29 23:39:30 -0700531 return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
Patrice Arrudab7b22822019-05-21 17:46:23 -0700532}
533
MarkDacek6614d9c2022-12-07 21:57:38 +0000534func runMake(ctx build.Context, config build.Config, _ []string) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000535 logsDir := config.LogsDir()
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700536 if config.IsVerbose() {
537 writer := ctx.Writer
Colin Cross097ed2a2019-06-08 21:48:58 -0700538 fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
539 fmt.Fprintln(writer, "! Instead, the verbose log is always written to a compressed file in the output dir:")
540 fmt.Fprintln(writer, "!")
541 fmt.Fprintf(writer, "! gzip -cd %s/verbose.log.gz | less -R\n", logsDir)
542 fmt.Fprintln(writer, "!")
543 fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
544 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400545 ctx.Fatal("Invalid argument")
Dan Willemsenc6360832019-07-25 14:07:36 -0700546 }
547
548 if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
549 writer := ctx.Writer
Dan Willemsence41e942019-07-29 23:39:30 -0700550 fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
Dan Willemsenc6360832019-07-25 14:07:36 -0700551 fmt.Fprintln(writer, "!")
552 fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
553 fmt.Fprintln(writer, "!")
554 fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
555 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400556 ctx.Fatal("Invalid environment")
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700557 }
558
Anton Hansson5a7861a2021-06-04 10:09:01 +0100559 build.Build(ctx, config)
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700560}
561
562// getCommand finds the appropriate command based on args[1] flag. args[0]
563// is the soong_ui filename.
Liz Kammer0e7993e2020-10-15 11:07:13 -0700564func getCommand(args []string) (*command, []string, error) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400565 listFlags := func() []string {
566 flags := make([]string, len(commands))
567 for i, c := range commands {
568 flags[i] = c.flag
569 }
570 return flags
571 }
572
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700573 if len(args) < 2 {
Usta Shrestha675564d2022-08-09 18:03:23 -0400574 return nil, nil, fmt.Errorf("Too few arguments: %q\nUse one of these: %q", args, listFlags())
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700575 }
576
577 for _, c := range commands {
578 if c.flag == args[1] {
Liz Kammer0e7993e2020-10-15 11:07:13 -0700579 return &c, args[2:], nil
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700580 }
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700581 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400582 return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args[1], listFlags())
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700583}
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000584
Liz Kammer4ae119c2022-02-09 10:54:05 -0500585func setMaxFiles(ctx build.Context) {
586 var limits syscall.Rlimit
587
588 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
589 if err != nil {
590 ctx.Println("Failed to get file limit:", err)
591 return
592 }
593
594 ctx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
Colin Cross611a2fb2023-11-08 22:09:57 -0800595
596 // Go 1.21 modifies the file limit but restores the original when
597 // execing subprocesses if it hasn't be overridden. Call Setrlimit
598 // here even if it doesn't appear to be necessary so that the
599 // syscall package considers it set.
Liz Kammer4ae119c2022-02-09 10:54:05 -0500600
601 limits.Cur = limits.Max
602 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
603 if err != nil {
604 ctx.Println("Failed to increase file limit:", err)
605 }
606}