blob: 7f6ee65d10193e7afafc541bce20f9be7c096551 [file] [log] [blame]
Colin Cross3f40fa42015-01-30 17:27:36 -08001// 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
Colin Cross1332b002015-04-07 17:11:30 -070015package common
Colin Cross3f40fa42015-01-30 17:27:36 -080016
17import (
Colin Cross3f40fa42015-01-30 17:27:36 -080018 "encoding/json"
19 "fmt"
20 "os"
Colin Cross35cec122015-04-02 14:37:16 -070021 "path/filepath"
Colin Cross3f40fa42015-01-30 17:27:36 -080022 "runtime"
Dan Willemsen34cc69e2015-09-23 15:26:20 -070023 "strings"
Colin Crossc1e86a32015-04-15 12:33:28 -070024 "sync"
Colin Cross3f40fa42015-01-30 17:27:36 -080025)
26
Colin Cross3f40fa42015-01-30 17:27:36 -080027// The configuration file name
Dan Willemsen87b17d12015-07-14 00:39:06 -070028const configFileName = "soong.config"
29const productVariablesFileName = "soong.variables"
Colin Cross3f40fa42015-01-30 17:27:36 -080030
31// A FileConfigurableOptions contains options which can be configured by the
32// config file. These will be included in the config struct.
33type FileConfigurableOptions struct {
34}
35
Colin Cross27385972015-09-18 10:57:10 -070036func (f *FileConfigurableOptions) SetDefaultConfig() {
37 *f = FileConfigurableOptions{}
Colin Cross3f40fa42015-01-30 17:27:36 -080038}
39
Colin Crossc3c0a492015-04-10 15:43:55 -070040type Config struct {
41 *config
42}
43
Dan Willemsen218f6562015-07-08 18:13:11 -070044// A config object represents the entire build configuration for Android.
Colin Cross1332b002015-04-07 17:11:30 -070045type config struct {
Colin Cross3f40fa42015-01-30 17:27:36 -080046 FileConfigurableOptions
Colin Cross485e5722015-08-27 13:28:01 -070047 ProductVariables productVariables
Colin Cross3f40fa42015-01-30 17:27:36 -080048
Dan Willemsen87b17d12015-07-14 00:39:06 -070049 ConfigFileName string
50 ProductVariablesFileName string
51
Dan Willemsen218f6562015-07-08 18:13:11 -070052 DeviceArches []Arch
53 HostArches map[HostType][]Arch
54
Dan Willemsen87b17d12015-07-14 00:39:06 -070055 srcDir string // the path of the root source directory
56 buildDir string // the path of the build output directory
Colin Crossc1e86a32015-04-15 12:33:28 -070057
Dan Willemsene7680ba2015-09-11 17:06:19 -070058 envLock sync.Mutex
59 envDeps map[string]string
60 envFrozen bool
Colin Cross3f40fa42015-01-30 17:27:36 -080061}
62
Colin Cross485e5722015-08-27 13:28:01 -070063type jsonConfigurable interface {
Colin Cross27385972015-09-18 10:57:10 -070064 SetDefaultConfig()
Colin Cross485e5722015-08-27 13:28:01 -070065}
Colin Cross3f40fa42015-01-30 17:27:36 -080066
Colin Cross485e5722015-08-27 13:28:01 -070067func loadConfig(config *config) error {
Dan Willemsen87b17d12015-07-14 00:39:06 -070068 err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName)
Colin Cross485e5722015-08-27 13:28:01 -070069 if err != nil {
70 return err
71 }
72
Dan Willemsen87b17d12015-07-14 00:39:06 -070073 return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
Colin Cross485e5722015-08-27 13:28:01 -070074}
75
76// loads configuration options from a JSON file in the cwd.
77func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -080078 // Try to open the file
Colin Cross485e5722015-08-27 13:28:01 -070079 configFileReader, err := os.Open(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080080 defer configFileReader.Close()
81 if os.IsNotExist(err) {
82 // Need to create a file, so that blueprint & ninja don't get in
83 // a dependency tracking loop.
84 // Make a file-configurable-options with defaults, write it out using
85 // a json writer.
Colin Cross27385972015-09-18 10:57:10 -070086 configurable.SetDefaultConfig()
87 err = saveToConfigFile(configurable, filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080088 if err != nil {
89 return err
90 }
91 } else {
92 // Make a decoder for it
93 jsonDecoder := json.NewDecoder(configFileReader)
Colin Cross485e5722015-08-27 13:28:01 -070094 err = jsonDecoder.Decode(configurable)
Colin Cross3f40fa42015-01-30 17:27:36 -080095 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -070096 return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080097 }
98 }
99
Colin Cross3f40fa42015-01-30 17:27:36 -0800100 // No error
101 return nil
102}
103
Colin Cross485e5722015-08-27 13:28:01 -0700104func saveToConfigFile(config jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -0800105 data, err := json.MarshalIndent(&config, "", " ")
106 if err != nil {
107 return fmt.Errorf("cannot marshal config data: %s", err.Error())
108 }
109
Colin Cross485e5722015-08-27 13:28:01 -0700110 configFileWriter, err := os.Create(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800111 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700112 return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800113 }
114 defer configFileWriter.Close()
115
116 _, err = configFileWriter.Write(data)
117 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700118 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
119 }
120
121 _, err = configFileWriter.WriteString("\n")
122 if err != nil {
123 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800124 }
125
126 return nil
127}
128
129// New creates a new Config object. The srcDir argument specifies the path to
130// the root source directory. It also loads the config file, if found.
Dan Willemsen87b17d12015-07-14 00:39:06 -0700131func NewConfig(srcDir, buildDir string) (Config, error) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800132 // Make a config with default options
Colin Crossc3c0a492015-04-10 15:43:55 -0700133 config := Config{
134 config: &config{
Dan Willemsen87b17d12015-07-14 00:39:06 -0700135 ConfigFileName: filepath.Join(buildDir, configFileName),
136 ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
137
138 srcDir: srcDir,
139 buildDir: buildDir,
140 envDeps: make(map[string]string),
Colin Crossc3c0a492015-04-10 15:43:55 -0700141 },
Colin Cross68f55102015-03-25 14:43:57 -0700142 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800143
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700144 // Sanity check the build and source directories. This won't catch strange
145 // configurations with symlinks, but at least checks the obvious cases.
146 absBuildDir, err := filepath.Abs(buildDir)
147 if err != nil {
148 return Config{}, err
149 }
150
151 absSrcDir, err := filepath.Abs(srcDir)
152 if err != nil {
153 return Config{}, err
154 }
155
156 if strings.HasPrefix(absSrcDir, absBuildDir) {
157 return Config{}, fmt.Errorf("Build dir must not contain source directory")
158 }
159
Colin Cross3f40fa42015-01-30 17:27:36 -0800160 // Load any configurable options from the configuration file
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700161 err = loadConfig(config.config)
Colin Cross3f40fa42015-01-30 17:27:36 -0800162 if err != nil {
Colin Crossc3c0a492015-04-10 15:43:55 -0700163 return Config{}, err
Colin Cross3f40fa42015-01-30 17:27:36 -0800164 }
165
Dan Willemsen218f6562015-07-08 18:13:11 -0700166 hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
167 if err != nil {
168 return Config{}, err
169 }
170
171 config.HostArches = hostArches
172 config.DeviceArches = deviceArches
173
Colin Cross3f40fa42015-01-30 17:27:36 -0800174 return config, nil
175}
176
Dan Willemsen218f6562015-07-08 18:13:11 -0700177func (c *config) RemoveAbandonedFiles() bool {
178 return false
179}
180
Colin Cross3f40fa42015-01-30 17:27:36 -0800181// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700182func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800183 switch runtime.GOOS {
184 case "linux":
185 return "linux-x86"
186 case "darwin":
187 return "darwin-x86"
188 default:
189 panic("Unknown GOOS")
190 }
191}
192
193// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700194func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800195 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
196}
197
Colin Cross1332b002015-04-07 17:11:30 -0700198func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700199 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800200 case "darwin":
201 return "-R"
202 case "linux":
203 return "-d"
204 default:
205 return ""
206 }
207}
Colin Cross68f55102015-03-25 14:43:57 -0700208
Colin Cross1332b002015-04-07 17:11:30 -0700209func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700210 var val string
211 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700212 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700213 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700214 if c.envFrozen {
215 panic("Cannot access new environment variables after envdeps are frozen")
216 }
Colin Cross68f55102015-03-25 14:43:57 -0700217 val = os.Getenv(key)
218 c.envDeps[key] = val
219 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700220 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700221 return val
222}
223
Colin Cross1332b002015-04-07 17:11:30 -0700224func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700225 c.envLock.Lock()
226 c.envFrozen = true
227 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700228 return c.envDeps
229}
Colin Cross35cec122015-04-02 14:37:16 -0700230
231// DeviceName returns the name of the current device target
232// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700233func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700234 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700235}
236
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700237func (c *config) DeviceUsesClang() bool {
238 if c.ProductVariables.DeviceUsesClang != nil {
239 return *c.ProductVariables.DeviceUsesClang
240 }
241 return false
242}
243
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700244func (c *config) ResourceOverlays() []SourcePath {
Colin Cross30e076a2015-04-13 13:58:27 -0700245 return nil
246}
247
248func (c *config) PlatformVersion() string {
249 return "M"
250}
251
252func (c *config) PlatformSdkVersion() string {
253 return "22"
254}
255
256func (c *config) BuildNumber() string {
257 return "000000"
258}
259
260func (c *config) ProductAaptConfig() []string {
261 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
262}
263
264func (c *config) ProductAaptPreferredConfig() string {
265 return "xhdpi"
266}
267
268func (c *config) ProductAaptCharacteristics() string {
269 return "nosdcard"
270}
271
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700272func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
273 return PathForSource(ctx, "build/target/product/security")
Colin Cross30e076a2015-04-13 13:58:27 -0700274}
275
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700276func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
277 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
Colin Cross30e076a2015-04-13 13:58:27 -0700278}