blob: c011ea61fda2aca26648a17a1b53f9fbc006c0b5 [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
Colin Crossed023ec2019-02-19 12:38:45 -080093// SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
94type SingletonMakeVarsProvider interface {
95 Singleton
96
97 // MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
98 MakeVars(ctx MakeVarsContext)
99}
100
101// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to the list of
102// MakeVarsProviders to run.
103func registerSingletonMakeVarsProvider(singleton SingletonMakeVarsProvider) {
104 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, SingletonmakeVarsProviderAdapter(singleton)})
105}
106
107// SingletonmakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
108func SingletonmakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeVarsProvider {
109 return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
110}
111
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800112///////////////////////////////////////////////////////////////////////////////
113
Colin Cross0875c522017-11-28 17:34:01 -0800114func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800115 return &makeVarsSingleton{}
116}
117
118type makeVarsSingleton struct{}
119
120type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -0800121 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800122 call MakeVarsProvider
123}
124
125var makeVarsProviders []makeVarsProvider
126
127type makeVarsContext struct {
Colin Cross65494b92019-02-07 14:25:51 -0800128 SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800129 config Config
Colin Cross0875c522017-11-28 17:34:01 -0800130 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800131 vars []makeVarsVariable
132}
133
134var _ MakeVarsContext = &makeVarsContext{}
135
136type makeVarsVariable struct {
137 name string
138 value string
139 sort bool
140 strict bool
141}
142
Colin Cross0875c522017-11-28 17:34:01 -0800143func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800144 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800145 return
146 }
147
Dan Willemsen45133ac2018-03-09 21:22:06 -0800148 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800149
150 if ctx.Failed() {
151 return
152 }
153
154 vars := []makeVarsVariable{}
155 for _, provider := range makeVarsProviders {
156 mctx := &makeVarsContext{
Colin Cross65494b92019-02-07 14:25:51 -0800157 SingletonContext: ctx,
158 pctx: provider.pctx,
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800159 }
160
161 provider.call(mctx)
162
163 vars = append(vars, mctx.vars...)
164 }
165
166 if ctx.Failed() {
167 return
168 }
169
170 outBytes := s.writeVars(vars)
171
172 if _, err := os.Stat(outFile); err == nil {
173 if data, err := ioutil.ReadFile(outFile); err == nil {
174 if bytes.Equal(data, outBytes) {
175 return
176 }
177 }
178 }
179
180 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
181 ctx.Errorf(err.Error())
182 }
183}
184
185func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
186 buf := &bytes.Buffer{}
187
Dan Willemsen59339a22018-07-22 21:18:45 -0700188 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800189
190# Compares SOONG_$(1) against $(1), and warns if they are not equal.
191#
192# If the original variable is empty, then just set it to the SOONG_ version.
193#
194# $(1): Name of the variable to check
195# $(2): If not-empty, sort the values before comparing
196# $(3): Extra snippet to run if it does not match
197define soong-compare-var
198ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700199 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800200 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
201 ifneq ($$(my_val_make),$$(my_val_soong))
202 $$(warning $(1) does not match between Make and Soong:)
203 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
204 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
205 $(3)
206 endif
207 my_val_make :=
208 my_val_soong :=
209else
210 $(1) := $$(SOONG_$(1))
211endif
Dan Willemsende18f472016-09-30 10:16:38 -0700212.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800213endef
214
215my_check_failed := false
216
217`)
218
219 // Write all the strict checks out first so that if one of them errors,
220 // we get all of the strict errors printed, but not the non-strict
221 // warnings.
222 for _, v := range vars {
223 if !v.strict {
224 continue
225 }
226
227 sort := ""
228 if v.sort {
229 sort = "true"
230 }
231
232 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
233 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
234 }
235
Dan Willemsen59339a22018-07-22 21:18:45 -0700236 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800237ifneq ($(my_check_failed),false)
238 $(error Soong variable check failed)
239endif
240my_check_failed :=
241
242
243`)
244
245 for _, v := range vars {
246 if v.strict {
247 continue
248 }
249
250 sort := ""
251 if v.sort {
252 sort = "true"
253 }
254
255 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
256 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
257 }
258
259 fmt.Fprintln(buf, "\nsoong-compare-var :=")
260
261 return buf.Bytes()
262}
263
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700264func (c *makeVarsContext) DeviceConfig() DeviceConfig {
Colin Cross65494b92019-02-07 14:25:51 -0800265 return DeviceConfig{c.Config().deviceConfig}
Jiyong Park374510b2018-03-19 18:23:01 +0900266}
267
Colin Cross31656952018-05-24 16:11:20 -0700268var ninjaDescaper = strings.NewReplacer("$$", "$")
269
Dan Willemsen558e5172016-05-19 16:58:46 -0700270func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross65494b92019-02-07 14:25:51 -0800271 s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
Colin Cross31656952018-05-24 16:11:20 -0700272 if err != nil {
273 return "", err
274 }
275 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
276 // in a Makefile
277 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700278}
279
280func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800281 c.vars = append(c.vars, makeVarsVariable{
282 name: name,
283 value: value,
284 strict: strict,
285 sort: sort,
286 })
287}
288
Dan Willemsen558e5172016-05-19 16:58:46 -0700289func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
290 value, err := c.Eval(ninjaStr)
291 if err != nil {
Colin Cross65494b92019-02-07 14:25:51 -0800292 c.SingletonContext.Errorf(err.Error())
Dan Willemsen558e5172016-05-19 16:58:46 -0700293 }
294 c.addVariableRaw(name, value, strict, sort)
295}
296
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800297func (c *makeVarsContext) Strict(name, ninjaStr string) {
298 c.addVariable(name, ninjaStr, true, false)
299}
300func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
301 c.addVariable(name, ninjaStr, true, true)
302}
Dan Willemsen558e5172016-05-19 16:58:46 -0700303func (c *makeVarsContext) StrictRaw(name, value string) {
304 c.addVariableRaw(name, value, true, false)
305}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800306
307func (c *makeVarsContext) Check(name, ninjaStr string) {
308 c.addVariable(name, ninjaStr, false, false)
309}
310func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
311 c.addVariable(name, ninjaStr, false, true)
312}
Dan Willemsen558e5172016-05-19 16:58:46 -0700313func (c *makeVarsContext) CheckRaw(name, value string) {
314 c.addVariableRaw(name, value, false, false)
315}