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