blob: c67023e32775444de83ea3d93e1cd9817acd0b35 [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"
Colin Crossc1e86a32015-04-15 12:33:28 -070023 "sync"
Colin Cross3f40fa42015-01-30 17:27:36 -080024)
25
Colin Cross3f40fa42015-01-30 17:27:36 -080026// The configuration file name
Dan Willemsen87b17d12015-07-14 00:39:06 -070027const configFileName = "soong.config"
28const productVariablesFileName = "soong.variables"
Colin Cross3f40fa42015-01-30 17:27:36 -080029
30// A FileConfigurableOptions contains options which can be configured by the
31// config file. These will be included in the config struct.
32type FileConfigurableOptions struct {
33}
34
Colin Cross27385972015-09-18 10:57:10 -070035func (f *FileConfigurableOptions) SetDefaultConfig() {
36 *f = FileConfigurableOptions{}
Colin Cross3f40fa42015-01-30 17:27:36 -080037}
38
Colin Crossc3c0a492015-04-10 15:43:55 -070039type Config struct {
40 *config
Dan Willemsen218f6562015-07-08 18:13:11 -070041
42 dontCreateNinjaFile bool
Colin Crossc3c0a492015-04-10 15:43:55 -070043}
44
Dan Willemsen218f6562015-07-08 18:13:11 -070045// A config object represents the entire build configuration for Android.
Colin Cross1332b002015-04-07 17:11:30 -070046type config struct {
Colin Cross3f40fa42015-01-30 17:27:36 -080047 FileConfigurableOptions
Colin Cross485e5722015-08-27 13:28:01 -070048 ProductVariables productVariables
Colin Cross3f40fa42015-01-30 17:27:36 -080049
Dan Willemsen87b17d12015-07-14 00:39:06 -070050 ConfigFileName string
51 ProductVariablesFileName string
52
Dan Willemsen218f6562015-07-08 18:13:11 -070053 DeviceArches []Arch
54 HostArches map[HostType][]Arch
55
Dan Willemsen87b17d12015-07-14 00:39:06 -070056 srcDir string // the path of the root source directory
57 buildDir string // the path of the build output directory
Colin Crossc1e86a32015-04-15 12:33:28 -070058
Dan Willemsene7680ba2015-09-11 17:06:19 -070059 envLock sync.Mutex
60 envDeps map[string]string
61 envFrozen bool
Colin Cross3f40fa42015-01-30 17:27:36 -080062}
63
Colin Cross485e5722015-08-27 13:28:01 -070064type jsonConfigurable interface {
Colin Cross27385972015-09-18 10:57:10 -070065 SetDefaultConfig()
Colin Cross485e5722015-08-27 13:28:01 -070066}
Colin Cross3f40fa42015-01-30 17:27:36 -080067
Colin Cross485e5722015-08-27 13:28:01 -070068func loadConfig(config *config) error {
Dan Willemsen87b17d12015-07-14 00:39:06 -070069 err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName)
Colin Cross485e5722015-08-27 13:28:01 -070070 if err != nil {
71 return err
72 }
73
Dan Willemsen87b17d12015-07-14 00:39:06 -070074 return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
Colin Cross485e5722015-08-27 13:28:01 -070075}
76
77// loads configuration options from a JSON file in the cwd.
78func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -080079 // Try to open the file
Colin Cross485e5722015-08-27 13:28:01 -070080 configFileReader, err := os.Open(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080081 defer configFileReader.Close()
82 if os.IsNotExist(err) {
83 // Need to create a file, so that blueprint & ninja don't get in
84 // a dependency tracking loop.
85 // Make a file-configurable-options with defaults, write it out using
86 // a json writer.
Colin Cross27385972015-09-18 10:57:10 -070087 configurable.SetDefaultConfig()
88 err = saveToConfigFile(configurable, filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080089 if err != nil {
90 return err
91 }
92 } else {
93 // Make a decoder for it
94 jsonDecoder := json.NewDecoder(configFileReader)
Colin Cross485e5722015-08-27 13:28:01 -070095 err = jsonDecoder.Decode(configurable)
Colin Cross3f40fa42015-01-30 17:27:36 -080096 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -070097 return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080098 }
99 }
100
Colin Cross3f40fa42015-01-30 17:27:36 -0800101 // No error
102 return nil
103}
104
Colin Cross485e5722015-08-27 13:28:01 -0700105func saveToConfigFile(config jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -0800106 data, err := json.MarshalIndent(&config, "", " ")
107 if err != nil {
108 return fmt.Errorf("cannot marshal config data: %s", err.Error())
109 }
110
Colin Cross485e5722015-08-27 13:28:01 -0700111 configFileWriter, err := os.Create(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800112 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700113 return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800114 }
115 defer configFileWriter.Close()
116
117 _, err = configFileWriter.Write(data)
118 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700119 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
120 }
121
122 _, err = configFileWriter.WriteString("\n")
123 if err != nil {
124 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800125 }
126
127 return nil
128}
129
130// New creates a new Config object. The srcDir argument specifies the path to
131// the root source directory. It also loads the config file, if found.
Dan Willemsen87b17d12015-07-14 00:39:06 -0700132func NewConfig(srcDir, buildDir string) (Config, error) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800133 // Make a config with default options
Colin Crossc3c0a492015-04-10 15:43:55 -0700134 config := Config{
135 config: &config{
Dan Willemsen87b17d12015-07-14 00:39:06 -0700136 ConfigFileName: filepath.Join(buildDir, configFileName),
137 ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
138
139 srcDir: srcDir,
140 buildDir: buildDir,
141 envDeps: make(map[string]string),
Colin Crossc3c0a492015-04-10 15:43:55 -0700142 },
Colin Cross68f55102015-03-25 14:43:57 -0700143 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800144
145 // Load any configurable options from the configuration file
Colin Cross485e5722015-08-27 13:28:01 -0700146 err := loadConfig(config.config)
Colin Cross3f40fa42015-01-30 17:27:36 -0800147 if err != nil {
Colin Crossc3c0a492015-04-10 15:43:55 -0700148 return Config{}, err
Colin Cross3f40fa42015-01-30 17:27:36 -0800149 }
150
Dan Willemsen218f6562015-07-08 18:13:11 -0700151 hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
152 if err != nil {
153 return Config{}, err
154 }
155
156 config.HostArches = hostArches
157 config.DeviceArches = deviceArches
158
Colin Cross3f40fa42015-01-30 17:27:36 -0800159 return config, nil
160}
161
Colin Cross1332b002015-04-07 17:11:30 -0700162func (c *config) SrcDir() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800163 return c.srcDir
164}
165
Dan Willemsen87b17d12015-07-14 00:39:06 -0700166func (c *config) BuildDir() string {
167 return c.buildDir
168}
169
Colin Cross1332b002015-04-07 17:11:30 -0700170func (c *config) IntermediatesDir() string {
Dan Willemsen87b17d12015-07-14 00:39:06 -0700171 return filepath.Join(c.BuildDir(), ".intermediates")
Colin Cross581c1892015-04-07 16:50:10 -0700172}
173
Dan Willemsen218f6562015-07-08 18:13:11 -0700174func (c *config) RemoveAbandonedFiles() bool {
175 return false
176}
177
Colin Cross3f40fa42015-01-30 17:27:36 -0800178// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700179func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800180 switch runtime.GOOS {
181 case "linux":
182 return "linux-x86"
183 case "darwin":
184 return "darwin-x86"
185 default:
186 panic("Unknown GOOS")
187 }
188}
189
190// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700191func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800192 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
193}
194
Colin Cross1332b002015-04-07 17:11:30 -0700195func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700196 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800197 case "darwin":
198 return "-R"
199 case "linux":
200 return "-d"
201 default:
202 return ""
203 }
204}
Colin Cross68f55102015-03-25 14:43:57 -0700205
Colin Cross1332b002015-04-07 17:11:30 -0700206func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700207 var val string
208 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700209 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700210 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700211 if c.envFrozen {
212 panic("Cannot access new environment variables after envdeps are frozen")
213 }
Colin Cross68f55102015-03-25 14:43:57 -0700214 val = os.Getenv(key)
215 c.envDeps[key] = val
216 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700217 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700218 return val
219}
220
Colin Cross1332b002015-04-07 17:11:30 -0700221func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700222 c.envLock.Lock()
223 c.envFrozen = true
224 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700225 return c.envDeps
226}
Colin Cross35cec122015-04-02 14:37:16 -0700227
228// DeviceName returns the name of the current device target
229// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700230func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700231 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700232}
233
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700234func (c *config) DeviceUsesClang() bool {
235 if c.ProductVariables.DeviceUsesClang != nil {
236 return *c.ProductVariables.DeviceUsesClang
237 }
238 return false
239}
240
Colin Cross35cec122015-04-02 14:37:16 -0700241// DeviceOut returns the path to out directory for device targets
Colin Cross1332b002015-04-07 17:11:30 -0700242func (c *config) DeviceOut() string {
Dan Willemsen87b17d12015-07-14 00:39:06 -0700243 return filepath.Join(c.BuildDir(), "target/product", c.DeviceName())
Colin Cross35cec122015-04-02 14:37:16 -0700244}
245
246// HostOut returns the path to out directory for host targets
Colin Cross1332b002015-04-07 17:11:30 -0700247func (c *config) HostOut() string {
Dan Willemsen87b17d12015-07-14 00:39:06 -0700248 return filepath.Join(c.BuildDir(), "host", c.PrebuiltOS())
Colin Cross35cec122015-04-02 14:37:16 -0700249}
250
251// HostBin returns the path to bin directory for host targets
Colin Cross1332b002015-04-07 17:11:30 -0700252func (c *config) HostBin() string {
Colin Cross35cec122015-04-02 14:37:16 -0700253 return filepath.Join(c.HostOut(), "bin")
254}
255
256// HostBinTool returns the path to a host tool in the bin directory for host targets
Colin Cross1332b002015-04-07 17:11:30 -0700257func (c *config) HostBinTool(tool string) (string, error) {
Colin Cross35cec122015-04-02 14:37:16 -0700258 return filepath.Join(c.HostBin(), tool), nil
259}
Colin Cross65bf4f22015-04-03 16:54:17 -0700260
261// HostJavaDir returns the path to framework directory for host targets
Colin Cross1332b002015-04-07 17:11:30 -0700262func (c *config) HostJavaDir() string {
Colin Cross65bf4f22015-04-03 16:54:17 -0700263 return filepath.Join(c.HostOut(), "framework")
264}
265
266// HostJavaTool returns the path to a host tool in the frameworks directory for host targets
Colin Cross1332b002015-04-07 17:11:30 -0700267func (c *config) HostJavaTool(tool string) (string, error) {
Colin Cross65bf4f22015-04-03 16:54:17 -0700268 return filepath.Join(c.HostJavaDir(), tool), nil
269}
Colin Cross30e076a2015-04-13 13:58:27 -0700270
271func (c *config) ResourceOverlays() []string {
272 return nil
273}
274
275func (c *config) PlatformVersion() string {
276 return "M"
277}
278
279func (c *config) PlatformSdkVersion() string {
280 return "22"
281}
282
283func (c *config) BuildNumber() string {
284 return "000000"
285}
286
287func (c *config) ProductAaptConfig() []string {
288 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
289}
290
291func (c *config) ProductAaptPreferredConfig() string {
292 return "xhdpi"
293}
294
295func (c *config) ProductAaptCharacteristics() string {
296 return "nosdcard"
297}
298
299func (c *config) DefaultAppCertificateDir() string {
300 return filepath.Join(c.SrcDir(), "build/target/product/security")
301}
302
303func (c *config) DefaultAppCertificate() string {
304 return filepath.Join(c.DefaultAppCertificateDir(), "testkey")
305}