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"
Colin Cross47e4f9e2020-01-10 18:51:04 +000026 "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)
Colin Cross47e4f9e2020-01-10 18:51:04 +000044 Fs() pathtools.FileSystem
Colin Cross65494b92019-02-07 14:25:51 -080045
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
Colin Cross47e4f9e2020-01-10 18:51:04 +0000154 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
Colin Cross47e4f9e2020-01-10 18:51:04 +0000178 if _, err := os.Stat(outFile); err == nil {
179 if data, err := ioutil.ReadFile(outFile); err == nil {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800180 if bytes.Equal(data, outBytes) {
181 return
182 }
183 }
184 }
185
Colin Cross47e4f9e2020-01-10 18:51:04 +0000186 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800187 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}