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