blob: 2022e50bdd5f5be58b3715b5d88899e61e8bfc0b [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 build
16
17import (
Dan Willemsendb8457c2017-05-12 16:38:17 -070018 "io/ioutil"
Dan Willemsen1e704462016-08-21 15:17:17 -070019 "os"
Dan Willemsen1e704462016-08-21 15:17:17 -070020 "path/filepath"
Dan Willemsen80d72612022-04-20 21:45:00 -070021 "sync"
Dan Willemsen1e704462016-08-21 15:17:17 -070022 "text/template"
Colin Cross74cda722020-01-16 15:25:50 -080023
24 "android/soong/ui/metrics"
Dan Willemsen1e704462016-08-21 15:17:17 -070025)
26
Jingwen Chencda22c92020-11-23 00:22:30 -050027// SetupOutDir ensures the out directory exists, and has the proper files to
28// prevent kati from recursing into it.
Dan Willemsen1e704462016-08-21 15:17:17 -070029func SetupOutDir(ctx Context, config Config) {
30 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
31 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
Anton Hansson17fc5a02021-06-18 16:37:14 +010032
33 // Potentially write a marker file for whether kati is enabled. This is used by soong_build to
34 // potentially run the AndroidMk singleton and postinstall commands.
35 // Note that the absence of the file does not not preclude running Kati for product
36 // configuration purposes.
37 katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled")
38 if config.SkipKatiNinja() {
39 os.Remove(katiEnabledMarker)
40 // Note that we can not remove the file for SkipKati builds yet -- some continuous builds
41 // --skip-make builds rely on kati targets being defined.
42 } else if !config.SkipKati() {
43 ensureEmptyFileExists(ctx, katiEnabledMarker)
Dan Willemsene0879fc2017-08-04 15:06:27 -070044 }
Anton Hansson17fc5a02021-06-18 16:37:14 +010045
Dan Willemsen1e704462016-08-21 15:17:17 -070046 // The ninja_build file is used by our buildbots to understand that the output
47 // can be parsed as ninja output.
48 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
Jeff Gastonb64fc1c2017-08-04 12:30:12 -070049 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
Colin Cross28f527c2019-11-26 16:19:04 -080050
51 if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +000052 err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw
Colin Cross28f527c2019-11-26 16:19:04 -080053 if err != nil {
54 ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
55 }
56 } else {
57 ctx.Fatalln("Missing BUILD_DATETIME_FILE")
58 }
Dan Willemsen1e704462016-08-21 15:17:17 -070059}
60
61var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
62builddir = {{.OutDir}}
Colin Cross8b8bec32019-11-15 13:18:43 -080063{{if .UseRemoteBuild }}pool local_pool
Dan Willemsen29971232018-09-26 14:58:30 -070064 depth = {{.Parallel}}
Colin Cross8b8bec32019-11-15 13:18:43 -080065{{end -}}
66pool highmem_pool
67 depth = {{.HighmemParallel}}
Anton Hansson0b55bdb2021-06-04 10:08:08 +010068{{if and (not .SkipKatiNinja) .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070069subninja {{.KatiPackageNinjaFile}}
Dan Willemsene0879fc2017-08-04 15:06:27 -070070{{end -}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070071subninja {{.SoongNinjaFile}}
Dan Willemsen1e704462016-08-21 15:17:17 -070072`))
73
74func createCombinedBuildNinjaFile(ctx Context, config Config) {
Anton Hansson0b55bdb2021-06-04 10:08:08 +010075 // If we're in SkipKati mode but want to run kati ninja, skip creating this file if it already exists
76 if config.SkipKati() && !config.SkipKatiNinja() {
Dan Willemsene0879fc2017-08-04 15:06:27 -070077 if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
78 return
79 }
80 }
81
Dan Willemsen1e704462016-08-21 15:17:17 -070082 file, err := os.Create(config.CombinedNinjaFile())
83 if err != nil {
84 ctx.Fatalln("Failed to create combined ninja file:", err)
85 }
86 defer file.Close()
87
88 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
89 ctx.Fatalln("Failed to write combined ninja file:", err)
90 }
91}
92
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +000093// These are bitmasks which can be used to check whether various flags are set e.g. whether to use Bazel.
Dan Willemsen1e704462016-08-21 15:17:17 -070094const (
Anton Hansson5a7861a2021-06-04 10:09:01 +010095 _ = iota
96 // Whether to run the kati config step.
97 RunProductConfig = 1 << iota
98 // Whether to run soong to generate a ninja file.
99 RunSoong = 1 << iota
100 // Whether to run kati to generate a ninja file.
101 RunKati = 1 << iota
Anton Hansson0b55bdb2021-06-04 10:08:08 +0100102 // Whether to include the kati-generated ninja file in the combined ninja.
103 RunKatiNinja = 1 << iota
Anton Hansson5a7861a2021-06-04 10:09:01 +0100104 // Whether to run ninja on the combined ninja.
105 RunNinja = 1 << iota
106 // Whether to run bazel on the combined ninja.
Chris Parsons19ab9a42022-08-30 13:15:04 -0400107 RunBazel = 1 << iota
108 RunBuildTests = 1 << iota
109 RunAll = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunNinja
Dan Willemsen1e704462016-08-21 15:17:17 -0700110)
111
Chris Parsonsef615e52022-08-18 22:04:11 -0400112// checkBazelMode fails the build if there are conflicting arguments for which bazel
113// build mode to use.
114func checkBazelMode(ctx Context, config Config) {
Chris Parsonsef615e52022-08-18 22:04:11 -0400115 if config.bazelProdMode && config.bazelDevMode {
Chris Parsons1bb58da2022-08-30 13:37:57 -0400116 ctx.Fatalln("Conflicting bazel mode.\n" +
Chris Parsonsef615e52022-08-18 22:04:11 -0400117 "Do not specify both --bazel-mode and --bazel-mode-dev")
118 }
119}
120
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000121// checkProblematicFiles fails the build if existing Android.mk or CleanSpec.mk files are found at the root of the tree.
Anton Hanssonecf0f102018-09-19 22:14:17 +0100122func checkProblematicFiles(ctx Context) {
123 files := []string{"Android.mk", "CleanSpec.mk"}
124 for _, file := range files {
125 if _, err := os.Stat(file); !os.IsNotExist(err) {
126 absolute := absPath(ctx, file)
127 ctx.Printf("Found %s in tree root. This file needs to be removed to build.\n", file)
128 ctx.Fatalf(" rm %s\n", absolute)
129 }
130 }
131}
132
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000133// checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
Dan Willemsendb8457c2017-05-12 16:38:17 -0700134func checkCaseSensitivity(ctx Context, config Config) {
135 outDir := config.OutDir()
136 lowerCase := filepath.Join(outDir, "casecheck.txt")
137 upperCase := filepath.Join(outDir, "CaseCheck.txt")
138 lowerData := "a"
139 upperData := "B"
140
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000141 if err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0666); err != nil { // a+rw
Dan Willemsendb8457c2017-05-12 16:38:17 -0700142 ctx.Fatalln("Failed to check case sensitivity:", err)
143 }
144
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000145 if err := ioutil.WriteFile(upperCase, []byte(upperData), 0666); err != nil { // a+rw
Dan Willemsendb8457c2017-05-12 16:38:17 -0700146 ctx.Fatalln("Failed to check case sensitivity:", err)
147 }
148
149 res, err := ioutil.ReadFile(lowerCase)
150 if err != nil {
151 ctx.Fatalln("Failed to check case sensitivity:", err)
152 }
153
154 if string(res) != lowerData {
155 ctx.Println("************************************************************")
156 ctx.Println("You are building on a case-insensitive filesystem.")
157 ctx.Println("Please move your source tree to a case-sensitive filesystem.")
158 ctx.Println("************************************************************")
159 ctx.Fatalln("Case-insensitive filesystems not supported")
160 }
161}
162
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000163// help prints a help/usage message, via the build/make/help.sh script.
164func help(ctx Context, config Config) {
Jeff Gastondf4a0812017-05-30 20:11:20 -0700165 cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700166 cmd.Sandbox = dumpvarsSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -0700167 cmd.RunAndPrintOrFatal()
Dan Willemsen02781d52017-05-12 19:28:13 -0700168}
169
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000170// checkRAM warns if there probably isn't enough RAM to complete a build.
171func checkRAM(ctx Context, config Config) {
Dan Willemsen570a2922020-05-26 23:02:29 -0700172 if totalRAM := config.TotalRAM(); totalRAM != 0 {
173 ram := float32(totalRAM) / (1024 * 1024 * 1024)
174 ctx.Verbosef("Total RAM: %.3vGB", ram)
175
176 if ram <= 16 {
177 ctx.Println("************************************************************")
178 ctx.Printf("You are building on a machine with %.3vGB of RAM\n", ram)
179 ctx.Println("")
180 ctx.Println("The minimum required amount of free memory is around 16GB,")
181 ctx.Println("and even with that, some configurations may not work.")
182 ctx.Println("")
183 ctx.Println("If you run into segfaults or other errors, try reducing your")
184 ctx.Println("-j value.")
185 ctx.Println("************************************************************")
186 } else if ram <= float32(config.Parallel()) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000187 // Want at least 1GB of RAM per job.
Dan Willemsen570a2922020-05-26 23:02:29 -0700188 ctx.Printf("Warning: high -j%d count compared to %.3vGB of RAM", config.Parallel(), ram)
189 ctx.Println("If you run into segfaults or other errors, try a lower -j value")
190 }
191 }
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000192}
193
Usta Shresthadb46a9b2022-07-11 11:29:56 -0400194// Build the tree. Various flags in `config` govern which components of
195// the build to run.
Anton Hansson5a7861a2021-06-04 10:09:01 +0100196func Build(ctx Context, config Config) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000197 ctx.Verboseln("Starting build with args:", config.Arguments())
198 ctx.Verboseln("Environment:", config.Environment().Environ())
Dan Willemsen1e704462016-08-21 15:17:17 -0700199
Colin Cross74cda722020-01-16 15:25:50 -0800200 ctx.BeginTrace(metrics.Total, "total")
201 defer ctx.EndTrace()
202
Dan Willemsen1e704462016-08-21 15:17:17 -0700203 if inList("help", config.Arguments()) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000204 help(ctx, config)
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700205 return
Dan Willemsen1e704462016-08-21 15:17:17 -0700206 }
207
Jeff Gaston3615fe82017-05-24 13:14:34 -0700208 // Make sure that no other Soong process is running with the same output directory
209 buildLock := BecomeSingletonOrFail(ctx, config)
210 defer buildLock.Unlock()
211
Usta Shrestha675564d2022-08-09 18:03:23 -0400212 logArgsOtherThan := func(specialTargets ...string) {
213 var ignored []string
214 for _, a := range config.Arguments() {
215 if !inList(a, specialTargets) {
216 ignored = append(ignored, a)
217 }
218 }
219 if len(ignored) > 0 {
220 ctx.Printf("ignoring arguments %q", ignored)
221 }
222 }
223
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000224 if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400225 logArgsOtherThan("clean", "clobber")
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000226 clean(ctx, config)
227 return
228 }
229
Dan Willemsen80d72612022-04-20 21:45:00 -0700230 defer waitForDist(ctx)
231
Chris Parsonsef615e52022-08-18 22:04:11 -0400232 checkBazelMode(ctx, config)
233
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000234 // checkProblematicFiles aborts the build if Android.mk or CleanSpec.mk are found at the root of the tree.
Anton Hanssonecf0f102018-09-19 22:14:17 +0100235 checkProblematicFiles(ctx)
236
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000237 checkRAM(ctx, config)
238
Dan Willemsen1e704462016-08-21 15:17:17 -0700239 SetupOutDir(ctx, config)
240
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000241 // checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
Dan Willemsendb8457c2017-05-12 16:38:17 -0700242 checkCaseSensitivity(ctx, config)
243
Jeff Gastonefc1b412017-03-29 17:29:06 -0700244 ensureEmptyDirectoriesExist(ctx, config.TempDir())
245
Dan Willemsen18490112018-05-25 16:30:04 -0700246 SetupPath(ctx, config)
247
usta6fffdd52022-09-19 13:16:18 -0400248 what := evaluateWhatToRun(config, ctx.Verboseln)
Lukacs T. Berkia1b93722021-09-02 17:23:06 +0200249
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900250 if config.StartGoma() {
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900251 startGoma(ctx, config)
252 }
253
Ramy Medhatbbf25672019-07-17 12:30:04 +0000254 if config.StartRBE() {
Kousik Kumar4c180ad2022-05-27 07:48:37 -0400255 cleanupRBELogsDir(ctx, config)
Ramy Medhatbbf25672019-07-17 12:30:04 +0000256 startRBE(ctx, config)
Kousik Kumara1d8fa92022-03-18 02:50:31 -0400257 defer DumpRBEMetrics(ctx, config, filepath.Join(config.LogsDir(), "rbe_metrics.pb"))
Ramy Medhatbbf25672019-07-17 12:30:04 +0000258 }
259
Anton Hansson5a7861a2021-06-04 10:09:01 +0100260 if what&RunProductConfig != 0 {
Dan Willemsen1e704462016-08-21 15:17:17 -0700261 runMakeProductConfig(ctx, config)
262 }
263
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000264 // Everything below here depends on product config.
265
Colin Cross806fd942019-05-03 13:35:58 -0700266 if inList("installclean", config.Arguments()) ||
267 inList("install-clean", config.Arguments()) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400268 logArgsOtherThan("installclean", "install-clean")
Rupert Shuttleworth1f304e62020-11-24 14:13:41 +0000269 installClean(ctx, config)
Dan Willemsenf052f782017-05-18 15:29:04 -0700270 ctx.Println("Deleted images and staging directories.")
271 return
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000272 }
273
274 if inList("dataclean", config.Arguments()) ||
Colin Cross806fd942019-05-03 13:35:58 -0700275 inList("data-clean", config.Arguments()) {
Usta Shrestha675564d2022-08-09 18:03:23 -0400276 logArgsOtherThan("dataclean", "data-clean")
Rupert Shuttleworth1f304e62020-11-24 14:13:41 +0000277 dataClean(ctx, config)
Dan Willemsenf052f782017-05-18 15:29:04 -0700278 ctx.Println("Deleted data files.")
279 return
280 }
281
Anton Hansson5a7861a2021-06-04 10:09:01 +0100282 if what&RunSoong != 0 {
Dan Willemsen1e704462016-08-21 15:17:17 -0700283 runSoong(ctx, config)
284 }
285
Anton Hansson5a7861a2021-06-04 10:09:01 +0100286 if what&RunKati != 0 {
Dan Willemsen29971232018-09-26 14:58:30 -0700287 genKatiSuffix(ctx, config)
288 runKatiCleanSpec(ctx, config)
289 runKatiBuild(ctx, config)
Dan Willemsenfb1271a2018-09-26 15:00:42 -0700290 runKatiPackage(ctx, config)
Dan Willemsene0879fc2017-08-04 15:06:27 -0700291
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000292 ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
Anton Hansson0b55bdb2021-06-04 10:08:08 +0100293 } else if what&RunKatiNinja != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700294 // Load last Kati Suffix if it exists
295 if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
296 ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
297 config.SetKatiSuffix(string(katiSuffix))
298 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700299 }
300
Colin Cross37193492017-11-16 17:55:00 -0800301 // Write combined ninja file
302 createCombinedBuildNinjaFile(ctx, config)
303
Colin Cross8ba7d472020-06-25 11:27:52 -0700304 distGzipFile(ctx, config, config.CombinedNinjaFile())
305
Colin Cross37193492017-11-16 17:55:00 -0800306 if what&RunBuildTests != 0 {
307 testForDanglingRules(ctx, config)
308 }
309
Anton Hansson5a7861a2021-06-04 10:09:01 +0100310 if what&RunNinja != 0 {
311 if what&RunKati != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700312 installCleanIfNecessary(ctx, config)
313 }
Dan Willemsen02781d52017-05-12 19:28:13 -0700314
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100315 runNinjaForBuild(ctx, config)
Dan Willemsen1e704462016-08-21 15:17:17 -0700316 }
Rupert Shuttleworth680387b2020-10-25 12:31:27 +0000317
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000318 // Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
Anton Hansson5a7861a2021-06-04 10:09:01 +0100319 if what&RunBazel != 0 {
Rupert Shuttleworth680387b2020-10-25 12:31:27 +0000320 runBazel(ctx, config)
321 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700322}
Colin Cross8ba7d472020-06-25 11:27:52 -0700323
usta6fffdd52022-09-19 13:16:18 -0400324func evaluateWhatToRun(config Config, verboseln func(v ...interface{})) int {
325 //evaluate what to run
326 what := RunAll
327 if config.Checkbuild() {
328 what |= RunBuildTests
329 }
330 if config.SkipConfig() {
331 verboseln("Skipping Config as requested")
332 what = what &^ RunProductConfig
333 }
334 if config.SkipKati() {
335 verboseln("Skipping Kati as requested")
336 what = what &^ RunKati
337 }
338 if config.SkipKatiNinja() {
339 verboseln("Skipping use of Kati ninja as requested")
340 what = what &^ RunKatiNinja
341 }
342 if config.SkipSoong() {
343 verboseln("Skipping use of Soong as requested")
344 what = what &^ RunSoong
345 }
346
347 if config.SkipNinja() {
348 verboseln("Skipping Ninja as requested")
349 what = what &^ RunNinja
350 }
351
352 if !config.SoongBuildInvocationNeeded() {
353 // This means that the output of soong_build is not needed and thus it would
354 // run unnecessarily. In addition, if this code wasn't there invocations
355 // with only special-cased target names like "m bp2build" would result in
356 // passing Ninja the empty target list and it would then build the default
357 // targets which is not what the user asked for.
358 what = what &^ RunNinja
359 what = what &^ RunKati
360 }
361 return what
362}
363
Dan Willemsen80d72612022-04-20 21:45:00 -0700364var distWaitGroup sync.WaitGroup
365
366// waitForDist waits for all backgrounded distGzipFile and distFile writes to finish
367func waitForDist(ctx Context) {
368 ctx.BeginTrace("soong_ui", "dist")
369 defer ctx.EndTrace()
370
371 distWaitGroup.Wait()
372}
373
Colin Cross8ba7d472020-06-25 11:27:52 -0700374// distGzipFile writes a compressed copy of src to the distDir if dist is enabled. Failures
Dan Willemsen80d72612022-04-20 21:45:00 -0700375// are printed but non-fatal. Uses the distWaitGroup func for backgrounding (optimization).
Colin Cross8ba7d472020-06-25 11:27:52 -0700376func distGzipFile(ctx Context, config Config, src string, subDirs ...string) {
377 if !config.Dist() {
378 return
379 }
380
381 subDir := filepath.Join(subDirs...)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000382 destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
Colin Cross8ba7d472020-06-25 11:27:52 -0700383
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000384 if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
Colin Cross8ba7d472020-06-25 11:27:52 -0700385 ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
Colin Cross8ba7d472020-06-25 11:27:52 -0700386 }
387
Dan Willemsen80d72612022-04-20 21:45:00 -0700388 distWaitGroup.Add(1)
389 go func() {
390 defer distWaitGroup.Done()
391 if err := gzipFileToDir(src, destDir); err != nil {
392 ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
393 }
394 }()
Colin Cross8ba7d472020-06-25 11:27:52 -0700395}
396
397// distFile writes a copy of src to the distDir if dist is enabled. Failures are printed but
Dan Willemsen80d72612022-04-20 21:45:00 -0700398// non-fatal. Uses the distWaitGroup func for backgrounding (optimization).
Colin Cross8ba7d472020-06-25 11:27:52 -0700399func distFile(ctx Context, config Config, src string, subDirs ...string) {
400 if !config.Dist() {
401 return
402 }
403
404 subDir := filepath.Join(subDirs...)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000405 destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
Colin Cross8ba7d472020-06-25 11:27:52 -0700406
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000407 if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
Colin Cross8ba7d472020-06-25 11:27:52 -0700408 ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
Colin Cross8ba7d472020-06-25 11:27:52 -0700409 }
410
Dan Willemsen80d72612022-04-20 21:45:00 -0700411 distWaitGroup.Add(1)
412 go func() {
413 defer distWaitGroup.Done()
414 if _, err := copyFile(src, filepath.Join(destDir, filepath.Base(src))); err != nil {
415 ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
416 }
417 }()
Colin Cross8ba7d472020-06-25 11:27:52 -0700418}