xref: /aosp_15_r20/build/soong/android/soongconfig/modules.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2020 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage soongconfig
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"io"
20*333d2b36SAndroid Build Coastguard Worker	"reflect"
21*333d2b36SAndroid Build Coastguard Worker	"sort"
22*333d2b36SAndroid Build Coastguard Worker	"strings"
23*333d2b36SAndroid Build Coastguard Worker
24*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/parser"
25*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
26*333d2b36SAndroid Build Coastguard Worker)
27*333d2b36SAndroid Build Coastguard Worker
28*333d2b36SAndroid Build Coastguard Workerconst conditionsDefault = "conditions_default"
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Workervar SoongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard Worker// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file.  It caches the
33*333d2b36SAndroid Build Coastguard Worker// result so each file is only parsed once.
34*333d2b36SAndroid Build Coastguard Workerfunc Parse(r io.Reader, from string) (*SoongConfigDefinition, []error) {
35*333d2b36SAndroid Build Coastguard Worker	scope := parser.NewScope(nil)
36*333d2b36SAndroid Build Coastguard Worker	file, errs := parser.ParseAndEval(from, r, scope)
37*333d2b36SAndroid Build Coastguard Worker
38*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
39*333d2b36SAndroid Build Coastguard Worker		return nil, errs
40*333d2b36SAndroid Build Coastguard Worker	}
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Worker	mtDef := &SoongConfigDefinition{
43*333d2b36SAndroid Build Coastguard Worker		ModuleTypes: make(map[string]*ModuleType),
44*333d2b36SAndroid Build Coastguard Worker		variables:   make(map[string]soongConfigVariable),
45*333d2b36SAndroid Build Coastguard Worker	}
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker	for _, def := range file.Defs {
48*333d2b36SAndroid Build Coastguard Worker		switch def := def.(type) {
49*333d2b36SAndroid Build Coastguard Worker		case *parser.Module:
50*333d2b36SAndroid Build Coastguard Worker			newErrs := processImportModuleDef(mtDef, def)
51*333d2b36SAndroid Build Coastguard Worker
52*333d2b36SAndroid Build Coastguard Worker			if len(newErrs) > 0 {
53*333d2b36SAndroid Build Coastguard Worker				errs = append(errs, newErrs...)
54*333d2b36SAndroid Build Coastguard Worker			}
55*333d2b36SAndroid Build Coastguard Worker
56*333d2b36SAndroid Build Coastguard Worker		case *parser.Assignment:
57*333d2b36SAndroid Build Coastguard Worker			// Already handled via Scope object
58*333d2b36SAndroid Build Coastguard Worker		default:
59*333d2b36SAndroid Build Coastguard Worker			panic("unknown definition type")
60*333d2b36SAndroid Build Coastguard Worker		}
61*333d2b36SAndroid Build Coastguard Worker	}
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
64*333d2b36SAndroid Build Coastguard Worker		return nil, errs
65*333d2b36SAndroid Build Coastguard Worker	}
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Worker	for name, moduleType := range mtDef.ModuleTypes {
68*333d2b36SAndroid Build Coastguard Worker		for _, varName := range moduleType.variableNames {
69*333d2b36SAndroid Build Coastguard Worker			if v, ok := mtDef.variables[varName]; ok {
70*333d2b36SAndroid Build Coastguard Worker				moduleType.Variables = append(moduleType.Variables, v)
71*333d2b36SAndroid Build Coastguard Worker			} else {
72*333d2b36SAndroid Build Coastguard Worker				return nil, []error{
73*333d2b36SAndroid Build Coastguard Worker					fmt.Errorf("unknown variable %q in module type %q", varName, name),
74*333d2b36SAndroid Build Coastguard Worker				}
75*333d2b36SAndroid Build Coastguard Worker			}
76*333d2b36SAndroid Build Coastguard Worker		}
77*333d2b36SAndroid Build Coastguard Worker	}
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Worker	return mtDef, nil
80*333d2b36SAndroid Build Coastguard Worker}
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Workerfunc processImportModuleDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
83*333d2b36SAndroid Build Coastguard Worker	switch def.Type {
84*333d2b36SAndroid Build Coastguard Worker	case "soong_config_module_type":
85*333d2b36SAndroid Build Coastguard Worker		return processModuleTypeDef(v, def)
86*333d2b36SAndroid Build Coastguard Worker	case "soong_config_string_variable":
87*333d2b36SAndroid Build Coastguard Worker		return processStringVariableDef(v, def)
88*333d2b36SAndroid Build Coastguard Worker	case "soong_config_bool_variable":
89*333d2b36SAndroid Build Coastguard Worker		return processBoolVariableDef(v, def)
90*333d2b36SAndroid Build Coastguard Worker	default:
91*333d2b36SAndroid Build Coastguard Worker		// Unknown module types will be handled when the file is parsed as a normal
92*333d2b36SAndroid Build Coastguard Worker		// Android.bp file.
93*333d2b36SAndroid Build Coastguard Worker	}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Worker	return nil
96*333d2b36SAndroid Build Coastguard Worker}
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Workertype ModuleTypeProperties struct {
99*333d2b36SAndroid Build Coastguard Worker	// the name of the new module type.  Unlike most modules, this name does not need to be unique,
100*333d2b36SAndroid Build Coastguard Worker	// although only one module type with any name will be importable into an Android.bp file.
101*333d2b36SAndroid Build Coastguard Worker	Name string
102*333d2b36SAndroid Build Coastguard Worker
103*333d2b36SAndroid Build Coastguard Worker	// the module type that this module type will extend.
104*333d2b36SAndroid Build Coastguard Worker	Module_type string
105*333d2b36SAndroid Build Coastguard Worker
106*333d2b36SAndroid Build Coastguard Worker	// the SOONG_CONFIG_NAMESPACE value from a BoardConfig.mk that this module type will read
107*333d2b36SAndroid Build Coastguard Worker	// configuration variables from.
108*333d2b36SAndroid Build Coastguard Worker	Config_namespace string
109*333d2b36SAndroid Build Coastguard Worker
110*333d2b36SAndroid Build Coastguard Worker	// the list of SOONG_CONFIG variables that this module type will read
111*333d2b36SAndroid Build Coastguard Worker	Variables []string
112*333d2b36SAndroid Build Coastguard Worker
113*333d2b36SAndroid Build Coastguard Worker	// the list of boolean SOONG_CONFIG variables that this module type will read
114*333d2b36SAndroid Build Coastguard Worker	Bool_variables []string
115*333d2b36SAndroid Build Coastguard Worker
116*333d2b36SAndroid Build Coastguard Worker	// the list of SOONG_CONFIG variables that this module type will read. The value will be
117*333d2b36SAndroid Build Coastguard Worker	// inserted into the properties with %s substitution.
118*333d2b36SAndroid Build Coastguard Worker	Value_variables []string
119*333d2b36SAndroid Build Coastguard Worker
120*333d2b36SAndroid Build Coastguard Worker	// the list of SOONG_CONFIG list variables that this module type will read. Each value will be
121*333d2b36SAndroid Build Coastguard Worker	// inserted into the properties with %s substitution.
122*333d2b36SAndroid Build Coastguard Worker	List_variables []string
123*333d2b36SAndroid Build Coastguard Worker
124*333d2b36SAndroid Build Coastguard Worker	// the list of properties that this module type will extend.
125*333d2b36SAndroid Build Coastguard Worker	Properties []string
126*333d2b36SAndroid Build Coastguard Worker}
127*333d2b36SAndroid Build Coastguard Worker
128*333d2b36SAndroid Build Coastguard Workerfunc processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Worker	props := &ModuleTypeProperties{}
131*333d2b36SAndroid Build Coastguard Worker
132*333d2b36SAndroid Build Coastguard Worker	_, errs = proptools.UnpackProperties(def.Properties, props)
133*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
134*333d2b36SAndroid Build Coastguard Worker		return errs
135*333d2b36SAndroid Build Coastguard Worker	}
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Worker	if props.Name == "" {
138*333d2b36SAndroid Build Coastguard Worker		errs = append(errs, fmt.Errorf("name property must be set"))
139*333d2b36SAndroid Build Coastguard Worker	}
140*333d2b36SAndroid Build Coastguard Worker
141*333d2b36SAndroid Build Coastguard Worker	if props.Config_namespace == "" {
142*333d2b36SAndroid Build Coastguard Worker		errs = append(errs, fmt.Errorf("config_namespace property must be set"))
143*333d2b36SAndroid Build Coastguard Worker	}
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Worker	if props.Module_type == "" {
146*333d2b36SAndroid Build Coastguard Worker		errs = append(errs, fmt.Errorf("module_type property must be set"))
147*333d2b36SAndroid Build Coastguard Worker	}
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
150*333d2b36SAndroid Build Coastguard Worker		return errs
151*333d2b36SAndroid Build Coastguard Worker	}
152*333d2b36SAndroid Build Coastguard Worker
153*333d2b36SAndroid Build Coastguard Worker	if mt, errs := newModuleType(props); len(errs) > 0 {
154*333d2b36SAndroid Build Coastguard Worker		return errs
155*333d2b36SAndroid Build Coastguard Worker	} else {
156*333d2b36SAndroid Build Coastguard Worker		v.ModuleTypes[props.Name] = mt
157*333d2b36SAndroid Build Coastguard Worker	}
158*333d2b36SAndroid Build Coastguard Worker
159*333d2b36SAndroid Build Coastguard Worker	return nil
160*333d2b36SAndroid Build Coastguard Worker}
161*333d2b36SAndroid Build Coastguard Worker
162*333d2b36SAndroid Build Coastguard Workertype VariableProperties struct {
163*333d2b36SAndroid Build Coastguard Worker	Name string
164*333d2b36SAndroid Build Coastguard Worker}
165*333d2b36SAndroid Build Coastguard Worker
166*333d2b36SAndroid Build Coastguard Workertype StringVariableProperties struct {
167*333d2b36SAndroid Build Coastguard Worker	Values []string
168*333d2b36SAndroid Build Coastguard Worker}
169*333d2b36SAndroid Build Coastguard Worker
170*333d2b36SAndroid Build Coastguard Workerfunc processStringVariableDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
171*333d2b36SAndroid Build Coastguard Worker	stringProps := &StringVariableProperties{}
172*333d2b36SAndroid Build Coastguard Worker
173*333d2b36SAndroid Build Coastguard Worker	base, errs := processVariableDef(def, stringProps)
174*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
175*333d2b36SAndroid Build Coastguard Worker		return errs
176*333d2b36SAndroid Build Coastguard Worker	}
177*333d2b36SAndroid Build Coastguard Worker
178*333d2b36SAndroid Build Coastguard Worker	if len(stringProps.Values) == 0 {
179*333d2b36SAndroid Build Coastguard Worker		return []error{fmt.Errorf("values property must be set")}
180*333d2b36SAndroid Build Coastguard Worker	}
181*333d2b36SAndroid Build Coastguard Worker
182*333d2b36SAndroid Build Coastguard Worker	vals := make(map[string]bool, len(stringProps.Values))
183*333d2b36SAndroid Build Coastguard Worker	for _, name := range stringProps.Values {
184*333d2b36SAndroid Build Coastguard Worker		if err := checkVariableName(name); err != nil {
185*333d2b36SAndroid Build Coastguard Worker			return []error{fmt.Errorf("soong_config_string_variable: values property error %s", err)}
186*333d2b36SAndroid Build Coastguard Worker		} else if _, ok := vals[name]; ok {
187*333d2b36SAndroid Build Coastguard Worker			return []error{fmt.Errorf("soong_config_string_variable: values property error: duplicate value: %q", name)}
188*333d2b36SAndroid Build Coastguard Worker		}
189*333d2b36SAndroid Build Coastguard Worker		vals[name] = true
190*333d2b36SAndroid Build Coastguard Worker	}
191*333d2b36SAndroid Build Coastguard Worker
192*333d2b36SAndroid Build Coastguard Worker	v.variables[base.variable] = &stringVariable{
193*333d2b36SAndroid Build Coastguard Worker		baseVariable: base,
194*333d2b36SAndroid Build Coastguard Worker		values:       CanonicalizeToProperties(stringProps.Values),
195*333d2b36SAndroid Build Coastguard Worker	}
196*333d2b36SAndroid Build Coastguard Worker
197*333d2b36SAndroid Build Coastguard Worker	return nil
198*333d2b36SAndroid Build Coastguard Worker}
199*333d2b36SAndroid Build Coastguard Worker
200*333d2b36SAndroid Build Coastguard Workerfunc processBoolVariableDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
201*333d2b36SAndroid Build Coastguard Worker	base, errs := processVariableDef(def)
202*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
203*333d2b36SAndroid Build Coastguard Worker		return errs
204*333d2b36SAndroid Build Coastguard Worker	}
205*333d2b36SAndroid Build Coastguard Worker
206*333d2b36SAndroid Build Coastguard Worker	v.variables[base.variable] = &boolVariable{
207*333d2b36SAndroid Build Coastguard Worker		baseVariable: base,
208*333d2b36SAndroid Build Coastguard Worker	}
209*333d2b36SAndroid Build Coastguard Worker
210*333d2b36SAndroid Build Coastguard Worker	return nil
211*333d2b36SAndroid Build Coastguard Worker}
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Workerfunc processVariableDef(def *parser.Module,
214*333d2b36SAndroid Build Coastguard Worker	extraProps ...interface{}) (cond baseVariable, errs []error) {
215*333d2b36SAndroid Build Coastguard Worker
216*333d2b36SAndroid Build Coastguard Worker	props := &VariableProperties{}
217*333d2b36SAndroid Build Coastguard Worker
218*333d2b36SAndroid Build Coastguard Worker	allProps := append([]interface{}{props}, extraProps...)
219*333d2b36SAndroid Build Coastguard Worker
220*333d2b36SAndroid Build Coastguard Worker	_, errs = proptools.UnpackProperties(def.Properties, allProps...)
221*333d2b36SAndroid Build Coastguard Worker	if len(errs) > 0 {
222*333d2b36SAndroid Build Coastguard Worker		return baseVariable{}, errs
223*333d2b36SAndroid Build Coastguard Worker	}
224*333d2b36SAndroid Build Coastguard Worker
225*333d2b36SAndroid Build Coastguard Worker	if props.Name == "" {
226*333d2b36SAndroid Build Coastguard Worker		return baseVariable{}, []error{fmt.Errorf("name property must be set")}
227*333d2b36SAndroid Build Coastguard Worker	}
228*333d2b36SAndroid Build Coastguard Worker
229*333d2b36SAndroid Build Coastguard Worker	return baseVariable{
230*333d2b36SAndroid Build Coastguard Worker		variable: props.Name,
231*333d2b36SAndroid Build Coastguard Worker	}, nil
232*333d2b36SAndroid Build Coastguard Worker}
233*333d2b36SAndroid Build Coastguard Worker
234*333d2b36SAndroid Build Coastguard Workertype SoongConfigDefinition struct {
235*333d2b36SAndroid Build Coastguard Worker	ModuleTypes map[string]*ModuleType
236*333d2b36SAndroid Build Coastguard Worker
237*333d2b36SAndroid Build Coastguard Worker	variables map[string]soongConfigVariable
238*333d2b36SAndroid Build Coastguard Worker}
239*333d2b36SAndroid Build Coastguard Worker
240*333d2b36SAndroid Build Coastguard Worker// CreateProperties returns a reflect.Value of a newly constructed type that contains the desired
241*333d2b36SAndroid Build Coastguard Worker// property layout for the Soong config variables, with each possible value an interface{} that
242*333d2b36SAndroid Build Coastguard Worker// contains a nil pointer to another newly constructed type that contains the affectable properties.
243*333d2b36SAndroid Build Coastguard Worker// The reflect.Value will be cloned for each call to the Soong config module type's factory method.
244*333d2b36SAndroid Build Coastguard Worker//
245*333d2b36SAndroid Build Coastguard Worker// For example, the acme_cc_defaults example above would
246*333d2b36SAndroid Build Coastguard Worker// produce a reflect.Value whose type is:
247*333d2b36SAndroid Build Coastguard Worker//
248*333d2b36SAndroid Build Coastguard Worker//	*struct {
249*333d2b36SAndroid Build Coastguard Worker//	    Soong_config_variables struct {
250*333d2b36SAndroid Build Coastguard Worker//	        Board struct {
251*333d2b36SAndroid Build Coastguard Worker//	            Soc_a interface{}
252*333d2b36SAndroid Build Coastguard Worker//	            Soc_b interface{}
253*333d2b36SAndroid Build Coastguard Worker//	        }
254*333d2b36SAndroid Build Coastguard Worker//	    }
255*333d2b36SAndroid Build Coastguard Worker//	}
256*333d2b36SAndroid Build Coastguard Worker//
257*333d2b36SAndroid Build Coastguard Worker// And whose value is:
258*333d2b36SAndroid Build Coastguard Worker//
259*333d2b36SAndroid Build Coastguard Worker//	&{
260*333d2b36SAndroid Build Coastguard Worker//	    Soong_config_variables: {
261*333d2b36SAndroid Build Coastguard Worker//	        Board: {
262*333d2b36SAndroid Build Coastguard Worker//	            Soc_a: (*struct{ Cflags []string })(nil),
263*333d2b36SAndroid Build Coastguard Worker//	            Soc_b: (*struct{ Cflags []string })(nil),
264*333d2b36SAndroid Build Coastguard Worker//	        },
265*333d2b36SAndroid Build Coastguard Worker//	    },
266*333d2b36SAndroid Build Coastguard Worker//	}
267*333d2b36SAndroid Build Coastguard Workerfunc CreateProperties(factoryProps []interface{}, moduleType *ModuleType) reflect.Value {
268*333d2b36SAndroid Build Coastguard Worker	var fields []reflect.StructField
269*333d2b36SAndroid Build Coastguard Worker
270*333d2b36SAndroid Build Coastguard Worker	affectablePropertiesType := createAffectablePropertiesType(moduleType.affectableProperties, factoryProps)
271*333d2b36SAndroid Build Coastguard Worker	if affectablePropertiesType == nil {
272*333d2b36SAndroid Build Coastguard Worker		return reflect.Value{}
273*333d2b36SAndroid Build Coastguard Worker	}
274*333d2b36SAndroid Build Coastguard Worker
275*333d2b36SAndroid Build Coastguard Worker	for _, c := range moduleType.Variables {
276*333d2b36SAndroid Build Coastguard Worker		fields = append(fields, reflect.StructField{
277*333d2b36SAndroid Build Coastguard Worker			Name: proptools.FieldNameForProperty(c.variableProperty()),
278*333d2b36SAndroid Build Coastguard Worker			Type: c.variableValuesType(),
279*333d2b36SAndroid Build Coastguard Worker		})
280*333d2b36SAndroid Build Coastguard Worker	}
281*333d2b36SAndroid Build Coastguard Worker
282*333d2b36SAndroid Build Coastguard Worker	typ := reflect.StructOf([]reflect.StructField{{
283*333d2b36SAndroid Build Coastguard Worker		Name: SoongConfigProperty,
284*333d2b36SAndroid Build Coastguard Worker		Type: reflect.StructOf(fields),
285*333d2b36SAndroid Build Coastguard Worker	}})
286*333d2b36SAndroid Build Coastguard Worker
287*333d2b36SAndroid Build Coastguard Worker	props := reflect.New(typ)
288*333d2b36SAndroid Build Coastguard Worker	structConditions := props.Elem().FieldByName(SoongConfigProperty)
289*333d2b36SAndroid Build Coastguard Worker
290*333d2b36SAndroid Build Coastguard Worker	for i, c := range moduleType.Variables {
291*333d2b36SAndroid Build Coastguard Worker		c.initializeProperties(structConditions.Field(i), affectablePropertiesType)
292*333d2b36SAndroid Build Coastguard Worker	}
293*333d2b36SAndroid Build Coastguard Worker
294*333d2b36SAndroid Build Coastguard Worker	return props
295*333d2b36SAndroid Build Coastguard Worker}
296*333d2b36SAndroid Build Coastguard Worker
297*333d2b36SAndroid Build Coastguard Worker// createAffectablePropertiesType creates a reflect.Type of a struct that has a field for each affectable property
298*333d2b36SAndroid Build Coastguard Worker// that exists in factoryProps.
299*333d2b36SAndroid Build Coastguard Workerfunc createAffectablePropertiesType(affectableProperties []string, factoryProps []interface{}) reflect.Type {
300*333d2b36SAndroid Build Coastguard Worker	affectableProperties = append([]string(nil), affectableProperties...)
301*333d2b36SAndroid Build Coastguard Worker	sort.Strings(affectableProperties)
302*333d2b36SAndroid Build Coastguard Worker
303*333d2b36SAndroid Build Coastguard Worker	var recurse func(prefix string, aps []string) ([]string, reflect.Type)
304*333d2b36SAndroid Build Coastguard Worker	recurse = func(prefix string, aps []string) ([]string, reflect.Type) {
305*333d2b36SAndroid Build Coastguard Worker		var fields []reflect.StructField
306*333d2b36SAndroid Build Coastguard Worker
307*333d2b36SAndroid Build Coastguard Worker		// Iterate while the list is non-empty so it can be modified in the loop.
308*333d2b36SAndroid Build Coastguard Worker		for len(affectableProperties) > 0 {
309*333d2b36SAndroid Build Coastguard Worker			p := affectableProperties[0]
310*333d2b36SAndroid Build Coastguard Worker			if !strings.HasPrefix(affectableProperties[0], prefix) {
311*333d2b36SAndroid Build Coastguard Worker				// The properties are sorted and recurse is always called with a prefix that matches
312*333d2b36SAndroid Build Coastguard Worker				// the first property in the list, so if we've reached one that doesn't match the
313*333d2b36SAndroid Build Coastguard Worker				// prefix we are done with this prefix.
314*333d2b36SAndroid Build Coastguard Worker				break
315*333d2b36SAndroid Build Coastguard Worker			}
316*333d2b36SAndroid Build Coastguard Worker
317*333d2b36SAndroid Build Coastguard Worker			nestedProperty := strings.TrimPrefix(p, prefix)
318*333d2b36SAndroid Build Coastguard Worker			if i := strings.IndexRune(nestedProperty, '.'); i >= 0 {
319*333d2b36SAndroid Build Coastguard Worker				var nestedType reflect.Type
320*333d2b36SAndroid Build Coastguard Worker				nestedPrefix := nestedProperty[:i+1]
321*333d2b36SAndroid Build Coastguard Worker
322*333d2b36SAndroid Build Coastguard Worker				// Recurse to handle the properties with the found prefix.  This will return
323*333d2b36SAndroid Build Coastguard Worker				// an updated affectableProperties with the handled entries removed from the front
324*333d2b36SAndroid Build Coastguard Worker				// of the list, and the type that contains the handled entries.  The type may be
325*333d2b36SAndroid Build Coastguard Worker				// nil if none of the entries matched factoryProps.
326*333d2b36SAndroid Build Coastguard Worker				affectableProperties, nestedType = recurse(prefix+nestedPrefix, affectableProperties)
327*333d2b36SAndroid Build Coastguard Worker
328*333d2b36SAndroid Build Coastguard Worker				if nestedType != nil {
329*333d2b36SAndroid Build Coastguard Worker					nestedFieldName := proptools.FieldNameForProperty(strings.TrimSuffix(nestedPrefix, "."))
330*333d2b36SAndroid Build Coastguard Worker
331*333d2b36SAndroid Build Coastguard Worker					fields = append(fields, reflect.StructField{
332*333d2b36SAndroid Build Coastguard Worker						Name: nestedFieldName,
333*333d2b36SAndroid Build Coastguard Worker						Type: nestedType,
334*333d2b36SAndroid Build Coastguard Worker					})
335*333d2b36SAndroid Build Coastguard Worker				}
336*333d2b36SAndroid Build Coastguard Worker			} else {
337*333d2b36SAndroid Build Coastguard Worker				typ := typeForPropertyFromPropertyStructs(factoryProps, p)
338*333d2b36SAndroid Build Coastguard Worker				if typ != nil {
339*333d2b36SAndroid Build Coastguard Worker					fields = append(fields, reflect.StructField{
340*333d2b36SAndroid Build Coastguard Worker						Name: proptools.FieldNameForProperty(nestedProperty),
341*333d2b36SAndroid Build Coastguard Worker						Type: typ,
342*333d2b36SAndroid Build Coastguard Worker					})
343*333d2b36SAndroid Build Coastguard Worker				}
344*333d2b36SAndroid Build Coastguard Worker				// The first element in the list has been handled, remove it from the list.
345*333d2b36SAndroid Build Coastguard Worker				affectableProperties = affectableProperties[1:]
346*333d2b36SAndroid Build Coastguard Worker			}
347*333d2b36SAndroid Build Coastguard Worker		}
348*333d2b36SAndroid Build Coastguard Worker
349*333d2b36SAndroid Build Coastguard Worker		var typ reflect.Type
350*333d2b36SAndroid Build Coastguard Worker		if len(fields) > 0 {
351*333d2b36SAndroid Build Coastguard Worker			typ = reflect.StructOf(fields)
352*333d2b36SAndroid Build Coastguard Worker		}
353*333d2b36SAndroid Build Coastguard Worker		return affectableProperties, typ
354*333d2b36SAndroid Build Coastguard Worker	}
355*333d2b36SAndroid Build Coastguard Worker
356*333d2b36SAndroid Build Coastguard Worker	affectableProperties, typ := recurse("", affectableProperties)
357*333d2b36SAndroid Build Coastguard Worker	if len(affectableProperties) > 0 {
358*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("didn't handle all affectable properties"))
359*333d2b36SAndroid Build Coastguard Worker	}
360*333d2b36SAndroid Build Coastguard Worker
361*333d2b36SAndroid Build Coastguard Worker	if typ != nil {
362*333d2b36SAndroid Build Coastguard Worker		return reflect.PtrTo(typ)
363*333d2b36SAndroid Build Coastguard Worker	}
364*333d2b36SAndroid Build Coastguard Worker
365*333d2b36SAndroid Build Coastguard Worker	return nil
366*333d2b36SAndroid Build Coastguard Worker}
367*333d2b36SAndroid Build Coastguard Worker
368*333d2b36SAndroid Build Coastguard Workerfunc typeForPropertyFromPropertyStructs(psList []interface{}, property string) reflect.Type {
369*333d2b36SAndroid Build Coastguard Worker	for _, ps := range psList {
370*333d2b36SAndroid Build Coastguard Worker		if typ := typeForPropertyFromPropertyStruct(ps, property); typ != nil {
371*333d2b36SAndroid Build Coastguard Worker			return typ
372*333d2b36SAndroid Build Coastguard Worker		}
373*333d2b36SAndroid Build Coastguard Worker	}
374*333d2b36SAndroid Build Coastguard Worker
375*333d2b36SAndroid Build Coastguard Worker	return nil
376*333d2b36SAndroid Build Coastguard Worker}
377*333d2b36SAndroid Build Coastguard Worker
378*333d2b36SAndroid Build Coastguard Workerfunc typeForPropertyFromPropertyStruct(ps interface{}, property string) reflect.Type {
379*333d2b36SAndroid Build Coastguard Worker	v := reflect.ValueOf(ps)
380*333d2b36SAndroid Build Coastguard Worker	for len(property) > 0 {
381*333d2b36SAndroid Build Coastguard Worker		if !v.IsValid() {
382*333d2b36SAndroid Build Coastguard Worker			return nil
383*333d2b36SAndroid Build Coastguard Worker		}
384*333d2b36SAndroid Build Coastguard Worker
385*333d2b36SAndroid Build Coastguard Worker		if v.Kind() == reflect.Interface {
386*333d2b36SAndroid Build Coastguard Worker			if v.IsNil() {
387*333d2b36SAndroid Build Coastguard Worker				return nil
388*333d2b36SAndroid Build Coastguard Worker			} else {
389*333d2b36SAndroid Build Coastguard Worker				v = v.Elem()
390*333d2b36SAndroid Build Coastguard Worker			}
391*333d2b36SAndroid Build Coastguard Worker		}
392*333d2b36SAndroid Build Coastguard Worker
393*333d2b36SAndroid Build Coastguard Worker		if v.Kind() == reflect.Ptr {
394*333d2b36SAndroid Build Coastguard Worker			if v.IsNil() {
395*333d2b36SAndroid Build Coastguard Worker				v = reflect.Zero(v.Type().Elem())
396*333d2b36SAndroid Build Coastguard Worker			} else {
397*333d2b36SAndroid Build Coastguard Worker				v = v.Elem()
398*333d2b36SAndroid Build Coastguard Worker			}
399*333d2b36SAndroid Build Coastguard Worker		}
400*333d2b36SAndroid Build Coastguard Worker
401*333d2b36SAndroid Build Coastguard Worker		if v.Kind() != reflect.Struct {
402*333d2b36SAndroid Build Coastguard Worker			return nil
403*333d2b36SAndroid Build Coastguard Worker		}
404*333d2b36SAndroid Build Coastguard Worker
405*333d2b36SAndroid Build Coastguard Worker		if index := strings.IndexRune(property, '.'); index >= 0 {
406*333d2b36SAndroid Build Coastguard Worker			prefix := property[:index]
407*333d2b36SAndroid Build Coastguard Worker			property = property[index+1:]
408*333d2b36SAndroid Build Coastguard Worker
409*333d2b36SAndroid Build Coastguard Worker			v = v.FieldByName(proptools.FieldNameForProperty(prefix))
410*333d2b36SAndroid Build Coastguard Worker		} else {
411*333d2b36SAndroid Build Coastguard Worker			f := v.FieldByName(proptools.FieldNameForProperty(property))
412*333d2b36SAndroid Build Coastguard Worker			if !f.IsValid() {
413*333d2b36SAndroid Build Coastguard Worker				return nil
414*333d2b36SAndroid Build Coastguard Worker			}
415*333d2b36SAndroid Build Coastguard Worker			return f.Type()
416*333d2b36SAndroid Build Coastguard Worker		}
417*333d2b36SAndroid Build Coastguard Worker	}
418*333d2b36SAndroid Build Coastguard Worker	return nil
419*333d2b36SAndroid Build Coastguard Worker}
420*333d2b36SAndroid Build Coastguard Worker
421*333d2b36SAndroid Build Coastguard Worker// PropertiesToApply returns the applicable properties from a ModuleType that should be applied
422*333d2b36SAndroid Build Coastguard Worker// based on SoongConfig values.
423*333d2b36SAndroid Build Coastguard Worker// Expects that props contains a struct field with name soong_config_variables. The fields within
424*333d2b36SAndroid Build Coastguard Worker// soong_config_variables are expected to be in the same order as moduleType.Variables.
425*333d2b36SAndroid Build Coastguard Workerfunc PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
426*333d2b36SAndroid Build Coastguard Worker	var ret []interface{}
427*333d2b36SAndroid Build Coastguard Worker	props = props.Elem().FieldByName(SoongConfigProperty)
428*333d2b36SAndroid Build Coastguard Worker	for i, c := range moduleType.Variables {
429*333d2b36SAndroid Build Coastguard Worker		if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
430*333d2b36SAndroid Build Coastguard Worker			return nil, err
431*333d2b36SAndroid Build Coastguard Worker		} else if ps != nil {
432*333d2b36SAndroid Build Coastguard Worker			ret = append(ret, ps)
433*333d2b36SAndroid Build Coastguard Worker		}
434*333d2b36SAndroid Build Coastguard Worker	}
435*333d2b36SAndroid Build Coastguard Worker	return ret, nil
436*333d2b36SAndroid Build Coastguard Worker}
437*333d2b36SAndroid Build Coastguard Worker
438*333d2b36SAndroid Build Coastguard Workertype ModuleType struct {
439*333d2b36SAndroid Build Coastguard Worker	BaseModuleType  string
440*333d2b36SAndroid Build Coastguard Worker	ConfigNamespace string
441*333d2b36SAndroid Build Coastguard Worker	Variables       []soongConfigVariable
442*333d2b36SAndroid Build Coastguard Worker
443*333d2b36SAndroid Build Coastguard Worker	affectableProperties []string
444*333d2b36SAndroid Build Coastguard Worker	variableNames        []string
445*333d2b36SAndroid Build Coastguard Worker}
446*333d2b36SAndroid Build Coastguard Worker
447*333d2b36SAndroid Build Coastguard Workerfunc newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
448*333d2b36SAndroid Build Coastguard Worker	mt := &ModuleType{
449*333d2b36SAndroid Build Coastguard Worker		affectableProperties: props.Properties,
450*333d2b36SAndroid Build Coastguard Worker		ConfigNamespace:      props.Config_namespace,
451*333d2b36SAndroid Build Coastguard Worker		BaseModuleType:       props.Module_type,
452*333d2b36SAndroid Build Coastguard Worker		variableNames:        props.Variables,
453*333d2b36SAndroid Build Coastguard Worker	}
454*333d2b36SAndroid Build Coastguard Worker
455*333d2b36SAndroid Build Coastguard Worker	for _, name := range props.Bool_variables {
456*333d2b36SAndroid Build Coastguard Worker		if err := checkVariableName(name); err != nil {
457*333d2b36SAndroid Build Coastguard Worker			return nil, []error{fmt.Errorf("bool_variables %s", err)}
458*333d2b36SAndroid Build Coastguard Worker		}
459*333d2b36SAndroid Build Coastguard Worker
460*333d2b36SAndroid Build Coastguard Worker		mt.Variables = append(mt.Variables, newBoolVariable(name))
461*333d2b36SAndroid Build Coastguard Worker	}
462*333d2b36SAndroid Build Coastguard Worker
463*333d2b36SAndroid Build Coastguard Worker	for _, name := range props.Value_variables {
464*333d2b36SAndroid Build Coastguard Worker		if err := checkVariableName(name); err != nil {
465*333d2b36SAndroid Build Coastguard Worker			return nil, []error{fmt.Errorf("value_variables %s", err)}
466*333d2b36SAndroid Build Coastguard Worker		}
467*333d2b36SAndroid Build Coastguard Worker
468*333d2b36SAndroid Build Coastguard Worker		mt.Variables = append(mt.Variables, &valueVariable{
469*333d2b36SAndroid Build Coastguard Worker			baseVariable: baseVariable{
470*333d2b36SAndroid Build Coastguard Worker				variable: name,
471*333d2b36SAndroid Build Coastguard Worker			},
472*333d2b36SAndroid Build Coastguard Worker		})
473*333d2b36SAndroid Build Coastguard Worker	}
474*333d2b36SAndroid Build Coastguard Worker
475*333d2b36SAndroid Build Coastguard Worker	for _, name := range props.List_variables {
476*333d2b36SAndroid Build Coastguard Worker		if err := checkVariableName(name); err != nil {
477*333d2b36SAndroid Build Coastguard Worker			return nil, []error{fmt.Errorf("list_variables %s", err)}
478*333d2b36SAndroid Build Coastguard Worker		}
479*333d2b36SAndroid Build Coastguard Worker
480*333d2b36SAndroid Build Coastguard Worker		mt.Variables = append(mt.Variables, &listVariable{
481*333d2b36SAndroid Build Coastguard Worker			baseVariable: baseVariable{
482*333d2b36SAndroid Build Coastguard Worker				variable: name,
483*333d2b36SAndroid Build Coastguard Worker			},
484*333d2b36SAndroid Build Coastguard Worker		})
485*333d2b36SAndroid Build Coastguard Worker	}
486*333d2b36SAndroid Build Coastguard Worker
487*333d2b36SAndroid Build Coastguard Worker	return mt, nil
488*333d2b36SAndroid Build Coastguard Worker}
489*333d2b36SAndroid Build Coastguard Worker
490*333d2b36SAndroid Build Coastguard Workerfunc checkVariableName(name string) error {
491*333d2b36SAndroid Build Coastguard Worker	if name == "" {
492*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("name must not be blank")
493*333d2b36SAndroid Build Coastguard Worker	} else if name == conditionsDefault {
494*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("%q is reserved", conditionsDefault)
495*333d2b36SAndroid Build Coastguard Worker	}
496*333d2b36SAndroid Build Coastguard Worker	return nil
497*333d2b36SAndroid Build Coastguard Worker}
498*333d2b36SAndroid Build Coastguard Worker
499*333d2b36SAndroid Build Coastguard Workertype soongConfigVariable interface {
500*333d2b36SAndroid Build Coastguard Worker	// variableProperty returns the name of the variable.
501*333d2b36SAndroid Build Coastguard Worker	variableProperty() string
502*333d2b36SAndroid Build Coastguard Worker
503*333d2b36SAndroid Build Coastguard Worker	// conditionalValuesType returns a reflect.Type that contains an interface{} for each possible value.
504*333d2b36SAndroid Build Coastguard Worker	variableValuesType() reflect.Type
505*333d2b36SAndroid Build Coastguard Worker
506*333d2b36SAndroid Build Coastguard Worker	// initializeProperties is passed a reflect.Value of the reflect.Type returned by conditionalValuesType and a
507*333d2b36SAndroid Build Coastguard Worker	// reflect.Type of the affectable properties, and should initialize each interface{} in the reflect.Value with
508*333d2b36SAndroid Build Coastguard Worker	// the zero value of the affectable properties type.
509*333d2b36SAndroid Build Coastguard Worker	initializeProperties(v reflect.Value, typ reflect.Type)
510*333d2b36SAndroid Build Coastguard Worker
511*333d2b36SAndroid Build Coastguard Worker	// PropertiesToApply should return one of the interface{} values set by initializeProperties to be applied
512*333d2b36SAndroid Build Coastguard Worker	// to the module.
513*333d2b36SAndroid Build Coastguard Worker	PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error)
514*333d2b36SAndroid Build Coastguard Worker}
515*333d2b36SAndroid Build Coastguard Worker
516*333d2b36SAndroid Build Coastguard Workertype baseVariable struct {
517*333d2b36SAndroid Build Coastguard Worker	variable string
518*333d2b36SAndroid Build Coastguard Worker}
519*333d2b36SAndroid Build Coastguard Worker
520*333d2b36SAndroid Build Coastguard Workerfunc (c *baseVariable) variableProperty() string {
521*333d2b36SAndroid Build Coastguard Worker	return CanonicalizeToProperty(c.variable)
522*333d2b36SAndroid Build Coastguard Worker}
523*333d2b36SAndroid Build Coastguard Worker
524*333d2b36SAndroid Build Coastguard Workertype stringVariable struct {
525*333d2b36SAndroid Build Coastguard Worker	baseVariable
526*333d2b36SAndroid Build Coastguard Worker	values []string
527*333d2b36SAndroid Build Coastguard Worker}
528*333d2b36SAndroid Build Coastguard Worker
529*333d2b36SAndroid Build Coastguard Workerfunc (s *stringVariable) variableValuesType() reflect.Type {
530*333d2b36SAndroid Build Coastguard Worker	var fields []reflect.StructField
531*333d2b36SAndroid Build Coastguard Worker
532*333d2b36SAndroid Build Coastguard Worker	var values []string
533*333d2b36SAndroid Build Coastguard Worker	values = append(values, s.values...)
534*333d2b36SAndroid Build Coastguard Worker	values = append(values, conditionsDefault)
535*333d2b36SAndroid Build Coastguard Worker	for _, v := range values {
536*333d2b36SAndroid Build Coastguard Worker		fields = append(fields, reflect.StructField{
537*333d2b36SAndroid Build Coastguard Worker			Name: proptools.FieldNameForProperty(v),
538*333d2b36SAndroid Build Coastguard Worker			Type: emptyInterfaceType,
539*333d2b36SAndroid Build Coastguard Worker		})
540*333d2b36SAndroid Build Coastguard Worker	}
541*333d2b36SAndroid Build Coastguard Worker
542*333d2b36SAndroid Build Coastguard Worker	return reflect.StructOf(fields)
543*333d2b36SAndroid Build Coastguard Worker}
544*333d2b36SAndroid Build Coastguard Worker
545*333d2b36SAndroid Build Coastguard Worker// initializeProperties initializes properties to zero value of typ for supported values and a final
546*333d2b36SAndroid Build Coastguard Worker// conditions default field.
547*333d2b36SAndroid Build Coastguard Workerfunc (s *stringVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
548*333d2b36SAndroid Build Coastguard Worker	for i := range s.values {
549*333d2b36SAndroid Build Coastguard Worker		v.Field(i).Set(reflect.Zero(typ))
550*333d2b36SAndroid Build Coastguard Worker	}
551*333d2b36SAndroid Build Coastguard Worker	v.Field(len(s.values)).Set(reflect.Zero(typ)) // conditions default is the final value
552*333d2b36SAndroid Build Coastguard Worker}
553*333d2b36SAndroid Build Coastguard Worker
554*333d2b36SAndroid Build Coastguard Worker// Extracts an interface from values containing the properties to apply based on config.
555*333d2b36SAndroid Build Coastguard Worker// If config does not match a value with a non-nil property set, the default value will be returned.
556*333d2b36SAndroid Build Coastguard Workerfunc (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
557*333d2b36SAndroid Build Coastguard Worker	configValue := config.String(s.variable)
558*333d2b36SAndroid Build Coastguard Worker	if configValue != "" && !InList(configValue, s.values) {
559*333d2b36SAndroid Build Coastguard Worker		return nil, fmt.Errorf("Soong config property %q must be one of %v, found %q", s.variable, s.values, configValue)
560*333d2b36SAndroid Build Coastguard Worker	}
561*333d2b36SAndroid Build Coastguard Worker	for j, v := range s.values {
562*333d2b36SAndroid Build Coastguard Worker		f := values.Field(j)
563*333d2b36SAndroid Build Coastguard Worker		if configValue == v && !f.Elem().IsNil() {
564*333d2b36SAndroid Build Coastguard Worker			return f.Interface(), nil
565*333d2b36SAndroid Build Coastguard Worker		}
566*333d2b36SAndroid Build Coastguard Worker	}
567*333d2b36SAndroid Build Coastguard Worker	// if we have reached this point, we have checked all valid values of string and either:
568*333d2b36SAndroid Build Coastguard Worker	//   * the value was not set
569*333d2b36SAndroid Build Coastguard Worker	//   * the value was set but that value was not specified in the Android.bp file
570*333d2b36SAndroid Build Coastguard Worker	return values.Field(len(s.values)).Interface(), nil
571*333d2b36SAndroid Build Coastguard Worker}
572*333d2b36SAndroid Build Coastguard Worker
573*333d2b36SAndroid Build Coastguard Worker// Struct to allow conditions set based on a boolean variable
574*333d2b36SAndroid Build Coastguard Workertype boolVariable struct {
575*333d2b36SAndroid Build Coastguard Worker	baseVariable
576*333d2b36SAndroid Build Coastguard Worker}
577*333d2b36SAndroid Build Coastguard Worker
578*333d2b36SAndroid Build Coastguard Worker// newBoolVariable constructs a boolVariable with the given name
579*333d2b36SAndroid Build Coastguard Workerfunc newBoolVariable(name string) *boolVariable {
580*333d2b36SAndroid Build Coastguard Worker	return &boolVariable{
581*333d2b36SAndroid Build Coastguard Worker		baseVariable{
582*333d2b36SAndroid Build Coastguard Worker			variable: name,
583*333d2b36SAndroid Build Coastguard Worker		},
584*333d2b36SAndroid Build Coastguard Worker	}
585*333d2b36SAndroid Build Coastguard Worker}
586*333d2b36SAndroid Build Coastguard Worker
587*333d2b36SAndroid Build Coastguard Workerfunc (b boolVariable) variableValuesType() reflect.Type {
588*333d2b36SAndroid Build Coastguard Worker	return emptyInterfaceType
589*333d2b36SAndroid Build Coastguard Worker}
590*333d2b36SAndroid Build Coastguard Worker
591*333d2b36SAndroid Build Coastguard Worker// initializeProperties initializes a property to zero value of typ with an additional conditions
592*333d2b36SAndroid Build Coastguard Worker// default field.
593*333d2b36SAndroid Build Coastguard Workerfunc (b boolVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
594*333d2b36SAndroid Build Coastguard Worker	initializePropertiesWithDefault(v, typ)
595*333d2b36SAndroid Build Coastguard Worker}
596*333d2b36SAndroid Build Coastguard Worker
597*333d2b36SAndroid Build Coastguard Worker// initializePropertiesWithDefault, initialize with zero value,  v to contain a field for each field
598*333d2b36SAndroid Build Coastguard Worker// in typ, with an additional field for defaults of type typ. This should be used to initialize
599*333d2b36SAndroid Build Coastguard Worker// boolVariable, valueVariable, or any future implementations of soongConfigVariable which support
600*333d2b36SAndroid Build Coastguard Worker// one variable and a default.
601*333d2b36SAndroid Build Coastguard Workerfunc initializePropertiesWithDefault(v reflect.Value, typ reflect.Type) {
602*333d2b36SAndroid Build Coastguard Worker	sTyp := typ.Elem()
603*333d2b36SAndroid Build Coastguard Worker	var fields []reflect.StructField
604*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < sTyp.NumField(); i++ {
605*333d2b36SAndroid Build Coastguard Worker		fields = append(fields, sTyp.Field(i))
606*333d2b36SAndroid Build Coastguard Worker	}
607*333d2b36SAndroid Build Coastguard Worker
608*333d2b36SAndroid Build Coastguard Worker	// create conditions_default field
609*333d2b36SAndroid Build Coastguard Worker	nestedFieldName := proptools.FieldNameForProperty(conditionsDefault)
610*333d2b36SAndroid Build Coastguard Worker	fields = append(fields, reflect.StructField{
611*333d2b36SAndroid Build Coastguard Worker		Name: nestedFieldName,
612*333d2b36SAndroid Build Coastguard Worker		Type: typ,
613*333d2b36SAndroid Build Coastguard Worker	})
614*333d2b36SAndroid Build Coastguard Worker
615*333d2b36SAndroid Build Coastguard Worker	newTyp := reflect.PtrTo(reflect.StructOf(fields))
616*333d2b36SAndroid Build Coastguard Worker	v.Set(reflect.Zero(newTyp))
617*333d2b36SAndroid Build Coastguard Worker}
618*333d2b36SAndroid Build Coastguard Worker
619*333d2b36SAndroid Build Coastguard Worker// conditionsDefaultField extracts the conditions_default field from v. This is always the final
620*333d2b36SAndroid Build Coastguard Worker// field if initialized with initializePropertiesWithDefault.
621*333d2b36SAndroid Build Coastguard Workerfunc conditionsDefaultField(v reflect.Value) reflect.Value {
622*333d2b36SAndroid Build Coastguard Worker	return v.Field(v.NumField() - 1)
623*333d2b36SAndroid Build Coastguard Worker}
624*333d2b36SAndroid Build Coastguard Worker
625*333d2b36SAndroid Build Coastguard Worker// removeDefault removes the conditions_default field from values while retaining values from all
626*333d2b36SAndroid Build Coastguard Worker// other fields. This allows
627*333d2b36SAndroid Build Coastguard Workerfunc removeDefault(values reflect.Value) reflect.Value {
628*333d2b36SAndroid Build Coastguard Worker	v := values.Elem().Elem()
629*333d2b36SAndroid Build Coastguard Worker	s := conditionsDefaultField(v)
630*333d2b36SAndroid Build Coastguard Worker	// if conditions_default field was not set, there will be no issues extending properties.
631*333d2b36SAndroid Build Coastguard Worker	if !s.IsValid() {
632*333d2b36SAndroid Build Coastguard Worker		return v
633*333d2b36SAndroid Build Coastguard Worker	}
634*333d2b36SAndroid Build Coastguard Worker
635*333d2b36SAndroid Build Coastguard Worker	// If conditions_default field was set, it has the correct type for our property. Create a new
636*333d2b36SAndroid Build Coastguard Worker	// reflect.Value of the conditions_default type and copy all fields (except for
637*333d2b36SAndroid Build Coastguard Worker	// conditions_default) based on values to the result.
638*333d2b36SAndroid Build Coastguard Worker	res := reflect.New(s.Type().Elem())
639*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < res.Type().Elem().NumField(); i++ {
640*333d2b36SAndroid Build Coastguard Worker		val := v.Field(i)
641*333d2b36SAndroid Build Coastguard Worker		res.Elem().Field(i).Set(val)
642*333d2b36SAndroid Build Coastguard Worker	}
643*333d2b36SAndroid Build Coastguard Worker
644*333d2b36SAndroid Build Coastguard Worker	return res
645*333d2b36SAndroid Build Coastguard Worker}
646*333d2b36SAndroid Build Coastguard Worker
647*333d2b36SAndroid Build Coastguard Worker// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
648*333d2b36SAndroid Build Coastguard Worker// the module. If the value was not set, conditions_default interface will be returned; otherwise,
649*333d2b36SAndroid Build Coastguard Worker// the interface in values, without conditions_default will be returned.
650*333d2b36SAndroid Build Coastguard Workerfunc (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
651*333d2b36SAndroid Build Coastguard Worker	// If this variable was not referenced in the module, there are no properties to apply.
652*333d2b36SAndroid Build Coastguard Worker	if values.Elem().IsZero() {
653*333d2b36SAndroid Build Coastguard Worker		return nil, nil
654*333d2b36SAndroid Build Coastguard Worker	}
655*333d2b36SAndroid Build Coastguard Worker	if config.Bool(b.variable) {
656*333d2b36SAndroid Build Coastguard Worker		values = removeDefault(values)
657*333d2b36SAndroid Build Coastguard Worker		return values.Interface(), nil
658*333d2b36SAndroid Build Coastguard Worker	}
659*333d2b36SAndroid Build Coastguard Worker	v := values.Elem().Elem()
660*333d2b36SAndroid Build Coastguard Worker	if f := conditionsDefaultField(v); f.IsValid() {
661*333d2b36SAndroid Build Coastguard Worker		return f.Interface(), nil
662*333d2b36SAndroid Build Coastguard Worker	}
663*333d2b36SAndroid Build Coastguard Worker	return nil, nil
664*333d2b36SAndroid Build Coastguard Worker}
665*333d2b36SAndroid Build Coastguard Worker
666*333d2b36SAndroid Build Coastguard Worker// Struct to allow conditions set based on a value variable, supporting string substitution.
667*333d2b36SAndroid Build Coastguard Workertype valueVariable struct {
668*333d2b36SAndroid Build Coastguard Worker	baseVariable
669*333d2b36SAndroid Build Coastguard Worker}
670*333d2b36SAndroid Build Coastguard Worker
671*333d2b36SAndroid Build Coastguard Workerfunc (s *valueVariable) variableValuesType() reflect.Type {
672*333d2b36SAndroid Build Coastguard Worker	return emptyInterfaceType
673*333d2b36SAndroid Build Coastguard Worker}
674*333d2b36SAndroid Build Coastguard Worker
675*333d2b36SAndroid Build Coastguard Worker// initializeProperties initializes a property to zero value of typ with an additional conditions
676*333d2b36SAndroid Build Coastguard Worker// default field.
677*333d2b36SAndroid Build Coastguard Workerfunc (s *valueVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
678*333d2b36SAndroid Build Coastguard Worker	initializePropertiesWithDefault(v, typ)
679*333d2b36SAndroid Build Coastguard Worker}
680*333d2b36SAndroid Build Coastguard Worker
681*333d2b36SAndroid Build Coastguard Worker// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
682*333d2b36SAndroid Build Coastguard Worker// the module. If the variable was not set, conditions_default interface will be returned;
683*333d2b36SAndroid Build Coastguard Worker// otherwise, the interface in values, without conditions_default will be returned with all
684*333d2b36SAndroid Build Coastguard Worker// appropriate string substitutions based on variable being set.
685*333d2b36SAndroid Build Coastguard Workerfunc (s *valueVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
686*333d2b36SAndroid Build Coastguard Worker	// If this variable was not referenced in the module, there are no properties to apply.
687*333d2b36SAndroid Build Coastguard Worker	if !values.IsValid() || values.Elem().IsZero() {
688*333d2b36SAndroid Build Coastguard Worker		return nil, nil
689*333d2b36SAndroid Build Coastguard Worker	}
690*333d2b36SAndroid Build Coastguard Worker	if !config.IsSet(s.variable) {
691*333d2b36SAndroid Build Coastguard Worker		return conditionsDefaultField(values.Elem().Elem()).Interface(), nil
692*333d2b36SAndroid Build Coastguard Worker	}
693*333d2b36SAndroid Build Coastguard Worker	configValue := config.String(s.variable)
694*333d2b36SAndroid Build Coastguard Worker
695*333d2b36SAndroid Build Coastguard Worker	values = removeDefault(values)
696*333d2b36SAndroid Build Coastguard Worker	propStruct := values.Elem()
697*333d2b36SAndroid Build Coastguard Worker	if !propStruct.IsValid() {
698*333d2b36SAndroid Build Coastguard Worker		return nil, nil
699*333d2b36SAndroid Build Coastguard Worker	}
700*333d2b36SAndroid Build Coastguard Worker	if err := s.printfIntoPropertyRecursive(nil, propStruct, configValue); err != nil {
701*333d2b36SAndroid Build Coastguard Worker		return nil, err
702*333d2b36SAndroid Build Coastguard Worker	}
703*333d2b36SAndroid Build Coastguard Worker
704*333d2b36SAndroid Build Coastguard Worker	return values.Interface(), nil
705*333d2b36SAndroid Build Coastguard Worker}
706*333d2b36SAndroid Build Coastguard Worker
707*333d2b36SAndroid Build Coastguard Workerfunc (s *valueVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValue string) error {
708*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < propStruct.NumField(); i++ {
709*333d2b36SAndroid Build Coastguard Worker		field := propStruct.Field(i)
710*333d2b36SAndroid Build Coastguard Worker		kind := field.Kind()
711*333d2b36SAndroid Build Coastguard Worker		if kind == reflect.Ptr {
712*333d2b36SAndroid Build Coastguard Worker			if field.IsNil() {
713*333d2b36SAndroid Build Coastguard Worker				continue
714*333d2b36SAndroid Build Coastguard Worker			}
715*333d2b36SAndroid Build Coastguard Worker			field = field.Elem()
716*333d2b36SAndroid Build Coastguard Worker			kind = field.Kind()
717*333d2b36SAndroid Build Coastguard Worker		}
718*333d2b36SAndroid Build Coastguard Worker		switch kind {
719*333d2b36SAndroid Build Coastguard Worker		case reflect.String:
720*333d2b36SAndroid Build Coastguard Worker			err := printfIntoProperty(field, configValue)
721*333d2b36SAndroid Build Coastguard Worker			if err != nil {
722*333d2b36SAndroid Build Coastguard Worker				fieldName = append(fieldName, propStruct.Type().Field(i).Name)
723*333d2b36SAndroid Build Coastguard Worker				return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
724*333d2b36SAndroid Build Coastguard Worker			}
725*333d2b36SAndroid Build Coastguard Worker		case reflect.Slice:
726*333d2b36SAndroid Build Coastguard Worker			for j := 0; j < field.Len(); j++ {
727*333d2b36SAndroid Build Coastguard Worker				err := printfIntoProperty(field.Index(j), configValue)
728*333d2b36SAndroid Build Coastguard Worker				if err != nil {
729*333d2b36SAndroid Build Coastguard Worker					fieldName = append(fieldName, propStruct.Type().Field(i).Name)
730*333d2b36SAndroid Build Coastguard Worker					return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
731*333d2b36SAndroid Build Coastguard Worker				}
732*333d2b36SAndroid Build Coastguard Worker			}
733*333d2b36SAndroid Build Coastguard Worker		case reflect.Bool:
734*333d2b36SAndroid Build Coastguard Worker			// Nothing to do
735*333d2b36SAndroid Build Coastguard Worker		case reflect.Struct:
736*333d2b36SAndroid Build Coastguard Worker			if proptools.IsConfigurable(field.Type()) {
737*333d2b36SAndroid Build Coastguard Worker				if err := proptools.PrintfIntoConfigurable(field.Interface(), configValue); err != nil {
738*333d2b36SAndroid Build Coastguard Worker					fieldName = append(fieldName, propStruct.Type().Field(i).Name)
739*333d2b36SAndroid Build Coastguard Worker					return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
740*333d2b36SAndroid Build Coastguard Worker				}
741*333d2b36SAndroid Build Coastguard Worker			} else {
742*333d2b36SAndroid Build Coastguard Worker				fieldName = append(fieldName, propStruct.Type().Field(i).Name)
743*333d2b36SAndroid Build Coastguard Worker				if err := s.printfIntoPropertyRecursive(fieldName, field, configValue); err != nil {
744*333d2b36SAndroid Build Coastguard Worker					return err
745*333d2b36SAndroid Build Coastguard Worker				}
746*333d2b36SAndroid Build Coastguard Worker				fieldName = fieldName[:len(fieldName)-1]
747*333d2b36SAndroid Build Coastguard Worker			}
748*333d2b36SAndroid Build Coastguard Worker		default:
749*333d2b36SAndroid Build Coastguard Worker			fieldName = append(fieldName, propStruct.Type().Field(i).Name)
750*333d2b36SAndroid Build Coastguard Worker			return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind)
751*333d2b36SAndroid Build Coastguard Worker		}
752*333d2b36SAndroid Build Coastguard Worker	}
753*333d2b36SAndroid Build Coastguard Worker	return nil
754*333d2b36SAndroid Build Coastguard Worker}
755*333d2b36SAndroid Build Coastguard Worker
756*333d2b36SAndroid Build Coastguard Worker// Struct to allow conditions set based on a list variable, supporting string substitution.
757*333d2b36SAndroid Build Coastguard Workertype listVariable struct {
758*333d2b36SAndroid Build Coastguard Worker	baseVariable
759*333d2b36SAndroid Build Coastguard Worker}
760*333d2b36SAndroid Build Coastguard Worker
761*333d2b36SAndroid Build Coastguard Workerfunc (s *listVariable) variableValuesType() reflect.Type {
762*333d2b36SAndroid Build Coastguard Worker	return emptyInterfaceType
763*333d2b36SAndroid Build Coastguard Worker}
764*333d2b36SAndroid Build Coastguard Worker
765*333d2b36SAndroid Build Coastguard Worker// initializeProperties initializes a property to zero value of typ with an additional conditions
766*333d2b36SAndroid Build Coastguard Worker// default field.
767*333d2b36SAndroid Build Coastguard Workerfunc (s *listVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
768*333d2b36SAndroid Build Coastguard Worker	initializePropertiesWithDefault(v, typ)
769*333d2b36SAndroid Build Coastguard Worker}
770*333d2b36SAndroid Build Coastguard Worker
771*333d2b36SAndroid Build Coastguard Worker// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
772*333d2b36SAndroid Build Coastguard Worker// the module. If the variable was not set, conditions_default interface will be returned;
773*333d2b36SAndroid Build Coastguard Worker// otherwise, the interface in values, without conditions_default will be returned with all
774*333d2b36SAndroid Build Coastguard Worker// appropriate string substitutions based on variable being set.
775*333d2b36SAndroid Build Coastguard Workerfunc (s *listVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
776*333d2b36SAndroid Build Coastguard Worker	// If this variable was not referenced in the module, there are no properties to apply.
777*333d2b36SAndroid Build Coastguard Worker	if !values.IsValid() || values.Elem().IsZero() {
778*333d2b36SAndroid Build Coastguard Worker		return nil, nil
779*333d2b36SAndroid Build Coastguard Worker	}
780*333d2b36SAndroid Build Coastguard Worker	if !config.IsSet(s.variable) {
781*333d2b36SAndroid Build Coastguard Worker		return conditionsDefaultField(values.Elem().Elem()).Interface(), nil
782*333d2b36SAndroid Build Coastguard Worker	}
783*333d2b36SAndroid Build Coastguard Worker	configValues := strings.Split(config.String(s.variable), " ")
784*333d2b36SAndroid Build Coastguard Worker
785*333d2b36SAndroid Build Coastguard Worker	values = removeDefault(values)
786*333d2b36SAndroid Build Coastguard Worker	propStruct := values.Elem()
787*333d2b36SAndroid Build Coastguard Worker	if !propStruct.IsValid() {
788*333d2b36SAndroid Build Coastguard Worker		return nil, nil
789*333d2b36SAndroid Build Coastguard Worker	}
790*333d2b36SAndroid Build Coastguard Worker	if err := s.printfIntoPropertyRecursive(nil, propStruct, configValues); err != nil {
791*333d2b36SAndroid Build Coastguard Worker		return nil, err
792*333d2b36SAndroid Build Coastguard Worker	}
793*333d2b36SAndroid Build Coastguard Worker
794*333d2b36SAndroid Build Coastguard Worker	return values.Interface(), nil
795*333d2b36SAndroid Build Coastguard Worker}
796*333d2b36SAndroid Build Coastguard Worker
797*333d2b36SAndroid Build Coastguard Workerfunc (s *listVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValues []string) error {
798*333d2b36SAndroid Build Coastguard Worker	for i := 0; i < propStruct.NumField(); i++ {
799*333d2b36SAndroid Build Coastguard Worker		field := propStruct.Field(i)
800*333d2b36SAndroid Build Coastguard Worker		kind := field.Kind()
801*333d2b36SAndroid Build Coastguard Worker		if kind == reflect.Ptr {
802*333d2b36SAndroid Build Coastguard Worker			if field.IsNil() {
803*333d2b36SAndroid Build Coastguard Worker				continue
804*333d2b36SAndroid Build Coastguard Worker			}
805*333d2b36SAndroid Build Coastguard Worker			field = field.Elem()
806*333d2b36SAndroid Build Coastguard Worker			kind = field.Kind()
807*333d2b36SAndroid Build Coastguard Worker		}
808*333d2b36SAndroid Build Coastguard Worker		switch kind {
809*333d2b36SAndroid Build Coastguard Worker		case reflect.Slice:
810*333d2b36SAndroid Build Coastguard Worker			elemType := field.Type().Elem()
811*333d2b36SAndroid Build Coastguard Worker			newLen := field.Len() * len(configValues)
812*333d2b36SAndroid Build Coastguard Worker			newField := reflect.MakeSlice(field.Type(), 0, newLen)
813*333d2b36SAndroid Build Coastguard Worker			for j := 0; j < field.Len(); j++ {
814*333d2b36SAndroid Build Coastguard Worker				for _, configValue := range configValues {
815*333d2b36SAndroid Build Coastguard Worker					res := reflect.Indirect(reflect.New(elemType))
816*333d2b36SAndroid Build Coastguard Worker					res.Set(field.Index(j))
817*333d2b36SAndroid Build Coastguard Worker					err := printfIntoProperty(res, configValue)
818*333d2b36SAndroid Build Coastguard Worker					if err != nil {
819*333d2b36SAndroid Build Coastguard Worker						fieldName = append(fieldName, propStruct.Type().Field(i).Name)
820*333d2b36SAndroid Build Coastguard Worker						return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
821*333d2b36SAndroid Build Coastguard Worker					}
822*333d2b36SAndroid Build Coastguard Worker					newField = reflect.Append(newField, res)
823*333d2b36SAndroid Build Coastguard Worker				}
824*333d2b36SAndroid Build Coastguard Worker			}
825*333d2b36SAndroid Build Coastguard Worker			field.Set(newField)
826*333d2b36SAndroid Build Coastguard Worker		case reflect.Struct:
827*333d2b36SAndroid Build Coastguard Worker			if proptools.IsConfigurable(field.Type()) {
828*333d2b36SAndroid Build Coastguard Worker				fieldName = append(fieldName, propStruct.Type().Field(i).Name)
829*333d2b36SAndroid Build Coastguard Worker				return fmt.Errorf("soong_config_variables.%s.%s: list variables are not supported on configurable properties", s.variable, strings.Join(fieldName, "."))
830*333d2b36SAndroid Build Coastguard Worker			} else {
831*333d2b36SAndroid Build Coastguard Worker				fieldName = append(fieldName, propStruct.Type().Field(i).Name)
832*333d2b36SAndroid Build Coastguard Worker				if err := s.printfIntoPropertyRecursive(fieldName, field, configValues); err != nil {
833*333d2b36SAndroid Build Coastguard Worker					return err
834*333d2b36SAndroid Build Coastguard Worker				}
835*333d2b36SAndroid Build Coastguard Worker				fieldName = fieldName[:len(fieldName)-1]
836*333d2b36SAndroid Build Coastguard Worker			}
837*333d2b36SAndroid Build Coastguard Worker		default:
838*333d2b36SAndroid Build Coastguard Worker			fieldName = append(fieldName, propStruct.Type().Field(i).Name)
839*333d2b36SAndroid Build Coastguard Worker			return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind)
840*333d2b36SAndroid Build Coastguard Worker		}
841*333d2b36SAndroid Build Coastguard Worker	}
842*333d2b36SAndroid Build Coastguard Worker	return nil
843*333d2b36SAndroid Build Coastguard Worker}
844*333d2b36SAndroid Build Coastguard Worker
845*333d2b36SAndroid Build Coastguard Workerfunc printfIntoProperty(propertyValue reflect.Value, configValue string) error {
846*333d2b36SAndroid Build Coastguard Worker	s := propertyValue.String()
847*333d2b36SAndroid Build Coastguard Worker
848*333d2b36SAndroid Build Coastguard Worker	count := strings.Count(s, "%")
849*333d2b36SAndroid Build Coastguard Worker	if count == 0 {
850*333d2b36SAndroid Build Coastguard Worker		return nil
851*333d2b36SAndroid Build Coastguard Worker	}
852*333d2b36SAndroid Build Coastguard Worker
853*333d2b36SAndroid Build Coastguard Worker	if count > 1 {
854*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("list/value variable properties only support a single '%%'")
855*333d2b36SAndroid Build Coastguard Worker	}
856*333d2b36SAndroid Build Coastguard Worker
857*333d2b36SAndroid Build Coastguard Worker	if !strings.Contains(s, "%s") {
858*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("unsupported %% in value variable property")
859*333d2b36SAndroid Build Coastguard Worker	}
860*333d2b36SAndroid Build Coastguard Worker
861*333d2b36SAndroid Build Coastguard Worker	propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, configValue)))
862*333d2b36SAndroid Build Coastguard Worker
863*333d2b36SAndroid Build Coastguard Worker	return nil
864*333d2b36SAndroid Build Coastguard Worker}
865*333d2b36SAndroid Build Coastguard Worker
866*333d2b36SAndroid Build Coastguard Workerfunc CanonicalizeToProperty(v string) string {
867*333d2b36SAndroid Build Coastguard Worker	return strings.Map(func(r rune) rune {
868*333d2b36SAndroid Build Coastguard Worker		switch {
869*333d2b36SAndroid Build Coastguard Worker		case r >= 'A' && r <= 'Z',
870*333d2b36SAndroid Build Coastguard Worker			r >= 'a' && r <= 'z',
871*333d2b36SAndroid Build Coastguard Worker			r >= '0' && r <= '9',
872*333d2b36SAndroid Build Coastguard Worker			r == '_':
873*333d2b36SAndroid Build Coastguard Worker			return r
874*333d2b36SAndroid Build Coastguard Worker		default:
875*333d2b36SAndroid Build Coastguard Worker			return '_'
876*333d2b36SAndroid Build Coastguard Worker		}
877*333d2b36SAndroid Build Coastguard Worker	}, v)
878*333d2b36SAndroid Build Coastguard Worker}
879*333d2b36SAndroid Build Coastguard Worker
880*333d2b36SAndroid Build Coastguard Workerfunc CanonicalizeToProperties(values []string) []string {
881*333d2b36SAndroid Build Coastguard Worker	ret := make([]string, len(values))
882*333d2b36SAndroid Build Coastguard Worker	for i, v := range values {
883*333d2b36SAndroid Build Coastguard Worker		ret[i] = CanonicalizeToProperty(v)
884*333d2b36SAndroid Build Coastguard Worker	}
885*333d2b36SAndroid Build Coastguard Worker	return ret
886*333d2b36SAndroid Build Coastguard Worker}
887*333d2b36SAndroid Build Coastguard Worker
888*333d2b36SAndroid Build Coastguard Workertype emptyInterfaceStruct struct {
889*333d2b36SAndroid Build Coastguard Worker	i interface{}
890*333d2b36SAndroid Build Coastguard Worker}
891*333d2b36SAndroid Build Coastguard Worker
892*333d2b36SAndroid Build Coastguard Workervar emptyInterfaceType = reflect.TypeOf(emptyInterfaceStruct{}).Field(0).Type
893*333d2b36SAndroid Build Coastguard Worker
894*333d2b36SAndroid Build Coastguard Worker// InList checks if the string belongs to the list
895*333d2b36SAndroid Build Coastguard Workerfunc InList(s string, list []string) bool {
896*333d2b36SAndroid Build Coastguard Worker	for _, s2 := range list {
897*333d2b36SAndroid Build Coastguard Worker		if s2 == s {
898*333d2b36SAndroid Build Coastguard Worker			return true
899*333d2b36SAndroid Build Coastguard Worker		}
900*333d2b36SAndroid Build Coastguard Worker	}
901*333d2b36SAndroid Build Coastguard Worker	return false
902*333d2b36SAndroid Build Coastguard Worker}
903