Add DeviceConfig and OncePer objects
Add DeviceConfig to store per-device configuration information. Put a OncePer object inside Config and DeviceConfig, which computes a value once per key per object to allow build logic to store arbitrary per-build or per-device computed values. Change-Id: I1a38b426f29d223ef5e803e0d4d9604500de2fd2
This commit is contained in:
@@ -100,6 +100,7 @@ bootstrap_go_package {
|
||||
"android/makevars.go",
|
||||
"android/module.go",
|
||||
"android/mutator.go",
|
||||
"android/onceper.go",
|
||||
"android/package_ctx.go",
|
||||
"android/paths.go",
|
||||
"android/util.go",
|
||||
|
@@ -717,7 +717,7 @@ func forEachInterface(v reflect.Value, f func(reflect.Value)) {
|
||||
}
|
||||
|
||||
// Convert the arch product variables into a list of targets for each os class structs
|
||||
func decodeTargetProductVariables(config Config) (map[OsClass][]Target, error) {
|
||||
func decodeTargetProductVariables(config *config) (map[OsClass][]Target, error) {
|
||||
variables := config.ProductVariables
|
||||
|
||||
targets := make(map[OsClass][]Target)
|
||||
|
@@ -43,11 +43,18 @@ func (f *FileConfigurableOptions) SetDefaultConfig() {
|
||||
*f = FileConfigurableOptions{}
|
||||
}
|
||||
|
||||
// A Config object represents the entire build configuration for Android.
|
||||
type Config struct {
|
||||
*config
|
||||
}
|
||||
|
||||
// A config object represents the entire build configuration for Android.
|
||||
// A DeviceConfig object represents the configuration for a particular device being built. For
|
||||
// now there will only be one of these, but in the future there may be multiple devices being
|
||||
// built
|
||||
type DeviceConfig struct {
|
||||
*deviceConfig
|
||||
}
|
||||
|
||||
type config struct {
|
||||
FileConfigurableOptions
|
||||
ProductVariables productVariables
|
||||
@@ -58,6 +65,8 @@ type config struct {
|
||||
Targets map[OsClass][]Target
|
||||
BuildOsVariant string
|
||||
|
||||
deviceConfig *deviceConfig
|
||||
|
||||
srcDir string // the path of the root source directory
|
||||
buildDir string // the path of the build output directory
|
||||
|
||||
@@ -66,6 +75,13 @@ type config struct {
|
||||
envFrozen bool
|
||||
|
||||
inMake bool
|
||||
OncePer
|
||||
}
|
||||
|
||||
type deviceConfig struct {
|
||||
config *config
|
||||
targets []Arch
|
||||
OncePer
|
||||
}
|
||||
|
||||
type jsonConfigurable interface {
|
||||
@@ -138,17 +154,23 @@ func saveToConfigFile(config jsonConfigurable, filename string) error {
|
||||
// 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),
|
||||
config := &config{
|
||||
ConfigFileName: filepath.Join(buildDir, configFileName),
|
||||
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
|
||||
|
||||
srcDir: srcDir,
|
||||
buildDir: buildDir,
|
||||
envDeps: make(map[string]string),
|
||||
},
|
||||
srcDir: srcDir,
|
||||
buildDir: buildDir,
|
||||
envDeps: make(map[string]string),
|
||||
|
||||
deviceConfig: &deviceConfig{},
|
||||
}
|
||||
|
||||
deviceConfig := &deviceConfig{
|
||||
config: config,
|
||||
}
|
||||
|
||||
config.deviceConfig = deviceConfig
|
||||
|
||||
// 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)
|
||||
@@ -166,7 +188,7 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
|
||||
}
|
||||
|
||||
// Load any configurable options from the configuration file
|
||||
err = loadConfig(config.config)
|
||||
err = loadConfig(config)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
@@ -192,7 +214,7 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
|
||||
config.Targets = targets
|
||||
config.BuildOsVariant = targets[Host][0].String()
|
||||
|
||||
return config, nil
|
||||
return Config{config}, nil
|
||||
}
|
||||
|
||||
func (c *config) RemoveAbandonedFiles() bool {
|
||||
@@ -337,3 +359,11 @@ func (c *config) Android64() bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *deviceConfig) Arches() []Arch {
|
||||
var arches []Arch
|
||||
for _, target := range c.config.Targets[Device] {
|
||||
arches = append(arches, target.Arch)
|
||||
}
|
||||
return arches
|
||||
}
|
||||
|
@@ -56,6 +56,7 @@ type androidBaseContext interface {
|
||||
Darwin() bool
|
||||
Debug() bool
|
||||
AConfig() Config
|
||||
DeviceConfig() DeviceConfig
|
||||
}
|
||||
|
||||
type BaseContext interface {
|
||||
@@ -535,6 +536,10 @@ func (a *androidBaseContextImpl) AConfig() Config {
|
||||
return a.config
|
||||
}
|
||||
|
||||
func (a *androidBaseContextImpl) DeviceConfig() DeviceConfig {
|
||||
return DeviceConfig{a.config.deviceConfig}
|
||||
}
|
||||
|
||||
func (a *androidModuleContext) Proprietary() bool {
|
||||
return a.module.base().commonProperties.Proprietary
|
||||
}
|
||||
|
75
android/onceper.go
Normal file
75
android/onceper.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2016 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 (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type OncePer struct {
|
||||
values atomic.Value
|
||||
valuesLock sync.Mutex
|
||||
}
|
||||
|
||||
type valueMap map[interface{}]interface{}
|
||||
|
||||
// Once computes a value the first time it is called with a given key per OncePer, and returns the
|
||||
// value without recomputing when called with the same key. key must be hashable.
|
||||
func (once *OncePer) Once(key interface{}, value func() interface{}) interface{} {
|
||||
// Atomically load the map without locking. If this is the first call Load() will return nil
|
||||
// and the type assertion will fail, leaving a nil map in m, but that's OK since m is only used
|
||||
// for reads.
|
||||
m, _ := once.values.Load().(valueMap)
|
||||
if v, ok := m[key]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
once.valuesLock.Lock()
|
||||
defer once.valuesLock.Unlock()
|
||||
|
||||
// Check again with the lock held
|
||||
m, _ = once.values.Load().(valueMap)
|
||||
if v, ok := m[key]; ok {
|
||||
return v
|
||||
}
|
||||
|
||||
// Copy the existing map
|
||||
newMap := make(valueMap, len(m))
|
||||
for k, v := range m {
|
||||
newMap[k] = v
|
||||
}
|
||||
|
||||
v := value()
|
||||
|
||||
newMap[key] = v
|
||||
once.values.Store(newMap)
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func (once *OncePer) OnceStringSlice(key interface{}, value func() []string) []string {
|
||||
return once.Once(key, func() interface{} { return value() }).([]string)
|
||||
}
|
||||
|
||||
func (once *OncePer) Once2StringSlice(key interface{}, value func() ([]string, []string)) ([]string, []string) {
|
||||
type twoStringSlice [2][]string
|
||||
s := once.Once(key, func() interface{} {
|
||||
var s twoStringSlice
|
||||
s[0], s[1] = value()
|
||||
return s
|
||||
}).(twoStringSlice)
|
||||
return s[0], s[1]
|
||||
}
|
Reference in New Issue
Block a user