blob: b6cd571f5eba9582c1a1c3385b2ea30b62b17b51 [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"
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080023
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080024 "github.com/google/blueprint/proptools"
25)
26
Dan Albertf5415d72017-08-17 16:19:59 -070027func init() {
28 RegisterMakeVarsProvider(pctx, androidMakeVarsProvider)
29}
30
31func androidMakeVarsProvider(ctx MakeVarsContext) {
32 ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion()))
33}
34
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080035///////////////////////////////////////////////////////////////////////////////
36// Interface for other packages to use to declare make variables
37type MakeVarsContext interface {
38 Config() Config
Jiyong Park374510b2018-03-19 18:23:01 +090039 SingletonContext() SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080040
41 // Verify the make variable matches the Soong version, fail the build
42 // if it does not. If the make variable is empty, just set it.
43 Strict(name, ninjaStr string)
44 // Check to see if the make variable matches the Soong version, warn if
45 // it does not. If the make variable is empty, just set it.
46 Check(name, ninjaStr string)
47
48 // These are equivalent to the above, but sort the make and soong
49 // variables before comparing them. They also show the unique entries
50 // in each list when displaying the difference, instead of the entire
51 // string.
52 StrictSorted(name, ninjaStr string)
53 CheckSorted(name, ninjaStr string)
Dan Willemsen558e5172016-05-19 16:58:46 -070054
55 // Evaluates a ninja string and returns the result. Used if more
56 // complicated modification needs to happen before giving it to Make.
57 Eval(ninjaStr string) (string, error)
58
59 // These are equivalent to Strict and Check, but do not attempt to
60 // evaluate the values before writing them to the Makefile. They can
61 // be used when all ninja variables have already been evaluated through
62 // Eval().
63 StrictRaw(name, value string)
64 CheckRaw(name, value string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080065}
66
67type MakeVarsProvider func(ctx MakeVarsContext)
68
Colin Cross0875c522017-11-28 17:34:01 -080069func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080070 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
71}
72
73///////////////////////////////////////////////////////////////////////////////
74
75func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070076 RegisterSingletonType("makevars", makeVarsSingletonFunc)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080077}
78
Colin Cross0875c522017-11-28 17:34:01 -080079func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080080 return &makeVarsSingleton{}
81}
82
83type makeVarsSingleton struct{}
84
85type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -080086 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080087 call MakeVarsProvider
88}
89
90var makeVarsProviders []makeVarsProvider
91
92type makeVarsContext struct {
93 config Config
Colin Cross0875c522017-11-28 17:34:01 -080094 ctx SingletonContext
95 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080096 vars []makeVarsVariable
97}
98
99var _ MakeVarsContext = &makeVarsContext{}
100
101type makeVarsVariable struct {
102 name string
103 value string
104 sort bool
105 strict bool
106}
107
Colin Cross0875c522017-11-28 17:34:01 -0800108func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800109 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800110 return
111 }
112
Colin Crossaabf6792017-11-29 00:27:14 -0800113 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().ProductVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800114
115 if ctx.Failed() {
116 return
117 }
118
119 vars := []makeVarsVariable{}
120 for _, provider := range makeVarsProviders {
121 mctx := &makeVarsContext{
Colin Crossaabf6792017-11-29 00:27:14 -0800122 config: ctx.Config(),
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800123 ctx: ctx,
124 pctx: provider.pctx,
125 }
126
127 provider.call(mctx)
128
129 vars = append(vars, mctx.vars...)
130 }
131
132 if ctx.Failed() {
133 return
134 }
135
136 outBytes := s.writeVars(vars)
137
138 if _, err := os.Stat(outFile); err == nil {
139 if data, err := ioutil.ReadFile(outFile); err == nil {
140 if bytes.Equal(data, outBytes) {
141 return
142 }
143 }
144 }
145
146 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
147 ctx.Errorf(err.Error())
148 }
149}
150
151func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
152 buf := &bytes.Buffer{}
153
154 fmt.Fprintln(buf, `# Autogenerated file
155
156# Compares SOONG_$(1) against $(1), and warns if they are not equal.
157#
158# If the original variable is empty, then just set it to the SOONG_ version.
159#
160# $(1): Name of the variable to check
161# $(2): If not-empty, sort the values before comparing
162# $(3): Extra snippet to run if it does not match
163define soong-compare-var
164ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700165 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800166 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
167 ifneq ($$(my_val_make),$$(my_val_soong))
168 $$(warning $(1) does not match between Make and Soong:)
169 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
170 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
171 $(3)
172 endif
173 my_val_make :=
174 my_val_soong :=
175else
176 $(1) := $$(SOONG_$(1))
177endif
Dan Willemsende18f472016-09-30 10:16:38 -0700178.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800179endef
180
181my_check_failed := false
182
183`)
184
185 // Write all the strict checks out first so that if one of them errors,
186 // we get all of the strict errors printed, but not the non-strict
187 // warnings.
188 for _, v := range vars {
189 if !v.strict {
190 continue
191 }
192
193 sort := ""
194 if v.sort {
195 sort = "true"
196 }
197
198 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
199 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
200 }
201
202 fmt.Fprintln(buf, `
203ifneq ($(my_check_failed),false)
204 $(error Soong variable check failed)
205endif
206my_check_failed :=
207
208
209`)
210
211 for _, v := range vars {
212 if v.strict {
213 continue
214 }
215
216 sort := ""
217 if v.sort {
218 sort = "true"
219 }
220
221 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
222 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
223 }
224
225 fmt.Fprintln(buf, "\nsoong-compare-var :=")
226
227 return buf.Bytes()
228}
229
230func (c *makeVarsContext) Config() Config {
231 return c.config
232}
233
Jiyong Park374510b2018-03-19 18:23:01 +0900234func (c *makeVarsContext) SingletonContext() SingletonContext {
235 return c.ctx
236}
237
Dan Willemsen558e5172016-05-19 16:58:46 -0700238func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
239 return c.ctx.Eval(c.pctx, ninjaStr)
240}
241
242func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800243 c.vars = append(c.vars, makeVarsVariable{
244 name: name,
245 value: value,
246 strict: strict,
247 sort: sort,
248 })
249}
250
Dan Willemsen558e5172016-05-19 16:58:46 -0700251func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
252 value, err := c.Eval(ninjaStr)
253 if err != nil {
254 c.ctx.Errorf(err.Error())
255 }
256 c.addVariableRaw(name, value, strict, sort)
257}
258
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800259func (c *makeVarsContext) Strict(name, ninjaStr string) {
260 c.addVariable(name, ninjaStr, true, false)
261}
262func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
263 c.addVariable(name, ninjaStr, true, true)
264}
Dan Willemsen558e5172016-05-19 16:58:46 -0700265func (c *makeVarsContext) StrictRaw(name, value string) {
266 c.addVariableRaw(name, value, true, false)
267}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800268
269func (c *makeVarsContext) Check(name, ninjaStr string) {
270 c.addVariable(name, ninjaStr, false, false)
271}
272func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
273 c.addVariable(name, ninjaStr, false, true)
274}
Dan Willemsen558e5172016-05-19 16:58:46 -0700275func (c *makeVarsContext) CheckRaw(name, value string) {
276 c.addVariableRaw(name, value, false, false)
277}