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/makevars.go",
|
||||||
"android/module.go",
|
"android/module.go",
|
||||||
"android/mutator.go",
|
"android/mutator.go",
|
||||||
|
"android/onceper.go",
|
||||||
"android/package_ctx.go",
|
"android/package_ctx.go",
|
||||||
"android/paths.go",
|
"android/paths.go",
|
||||||
"android/util.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
|
// 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
|
variables := config.ProductVariables
|
||||||
|
|
||||||
targets := make(map[OsClass][]Target)
|
targets := make(map[OsClass][]Target)
|
||||||
|
@@ -43,11 +43,18 @@ func (f *FileConfigurableOptions) SetDefaultConfig() {
|
|||||||
*f = FileConfigurableOptions{}
|
*f = FileConfigurableOptions{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A Config object represents the entire build configuration for Android.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
*config
|
*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 {
|
type config struct {
|
||||||
FileConfigurableOptions
|
FileConfigurableOptions
|
||||||
ProductVariables productVariables
|
ProductVariables productVariables
|
||||||
@@ -58,6 +65,8 @@ type config struct {
|
|||||||
Targets map[OsClass][]Target
|
Targets map[OsClass][]Target
|
||||||
BuildOsVariant string
|
BuildOsVariant string
|
||||||
|
|
||||||
|
deviceConfig *deviceConfig
|
||||||
|
|
||||||
srcDir string // the path of the root source directory
|
srcDir string // the path of the root source directory
|
||||||
buildDir string // the path of the build output directory
|
buildDir string // the path of the build output directory
|
||||||
|
|
||||||
@@ -66,6 +75,13 @@ type config struct {
|
|||||||
envFrozen bool
|
envFrozen bool
|
||||||
|
|
||||||
inMake bool
|
inMake bool
|
||||||
|
OncePer
|
||||||
|
}
|
||||||
|
|
||||||
|
type deviceConfig struct {
|
||||||
|
config *config
|
||||||
|
targets []Arch
|
||||||
|
OncePer
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonConfigurable interface {
|
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.
|
// the root source directory. It also loads the config file, if found.
|
||||||
func NewConfig(srcDir, buildDir string) (Config, error) {
|
func NewConfig(srcDir, buildDir string) (Config, error) {
|
||||||
// Make a config with default options
|
// Make a config with default options
|
||||||
config := Config{
|
config := &config{
|
||||||
config: &config{
|
ConfigFileName: filepath.Join(buildDir, configFileName),
|
||||||
ConfigFileName: filepath.Join(buildDir, configFileName),
|
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
|
||||||
ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
|
|
||||||
|
|
||||||
srcDir: srcDir,
|
srcDir: srcDir,
|
||||||
buildDir: buildDir,
|
buildDir: buildDir,
|
||||||
envDeps: make(map[string]string),
|
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
|
// Sanity check the build and source directories. This won't catch strange
|
||||||
// configurations with symlinks, but at least checks the obvious cases.
|
// configurations with symlinks, but at least checks the obvious cases.
|
||||||
absBuildDir, err := filepath.Abs(buildDir)
|
absBuildDir, err := filepath.Abs(buildDir)
|
||||||
@@ -166,7 +188,7 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load any configurable options from the configuration file
|
// Load any configurable options from the configuration file
|
||||||
err = loadConfig(config.config)
|
err = loadConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Config{}, err
|
return Config{}, err
|
||||||
}
|
}
|
||||||
@@ -192,7 +214,7 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
|
|||||||
config.Targets = targets
|
config.Targets = targets
|
||||||
config.BuildOsVariant = targets[Host][0].String()
|
config.BuildOsVariant = targets[Host][0].String()
|
||||||
|
|
||||||
return config, nil
|
return Config{config}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) RemoveAbandonedFiles() bool {
|
func (c *config) RemoveAbandonedFiles() bool {
|
||||||
@@ -337,3 +359,11 @@ func (c *config) Android64() bool {
|
|||||||
|
|
||||||
return false
|
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
|
Darwin() bool
|
||||||
Debug() bool
|
Debug() bool
|
||||||
AConfig() Config
|
AConfig() Config
|
||||||
|
DeviceConfig() DeviceConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseContext interface {
|
type BaseContext interface {
|
||||||
@@ -535,6 +536,10 @@ func (a *androidBaseContextImpl) AConfig() Config {
|
|||||||
return a.config
|
return a.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *androidBaseContextImpl) DeviceConfig() DeviceConfig {
|
||||||
|
return DeviceConfig{a.config.deviceConfig}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *androidModuleContext) Proprietary() bool {
|
func (a *androidModuleContext) Proprietary() bool {
|
||||||
return a.module.base().commonProperties.Proprietary
|
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