blob: 3a7ec6e01b1be65e30a445a01cf9f25e3baf661b [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
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080025 "github.com/google/blueprint/proptools"
26)
27
Dan Albertf5415d72017-08-17 16:19:59 -070028func init() {
29 RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
30}
31
32func androidMakeVarsProvider(ctx MakeVarsContext) {
33 ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion()))
34}
35
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080036///////////////////////////////////////////////////////////////////////////////
37// Interface for other packages to use to declare make variables
38type MakeVarsContext interface {
39 Config() Config
Dan Willemsen3fb1fae2018-03-12 15:30:26 -070040 DeviceConfig() DeviceConfig
Jiyong Park374510b2018-03-19 18:23:01 +090041 SingletonContext() SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080042
43 // Verify the make variable matches the Soong version, fail the build
44 // if it does not. If the make variable is empty, just set it.
45 Strict(name, ninjaStr string)
46 // Check to see if the make variable matches the Soong version, warn if
47 // it does not. If the make variable is empty, just set it.
48 Check(name, ninjaStr string)
49
50 // These are equivalent to the above, but sort the make and soong
51 // variables before comparing them. They also show the unique entries
52 // in each list when displaying the difference, instead of the entire
53 // string.
54 StrictSorted(name, ninjaStr string)
55 CheckSorted(name, ninjaStr string)
Dan Willemsen558e5172016-05-19 16:58:46 -070056
57 // Evaluates a ninja string and returns the result. Used if more
58 // complicated modification needs to happen before giving it to Make.
59 Eval(ninjaStr string) (string, error)
60
61 // These are equivalent to Strict and Check, but do not attempt to
62 // evaluate the values before writing them to the Makefile. They can
63 // be used when all ninja variables have already been evaluated through
64 // Eval().
65 StrictRaw(name, value string)
66 CheckRaw(name, value string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080067}
68
69type MakeVarsProvider func(ctx MakeVarsContext)
70
Colin Cross0875c522017-11-28 17:34:01 -080071func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080072 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
73}
74
75///////////////////////////////////////////////////////////////////////////////
76
77func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070078 RegisterSingletonType("makevars", makeVarsSingletonFunc)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080079}
80
Colin Cross0875c522017-11-28 17:34:01 -080081func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080082 return &makeVarsSingleton{}
83}
84
85type makeVarsSingleton struct{}
86
87type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -080088 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080089 call MakeVarsProvider
90}
91
92var makeVarsProviders []makeVarsProvider
93
94type makeVarsContext struct {
95 config Config
Colin Cross0875c522017-11-28 17:34:01 -080096 ctx SingletonContext
97 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080098 vars []makeVarsVariable
99}
100
101var _ MakeVarsContext = &makeVarsContext{}
102
103type makeVarsVariable struct {
104 name string
105 value string
106 sort bool
107 strict bool
108}
109
Colin Cross0875c522017-11-28 17:34:01 -0800110func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800111 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800112 return
113 }
114
Dan Willemsen45133ac2018-03-09 21:22:06 -0800115 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800116
117 if ctx.Failed() {
118 return
119 }
120
121 vars := []makeVarsVariable{}
122 for _, provider := range makeVarsProviders {
123 mctx := &makeVarsContext{
Colin Crossaabf6792017-11-29 00:27:14 -0800124 config: ctx.Config(),
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800125 ctx: ctx,
126 pctx: provider.pctx,
127 }
128
129 provider.call(mctx)
130
131 vars = append(vars, mctx.vars...)
132 }
133
134 if ctx.Failed() {
135 return
136 }
137
138 outBytes := s.writeVars(vars)
139
140 if _, err := os.Stat(outFile); err == nil {
141 if data, err := ioutil.ReadFile(outFile); err == nil {
142 if bytes.Equal(data, outBytes) {
143 return
144 }
145 }
146 }
147
148 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
149 ctx.Errorf(err.Error())
150 }
151}
152
153func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
154 buf := &bytes.Buffer{}
155
Dan Willemsen59339a22018-07-22 21:18:45 -0700156 fmt.Fprint(buf, `# Autogenerated file
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800157
158# Compares SOONG_$(1) against $(1), and warns if they are not equal.
159#
160# If the original variable is empty, then just set it to the SOONG_ version.
161#
162# $(1): Name of the variable to check
163# $(2): If not-empty, sort the values before comparing
164# $(3): Extra snippet to run if it does not match
165define soong-compare-var
166ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700167 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800168 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
169 ifneq ($$(my_val_make),$$(my_val_soong))
170 $$(warning $(1) does not match between Make and Soong:)
171 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
172 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
173 $(3)
174 endif
175 my_val_make :=
176 my_val_soong :=
177else
178 $(1) := $$(SOONG_$(1))
179endif
Dan Willemsende18f472016-09-30 10:16:38 -0700180.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800181endef
182
183my_check_failed := false
184
185`)
186
187 // Write all the strict checks out first so that if one of them errors,
188 // we get all of the strict errors printed, but not the non-strict
189 // warnings.
190 for _, v := range vars {
191 if !v.strict {
192 continue
193 }
194
195 sort := ""
196 if v.sort {
197 sort = "true"
198 }
199
200 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
201 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
202 }
203
Dan Willemsen59339a22018-07-22 21:18:45 -0700204 fmt.Fprint(buf, `
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800205ifneq ($(my_check_failed),false)
206 $(error Soong variable check failed)
207endif
208my_check_failed :=
209
210
211`)
212
213 for _, v := range vars {
214 if v.strict {
215 continue
216 }
217
218 sort := ""
219 if v.sort {
220 sort = "true"
221 }
222
223 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
224 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
225 }
226
227 fmt.Fprintln(buf, "\nsoong-compare-var :=")
228
229 return buf.Bytes()
230}
231
232func (c *makeVarsContext) Config() Config {
233 return c.config
234}
235
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700236func (c *makeVarsContext) DeviceConfig() DeviceConfig {
237 return DeviceConfig{c.config.deviceConfig}
238}
239
Jiyong Park374510b2018-03-19 18:23:01 +0900240func (c *makeVarsContext) SingletonContext() SingletonContext {
241 return c.ctx
242}
243
Colin Cross31656952018-05-24 16:11:20 -0700244var ninjaDescaper = strings.NewReplacer("$$", "$")
245
Dan Willemsen558e5172016-05-19 16:58:46 -0700246func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
Colin Cross31656952018-05-24 16:11:20 -0700247 s, err := c.ctx.Eval(c.pctx, ninjaStr)
248 if err != nil {
249 return "", err
250 }
251 // SingletonContext.Eval returns an exapnded string that is valid for a ninja file, de-escape $$ to $ for use
252 // in a Makefile
253 return ninjaDescaper.Replace(s), nil
Dan Willemsen558e5172016-05-19 16:58:46 -0700254}
255
256func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800257 c.vars = append(c.vars, makeVarsVariable{
258 name: name,
259 value: value,
260 strict: strict,
261 sort: sort,
262 })
263}
264
Dan Willemsen558e5172016-05-19 16:58:46 -0700265func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
266 value, err := c.Eval(ninjaStr)
267 if err != nil {
268 c.ctx.Errorf(err.Error())
269 }
270 c.addVariableRaw(name, value, strict, sort)
271}
272
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800273func (c *makeVarsContext) Strict(name, ninjaStr string) {
274 c.addVariable(name, ninjaStr, true, false)
275}
276func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
277 c.addVariable(name, ninjaStr, true, true)
278}
Dan Willemsen558e5172016-05-19 16:58:46 -0700279func (c *makeVarsContext) StrictRaw(name, value string) {
280 c.addVariableRaw(name, value, true, false)
281}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800282
283func (c *makeVarsContext) Check(name, ninjaStr string) {
284 c.addVariable(name, ninjaStr, false, false)
285}
286func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
287 c.addVariable(name, ninjaStr, false, true)
288}
Dan Willemsen558e5172016-05-19 16:58:46 -0700289func (c *makeVarsContext) CheckRaw(name, value string) {
290 c.addVariableRaw(name, value, false, false)
291}