blob: aba4ccec3ebca1aedf624396ec8868795ebdb942 [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"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080026 "github.com/google/blueprint/proptools"
27)
28
Dan Albertf5415d72017-08-17 16:19:59 -070029func init() {
30 RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
31}
32
33func androidMakeVarsProvider(ctx MakeVarsContext) {
34 ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion()))
35}
36
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080037///////////////////////////////////////////////////////////////////////////////
38// Interface for other packages to use to declare make variables
39type MakeVarsContext interface {
40 Config() Config
Dan Willemsen3fb1fae2018-03-12 15:30:26 -070041 DeviceConfig() DeviceConfig
Colin Cross65494b92019-02-07 14:25:51 -080042 AddNinjaFileDeps(deps ...string)
Colin Cross65494b92019-02-07 14:25:51 -080043
44 ModuleName(module blueprint.Module) string
45 ModuleDir(module blueprint.Module) string
46 ModuleSubDir(module blueprint.Module) string
47 ModuleType(module blueprint.Module) string
48 BlueprintFile(module blueprint.Module) string
49
50 ModuleErrorf(module blueprint.Module, format string, args ...interface{})
51 Errorf(format string, args ...interface{})
52 Failed() bool
53
54 VisitAllModules(visit func(Module))
55 VisitAllModulesIf(pred func(Module) bool, visit func(Module))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080056
57 // Verify the make variable matches the Soong version, fail the build
58 // if it does not. If the make variable is empty, just set it.
59 Strict(name, ninjaStr string)
60 // Check to see if the make variable matches the Soong version, warn if
61 // it does not. If the make variable is empty, just set it.
62 Check(name, ninjaStr string)
63
64 // These are equivalent to the above, but sort the make and soong
65 // variables before comparing them. They also show the unique entries
66 // in each list when displaying the difference, instead of the entire
67 // string.
68 StrictSorted(name, ninjaStr string)
69 CheckSorted(name, ninjaStr string)
Dan Willemsen558e5172016-05-19 16:58:46 -070070
71 // Evaluates a ninja string and returns the result. Used if more
72 // complicated modification needs to happen before giving it to Make.
73 Eval(ninjaStr string) (string, error)
74
75 // These are equivalent to Strict and Check, but do not attempt to
76 // evaluate the values before writing them to the Makefile. They can
77 // be used when all ninja variables have already been evaluated through
78 // Eval().
79 StrictRaw(name, value string)
80 CheckRaw(name, value string)
Colin Cross8177ad22019-11-04 10:27:48 -080081
82 // GlobWithDeps returns a list of files that match the specified pattern but do not match any
83 // of the patterns in excludes. It also adds efficient dependencies to rerun the primary
84 // builder whenever a file matching the pattern as added or removed, without rerunning if a
85 // file that does not match the pattern is added to a searched directory.
86 GlobWithDeps(pattern string, excludes []string) ([]string, error)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080087}
88
Colin Cross65494b92019-02-07 14:25:51 -080089var _ PathContext = MakeVarsContext(nil)
90
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080091type MakeVarsProvider func(ctx MakeVarsContext)
92
Colin Cross0875c522017-11-28 17:34:01 -080093func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080094 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
95}
96
Colin Crossed023ec2019-02-19 12:38:45 -080097// SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
98type SingletonMakeVarsProvider interface {
99 Singleton
100
101 // MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
102 MakeVars(ctx MakeVarsContext)
103}
104
105// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to the list of
106// MakeVarsProviders to run.
107func registerSingletonMakeVarsProvider(singleton SingletonMakeVarsProvider) {
108 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, SingletonmakeVarsProviderAdapter(singleton)})
109}
110
111// SingletonmakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
112func SingletonmakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeVarsProvider {
113 return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
114}
115
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800116///////////////////////////////////////////////////////////////////////////////
117
Colin Cross0875c522017-11-28 17:34:01 -0800118func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800119 return &makeVarsSingleton{}
120}
121
122type makeVarsSingleton struct{}
123
124type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800125 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800126 call MakeVarsProvider
127}
128
129var makeVarsProviders []makeVarsProvider
130
131type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800132 SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800133 config Config
Colin Cross0875c522017-11-28 17:34:01 -0800134 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800135 vars []makeVarsVariable
136}
137
138var _ MakeVarsContext = &makeVarsContext{}
139
140type makeVarsVariable struct {
141 name string
142 value string
143 sort bool
144 strict bool
145}
146
Colin Cross0875c522017-11-28 17:34:01 -0800147func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800148 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800149 return
150 }
151
Colin Cross988414c2020-01-11 01:11:46 +0000152 outFile := absolutePath(PathForOutput(ctx,
153 "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800154
155 if ctx.Failed() {
156 return
157 }
158
159 vars := []makeVarsVariable{}
160 for _, provider := range makeVarsProviders {
161 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800162 SingletonContext: ctx,
163 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800164 }
165
166 provider.call(mctx)
167
168 vars = append(vars, mctx.vars...)
169 }
170
171 if ctx.Failed() {
172 return
173 }
174
175 outBytes := s.writeVars(vars)
176
Colin Cross988414c2020-01-11 01:11:46 +0000177 if _, err := os.Stat(absolutePath(outFile)); err == nil {
178 if data, err := ioutil.ReadFile(absolutePath(outFile)); err == nil {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800179 if bytes.Equal(data, outBytes) {
180 return
181 }
182 }
183 }
184
Colin Cross988414c2020-01-11 01:11:46 +0000185 if err := ioutil.WriteFile(absolutePath(outFile), outBytes, 0666); err != nil {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800186 ctx.Errorf(err.Error())
187 }
188}
189
190func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
191 buf := &bytes.Buffer{}
192
Dan Willemsen59339a22018-07-22 21:18:45 -0700193 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800194
195# Compares SOONG_$(1) against $(1), and warns if they are not equal.
196#
197# If the original variable is empty, then just set it to the SOONG_ version.
198#
199# $(1): Name of the variable to check
200# $(2): If not-empty, sort the values before comparing
201# $(3): Extra snippet to run if it does not match
202define soong-compare-var
203ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700204 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800205 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
206 ifneq ($$(my_val_make),$$(my_val_soong))
207 $$(warning $(1) does not match between Make and Soong:)
208 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
209 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
210 $(3)
211 endif
212 my_val_make :=
213 my_val_soong :=
214else
215 $(1) := $$(SOONG_$(1))
216endif
Dan Willemsende18f472016-09-30 10:16:38 -0700217.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800218endef
219
220my_check_failed := false
221
222`)
223
224 // Write all the strict checks out first so that if one of them errors,
225 // we get all of the strict errors printed, but not the non-strict
226 // warnings.
227 for _, v := range vars {
228 if !v.strict {
229 continue
230 }
231
232 sort := ""
233 if v.sort {
234 sort = "true"
235 }
236
237 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
238 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
239 }
240
Dan Willemsen59339a22018-07-22 21:18:45 -0700241 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800242ifneq ($(my_check_failed),false)
243 $(error Soong variable check failed)
244endif
245my_check_failed :=
246
247
248`)
249
250 for _, v := range vars {
251 if v.strict {
252 continue
253 }
254
255 sort := ""
256 if v.sort {
257 sort = "true"
258 }
259
260 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
261 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
262 }
263
264 fmt.Fprintln(buf, "\nsoong-compare-var :=")
265
266 return buf.Bytes()
267}
268
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700269func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800270 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900271}
272
Colin Cross31656952018-05-24 16:11:20 -0700273var ninjaDescaper = strings.NewReplacer("$$", "$")
274
Dan Willemsen558e5172016-05-19 16:58:46 -0700275func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800276 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700277 if err != nil {
278 return "", err
279 }
280 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
281 // in a Makefile
282 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700283}
284
285func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800286 c.vars = append(c.vars, makeVarsVariable{
287 name: name,
288 value: value,
289 strict: strict,
290 sort: sort,
291 })
292}
293
Dan Willemsen558e5172016-05-19 16:58:46 -0700294func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
295 value, err := c.Eval(ninjaStr)
296 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800297 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700298 }
299 c.addVariableRaw(name, value, strict, sort)
300}
301
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800302func (c *makeVarsContext) Strict(name, ninjaStr string) {
303 c.addVariable(name, ninjaStr, true, false)
304}
305func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
306 c.addVariable(name, ninjaStr, true, true)
307}
Dan Willemsen558e5172016-05-19 16:58:46 -0700308func (c *makeVarsContext) StrictRaw(name, value string) {
309 c.addVariableRaw(name, value, true, false)
310}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800311
312func (c *makeVarsContext) Check(name, ninjaStr string) {
313 c.addVariable(name, ninjaStr, false, false)
314}
315func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
316 c.addVariable(name, ninjaStr, false, true)
317}
Dan Willemsen558e5172016-05-19 16:58:46 -0700318func (c *makeVarsContext) CheckRaw(name, value string) {
319 c.addVariableRaw(name, value, false, false)
320}