blob: 482fbdea7d7162d961af65ab56f507674cb2bee1 [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"
22
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080023 "github.com/google/blueprint"
24 "github.com/google/blueprint/proptools"
25)
26
27///////////////////////////////////////////////////////////////////////////////
28// Interface for other packages to use to declare make variables
29type MakeVarsContext interface {
30 Config() Config
31
32 // Verify the make variable matches the Soong version, fail the build
33 // if it does not. If the make variable is empty, just set it.
34 Strict(name, ninjaStr string)
35 // Check to see if the make variable matches the Soong version, warn if
36 // it does not. If the make variable is empty, just set it.
37 Check(name, ninjaStr string)
38
39 // These are equivalent to the above, but sort the make and soong
40 // variables before comparing them. They also show the unique entries
41 // in each list when displaying the difference, instead of the entire
42 // string.
43 StrictSorted(name, ninjaStr string)
44 CheckSorted(name, ninjaStr string)
Dan Willemsen558e5172016-05-19 16:58:46 -070045
46 // Evaluates a ninja string and returns the result. Used if more
47 // complicated modification needs to happen before giving it to Make.
48 Eval(ninjaStr string) (string, error)
49
50 // These are equivalent to Strict and Check, but do not attempt to
51 // evaluate the values before writing them to the Makefile. They can
52 // be used when all ninja variables have already been evaluated through
53 // Eval().
54 StrictRaw(name, value string)
55 CheckRaw(name, value string)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080056}
57
58type MakeVarsProvider func(ctx MakeVarsContext)
59
60func RegisterMakeVarsProvider(pctx blueprint.PackageContext, provider MakeVarsProvider) {
61 makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
62}
63
64///////////////////////////////////////////////////////////////////////////////
65
66func init() {
Colin Cross798bfce2016-10-12 14:28:16 -070067 RegisterSingletonType("makevars", makeVarsSingletonFunc)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -080068}
69
70func makeVarsSingletonFunc() blueprint.Singleton {
71 return &makeVarsSingleton{}
72}
73
74type makeVarsSingleton struct{}
75
76type makeVarsProvider struct {
77 pctx blueprint.PackageContext
78 call MakeVarsProvider
79}
80
81var makeVarsProviders []makeVarsProvider
82
83type makeVarsContext struct {
84 config Config
85 ctx blueprint.SingletonContext
86 pctx blueprint.PackageContext
87 vars []makeVarsVariable
88}
89
90var _ MakeVarsContext = &makeVarsContext{}
91
92type makeVarsVariable struct {
93 name string
94 value string
95 sort bool
96 strict bool
97}
98
99func (s *makeVarsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
100 config := ctx.Config().(Config)
101
102 if !config.EmbeddedInMake() {
103 return
104 }
105
106 outFile := PathForOutput(ctx, "make_vars"+proptools.String(config.ProductVariables.Make_suffix)+".mk").String()
107
108 if ctx.Failed() {
109 return
110 }
111
112 vars := []makeVarsVariable{}
113 for _, provider := range makeVarsProviders {
114 mctx := &makeVarsContext{
115 config: config,
116 ctx: ctx,
117 pctx: provider.pctx,
118 }
119
120 provider.call(mctx)
121
122 vars = append(vars, mctx.vars...)
123 }
124
125 if ctx.Failed() {
126 return
127 }
128
129 outBytes := s.writeVars(vars)
130
131 if _, err := os.Stat(outFile); err == nil {
132 if data, err := ioutil.ReadFile(outFile); err == nil {
133 if bytes.Equal(data, outBytes) {
134 return
135 }
136 }
137 }
138
139 if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil {
140 ctx.Errorf(err.Error())
141 }
142}
143
144func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
145 buf := &bytes.Buffer{}
146
147 fmt.Fprintln(buf, `# Autogenerated file
148
149# Compares SOONG_$(1) against $(1), and warns if they are not equal.
150#
151# If the original variable is empty, then just set it to the SOONG_ version.
152#
153# $(1): Name of the variable to check
154# $(2): If not-empty, sort the values before comparing
155# $(3): Extra snippet to run if it does not match
156define soong-compare-var
157ifneq ($$($(1)),)
Dan Willemsen558e5172016-05-19 16:58:46 -0700158 my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800159 my_val_soong := $(if $(2),$$(sort $$(SOONG_$(1))),$$(SOONG_$(1)))
160 ifneq ($$(my_val_make),$$(my_val_soong))
161 $$(warning $(1) does not match between Make and Soong:)
162 $(if $(2),$$(warning Make adds: $$(filter-out $$(my_val_soong),$$(my_val_make))),$$(warning Make : $$(my_val_make)))
163 $(if $(2),$$(warning Soong adds: $$(filter-out $$(my_val_make),$$(my_val_soong))),$$(warning Soong: $$(my_val_soong)))
164 $(3)
165 endif
166 my_val_make :=
167 my_val_soong :=
168else
169 $(1) := $$(SOONG_$(1))
170endif
Dan Willemsende18f472016-09-30 10:16:38 -0700171.KATI_READONLY := $(1) SOONG_$(1)
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800172endef
173
174my_check_failed := false
175
176`)
177
178 // Write all the strict checks out first so that if one of them errors,
179 // we get all of the strict errors printed, but not the non-strict
180 // warnings.
181 for _, v := range vars {
182 if !v.strict {
183 continue
184 }
185
186 sort := ""
187 if v.sort {
188 sort = "true"
189 }
190
191 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
192 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s,my_check_failed := true))\n\n", v.name, sort)
193 }
194
195 fmt.Fprintln(buf, `
196ifneq ($(my_check_failed),false)
197 $(error Soong variable check failed)
198endif
199my_check_failed :=
200
201
202`)
203
204 for _, v := range vars {
205 if v.strict {
206 continue
207 }
208
209 sort := ""
210 if v.sort {
211 sort = "true"
212 }
213
214 fmt.Fprintf(buf, "SOONG_%s := %s\n", v.name, v.value)
215 fmt.Fprintf(buf, "$(eval $(call soong-compare-var,%s,%s))\n\n", v.name, sort)
216 }
217
218 fmt.Fprintln(buf, "\nsoong-compare-var :=")
219
220 return buf.Bytes()
221}
222
223func (c *makeVarsContext) Config() Config {
224 return c.config
225}
226
Dan Willemsen558e5172016-05-19 16:58:46 -0700227func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
228 return c.ctx.Eval(c.pctx, ninjaStr)
229}
230
231func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800232 c.vars = append(c.vars, makeVarsVariable{
233 name: name,
234 value: value,
235 strict: strict,
236 sort: sort,
237 })
238}
239
Dan Willemsen558e5172016-05-19 16:58:46 -0700240func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
241 value, err := c.Eval(ninjaStr)
242 if err != nil {
243 c.ctx.Errorf(err.Error())
244 }
245 c.addVariableRaw(name, value, strict, sort)
246}
247
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800248func (c *makeVarsContext) Strict(name, ninjaStr string) {
249 c.addVariable(name, ninjaStr, true, false)
250}
251func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
252 c.addVariable(name, ninjaStr, true, true)
253}
Dan Willemsen558e5172016-05-19 16:58:46 -0700254func (c *makeVarsContext) StrictRaw(name, value string) {
255 c.addVariableRaw(name, value, true, false)
256}
Dan Willemsen4b7d5de2016-01-12 23:20:28 -0800257
258func (c *makeVarsContext) Check(name, ninjaStr string) {
259 c.addVariable(name, ninjaStr, false, false)
260}
261func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
262 c.addVariable(name, ninjaStr, false, true)
263}
Dan Willemsen558e5172016-05-19 16:58:46 -0700264func (c *makeVarsContext) CheckRaw(name, value string) {
265 c.addVariableRaw(name, value, false, false)
266}