blob: 7dfb900ef0120d4385fb0d04c53c58922c9e4f67 [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"
22)
23
24// Ensures the out directory exists, and has the proper files to prevent kati
25// from recursing into it.
26func SetupOutDir(ctx Context, config Config) {
27 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
28 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
Dan Willemsene0879fc2017-08-04 15:06:27 -070029 if !config.SkipMake() {
30 ensureEmptyFileExists(ctx, filepath.Join(config.SoongOutDir(), ".soong.in_make"))
31 }
Dan Willemsen1e704462016-08-21 15:17:17 -070032 // The ninja_build file is used by our buildbots to understand that the output
33 // can be parsed as ninja output.
34 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
Jeff Gastonb64fc1c2017-08-04 12:30:12 -070035 ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
Colin Cross28f527c2019-11-26 16:19:04 -080036
37 if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
38 err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0777)
39 if err != nil {
40 ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
41 }
42 } else {
43 ctx.Fatalln("Missing BUILD_DATETIME_FILE")
44 }
Dan Willemsen1e704462016-08-21 15:17:17 -070045}
46
47var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
48builddir = {{.OutDir}}
Dan Willemsen29971232018-09-26 14:58:30 -070049pool local_pool
50 depth = {{.Parallel}}
51build _kati_always_build_: phony
Dan Willemsenfb1271a2018-09-26 15:00:42 -070052{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
53subninja {{.KatiPackageNinjaFile}}
Dan Willemsene0879fc2017-08-04 15:06:27 -070054{{end -}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070055subninja {{.SoongNinjaFile}}
Dan Willemsen1e704462016-08-21 15:17:17 -070056`))
57
58func createCombinedBuildNinjaFile(ctx Context, config Config) {
Dan Willemsene0879fc2017-08-04 15:06:27 -070059 // If we're in SkipMake mode, skip creating this file if it already exists
60 if config.SkipMake() {
61 if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
62 return
63 }
64 }
65
Dan Willemsen1e704462016-08-21 15:17:17 -070066 file, err := os.Create(config.CombinedNinjaFile())
67 if err != nil {
68 ctx.Fatalln("Failed to create combined ninja file:", err)
69 }
70 defer file.Close()
71
72 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
73 ctx.Fatalln("Failed to write combined ninja file:", err)
74 }
75}
76
77const (
78 BuildNone = iota
79 BuildProductConfig = 1 << iota
80 BuildSoong = 1 << iota
81 BuildKati = 1 << iota
82 BuildNinja = 1 << iota
Colin Cross37193492017-11-16 17:55:00 -080083 RunBuildTests = 1 << iota
Dan Willemsen1e704462016-08-21 15:17:17 -070084 BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
85)
86
Anton Hanssonecf0f102018-09-19 22:14:17 +010087func checkProblematicFiles(ctx Context) {
88 files := []string{"Android.mk", "CleanSpec.mk"}
89 for _, file := range files {
90 if _, err := os.Stat(file); !os.IsNotExist(err) {
91 absolute := absPath(ctx, file)
92 ctx.Printf("Found %s in tree root. This file needs to be removed to build.\n", file)
93 ctx.Fatalf(" rm %s\n", absolute)
94 }
95 }
96}
97
Dan Willemsendb8457c2017-05-12 16:38:17 -070098func checkCaseSensitivity(ctx Context, config Config) {
99 outDir := config.OutDir()
100 lowerCase := filepath.Join(outDir, "casecheck.txt")
101 upperCase := filepath.Join(outDir, "CaseCheck.txt")
102 lowerData := "a"
103 upperData := "B"
104
105 err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0777)
106 if err != nil {
107 ctx.Fatalln("Failed to check case sensitivity:", err)
108 }
109
110 err = ioutil.WriteFile(upperCase, []byte(upperData), 0777)
111 if err != nil {
112 ctx.Fatalln("Failed to check case sensitivity:", err)
113 }
114
115 res, err := ioutil.ReadFile(lowerCase)
116 if err != nil {
117 ctx.Fatalln("Failed to check case sensitivity:", err)
118 }
119
120 if string(res) != lowerData {
121 ctx.Println("************************************************************")
122 ctx.Println("You are building on a case-insensitive filesystem.")
123 ctx.Println("Please move your source tree to a case-sensitive filesystem.")
124 ctx.Println("************************************************************")
125 ctx.Fatalln("Case-insensitive filesystems not supported")
126 }
127}
128
Dan Willemsenf052f782017-05-18 15:29:04 -0700129func help(ctx Context, config Config, what int) {
Jeff Gastondf4a0812017-05-30 20:11:20 -0700130 cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700131 cmd.Sandbox = dumpvarsSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -0700132 cmd.RunAndPrintOrFatal()
Dan Willemsen02781d52017-05-12 19:28:13 -0700133}
134
Dan Willemsen1e704462016-08-21 15:17:17 -0700135// Build the tree. The 'what' argument can be used to chose which components of
136// the build to run.
137func Build(ctx Context, config Config, what int) {
138 ctx.Verboseln("Starting build with args:", config.Arguments())
139 ctx.Verboseln("Environment:", config.Environment().Environ())
140
Dan Willemsene0879fc2017-08-04 15:06:27 -0700141 if config.SkipMake() {
142 ctx.Verboseln("Skipping Make/Kati as requested")
143 what = what & (BuildSoong | BuildNinja)
144 }
145
Dan Willemsen1e704462016-08-21 15:17:17 -0700146 if inList("help", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700147 help(ctx, config, what)
Dan Willemsen1e704462016-08-21 15:17:17 -0700148 return
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700149 } else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700150 clean(ctx, config, what)
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700151 return
Dan Willemsen1e704462016-08-21 15:17:17 -0700152 }
153
Jeff Gaston3615fe82017-05-24 13:14:34 -0700154 // Make sure that no other Soong process is running with the same output directory
155 buildLock := BecomeSingletonOrFail(ctx, config)
156 defer buildLock.Unlock()
157
Anton Hanssonecf0f102018-09-19 22:14:17 +0100158 checkProblematicFiles(ctx)
159
Dan Willemsen1e704462016-08-21 15:17:17 -0700160 SetupOutDir(ctx, config)
161
Dan Willemsendb8457c2017-05-12 16:38:17 -0700162 checkCaseSensitivity(ctx, config)
163
Jeff Gastonefc1b412017-03-29 17:29:06 -0700164 ensureEmptyDirectoriesExist(ctx, config.TempDir())
165
Dan Willemsen18490112018-05-25 16:30:04 -0700166 SetupPath(ctx, config)
167
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900168 if config.StartGoma() {
169 // Ensure start Goma compiler_proxy
170 startGoma(ctx, config)
171 }
172
Ramy Medhatbbf25672019-07-17 12:30:04 +0000173 if config.StartRBE() {
174 // Ensure RBE proxy is started
175 startRBE(ctx, config)
176 }
177
Dan Willemsen1e704462016-08-21 15:17:17 -0700178 if what&BuildProductConfig != 0 {
179 // Run make for product config
180 runMakeProductConfig(ctx, config)
181 }
182
Colin Cross806fd942019-05-03 13:35:58 -0700183 if inList("installclean", config.Arguments()) ||
184 inList("install-clean", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700185 installClean(ctx, config, what)
186 ctx.Println("Deleted images and staging directories.")
187 return
Colin Cross806fd942019-05-03 13:35:58 -0700188 } else if inList("dataclean", config.Arguments()) ||
189 inList("data-clean", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700190 dataClean(ctx, config, what)
191 ctx.Println("Deleted data files.")
192 return
193 }
194
Dan Willemsen1e704462016-08-21 15:17:17 -0700195 if what&BuildSoong != 0 {
196 // Run Soong
Dan Willemsen1e704462016-08-21 15:17:17 -0700197 runSoong(ctx, config)
198 }
199
Dan Willemsen1e704462016-08-21 15:17:17 -0700200 if what&BuildKati != 0 {
201 // Run ckati
Dan Willemsen29971232018-09-26 14:58:30 -0700202 genKatiSuffix(ctx, config)
203 runKatiCleanSpec(ctx, config)
204 runKatiBuild(ctx, config)
Dan Willemsenfb1271a2018-09-26 15:00:42 -0700205 runKatiPackage(ctx, config)
Dan Willemsene0879fc2017-08-04 15:06:27 -0700206
207 ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0777)
208 } else {
209 // Load last Kati Suffix if it exists
210 if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
211 ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
212 config.SetKatiSuffix(string(katiSuffix))
213 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700214 }
215
Colin Cross37193492017-11-16 17:55:00 -0800216 // Write combined ninja file
217 createCombinedBuildNinjaFile(ctx, config)
218
219 if what&RunBuildTests != 0 {
220 testForDanglingRules(ctx, config)
221 }
222
Dan Willemsen1e704462016-08-21 15:17:17 -0700223 if what&BuildNinja != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700224 if !config.SkipMake() {
225 installCleanIfNecessary(ctx, config)
226 }
Dan Willemsen02781d52017-05-12 19:28:13 -0700227
Dan Willemsen1e704462016-08-21 15:17:17 -0700228 // Run ninja
229 runNinja(ctx, config)
230 }
231}