blob: fe3f8f72566f006fc56f43ffa933f34d801e5459 [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)
158 defer trace.Close()
Dan Willemsen1e704462016-08-21 15:17:17 -0700159
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800160 // Create a new Status instance, which manages action counts and event output channels.
Dan Willemsenb82471a2018-05-17 16:37:09 -0700161 stat := &status.Status{}
Jeongik Cha036b5a32023-03-22 17:31:48 +0900162
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800163 // Hook up the terminal output and tracer to Status.
Colin Crosse0df1a32019-06-09 19:40:08 -0700164 stat.AddOutput(output)
Dan Willemsenb82471a2018-05-17 16:37:09 -0700165 stat.AddOutput(trace.StatusTracer())
166
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800167 // Set up a cleanup procedure in case the normal termination process doesn't work.
Lukacs T. Berkif656b842021-08-11 11:10:28 +0200168 signal.SetupSignals(log, cancel, func() {
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700169 trace.Close()
170 log.Cleanup()
Dan Willemsenb82471a2018-05-17 16:37:09 -0700171 stat.Finish()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700172 })
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900173 criticalPath := status.NewCriticalPath()
Dan Willemsen59339a22018-07-22 21:18:45 -0700174 buildCtx := build.Context{ContextImpl: &build.ContextImpl{
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900175 Context: ctx,
176 Logger: log,
177 Metrics: met,
178 Tracer: trace,
179 Writer: output,
180 Status: stat,
181 CriticalPath: criticalPath,
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700182 }}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700183
LaMont Jones9a912862023-11-06 22:11:08 +0000184 freshConfig := func() build.Config {
185 config := c.config(buildCtx, args...)
186 config.SetLogsPrefix(c.logsPrefix)
187 return config
188 }
189 config := freshConfig()
MarkDacek6614d9c2022-12-07 21:57:38 +0000190 logsDir := config.LogsDir()
191 buildStarted = config.BuildStartedTimeOrDefault(buildStarted)
Kousik Kumar7b7dca42022-01-14 00:22:32 -0500192
MarkDacek6614d9c2022-12-07 21:57:38 +0000193 buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
194 soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
195 rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
Jason Wud1254402023-03-01 20:26:30 -0500196 soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
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
MarkDacek6614d9c2022-12-07 21:57:38 +0000203 }
204
205 os.MkdirAll(logsDir, 0777)
206
207 log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
208
209 trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
210
Joe Onorato010c6b62023-07-14 16:32:53 -0700211 log.Verbose("Command Line: ")
212 for i, arg := range os.Args {
213 log.Verbosef(" [%d] %s", i, arg)
214 }
215
LaMont Jones9a912862023-11-06 22:11:08 +0000216 // We need to call preProductConfigSetup before we can do product config, which is how we get
217 // PRODUCT_CONFIG_RELEASE_MAPS set for the final product config for the build.
218 // When product config uses a declarative language, we won't need to rerun product config.
219 preProductConfigSetup(buildCtx, config)
220 if build.SetProductReleaseConfigMaps(buildCtx, config) {
221 log.Verbose("Product release config maps found\n")
222 config = freshConfig()
223 }
224
Jeongik Cha036b5a32023-03-22 17:31:48 +0900225 defer func() {
226 stat.Finish()
227 criticalPath.WriteToMetrics(met)
228 met.Dump(soongMetricsFile)
229 if !config.SkipMetricsUpload() {
MarkDacek733b77c2023-05-09 18:21:36 +0000230 build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...)
Jeongik Cha036b5a32023-03-22 17:31:48 +0900231 }
232 }()
Jason Wu51d0ad72023-02-08 18:00:33 -0500233 c.run(buildCtx, config, args)
234
MarkDacek6614d9c2022-12-07 21:57:38 +0000235}
236
LaMont Jones9a912862023-11-06 22:11:08 +0000237// This function must not modify config, since product config may cause us to recreate the config,
238// and we won't call this function a second time.
239func preProductConfigSetup(buildCtx build.Context, config build.Config) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000240 log := buildCtx.ContextImpl.Logger
241 logsPrefix := config.GetLogsPrefix()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700242 build.SetupOutDir(buildCtx, config)
Patrice Arruda83842d72020-12-08 19:42:08 +0000243 logsDir := config.LogsDir()
Dan Willemsen1e704462016-08-21 15:17:17 -0700244
Patrice Arruda40564022020-12-10 00:42:58 +0000245 // Common list of metric file definition.
MarkDacek6614d9c2022-12-07 21:57:38 +0000246 buildErrorFile := filepath.Join(logsDir, logsPrefix+"build_error")
247 rbeMetricsFile := filepath.Join(logsDir, logsPrefix+"rbe_metrics.pb")
248 soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
249 bp2buildMetricsFile := filepath.Join(logsDir, logsPrefix+"bp2build_metrics.pb")
250 soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
Patrice Arruda40564022020-12-10 00:42:58 +0000251
Jason Wucc166a72022-12-19 11:53:12 -0500252 //Delete the stale metrics files
MarkDacek39825ea2023-10-26 19:59:27 +0000253 staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
Jason Wucc166a72022-12-19 11:53:12 -0500254 if err := deleteStaleMetrics(staleFileSlice); err != nil {
255 log.Fatalln(err)
256 }
257
Kousik Kumara0a44a82020-10-08 02:33:29 -0400258 build.PrintOutDirWarning(buildCtx, config)
Patrice Arruda219eef32020-06-01 17:29:30 +0000259
MarkDacek6614d9c2022-12-07 21:57:38 +0000260 stat := buildCtx.Status
261 stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, logsPrefix+"verbose.log")))
262 stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, logsPrefix+"error.log")))
Patrice Arruda219eef32020-06-01 17:29:30 +0000263 stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900264 stat.AddOutput(status.NewCriticalPathLogger(log, buildCtx.CriticalPath))
MarkDacek6614d9c2022-12-07 21:57:38 +0000265 stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, logsPrefix+"build_progress.pb")))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700266
Colin Cross8b8bec32019-11-15 13:18:43 -0800267 buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
268 buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
269 config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
270
Liz Kammer4ae119c2022-02-09 10:54:05 -0500271 setMaxFiles(buildCtx)
Liz Kammera7541782022-02-07 13:38:52 -0500272
MarkDacek6614d9c2022-12-07 21:57:38 +0000273 defer build.CheckProdCreds(buildCtx, config)
Nan Zhangd50f53b2019-01-07 20:26:51 -0800274
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800275 // Read the time at the starting point.
Dan Willemsen1e704462016-08-21 15:17:17 -0700276 if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800277 // soong_ui.bash uses the date command's %N (nanosec) flag when getting the start time,
278 // which Darwin doesn't support. Check if it was executed properly before parsing the value.
Dan Willemsen1e704462016-08-21 15:17:17 -0700279 if !strings.HasSuffix(start, "N") {
280 if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
281 log.Verbosef("Took %dms to start up.",
282 time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
Nan Zhang17f27672018-12-12 16:01:49 -0800283 buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
Dan Willemsen1e704462016-08-21 15:17:17 -0700284 }
285 }
Dan Willemsencae59bc2017-07-13 14:27:31 -0700286
287 if executable, err := os.Executable(); err == nil {
MarkDacek6614d9c2022-12-07 21:57:38 +0000288 buildCtx.ContextImpl.Tracer.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
Dan Willemsencae59bc2017-07-13 14:27:31 -0700289 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700290 }
291
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800292 // Create a source finder.
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700293 f := build.NewSourceFinder(buildCtx, config)
294 defer f.Shutdown()
295 build.FindSources(buildCtx, config, f)
Dan Willemsen051133b2017-07-14 11:29:29 -0700296}
297
MarkDacek6614d9c2022-12-07 21:57:38 +0000298func dumpVar(ctx build.Context, config build.Config, args []string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700299 flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400300 flags.SetOutput(ctx.Writer)
301
Dan Willemsen051133b2017-07-14 11:29:29 -0700302 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700303 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
304 fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
305 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700306
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700307 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that prints the human-readable config banner")
308 fmt.Fprintln(ctx.Writer, "from the beginning of the build.")
309 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700310 flags.PrintDefaults()
311 }
312 abs := flags.Bool("abs", false, "Print the absolute path of the value")
313 flags.Parse(args)
314
315 if flags.NArg() != 1 {
316 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400317 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700318 }
319
320 varName := flags.Arg(0)
321 if varName == "report_config" {
322 varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
323 if err != nil {
324 ctx.Fatal(err)
325 }
326
327 fmt.Println(build.Banner(varData))
328 } else {
329 varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
330 if err != nil {
331 ctx.Fatal(err)
332 }
333
334 if *abs {
335 var res []string
336 for _, path := range strings.Fields(varData[varName]) {
337 if abs, err := filepath.Abs(path); err == nil {
338 res = append(res, abs)
339 } else {
340 ctx.Fatalln("Failed to get absolute path of", path, err)
341 }
342 }
343 fmt.Println(strings.Join(res, " "))
344 } else {
345 fmt.Println(varData[varName])
346 }
347 }
348}
349
MarkDacek6614d9c2022-12-07 21:57:38 +0000350func dumpVars(ctx build.Context, config build.Config, args []string) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000351
Dan Willemsen051133b2017-07-14 11:29:29 -0700352 flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400353 flags.SetOutput(ctx.Writer)
354
Dan Willemsen051133b2017-07-14 11:29:29 -0700355 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700356 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
357 fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
358 fmt.Fprintln(ctx.Writer, "shell syntax. The resulting output may be sourced directly into a shell to")
359 fmt.Fprintln(ctx.Writer, "set corresponding shell variables.")
360 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700361
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700362 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that dumps a variable containing the")
363 fmt.Fprintln(ctx.Writer, "human-readable config banner from the beginning of the build.")
364 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700365 flags.PrintDefaults()
366 }
367
368 varsStr := flags.String("vars", "", "Space-separated list of variables to dump")
369 absVarsStr := flags.String("abs-vars", "", "Space-separated list of variables to dump (using absolute paths)")
370
371 varPrefix := flags.String("var-prefix", "", "String to prepend to all variable names when dumping")
372 absVarPrefix := flags.String("abs-var-prefix", "", "String to prepent to all absolute path variable names when dumping")
373
374 flags.Parse(args)
375
376 if flags.NArg() != 0 {
377 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400378 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700379 }
380
381 vars := strings.Fields(*varsStr)
382 absVars := strings.Fields(*absVarsStr)
383
384 allVars := append([]string{}, vars...)
385 allVars = append(allVars, absVars...)
386
387 if i := indexList("report_config", allVars); i != -1 {
388 allVars = append(allVars[:i], allVars[i+1:]...)
389 allVars = append(allVars, build.BannerVars...)
390 }
391
392 if len(allVars) == 0 {
393 return
394 }
395
396 varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
397 if err != nil {
398 ctx.Fatal(err)
399 }
400
401 for _, name := range vars {
402 if name == "report_config" {
403 fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
404 } else {
405 fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
406 }
407 }
408 for _, name := range absVars {
409 var res []string
410 for _, path := range strings.Fields(varData[name]) {
411 abs, err := filepath.Abs(path)
412 if err != nil {
413 ctx.Fatalln("Failed to get absolute path of", path, err)
414 }
415 res = append(res, abs)
416 }
417 fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
418 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700419}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700420
Patrice Arrudab7b22822019-05-21 17:46:23 -0700421func stdio() terminal.StdioInterface {
422 return terminal.StdioImpl{}
423}
424
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800425// dumpvar and dumpvars use stdout to output variable values, so use stderr instead of stdout when
426// reporting events to keep stdout clean from noise.
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700427func customStdio() terminal.StdioInterface {
428 return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
429}
430
431// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
432func dumpVarConfig(ctx build.Context, args ...string) build.Config {
433 return build.NewConfig(ctx)
434}
435
Patrice Arrudab7b22822019-05-21 17:46:23 -0700436func buildActionConfig(ctx build.Context, args ...string) build.Config {
437 flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400438 flags.SetOutput(ctx.Writer)
439
Patrice Arrudab7b22822019-05-21 17:46:23 -0700440 flags.Usage = func() {
441 fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
442 fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
443 fmt.Fprintln(ctx.Writer, "action. The --dir flag is required to determine what is needed to")
444 fmt.Fprintln(ctx.Writer, "build in the source tree based on the build action. See below for")
445 fmt.Fprintln(ctx.Writer, "the list of acceptable build action flags.")
446 fmt.Fprintln(ctx.Writer, "")
447 flags.PrintDefaults()
448 }
449
450 buildActionFlags := []struct {
Dan Willemsence41e942019-07-29 23:39:30 -0700451 name string
452 description string
453 action build.BuildAction
454 set bool
Patrice Arrudab7b22822019-05-21 17:46:23 -0700455 }{{
Dan Willemsence41e942019-07-29 23:39:30 -0700456 name: "all-modules",
457 description: "Build action: build from the top of the source tree.",
458 action: build.BUILD_MODULES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700459 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700460 // This is redirecting to mma build command behaviour. Once it has soaked for a
461 // while, the build command is deleted from here once it has been removed from the
462 // envsetup.sh.
463 name: "modules-in-a-dir-no-deps",
464 description: "Build action: builds all of the modules in the current directory without their dependencies.",
465 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700466 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700467 // This is redirecting to mmma build command behaviour. Once it has soaked for a
468 // while, the build command is deleted from here once it has been removed from the
469 // envsetup.sh.
470 name: "modules-in-dirs-no-deps",
471 description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
472 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700473 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700474 name: "modules-in-a-dir",
475 description: "Build action: builds all of the modules in the current directory and their dependencies.",
476 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700477 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700478 name: "modules-in-dirs",
479 description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
480 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700481 }}
482 for i, flag := range buildActionFlags {
483 flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
484 }
485 dir := flags.String("dir", "", "Directory of the executed build command.")
486
487 // Only interested in the first two args which defines the build action and the directory.
488 // The remaining arguments are passed down to the config.
489 const numBuildActionFlags = 2
490 if len(args) < numBuildActionFlags {
491 flags.Usage()
Usta Shrestha675564d2022-08-09 18:03:23 -0400492 ctx.Fatalln("Improper build action arguments: too few arguments")
Patrice Arrudab7b22822019-05-21 17:46:23 -0700493 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400494 parseError := flags.Parse(args[0:numBuildActionFlags])
Patrice Arrudab7b22822019-05-21 17:46:23 -0700495
496 // The next block of code is to validate that exactly one build action is set and the dir flag
497 // is specified.
Usta Shrestha675564d2022-08-09 18:03:23 -0400498 buildActionFound := false
Patrice Arrudab7b22822019-05-21 17:46:23 -0700499 var buildAction build.BuildAction
Usta Shrestha675564d2022-08-09 18:03:23 -0400500 for _, f := range buildActionFlags {
501 if f.set {
502 if buildActionFound {
503 if parseError == nil {
504 //otherwise Parse() already called Usage()
505 flags.Usage()
506 }
507 ctx.Fatalf("Build action already specified, omit: --%s\n", f.name)
508 }
509 buildActionFound = true
510 buildAction = f.action
Patrice Arrudab7b22822019-05-21 17:46:23 -0700511 }
512 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400513 if !buildActionFound {
514 if parseError == nil {
515 //otherwise Parse() already called Usage()
516 flags.Usage()
517 }
Patrice Arrudab7b22822019-05-21 17:46:23 -0700518 ctx.Fatalln("Build action not defined.")
519 }
520 if *dir == "" {
521 ctx.Fatalln("-dir not specified.")
522 }
523
524 // Remove the build action flags from the args as they are not recognized by the config.
525 args = args[numBuildActionFlags:]
Dan Willemsence41e942019-07-29 23:39:30 -0700526 return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
Patrice Arrudab7b22822019-05-21 17:46:23 -0700527}
528
MarkDacek6614d9c2022-12-07 21:57:38 +0000529func runMake(ctx build.Context, config build.Config, _ []string) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000530 logsDir := config.LogsDir()
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700531 if config.IsVerbose() {
532 writer := ctx.Writer
Colin Cross097ed2a2019-06-08 21:48:58 -0700533 fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
534 fmt.Fprintln(writer, "! Instead, the verbose log is always written to a compressed file in the output dir:")
535 fmt.Fprintln(writer, "!")
536 fmt.Fprintf(writer, "! gzip -cd %s/verbose.log.gz | less -R\n", logsDir)
537 fmt.Fprintln(writer, "!")
538 fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
539 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400540 ctx.Fatal("Invalid argument")
Dan Willemsenc6360832019-07-25 14:07:36 -0700541 }
542
543 if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
544 writer := ctx.Writer
Dan Willemsence41e942019-07-29 23:39:30 -0700545 fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
Dan Willemsenc6360832019-07-25 14:07:36 -0700546 fmt.Fprintln(writer, "!")
547 fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
548 fmt.Fprintln(writer, "!")
549 fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
550 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400551 ctx.Fatal("Invalid environment")
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700552 }
553
Anton Hansson5a7861a2021-06-04 10:09:01 +0100554 build.Build(ctx, config)
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700555}
556
557// getCommand finds the appropriate command based on args[1] flag. args[0]
558// is the soong_ui filename.
Liz Kammer0e7993e2020-10-15 11:07:13 -0700559func getCommand(args []string) (*command, []string, error) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400560 listFlags := func() []string {
561 flags := make([]string, len(commands))
562 for i, c := range commands {
563 flags[i] = c.flag
564 }
565 return flags
566 }
567
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700568 if len(args) < 2 {
Usta Shrestha675564d2022-08-09 18:03:23 -0400569 return nil, nil, fmt.Errorf("Too few arguments: %q\nUse one of these: %q", args, listFlags())
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700570 }
571
572 for _, c := range commands {
573 if c.flag == args[1] {
Liz Kammer0e7993e2020-10-15 11:07:13 -0700574 return &c, args[2:], nil
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700575 }
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700576 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400577 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 -0700578}
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000579
Liz Kammer4ae119c2022-02-09 10:54:05 -0500580func setMaxFiles(ctx build.Context) {
581 var limits syscall.Rlimit
582
583 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
584 if err != nil {
585 ctx.Println("Failed to get file limit:", err)
586 return
587 }
588
589 ctx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
Colin Cross611a2fb2023-11-08 22:09:57 -0800590
591 // Go 1.21 modifies the file limit but restores the original when
592 // execing subprocesses if it hasn't be overridden. Call Setrlimit
593 // here even if it doesn't appear to be necessary so that the
594 // syscall package considers it set.
Liz Kammer4ae119c2022-02-09 10:54:05 -0500595
596 limits.Cur = limits.Max
597 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
598 if err != nil {
599 ctx.Println("Failed to increase file limit:", err)
600 }
601}