blob: 80367f5475fc51d6744a564f52f1be113706e2b5 [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 Hansson5e5c48b2020-11-27 12:35:20 +000031 if !config.SkipKati() {
Jingwen Chencda22c92020-11-23 00:22:30 -050032 // Run soong_build with Kati for a hybrid build, e.g. running the
33 // AndroidMk singleton and postinstall commands. Communicate this to
34 // soong_build by writing an empty .soong.kati_enabled marker file in the
35 // soong_build output directory for the soong_build primary builder to
36 // know if the user wants to run Kati after.
37 //
38 // This does not preclude running Kati for *product configuration purposes*.
39 ensureEmptyFileExists(ctx, filepath.Join(config.SoongOutDir(), ".soong.kati_enabled"))
Dan Willemsene0879fc2017-08-04 15:06:27 -070040 }
Dan Willemsen1e704462016-08-21 15:17:17 -070041 // The ninja_build file is used by our buildbots to understand that the output
42 // can be parsed as ninja output.
43 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
Jeff Gastonb64fc1c2017-08-04 12:30:12 -070044 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
Colin Cross28f527c2019-11-26 16:19:04 -080045
46 if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +000047 err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw
Colin Cross28f527c2019-11-26 16:19:04 -080048 if err != nil {
49 ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
50 }
51 } else {
52 ctx.Fatalln("Missing BUILD_DATETIME_FILE")
53 }
Dan Willemsen1e704462016-08-21 15:17:17 -070054}
55
56var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
57builddir = {{.OutDir}}
Colin Cross8b8bec32019-11-15 13:18:43 -080058{{if .UseRemoteBuild }}pool local_pool
Dan Willemsen29971232018-09-26 14:58:30 -070059 depth = {{.Parallel}}
Colin Cross8b8bec32019-11-15 13:18:43 -080060{{end -}}
61pool highmem_pool
62 depth = {{.HighmemParallel}}
Anton Hansson546de4a2021-06-04 10:08:08 +010063{{if and (not .SkipKatiNinja) .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070064subninja {{.KatiPackageNinjaFile}}
Dan Willemsene0879fc2017-08-04 15:06:27 -070065{{end -}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070066subninja {{.SoongNinjaFile}}
Dan Willemsen1e704462016-08-21 15:17:17 -070067`))
68
69func createCombinedBuildNinjaFile(ctx Context, config Config) {
Anton Hansson546de4a2021-06-04 10:08:08 +010070 // If we're in SkipKati mode but want to run kati ninja, skip creating this file if it already exists
71 if config.SkipKati() && !config.SkipKatiNinja() {
Dan Willemsene0879fc2017-08-04 15:06:27 -070072 if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
73 return
74 }
75 }
76
Dan Willemsen1e704462016-08-21 15:17:17 -070077 file, err := os.Create(config.CombinedNinjaFile())
78 if err != nil {
79 ctx.Fatalln("Failed to create combined ninja file:", err)
80 }
81 defer file.Close()
82
83 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
84 ctx.Fatalln("Failed to write combined ninja file:", err)
85 }
86}
87
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +000088// 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 -070089const (
Anton Hanssond274ea92021-06-04 10:09:01 +010090 _ = iota
91 // Whether to run the kati config step.
92 RunProductConfig = 1 << iota
93 // Whether to run soong to generate a ninja file.
94 RunSoong = 1 << iota
95 // Whether to run kati to generate a ninja file.
96 RunKati = 1 << iota
Anton Hansson546de4a2021-06-04 10:08:08 +010097 // Whether to include the kati-generated ninja file in the combined ninja.
98 RunKatiNinja = 1 << iota
Anton Hanssond274ea92021-06-04 10:09:01 +010099 // Whether to run ninja on the combined ninja.
100 RunNinja = 1 << iota
101 // Whether to run bazel on the combined ninja.
102 RunBazel = 1 << iota
103 RunBuildTests = 1 << iota
Anton Hansson546de4a2021-06-04 10:08:08 +0100104 RunAll = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunNinja
105 RunAllWithBazel = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunBazel
Dan Willemsen1e704462016-08-21 15:17:17 -0700106)
107
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000108// 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 +0100109func checkProblematicFiles(ctx Context) {
110 files := []string{"Android.mk", "CleanSpec.mk"}
111 for _, file := range files {
112 if _, err := os.Stat(file); !os.IsNotExist(err) {
113 absolute := absPath(ctx, file)
114 ctx.Printf("Found %s in tree root. This file needs to be removed to build.\n", file)
115 ctx.Fatalf(" rm %s\n", absolute)
116 }
117 }
118}
119
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000120// checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
Dan Willemsendb8457c2017-05-12 16:38:17 -0700121func checkCaseSensitivity(ctx Context, config Config) {
122 outDir := config.OutDir()
123 lowerCase := filepath.Join(outDir, "casecheck.txt")
124 upperCase := filepath.Join(outDir, "CaseCheck.txt")
125 lowerData := "a"
126 upperData := "B"
127
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000128 if err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0666); err != nil { // a+rw
Dan Willemsendb8457c2017-05-12 16:38:17 -0700129 ctx.Fatalln("Failed to check case sensitivity:", err)
130 }
131
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000132 if err := ioutil.WriteFile(upperCase, []byte(upperData), 0666); err != nil { // a+rw
Dan Willemsendb8457c2017-05-12 16:38:17 -0700133 ctx.Fatalln("Failed to check case sensitivity:", err)
134 }
135
136 res, err := ioutil.ReadFile(lowerCase)
137 if err != nil {
138 ctx.Fatalln("Failed to check case sensitivity:", err)
139 }
140
141 if string(res) != lowerData {
142 ctx.Println("************************************************************")
143 ctx.Println("You are building on a case-insensitive filesystem.")
144 ctx.Println("Please move your source tree to a case-sensitive filesystem.")
145 ctx.Println("************************************************************")
146 ctx.Fatalln("Case-insensitive filesystems not supported")
147 }
148}
149
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000150// help prints a help/usage message, via the build/make/help.sh script.
151func help(ctx Context, config Config) {
Jeff Gastondf4a0812017-05-30 20:11:20 -0700152 cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700153 cmd.Sandbox = dumpvarsSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -0700154 cmd.RunAndPrintOrFatal()
Dan Willemsen02781d52017-05-12 19:28:13 -0700155}
156
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000157// checkRAM warns if there probably isn't enough RAM to complete a build.
158func checkRAM(ctx Context, config Config) {
Dan Willemsen570a2922020-05-26 23:02:29 -0700159 if totalRAM := config.TotalRAM(); totalRAM != 0 {
160 ram := float32(totalRAM) / (1024 * 1024 * 1024)
161 ctx.Verbosef("Total RAM: %.3vGB", ram)
162
163 if ram <= 16 {
164 ctx.Println("************************************************************")
165 ctx.Printf("You are building on a machine with %.3vGB of RAM\n", ram)
166 ctx.Println("")
167 ctx.Println("The minimum required amount of free memory is around 16GB,")
168 ctx.Println("and even with that, some configurations may not work.")
169 ctx.Println("")
170 ctx.Println("If you run into segfaults or other errors, try reducing your")
171 ctx.Println("-j value.")
172 ctx.Println("************************************************************")
173 } else if ram <= float32(config.Parallel()) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000174 // Want at least 1GB of RAM per job.
Dan Willemsen570a2922020-05-26 23:02:29 -0700175 ctx.Printf("Warning: high -j%d count compared to %.3vGB of RAM", config.Parallel(), ram)
176 ctx.Println("If you run into segfaults or other errors, try a lower -j value")
177 }
178 }
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000179}
180
181// Build the tree. The 'what' argument can be used to chose which components of
182// the build to run, via checking various bitmasks.
Anton Hanssond274ea92021-06-04 10:09:01 +0100183func Build(ctx Context, config Config) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000184 ctx.Verboseln("Starting build with args:", config.Arguments())
185 ctx.Verboseln("Environment:", config.Environment().Environ())
Dan Willemsen1e704462016-08-21 15:17:17 -0700186
Colin Cross74cda722020-01-16 15:25:50 -0800187 ctx.BeginTrace(metrics.Total, "total")
188 defer ctx.EndTrace()
189
Dan Willemsen1e704462016-08-21 15:17:17 -0700190 if inList("help", config.Arguments()) {
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000191 help(ctx, config)
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700192 return
Dan Willemsen1e704462016-08-21 15:17:17 -0700193 }
194
Jeff Gaston3615fe82017-05-24 13:14:34 -0700195 // Make sure that no other Soong process is running with the same output directory
196 buildLock := BecomeSingletonOrFail(ctx, config)
197 defer buildLock.Unlock()
198
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000199 if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
200 clean(ctx, config)
201 return
202 }
203
204 // 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 +0100205 checkProblematicFiles(ctx)
206
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000207 checkRAM(ctx, config)
208
Dan Willemsen1e704462016-08-21 15:17:17 -0700209 SetupOutDir(ctx, config)
210
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000211 // checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
Dan Willemsendb8457c2017-05-12 16:38:17 -0700212 checkCaseSensitivity(ctx, config)
213
Jeff Gastonefc1b412017-03-29 17:29:06 -0700214 ensureEmptyDirectoriesExist(ctx, config.TempDir())
215
Dan Willemsen18490112018-05-25 16:30:04 -0700216 SetupPath(ctx, config)
217
Anton Hanssond274ea92021-06-04 10:09:01 +0100218 what := RunAll
219 if config.UseBazel() {
220 what = RunAllWithBazel
221 }
222 if config.Checkbuild() {
223 what |= RunBuildTests
224 }
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000225 if config.SkipConfig() {
226 ctx.Verboseln("Skipping Config as requested")
Anton Hanssond274ea92021-06-04 10:09:01 +0100227 what = what &^ RunProductConfig
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000228 }
Anton Hansson5e5c48b2020-11-27 12:35:20 +0000229 if config.SkipKati() {
230 ctx.Verboseln("Skipping Kati as requested")
Anton Hanssond274ea92021-06-04 10:09:01 +0100231 what = what &^ RunKati
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000232 }
Anton Hansson546de4a2021-06-04 10:08:08 +0100233 if config.SkipKatiNinja() {
234 ctx.Verboseln("Skipping use of Kati ninja as requested")
235 what = what &^ RunKatiNinja
236 }
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100237 if config.SkipNinja() {
238 ctx.Verboseln("Skipping Ninja as requested")
Anton Hanssond274ea92021-06-04 10:09:01 +0100239 what = what &^ RunNinja
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100240 }
241
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900242 if config.StartGoma() {
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900243 startGoma(ctx, config)
244 }
245
Ramy Medhatbbf25672019-07-17 12:30:04 +0000246 if config.StartRBE() {
Ramy Medhatbbf25672019-07-17 12:30:04 +0000247 startRBE(ctx, config)
248 }
249
Anton Hanssond274ea92021-06-04 10:09:01 +0100250 if what&RunProductConfig != 0 {
Dan Willemsen1e704462016-08-21 15:17:17 -0700251 runMakeProductConfig(ctx, config)
252 }
253
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000254 // Everything below here depends on product config.
255
Colin Cross806fd942019-05-03 13:35:58 -0700256 if inList("installclean", config.Arguments()) ||
257 inList("install-clean", config.Arguments()) {
Rupert Shuttleworth1f304e62020-11-24 14:13:41 +0000258 installClean(ctx, config)
Dan Willemsenf052f782017-05-18 15:29:04 -0700259 ctx.Println("Deleted images and staging directories.")
260 return
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000261 }
262
263 if inList("dataclean", config.Arguments()) ||
Colin Cross806fd942019-05-03 13:35:58 -0700264 inList("data-clean", config.Arguments()) {
Rupert Shuttleworth1f304e62020-11-24 14:13:41 +0000265 dataClean(ctx, config)
Dan Willemsenf052f782017-05-18 15:29:04 -0700266 ctx.Println("Deleted data files.")
267 return
Alberto97e3a44232018-05-05 22:01:02 +0200268 } else if inList("deviceclean", config.Arguments()) {
269 deviceClean(ctx, config, what)
Harsh Shandilya6a2a5132019-05-12 05:48:29 +0530270 ctx.Println(config.ProductOut(), "removed.")
Alberto97e3a44232018-05-05 22:01:02 +0200271 return
Dan Willemsenf052f782017-05-18 15:29:04 -0700272 }
273
Anton Hanssond274ea92021-06-04 10:09:01 +0100274 if what&RunSoong != 0 {
Dan Willemsen1e704462016-08-21 15:17:17 -0700275 runSoong(ctx, config)
Jingwen Cheneb76c432021-01-28 08:22:12 -0500276
Chris Parsonsec1a3dc2021-04-20 15:32:07 -0400277 if config.bazelBuildMode() == generateBuildFiles {
278 // Return early, if we're using Soong as solely the generator of BUILD files.
Jingwen Cheneb76c432021-01-28 08:22:12 -0500279 return
280 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700281 }
282
Anton Hanssond274ea92021-06-04 10:09:01 +0100283 if what&RunKati != 0 {
Dan Willemsen29971232018-09-26 14:58:30 -0700284 genKatiSuffix(ctx, config)
285 runKatiCleanSpec(ctx, config)
286 runKatiBuild(ctx, config)
Dan Willemsenfb1271a2018-09-26 15:00:42 -0700287 runKatiPackage(ctx, config)
Dan Willemsene0879fc2017-08-04 15:06:27 -0700288
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000289 ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw
Anton Hansson546de4a2021-06-04 10:08:08 +0100290 } else if what&RunKatiNinja != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700291 // Load last Kati Suffix if it exists
292 if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
293 ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
294 config.SetKatiSuffix(string(katiSuffix))
295 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700296 }
297
Colin Cross37193492017-11-16 17:55:00 -0800298 // Write combined ninja file
299 createCombinedBuildNinjaFile(ctx, config)
300
Colin Cross8ba7d472020-06-25 11:27:52 -0700301 distGzipFile(ctx, config, config.CombinedNinjaFile())
302
Colin Cross37193492017-11-16 17:55:00 -0800303 if what&RunBuildTests != 0 {
304 testForDanglingRules(ctx, config)
305 }
306
Anton Hanssond274ea92021-06-04 10:09:01 +0100307 if what&RunNinja != 0 {
308 if what&RunKati != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700309 installCleanIfNecessary(ctx, config)
310 }
Dan Willemsen02781d52017-05-12 19:28:13 -0700311
Lukacs T. Berkid1e3f1f2021-03-16 08:55:23 +0100312 runNinjaForBuild(ctx, config)
Dan Willemsen1e704462016-08-21 15:17:17 -0700313 }
Rupert Shuttleworth680387b2020-10-25 12:31:27 +0000314
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000315 // Currently, using Bazel requires Kati and Soong to run first, so check whether to run Bazel last.
Anton Hanssond274ea92021-06-04 10:09:01 +0100316 if what&RunBazel != 0 {
Rupert Shuttleworth680387b2020-10-25 12:31:27 +0000317 runBazel(ctx, config)
318 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700319}
Colin Cross8ba7d472020-06-25 11:27:52 -0700320
321// distGzipFile writes a compressed copy of src to the distDir if dist is enabled. Failures
322// are printed but non-fatal.
323func distGzipFile(ctx Context, config Config, src string, subDirs ...string) {
324 if !config.Dist() {
325 return
326 }
327
328 subDir := filepath.Join(subDirs...)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000329 destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
Colin Cross8ba7d472020-06-25 11:27:52 -0700330
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000331 if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
Colin Cross8ba7d472020-06-25 11:27:52 -0700332 ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
Colin Cross8ba7d472020-06-25 11:27:52 -0700333 }
334
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000335 if err := gzipFileToDir(src, destDir); err != nil {
Colin Cross8ba7d472020-06-25 11:27:52 -0700336 ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
337 }
338}
339
340// distFile writes a copy of src to the distDir if dist is enabled. Failures are printed but
341// non-fatal.
342func distFile(ctx Context, config Config, src string, subDirs ...string) {
343 if !config.Dist() {
344 return
345 }
346
347 subDir := filepath.Join(subDirs...)
Rupert Shuttleworth3c9f5ac2020-12-10 11:32:38 +0000348 destDir := filepath.Join(config.RealDistDir(), "soong_ui", subDir)
Colin Cross8ba7d472020-06-25 11:27:52 -0700349
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000350 if err := os.MkdirAll(destDir, 0777); err != nil { // a+rwx
Colin Cross8ba7d472020-06-25 11:27:52 -0700351 ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
Colin Cross8ba7d472020-06-25 11:27:52 -0700352 }
353
Rupert Shuttlewortheeb5caa2020-11-25 07:13:54 +0000354 if _, err := copyFile(src, filepath.Join(destDir, filepath.Base(src))); err != nil {
Colin Cross8ba7d472020-06-25 11:27:52 -0700355 ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
356 }
357}