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 func (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
     62 type DeviceConfig struct {
     63 	*deviceConfig
     64 }
     65 
     66 type 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 
     92 type deviceConfig struct {
     93 	config *config
     94 	OncePer
     95 }
     96 
     97 type jsonConfigurable interface {
     98 	SetDefaultConfig()
     99 }
    100 
    101 func 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.
    111 func 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)
    140 func 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
    170 func 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.
    188 func 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 
    255 func (c *config) RemoveAbandonedFiles() bool {
    256 	return false
    257 }
    258 
    259 func (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.
    265 func (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
    278 func (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.
    290 func (c *config) GoRoot() string {
    291 	return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
    292 }
    293 
    294 func (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 
    305 func (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 
    323 func (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 
    331 func (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 
    336 func (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 
    341 func (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 
    348 func (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
    354 func (c *config) DeviceName() string {
    355 	return *c.ProductVariables.DeviceName
    356 }
    357 
    358 func (c *config) DeviceUsesClang() bool {
    359 	if c.ProductVariables.DeviceUsesClang != nil {
    360 		return *c.ProductVariables.DeviceUsesClang
    361 	}
    362 	return true
    363 }
    364 
    365 func (c *config) ResourceOverlays() []SourcePath {
    366 	return nil
    367 }
    368 
    369 func (c *config) PlatformVersion() string {
    370 	return "M"
    371 }
    372 
    373 func (c *config) PlatformSdkVersionInt() int {
    374 	return *c.ProductVariables.Platform_sdk_version
    375 }
    376 
    377 func (c *config) PlatformSdkVersion() string {
    378 	return strconv.Itoa(c.PlatformSdkVersionInt())
    379 }
    380 
    381 func (c *config) PlatformVersionAllCodenames() []string {
    382 	return c.ProductVariables.Platform_version_all_codenames
    383 }
    384 
    385 func (c *config) BuildNumber() string {
    386 	return "000000"
    387 }
    388 
    389 func (c *config) ProductAaptConfig() []string {
    390 	return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
    391 }
    392 
    393 func (c *config) ProductAaptPreferredConfig() string {
    394 	return "xhdpi"
    395 }
    396 
    397 func (c *config) ProductAaptCharacteristics() string {
    398 	return "nosdcard"
    399 }
    400 
    401 func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
    402 	return PathForSource(ctx, "build/target/product/security")
    403 }
    404 
    405 func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
    406 	return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
    407 }
    408 
    409 func (c *config) AllowMissingDependencies() bool {
    410 	return Bool(c.ProductVariables.Allow_missing_dependencies)
    411 }
    412 
    413 func (c *config) DevicePrefer32BitExecutables() bool {
    414 	return Bool(c.ProductVariables.DevicePrefer32BitExecutables)
    415 }
    416 
    417 func (c *config) SkipDeviceInstall() bool {
    418 	return c.EmbeddedInMake()
    419 }
    420 
    421 func (c *config) SkipMegaDeviceInstall(path string) bool {
    422 	return Bool(c.Mega_device) &&
    423 		strings.HasPrefix(path, filepath.Join(c.buildDir, "target", "product"))
    424 }
    425 
    426 func (c *config) SanitizeHost() []string {
    427 	return append([]string(nil), c.ProductVariables.SanitizeHost...)
    428 }
    429 
    430 func (c *config) SanitizeDevice() []string {
    431 	return append([]string(nil), c.ProductVariables.SanitizeDevice...)
    432 }
    433 
    434 func (c *config) SanitizeDeviceDiag() []string {
    435 	return append([]string(nil), c.ProductVariables.SanitizeDeviceDiag...)
    436 }
    437 
    438 func (c *config) SanitizeDeviceArch() []string {
    439 	return append([]string(nil), c.ProductVariables.SanitizeDeviceArch...)
    440 }
    441 
    442 func (c *config) EnableCFI() bool {
    443 	if c.ProductVariables.EnableCFI == nil {
    444 		return true
    445 	} else {
    446 		return *c.ProductVariables.EnableCFI
    447 	}
    448 }
    449 
    450 func (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 
    460 func (c *config) UseGoma() bool {
    461 	return Bool(c.ProductVariables.UseGoma)
    462 }
    463 
    464 func (c *config) ClangTidy() bool {
    465 	return Bool(c.ProductVariables.ClangTidy)
    466 }
    467 
    468 func (c *config) TidyChecks() string {
    469 	if c.ProductVariables.TidyChecks == nil {
    470 		return ""
    471 	}
    472 	return *c.ProductVariables.TidyChecks
    473 }
    474 
    475 func (c *config) LibartImgHostBaseAddress() string {
    476 	return "0x60000000"
    477 }
    478 
    479 func (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 
    492 func (c *config) ArtUseReadBarrier() bool {
    493 	return Bool(c.ProductVariables.ArtUseReadBarrier)
    494 }
    495 
    496 func (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 
    504 func (c *deviceConfig) VendorPath() string {
    505 	if c.config.ProductVariables.VendorPath != nil {
    506 		return *c.config.ProductVariables.VendorPath
    507 	}
    508 	return "vendor"
    509 }
    510 
    511 func (c *deviceConfig) CompileVndk() bool {
    512 	if c.config.ProductVariables.DeviceVndkVersion == nil {
    513 		return false
    514 	}
    515 	return *c.config.ProductVariables.DeviceVndkVersion == "current"
    516 }
    517 
    518 func (c *deviceConfig) BtConfigIncludeDir() string {
    519 	return String(c.config.ProductVariables.BtConfigIncludeDir)
    520 }
    521 
    522 func (c *deviceConfig) DeviceKernelHeaderDirs() []string {
    523 	return c.config.ProductVariables.DeviceKernelHeaders
    524 }
    525 
    526 func (c *deviceConfig) NativeCoverageEnabled() bool {
    527 	return Bool(c.config.ProductVariables.NativeCoverage)
    528 }
    529 
    530 func (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 
    545 func (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