github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/android/makevars.go (about)

     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  
    15  package android
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"os"
    22  	"strconv"
    23  
    24  	"github.com/google/blueprint/proptools"
    25  )
    26  
    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  
    35  ///////////////////////////////////////////////////////////////////////////////
    36  // Interface for other packages to use to declare make variables
    37  type MakeVarsContext interface {
    38  	Config() Config
    39  	DeviceConfig() DeviceConfig
    40  	SingletonContext() SingletonContext
    41  
    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)
    55  
    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)
    66  }
    67  
    68  type MakeVarsProvider func(ctx MakeVarsContext)
    69  
    70  func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
    71  	makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
    72  }
    73  
    74  ///////////////////////////////////////////////////////////////////////////////
    75  
    76  func init() {
    77  	RegisterSingletonType("makevars", makeVarsSingletonFunc)
    78  }
    79  
    80  func makeVarsSingletonFunc() Singleton {
    81  	return &makeVarsSingleton{}
    82  }
    83  
    84  type makeVarsSingleton struct{}
    85  
    86  type makeVarsProvider struct {
    87  	pctx PackageContext
    88  	call MakeVarsProvider
    89  }
    90  
    91  var makeVarsProviders []makeVarsProvider
    92  
    93  type makeVarsContext struct {
    94  	config Config
    95  	ctx    SingletonContext
    96  	pctx   PackageContext
    97  	vars   []makeVarsVariable
    98  }
    99  
   100  var _ MakeVarsContext = &makeVarsContext{}
   101  
   102  type makeVarsVariable struct {
   103  	name   string
   104  	value  string
   105  	sort   bool
   106  	strict bool
   107  }
   108  
   109  func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
   110  	if !ctx.Config().EmbeddedInMake() {
   111  		return
   112  	}
   113  
   114  	outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()
   115  
   116  	if ctx.Failed() {
   117  		return
   118  	}
   119  
   120  	vars := []makeVarsVariable{}
   121  	for _, provider := range makeVarsProviders {
   122  		mctx := &makeVarsContext{
   123  			config: ctx.Config(),
   124  			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  
   152  func (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
   164  define soong-compare-var
   165  ifneq ($$($(1)),)
   166    my_val_make := $$(strip $(if $(2),$$(sort $$($(1))),$$($(1))))
   167    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 :=
   176  else
   177    $(1) := $$(SOONG_$(1))
   178  endif
   179  .KATI_READONLY := $(1) SOONG_$(1)
   180  endef
   181  
   182  my_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, `
   204  ifneq ($(my_check_failed),false)
   205    $(error Soong variable check failed)
   206  endif
   207  my_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  
   231  func (c *makeVarsContext) Config() Config {
   232  	return c.config
   233  }
   234  
   235  func (c *makeVarsContext) DeviceConfig() DeviceConfig {
   236  	return DeviceConfig{c.config.deviceConfig}
   237  }
   238  
   239  func (c *makeVarsContext) SingletonContext() SingletonContext {
   240  	return c.ctx
   241  }
   242  
   243  func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
   244  	return c.ctx.Eval(c.pctx, ninjaStr)
   245  }
   246  
   247  func (c *makeVarsContext) addVariableRaw(name, value string, strict, sort bool) {
   248  	c.vars = append(c.vars, makeVarsVariable{
   249  		name:   name,
   250  		value:  value,
   251  		strict: strict,
   252  		sort:   sort,
   253  	})
   254  }
   255  
   256  func (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  
   264  func (c *makeVarsContext) Strict(name, ninjaStr string) {
   265  	c.addVariable(name, ninjaStr, true, false)
   266  }
   267  func (c *makeVarsContext) StrictSorted(name, ninjaStr string) {
   268  	c.addVariable(name, ninjaStr, true, true)
   269  }
   270  func (c *makeVarsContext) StrictRaw(name, value string) {
   271  	c.addVariableRaw(name, value, true, false)
   272  }
   273  
   274  func (c *makeVarsContext) Check(name, ninjaStr string) {
   275  	c.addVariable(name, ninjaStr, false, false)
   276  }
   277  func (c *makeVarsContext) CheckSorted(name, ninjaStr string) {
   278  	c.addVariable(name, ninjaStr, false, true)
   279  }
   280  func (c *makeVarsContext) CheckRaw(name, value string) {
   281  	c.addVariableRaw(name, value, false, false)
   282  }