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