blob: 971c4c1179ec38c41788db7242d5a862181c5a09 [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 Cross3f40fa42015-01-30 17:27:36 -080025)
26
Colin Cross3f40fa42015-01-30 17:27:36 -080027// The configuration file name
Dan Willemsen87b17d12015-07-14 00:39:06 -070028const configFileName = "soong.config"
29const productVariablesFileName = "soong.variables"
Colin Cross3f40fa42015-01-30 17:27:36 -080030
31// A FileConfigurableOptions contains options which can be configured by the
32// config file. These will be included in the config struct.
33type FileConfigurableOptions struct {
34}
35
Colin Cross27385972015-09-18 10:57:10 -070036func (f *FileConfigurableOptions) SetDefaultConfig() {
37 *f = FileConfigurableOptions{}
Colin Cross3f40fa42015-01-30 17:27:36 -080038}
39
Colin Crossc3c0a492015-04-10 15:43:55 -070040type Config struct {
41 *config
42}
43
Dan Willemsen218f6562015-07-08 18:13:11 -070044// A config object represents the entire build configuration for Android.
Colin Cross1332b002015-04-07 17:11:30 -070045type config struct {
Colin Cross3f40fa42015-01-30 17:27:36 -080046 FileConfigurableOptions
Colin Cross485e5722015-08-27 13:28:01 -070047 ProductVariables productVariables
Colin Cross3f40fa42015-01-30 17:27:36 -080048
Dan Willemsen87b17d12015-07-14 00:39:06 -070049 ConfigFileName string
50 ProductVariablesFileName string
51
Dan Willemsen218f6562015-07-08 18:13:11 -070052 DeviceArches []Arch
53 HostArches map[HostType][]Arch
54
Dan Willemsen87b17d12015-07-14 00:39:06 -070055 srcDir string // the path of the root source directory
56 buildDir string // the path of the build output directory
Colin Crossc1e86a32015-04-15 12:33:28 -070057
Dan Willemsene7680ba2015-09-11 17:06:19 -070058 envLock sync.Mutex
59 envDeps map[string]string
60 envFrozen bool
Dan Willemsen5ba07e82015-12-11 13:51:06 -080061
62 inMake bool
Colin Cross3f40fa42015-01-30 17:27:36 -080063}
64
Colin Cross485e5722015-08-27 13:28:01 -070065type jsonConfigurable interface {
Colin Cross27385972015-09-18 10:57:10 -070066 SetDefaultConfig()
Colin Cross485e5722015-08-27 13:28:01 -070067}
Colin Cross3f40fa42015-01-30 17:27:36 -080068
Colin Cross485e5722015-08-27 13:28:01 -070069func loadConfig(config *config) error {
Dan Willemsen87b17d12015-07-14 00:39:06 -070070 err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName)
Colin Cross485e5722015-08-27 13:28:01 -070071 if err != nil {
72 return err
73 }
74
Dan Willemsen87b17d12015-07-14 00:39:06 -070075 return loadFromConfigFile(&config.ProductVariables, config.ProductVariablesFileName)
Colin Cross485e5722015-08-27 13:28:01 -070076}
77
78// loads configuration options from a JSON file in the cwd.
79func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -080080 // Try to open the file
Colin Cross485e5722015-08-27 13:28:01 -070081 configFileReader, err := os.Open(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080082 defer configFileReader.Close()
83 if os.IsNotExist(err) {
84 // Need to create a file, so that blueprint & ninja don't get in
85 // a dependency tracking loop.
86 // Make a file-configurable-options with defaults, write it out using
87 // a json writer.
Colin Cross27385972015-09-18 10:57:10 -070088 configurable.SetDefaultConfig()
89 err = saveToConfigFile(configurable, filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080090 if err != nil {
91 return err
92 }
93 } else {
94 // Make a decoder for it
95 jsonDecoder := json.NewDecoder(configFileReader)
Colin Cross485e5722015-08-27 13:28:01 -070096 err = jsonDecoder.Decode(configurable)
Colin Cross3f40fa42015-01-30 17:27:36 -080097 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -070098 return fmt.Errorf("config file: %s did not parse correctly: "+err.Error(), filename)
Colin Cross3f40fa42015-01-30 17:27:36 -080099 }
100 }
101
Colin Cross3f40fa42015-01-30 17:27:36 -0800102 // No error
103 return nil
104}
105
Colin Cross485e5722015-08-27 13:28:01 -0700106func saveToConfigFile(config jsonConfigurable, filename string) error {
Colin Cross3f40fa42015-01-30 17:27:36 -0800107 data, err := json.MarshalIndent(&config, "", " ")
108 if err != nil {
109 return fmt.Errorf("cannot marshal config data: %s", err.Error())
110 }
111
Colin Cross485e5722015-08-27 13:28:01 -0700112 configFileWriter, err := os.Create(filename)
Colin Cross3f40fa42015-01-30 17:27:36 -0800113 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700114 return fmt.Errorf("cannot create empty config file %s: %s\n", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800115 }
116 defer configFileWriter.Close()
117
118 _, err = configFileWriter.Write(data)
119 if err != nil {
Colin Cross485e5722015-08-27 13:28:01 -0700120 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
121 }
122
123 _, err = configFileWriter.WriteString("\n")
124 if err != nil {
125 return fmt.Errorf("default config file: %s could not be written: %s", filename, err.Error())
Colin Cross3f40fa42015-01-30 17:27:36 -0800126 }
127
128 return nil
129}
130
131// New creates a new Config object. The srcDir argument specifies the path to
132// the root source directory. It also loads the config file, if found.
Dan Willemsen87b17d12015-07-14 00:39:06 -0700133func NewConfig(srcDir, buildDir string) (Config, error) {
Colin Cross3f40fa42015-01-30 17:27:36 -0800134 // Make a config with default options
Colin Crossc3c0a492015-04-10 15:43:55 -0700135 config := Config{
136 config: &config{
Dan Willemsen87b17d12015-07-14 00:39:06 -0700137 ConfigFileName: filepath.Join(buildDir, configFileName),
138 ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
139
140 srcDir: srcDir,
141 buildDir: buildDir,
142 envDeps: make(map[string]string),
Colin Crossc3c0a492015-04-10 15:43:55 -0700143 },
Colin Cross68f55102015-03-25 14:43:57 -0700144 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800145
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700146 // Sanity check the build and source directories. This won't catch strange
147 // configurations with symlinks, but at least checks the obvious cases.
148 absBuildDir, err := filepath.Abs(buildDir)
149 if err != nil {
150 return Config{}, err
151 }
152
153 absSrcDir, err := filepath.Abs(srcDir)
154 if err != nil {
155 return Config{}, err
156 }
157
158 if strings.HasPrefix(absSrcDir, absBuildDir) {
159 return Config{}, fmt.Errorf("Build dir must not contain source directory")
160 }
161
Colin Cross3f40fa42015-01-30 17:27:36 -0800162 // Load any configurable options from the configuration file
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700163 err = loadConfig(config.config)
Colin Cross3f40fa42015-01-30 17:27:36 -0800164 if err != nil {
Colin Crossc3c0a492015-04-10 15:43:55 -0700165 return Config{}, err
Colin Cross3f40fa42015-01-30 17:27:36 -0800166 }
167
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800168 inMakeFile := filepath.Join(buildDir, ".soong.in_make")
169 if _, err := os.Stat(inMakeFile); err == nil {
170 config.inMake = true
171 }
172
Dan Willemsen218f6562015-07-08 18:13:11 -0700173 hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
174 if err != nil {
175 return Config{}, err
176 }
177
178 config.HostArches = hostArches
179 config.DeviceArches = deviceArches
180
Colin Cross3f40fa42015-01-30 17:27:36 -0800181 return config, nil
182}
183
Dan Willemsen218f6562015-07-08 18:13:11 -0700184func (c *config) RemoveAbandonedFiles() bool {
185 return false
186}
187
Colin Cross3f40fa42015-01-30 17:27:36 -0800188// PrebuiltOS returns the name of the host OS used in prebuilts directories
Colin Cross1332b002015-04-07 17:11:30 -0700189func (c *config) PrebuiltOS() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800190 switch runtime.GOOS {
191 case "linux":
192 return "linux-x86"
193 case "darwin":
194 return "darwin-x86"
195 default:
196 panic("Unknown GOOS")
197 }
198}
199
200// GoRoot returns the path to the root directory of the Go toolchain.
Colin Cross1332b002015-04-07 17:11:30 -0700201func (c *config) GoRoot() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800202 return fmt.Sprintf("%s/prebuilts/go/%s", c.srcDir, c.PrebuiltOS())
203}
204
Colin Cross1332b002015-04-07 17:11:30 -0700205func (c *config) CpPreserveSymlinksFlags() string {
Colin Cross485e5722015-08-27 13:28:01 -0700206 switch runtime.GOOS {
Colin Cross3f40fa42015-01-30 17:27:36 -0800207 case "darwin":
208 return "-R"
209 case "linux":
210 return "-d"
211 default:
212 return ""
213 }
214}
Colin Cross68f55102015-03-25 14:43:57 -0700215
Colin Cross1332b002015-04-07 17:11:30 -0700216func (c *config) Getenv(key string) string {
Colin Cross68f55102015-03-25 14:43:57 -0700217 var val string
218 var exists bool
Colin Crossc1e86a32015-04-15 12:33:28 -0700219 c.envLock.Lock()
Colin Cross68f55102015-03-25 14:43:57 -0700220 if val, exists = c.envDeps[key]; !exists {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700221 if c.envFrozen {
222 panic("Cannot access new environment variables after envdeps are frozen")
223 }
Colin Cross68f55102015-03-25 14:43:57 -0700224 val = os.Getenv(key)
225 c.envDeps[key] = val
226 }
Colin Crossc1e86a32015-04-15 12:33:28 -0700227 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700228 return val
229}
230
Colin Cross1332b002015-04-07 17:11:30 -0700231func (c *config) EnvDeps() map[string]string {
Dan Willemsene7680ba2015-09-11 17:06:19 -0700232 c.envLock.Lock()
233 c.envFrozen = true
234 c.envLock.Unlock()
Colin Cross68f55102015-03-25 14:43:57 -0700235 return c.envDeps
236}
Colin Cross35cec122015-04-02 14:37:16 -0700237
Dan Willemsen5ba07e82015-12-11 13:51:06 -0800238func (c *config) EmbeddedInMake() bool {
239 return c.inMake
240}
241
Colin Cross35cec122015-04-02 14:37:16 -0700242// DeviceName returns the name of the current device target
243// TODO: take an AndroidModuleContext to select the device name for multi-device builds
Colin Cross1332b002015-04-07 17:11:30 -0700244func (c *config) DeviceName() string {
Dan Willemsen1d31ec32015-09-22 16:56:09 -0700245 return *c.ProductVariables.DeviceName
Colin Cross35cec122015-04-02 14:37:16 -0700246}
247
Dan Willemsendd0e2c32015-10-20 14:29:35 -0700248func (c *config) DeviceUsesClang() bool {
249 if c.ProductVariables.DeviceUsesClang != nil {
250 return *c.ProductVariables.DeviceUsesClang
251 }
252 return false
253}
254
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700255func (c *config) ResourceOverlays() []SourcePath {
Colin Cross30e076a2015-04-13 13:58:27 -0700256 return nil
257}
258
259func (c *config) PlatformVersion() string {
260 return "M"
261}
262
263func (c *config) PlatformSdkVersion() string {
264 return "22"
265}
266
267func (c *config) BuildNumber() string {
268 return "000000"
269}
270
271func (c *config) ProductAaptConfig() []string {
272 return []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}
273}
274
275func (c *config) ProductAaptPreferredConfig() string {
276 return "xhdpi"
277}
278
279func (c *config) ProductAaptCharacteristics() string {
280 return "nosdcard"
281}
282
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700283func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
284 return PathForSource(ctx, "build/target/product/security")
Colin Cross30e076a2015-04-13 13:58:27 -0700285}
286
Dan Willemsen34cc69e2015-09-23 15:26:20 -0700287func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
288 return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
Colin Cross30e076a2015-04-13 13:58:27 -0700289}