blob: 0f65410fcfbc7d694ad054b750ec887245f8f3bd [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
Colin Crossa1ad8d12016-06-01 17:09:44 -070057 Targets map[OsClass][]Target
58 BuildOsVariant string
Dan Willemsen218f6562015-07-08 18:13:11 -070059
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
Colin Crossa1ad8d12016-06-01 17:09:44 -0700178 targets, err := decodeTargetProductVariables(config)
Dan Willemsen218f6562015-07-08 18:13:11 -0700179 if err != nil {
180 return Config{}, err
181 }
182
Dan Willemsen322acaf2016-01-12 23:07:05 -0800183 if Bool(config.Mega_device) {
Colin Crossa1ad8d12016-06-01 17:09:44 -0700184 deviceTargets, err := decodeMegaDevice()
Dan Willemsen322acaf2016-01-12 23:07:05 -0800185 if err != nil {
186 return Config{}, err
187 }
Colin Crossa1ad8d12016-06-01 17:09:44 -0700188 targets[Device] = deviceTargets
Dan Willemsen322acaf2016-01-12 23:07:05 -0800189 }
190
Colin Crossa1ad8d12016-06-01 17:09:44 -0700191 config.Targets = targets
192 config.BuildOsVariant = targets[Host][0].String()
Dan Willemsen218f6562015-07-08 18:13:11 -0700193
Colin Cross3f40fa42015-01-30 17:27:36 -0800194 return config, nil
195}
196
Dan Willemsen218f6562015-07-08 18:13:11 -0700197func (c *config) RemoveAbandonedFiles() bool {
198 return false
199}
200
Dan Willemsenc2aa4a92016-05-26 15:13:03 -0700201func (c *config) BlueprintToolLocation() string {
202 return filepath.Join(c.buildDir, "host", c.PrebuiltOS(), "bin")
203}
204
Colin Cross3f40fa42015-01-30 17:27:36 -0800205// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700206func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800207 switch runtime.GOOS {
208 case "linux":
209 return "linux-x86"
210 case "darwin":
211 return "darwin-x86"
212 default:
213 panic("Unknown GOOS")
214 }
215}
216
217// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700218func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800219 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
220}
221
Colin Cross1332b002015-04-07 17:11:30 -0700222func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700223 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800224 case "darwin":
225 return "-R"
226 case "linux":
227 return "-d"
228 default:
229 return ""
230 }
231}
Colin Cross68f55102015-03-25 14:43:57 -0700232
Colin Cross1332b002015-04-07 17:11:30 -0700233func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700234 var val string
235 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700236 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700237 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700238 if c.envFrozen {
239 panic("Cannot access new environment variables after envdeps are frozen")
240 }
Colin Cross68f55102015-03-25 14:43:57 -0700241 val = os.Getenv(key)
242 c.envDeps[key] = val
243 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700244 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700245 return val
246}
247
Colin Cross1332b002015-04-07 17:11:30 -0700248func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700249 c.envLock.Lock()
250 c.envFrozen = true
251 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700252 return c.envDeps
253}
Colin Cross35cec122015-04-02 14:37:16 -0700254
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800255func (c *config) EmbeddedInMake() bool {
256 return c.inMake
257}
258
Colin Cross35cec122015-04-02 14:37:16 -0700259// DeviceName returns the name of the current device target
260// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700261func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700262 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700263}
264
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700265func (c *config) DeviceUsesClang() bool {
266 if c.ProductVariables.DeviceUsesClang != nil {
267 return *c.ProductVariables.DeviceUsesClang
268 }
Dan Willemsen0084d782016-03-01 14:54:24 -0800269 return true
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700270}
271
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700272func (c *config) ResourceOverlays() []SourcePath {
Colin Cross30e076a2015-04-13 13:58:27 -0700273 return nil
274}
275
276func (c *config) PlatformVersion() string {
277 return "M"
278}
279
280func (c *config) PlatformSdkVersion() string {
281 return "22"
282}
283
284func (c *config) BuildNumber() string {
285 return "000000"
286}
287
288func (c *config) ProductAaptConfig() []string {
289 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
290}
291
292func (c *config) ProductAaptPreferredConfig() string {
293 return "xhdpi"
294}
295
296func (c *config) ProductAaptCharacteristics() string {
297 return "nosdcard"
298}
299
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700300func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
301 return PathForSource(ctx, "build/target/product/security")
Colin Cross30e076a2015-04-13 13:58:27 -0700302}
303
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700304func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
305 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
Colin Cross30e076a2015-04-13 13:58:27 -0700306}
Colin Cross6ff51382015-12-17 16:39:19 -0800307
308func (c *config) AllowMissingDependencies() bool {
Dan Willemsenb5038162016-03-16 12:35:33 -0700309 return Bool(c.ProductVariables.Allow_missing_dependencies)
Colin Cross6ff51382015-12-17 16:39:19 -0800310}
Dan Willemsen322acaf2016-01-12 23:07:05 -0800311
Dan Willemsen7f730fd2016-01-14 11:22:23 -0800312func (c *config) SkipDeviceInstall() bool {
Dan Willemsen322acaf2016-01-12 23:07:05 -0800313 return c.EmbeddedInMake() || Bool(c.Mega_device)
314}
Colin Cross16b23492016-01-06 14:41:07 -0800315
316func (c *config) SanitizeHost() []string {
317 if c.ProductVariables.SanitizeHost == nil {
318 return nil
319 }
Colin Crosscc85e682016-07-06 14:24:16 -0700320 return append([]string(nil), *c.ProductVariables.SanitizeHost...)
Colin Cross16b23492016-01-06 14:41:07 -0800321}
322
323func (c *config) SanitizeDevice() []string {
324 if c.ProductVariables.SanitizeDevice == nil {
325 return nil
326 }
Colin Crosscc85e682016-07-06 14:24:16 -0700327 return append([]string(nil), *c.ProductVariables.SanitizeDevice...)
Colin Cross16b23492016-01-06 14:41:07 -0800328}
Colin Crossa1ad8d12016-06-01 17:09:44 -0700329
330func (c *config) Android64() bool {
331 for _, t := range c.Targets[Device] {
332 if t.Arch.ArchType.Multilib == "lib64" {
333 return true
334 }
335 }
336
337 return false
338}