blob: 8701960e5cf3a5bb8fea05ec88595f9731eed4dc [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
Colin Cross3f40fa42015-01-30 17:27:36 -0800200// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700201func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800202 switch runtime.GOOS {
203 case "linux":
204 return "linux-x86"
205 case "darwin":
206 return "darwin-x86"
207 default:
208 panic("Unknown GOOS")
209 }
210}
211
212// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700213func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800214 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
215}
216
Colin Cross1332b002015-04-07 17:11:30 -0700217func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700218 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800219 case "darwin":
220 return "-R"
221 case "linux":
222 return "-d"
223 default:
224 return ""
225 }
226}
Colin Cross68f55102015-03-25 14:43:57 -0700227
Colin Cross1332b002015-04-07 17:11:30 -0700228func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700229 var val string
230 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700231 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700232 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700233 if c.envFrozen {
234 panic("Cannot access new environment variables after envdeps are frozen")
235 }
Colin Cross68f55102015-03-25 14:43:57 -0700236 val = os.Getenv(key)
237 c.envDeps[key] = val
238 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700239 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700240 return val
241}
242
Colin Cross1332b002015-04-07 17:11:30 -0700243func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700244 c.envLock.Lock()
245 c.envFrozen = true
246 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700247 return c.envDeps
248}
Colin Cross35cec122015-04-02 14:37:16 -0700249
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800250func (c *config) EmbeddedInMake() bool {
251 return c.inMake
252}
253
Colin Cross35cec122015-04-02 14:37:16 -0700254// DeviceName returns the name of the current device target
255// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700256func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700257 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700258}
259
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700260func (c *config) DeviceUsesClang() bool {
261 if c.ProductVariables.DeviceUsesClang != nil {
262 return *c.ProductVariables.DeviceUsesClang
263 }
Dan Willemsen0084d782016-03-01 14:54:24 -0800264 return true
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700265}
266
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700267func (c *config) ResourceOverlays() []SourcePath {
Colin Cross30e076a2015-04-13 13:58:27 -0700268 return nil
269}
270
271func (c *config) PlatformVersion() string {
272 return "M"
273}
274
275func (c *config) PlatformSdkVersion() string {
276 return "22"
277}
278
279func (c *config) BuildNumber() string {
280 return "000000"
281}
282
283func (c *config) ProductAaptConfig() []string {
284 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
285}
286
287func (c *config) ProductAaptPreferredConfig() string {
288 return "xhdpi"
289}
290
291func (c *config) ProductAaptCharacteristics() string {
292 return "nosdcard"
293}
294
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700295func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
296 return PathForSource(ctx, "build/target/product/security")
Colin Cross30e076a2015-04-13 13:58:27 -0700297}
298
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700299func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
300 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
Colin Cross30e076a2015-04-13 13:58:27 -0700301}
Colin Cross6ff51382015-12-17 16:39:19 -0800302
303func (c *config) AllowMissingDependencies() bool {
Dan Willemsenb5038162016-03-16 12:35:33 -0700304 return Bool(c.ProductVariables.Allow_missing_dependencies)
Colin Cross6ff51382015-12-17 16:39:19 -0800305}
Dan Willemsen322acaf2016-01-12 23:07:05 -0800306
Dan Willemsen7f730fd2016-01-14 11:22:23 -0800307func (c *config) SkipDeviceInstall() bool {
Dan Willemsen322acaf2016-01-12 23:07:05 -0800308 return c.EmbeddedInMake() || Bool(c.Mega_device)
309}
Colin Cross16b23492016-01-06 14:41:07 -0800310
311func (c *config) SanitizeHost() []string {
312 if c.ProductVariables.SanitizeHost == nil {
313 return nil
314 }
315 return *c.ProductVariables.SanitizeHost
316}
317
318func (c *config) SanitizeDevice() []string {
319 if c.ProductVariables.SanitizeDevice == nil {
320 return nil
321 }
322 return *c.ProductVariables.SanitizeDevice
323}