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 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 58type DeviceConfig struct { 59 *deviceConfig 60} 61 62type 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 86type deviceConfig struct { 87 config *config 88 targets []Arch 89 OncePer 90} 91 92type jsonConfigurable interface { 93 SetDefaultConfig() 94} 95 96func 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. 106func 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) 135func 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 165func 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. 173func 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 244func (c *config) RemoveAbandonedFiles() bool { 245 return false 246} 247 248func (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 253func (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. 265func (c *config) GoRoot() string { 266 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS()) 267} 268 269func (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 280func (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 298func (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 306func (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 311func (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 316func (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 323func (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 329func (c *config) DeviceName() string { 330 return *c.ProductVariables.DeviceName 331} 332 333func (c *config) DeviceUsesClang() bool { 334 if c.ProductVariables.DeviceUsesClang != nil { 335 return *c.ProductVariables.DeviceUsesClang 336 } 337 return true 338} 339 340func (c *config) ResourceOverlays() []SourcePath { 341 return nil 342} 343 344func (c *config) PlatformVersion() string { 345 return "M" 346} 347 348func (c *config) PlatformSdkVersionInt() int { 349 return *c.ProductVariables.Platform_sdk_version 350} 351 352func (c *config) PlatformSdkVersion() string { 353 return strconv.Itoa(c.PlatformSdkVersionInt()) 354} 355 356func (c *config) BuildNumber() string { 357 return "000000" 358} 359 360func (c *config) ProductAaptConfig() []string { 361 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"} 362} 363 364func (c *config) ProductAaptPreferredConfig() string { 365 return "xhdpi" 366} 367 368func (c *config) ProductAaptCharacteristics() string { 369 return "nosdcard" 370} 371 372func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath { 373 return PathForSource(ctx, "build/target/product/security") 374} 375 376func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath { 377 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey") 378} 379 380func (c *config) AllowMissingDependencies() bool { 381 return Bool(c.ProductVariables.Allow_missing_dependencies) 382} 383 384func (c *config) DevicePrefer32BitExecutables() bool { 385 return Bool(c.ProductVariables.DevicePrefer32BitExecutables) 386} 387 388func (c *config) SkipDeviceInstall() bool { 389 return c.EmbeddedInMake() || Bool(c.Mega_device) 390} 391 392func (c *config) SanitizeHost() []string { 393 return append([]string(nil), c.ProductVariables.SanitizeHost...) 394} 395 396func (c *config) SanitizeDevice() []string { 397 return append([]string(nil), c.ProductVariables.SanitizeDevice...) 398} 399 400func (c *config) SanitizeDeviceArch() []string { 401 return append([]string(nil), c.ProductVariables.SanitizeDeviceArch...) 402} 403 404func (c *config) EnableCFI() bool { 405 return Bool(c.ProductVariables.EnableCFI) 406} 407 408func (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 418func (c *config) UseGoma() bool { 419 return Bool(c.ProductVariables.UseGoma) 420} 421 422func (c *config) ClangTidy() bool { 423 return Bool(c.ProductVariables.ClangTidy) 424} 425 426func (c *config) TidyChecks() string { 427 if c.ProductVariables.TidyChecks == nil { 428 return "" 429 } 430 return *c.ProductVariables.TidyChecks 431} 432 433func (c *config) LibartImgHostBaseAddress() string { 434 return "0x60000000" 435} 436 437func (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 446func (c *config) ArtUseReadBarrier() bool { 447 return Bool(c.ProductVariables.ArtUseReadBarrier) 448} 449 450func (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 458func (c *deviceConfig) VendorPath() string { 459 if c.config.ProductVariables.VendorPath != nil { 460 return *c.config.ProductVariables.VendorPath 461 } 462 return "vendor" 463} 464 465func (c *deviceConfig) CompileVndk() bool { 466 if c.config.ProductVariables.DeviceVndkVersion == nil { 467 return false 468 } 469 return *c.config.ProductVariables.DeviceVndkVersion == "current" 470} 471 472func (c *deviceConfig) BtConfigIncludeDir() string { 473 return String(c.config.ProductVariables.BtConfigIncludeDir) 474} 475 476func (c *deviceConfig) NativeCoverageEnabled() bool { 477 return Bool(c.config.ProductVariables.NativeCoverage) 478} 479 480func (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