blob: 7293bbc6402c19f6026ba425c0bc3eeb543837d2 [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
26// Ensures the out directory exists, and has the proper files to prevent kati
27// from recursing into it.
28func SetupOutDir(ctx Context, config Config) {
29 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
30 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
Dan Willemsene0879fc2017-08-04 15:06:27 -070031 if !config.SkipMake() {
32 ensureEmptyFileExists(ctx, filepath.Join(config.SoongOutDir(), ".soong.in_make"))
33 }
Dan Willemsen1e704462016-08-21 15:17:17 -070034 // The ninja_build file is used by our buildbots to understand that the output
35 // can be parsed as ninja output.
36 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
Jeff Gastonb64fc1c2017-08-04 12:30:12 -070037 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
Colin Cross28f527c2019-11-26 16:19:04 -080038
39 if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
40 err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0777)
41 if err != nil {
42 ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
43 }
44 } else {
45 ctx.Fatalln("Missing BUILD_DATETIME_FILE")
46 }
Dan Willemsen1e704462016-08-21 15:17:17 -070047}
48
49var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
50builddir = {{.OutDir}}
Colin Cross8b8bec32019-11-15 13:18:43 -080051{{if .UseRemoteBuild }}pool local_pool
Dan Willemsen29971232018-09-26 14:58:30 -070052 depth = {{.Parallel}}
Colin Cross8b8bec32019-11-15 13:18:43 -080053{{end -}}
54pool highmem_pool
55 depth = {{.HighmemParallel}}
Dan Willemsen29971232018-09-26 14:58:30 -070056build _kati_always_build_: phony
Dan Willemsenfb1271a2018-09-26 15:00:42 -070057{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
58subninja {{.KatiPackageNinjaFile}}
Dan Willemsene0879fc2017-08-04 15:06:27 -070059{{end -}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070060subninja {{.SoongNinjaFile}}
Dan Willemsen1e704462016-08-21 15:17:17 -070061`))
62
63func createCombinedBuildNinjaFile(ctx Context, config Config) {
Dan Willemsene0879fc2017-08-04 15:06:27 -070064 // If we're in SkipMake mode, skip creating this file if it already exists
65 if config.SkipMake() {
66 if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
67 return
68 }
69 }
70
Dan Willemsen1e704462016-08-21 15:17:17 -070071 file, err := os.Create(config.CombinedNinjaFile())
72 if err != nil {
73 ctx.Fatalln("Failed to create combined ninja file:", err)
74 }
75 defer file.Close()
76
77 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
78 ctx.Fatalln("Failed to write combined ninja file:", err)
79 }
80}
81
82const (
83 BuildNone = iota
84 BuildProductConfig = 1 << iota
85 BuildSoong = 1 << iota
86 BuildKati = 1 << iota
87 BuildNinja = 1 << iota
Colin Cross37193492017-11-16 17:55:00 -080088 RunBuildTests = 1 << iota
Dan Willemsen1e704462016-08-21 15:17:17 -070089 BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
90)
91
Anton Hanssonecf0f102018-09-19 22:14:17 +010092func checkProblematicFiles(ctx Context) {
93 files := []string{"Android.mk", "CleanSpec.mk"}
94 for _, file := range files {
95 if _, err := os.Stat(file); !os.IsNotExist(err) {
96 absolute := absPath(ctx, file)
97 ctx.Printf("Found %s in tree root. This file needs to be removed to build.\n", file)
98 ctx.Fatalf(" rm %s\n", absolute)
99 }
100 }
101}
102
Dan Willemsendb8457c2017-05-12 16:38:17 -0700103func checkCaseSensitivity(ctx Context, config Config) {
104 outDir := config.OutDir()
105 lowerCase := filepath.Join(outDir, "casecheck.txt")
106 upperCase := filepath.Join(outDir, "CaseCheck.txt")
107 lowerData := "a"
108 upperData := "B"
109
110 err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0777)
111 if err != nil {
112 ctx.Fatalln("Failed to check case sensitivity:", err)
113 }
114
115 err = ioutil.WriteFile(upperCase, []byte(upperData), 0777)
116 if err != nil {
117 ctx.Fatalln("Failed to check case sensitivity:", err)
118 }
119
120 res, err := ioutil.ReadFile(lowerCase)
121 if err != nil {
122 ctx.Fatalln("Failed to check case sensitivity:", err)
123 }
124
125 if string(res) != lowerData {
126 ctx.Println("************************************************************")
127 ctx.Println("You are building on a case-insensitive filesystem.")
128 ctx.Println("Please move your source tree to a case-sensitive filesystem.")
129 ctx.Println("************************************************************")
130 ctx.Fatalln("Case-insensitive filesystems not supported")
131 }
132}
133
Dan Willemsenf052f782017-05-18 15:29:04 -0700134func help(ctx Context, config Config, what int) {
Jeff Gastondf4a0812017-05-30 20:11:20 -0700135 cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700136 cmd.Sandbox = dumpvarsSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -0700137 cmd.RunAndPrintOrFatal()
Dan Willemsen02781d52017-05-12 19:28:13 -0700138}
139
Dan Willemsen1e704462016-08-21 15:17:17 -0700140// Build the tree. The 'what' argument can be used to chose which components of
141// the build to run.
142func Build(ctx Context, config Config, what int) {
143 ctx.Verboseln("Starting build with args:", config.Arguments())
144 ctx.Verboseln("Environment:", config.Environment().Environ())
Dan Willemsen104d9eb2020-05-26 23:02:29 -0700145
146 if totalRAM := config.TotalRAM(); totalRAM != 0 {
147 ram := float32(totalRAM) / (1024 * 1024 * 1024)
148 ctx.Verbosef("Total RAM: %.3vGB", ram)
149
150 if ram <= 16 {
151 ctx.Println("************************************************************")
152 ctx.Printf("You are building on a machine with %.3vGB of RAM\n", ram)
153 ctx.Println("")
154 ctx.Println("The minimum required amount of free memory is around 16GB,")
155 ctx.Println("and even with that, some configurations may not work.")
156 ctx.Println("")
157 ctx.Println("If you run into segfaults or other errors, try reducing your")
158 ctx.Println("-j value.")
159 ctx.Println("************************************************************")
160 } else if ram <= float32(config.Parallel()) {
161 ctx.Printf("Warning: high -j%d count compared to %.3vGB of RAM", config.Parallel(), ram)
162 ctx.Println("If you run into segfaults or other errors, try a lower -j value")
163 }
164 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700165
Colin Cross74cda722020-01-16 15:25:50 -0800166 ctx.BeginTrace(metrics.Total, "total")
167 defer ctx.EndTrace()
168
Dan Willemsene0879fc2017-08-04 15:06:27 -0700169 if config.SkipMake() {
170 ctx.Verboseln("Skipping Make/Kati as requested")
171 what = what & (BuildSoong | BuildNinja)
172 }
173
Dan Willemsen1e704462016-08-21 15:17:17 -0700174 if inList("help", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700175 help(ctx, config, what)
Dan Willemsen1e704462016-08-21 15:17:17 -0700176 return
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700177 } else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700178 clean(ctx, config, what)
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700179 return
Dan Willemsen1e704462016-08-21 15:17:17 -0700180 }
181
Jeff Gaston3615fe82017-05-24 13:14:34 -0700182 // Make sure that no other Soong process is running with the same output directory
183 buildLock := BecomeSingletonOrFail(ctx, config)
184 defer buildLock.Unlock()
185
Anton Hanssonecf0f102018-09-19 22:14:17 +0100186 checkProblematicFiles(ctx)
187
Dan Willemsen1e704462016-08-21 15:17:17 -0700188 SetupOutDir(ctx, config)
189
Dan Willemsendb8457c2017-05-12 16:38:17 -0700190 checkCaseSensitivity(ctx, config)
191
Jeff Gastonefc1b412017-03-29 17:29:06 -0700192 ensureEmptyDirectoriesExist(ctx, config.TempDir())
193
Dan Willemsen18490112018-05-25 16:30:04 -0700194 SetupPath(ctx, config)
195
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900196 if config.StartGoma() {
197 // Ensure start Goma compiler_proxy
198 startGoma(ctx, config)
199 }
200
Ramy Medhatbbf25672019-07-17 12:30:04 +0000201 if config.StartRBE() {
202 // Ensure RBE proxy is started
203 startRBE(ctx, config)
204 }
205
Dan Willemsen1e704462016-08-21 15:17:17 -0700206 if what&BuildProductConfig != 0 {
207 // Run make for product config
208 runMakeProductConfig(ctx, config)
209 }
210
Colin Cross806fd942019-05-03 13:35:58 -0700211 if inList("installclean", config.Arguments()) ||
212 inList("install-clean", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700213 installClean(ctx, config, what)
214 ctx.Println("Deleted images and staging directories.")
215 return
Colin Cross806fd942019-05-03 13:35:58 -0700216 } else if inList("dataclean", config.Arguments()) ||
217 inList("data-clean", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700218 dataClean(ctx, config, what)
219 ctx.Println("Deleted data files.")
220 return
Alberto97ead67922018-05-05 22:01:02 +0200221 } else if inList("deviceclean", config.Arguments()) {
222 deviceClean(ctx, config, what)
Harsh Shandilyabf1b9ae2019-05-12 05:48:29 +0530223 ctx.Println(config.ProductOut(), "removed.")
Alberto97ead67922018-05-05 22:01:02 +0200224 return
Dan Willemsenf052f782017-05-18 15:29:04 -0700225 }
226
Dan Willemsen1e704462016-08-21 15:17:17 -0700227 if what&BuildSoong != 0 {
228 // Run Soong
Dan Willemsen1e704462016-08-21 15:17:17 -0700229 runSoong(ctx, config)
230 }
231
Dan Willemsen1e704462016-08-21 15:17:17 -0700232 if what&BuildKati != 0 {
233 // Run ckati
Dan Willemsen29971232018-09-26 14:58:30 -0700234 genKatiSuffix(ctx, config)
235 runKatiCleanSpec(ctx, config)
236 runKatiBuild(ctx, config)
Dan Willemsenfb1271a2018-09-26 15:00:42 -0700237 runKatiPackage(ctx, config)
Dan Willemsene0879fc2017-08-04 15:06:27 -0700238
239 ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0777)
240 } else {
241 // Load last Kati Suffix if it exists
242 if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
243 ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
244 config.SetKatiSuffix(string(katiSuffix))
245 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700246 }
247
Colin Cross37193492017-11-16 17:55:00 -0800248 // Write combined ninja file
249 createCombinedBuildNinjaFile(ctx, config)
250
251 if what&RunBuildTests != 0 {
252 testForDanglingRules(ctx, config)
253 }
254
Dan Willemsen1e704462016-08-21 15:17:17 -0700255 if what&BuildNinja != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700256 if !config.SkipMake() {
257 installCleanIfNecessary(ctx, config)
258 }
Dan Willemsen02781d52017-05-12 19:28:13 -0700259
Dan Willemsen1e704462016-08-21 15:17:17 -0700260 // Run ninja
261 runNinja(ctx, config)
262 }
263}