blob: 713ccbe720982fdff0975166203b6c3f2cb4d743 [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"
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +000021 "io/ioutil"
Dan Willemsen1e704462016-08-21 15:17:17 -070022 "os"
23 "path/filepath"
24 "strconv"
25 "strings"
Liz Kammera7541782022-02-07 13:38:52 -050026 "syscall"
Dan Willemsen1e704462016-08-21 15:17:17 -070027 "time"
28
Lukacs T. Berki7d613bf2021-03-02 10:09:41 +010029 "android/soong/shared"
Dan Willemsen1e704462016-08-21 15:17:17 -070030 "android/soong/ui/build"
31 "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
61 run func(ctx build.Context, config build.Config, args []string, logsDir string)
62}
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)
159 defer trace.Close()
Dan Willemsen1e704462016-08-21 15:17:17 -0700160
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800161 // Create a new Status instance, which manages action counts and event output channels.
Dan Willemsenb82471a2018-05-17 16:37:09 -0700162 stat := &status.Status{}
163 defer stat.Finish()
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800164 // Hook up the terminal output and tracer to Status.
Colin Crosse0df1a32019-06-09 19:40:08 -0700165 stat.AddOutput(output)
Dan Willemsenb82471a2018-05-17 16:37:09 -0700166 stat.AddOutput(trace.StatusTracer())
167
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800168 // Set up a cleanup procedure in case the normal termination process doesn't work.
Lukacs T. Berkif656b842021-08-11 11:10:28 +0200169 signal.SetupSignals(log, cancel, func() {
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700170 trace.Close()
171 log.Cleanup()
Dan Willemsenb82471a2018-05-17 16:37:09 -0700172 stat.Finish()
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700173 })
174
Dan Willemsen59339a22018-07-22 21:18:45 -0700175 buildCtx := build.Context{ContextImpl: &build.ContextImpl{
Dan Willemsenb82471a2018-05-17 16:37:09 -0700176 Context: ctx,
177 Logger: log,
Nan Zhang17f27672018-12-12 16:01:49 -0800178 Metrics: met,
Dan Willemsenb82471a2018-05-17 16:37:09 -0700179 Tracer: trace,
Colin Crosse0df1a32019-06-09 19:40:08 -0700180 Writer: output,
Dan Willemsenb82471a2018-05-17 16:37:09 -0700181 Status: stat,
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700182 }}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700183
Kousik Kumar7b7dca42022-01-14 00:22:32 -0500184 config := c.config(buildCtx, args...)
185
Dan Willemsend9f6fa22016-08-21 15:17:17 -0700186 build.SetupOutDir(buildCtx, config)
Dan Willemsen8a073a82017-02-04 17:30:44 -0800187
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800188 // Set up files to be outputted in the log directory.
Patrice Arruda83842d72020-12-08 19:42:08 +0000189 logsDir := config.LogsDir()
Dan Willemsen1e704462016-08-21 15:17:17 -0700190
Patrice Arruda40564022020-12-10 00:42:58 +0000191 // Common list of metric file definition.
Patrice Arruda219eef32020-06-01 17:29:30 +0000192 buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
193 rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
194 soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
Jason Wuc4a03132022-11-28 13:39:48 -0500195 bp2buildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bp2build_metrics.pb")
Jason Wuf0ec6312022-11-30 10:55:05 -0500196 soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
Patrice Arruda40564022020-12-10 00:42:58 +0000197
Jason Wucc166a72022-12-19 11:53:12 -0500198 //Delete the stale metrics files
199 staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
200 if err := deleteStaleMetrics(staleFileSlice); err != nil {
201 log.Fatalln(err)
202 }
203
Kousik Kumara0a44a82020-10-08 02:33:29 -0400204 build.PrintOutDirWarning(buildCtx, config)
Patrice Arruda219eef32020-06-01 17:29:30 +0000205
Dan Willemsenb82471a2018-05-17 16:37:09 -0700206 os.MkdirAll(logsDir, 0777)
Colin Crossc0b9f6b2019-09-23 12:44:54 -0700207 log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
208 trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
209 stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, c.logsPrefix+"verbose.log")))
210 stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
Patrice Arruda219eef32020-06-01 17:29:30 +0000211 stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
Colin Cross7b624532019-06-21 15:08:30 -0700212 stat.AddOutput(status.NewCriticalPath(log))
Patrice Arruda74b43992020-03-11 08:21:05 -0700213 stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, c.logsPrefix+"build_progress.pb")))
Dan Willemsenb82471a2018-05-17 16:37:09 -0700214
Colin Cross8b8bec32019-11-15 13:18:43 -0800215 buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
216 buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
217 config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
218
Liz Kammer4ae119c2022-02-09 10:54:05 -0500219 setMaxFiles(buildCtx)
Liz Kammera7541782022-02-07 13:38:52 -0500220
221 {
Patrice Arruda40564022020-12-10 00:42:58 +0000222 // The order of the function calls is important. The last defer function call
223 // is the first one that is executed to save the rbe metrics to a protobuf
224 // file. The soong metrics file is then next. Bazel profiles are written
225 // before the uploadMetrics is invoked. The written files are then uploaded
226 // if the uploading of the metrics is enabled.
227 files := []string{
228 buildErrorFile, // build error strings
229 rbeMetricsFile, // high level metrics related to remote build execution.
Jason Wuf0ec6312022-11-30 10:55:05 -0500230 soongBuildMetricsFile, // high level metrics related to soong build(except bp2build).
Jason Wuc4a03132022-11-28 13:39:48 -0500231 bp2buildMetricsFile, // high level metrics related to bp2build.
Patrice Arruda40564022020-12-10 00:42:58 +0000232 soongMetricsFile, // high level metrics related to this build system.
233 config.BazelMetricsDir(), // directory that contains a set of bazel metrics.
234 }
MarkDacekd0e7cd32022-12-02 22:22:40 +0000235
236 if !config.SkipMetricsUpload() {
237 defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, files...)
238 }
Patrice Arruda40564022020-12-10 00:42:58 +0000239 defer met.Dump(soongMetricsFile)
Kousik Kumar7bc78192022-04-27 14:52:56 -0400240 defer build.CheckProdCreds(buildCtx, config)
Patrice Arruda40564022020-12-10 00:42:58 +0000241 }
Nan Zhangd50f53b2019-01-07 20:26:51 -0800242
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800243 // Read the time at the starting point.
Dan Willemsen1e704462016-08-21 15:17:17 -0700244 if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800245 // soong_ui.bash uses the date command's %N (nanosec) flag when getting the start time,
246 // which Darwin doesn't support. Check if it was executed properly before parsing the value.
Dan Willemsen1e704462016-08-21 15:17:17 -0700247 if !strings.HasSuffix(start, "N") {
248 if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
249 log.Verbosef("Took %dms to start up.",
250 time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
Nan Zhang17f27672018-12-12 16:01:49 -0800251 buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
Dan Willemsen1e704462016-08-21 15:17:17 -0700252 }
253 }
Dan Willemsencae59bc2017-07-13 14:27:31 -0700254
255 if executable, err := os.Executable(); err == nil {
256 trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
257 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700258 }
259
Dan Willemsen6b783c82019-03-08 11:42:28 -0800260 // Fix up the source tree due to a repo bug where it doesn't remove
261 // linkfiles that have been removed
262 fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.bp")
263 fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.mk")
264
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800265 // Create a source finder.
Jeff Gastonb64fc1c2017-08-04 12:30:12 -0700266 f := build.NewSourceFinder(buildCtx, config)
267 defer f.Shutdown()
268 build.FindSources(buildCtx, config, f)
269
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700270 c.run(buildCtx, config, args, logsDir)
Dan Willemsen051133b2017-07-14 11:29:29 -0700271}
272
Dan Willemsen6b783c82019-03-08 11:42:28 -0800273func fixBadDanglingLink(ctx build.Context, name string) {
274 _, err := os.Lstat(name)
275 if err != nil {
276 return
277 }
278 _, err = os.Stat(name)
279 if os.IsNotExist(err) {
280 err = os.Remove(name)
281 if err != nil {
282 ctx.Fatalf("Failed to remove dangling link %q: %v", name, err)
283 }
284 }
285}
286
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700287func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700288 flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400289 flags.SetOutput(ctx.Writer)
290
Dan Willemsen051133b2017-07-14 11:29:29 -0700291 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700292 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
293 fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
294 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700295
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700296 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that prints the human-readable config banner")
297 fmt.Fprintln(ctx.Writer, "from the beginning of the build.")
298 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700299 flags.PrintDefaults()
300 }
301 abs := flags.Bool("abs", false, "Print the absolute path of the value")
302 flags.Parse(args)
303
304 if flags.NArg() != 1 {
305 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400306 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700307 }
308
309 varName := flags.Arg(0)
310 if varName == "report_config" {
311 varData, err := build.DumpMakeVars(ctx, config, nil, build.BannerVars)
312 if err != nil {
313 ctx.Fatal(err)
314 }
315
316 fmt.Println(build.Banner(varData))
317 } else {
318 varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName})
319 if err != nil {
320 ctx.Fatal(err)
321 }
322
323 if *abs {
324 var res []string
325 for _, path := range strings.Fields(varData[varName]) {
326 if abs, err := filepath.Abs(path); err == nil {
327 res = append(res, abs)
328 } else {
329 ctx.Fatalln("Failed to get absolute path of", path, err)
330 }
331 }
332 fmt.Println(strings.Join(res, " "))
333 } else {
334 fmt.Println(varData[varName])
335 }
336 }
337}
338
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700339func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
Dan Willemsen051133b2017-07-14 11:29:29 -0700340 flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400341 flags.SetOutput(ctx.Writer)
342
Dan Willemsen051133b2017-07-14 11:29:29 -0700343 flags.Usage = func() {
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700344 fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
345 fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
346 fmt.Fprintln(ctx.Writer, "shell syntax. The resulting output may be sourced directly into a shell to")
347 fmt.Fprintln(ctx.Writer, "set corresponding shell variables.")
348 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700349
Patrice Arrudadb4c2f12019-06-17 17:27:09 -0700350 fmt.Fprintln(ctx.Writer, "'report_config' is a special case that dumps a variable containing the")
351 fmt.Fprintln(ctx.Writer, "human-readable config banner from the beginning of the build.")
352 fmt.Fprintln(ctx.Writer, "")
Dan Willemsen051133b2017-07-14 11:29:29 -0700353 flags.PrintDefaults()
354 }
355
356 varsStr := flags.String("vars", "", "Space-separated list of variables to dump")
357 absVarsStr := flags.String("abs-vars", "", "Space-separated list of variables to dump (using absolute paths)")
358
359 varPrefix := flags.String("var-prefix", "", "String to prepend to all variable names when dumping")
360 absVarPrefix := flags.String("abs-var-prefix", "", "String to prepent to all absolute path variable names when dumping")
361
362 flags.Parse(args)
363
364 if flags.NArg() != 0 {
365 flags.Usage()
Liz Kammerf2a80c62022-10-21 10:42:35 -0400366 ctx.Fatalf("Invalid usage")
Dan Willemsen051133b2017-07-14 11:29:29 -0700367 }
368
369 vars := strings.Fields(*varsStr)
370 absVars := strings.Fields(*absVarsStr)
371
372 allVars := append([]string{}, vars...)
373 allVars = append(allVars, absVars...)
374
375 if i := indexList("report_config", allVars); i != -1 {
376 allVars = append(allVars[:i], allVars[i+1:]...)
377 allVars = append(allVars, build.BannerVars...)
378 }
379
380 if len(allVars) == 0 {
381 return
382 }
383
384 varData, err := build.DumpMakeVars(ctx, config, nil, allVars)
385 if err != nil {
386 ctx.Fatal(err)
387 }
388
389 for _, name := range vars {
390 if name == "report_config" {
391 fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData))
392 } else {
393 fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name])
394 }
395 }
396 for _, name := range absVars {
397 var res []string
398 for _, path := range strings.Fields(varData[name]) {
399 abs, err := filepath.Abs(path)
400 if err != nil {
401 ctx.Fatalln("Failed to get absolute path of", path, err)
402 }
403 res = append(res, abs)
404 }
405 fmt.Printf("%s%s='%s'\n", *absVarPrefix, name, strings.Join(res, " "))
406 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700407}
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700408
Patrice Arrudab7b22822019-05-21 17:46:23 -0700409func stdio() terminal.StdioInterface {
410 return terminal.StdioImpl{}
411}
412
Jaewoong Jung9f98d3f2020-11-17 18:20:14 -0800413// dumpvar and dumpvars use stdout to output variable values, so use stderr instead of stdout when
414// reporting events to keep stdout clean from noise.
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700415func customStdio() terminal.StdioInterface {
416 return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr)
417}
418
419// dumpVarConfig does not require any arguments to be parsed by the NewConfig.
420func dumpVarConfig(ctx build.Context, args ...string) build.Config {
421 return build.NewConfig(ctx)
422}
423
Patrice Arrudab7b22822019-05-21 17:46:23 -0700424func buildActionConfig(ctx build.Context, args ...string) build.Config {
425 flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
Usta Shrestha675564d2022-08-09 18:03:23 -0400426 flags.SetOutput(ctx.Writer)
427
Patrice Arrudab7b22822019-05-21 17:46:23 -0700428 flags.Usage = func() {
429 fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
430 fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
431 fmt.Fprintln(ctx.Writer, "action. The --dir flag is required to determine what is needed to")
432 fmt.Fprintln(ctx.Writer, "build in the source tree based on the build action. See below for")
433 fmt.Fprintln(ctx.Writer, "the list of acceptable build action flags.")
434 fmt.Fprintln(ctx.Writer, "")
435 flags.PrintDefaults()
436 }
437
438 buildActionFlags := []struct {
Dan Willemsence41e942019-07-29 23:39:30 -0700439 name string
440 description string
441 action build.BuildAction
442 set bool
Patrice Arrudab7b22822019-05-21 17:46:23 -0700443 }{{
Dan Willemsence41e942019-07-29 23:39:30 -0700444 name: "all-modules",
445 description: "Build action: build from the top of the source tree.",
446 action: build.BUILD_MODULES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700447 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700448 // This is redirecting to mma build command behaviour. Once it has soaked for a
449 // while, the build command is deleted from here once it has been removed from the
450 // envsetup.sh.
451 name: "modules-in-a-dir-no-deps",
452 description: "Build action: builds all of the modules in the current directory without their dependencies.",
453 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700454 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700455 // This is redirecting to mmma build command behaviour. Once it has soaked for a
456 // while, the build command is deleted from here once it has been removed from the
457 // envsetup.sh.
458 name: "modules-in-dirs-no-deps",
459 description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
460 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700461 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700462 name: "modules-in-a-dir",
463 description: "Build action: builds all of the modules in the current directory and their dependencies.",
464 action: build.BUILD_MODULES_IN_A_DIRECTORY,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700465 }, {
Dan Willemsence41e942019-07-29 23:39:30 -0700466 name: "modules-in-dirs",
467 description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
468 action: build.BUILD_MODULES_IN_DIRECTORIES,
Patrice Arrudab7b22822019-05-21 17:46:23 -0700469 }}
470 for i, flag := range buildActionFlags {
471 flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
472 }
473 dir := flags.String("dir", "", "Directory of the executed build command.")
474
475 // Only interested in the first two args which defines the build action and the directory.
476 // The remaining arguments are passed down to the config.
477 const numBuildActionFlags = 2
478 if len(args) < numBuildActionFlags {
479 flags.Usage()
Usta Shrestha675564d2022-08-09 18:03:23 -0400480 ctx.Fatalln("Improper build action arguments: too few arguments")
Patrice Arrudab7b22822019-05-21 17:46:23 -0700481 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400482 parseError := flags.Parse(args[0:numBuildActionFlags])
Patrice Arrudab7b22822019-05-21 17:46:23 -0700483
484 // The next block of code is to validate that exactly one build action is set and the dir flag
485 // is specified.
Usta Shrestha675564d2022-08-09 18:03:23 -0400486 buildActionFound := false
Patrice Arrudab7b22822019-05-21 17:46:23 -0700487 var buildAction build.BuildAction
Usta Shrestha675564d2022-08-09 18:03:23 -0400488 for _, f := range buildActionFlags {
489 if f.set {
490 if buildActionFound {
491 if parseError == nil {
492 //otherwise Parse() already called Usage()
493 flags.Usage()
494 }
495 ctx.Fatalf("Build action already specified, omit: --%s\n", f.name)
496 }
497 buildActionFound = true
498 buildAction = f.action
Patrice Arrudab7b22822019-05-21 17:46:23 -0700499 }
500 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400501 if !buildActionFound {
502 if parseError == nil {
503 //otherwise Parse() already called Usage()
504 flags.Usage()
505 }
Patrice Arrudab7b22822019-05-21 17:46:23 -0700506 ctx.Fatalln("Build action not defined.")
507 }
508 if *dir == "" {
509 ctx.Fatalln("-dir not specified.")
510 }
511
512 // Remove the build action flags from the args as they are not recognized by the config.
513 args = args[numBuildActionFlags:]
Dan Willemsence41e942019-07-29 23:39:30 -0700514 return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
Patrice Arrudab7b22822019-05-21 17:46:23 -0700515}
516
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100517func runMake(ctx build.Context, config build.Config, _ []string, logsDir string) {
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700518 if config.IsVerbose() {
519 writer := ctx.Writer
Colin Cross097ed2a2019-06-08 21:48:58 -0700520 fmt.Fprintln(writer, "! The argument `showcommands` is no longer supported.")
521 fmt.Fprintln(writer, "! Instead, the verbose log is always written to a compressed file in the output dir:")
522 fmt.Fprintln(writer, "!")
523 fmt.Fprintf(writer, "! gzip -cd %s/verbose.log.gz | less -R\n", logsDir)
524 fmt.Fprintln(writer, "!")
525 fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
526 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400527 ctx.Fatal("Invalid argument")
Dan Willemsenc6360832019-07-25 14:07:36 -0700528 }
529
530 if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
531 writer := ctx.Writer
Dan Willemsence41e942019-07-29 23:39:30 -0700532 fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
Dan Willemsenc6360832019-07-25 14:07:36 -0700533 fmt.Fprintln(writer, "!")
534 fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
535 fmt.Fprintln(writer, "!")
536 fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
537 fmt.Fprintln(writer, "")
Liz Kammerf2a80c62022-10-21 10:42:35 -0400538 ctx.Fatal("Invalid environment")
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700539 }
540
Anton Hansson5a7861a2021-06-04 10:09:01 +0100541 build.Build(ctx, config)
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700542}
543
544// getCommand finds the appropriate command based on args[1] flag. args[0]
545// is the soong_ui filename.
Liz Kammer0e7993e2020-10-15 11:07:13 -0700546func getCommand(args []string) (*command, []string, error) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400547 listFlags := func() []string {
548 flags := make([]string, len(commands))
549 for i, c := range commands {
550 flags[i] = c.flag
551 }
552 return flags
553 }
554
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700555 if len(args) < 2 {
Usta Shrestha675564d2022-08-09 18:03:23 -0400556 return nil, nil, fmt.Errorf("Too few arguments: %q\nUse one of these: %q", args, listFlags())
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700557 }
558
559 for _, c := range commands {
560 if c.flag == args[1] {
Liz Kammer0e7993e2020-10-15 11:07:13 -0700561 return &c, args[2:], nil
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700562 }
Patrice Arrudaa5c25422019-04-09 18:49:49 -0700563 }
Usta Shrestha675564d2022-08-09 18:03:23 -0400564 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 -0700565}
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000566
567// For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
568func populateExternalDistDir(ctx build.Context, config build.Config) {
569 // Make sure that internalDistDirPath and externalDistDirPath are both absolute paths, so we can compare them
570 var err error
571 var internalDistDirPath string
572 var externalDistDirPath string
573 if internalDistDirPath, err = filepath.Abs(config.DistDir()); err != nil {
574 ctx.Fatalf("Unable to find absolute path of %s: %s", internalDistDirPath, err)
575 }
576 if externalDistDirPath, err = filepath.Abs(config.RealDistDir()); err != nil {
577 ctx.Fatalf("Unable to find absolute path of %s: %s", externalDistDirPath, err)
578 }
579 if externalDistDirPath == internalDistDirPath {
580 return
581 }
582
Rupert Shuttleworth534f1572020-12-16 23:07:06 +0000583 // Make sure the internal DIST_DIR actually exists before trying to read from it
584 if _, err = os.Stat(internalDistDirPath); os.IsNotExist(err) {
585 ctx.Println("Skipping Bazel dist dir migration - nothing to do!")
586 return
587 }
588
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000589 // Make sure the external DIST_DIR actually exists before trying to write to it
590 if err = os.MkdirAll(externalDistDirPath, 0755); err != nil {
591 ctx.Fatalf("Unable to make directory %s: %s", externalDistDirPath, err)
592 }
593
594 ctx.Println("Populating external DIST_DIR...")
595
596 populateExternalDistDirHelper(ctx, config, internalDistDirPath, externalDistDirPath)
597}
598
599func populateExternalDistDirHelper(ctx build.Context, config build.Config, internalDistDirPath string, externalDistDirPath string) {
600 files, err := ioutil.ReadDir(internalDistDirPath)
601 if err != nil {
602 ctx.Fatalf("Can't read internal distdir %s: %s", internalDistDirPath, err)
603 }
604 for _, f := range files {
605 internalFilePath := filepath.Join(internalDistDirPath, f.Name())
606 externalFilePath := filepath.Join(externalDistDirPath, f.Name())
607
608 if f.IsDir() {
609 // Moving a directory - check if there is an existing directory to merge with
610 externalLstat, err := os.Lstat(externalFilePath)
611 if err != nil {
612 if !os.IsNotExist(err) {
613 ctx.Fatalf("Can't lstat external %s: %s", externalDistDirPath, err)
614 }
615 // Otherwise, if the error was os.IsNotExist, that's fine and we fall through to the rename at the bottom
616 } else {
617 if externalLstat.IsDir() {
618 // Existing dir - try to merge the directories?
619 populateExternalDistDirHelper(ctx, config, internalFilePath, externalFilePath)
620 continue
621 } else {
622 // Existing file being replaced with a directory. Delete the existing file...
623 if err := os.RemoveAll(externalFilePath); err != nil {
624 ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
625 }
626 }
627 }
628 } else {
629 // Moving a file (not a dir) - delete any existing file or directory
630 if err := os.RemoveAll(externalFilePath); err != nil {
631 ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
632 }
633 }
634
635 // The actual move - do a rename instead of a copy in order to save disk space.
636 if err := os.Rename(internalFilePath, externalFilePath); err != nil {
637 ctx.Fatalf("Unable to rename %s -> %s due to error %s", internalFilePath, externalFilePath, err)
638 }
639 }
640}
Liz Kammer4ae119c2022-02-09 10:54:05 -0500641
642func setMaxFiles(ctx build.Context) {
643 var limits syscall.Rlimit
644
645 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limits)
646 if err != nil {
647 ctx.Println("Failed to get file limit:", err)
648 return
649 }
650
651 ctx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
652 if limits.Cur == limits.Max {
653 return
654 }
655
656 limits.Cur = limits.Max
657 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
658 if err != nil {
659 ctx.Println("Failed to increase file limit:", err)
660 }
661}