blob: 38a028cafbac21bf0ea8052f94268b07a9044fc2 [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)
Colin Cross8177ad22019-11-04 10:27:48 -080083
84 // GlobWithDeps returns a list of files that match the specified pattern but do not match any
85 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary
86 // builder whenever a file matching the pattern as added or removed, without rerunning if a
87 // file that does not match the pattern is added to a searched directory.
88 GlobWithDeps(pattern string, excludes []string) ([]string, error)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080089}
90
Colin Cross65494b92019-02-07 14:25:51 -080091var _ PathContext = MakeVarsContext(nil)
92
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080093type MakeVarsProvider func(ctx MakeVarsContext)
94
Colin Cross0875c522017-11-28 17:34:01 -080095func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080096 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
97}
98
Colin Crossed023ec2019-02-19 12:38:45 -080099// SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
100type SingletonMakeVarsProvider interface {
101 Singleton
102
103 // MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
104 MakeVars(ctx MakeVarsContext)
105}
106
107// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to the list of
108// MakeVarsProviders to run.
109func registerSingletonMakeVarsProvider(singleton SingletonMakeVarsProvider) {
110 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, SingletonmakeVarsProviderAdapter(singleton)})
111}
112
113// SingletonmakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
114func SingletonmakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeVarsProvider {
115 return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
116}
117
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800118///////////////////////////////////////////////////////////////////////////////
119
Colin Cross0875c522017-11-28 17:34:01 -0800120func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800121 return &makeVarsSingleton{}
122}
123
124type makeVarsSingleton struct{}
125
126type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800127 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800128 call MakeVarsProvider
129}
130
131var makeVarsProviders []makeVarsProvider
132
133type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800134 SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800135 config Config
Colin Cross0875c522017-11-28 17:34:01 -0800136 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800137 vars []makeVarsVariable
138}
139
140var _ MakeVarsContext = &makeVarsContext{}
141
142type makeVarsVariable struct {
143 name string
144 value string
145 sort bool
146 strict bool
147}
148
Colin Cross0875c522017-11-28 17:34:01 -0800149func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800150 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800151 return
152 }
153
Dan Willemsen45133ac2018-03-09 21:22:06 -0800154 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800155
156 if ctx.Failed() {
157 return
158 }
159
160 vars := []makeVarsVariable{}
161 for _, provider := range makeVarsProviders {
162 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800163 SingletonContext: ctx,
164 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800165 }
166
167 provider.call(mctx)
168
169 vars = append(vars, mctx.vars...)
170 }
171
172 if ctx.Failed() {
173 return
174 }
175
176 outBytes := s.writeVars(vars)
177
178 if _, err := os.Stat(outFile); err == nil {
179 if data, err := ioutil.ReadFile(outFile); err == nil {
180 if bytes.Equal(data, outBytes) {
181 return
182 }
183 }
184 }
185
186 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
187 ctx.Errorf(err.Error())
188 }
189}
190
191func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
192 buf := &bytes.Buffer{}
193
Dan Willemsen59339a22018-07-22 21:18:45 -0700194 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800195
196# Compares SOONG_$(1) against $(1), and warns if they are not equal.
197#
198# If the original variable is empty, then just set it to the SOONG_ version.
199#
200# $(1): Name of the variable to check
201# $(2): If not-empty, sort the values before comparing
202# $(3): Extra snippet to run if it does not match
203define soong-compare-var
204ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700205 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800206 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
207 ifneq ($$(my_val_make),$$(my_val_soong))
208 $$(warning $(1) does not match between Make and Soong:)
209 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
210 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
211 $(3)
212 endif
213 my_val_make :=
214 my_val_soong :=
215else
216 $(1) := $$(SOONG_$(1))
217endif
Dan Willemsende18f472016-09-30 10:16:38 -0700218.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800219endef
220
221my_check_failed := false
222
223`)
224
225 // Write all the strict checks out first so that if one of them errors,
226 // we get all of the strict errors printed, but not the non-strict
227 // warnings.
228 for _, v := range vars {
229 if !v.strict {
230 continue
231 }
232
233 sort := ""
234 if v.sort {
235 sort = "true"
236 }
237
238 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
239 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
240 }
241
Dan Willemsen59339a22018-07-22 21:18:45 -0700242 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800243ifneq ($(my_check_failed),false)
244 $(error Soong variable check failed)
245endif
246my_check_failed :=
247
248
249`)
250
251 for _, v := range vars {
252 if v.strict {
253 continue
254 }
255
256 sort := ""
257 if v.sort {
258 sort = "true"
259 }
260
261 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
262 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
263 }
264
265 fmt.Fprintln(buf, "\nsoong-compare-var :=")
266
267 return buf.Bytes()
268}
269
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700270func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800271 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900272}
273
Colin Cross31656952018-05-24 16:11:20 -0700274var ninjaDescaper = strings.NewReplacer("$$", "$")
275
Dan Willemsen558e5172016-05-19 16:58:46 -0700276func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800277 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700278 if err != nil {
279 return "", err
280 }
281 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
282 // in a Makefile
283 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700284}
285
286func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800287 c.vars = append(c.vars, makeVarsVariable{
288 name: name,
289 value: value,
290 strict: strict,
291 sort: sort,
292 })
293}
294
Dan Willemsen558e5172016-05-19 16:58:46 -0700295func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
296 value, err := c.Eval(ninjaStr)
297 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800298 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700299 }
300 c.addVariableRaw(name, value, strict, sort)
301}
302
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800303func (c *makeVarsContext) Strict(name, ninjaStr string) {
304 c.addVariable(name, ninjaStr, true, false)
305}
306func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
307 c.addVariable(name, ninjaStr, true, true)
308}
Dan Willemsen558e5172016-05-19 16:58:46 -0700309func (c *makeVarsContext) StrictRaw(name, value string) {
310 c.addVariableRaw(name, value, true, false)
311}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800312
313func (c *makeVarsContext) Check(name, ninjaStr string) {
314 c.addVariable(name, ninjaStr, false, false)
315}
316func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
317 c.addVariable(name, ninjaStr, false, true)
318}
Dan Willemsen558e5172016-05-19 16:58:46 -0700319func (c *makeVarsContext) CheckRaw(name, value string) {
320 c.addVariableRaw(name, value, false, false)
321}