blob: d261f89479c205946cba2e69dff55f9916ddf89c [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"
21 "text/template"
Colin Cross74cda722020-01-16 15:25:50 -080022
23 "android/soong/ui/metrics"
Dan Willemsen1e704462016-08-21 15:17:17 -070024)
25
Jingwen Chencda22c92020-11-23 00:22:30 -050026// SetupOutDir ensures the out directory exists, and has the proper files to
27// prevent kati from recursing into it.
Dan Willemsen1e704462016-08-21 15:17:17 -070028func SetupOutDir(ctx Context, config Config) {
29 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
30 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
Anton Hansson17fc5a02021-06-18 16:37:14 +010031
32 // Potentially write a marker file for whether kati is enabled. This is used by soong_build to
33 // potentially run the AndroidMk singleton and postinstall commands.
34 // Note that the absence of the file does not not preclude running Kati for product
35 // configuration purposes.
36 katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled")
37 if config.SkipKatiNinja() {
38 os.Remove(katiEnabledMarker)
39 // Note that we can not remove the file for SkipKati builds yet -- some continuous builds
40 // --skip-make builds rely on kati targets being defined.
41 } else if !config.SkipKati() {
42 ensureEmptyFileExists(ctx, katiEnabledMarker)
Dan Willemsene0879fc2017-08-04 15:06:27 -070043 }
Anton Hansson17fc5a02021-06-18 16:37:14 +010044
Dan Willemsen1e704462016-08-21 15:17:17 -070045 // The ninja_build file is used by our buildbots to understand that the output
46 // can be parsed as ninja output.
47 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
Jeff Gastonb64fc1c2017-08-04 12:30:12 -070048 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
Colin Cross28f527c2019-11-26 16:19:04 -080049
50 if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +000051 err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw
Colin Cross28f527c2019-11-26 16:19:04 -080052 if err != nil {
53 ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
54 }
55 } else {
56 ctx.Fatalln("Missing BUILD_DATETIME_FILE")
57 }
Dan Willemsen1e704462016-08-21 15:17:17 -070058}
59
60var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
61builddir = {{.OutDir}}
Colin Cross8b8bec32019-11-15 13:18:43 -080062{{if .UseRemoteBuild }}pool local_pool
Dan Willemsen29971232018-09-26 14:58:30 -070063 depth = {{.Parallel}}
Colin Cross8b8bec32019-11-15 13:18:43 -080064{{end -}}
65pool highmem_pool
66 depth = {{.HighmemParallel}}
Anton Hansson0b55bdb2021-06-04 10:08:08 +010067{{if and (not .SkipKatiNinja) .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070068subninja {{.KatiPackageNinjaFile}}
Dan Willemsene0879fc2017-08-04 15:06:27 -070069{{end -}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070070subninja {{.SoongNinjaFile}}
Dan Willemsen1e704462016-08-21 15:17:17 -070071`))
72
73func createCombinedBuildNinjaFile(ctx Context, config Config) {
Anton Hansson0b55bdb2021-06-04 10:08:08 +010074 // If we're in SkipKati mode but want to run kati ninja, skip creating this file if it already exists
75 if config.SkipKati() && !config.SkipKatiNinja() {
Dan Willemsene0879fc2017-08-04 15:06:27 -070076 if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
77 return
78 }
79 }
80
Dan Willemsen1e704462016-08-21 15:17:17 -070081 file, err := os.Create(config.CombinedNinjaFile())
82 if err != nil {
83 ctx.Fatalln("Failed to create combined ninja file:", err)
84 }
85 defer file.Close()
86
87 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
88 ctx.Fatalln("Failed to write combined ninja file:", err)
89 }
90}
91
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +000092// 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 -070093const (
Anton Hansson5a7861a2021-06-04 10:09:01 +010094 _ = iota
95 // Whether to run the kati config step.
96 RunProductConfig = 1 << iota
97 // Whether to run soong to generate a ninja file.
98 RunSoong = 1 << iota
99 // Whether to run kati to generate a ninja file.
100 RunKati = 1 << iota
Anton Hansson0b55bdb2021-06-04 10:08:08 +0100101 // Whether to include the kati-generated ninja file in the combined ninja.
102 RunKatiNinja = 1 << iota
Anton Hansson5a7861a2021-06-04 10:09:01 +0100103 // Whether to run ninja on the combined ninja.
104 RunNinja = 1 << iota
105 // Whether to run bazel on the combined ninja.
106 RunBazel = 1 << iota
107 RunBuildTests = 1 << iota
Anton Hansson0b55bdb2021-06-04 10:08:08 +0100108 RunAll = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunNinja
109 RunAllWithBazel = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunBazel
Dan Willemsen1e704462016-08-21 15:17:17 -0700110)
111
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000112// 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 +0100113func checkProblematicFiles(ctx Context) {
114 files := []string{"Android.mk", "CleanSpec.mk"}
115 for _, file := range files {
116 if _, err := os.Stat(file); !os.IsNotExist(err) {
117 absolute := absPath(ctx, file)
118 ctx.Printf("Found %s in tree root. This file needs to be removed to build.\n", file)
119 ctx.Fatalf(" rm %s\n", absolute)
120 }
121 }
122}
123
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000124// checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
Dan Willemsendb8457c2017-05-12 16:38:17 -0700125func checkCaseSensitivity(ctx Context, config Config) {
126 outDir := config.OutDir()
127 lowerCase := filepath.Join(outDir, "casecheck.txt")
128 upperCase := filepath.Join(outDir, "CaseCheck.txt")
129 lowerData := "a"
130 upperData := "B"
131
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000132 if err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0666); err != nil { // a+rw
Dan Willemsendb8457c2017-05-12 16:38:17 -0700133 ctx.Fatalln("Failed to check case sensitivity:", err)
134 }
135
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000136 if err := ioutil.WriteFile(upperCase, []byte(upperData), 0666); err != nil { // a+rw
Dan Willemsendb8457c2017-05-12 16:38:17 -0700137 ctx.Fatalln("Failed to check case sensitivity:", err)
138 }
139
140 res, err := ioutil.ReadFile(lowerCase)
141 if err != nil {
142 ctx.Fatalln("Failed to check case sensitivity:", err)
143 }
144
145 if string(res) != lowerData {
146 ctx.Println("************************************************************")
147 ctx.Println("You are building on a case-insensitive filesystem.")
148 ctx.Println("Please move your source tree to a case-sensitive filesystem.")
149 ctx.Println("************************************************************")
150 ctx.Fatalln("Case-insensitive filesystems not supported")
151 }
152}
153
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000154// help prints a help/usage message, via the build/make/help.sh script.
155func help(ctx Context, config Config) {
Jeff Gastondf4a0812017-05-30 20:11:20 -0700156 cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700157 cmd.Sandbox = dumpvarsSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -0700158 cmd.RunAndPrintOrFatal()
Dan Willemsen02781d52017-05-12 19:28:13 -0700159}
160
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000161// checkRAM warns if there probably isn't enough RAM to complete a build.
162func checkRAM(ctx Context, config Config) {
Dan Willemsen570a2922020-05-26 23:02:29 -0700163 if totalRAM := config.TotalRAM(); totalRAM != 0 {
164 ram := float32(totalRAM) / (1024 * 1024 * 1024)
165 ctx.Verbosef("Total RAM: %.3vGB", ram)
166
167 if ram <= 16 {
168 ctx.Println("************************************************************")
169 ctx.Printf("You are building on a machine with %.3vGB of RAM\n", ram)
170 ctx.Println("")
171 ctx.Println("The minimum required amount of free memory is around 16GB,")
172 ctx.Println("and even with that, some configurations may not work.")
173 ctx.Println("")
174 ctx.Println("If you run into segfaults or other errors, try reducing your")
175 ctx.Println("-j value.")
176 ctx.Println("************************************************************")
177 } else if ram <= float32(config.Parallel()) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000178 // Want at least 1GB of RAM per job.
Dan Willemsen570a2922020-05-26 23:02:29 -0700179 ctx.Printf("Warning: high -j%d count compared to %.3vGB of RAM", config.Parallel(), ram)
180 ctx.Println("If you run into segfaults or other errors, try a lower -j value")
181 }
182 }
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000183}
184
185// Build the tree. The 'what' argument can be used to chose which components of
186// the build to run, via checking various bitmasks.
Anton Hansson5a7861a2021-06-04 10:09:01 +0100187func Build(ctx Context, config Config) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000188 ctx.Verboseln("Starting build with args:", config.Arguments())
189 ctx.Verboseln("Environment:", config.Environment().Environ())
Dan Willemsen1e704462016-08-21 15:17:17 -0700190
Colin Cross74cda722020-01-16 15:25:50 -0800191 ctx.BeginTrace(metrics.Total, "total")
192 defer ctx.EndTrace()
193
Dan Willemsen1e704462016-08-21 15:17:17 -0700194 if inList("help", config.Arguments()) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000195 help(ctx, config)
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700196 return
Dan Willemsen1e704462016-08-21 15:17:17 -0700197 }
198
Jeff Gaston3615fe82017-05-24 13:14:34 -0700199 // Make sure that no other Soong process is running with the same output directory
200 buildLock := BecomeSingletonOrFail(ctx, config)
201 defer buildLock.Unlock()
202
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000203 if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
204 clean(ctx, config)
205 return
206 }
207
208 // 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 +0100209 checkProblematicFiles(ctx)
210
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000211 checkRAM(ctx, config)
212
Dan Willemsen1e704462016-08-21 15:17:17 -0700213 SetupOutDir(ctx, config)
214
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000215 // checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
Dan Willemsendb8457c2017-05-12 16:38:17 -0700216 checkCaseSensitivity(ctx, config)
217
Jeff Gastonefc1b412017-03-29 17:29:06 -0700218 ensureEmptyDirectoriesExist(ctx, config.TempDir())
219
Dan Willemsen18490112018-05-25 16:30:04 -0700220 SetupPath(ctx, config)
221
Anton Hansson5a7861a2021-06-04 10:09:01 +0100222 what := RunAll
223 if config.UseBazel() {
224 what = RunAllWithBazel
225 }
226 if config.Checkbuild() {
227 what |= RunBuildTests
228 }
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000229 if config.SkipConfig() {
230 ctx.Verboseln("Skipping Config as requested")
Anton Hansson5a7861a2021-06-04 10:09:01 +0100231 what = what &^ RunProductConfig
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000232 }
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000233 if config.SkipKati() {
234 ctx.Verboseln("Skipping Kati as requested")
Anton Hansson5a7861a2021-06-04 10:09:01 +0100235 what = what &^ RunKati
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000236 }
Anton Hansson0b55bdb2021-06-04 10:08:08 +0100237 if config.SkipKatiNinja() {
238 ctx.Verboseln("Skipping use of Kati ninja as requested")
239 what = what &^ RunKatiNinja
240 }
Lukacs T. Berkicef87b62021-08-10 15:01:13 +0200241 if config.SkipSoong() {
242 ctx.Verboseln("Skipping use of Soong as requested")
243 what = what &^ RunSoong
244 }
245
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100246 if config.SkipNinja() {
247 ctx.Verboseln("Skipping Ninja as requested")
Anton Hansson5a7861a2021-06-04 10:09:01 +0100248 what = what &^ RunNinja
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100249 }
250
Lukacs T. Berkia1b93722021-09-02 17:23:06 +0200251 if !config.SoongBuildInvocationNeeded() {
252 // This means that the output of soong_build is not needed and thus it would
253 // run unnecessarily. In addition, if this code wasn't there invocations
254 // with only special-cased target names like "m bp2build" would result in
255 // passing Ninja the empty target list and it would then build the default
256 // targets which is not what the user asked for.
257 what = what &^ RunNinja
258 what = what &^ RunKati
259 }
260
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900261 if config.StartGoma() {
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900262 startGoma(ctx, config)
263 }
264
Ramy Medhatbbf25672019-07-17 12:30:04 +0000265 if config.StartRBE() {
Ramy Medhatbbf25672019-07-17 12:30:04 +0000266 startRBE(ctx, config)
Kousik Kumara1d8fa92022-03-18 02:50:31 -0400267 defer DumpRBEMetrics(ctx, config, filepath.Join(config.LogsDir(), "rbe_metrics.pb"))
Ramy Medhatbbf25672019-07-17 12:30:04 +0000268 }
269
Anton Hansson5a7861a2021-06-04 10:09:01 +0100270 if what&RunProductConfig != 0 {
Dan Willemsen1e704462016-08-21 15:17:17 -0700271 runMakeProductConfig(ctx, config)
272 }
273
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000274 // Everything below here depends on product config.
275
Colin Cross806fd942019-05-03 13:35:58 -0700276 if inList("installclean", config.Arguments()) ||
277 inList("install-clean", config.Arguments()) {
Rupert Shuttleworth1f304e62020-11-24 14:13:41 +0000278 installClean(ctx, config)
Dan Willemsenf052f782017-05-18 15:29:04 -0700279 ctx.Println("Deleted images and staging directories.")
280 return
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000281 }
282
283 if inList("dataclean", config.Arguments()) ||
Colin Cross806fd942019-05-03 13:35:58 -0700284 inList("data-clean", config.Arguments()) {
Rupert Shuttleworth1f304e62020-11-24 14:13:41 +0000285 dataClean(ctx, config)
Dan Willemsenf052f782017-05-18 15:29:04 -0700286 ctx.Println("Deleted data files.")
287 return
288 }
289
Anton Hansson5a7861a2021-06-04 10:09:01 +0100290 if what&RunSoong != 0 {
Dan Willemsen1e704462016-08-21 15:17:17 -0700291 runSoong(ctx, config)
292 }
293
Anton Hansson5a7861a2021-06-04 10:09:01 +0100294 if what&RunKati != 0 {
Dan Willemsen29971232018-09-26 14:58:30 -0700295 genKatiSuffix(ctx, config)
296 runKatiCleanSpec(ctx, config)
297 runKatiBuild(ctx, config)
Dan Willemsenfb1271a2018-09-26 15:00:42 -0700298 runKatiPackage(ctx, config)
Dan Willemsene0879fc2017-08-04 15:06:27 -0700299
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000300 ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
Anton Hansson0b55bdb2021-06-04 10:08:08 +0100301 } else if what&RunKatiNinja != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700302 // Load last Kati Suffix if it exists
303 if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
304 ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
305 config.SetKatiSuffix(string(katiSuffix))
306 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700307 }
308
Colin Cross37193492017-11-16 17:55:00 -0800309 // Write combined ninja file
310 createCombinedBuildNinjaFile(ctx, config)
311
Colin Cross8ba7d472020-06-25 11:27:52 -0700312 distGzipFile(ctx, config, config.CombinedNinjaFile())
313
Colin Cross37193492017-11-16 17:55:00 -0800314 if what&RunBuildTests != 0 {
315 testForDanglingRules(ctx, config)
316 }
317
Anton Hansson5a7861a2021-06-04 10:09:01 +0100318 if what&RunNinja != 0 {
319 if what&RunKati != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700320 installCleanIfNecessary(ctx, config)
321 }
Dan Willemsen02781d52017-05-12 19:28:13 -0700322
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100323 runNinjaForBuild(ctx, config)
Dan Willemsen1e704462016-08-21 15:17:17 -0700324 }
Rupert Shuttleworth680387b2020-10-25 12:31:27 +0000325
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000326 // Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
Anton Hansson5a7861a2021-06-04 10:09:01 +0100327 if what&RunBazel != 0 {
Rupert Shuttleworth680387b2020-10-25 12:31:27 +0000328 runBazel(ctx, config)
329 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700330}
Colin Cross8ba7d472020-06-25 11:27:52 -0700331
332// distGzipFile writes a compressed copy of src to the distDir if dist is enabled. Failures
333// are printed but non-fatal.
334func distGzipFile(ctx Context, config Config, src string, subDirs ...string) {
335 if !config.Dist() {
336 return
337 }
338
339 subDir := filepath.Join(subDirs...)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000340 destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
Colin Cross8ba7d472020-06-25 11:27:52 -0700341
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000342 if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
Colin Cross8ba7d472020-06-25 11:27:52 -0700343 ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
Colin Cross8ba7d472020-06-25 11:27:52 -0700344 }
345
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000346 if err := gzipFileToDir(src, destDir); err != nil {
Colin Cross8ba7d472020-06-25 11:27:52 -0700347 ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
348 }
349}
350
351// distFile writes a copy of src to the distDir if dist is enabled. Failures are printed but
352// non-fatal.
353func distFile(ctx Context, config Config, src string, subDirs ...string) {
354 if !config.Dist() {
355 return
356 }
357
358 subDir := filepath.Join(subDirs...)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000359 destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
Colin Cross8ba7d472020-06-25 11:27:52 -0700360
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000361 if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
Colin Cross8ba7d472020-06-25 11:27:52 -0700362 ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
Colin Cross8ba7d472020-06-25 11:27:52 -0700363 }
364
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000365 if _, err := copyFile(src, filepath.Join(destDir, filepath.Base(src))); err != nil {
Colin Cross8ba7d472020-06-25 11:27:52 -0700366 ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
367 }
368}