blob: 2c2fb6f3cc1841a5fa0c9a9bd681227db9320bc7 [file] [log] [blame]
Dan Willemsen4b7d5de2016-01-12 23:20:28 -08001// Copyright 2016 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
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080016
17import (
18 "bytes"
19 "fmt"
20 "io/ioutil"
21 "os"
Dan Albertf5415d72017-08-17 16:19:59 -070022 "strconv"
Colin Cross31656952018-05-24 16:11:20 -070023 "strings"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080024
Colin Cross65494b92019-02-07 14:25:51 -080025 "github.com/google/blueprint"
26 "github.com/google/blueprint/pathtools"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080027 "github.com/google/blueprint/proptools"
28)
29
Dan Albertf5415d72017-08-17 16:19:59 -070030func init() {
31 RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
32}
33
34func androidMakeVarsProvider(ctx MakeVarsContext) {
35 ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion()))
36}
37
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080038///////////////////////////////////////////////////////////////////////////////
39// Interface for other packages to use to declare make variables
40type MakeVarsContext interface {
41 Config() Config
Dan Willemsen3fb1fae2018-03-12 15:30:26 -070042 DeviceConfig() DeviceConfig
Colin Cross65494b92019-02-07 14:25:51 -080043 AddNinjaFileDeps(deps ...string)
44 Fs() pathtools.FileSystem
45
46 ModuleName(module blueprint.Module) string
47 ModuleDir(module blueprint.Module) string
48 ModuleSubDir(module blueprint.Module) string
49 ModuleType(module blueprint.Module) string
50 BlueprintFile(module blueprint.Module) string
51
52 ModuleErrorf(module blueprint.Module, format string, args ...interface{})
53 Errorf(format string, args ...interface{})
54 Failed() bool
55
56 VisitAllModules(visit func(Module))
57 VisitAllModulesIf(pred func(Module) bool, visit func(Module))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080058
59 // Verify the make variable matches the Soong version, fail the build
60 // if it does not. If the make variable is empty, just set it.
61 Strict(name, ninjaStr string)
62 // Check to see if the make variable matches the Soong version, warn if
63 // it does not. If the make variable is empty, just set it.
64 Check(name, ninjaStr string)
65
66 // These are equivalent to the above, but sort the make and soong
67 // variables before comparing them. They also show the unique entries
68 // in each list when displaying the difference, instead of the entire
69 // string.
70 StrictSorted(name, ninjaStr string)
71 CheckSorted(name, ninjaStr string)
Dan Willemsen558e5172016-05-19 16:58:46 -070072
73 // Evaluates a ninja string and returns the result. Used if more
74 // complicated modification needs to happen before giving it to Make.
75 Eval(ninjaStr string) (string, error)
76
77 // These are equivalent to Strict and Check, but do not attempt to
78 // evaluate the values before writing them to the Makefile. They can
79 // be used when all ninja variables have already been evaluated through
80 // Eval().
81 StrictRaw(name, value string)
82 CheckRaw(name, value string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080083}
84
Colin Cross65494b92019-02-07 14:25:51 -080085var _ PathContext = MakeVarsContext(nil)
86
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080087type MakeVarsProvider func(ctx MakeVarsContext)
88
Colin Cross0875c522017-11-28 17:34:01 -080089func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080090 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
91}
92
93///////////////////////////////////////////////////////////////////////////////
94
Colin Cross0875c522017-11-28 17:34:01 -080095func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080096 return &makeVarsSingleton{}
97}
98
99type makeVarsSingleton struct{}
100
101type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800102 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800103 call MakeVarsProvider
104}
105
106var makeVarsProviders []makeVarsProvider
107
108type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800109 SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800110 config Config
Colin Cross0875c522017-11-28 17:34:01 -0800111 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800112 vars []makeVarsVariable
113}
114
115var _ MakeVarsContext = &makeVarsContext{}
116
117type makeVarsVariable struct {
118 name string
119 value string
120 sort bool
121 strict bool
122}
123
Colin Cross0875c522017-11-28 17:34:01 -0800124func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800125 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800126 return
127 }
128
Dan Willemsen45133ac2018-03-09 21:22:06 -0800129 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800130
131 if ctx.Failed() {
132 return
133 }
134
135 vars := []makeVarsVariable{}
136 for _, provider := range makeVarsProviders {
137 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800138 SingletonContext: ctx,
139 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800140 }
141
142 provider.call(mctx)
143
144 vars = append(vars, mctx.vars...)
145 }
146
147 if ctx.Failed() {
148 return
149 }
150
151 outBytes := s.writeVars(vars)
152
153 if _, err := os.Stat(outFile); err == nil {
154 if data, err := ioutil.ReadFile(outFile); err == nil {
155 if bytes.Equal(data, outBytes) {
156 return
157 }
158 }
159 }
160
161 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
162 ctx.Errorf(err.Error())
163 }
164}
165
166func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
167 buf := &bytes.Buffer{}
168
Dan Willemsen59339a22018-07-22 21:18:45 -0700169 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800170
171# Compares SOONG_$(1) against $(1), and warns if they are not equal.
172#
173# If the original variable is empty, then just set it to the SOONG_ version.
174#
175# $(1): Name of the variable to check
176# $(2): If not-empty, sort the values before comparing
177# $(3): Extra snippet to run if it does not match
178define soong-compare-var
179ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700180 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800181 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
182 ifneq ($$(my_val_make),$$(my_val_soong))
183 $$(warning $(1) does not match between Make and Soong:)
184 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
185 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
186 $(3)
187 endif
188 my_val_make :=
189 my_val_soong :=
190else
191 $(1) := $$(SOONG_$(1))
192endif
Dan Willemsende18f472016-09-30 10:16:38 -0700193.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800194endef
195
196my_check_failed := false
197
198`)
199
200 // Write all the strict checks out first so that if one of them errors,
201 // we get all of the strict errors printed, but not the non-strict
202 // warnings.
203 for _, v := range vars {
204 if !v.strict {
205 continue
206 }
207
208 sort := ""
209 if v.sort {
210 sort = "true"
211 }
212
213 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
214 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
215 }
216
Dan Willemsen59339a22018-07-22 21:18:45 -0700217 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800218ifneq ($(my_check_failed),false)
219 $(error Soong variable check failed)
220endif
221my_check_failed :=
222
223
224`)
225
226 for _, v := range vars {
227 if v.strict {
228 continue
229 }
230
231 sort := ""
232 if v.sort {
233 sort = "true"
234 }
235
236 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
237 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
238 }
239
240 fmt.Fprintln(buf, "\nsoong-compare-var :=")
241
242 return buf.Bytes()
243}
244
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700245func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800246 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900247}
248
Colin Cross31656952018-05-24 16:11:20 -0700249var ninjaDescaper = strings.NewReplacer("$$", "$")
250
Dan Willemsen558e5172016-05-19 16:58:46 -0700251func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800252 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700253 if err != nil {
254 return "", err
255 }
256 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
257 // in a Makefile
258 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700259}
260
261func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800262 c.vars = append(c.vars, makeVarsVariable{
263 name: name,
264 value: value,
265 strict: strict,
266 sort: sort,
267 })
268}
269
Dan Willemsen558e5172016-05-19 16:58:46 -0700270func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
271 value, err := c.Eval(ninjaStr)
272 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800273 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700274 }
275 c.addVariableRaw(name, value, strict, sort)
276}
277
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800278func (c *makeVarsContext) Strict(name, ninjaStr string) {
279 c.addVariable(name, ninjaStr, true, false)
280}
281func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
282 c.addVariable(name, ninjaStr, true, true)
283}
Dan Willemsen558e5172016-05-19 16:58:46 -0700284func (c *makeVarsContext) StrictRaw(name, value string) {
285 c.addVariableRaw(name, value, true, false)
286}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800287
288func (c *makeVarsContext) Check(name, ninjaStr string) {
289 c.addVariable(name, ninjaStr, false, false)
290}
291func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
292 c.addVariable(name, ninjaStr, false, true)
293}
Dan Willemsen558e5172016-05-19 16:58:46 -0700294func (c *makeVarsContext) CheckRaw(name, value string) {
295 c.addVariableRaw(name, value, false, false)
296}