• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 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 android
16
17import (
18	"encoding/json"
19	"fmt"
20	"io/ioutil"
21	"os"
22	"path/filepath"
23	"runtime"
24	"strconv"
25	"strings"
26	"sync"
27
28	"github.com/google/blueprint/proptools"
29)
30
31var Bool = proptools.Bool
32var String = proptools.String
33
34// The configuration file name
35const configFileName = "soong.config"
36const productVariablesFileName = "soong.variables"
37
38// A FileConfigurableOptions contains options which can be configured by the
39// config file. These will be included in the config struct.
40type FileConfigurableOptions struct {
41	Mega_device *bool `json:",omitempty"`
42	Ndk_abis    *bool `json:",omitempty"`
43	Host_bionic *bool `json:",omitempty"`
44}
45
46func (f *FileConfigurableOptions) SetDefaultConfig() {
47	*f = FileConfigurableOptions{}
48}
49
50// A Config object represents the entire build configuration for Android.
51type Config struct {
52	*config
53}
54
55func (c Config) BuildDir() string {
56	return c.buildDir
57}
58
59// A DeviceConfig object represents the configuration for a particular device being built.  For
60// now there will only be one of these, but in the future there may be multiple devices being
61// built
62type DeviceConfig struct {
63	*deviceConfig
64}
65
66type config struct {
67	FileConfigurableOptions
68	ProductVariables productVariables
69
70	ConfigFileName           string
71	ProductVariablesFileName string
72
73	Targets        map[OsClass][]Target
74	BuildOsVariant string
75
76	deviceConfig *deviceConfig
77
78	srcDir   string // the path of the root source directory
79	buildDir string // the path of the build output directory
80
81	envLock   sync.Mutex
82	envDeps   map[string]string
83	envFrozen bool
84
85	inMake bool
86
87	captureBuild bool // true for tests, saves build parameters for each module
88
89	OncePer
90}
91
92type deviceConfig struct {
93	config *config
94	OncePer
95}
96
97type jsonConfigurable interface {
98	SetDefaultConfig()
99}
100
101func loadConfig(config *config) error {
102	err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName)
103	if err != nil {
104		return err
105	}
106
107	return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
108}
109
110// loads configuration options from a JSON file in the cwd.
111func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
112	// Try to open the file
113	configFileReader, err := os.Open(filename)
114	defer configFileReader.Close()
115	if os.IsNotExist(err) {
116		// Need to create a file, so that blueprint & ninja don't get in
117		// a dependency tracking loop.
118		// Make a file-configurable-options with defaults, write it out using
119		// a json writer.
120		configurable.SetDefaultConfig()
121		err = saveToConfigFile(configurable, filename)
122		if err != nil {
123			return err
124		}
125	} else {
126		// Make a decoder for it
127		jsonDecoder := json.NewDecoder(configFileReader)
128		err = jsonDecoder.Decode(configurable)
129		if err != nil {
130			return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename)
131		}
132	}
133
134	// No error
135	return nil
136}
137
138// atomically writes the config file in case two copies of soong_build are running simultaneously
139// (for example, docs generation and ninja manifest generation)
140func saveToConfigFile(config jsonConfigurable, filename string) error {
141	data, err := json.MarshalIndent(&config, "", "    ")
142	if err != nil {
143		return fmt.Errorf("cannot marshal config data: %s", err.Error())
144	}
145
146	f, err := ioutil.TempFile(filepath.Dir(filename), "config")
147	if err != nil {
148		return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error())
149	}
150	defer os.Remove(f.Name())
151	defer f.Close()
152
153	_, err = f.Write(data)
154	if err != nil {
155		return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
156	}
157
158	_, err = f.WriteString("\n")
159	if err != nil {
160		return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
161	}
162
163	f.Close()
164	os.Rename(f.Name(), filename)
165
166	return nil
167}
168
169// TestConfig returns a Config object suitable for using for tests
170func TestConfig(buildDir string) Config {
171	config := &config{
172		ProductVariables: productVariables{
173			DeviceName: stringPtr("test_device"),
174		},
175
176		buildDir:     buildDir,
177		captureBuild: true,
178	}
179	config.deviceConfig = &deviceConfig{
180		config: config,
181	}
182
183	return Config{config}
184}
185
186// New creates a new Config object.  The srcDir argument specifies the path to
187// the root source directory. It also loads the config file, if found.
188func NewConfig(srcDir, buildDir string) (Config, error) {
189	// Make a config with default options
190	config := &config{
191		ConfigFileName:           filepath.Join(buildDir, configFileName),
192		ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
193
194		srcDir:   srcDir,
195		buildDir: buildDir,
196	}
197
198	config.deviceConfig = &deviceConfig{
199		config: config,
200	}
201
202	// Sanity check the build and source directories. This won't catch strange
203	// configurations with symlinks, but at least checks the obvious cases.
204	absBuildDir, err := filepath.Abs(buildDir)
205	if err != nil {
206		return Config{}, err
207	}
208
209	absSrcDir, err := filepath.Abs(srcDir)
210	if err != nil {
211		return Config{}, err
212	}
213
214	if strings.HasPrefix(absSrcDir, absBuildDir) {
215		return Config{}, fmt.Errorf("Build dir must not contain source directory")
216	}
217
218	// Load any configurable options from the configuration file
219	err = loadConfig(config)
220	if err != nil {
221		return Config{}, err
222	}
223
224	inMakeFile := filepath.Join(buildDir, ".soong.in_make")
225	if _, err := os.Stat(inMakeFile); err == nil {
226		config.inMake = true
227	}
228
229	targets, err := decodeTargetProductVariables(config)
230	if err != nil {
231		return Config{}, err
232	}
233
234	var archConfig []archConfig
235	if Bool(config.Mega_device) {
236		archConfig = getMegaDeviceConfig()
237	} else if Bool(config.Ndk_abis) {
238		archConfig = getNdkAbisConfig()
239	}
240
241	if archConfig != nil {
242		deviceTargets, err := decodeArchSettings(archConfig)
243		if err != nil {
244			return Config{}, err
245		}
246		targets[Device] = deviceTargets
247	}
248
249	config.Targets = targets
250	config.BuildOsVariant = targets[Host][0].String()
251
252	return Config{config}, nil
253}
254
255func (c *config) RemoveAbandonedFiles() bool {
256	return false
257}
258
259func (c *config) BlueprintToolLocation() string {
260	return filepath.Join(c.buildDir, "host", c.PrebuiltOS(), "bin")
261}
262
263// HostSystemTool looks for non-hermetic tools from the system we're running on.
264// Generally shouldn't be used, but useful to find the XCode SDK, etc.
265func (c *config) HostSystemTool(name string) string {
266	for _, dir := range filepath.SplitList(c.Getenv("PATH")) {
267		path := filepath.Join(dir, name)
268		if s, err := os.Stat(path); err != nil {
269			continue
270		} else if m := s.Mode(); !s.IsDir() && m&0111 != 0 {
271			return path
272		}
273	}
274	return name
275}
276
277// PrebuiltOS returns the name of the host OS used in prebuilts directories
278func (c *config) PrebuiltOS() string {
279	switch runtime.GOOS {
280	case "linux":
281		return "linux-x86"
282	case "darwin":
283		return "darwin-x86"
284	default:
285		panic("Unknown GOOS")
286	}
287}
288
289// GoRoot returns the path to the root directory of the Go toolchain.
290func (c *config) GoRoot() string {
291	return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
292}
293
294func (c *config) CpPreserveSymlinksFlags() string {
295	switch runtime.GOOS {
296	case "darwin":
297		return "-R"
298	case "linux":
299		return "-d"
300	default:
301		return ""
302	}
303}
304
305func (c *config) Getenv(key string) string {
306	var val string
307	var exists bool
308	c.envLock.Lock()
309	defer c.envLock.Unlock()
310	if c.envDeps == nil {
311		c.envDeps = make(map[string]string)
312	}
313	if val, exists = c.envDeps[key]; !exists {
314		if c.envFrozen {
315			panic("Cannot access new environment variables after envdeps are frozen")
316		}
317		val, _ = originalEnv[key]
318		c.envDeps[key] = val
319	}
320	return val
321}
322
323func (c *config) GetenvWithDefault(key string, defaultValue string) string {
324	ret := c.Getenv(key)
325	if ret == "" {
326		return defaultValue
327	}
328	return ret
329}
330
331func (c *config) IsEnvTrue(key string) bool {
332	value := c.Getenv(key)
333	return value == "1" || value == "y" || value == "yes" || value == "on" || value == "true"
334}
335
336func (c *config) IsEnvFalse(key string) bool {
337	value := c.Getenv(key)
338	return value == "0" || value == "n" || value == "no" || value == "off" || value == "false"
339}
340
341func (c *config) EnvDeps() map[string]string {
342	c.envLock.Lock()
343	defer c.envLock.Unlock()
344	c.envFrozen = true
345	return c.envDeps
346}
347
348func (c *config) EmbeddedInMake() bool {
349	return c.inMake
350}
351
352// DeviceName returns the name of the current device target
353// TODO: take an AndroidModuleContext to select the device name for multi-device builds
354func (c *config) DeviceName() string {
355	return *c.ProductVariables.DeviceName
356}
357
358func (c *config) DeviceUsesClang() bool {
359	if c.ProductVariables.DeviceUsesClang != nil {
360		return *c.ProductVariables.DeviceUsesClang
361	}
362	return true
363}
364
365func (c *config) ResourceOverlays() []SourcePath {
366	return nil
367}
368
369func (c *config) PlatformVersion() string {
370	return "M"
371}
372
373func (c *config) PlatformSdkVersionInt() int {
374	return *c.ProductVariables.Platform_sdk_version
375}
376
377func (c *config) PlatformSdkVersion() string {
378	return strconv.Itoa(c.PlatformSdkVersionInt())
379}
380
381func (c *config) PlatformVersionAllCodenames() []string {
382	return c.ProductVariables.Platform_version_all_codenames
383}
384
385func (c *config) BuildNumber() string {
386	return "000000"
387}
388
389func (c *config) ProductAaptConfig() []string {
390	return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
391}
392
393func (c *config) ProductAaptPreferredConfig() string {
394	return "xhdpi"
395}
396
397func (c *config) ProductAaptCharacteristics() string {
398	return "nosdcard"
399}
400
401func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
402	return PathForSource(ctx, "build/target/product/security")
403}
404
405func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
406	return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
407}
408
409func (c *config) AllowMissingDependencies() bool {
410	return Bool(c.ProductVariables.Allow_missing_dependencies)
411}
412
413func (c *config) DevicePrefer32BitExecutables() bool {
414	return Bool(c.ProductVariables.DevicePrefer32BitExecutables)
415}
416
417func (c *config) SkipDeviceInstall() bool {
418	return c.EmbeddedInMake()
419}
420
421func (c *config) SkipMegaDeviceInstall(path string) bool {
422	return Bool(c.Mega_device) &&
423		strings.HasPrefix(path, filepath.Join(c.buildDir, "target", "product"))
424}
425
426func (c *config) SanitizeHost() []string {
427	return append([]string(nil), c.ProductVariables.SanitizeHost...)
428}
429
430func (c *config) SanitizeDevice() []string {
431	return append([]string(nil), c.ProductVariables.SanitizeDevice...)
432}
433
434func (c *config) SanitizeDeviceDiag() []string {
435	return append([]string(nil), c.ProductVariables.SanitizeDeviceDiag...)
436}
437
438func (c *config) SanitizeDeviceArch() []string {
439	return append([]string(nil), c.ProductVariables.SanitizeDeviceArch...)
440}
441
442func (c *config) EnableCFI() bool {
443	if c.ProductVariables.EnableCFI == nil {
444		return true
445	} else {
446		return *c.ProductVariables.EnableCFI
447	}
448}
449
450func (c *config) Android64() bool {
451	for _, t := range c.Targets[Device] {
452		if t.Arch.ArchType.Multilib == "lib64" {
453			return true
454		}
455	}
456
457	return false
458}
459
460func (c *config) UseGoma() bool {
461	return Bool(c.ProductVariables.UseGoma)
462}
463
464func (c *config) ClangTidy() bool {
465	return Bool(c.ProductVariables.ClangTidy)
466}
467
468func (c *config) TidyChecks() string {
469	if c.ProductVariables.TidyChecks == nil {
470		return ""
471	}
472	return *c.ProductVariables.TidyChecks
473}
474
475func (c *config) LibartImgHostBaseAddress() string {
476	return "0x60000000"
477}
478
479func (c *config) LibartImgDeviceBaseAddress() string {
480	archType := Common
481	if len(c.Targets[Device]) > 0 {
482		archType = c.Targets[Device][0].Arch.ArchType
483	}
484	switch archType {
485	default:
486		return "0x70000000"
487	case Mips, Mips64:
488		return "0x5C000000"
489	}
490}
491
492func (c *config) ArtUseReadBarrier() bool {
493	return Bool(c.ProductVariables.ArtUseReadBarrier)
494}
495
496func (c *deviceConfig) Arches() []Arch {
497	var arches []Arch
498	for _, target := range c.config.Targets[Device] {
499		arches = append(arches, target.Arch)
500	}
501	return arches
502}
503
504func (c *deviceConfig) VendorPath() string {
505	if c.config.ProductVariables.VendorPath != nil {
506		return *c.config.ProductVariables.VendorPath
507	}
508	return "vendor"
509}
510
511func (c *deviceConfig) CompileVndk() bool {
512	if c.config.ProductVariables.DeviceVndkVersion == nil {
513		return false
514	}
515	return *c.config.ProductVariables.DeviceVndkVersion == "current"
516}
517
518func (c *deviceConfig) BtConfigIncludeDir() string {
519	return String(c.config.ProductVariables.BtConfigIncludeDir)
520}
521
522func (c *deviceConfig) DeviceKernelHeaderDirs() []string {
523	return c.config.ProductVariables.DeviceKernelHeaders
524}
525
526func (c *deviceConfig) NativeCoverageEnabled() bool {
527	return Bool(c.config.ProductVariables.NativeCoverage)
528}
529
530func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
531	coverage := false
532	if c.config.ProductVariables.CoveragePaths != nil {
533		if prefixInList(path, *c.config.ProductVariables.CoveragePaths) {
534			coverage = true
535		}
536	}
537	if coverage && c.config.ProductVariables.CoverageExcludePaths != nil {
538		if prefixInList(path, *c.config.ProductVariables.CoverageExcludePaths) {
539			coverage = false
540		}
541	}
542	return coverage
543}
544
545func (c *config) IntegerOverflowDisabledForPath(path string) bool {
546	if c.ProductVariables.IntegerOverflowExcludePaths == nil {
547		return false
548	}
549	return prefixInList(path, *c.ProductVariables.IntegerOverflowExcludePaths)
550}
551