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