blob: ee95d2efd072165c4d98457682957cb0b1603488 [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 Cross635c3b02016-05-18 15:37:25 -070015package android
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 {
Dan Willemsen322acaf2016-01-12 23:07:05 -080038 Mega_device *bool `json:",omitempty"`
Colin Cross3f40fa42015-01-30 17:27:36 -080039}
40
Colin Cross27385972015-09-18 10:57:10 -070041func (f *FileConfigurableOptions) SetDefaultConfig() {
42 *f = FileConfigurableOptions{}
Colin Cross3f40fa42015-01-30 17:27:36 -080043}
44
Colin Crossc3c0a492015-04-10 15:43:55 -070045type Config struct {
46 *config
47}
48
Dan Willemsen218f6562015-07-08 18:13:11 -070049// A config object represents the entire build configuration for Android.
Colin Cross1332b002015-04-07 17:11:30 -070050type config struct {
Colin Cross3f40fa42015-01-30 17:27:36 -080051 FileConfigurableOptions
Colin Cross485e5722015-08-27 13:28:01 -070052 ProductVariables productVariables
Colin Cross3f40fa42015-01-30 17:27:36 -080053
Dan Willemsen87b17d12015-07-14 00:39:06 -070054 ConfigFileName string
55 ProductVariablesFileName string
56
Dan Willemsen218f6562015-07-08 18:13:11 -070057 DeviceArches []Arch
58 HostArches map[HostType][]Arch
59
Dan Willemsen87b17d12015-07-14 00:39:06 -070060 srcDir string // the path of the root source directory
61 buildDir string // the path of the build output directory
Colin Crossc1e86a32015-04-15 12:33:28 -070062
Dan Willemsene7680ba2015-09-11 17:06:19 -070063 envLock sync.Mutex
64 envDeps map[string]string
65 envFrozen bool
Dan Willemsen5ba07e82015-12-11 13:51:06 -080066
67 inMake bool
Colin Cross3f40fa42015-01-30 17:27:36 -080068}
69
Colin Cross485e5722015-08-27 13:28:01 -070070type jsonConfigurable interface {
Colin Cross27385972015-09-18 10:57:10 -070071 SetDefaultConfig()
Colin Cross485e5722015-08-27 13:28:01 -070072}
Colin Cross3f40fa42015-01-30 17:27:36 -080073
Colin Cross485e5722015-08-27 13:28:01 -070074func loadConfig(config *config) error {
Dan Willemsen87b17d12015-07-14 00:39:06 -070075 err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName)
Colin Cross485e5722015-08-27 13:28:01 -070076 if err != nil {
77 return err
78 }
79
Dan Willemsen87b17d12015-07-14 00:39:06 -070080 return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
Colin Cross485e5722015-08-27 13:28:01 -070081}
82
83// loads configuration options from a JSON file in the cwd.
84func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -080085 // Try to open the file
Colin Cross485e5722015-08-27 13:28:01 -070086 configFileReader, err := os.Open(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080087 defer configFileReader.Close()
88 if os.IsNotExist(err) {
89 // Need to create a file, so that blueprint & ninja don't get in
90 // a dependency tracking loop.
91 // Make a file-configurable-options with defaults, write it out using
92 // a json writer.
Colin Cross27385972015-09-18 10:57:10 -070093 configurable.SetDefaultConfig()
94 err = saveToConfigFile(configurable, filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080095 if err != nil {
96 return err
97 }
98 } else {
99 // Make a decoder for it
100 jsonDecoder := json.NewDecoder(configFileReader)
Colin Cross485e5722015-08-27 13:28:01 -0700101 err = jsonDecoder.Decode(configurable)
Colin Cross3f40fa42015-01-30 17:27:36 -0800102 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700103 return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800104 }
105 }
106
Colin Cross3f40fa42015-01-30 17:27:36 -0800107 // No error
108 return nil
109}
110
Colin Cross485e5722015-08-27 13:28:01 -0700111func saveToConfigFile(config jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -0800112 data, err := json.MarshalIndent(&config, "", " ")
113 if err != nil {
114 return fmt.Errorf("cannot marshal config data: %s", err.Error())
115 }
116
Colin Cross485e5722015-08-27 13:28:01 -0700117 configFileWriter, err := os.Create(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800118 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700119 return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800120 }
121 defer configFileWriter.Close()
122
123 _, err = configFileWriter.Write(data)
124 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700125 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
126 }
127
128 _, err = configFileWriter.WriteString("\n")
129 if err != nil {
130 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800131 }
132
133 return nil
134}
135
136// New creates a new Config object. The srcDir argument specifies the path to
137// the root source directory. It also loads the config file, if found.
Dan Willemsen87b17d12015-07-14 00:39:06 -0700138func NewConfig(srcDir, buildDir string) (Config, error) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800139 // Make a config with default options
Colin Crossc3c0a492015-04-10 15:43:55 -0700140 config := Config{
141 config: &config{
Dan Willemsen87b17d12015-07-14 00:39:06 -0700142 ConfigFileName: filepath.Join(buildDir, configFileName),
143 ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
144
145 srcDir: srcDir,
146 buildDir: buildDir,
147 envDeps: make(map[string]string),
Colin Crossc3c0a492015-04-10 15:43:55 -0700148 },
Colin Cross68f55102015-03-25 14:43:57 -0700149 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800150
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700151 // Sanity check the build and source directories. This won't catch strange
152 // configurations with symlinks, but at least checks the obvious cases.
153 absBuildDir, err := filepath.Abs(buildDir)
154 if err != nil {
155 return Config{}, err
156 }
157
158 absSrcDir, err := filepath.Abs(srcDir)
159 if err != nil {
160 return Config{}, err
161 }
162
163 if strings.HasPrefix(absSrcDir, absBuildDir) {
164 return Config{}, fmt.Errorf("Build dir must not contain source directory")
165 }
166
Colin Cross3f40fa42015-01-30 17:27:36 -0800167 // Load any configurable options from the configuration file
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700168 err = loadConfig(config.config)
Colin Cross3f40fa42015-01-30 17:27:36 -0800169 if err != nil {
Colin Crossc3c0a492015-04-10 15:43:55 -0700170 return Config{}, err
Colin Cross3f40fa42015-01-30 17:27:36 -0800171 }
172
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800173 inMakeFile := filepath.Join(buildDir, ".soong.in_make")
174 if _, err := os.Stat(inMakeFile); err == nil {
175 config.inMake = true
176 }
177
Dan Willemsen218f6562015-07-08 18:13:11 -0700178 hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
179 if err != nil {
180 return Config{}, err
181 }
182
Dan Willemsen322acaf2016-01-12 23:07:05 -0800183 if Bool(config.Mega_device) {
184 deviceArches, err = decodeMegaDevice()
185 if err != nil {
186 return Config{}, err
187 }
188 }
189
Dan Willemsen218f6562015-07-08 18:13:11 -0700190 config.HostArches = hostArches
191 config.DeviceArches = deviceArches
192
Colin Cross3f40fa42015-01-30 17:27:36 -0800193 return config, nil
194}
195
Dan Willemsen218f6562015-07-08 18:13:11 -0700196func (c *config) RemoveAbandonedFiles() bool {
197 return false
198}
199
Dan Willemsenc2aa4a92016-05-26 15:13:03 -0700200func (c *config) BlueprintToolLocation() string {
201 return filepath.Join(c.buildDir, "host", c.PrebuiltOS(), "bin")
202}
203
Colin Cross3f40fa42015-01-30 17:27:36 -0800204// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700205func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800206 switch runtime.GOOS {
207 case "linux":
208 return "linux-x86"
209 case "darwin":
210 return "darwin-x86"
211 default:
212 panic("Unknown GOOS")
213 }
214}
215
216// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700217func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800218 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
219}
220
Colin Cross1332b002015-04-07 17:11:30 -0700221func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700222 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800223 case "darwin":
224 return "-R"
225 case "linux":
226 return "-d"
227 default:
228 return ""
229 }
230}
Colin Cross68f55102015-03-25 14:43:57 -0700231
Colin Cross1332b002015-04-07 17:11:30 -0700232func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700233 var val string
234 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700235 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700236 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700237 if c.envFrozen {
238 panic("Cannot access new environment variables after envdeps are frozen")
239 }
Colin Cross68f55102015-03-25 14:43:57 -0700240 val = os.Getenv(key)
241 c.envDeps[key] = val
242 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700243 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700244 return val
245}
246
Colin Cross1332b002015-04-07 17:11:30 -0700247func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700248 c.envLock.Lock()
249 c.envFrozen = true
250 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700251 return c.envDeps
252}
Colin Cross35cec122015-04-02 14:37:16 -0700253
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800254func (c *config) EmbeddedInMake() bool {
255 return c.inMake
256}
257
Colin Cross35cec122015-04-02 14:37:16 -0700258// DeviceName returns the name of the current device target
259// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700260func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700261 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700262}
263
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700264func (c *config) DeviceUsesClang() bool {
265 if c.ProductVariables.DeviceUsesClang != nil {
266 return *c.ProductVariables.DeviceUsesClang
267 }
Dan Willemsen0084d782016-03-01 14:54:24 -0800268 return true
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700269}
270
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700271func (c *config) ResourceOverlays() []SourcePath {
Colin Cross30e076a2015-04-13 13:58:27 -0700272 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
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700299func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
300 return PathForSource(ctx, "build/target/product/security")
Colin Cross30e076a2015-04-13 13:58:27 -0700301}
302
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700303func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
304 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
Colin Cross30e076a2015-04-13 13:58:27 -0700305}
Colin Cross6ff51382015-12-17 16:39:19 -0800306
307func (c *config) AllowMissingDependencies() bool {
Dan Willemsenb5038162016-03-16 12:35:33 -0700308 return Bool(c.ProductVariables.Allow_missing_dependencies)
Colin Cross6ff51382015-12-17 16:39:19 -0800309}
Dan Willemsen322acaf2016-01-12 23:07:05 -0800310
Dan Willemsen7f730fd2016-01-14 11:22:23 -0800311func (c *config) SkipDeviceInstall() bool {
Dan Willemsen322acaf2016-01-12 23:07:05 -0800312 return c.EmbeddedInMake() || Bool(c.Mega_device)
313}
Colin Cross16b23492016-01-06 14:41:07 -0800314
315func (c *config) SanitizeHost() []string {
316 if c.ProductVariables.SanitizeHost == nil {
317 return nil
318 }
319 return *c.ProductVariables.SanitizeHost
320}
321
322func (c *config) SanitizeDevice() []string {
323 if c.ProductVariables.SanitizeDevice == nil {
324 return nil
325 }
326 return *c.ProductVariables.SanitizeDevice
327}