blob: 3094a48e2846222cb8edc19851de065739feacc1 [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
Dan Willemsen3fb1fae2018-03-12 15:30:26 -070039 DeviceConfig() DeviceConfig
Jiyong Park374510b2018-03-19 18:23:01 +090040 SingletonContext() SingletonContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080041
42 // Verify the make variable matches the Soong version, fail the build
43 // if it does not. If the make variable is empty, just set it.
44 Strict(name, ninjaStr string)
45 // Check to see if the make variable matches the Soong version, warn if
46 // it does not. If the make variable is empty, just set it.
47 Check(name, ninjaStr string)
48
49 // These are equivalent to the above, but sort the make and soong
50 // variables before comparing them. They also show the unique entries
51 // in each list when displaying the difference, instead of the entire
52 // string.
53 StrictSorted(name, ninjaStr string)
54 CheckSorted(name, ninjaStr string)
Dan Willemsen558e5172016-05-19 16:58:46 -070055
56 // Evaluates a ninja string and returns the result. Used if more
57 // complicated modification needs to happen before giving it to Make.
58 Eval(ninjaStr string) (string, error)
59
60 // These are equivalent to Strict and Check, but do not attempt to
61 // evaluate the values before writing them to the Makefile. They can
62 // be used when all ninja variables have already been evaluated through
63 // Eval().
64 StrictRaw(name, value string)
65 CheckRaw(name, value string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080066}
67
68type MakeVarsProvider func(ctx MakeVarsContext)
69
Colin Cross0875c522017-11-28 17:34:01 -080070func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080071 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
72}
73
74///////////////////////////////////////////////////////////////////////////////
75
76func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070077 RegisterSingletonType("makevars", makeVarsSingletonFunc)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080078}
79
Colin Cross0875c522017-11-28 17:34:01 -080080func makeVarsSingletonFunc() Singleton {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080081 return &makeVarsSingleton{}
82}
83
84type makeVarsSingleton struct{}
85
86type makeVarsProvider struct {
Colin Cross0875c522017-11-28 17:34:01 -080087 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080088 call MakeVarsProvider
89}
90
91var makeVarsProviders []makeVarsProvider
92
93type makeVarsContext struct {
94 config Config
Colin Cross0875c522017-11-28 17:34:01 -080095 ctx SingletonContext
96 pctx PackageContext
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080097 vars []makeVarsVariable
98}
99
100var _ MakeVarsContext = &makeVarsContext{}
101
102type makeVarsVariable struct {
103 name string
104 value string
105 sort bool
106 strict bool
107}
108
Colin Cross0875c522017-11-28 17:34:01 -0800109func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
Colin Crossaabf6792017-11-29 00:27:14 -0800110 if !ctx.Config().EmbeddedInMake() {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800111 return
112 }
113
Dan Willemsen45133ac2018-03-09 21:22:06 -0800114 outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800115
116 if ctx.Failed() {
117 return
118 }
119
120 vars := []makeVarsVariable{}
121 for _, provider := range makeVarsProviders {
122 mctx := &makeVarsContext{
Colin Crossaabf6792017-11-29 00:27:14 -0800123 config: ctx.Config(),
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800124 ctx: ctx,
125 pctx: provider.pctx,
126 }
127
128 provider.call(mctx)
129
130 vars = append(vars, mctx.vars...)
131 }
132
133 if ctx.Failed() {
134 return
135 }
136
137 outBytes := s.writeVars(vars)
138
139 if _, err := os.Stat(outFile); err == nil {
140 if data, err := ioutil.ReadFile(outFile); err == nil {
141 if bytes.Equal(data, outBytes) {
142 return
143 }
144 }
145 }
146
147 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
148 ctx.Errorf(err.Error())
149 }
150}
151
152func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
153 buf := &bytes.Buffer{}
154
155 fmt.Fprintln(buf, `# Autogenerated file
156
157# Compares SOONG_$(1) against $(1), and warns if they are not equal.
158#
159# If the original variable is empty, then just set it to the SOONG_ version.
160#
161# $(1): Name of the variable to check
162# $(2): If not-empty, sort the values before comparing
163# $(3): Extra snippet to run if it does not match
164define soong-compare-var
165ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700166 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800167 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
168 ifneq ($$(my_val_make),$$(my_val_soong))
169 $$(warning $(1) does not match between Make and Soong:)
170 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
171 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
172 $(3)
173 endif
174 my_val_make :=
175 my_val_soong :=
176else
177 $(1) := $$(SOONG_$(1))
178endif
Dan Willemsende18f472016-09-30 10:16:38 -0700179.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800180endef
181
182my_check_failed := false
183
184`)
185
186 // Write all the strict checks out first so that if one of them errors,
187 // we get all of the strict errors printed, but not the non-strict
188 // warnings.
189 for _, v := range vars {
190 if !v.strict {
191 continue
192 }
193
194 sort := ""
195 if v.sort {
196 sort = "true"
197 }
198
199 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
200 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
201 }
202
203 fmt.Fprintln(buf, `
204ifneq ($(my_check_failed),false)
205 $(error Soong variable check failed)
206endif
207my_check_failed :=
208
209
210`)
211
212 for _, v := range vars {
213 if v.strict {
214 continue
215 }
216
217 sort := ""
218 if v.sort {
219 sort = "true"
220 }
221
222 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
223 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
224 }
225
226 fmt.Fprintln(buf, "\nsoong-compare-var :=")
227
228 return buf.Bytes()
229}
230
231func (c *makeVarsContext) Config() Config {
232 return c.config
233}
234
Dan Willemsen3fb1fae2018-03-12 15:30:26 -0700235func (c *makeVarsContext) DeviceConfig() DeviceConfig {
236 return DeviceConfig{c.config.deviceConfig}
237}
238
Jiyong Park374510b2018-03-19 18:23:01 +0900239func (c *makeVarsContext) SingletonContext() SingletonContext {
240 return c.ctx
241}
242
Dan Willemsen558e5172016-05-19 16:58:46 -0700243func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
244 return c.ctx.Eval(c.pctx, ninjaStr)
245}
246
247func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800248 c.vars = append(c.vars, makeVarsVariable{
249 name: name,
250 value: value,
251 strict: strict,
252 sort: sort,
253 })
254}
255
Dan Willemsen558e5172016-05-19 16:58:46 -0700256func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
257 value, err := c.Eval(ninjaStr)
258 if err != nil {
259 c.ctx.Errorf(err.Error())
260 }
261 c.addVariableRaw(name, value, strict, sort)
262}
263
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800264func (c *makeVarsContext) Strict(name, ninjaStr string) {
265 c.addVariable(name, ninjaStr, true, false)
266}
267func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
268 c.addVariable(name, ninjaStr, true, true)
269}
Dan Willemsen558e5172016-05-19 16:58:46 -0700270func (c *makeVarsContext) StrictRaw(name, value string) {
271 c.addVariableRaw(name, value, true, false)
272}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800273
274func (c *makeVarsContext) Check(name, ninjaStr string) {
275 c.addVariable(name, ninjaStr, false, false)
276}
277func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
278 c.addVariable(name, ninjaStr, false, true)
279}
Dan Willemsen558e5172016-05-19 16:58:46 -0700280func (c *makeVarsContext) CheckRaw(name, value string) {
281 c.addVariableRaw(name, value, false, false)
282}