blob: 97217942263a6280551fac7132c2e9b9e5fd0def [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"
LaMont Jones8490ffb2024-11-14 16:42:54 -080030 "android/soong/ui/execution_metrics"
Dan Willemsen1e704462016-08-21 15:17:17 -070031 "android/soong/ui/logger"
Nan Zhang17f27672018-12-12 16:01:49 -080032 "android/soong/ui/metrics"
Lukacs T. Berkif656b842021-08-11 11:10:28 +020033 "android/soong/ui/signal"
Dan Willemsenb82471a2018-05-17 16:37:09 -070034 "android/soong/ui/status"
35 "android/soong/ui/terminal"
Dan Willemsend9f6fa22016-08-21 15:17:17 -070036 "android/soong/ui/tracer"
Dan Willemsen1e704462016-08-21 15:17:17 -070037)
38
Patrice Arrudaa5c25422019-04-09 18:49:49 -070039// A command represents an operation to be executed in the soong build
40// system.
41type command struct {
Patrice Arrudaf445ba12020-07-28 17:49:01 +000042 // The flag name (must have double dashes).
Patrice Arrudaa5c25422019-04-09 18:49:49 -070043 flag string
44
Patrice Arrudaf445ba12020-07-28 17:49:01 +000045 // Description for the flag (to display when running help).
Patrice Arrudaa5c25422019-04-09 18:49:49 -070046 description string
47
Patrice Arrudaf445ba12020-07-28 17:49:01 +000048 // Stream the build status output into the simple terminal mode.
49 simpleOutput bool
Colin Crossc0b9f6b2019-09-23 12:44:54 -070050
51 // Sets a prefix string to use for filenames of log files.
52 logsPrefix string
53
Patrice Arrudaa5c25422019-04-09 18:49:49 -070054 // Creates the build configuration based on the args and build context.
55 config func(ctx build.Context, args ...string) build.Config
56
57 // Returns what type of IO redirection this Command requires.
58 stdio func() terminal.StdioInterface
59
60 // run the command
MarkDacek6614d9c2022-12-07 21:57:38 +000061 run func(ctx build.Context, config build.Config, args []string)
Patrice Arrudaa5c25422019-04-09 18:49:49 -070062}
63
Patrice Arrudaa5c25422019-04-09 18:49:49 -070064// list of supported commands (flags) supported by soong ui
Usta6feae382021-12-13 12:31:50 -050065var commands = []command{
Patrice Arrudaa5c25422019-04-09 18:49:49 -070066 {
Anton Hansson5a7861a2021-06-04 10:09:01 +010067 flag: "--make-mode",
Patrice Arrudaa5c25422019-04-09 18:49:49 -070068 description: "build the modules by the target name (i.e. soong_docs)",
Usta Shrestha59417a12022-08-05 17:14:49 -040069 config: build.NewConfig,
70 stdio: stdio,
71 run: runMake,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070072 }, {
Patrice Arrudaf445ba12020-07-28 17:49:01 +000073 flag: "--dumpvar-mode",
74 description: "print the value of the legacy make variable VAR to stdout",
75 simpleOutput: true,
76 logsPrefix: "dumpvars-",
77 config: dumpVarConfig,
78 stdio: customStdio,
79 run: dumpVar,
Patrice Arrudaa5c25422019-04-09 18:49:49 -070080 }, {
Patrice Arrudaf445ba12020-07-28 17:49:01 +000081 flag: "--dumpvars-mode",
82 description: "dump the values of one or more legacy make variables, in shell syntax",
83 simpleOutput: 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,
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +010093 run: runMake,
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
Jason Wucc166a72022-12-19 11:53:12 -0500113func deleteStaleMetrics(metricsFilePathSlice []string) error {
114 for _, metricsFilePath := range metricsFilePathSlice {
115 if err := os.Remove(metricsFilePath); err != nil && !os.IsNotExist(err) {
116 return fmt.Errorf("Failed to remove %s\nError message: %w", metricsFilePath, err)
117 }
118 }
119 return nil
120}
121
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700122// Main execution of soong_ui. The command format is as follows:
123//
Usta Shrestha59417a12022-08-05 17:14:49 -0400124// soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700125//
126// Command is the type of soong_ui execution. Only one type of
127// execution is specified. The args are specific to the command.
Dan Willemsen1e704462016-08-21 15:17:17 -0700128func main() {
Lukacs T. Berki7d613bf2021-03-02 10:09:41 +0100129 shared.ReexecWithDelveMaybe(os.Getenv("SOONG_UI_DELVE"), shared.ResolveDelveBinary())
130
Patrice Arruda73c790f2020-07-13 23:01:18 +0000131 buildStarted := time.Now()
Patrice Arruda219eef32020-06-01 17:29:30 +0000132
Liz Kammer0e7993e2020-10-15 11:07:13 -0700133 c, args, err := getCommand(os.Args)
134 if err != nil {
135 fmt.Fprintf(os.Stderr, "Error parsing `soong` args: %s.\n", err)
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700136 os.Exit(1)
Dan Willemsenc35b3812018-07-16 19:59:10 -0700137 }
138
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800139 // Create a terminal output that mimics Ninja's.
Patrice Arrudaf445ba12020-07-28 17:49:01 +0000140 output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.simpleOutput,
Colin Cross3c0fe0e2021-02-10 13:11:18 -0800141 build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"),
142 build.OsEnvironment().IsEnvTrue("SOONG_UI_ANSI_OUTPUT"))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700143
Liz Kammerf2a80c62022-10-21 10:42:35 -0400144 // Create and start a new metric record.
145 met := metrics.New()
146 met.SetBuildDateTime(buildStarted)
147 met.SetBuildCommand(os.Args)
148
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800149 // Attach a new logger instance to the terminal output.
Liz Kammerf2a80c62022-10-21 10:42:35 -0400150 log := logger.NewWithMetrics(output, met)
Dan Willemsen1e704462016-08-21 15:17:17 -0700151 defer log.Cleanup()
152
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800153 // Create a context to simplify the program termination process.
Dan Willemsen1e704462016-08-21 15:17:17 -0700154 ctx, cancel := context.WithCancel(context.Background())
155 defer cancel()
156
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800157 // Create a new trace file writer, making it log events to the log instance.
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700158 trace := tracer.New(log)
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()
LaMont Jones8490ffb2024-11-14 16:42:54 -0800174 emet := execution_metrics.NewExecutionMetrics(log)
Dan Willemsen59339a22018-07-22 21:18:45 -0700175 buildCtx := build.Context{ContextImpl: &build.ContextImpl{
LaMont Jones8490ffb2024-11-14 16:42:54 -0800176 Context: ctx,
177 Logger: log,
178 Metrics: met,
179 ExecutionMetrics: emet,
180 Tracer: trace,
181 Writer: output,
182 Status: stat,
183 CriticalPath: criticalPath,
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700184 }}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700185
LaMont Jones9a912862023-11-06 22:11:08 +0000186 freshConfig := func() build.Config {
187 config := c.config(buildCtx, args...)
188 config.SetLogsPrefix(c.logsPrefix)
189 return config
190 }
191 config := freshConfig()
MarkDacek6614d9c2022-12-07 21:57:38 +0000192 logsDir := config.LogsDir()
193 buildStarted = config.BuildStartedTimeOrDefault(buildStarted)
Kousik Kumar7b7dca42022-01-14 00:22:32 -0500194
MarkDacek6614d9c2022-12-07 21:57:38 +0000195 buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
196 soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
197 rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
Jason Wud1254402023-03-01 20:26:30 -0500198 soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
Yu Liuf2615e92024-05-16 23:15:49 +0000199 buildTraceFile := filepath.Join(logsDir, c.logsPrefix+"build.trace.gz")
LaMont Jones8490ffb2024-11-14 16:42:54 -0800200 executionMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_execution_metrics.pb")
MarkDacek00e31522023-01-06 22:15:24 +0000201
MarkDacek6614d9c2022-12-07 21:57:38 +0000202 metricsFiles := []string{
Colin Cross8d411ff2023-12-07 10:31:24 -0800203 buildErrorFile, // build error strings
204 rbeMetricsFile, // high level metrics related to remote build execution.
205 soongMetricsFile, // high level metrics related to this build system.
206 soongBuildMetricsFile, // high level metrics related to soong build
Yu Liuf2615e92024-05-16 23:15:49 +0000207 buildTraceFile,
MarkDacek6614d9c2022-12-07 21:57:38 +0000208 }
209
Yu Liuf2615e92024-05-16 23:15:49 +0000210 defer func() {
LaMont Jones8490ffb2024-11-14 16:42:54 -0800211 emet.Finish(buildCtx)
Yu Liuf2615e92024-05-16 23:15:49 +0000212 stat.Finish()
213 criticalPath.WriteToMetrics(met)
214 met.Dump(soongMetricsFile)
LaMont Jones8490ffb2024-11-14 16:42:54 -0800215 emet.Dump(executionMetricsFile, args)
216 // If there are execution metrics, upload them.
217 if _, err := os.Stat(executionMetricsFile); err == nil {
218 // TODO: Upload the metrics file.
219 // metricsFiles = append(metricsFiles, executionMetricsFile)
220 }
Yu Liuf2615e92024-05-16 23:15:49 +0000221 if !config.SkipMetricsUpload() {
222 build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...)
223 }
224 }()
225
226 // This has to come after the metrics uploading function, so that
227 // build.trace.gz is closed and ready for upload.
228 defer trace.Close()
229
MarkDacek6614d9c2022-12-07 21:57:38 +0000230 os.MkdirAll(logsDir, 0777)
231
232 log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
233
234 trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
235
Joe Onorato010c6b62023-07-14 16:32:53 -0700236 log.Verbose("Command Line: ")
237 for i, arg := range os.Args {
238 log.Verbosef(" [%d] %s", i, arg)
239 }
240
LaMont Jones9a912862023-11-06 22:11:08 +0000241 // We need to call preProductConfigSetup before we can do product config, which is how we get
242 // PRODUCT_CONFIG_RELEASE_MAPS set for the final product config for the build.
243 // When product config uses a declarative language, we won't need to rerun product config.
244 preProductConfigSetup(buildCtx, config)
245 if build.SetProductReleaseConfigMaps(buildCtx, config) {
246 log.Verbose("Product release config maps found\n")
247 config = freshConfig()
248 }
249
Jason Wu51d0ad72023-02-08 18:00:33 -0500250 c.run(buildCtx, config, args)
MarkDacek6614d9c2022-12-07 21:57:38 +0000251}
252
LaMont Jones9a912862023-11-06 22:11:08 +0000253// This function must not modify config, since product config may cause us to recreate the config,
254// and we won't call this function a second time.
255func preProductConfigSetup(buildCtx build.Context, config build.Config) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000256 log := buildCtx.ContextImpl.Logger
257 logsPrefix := config.GetLogsPrefix()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700258 build.SetupOutDir(buildCtx, config)
Patrice Arruda83842d72020-12-08 19:42:08 +0000259 logsDir := config.LogsDir()
Dan Willemsen1e704462016-08-21 15:17:17 -0700260
Patrice Arruda40564022020-12-10 00:42:58 +0000261 // Common list of metric file definition.
MarkDacek6614d9c2022-12-07 21:57:38 +0000262 buildErrorFile := filepath.Join(logsDir, logsPrefix+"build_error")
263 rbeMetricsFile := filepath.Join(logsDir, logsPrefix+"rbe_metrics.pb")
264 soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
MarkDacek6614d9c2022-12-07 21:57:38 +0000265 soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
Patrice Arruda40564022020-12-10 00:42:58 +0000266
Jason Wucc166a72022-12-19 11:53:12 -0500267 //Delete the stale metrics files
Joe Onorato35f300d2024-10-21 15:02:44 -0700268 staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, soongBuildMetricsFile}
Jason Wucc166a72022-12-19 11:53:12 -0500269 if err := deleteStaleMetrics(staleFileSlice); err != nil {
270 log.Fatalln(err)
271 }
272
Kousik Kumara0a44a82020-10-08 02:33:29 -0400273 build.PrintOutDirWarning(buildCtx, config)
Patrice Arruda219eef32020-06-01 17:29:30 +0000274
MarkDacek6614d9c2022-12-07 21:57:38 +0000275 stat := buildCtx.Status
276 stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, logsPrefix+"verbose.log")))
277 stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, logsPrefix+"error.log")))
Patrice Arruda219eef32020-06-01 17:29:30 +0000278 stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
Jeongik Cha28c1fe52023-03-07 15:19:44 +0900279 stat.AddOutput(status.NewCriticalPathLogger(log, buildCtx.CriticalPath))
MarkDacek6614d9c2022-12-07 21:57:38 +0000280 stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, logsPrefix+"build_progress.pb")))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700281
Colin Cross8b8bec32019-11-15 13:18:43 -0800282 buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
283 buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
284 config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
285
Liz Kammer4ae119c2022-02-09 10:54:05 -0500286 setMaxFiles(buildCtx)
Liz Kammera7541782022-02-07 13:38:52 -0500287
MarkDacek6614d9c2022-12-07 21:57:38 +0000288 defer build.CheckProdCreds(buildCtx, config)
Nan Zhangd50f53b2019-01-07 20:26:51 -0800289
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800290 // Read the time at the starting point.
Dan Willemsen1e704462016-08-21 15:17:17 -0700291 if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800292 // soong_ui.bash uses the date command's %N (nanosec) flag when getting the start time,
293 // which Darwin doesn't support. Check if it was executed properly before parsing the value.
Dan Willemsen1e704462016-08-21 15:17:17 -0700294 if !strings.HasSuffix(start, "N") {
295 if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
296 log.Verbosef("Took %dms to start up.",
297 time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
Nan Zhang17f27672018-12-12 16:01:49 -0800298 buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
Dan Willemsen1e704462016-08-21 15:17:17 -0700299 }
300 }
Dan Willemsencae59bc2017-07-13 14:27:31 -0700301
302 if executable, err := os.Executable(); err == nil {
MarkDacek6614d9c2022-12-07 21:57:38 +0000303 buildCtx.ContextImpl.Tracer.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
Dan Willemsencae59bc2017-07-13 14:27:31 -0700304 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700305 }
306
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800307 // Create a source finder.
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700308 f := build.NewSourceFinder(buildCtx, config)
309 defer f.Shutdown()
310 build.FindSources(buildCtx, config, f)
Dan Willemsen051133b2017-07-14 11:29:29 -0700311}
312
MarkDacek6614d9c2022-12-07 21:57:38 +0000313func dumpVar(ctx build.Context, config build.Config, args []string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700314 flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400315 flags.SetOutput(ctx.Writer)
316
Dan Willemsen051133b2017-07-14 11:29:29 -0700317 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700318 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
319 fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
320 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700321
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700322 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that prints the human-readable config banner")
323 fmt.Fprintln(ctx.Writer, "from the beginning of the build.")
324 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700325 flags.PrintDefaults()
326 }
327 abs := flags.Bool("abs", false, "Print the absolute path of the value")
328 flags.Parse(args)
329
330 if flags.NArg() != 1 {
331 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400332 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700333 }
334
335 varName := flags.Arg(0)
336 if varName == "report_config" {
337 varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
338 if err != nil {
339 ctx.Fatal(err)
340 }
341
342 fmt.Println(build.Banner(varData))
343 } else {
344 varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
345 if err != nil {
346 ctx.Fatal(err)
347 }
348
349 if *abs {
350 var res []string
351 for _, path := range strings.Fields(varData[varName]) {
352 if abs, err := filepath.Abs(path); err == nil {
353 res = append(res, abs)
354 } else {
355 ctx.Fatalln("Failed to get absolute path of", path, err)
356 }
357 }
358 fmt.Println(strings.Join(res, " "))
359 } else {
360 fmt.Println(varData[varName])
361 }
362 }
363}
364
MarkDacek6614d9c2022-12-07 21:57:38 +0000365func dumpVars(ctx build.Context, config build.Config, args []string) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000366
Dan Willemsen051133b2017-07-14 11:29:29 -0700367 flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400368 flags.SetOutput(ctx.Writer)
369
Dan Willemsen051133b2017-07-14 11:29:29 -0700370 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700371 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
372 fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
373 fmt.Fprintln(ctx.Writer, "shell syntax. The resulting output may be sourced directly into a shell to")
374 fmt.Fprintln(ctx.Writer, "set corresponding shell variables.")
375 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700376
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700377 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that dumps a variable containing the")
378 fmt.Fprintln(ctx.Writer, "human-readable config banner from the beginning of the build.")
379 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700380 flags.PrintDefaults()
381 }
382
383 varsStr := flags.String("vars", "", "Space-separated list of variables to dump")
384 absVarsStr := flags.String("abs-vars", "", "Space-separated list of variables to dump (using absolute paths)")
385
386 varPrefix := flags.String("var-prefix", "", "String to prepend to all variable names when dumping")
387 absVarPrefix := flags.String("abs-var-prefix", "", "String to prepent to all absolute path variable names when dumping")
388
389 flags.Parse(args)
390
391 if flags.NArg() != 0 {
392 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400393 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700394 }
395
396 vars := strings.Fields(*varsStr)
397 absVars := strings.Fields(*absVarsStr)
398
399 allVars := append([]string{}, vars...)
400 allVars = append(allVars, absVars...)
401
402 if i := indexList("report_config", allVars); i != -1 {
403 allVars = append(allVars[:i], allVars[i+1:]...)
404 allVars = append(allVars, build.BannerVars...)
405 }
406
407 if len(allVars) == 0 {
408 return
409 }
410
411 varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
412 if err != nil {
413 ctx.Fatal(err)
414 }
415
416 for _, name := range vars {
417 if name == "report_config" {
418 fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
419 } else {
420 fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
421 }
422 }
423 for _, name := range absVars {
424 var res []string
425 for _, path := range strings.Fields(varData[name]) {
426 abs, err := filepath.Abs(path)
427 if err != nil {
428 ctx.Fatalln("Failed to get absolute path of", path, err)
429 }
430 res = append(res, abs)
431 }
432 fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
433 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700434}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700435
Patrice Arrudab7b22822019-05-21 17:46:23 -0700436func stdio() terminal.StdioInterface {
437 return terminal.StdioImpl{}
438}
439
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800440// dumpvar and dumpvars use stdout to output variable values, so use stderr instead of stdout when
441// reporting events to keep stdout clean from noise.
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700442func customStdio() terminal.StdioInterface {
443 return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
444}
445
446// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
447func dumpVarConfig(ctx build.Context, args ...string) build.Config {
448 return build.NewConfig(ctx)
449}
450
Patrice Arrudab7b22822019-05-21 17:46:23 -0700451func buildActionConfig(ctx build.Context, args ...string) build.Config {
452 flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400453 flags.SetOutput(ctx.Writer)
454
Patrice Arrudab7b22822019-05-21 17:46:23 -0700455 flags.Usage = func() {
456 fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
457 fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
458 fmt.Fprintln(ctx.Writer, "action. The --dir flag is required to determine what is needed to")
459 fmt.Fprintln(ctx.Writer, "build in the source tree based on the build action. See below for")
460 fmt.Fprintln(ctx.Writer, "the list of acceptable build action flags.")
461 fmt.Fprintln(ctx.Writer, "")
462 flags.PrintDefaults()
463 }
464
465 buildActionFlags := []struct {
Dan Willemsence41e942019-07-29 23:39:30 -0700466 name string
467 description string
468 action build.BuildAction
469 set bool
Patrice Arrudab7b22822019-05-21 17:46:23 -0700470 }{{
Dan Willemsence41e942019-07-29 23:39:30 -0700471 name: "all-modules",
472 description: "Build action: build from the top of the source tree.",
473 action: build.BUILD_MODULES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700474 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700475 // This is redirecting to mma build command behaviour. Once it has soaked for a
476 // while, the build command is deleted from here once it has been removed from the
477 // envsetup.sh.
478 name: "modules-in-a-dir-no-deps",
479 description: "Build action: builds all of the modules in the current directory without their dependencies.",
480 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700481 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700482 // This is redirecting to mmma build command behaviour. Once it has soaked for a
483 // while, the build command is deleted from here once it has been removed from the
484 // envsetup.sh.
485 name: "modules-in-dirs-no-deps",
486 description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
487 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700488 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700489 name: "modules-in-a-dir",
490 description: "Build action: builds all of the modules in the current directory and their dependencies.",
491 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700492 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700493 name: "modules-in-dirs",
494 description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
495 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700496 }}
497 for i, flag := range buildActionFlags {
498 flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
499 }
500 dir := flags.String("dir", "", "Directory of the executed build command.")
501
502 // Only interested in the first two args which defines the build action and the directory.
503 // The remaining arguments are passed down to the config.
504 const numBuildActionFlags = 2
505 if len(args) < numBuildActionFlags {
506 flags.Usage()
Usta Shrestha675564d2022-08-09 18:03:23 -0400507 ctx.Fatalln("Improper build action arguments: too few arguments")
Patrice Arrudab7b22822019-05-21 17:46:23 -0700508 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400509 parseError := flags.Parse(args[0:numBuildActionFlags])
Patrice Arrudab7b22822019-05-21 17:46:23 -0700510
511 // The next block of code is to validate that exactly one build action is set and the dir flag
512 // is specified.
Usta Shrestha675564d2022-08-09 18:03:23 -0400513 buildActionFound := false
Patrice Arrudab7b22822019-05-21 17:46:23 -0700514 var buildAction build.BuildAction
Usta Shrestha675564d2022-08-09 18:03:23 -0400515 for _, f := range buildActionFlags {
516 if f.set {
517 if buildActionFound {
518 if parseError == nil {
519 //otherwise Parse() already called Usage()
520 flags.Usage()
521 }
522 ctx.Fatalf("Build action already specified, omit: --%s\n", f.name)
523 }
524 buildActionFound = true
525 buildAction = f.action
Patrice Arrudab7b22822019-05-21 17:46:23 -0700526 }
527 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400528 if !buildActionFound {
529 if parseError == nil {
530 //otherwise Parse() already called Usage()
531 flags.Usage()
532 }
Patrice Arrudab7b22822019-05-21 17:46:23 -0700533 ctx.Fatalln("Build action not defined.")
534 }
535 if *dir == "" {
536 ctx.Fatalln("-dir not specified.")
537 }
538
539 // Remove the build action flags from the args as they are not recognized by the config.
540 args = args[numBuildActionFlags:]
Dan Willemsence41e942019-07-29 23:39:30 -0700541 return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
Patrice Arrudab7b22822019-05-21 17:46:23 -0700542}
543
MarkDacek6614d9c2022-12-07 21:57:38 +0000544func runMake(ctx build.Context, config build.Config, _ []string) {
MarkDacek6614d9c2022-12-07 21:57:38 +0000545 logsDir := config.LogsDir()
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700546 if config.IsVerbose() {
547 writer := ctx.Writer
Colin Cross097ed2a2019-06-08 21:48:58 -0700548 fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
549 fmt.Fprintln(writer, "! Instead, the verbose log is always written to a compressed file in the output dir:")
550 fmt.Fprintln(writer, "!")
551 fmt.Fprintf(writer, "! gzip -cd %s/verbose.log.gz | less -R\n", logsDir)
552 fmt.Fprintln(writer, "!")
553 fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
554 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400555 ctx.Fatal("Invalid argument")
Dan Willemsenc6360832019-07-25 14:07:36 -0700556 }
557
558 if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
559 writer := ctx.Writer
Dan Willemsence41e942019-07-29 23:39:30 -0700560 fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
Dan Willemsenc6360832019-07-25 14:07:36 -0700561 fmt.Fprintln(writer, "!")
562 fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
563 fmt.Fprintln(writer, "!")
564 fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
565 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400566 ctx.Fatal("Invalid environment")
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700567 }
568
Anton Hansson5a7861a2021-06-04 10:09:01 +0100569 build.Build(ctx, config)
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700570}
571
572// getCommand finds the appropriate command based on args[1] flag. args[0]
573// is the soong_ui filename.
Liz Kammer0e7993e2020-10-15 11:07:13 -0700574func getCommand(args []string) (*command, []string, error) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400575 listFlags := func() []string {
576 flags := make([]string, len(commands))
577 for i, c := range commands {
578 flags[i] = c.flag
579 }
580 return flags
581 }
582
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700583 if len(args) < 2 {
Usta Shrestha675564d2022-08-09 18:03:23 -0400584 return nil, nil, fmt.Errorf("Too few arguments: %q\nUse one of these: %q", args, listFlags())
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700585 }
586
587 for _, c := range commands {
588 if c.flag == args[1] {
Liz Kammer0e7993e2020-10-15 11:07:13 -0700589 return &c, args[2:], nil
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700590 }
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700591 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400592 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 -0700593}
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000594
Liz Kammer4ae119c2022-02-09 10:54:05 -0500595func setMaxFiles(ctx build.Context) {
596 var limits syscall.Rlimit
597
598 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
599 if err != nil {
600 ctx.Println("Failed to get file limit:", err)
601 return
602 }
603
604 ctx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
Colin Cross611a2fb2023-11-08 22:09:57 -0800605
606 // Go 1.21 modifies the file limit but restores the original when
607 // execing subprocesses if it hasn't be overridden. Call Setrlimit
608 // here even if it doesn't appear to be necessary so that the
609 // syscall package considers it set.
Liz Kammer4ae119c2022-02-09 10:54:05 -0500610
611 limits.Cur = limits.Max
612 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
613 if err != nil {
614 ctx.Println("Failed to increase file limit:", err)
615 }
616}