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