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