blob: 35c5213dba788106309d0944fecfd07ba55380b7 [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 Willemsenc2af0be2017-01-20 14:10:01 -080018 "log"
19 "os"
Dan Willemsen1e704462016-08-21 15:17:17 -070020 "path/filepath"
21 "runtime"
22 "strconv"
23 "strings"
24)
25
26type Config struct{ *configImpl }
27
28type configImpl struct {
29 // From the environment
30 arguments []string
31 goma bool
32 environ *Environment
33
34 // From the arguments
35 parallel int
36 keepGoing int
37 verbose bool
38
39 // From the product config
40 katiArgs []string
41 ninjaArgs []string
42 katiSuffix string
43}
44
Dan Willemsenc2af0be2017-01-20 14:10:01 -080045const srcDirFileCheck = "build/soong/root.bp"
46
Dan Willemsen1e704462016-08-21 15:17:17 -070047func NewConfig(ctx Context, args ...string) Config {
48 ret := &configImpl{
49 environ: OsEnvironment(),
50 }
51
52 ret.environ.Unset(
53 // We're already using it
54 "USE_SOONG_UI",
55
56 // We should never use GOROOT/GOPATH from the shell environment
57 "GOROOT",
58 "GOPATH",
59
60 // These should only come from Soong, not the environment.
61 "CLANG",
62 "CLANG_CXX",
63 "CCC_CC",
64 "CCC_CXX",
65
66 // Used by the goma compiler wrapper, but should only be set by
67 // gomacc
68 "GOMACC_PATH",
69 )
70
71 // Tell python not to spam the source tree with .pyc files.
72 ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
73
74 // Sane default matching ninja
75 ret.parallel = runtime.NumCPU() + 2
76 ret.keepGoing = 1
77
Dan Willemsenc2af0be2017-01-20 14:10:01 -080078 // Precondition: the current directory is the top of the source tree
79 if _, err := os.Stat(srcDirFileCheck); err != nil {
80 if os.IsNotExist(err) {
81 log.Fatalf("Current working directory must be the source tree. %q not found", srcDirFileCheck)
82 }
83 log.Fatalln("Error verifying tree state:", err)
84 }
85
Dan Willemsen1e704462016-08-21 15:17:17 -070086 for _, arg := range args {
87 arg = strings.TrimSpace(arg)
88 if arg == "--make-mode" {
89 continue
90 } else if arg == "showcommands" {
91 ret.verbose = true
92 continue
93 }
94 if arg[0] == '-' {
95 var err error
96 if arg[1] == 'j' {
97 // TODO: handle space between j and number
98 // Unnecessary if used with makeparallel
99 ret.parallel, err = strconv.Atoi(arg[2:])
100 } else if arg[1] == 'k' {
101 // TODO: handle space between k and number
102 // Unnecessary if used with makeparallel
103 ret.keepGoing, err = strconv.Atoi(arg[2:])
104 } else {
105 ctx.Fatalln("Unknown option:", arg)
106 }
107 if err != nil {
108 ctx.Fatalln("Argument error:", err, arg)
109 }
110 } else {
111 ret.arguments = append(ret.arguments, arg)
112 }
113 }
114
115 return Config{ret}
116}
117
118// Lunch configures the environment for a specific product similarly to the
119// `lunch` bash function.
120func (c *configImpl) Lunch(ctx Context, product, variant string) {
121 if variant != "eng" && variant != "userdebug" && variant != "user" {
122 ctx.Fatalf("Invalid variant %q. Must be one of 'user', 'userdebug' or 'eng'", variant)
123 }
124
125 c.environ.Set("TARGET_PRODUCT", product)
126 c.environ.Set("TARGET_BUILD_VARIANT", variant)
127 c.environ.Set("TARGET_BUILD_TYPE", "release")
128 c.environ.Unset("TARGET_BUILD_APPS")
129}
130
131// Tapas configures the environment to build one or more unbundled apps,
132// similarly to the `tapas` bash function.
133func (c *configImpl) Tapas(ctx Context, apps []string, arch, variant string) {
134 if len(apps) == 0 {
135 apps = []string{"all"}
136 }
137 if variant == "" {
138 variant = "eng"
139 }
140
141 if variant != "eng" && variant != "userdebug" && variant != "user" {
142 ctx.Fatalf("Invalid variant %q. Must be one of 'user', 'userdebug' or 'eng'", variant)
143 }
144
145 var product string
146 switch arch {
147 case "armv5":
148 product = "generic_armv5"
149 case "arm", "":
150 product = "aosp_arm"
151 case "arm64":
152 product = "aosm_arm64"
153 case "mips":
154 product = "aosp_mips"
155 case "mips64":
156 product = "aosp_mips64"
157 case "x86":
158 product = "aosp_x86"
159 case "x86_64":
160 product = "aosp_x86_64"
161 default:
162 ctx.Fatalf("Invalid architecture: %q", arch)
163 }
164
165 c.environ.Set("TARGET_PRODUCT", product)
166 c.environ.Set("TARGET_BUILD_VARIANT", variant)
167 c.environ.Set("TARGET_BUILD_TYPE", "release")
168 c.environ.Set("TARGET_BUILD_APPS", strings.Join(apps, " "))
169}
170
171func (c *configImpl) Environment() *Environment {
172 return c.environ
173}
174
175func (c *configImpl) Arguments() []string {
176 return c.arguments
177}
178
179func (c *configImpl) OutDir() string {
180 if outDir, ok := c.environ.Get("OUT_DIR"); ok {
181 return outDir
182 }
183 return "out"
184}
185
186func (c *configImpl) NinjaArgs() []string {
187 return c.ninjaArgs
188}
189
190func (c *configImpl) SoongOutDir() string {
191 return filepath.Join(c.OutDir(), "soong")
192}
193
194func (c *configImpl) KatiSuffix() string {
195 if c.katiSuffix != "" {
196 return c.katiSuffix
197 }
198 panic("SetKatiSuffix has not been called")
199}
200
201func (c *configImpl) IsVerbose() bool {
202 return c.verbose
203}
204
205func (c *configImpl) TargetProduct() string {
206 if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
207 return v
208 }
209 panic("TARGET_PRODUCT is not defined")
210}
211
212func (c *configImpl) KatiArgs() []string {
213 return c.katiArgs
214}
215
216func (c *configImpl) Parallel() int {
217 return c.parallel
218}
219
220func (c *configImpl) UseGoma() bool {
221 if v, ok := c.environ.Get("USE_GOMA"); ok {
222 v = strings.TrimSpace(v)
223 if v != "" && v != "false" {
224 return true
225 }
226 }
227 return false
228}
229
230// RemoteParallel controls how many remote jobs (i.e., commands which contain
231// gomacc) are run in parallel. Note the paralleism of all other jobs is
232// still limited by Parallel()
233func (c *configImpl) RemoteParallel() int {
234 if v, ok := c.environ.Get("NINJA_REMOTE_NUM_JOBS"); ok {
235 if i, err := strconv.Atoi(v); err == nil {
236 return i
237 }
238 }
239 return 500
240}
241
242func (c *configImpl) SetKatiArgs(args []string) {
243 c.katiArgs = args
244}
245
246func (c *configImpl) SetNinjaArgs(args []string) {
247 c.ninjaArgs = args
248}
249
250func (c *configImpl) SetKatiSuffix(suffix string) {
251 c.katiSuffix = suffix
252}
253
254func (c *configImpl) KatiEnvFile() string {
255 return filepath.Join(c.OutDir(), "env"+c.KatiSuffix()+".sh")
256}
257
258func (c *configImpl) KatiNinjaFile() string {
259 return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+".ninja")
260}
261
262func (c *configImpl) SoongNinjaFile() string {
263 return filepath.Join(c.SoongOutDir(), "build.ninja")
264}
265
266func (c *configImpl) CombinedNinjaFile() string {
267 return filepath.Join(c.OutDir(), "combined"+c.KatiSuffix()+".ninja")
268}
269
270func (c *configImpl) SoongAndroidMk() string {
271 return filepath.Join(c.SoongOutDir(), "Android-"+c.TargetProduct()+".mk")
272}
273
274func (c *configImpl) SoongMakeVarsMk() string {
275 return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
276}
277
278func (c *configImpl) HostPrebuiltTag() string {
279 if runtime.GOOS == "linux" {
280 return "linux-x86"
281 } else if runtime.GOOS == "darwin" {
282 return "darwin-x86"
283 } else {
284 panic("Unsupported OS")
285 }
286}