diff options
Diffstat (limited to 'android/config.go')
-rw-r--r-- | android/config.go | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/android/config.go b/android/config.go new file mode 100644 index 00000000..8701960e --- /dev/null +++ b/android/config.go @@ -0,0 +1,323 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + + "github.com/google/blueprint/proptools" +) + +var Bool = proptools.Bool + +// The configuration file name +const configFileName = "soong.config" +const productVariablesFileName = "soong.variables" + +// A FileConfigurableOptions contains options which can be configured by the +// config file. These will be included in the config struct. +type FileConfigurableOptions struct { + Mega_device *bool `json:",omitempty"` +} + +func (f *FileConfigurableOptions) SetDefaultConfig() { + *f = FileConfigurableOptions{} +} + +type Config struct { + *config +} + +// A config object represents the entire build configuration for Android. +type config struct { + FileConfigurableOptions + ProductVariables productVariables + + ConfigFileName string + ProductVariablesFileName string + + DeviceArches []Arch + HostArches map[HostType][]Arch + + srcDir string // the path of the root source directory + buildDir string // the path of the build output directory + + envLock sync.Mutex + envDeps map[string]string + envFrozen bool + + inMake bool +} + +type jsonConfigurable interface { + SetDefaultConfig() +} + +func loadConfig(config *config) error { + err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName) + if err != nil { + return err + } + + return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName) +} + +// loads configuration options from a JSON file in the cwd. +func loadFromConfigFile(configurable jsonConfigurable, filename string) error { + // Try to open the file + configFileReader, err := os.Open(filename) + defer configFileReader.Close() + if os.IsNotExist(err) { + // Need to create a file, so that blueprint & ninja don't get in + // a dependency tracking loop. + // Make a file-configurable-options with defaults, write it out using + // a json writer. + configurable.SetDefaultConfig() + err = saveToConfigFile(configurable, filename) + if err != nil { + return err + } + } else { + // Make a decoder for it + jsonDecoder := json.NewDecoder(configFileReader) + err = jsonDecoder.Decode(configurable) + if err != nil { + return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename) + } + } + + // No error + return nil +} + +func saveToConfigFile(config jsonConfigurable, filename string) error { + data, err := json.MarshalIndent(&config, "", " ") + if err != nil { + return fmt.Errorf("cannot marshal config data: %s", err.Error()) + } + + configFileWriter, err := os.Create(filename) + if err != nil { + return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error()) + } + defer configFileWriter.Close() + + _, err = configFileWriter.Write(data) + if err != nil { + return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error()) + } + + _, err = configFileWriter.WriteString("\n") + if err != nil { + return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error()) + } + + return nil +} + +// New creates a new Config object. The srcDir argument specifies the path to +// the root source directory. It also loads the config file, if found. +func NewConfig(srcDir, buildDir string) (Config, error) { + // Make a config with default options + config := Config{ + config: &config{ + ConfigFileName: filepath.Join(buildDir, configFileName), + ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName), + + srcDir: srcDir, + buildDir: buildDir, + envDeps: make(map[string]string), + }, + } + + // Sanity check the build and source directories. This won't catch strange + // configurations with symlinks, but at least checks the obvious cases. + absBuildDir, err := filepath.Abs(buildDir) + if err != nil { + return Config{}, err + } + + absSrcDir, err := filepath.Abs(srcDir) + if err != nil { + return Config{}, err + } + + if strings.HasPrefix(absSrcDir, absBuildDir) { + return Config{}, fmt.Errorf("Build dir must not contain source directory") + } + + // Load any configurable options from the configuration file + err = loadConfig(config.config) + if err != nil { + return Config{}, err + } + + inMakeFile := filepath.Join(buildDir, ".soong.in_make") + if _, err := os.Stat(inMakeFile); err == nil { + config.inMake = true + } + + hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables) + if err != nil { + return Config{}, err + } + + if Bool(config.Mega_device) { + deviceArches, err = decodeMegaDevice() + if err != nil { + return Config{}, err + } + } + + config.HostArches = hostArches + config.DeviceArches = deviceArches + + return config, nil +} + +func (c *config) RemoveAbandonedFiles() bool { + return false +} + +// PrebuiltOS returns the name of the host OS used in prebuilts directories +func (c *config) PrebuiltOS() string { + switch runtime.GOOS { + case "linux": + return "linux-x86" + case "darwin": + return "darwin-x86" + default: + panic("Unknown GOOS") + } +} + +// GoRoot returns the path to the root directory of the Go toolchain. +func (c *config) GoRoot() string { + return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS()) +} + +func (c *config) CpPreserveSymlinksFlags() string { + switch runtime.GOOS { + case "darwin": + return "-R" + case "linux": + return "-d" + default: + return "" + } +} + +func (c *config) Getenv(key string) string { + var val string + var exists bool + c.envLock.Lock() + if val, exists = c.envDeps[key]; !exists { + if c.envFrozen { + panic("Cannot access new environment variables after envdeps are frozen") + } + val = os.Getenv(key) + c.envDeps[key] = val + } + c.envLock.Unlock() + return val +} + +func (c *config) EnvDeps() map[string]string { + c.envLock.Lock() + c.envFrozen = true + c.envLock.Unlock() + return c.envDeps +} + +func (c *config) EmbeddedInMake() bool { + return c.inMake +} + +// DeviceName returns the name of the current device target +// TODO: take an AndroidModuleContext to select the device name for multi-device builds +func (c *config) DeviceName() string { + return *c.ProductVariables.DeviceName +} + +func (c *config) DeviceUsesClang() bool { + if c.ProductVariables.DeviceUsesClang != nil { + return *c.ProductVariables.DeviceUsesClang + } + return true +} + +func (c *config) ResourceOverlays() []SourcePath { + return nil +} + +func (c *config) PlatformVersion() string { + return "M" +} + +func (c *config) PlatformSdkVersion() string { + return "22" +} + +func (c *config) BuildNumber() string { + return "000000" +} + +func (c *config) ProductAaptConfig() []string { + return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"} +} + +func (c *config) ProductAaptPreferredConfig() string { + return "xhdpi" +} + +func (c *config) ProductAaptCharacteristics() string { + return "nosdcard" +} + +func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath { + return PathForSource(ctx, "build/target/product/security") +} + +func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath { + return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey") +} + +func (c *config) AllowMissingDependencies() bool { + return Bool(c.ProductVariables.Allow_missing_dependencies) +} + +func (c *config) SkipDeviceInstall() bool { + return c.EmbeddedInMake() || Bool(c.Mega_device) +} + +func (c *config) SanitizeHost() []string { + if c.ProductVariables.SanitizeHost == nil { + return nil + } + return *c.ProductVariables.SanitizeHost +} + +func (c *config) SanitizeDevice() []string { + if c.ProductVariables.SanitizeDevice == nil { + return nil + } + return *c.ProductVariables.SanitizeDevice +} |