blob: 74e0660329cef21bcb74d9c62c4350ad95d55318 [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 Cross6ff51382015-12-17 16:39:19 -080025
26 "github.com/google/blueprint/proptools"
Colin Cross3f40fa42015-01-30 17:27:36 -080027)
28
Colin Cross6ff51382015-12-17 16:39:19 -080029var Bool = proptools.Bool
30
Colin Cross3f40fa42015-01-30 17:27:36 -080031// The configuration file name
Dan Willemsen87b17d12015-07-14 00:39:06 -070032const configFileName = "soong.config"
33const productVariablesFileName = "soong.variables"
Colin Cross3f40fa42015-01-30 17:27:36 -080034
35// A FileConfigurableOptions contains options which can be configured by the
36// config file. These will be included in the config struct.
37type FileConfigurableOptions struct {
38}
39
Colin Cross27385972015-09-18 10:57:10 -070040func (f *FileConfigurableOptions) SetDefaultConfig() {
41 *f = FileConfigurableOptions{}
Colin Cross3f40fa42015-01-30 17:27:36 -080042}
43
Colin Crossc3c0a492015-04-10 15:43:55 -070044type Config struct {
45 *config
46}
47
Dan Willemsen218f6562015-07-08 18:13:11 -070048// A config object represents the entire build configuration for Android.
Colin Cross1332b002015-04-07 17:11:30 -070049type config struct {
Colin Cross3f40fa42015-01-30 17:27:36 -080050 FileConfigurableOptions
Colin Cross485e5722015-08-27 13:28:01 -070051 ProductVariables productVariables
Colin Cross3f40fa42015-01-30 17:27:36 -080052
Dan Willemsen87b17d12015-07-14 00:39:06 -070053 ConfigFileName string
54 ProductVariablesFileName string
55
Dan Willemsen218f6562015-07-08 18:13:11 -070056 DeviceArches []Arch
57 HostArches map[HostType][]Arch
58
Dan Willemsen87b17d12015-07-14 00:39:06 -070059 srcDir string // the path of the root source directory
60 buildDir string // the path of the build output directory
Colin Crossc1e86a32015-04-15 12:33:28 -070061
Dan Willemsene7680ba2015-09-11 17:06:19 -070062 envLock sync.Mutex
63 envDeps map[string]string
64 envFrozen bool
Dan Willemsen5ba07e82015-12-11 13:51:06 -080065
66 inMake bool
Colin Cross3f40fa42015-01-30 17:27:36 -080067}
68
Colin Cross485e5722015-08-27 13:28:01 -070069type jsonConfigurable interface {
Colin Cross27385972015-09-18 10:57:10 -070070 SetDefaultConfig()
Colin Cross485e5722015-08-27 13:28:01 -070071}
Colin Cross3f40fa42015-01-30 17:27:36 -080072
Colin Cross485e5722015-08-27 13:28:01 -070073func loadConfig(config *config) error {
Dan Willemsen87b17d12015-07-14 00:39:06 -070074 err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName)
Colin Cross485e5722015-08-27 13:28:01 -070075 if err != nil {
76 return err
77 }
78
Dan Willemsen87b17d12015-07-14 00:39:06 -070079 return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
Colin Cross485e5722015-08-27 13:28:01 -070080}
81
82// loads configuration options from a JSON file in the cwd.
83func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -080084 // Try to open the file
Colin Cross485e5722015-08-27 13:28:01 -070085 configFileReader, err := os.Open(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080086 defer configFileReader.Close()
87 if os.IsNotExist(err) {
88 // Need to create a file, so that blueprint & ninja don't get in
89 // a dependency tracking loop.
90 // Make a file-configurable-options with defaults, write it out using
91 // a json writer.
Colin Cross27385972015-09-18 10:57:10 -070092 configurable.SetDefaultConfig()
93 err = saveToConfigFile(configurable, filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080094 if err != nil {
95 return err
96 }
97 } else {
98 // Make a decoder for it
99 jsonDecoder := json.NewDecoder(configFileReader)
Colin Cross485e5722015-08-27 13:28:01 -0700100 err = jsonDecoder.Decode(configurable)
Colin Cross3f40fa42015-01-30 17:27:36 -0800101 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700102 return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800103 }
104 }
105
Colin Cross3f40fa42015-01-30 17:27:36 -0800106 // No error
107 return nil
108}
109
Colin Cross485e5722015-08-27 13:28:01 -0700110func saveToConfigFile(config jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -0800111 data, err := json.MarshalIndent(&config, "", " ")
112 if err != nil {
113 return fmt.Errorf("cannot marshal config data: %s", err.Error())
114 }
115
Colin Cross485e5722015-08-27 13:28:01 -0700116 configFileWriter, err := os.Create(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800117 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700118 return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800119 }
120 defer configFileWriter.Close()
121
122 _, err = configFileWriter.Write(data)
123 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700124 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
125 }
126
127 _, err = configFileWriter.WriteString("\n")
128 if err != nil {
129 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800130 }
131
132 return nil
133}
134
135// New creates a new Config object. The srcDir argument specifies the path to
136// the root source directory. It also loads the config file, if found.
Dan Willemsen87b17d12015-07-14 00:39:06 -0700137func NewConfig(srcDir, buildDir string) (Config, error) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800138 // Make a config with default options
Colin Crossc3c0a492015-04-10 15:43:55 -0700139 config := Config{
140 config: &config{
Dan Willemsen87b17d12015-07-14 00:39:06 -0700141 ConfigFileName: filepath.Join(buildDir, configFileName),
142 ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
143
144 srcDir: srcDir,
145 buildDir: buildDir,
146 envDeps: make(map[string]string),
Colin Crossc3c0a492015-04-10 15:43:55 -0700147 },
Colin Cross68f55102015-03-25 14:43:57 -0700148 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800149
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700150 // Sanity check the build and source directories. This won't catch strange
151 // configurations with symlinks, but at least checks the obvious cases.
152 absBuildDir, err := filepath.Abs(buildDir)
153 if err != nil {
154 return Config{}, err
155 }
156
157 absSrcDir, err := filepath.Abs(srcDir)
158 if err != nil {
159 return Config{}, err
160 }
161
162 if strings.HasPrefix(absSrcDir, absBuildDir) {
163 return Config{}, fmt.Errorf("Build dir must not contain source directory")
164 }
165
Colin Cross3f40fa42015-01-30 17:27:36 -0800166 // Load any configurable options from the configuration file
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700167 err = loadConfig(config.config)
Colin Cross3f40fa42015-01-30 17:27:36 -0800168 if err != nil {
Colin Crossc3c0a492015-04-10 15:43:55 -0700169 return Config{}, err
Colin Cross3f40fa42015-01-30 17:27:36 -0800170 }
171
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800172 inMakeFile := filepath.Join(buildDir, ".soong.in_make")
173 if _, err := os.Stat(inMakeFile); err == nil {
174 config.inMake = true
175 }
176
Dan Willemsen218f6562015-07-08 18:13:11 -0700177 hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
178 if err != nil {
179 return Config{}, err
180 }
181
182 config.HostArches = hostArches
183 config.DeviceArches = deviceArches
184
Colin Cross3f40fa42015-01-30 17:27:36 -0800185 return config, nil
186}
187
Dan Willemsen218f6562015-07-08 18:13:11 -0700188func (c *config) RemoveAbandonedFiles() bool {
189 return false
190}
191
Colin Cross3f40fa42015-01-30 17:27:36 -0800192// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700193func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800194 switch runtime.GOOS {
195 case "linux":
196 return "linux-x86"
197 case "darwin":
198 return "darwin-x86"
199 default:
200 panic("Unknown GOOS")
201 }
202}
203
204// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700205func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800206 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
207}
208
Colin Cross1332b002015-04-07 17:11:30 -0700209func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700210 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800211 case "darwin":
212 return "-R"
213 case "linux":
214 return "-d"
215 default:
216 return ""
217 }
218}
Colin Cross68f55102015-03-25 14:43:57 -0700219
Colin Cross1332b002015-04-07 17:11:30 -0700220func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700221 var val string
222 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700223 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700224 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700225 if c.envFrozen {
226 panic("Cannot access new environment variables after envdeps are frozen")
227 }
Colin Cross68f55102015-03-25 14:43:57 -0700228 val = os.Getenv(key)
229 c.envDeps[key] = val
230 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700231 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700232 return val
233}
234
Colin Cross1332b002015-04-07 17:11:30 -0700235func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700236 c.envLock.Lock()
237 c.envFrozen = true
238 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700239 return c.envDeps
240}
Colin Cross35cec122015-04-02 14:37:16 -0700241
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800242func (c *config) EmbeddedInMake() bool {
243 return c.inMake
244}
245
Colin Cross35cec122015-04-02 14:37:16 -0700246// DeviceName returns the name of the current device target
247// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700248func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700249 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700250}
251
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700252func (c *config) DeviceUsesClang() bool {
253 if c.ProductVariables.DeviceUsesClang != nil {
254 return *c.ProductVariables.DeviceUsesClang
255 }
256 return false
257}
258
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700259func (c *config) ResourceOverlays() []SourcePath {
Colin Cross30e076a2015-04-13 13:58:27 -0700260 return nil
261}
262
263func (c *config) PlatformVersion() string {
264 return "M"
265}
266
267func (c *config) PlatformSdkVersion() string {
268 return "22"
269}
270
271func (c *config) BuildNumber() string {
272 return "000000"
273}
274
275func (c *config) ProductAaptConfig() []string {
276 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
277}
278
279func (c *config) ProductAaptPreferredConfig() string {
280 return "xhdpi"
281}
282
283func (c *config) ProductAaptCharacteristics() string {
284 return "nosdcard"
285}
286
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700287func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
288 return PathForSource(ctx, "build/target/product/security")
Colin Cross30e076a2015-04-13 13:58:27 -0700289}
290
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700291func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
292 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
Colin Cross30e076a2015-04-13 13:58:27 -0700293}
Colin Cross6ff51382015-12-17 16:39:19 -0800294
295func (c *config) AllowMissingDependencies() bool {
296 return Bool(c.ProductVariables.Unbundled_build)
297}