blob: 366bb6b6189b7a97606c0321edf4234238a324ee [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
95func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070096 RegisterSingletonType("makevars", makeVarsSingletonFunc)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080097}
98
Colin Cross0875c522017-11-28 17:34:01 -080099func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800100 return &makeVarsSingleton{}
101}
102
103type makeVarsSingleton struct{}
104
105type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800106 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800107 call MakeVarsProvider
108}
109
110var makeVarsProviders []makeVarsProvider
111
112type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800113 SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800114 config Config
Colin Cross0875c522017-11-28 17:34:01 -0800115 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800116 vars []makeVarsVariable
117}
118
119var _ MakeVarsContext = &makeVarsContext{}
120
121type makeVarsVariable struct {
122 name string
123 value string
124 sort bool
125 strict bool
126}
127
Colin Cross0875c522017-11-28 17:34:01 -0800128func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800129 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800130 return
131 }
132
Dan Willemsen45133ac2018-03-09 21:22:06 -0800133 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800134
135 if ctx.Failed() {
136 return
137 }
138
139 vars := []makeVarsVariable{}
140 for _, provider := range makeVarsProviders {
141 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800142 SingletonContext: ctx,
143 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800144 }
145
146 provider.call(mctx)
147
148 vars = append(vars, mctx.vars...)
149 }
150
151 if ctx.Failed() {
152 return
153 }
154
155 outBytes := s.writeVars(vars)
156
157 if _, err := os.Stat(outFile); err == nil {
158 if data, err := ioutil.ReadFile(outFile); err == nil {
159 if bytes.Equal(data, outBytes) {
160 return
161 }
162 }
163 }
164
165 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
166 ctx.Errorf(err.Error())
167 }
168}
169
170func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
171 buf := &bytes.Buffer{}
172
Dan Willemsen59339a22018-07-22 21:18:45 -0700173 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800174
175# Compares SOONG_$(1) against $(1), and warns if they are not equal.
176#
177# If the original variable is empty, then just set it to the SOONG_ version.
178#
179# $(1): Name of the variable to check
180# $(2): If not-empty, sort the values before comparing
181# $(3): Extra snippet to run if it does not match
182define soong-compare-var
183ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700184 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800185 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
186 ifneq ($$(my_val_make),$$(my_val_soong))
187 $$(warning $(1) does not match between Make and Soong:)
188 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
189 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
190 $(3)
191 endif
192 my_val_make :=
193 my_val_soong :=
194else
195 $(1) := $$(SOONG_$(1))
196endif
Dan Willemsende18f472016-09-30 10:16:38 -0700197.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800198endef
199
200my_check_failed := false
201
202`)
203
204 // Write all the strict checks out first so that if one of them errors,
205 // we get all of the strict errors printed, but not the non-strict
206 // warnings.
207 for _, v := range vars {
208 if !v.strict {
209 continue
210 }
211
212 sort := ""
213 if v.sort {
214 sort = "true"
215 }
216
217 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
218 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
219 }
220
Dan Willemsen59339a22018-07-22 21:18:45 -0700221 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800222ifneq ($(my_check_failed),false)
223 $(error Soong variable check failed)
224endif
225my_check_failed :=
226
227
228`)
229
230 for _, v := range vars {
231 if v.strict {
232 continue
233 }
234
235 sort := ""
236 if v.sort {
237 sort = "true"
238 }
239
240 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
241 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
242 }
243
244 fmt.Fprintln(buf, "\nsoong-compare-var :=")
245
246 return buf.Bytes()
247}
248
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700249func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800250 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900251}
252
Colin Cross31656952018-05-24 16:11:20 -0700253var ninjaDescaper = strings.NewReplacer("$$", "$")
254
Dan Willemsen558e5172016-05-19 16:58:46 -0700255func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800256 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700257 if err != nil {
258 return "", err
259 }
260 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
261 // in a Makefile
262 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700263}
264
265func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800266 c.vars = append(c.vars, makeVarsVariable{
267 name: name,
268 value: value,
269 strict: strict,
270 sort: sort,
271 })
272}
273
Dan Willemsen558e5172016-05-19 16:58:46 -0700274func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
275 value, err := c.Eval(ninjaStr)
276 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800277 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700278 }
279 c.addVariableRaw(name, value, strict, sort)
280}
281
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800282func (c *makeVarsContext) Strict(name, ninjaStr string) {
283 c.addVariable(name, ninjaStr, true, false)
284}
285func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
286 c.addVariable(name, ninjaStr, true, true)
287}
Dan Willemsen558e5172016-05-19 16:58:46 -0700288func (c *makeVarsContext) StrictRaw(name, value string) {
289 c.addVariableRaw(name, value, true, false)
290}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800291
292func (c *makeVarsContext) Check(name, ninjaStr string) {
293 c.addVariable(name, ninjaStr, false, false)
294}
295func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
296 c.addVariable(name, ninjaStr, false, true)
297}
Dan Willemsen558e5172016-05-19 16:58:46 -0700298func (c *makeVarsContext) CheckRaw(name, value string) {
299 c.addVariableRaw(name, value, false, false)
300}