blob: 6a19314192b0c13d570ed546251aee13152a529b [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"))
Dan Willemsen1e704462016-08-21 15:17:17 -070036}
37
38var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
39builddir = {{.OutDir}}
Dan Willemsen29971232018-09-26 14:58:30 -070040pool local_pool
41 depth = {{.Parallel}}
42build _kati_always_build_: phony
Dan Willemsenfb1271a2018-09-26 15:00:42 -070043{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
44subninja {{.KatiPackageNinjaFile}}
Dan Willemsene0879fc2017-08-04 15:06:27 -070045{{end -}}
Dan Willemsenfb1271a2018-09-26 15:00:42 -070046subninja {{.SoongNinjaFile}}
Dan Willemsen1e704462016-08-21 15:17:17 -070047`))
48
49func createCombinedBuildNinjaFile(ctx Context, config Config) {
Dan Willemsene0879fc2017-08-04 15:06:27 -070050 // If we're in SkipMake mode, skip creating this file if it already exists
51 if config.SkipMake() {
52 if _, err := os.Stat(config.CombinedNinjaFile()); err == nil || !os.IsNotExist(err) {
53 return
54 }
55 }
56
Dan Willemsen1e704462016-08-21 15:17:17 -070057 file, err := os.Create(config.CombinedNinjaFile())
58 if err != nil {
59 ctx.Fatalln("Failed to create combined ninja file:", err)
60 }
61 defer file.Close()
62
63 if err := combinedBuildNinjaTemplate.Execute(file, config); err != nil {
64 ctx.Fatalln("Failed to write combined ninja file:", err)
65 }
66}
67
68const (
69 BuildNone = iota
70 BuildProductConfig = 1 << iota
71 BuildSoong = 1 << iota
72 BuildKati = 1 << iota
73 BuildNinja = 1 << iota
Colin Cross37193492017-11-16 17:55:00 -080074 RunBuildTests = 1 << iota
Dan Willemsen1e704462016-08-21 15:17:17 -070075 BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
76)
77
Anton Hanssonecf0f102018-09-19 22:14:17 +010078func checkProblematicFiles(ctx Context) {
79 files := []string{"Android.mk", "CleanSpec.mk"}
80 for _, file := range files {
81 if _, err := os.Stat(file); !os.IsNotExist(err) {
82 absolute := absPath(ctx, file)
83 ctx.Printf("Found %s in tree root. This file needs to be removed to build.\n", file)
84 ctx.Fatalf(" rm %s\n", absolute)
85 }
86 }
87}
88
Dan Willemsendb8457c2017-05-12 16:38:17 -070089func checkCaseSensitivity(ctx Context, config Config) {
90 outDir := config.OutDir()
91 lowerCase := filepath.Join(outDir, "casecheck.txt")
92 upperCase := filepath.Join(outDir, "CaseCheck.txt")
93 lowerData := "a"
94 upperData := "B"
95
96 err := ioutil.WriteFile(lowerCase, []byte(lowerData), 0777)
97 if err != nil {
98 ctx.Fatalln("Failed to check case sensitivity:", err)
99 }
100
101 err = ioutil.WriteFile(upperCase, []byte(upperData), 0777)
102 if err != nil {
103 ctx.Fatalln("Failed to check case sensitivity:", err)
104 }
105
106 res, err := ioutil.ReadFile(lowerCase)
107 if err != nil {
108 ctx.Fatalln("Failed to check case sensitivity:", err)
109 }
110
111 if string(res) != lowerData {
112 ctx.Println("************************************************************")
113 ctx.Println("You are building on a case-insensitive filesystem.")
114 ctx.Println("Please move your source tree to a case-sensitive filesystem.")
115 ctx.Println("************************************************************")
116 ctx.Fatalln("Case-insensitive filesystems not supported")
117 }
118}
119
Dan Willemsenf052f782017-05-18 15:29:04 -0700120func help(ctx Context, config Config, what int) {
Jeff Gastondf4a0812017-05-30 20:11:20 -0700121 cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
Dan Willemsenb2e6c2e2017-07-13 17:24:44 -0700122 cmd.Sandbox = dumpvarsSandbox
Dan Willemsenb82471a2018-05-17 16:37:09 -0700123 cmd.RunAndPrintOrFatal()
Dan Willemsen02781d52017-05-12 19:28:13 -0700124}
125
Dan Willemsen1e704462016-08-21 15:17:17 -0700126// Build the tree. The 'what' argument can be used to chose which components of
127// the build to run.
128func Build(ctx Context, config Config, what int) {
129 ctx.Verboseln("Starting build with args:", config.Arguments())
130 ctx.Verboseln("Environment:", config.Environment().Environ())
131
Dan Willemsene0879fc2017-08-04 15:06:27 -0700132 if config.SkipMake() {
133 ctx.Verboseln("Skipping Make/Kati as requested")
134 what = what & (BuildSoong | BuildNinja)
135 }
136
Dan Willemsen1e704462016-08-21 15:17:17 -0700137 if inList("help", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700138 help(ctx, config, what)
Dan Willemsen1e704462016-08-21 15:17:17 -0700139 return
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700140 } else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700141 clean(ctx, config, what)
Dan Willemsen0b73b4b2017-05-12 19:28:13 -0700142 return
Dan Willemsen1e704462016-08-21 15:17:17 -0700143 }
144
Jeff Gaston3615fe82017-05-24 13:14:34 -0700145 // Make sure that no other Soong process is running with the same output directory
146 buildLock := BecomeSingletonOrFail(ctx, config)
147 defer buildLock.Unlock()
148
Anton Hanssonecf0f102018-09-19 22:14:17 +0100149 checkProblematicFiles(ctx)
150
Dan Willemsen1e704462016-08-21 15:17:17 -0700151 SetupOutDir(ctx, config)
152
Dan Willemsendb8457c2017-05-12 16:38:17 -0700153 checkCaseSensitivity(ctx, config)
154
Jeff Gastonefc1b412017-03-29 17:29:06 -0700155 ensureEmptyDirectoriesExist(ctx, config.TempDir())
156
Dan Willemsen18490112018-05-25 16:30:04 -0700157 SetupPath(ctx, config)
158
Yoshisato Yanagisawa2cb0e5d2019-01-10 10:14:16 +0900159 if config.StartGoma() {
160 // Ensure start Goma compiler_proxy
161 startGoma(ctx, config)
162 }
163
Ramy Medhatbbf25672019-07-17 12:30:04 +0000164 if config.StartRBE() {
165 // Ensure RBE proxy is started
166 startRBE(ctx, config)
167 }
168
Dan Willemsen1e704462016-08-21 15:17:17 -0700169 if what&BuildProductConfig != 0 {
170 // Run make for product config
171 runMakeProductConfig(ctx, config)
172 }
173
Colin Cross806fd942019-05-03 13:35:58 -0700174 if inList("installclean", config.Arguments()) ||
175 inList("install-clean", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700176 installClean(ctx, config, what)
177 ctx.Println("Deleted images and staging directories.")
178 return
Colin Cross806fd942019-05-03 13:35:58 -0700179 } else if inList("dataclean", config.Arguments()) ||
180 inList("data-clean", config.Arguments()) {
Dan Willemsenf052f782017-05-18 15:29:04 -0700181 dataClean(ctx, config, what)
182 ctx.Println("Deleted data files.")
183 return
184 }
185
Dan Willemsen1e704462016-08-21 15:17:17 -0700186 if what&BuildSoong != 0 {
187 // Run Soong
Dan Willemsen1e704462016-08-21 15:17:17 -0700188 runSoong(ctx, config)
189 }
190
Dan Willemsen1e704462016-08-21 15:17:17 -0700191 if what&BuildKati != 0 {
192 // Run ckati
Dan Willemsen29971232018-09-26 14:58:30 -0700193 genKatiSuffix(ctx, config)
194 runKatiCleanSpec(ctx, config)
195 runKatiBuild(ctx, config)
Dan Willemsenfb1271a2018-09-26 15:00:42 -0700196 runKatiPackage(ctx, config)
Dan Willemsene0879fc2017-08-04 15:06:27 -0700197
198 ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0777)
199 } else {
200 // Load last Kati Suffix if it exists
201 if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil {
202 ctx.Verboseln("Loaded previous kati config:", string(katiSuffix))
203 config.SetKatiSuffix(string(katiSuffix))
204 }
Dan Willemsen1e704462016-08-21 15:17:17 -0700205 }
206
Colin Cross37193492017-11-16 17:55:00 -0800207 // Write combined ninja file
208 createCombinedBuildNinjaFile(ctx, config)
209
210 if what&RunBuildTests != 0 {
211 testForDanglingRules(ctx, config)
212 }
213
Dan Willemsen1e704462016-08-21 15:17:17 -0700214 if what&BuildNinja != 0 {
Dan Willemsene0879fc2017-08-04 15:06:27 -0700215 if !config.SkipMake() {
216 installCleanIfNecessary(ctx, config)
217 }
Dan Willemsen02781d52017-05-12 19:28:13 -0700218
Dan Willemsen1e704462016-08-21 15:17:17 -0700219 // Run ninja
220 runNinja(ctx, config)
221 }
222}