modules.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. // Copyright 2020 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. package soongconfig
  15. import (
  16. "fmt"
  17. "io"
  18. "reflect"
  19. "sort"
  20. "strings"
  21. "sync"
  22. "github.com/google/blueprint/parser"
  23. "github.com/google/blueprint/proptools"
  24. "android/soong/starlark_fmt"
  25. )
  26. const conditionsDefault = "conditions_default"
  27. var SoongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
  28. // loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
  29. // result so each file is only parsed once.
  30. func Parse(r io.Reader, from string) (*SoongConfigDefinition, []error) {
  31. scope := parser.NewScope(nil)
  32. file, errs := parser.ParseAndEval(from, r, scope)
  33. if len(errs) > 0 {
  34. return nil, errs
  35. }
  36. mtDef := &SoongConfigDefinition{
  37. ModuleTypes: make(map[string]*ModuleType),
  38. variables: make(map[string]soongConfigVariable),
  39. }
  40. for _, def := range file.Defs {
  41. switch def := def.(type) {
  42. case *parser.Module:
  43. newErrs := processImportModuleDef(mtDef, def)
  44. if len(newErrs) > 0 {
  45. errs = append(errs, newErrs...)
  46. }
  47. case *parser.Assignment:
  48. // Already handled via Scope object
  49. default:
  50. panic("unknown definition type")
  51. }
  52. }
  53. if len(errs) > 0 {
  54. return nil, errs
  55. }
  56. for name, moduleType := range mtDef.ModuleTypes {
  57. for _, varName := range moduleType.variableNames {
  58. if v, ok := mtDef.variables[varName]; ok {
  59. moduleType.Variables = append(moduleType.Variables, v)
  60. } else {
  61. return nil, []error{
  62. fmt.Errorf("unknown variable %q in module type %q", varName, name),
  63. }
  64. }
  65. }
  66. }
  67. return mtDef, nil
  68. }
  69. func processImportModuleDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
  70. switch def.Type {
  71. case "soong_config_module_type":
  72. return processModuleTypeDef(v, def)
  73. case "soong_config_string_variable":
  74. return processStringVariableDef(v, def)
  75. case "soong_config_bool_variable":
  76. return processBoolVariableDef(v, def)
  77. default:
  78. // Unknown module types will be handled when the file is parsed as a normal
  79. // Android.bp file.
  80. }
  81. return nil
  82. }
  83. type ModuleTypeProperties struct {
  84. // the name of the new module type. Unlike most modules, this name does not need to be unique,
  85. // although only one module type with any name will be importable into an Android.bp file.
  86. Name string
  87. // the module type that this module type will extend.
  88. Module_type string
  89. // the SOONG_CONFIG_NAMESPACE value from a BoardConfig.mk that this module type will read
  90. // configuration variables from.
  91. Config_namespace string
  92. // the list of SOONG_CONFIG variables that this module type will read
  93. Variables []string
  94. // the list of boolean SOONG_CONFIG variables that this module type will read
  95. Bool_variables []string
  96. // the list of SOONG_CONFIG variables that this module type will read. The value will be
  97. // inserted into the properties with %s substitution.
  98. Value_variables []string
  99. // the list of properties that this module type will extend.
  100. Properties []string
  101. }
  102. func processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
  103. props := &ModuleTypeProperties{}
  104. _, errs = proptools.UnpackProperties(def.Properties, props)
  105. if len(errs) > 0 {
  106. return errs
  107. }
  108. if props.Name == "" {
  109. errs = append(errs, fmt.Errorf("name property must be set"))
  110. }
  111. if props.Config_namespace == "" {
  112. errs = append(errs, fmt.Errorf("config_namespace property must be set"))
  113. }
  114. if props.Module_type == "" {
  115. errs = append(errs, fmt.Errorf("module_type property must be set"))
  116. }
  117. if len(errs) > 0 {
  118. return errs
  119. }
  120. if mt, errs := newModuleType(props); len(errs) > 0 {
  121. return errs
  122. } else {
  123. v.ModuleTypes[props.Name] = mt
  124. }
  125. return nil
  126. }
  127. type VariableProperties struct {
  128. Name string
  129. }
  130. type StringVariableProperties struct {
  131. Values []string
  132. }
  133. func processStringVariableDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
  134. stringProps := &StringVariableProperties{}
  135. base, errs := processVariableDef(def, stringProps)
  136. if len(errs) > 0 {
  137. return errs
  138. }
  139. if len(stringProps.Values) == 0 {
  140. return []error{fmt.Errorf("values property must be set")}
  141. }
  142. vals := make(map[string]bool, len(stringProps.Values))
  143. for _, name := range stringProps.Values {
  144. if err := checkVariableName(name); err != nil {
  145. return []error{fmt.Errorf("soong_config_string_variable: values property error %s", err)}
  146. } else if _, ok := vals[name]; ok {
  147. return []error{fmt.Errorf("soong_config_string_variable: values property error: duplicate value: %q", name)}
  148. }
  149. vals[name] = true
  150. }
  151. v.variables[base.variable] = &stringVariable{
  152. baseVariable: base,
  153. values: CanonicalizeToProperties(stringProps.Values),
  154. }
  155. return nil
  156. }
  157. func processBoolVariableDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
  158. base, errs := processVariableDef(def)
  159. if len(errs) > 0 {
  160. return errs
  161. }
  162. v.variables[base.variable] = &boolVariable{
  163. baseVariable: base,
  164. }
  165. return nil
  166. }
  167. func processVariableDef(def *parser.Module,
  168. extraProps ...interface{}) (cond baseVariable, errs []error) {
  169. props := &VariableProperties{}
  170. allProps := append([]interface{}{props}, extraProps...)
  171. _, errs = proptools.UnpackProperties(def.Properties, allProps...)
  172. if len(errs) > 0 {
  173. return baseVariable{}, errs
  174. }
  175. if props.Name == "" {
  176. return baseVariable{}, []error{fmt.Errorf("name property must be set")}
  177. }
  178. return baseVariable{
  179. variable: props.Name,
  180. }, nil
  181. }
  182. type SoongConfigDefinition struct {
  183. ModuleTypes map[string]*ModuleType
  184. variables map[string]soongConfigVariable
  185. }
  186. // Bp2BuildSoongConfigDefinition keeps a global record of all soong config
  187. // string vars, bool vars and value vars created by every
  188. // soong_config_module_type in this build.
  189. type Bp2BuildSoongConfigDefinitions struct {
  190. StringVars map[string]map[string]bool
  191. BoolVars map[string]bool
  192. ValueVars map[string]bool
  193. }
  194. var bp2buildSoongConfigVarsLock sync.Mutex
  195. // SoongConfigVariablesForBp2build extracts information from a
  196. // SoongConfigDefinition that bp2build needs to generate constraint settings and
  197. // values for, in order to migrate soong_config_module_type usages to Bazel.
  198. func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef *SoongConfigDefinition) {
  199. // In bp2build mode, this method is called concurrently in goroutines from
  200. // loadhooks while parsing soong_config_module_type, so add a mutex to
  201. // prevent concurrent map writes. See b/207572723
  202. bp2buildSoongConfigVarsLock.Lock()
  203. defer bp2buildSoongConfigVarsLock.Unlock()
  204. if defs.StringVars == nil {
  205. defs.StringVars = make(map[string]map[string]bool)
  206. }
  207. if defs.BoolVars == nil {
  208. defs.BoolVars = make(map[string]bool)
  209. }
  210. if defs.ValueVars == nil {
  211. defs.ValueVars = make(map[string]bool)
  212. }
  213. // varCache contains a cache of string variables namespace + property
  214. // The same variable may be used in multiple module types (for example, if need support
  215. // for cc_default and java_default), only need to process once
  216. varCache := map[string]bool{}
  217. for _, moduleType := range mtDef.ModuleTypes {
  218. for _, v := range moduleType.Variables {
  219. key := strings.Join([]string{moduleType.ConfigNamespace, v.variableProperty()}, "__")
  220. // The same variable may be used in multiple module types (for example, if need support
  221. // for cc_default and java_default), only need to process once
  222. if _, keyInCache := varCache[key]; keyInCache {
  223. continue
  224. } else {
  225. varCache[key] = true
  226. }
  227. if strVar, ok := v.(*stringVariable); ok {
  228. if _, ok := defs.StringVars[key]; !ok {
  229. defs.StringVars[key] = make(map[string]bool, len(strVar.values))
  230. }
  231. for _, value := range strVar.values {
  232. defs.StringVars[key][value] = true
  233. }
  234. } else if _, ok := v.(*boolVariable); ok {
  235. defs.BoolVars[key] = true
  236. } else if _, ok := v.(*valueVariable); ok {
  237. defs.ValueVars[key] = true
  238. } else {
  239. panic(fmt.Errorf("Unsupported variable type: %+v", v))
  240. }
  241. }
  242. }
  243. }
  244. // This is a copy of the one available in soong/android/util.go, but depending
  245. // on the android package causes a cyclic dependency. A refactoring here is to
  246. // extract common utils out from android/utils.go for other packages like this.
  247. func sortedStringKeys(m interface{}) []string {
  248. v := reflect.ValueOf(m)
  249. if v.Kind() != reflect.Map {
  250. panic(fmt.Sprintf("%#v is not a map", m))
  251. }
  252. keys := v.MapKeys()
  253. s := make([]string, 0, len(keys))
  254. for _, key := range keys {
  255. s = append(s, key.String())
  256. }
  257. sort.Strings(s)
  258. return s
  259. }
  260. // String emits the Soong config variable definitions as Starlark dictionaries.
  261. func (defs Bp2BuildSoongConfigDefinitions) String() string {
  262. ret := ""
  263. ret += "soong_config_bool_variables = "
  264. ret += starlark_fmt.PrintBoolDict(defs.BoolVars, 0)
  265. ret += "\n\n"
  266. ret += "soong_config_value_variables = "
  267. ret += starlark_fmt.PrintBoolDict(defs.ValueVars, 0)
  268. ret += "\n\n"
  269. stringVars := make(map[string][]string, len(defs.StringVars))
  270. for k, v := range defs.StringVars {
  271. stringVars[k] = sortedStringKeys(v)
  272. }
  273. ret += "soong_config_string_variables = "
  274. ret += starlark_fmt.PrintStringListDict(stringVars, 0)
  275. return ret
  276. }
  277. // CreateProperties returns a reflect.Value of a newly constructed type that contains the desired
  278. // property layout for the Soong config variables, with each possible value an interface{} that
  279. // contains a nil pointer to another newly constructed type that contains the affectable properties.
  280. // The reflect.Value will be cloned for each call to the Soong config module type's factory method.
  281. //
  282. // For example, the acme_cc_defaults example above would
  283. // produce a reflect.Value whose type is:
  284. //
  285. // *struct {
  286. // Soong_config_variables struct {
  287. // Board struct {
  288. // Soc_a interface{}
  289. // Soc_b interface{}
  290. // }
  291. // }
  292. // }
  293. //
  294. // And whose value is:
  295. //
  296. // &{
  297. // Soong_config_variables: {
  298. // Board: {
  299. // Soc_a: (*struct{ Cflags []string })(nil),
  300. // Soc_b: (*struct{ Cflags []string })(nil),
  301. // },
  302. // },
  303. // }
  304. func CreateProperties(factoryProps []interface{}, moduleType *ModuleType) reflect.Value {
  305. var fields []reflect.StructField
  306. affectablePropertiesType := createAffectablePropertiesType(moduleType.affectableProperties, factoryProps)
  307. if affectablePropertiesType == nil {
  308. return reflect.Value{}
  309. }
  310. for _, c := range moduleType.Variables {
  311. fields = append(fields, reflect.StructField{
  312. Name: proptools.FieldNameForProperty(c.variableProperty()),
  313. Type: c.variableValuesType(),
  314. })
  315. }
  316. typ := reflect.StructOf([]reflect.StructField{{
  317. Name: SoongConfigProperty,
  318. Type: reflect.StructOf(fields),
  319. }})
  320. props := reflect.New(typ)
  321. structConditions := props.Elem().FieldByName(SoongConfigProperty)
  322. for i, c := range moduleType.Variables {
  323. c.initializeProperties(structConditions.Field(i), affectablePropertiesType)
  324. }
  325. return props
  326. }
  327. // createAffectablePropertiesType creates a reflect.Type of a struct that has a field for each affectable property
  328. // that exists in factoryProps.
  329. func createAffectablePropertiesType(affectableProperties []string, factoryProps []interface{}) reflect.Type {
  330. affectableProperties = append([]string(nil), affectableProperties...)
  331. sort.Strings(affectableProperties)
  332. var recurse func(prefix string, aps []string) ([]string, reflect.Type)
  333. recurse = func(prefix string, aps []string) ([]string, reflect.Type) {
  334. var fields []reflect.StructField
  335. // Iterate while the list is non-empty so it can be modified in the loop.
  336. for len(affectableProperties) > 0 {
  337. p := affectableProperties[0]
  338. if !strings.HasPrefix(affectableProperties[0], prefix) {
  339. // The properties are sorted and recurse is always called with a prefix that matches
  340. // the first property in the list, so if we've reached one that doesn't match the
  341. // prefix we are done with this prefix.
  342. break
  343. }
  344. nestedProperty := strings.TrimPrefix(p, prefix)
  345. if i := strings.IndexRune(nestedProperty, '.'); i >= 0 {
  346. var nestedType reflect.Type
  347. nestedPrefix := nestedProperty[:i+1]
  348. // Recurse to handle the properties with the found prefix. This will return
  349. // an updated affectableProperties with the handled entries removed from the front
  350. // of the list, and the type that contains the handled entries. The type may be
  351. // nil if none of the entries matched factoryProps.
  352. affectableProperties, nestedType = recurse(prefix+nestedPrefix, affectableProperties)
  353. if nestedType != nil {
  354. nestedFieldName := proptools.FieldNameForProperty(strings.TrimSuffix(nestedPrefix, "."))
  355. fields = append(fields, reflect.StructField{
  356. Name: nestedFieldName,
  357. Type: nestedType,
  358. })
  359. }
  360. } else {
  361. typ := typeForPropertyFromPropertyStructs(factoryProps, p)
  362. if typ != nil {
  363. fields = append(fields, reflect.StructField{
  364. Name: proptools.FieldNameForProperty(nestedProperty),
  365. Type: typ,
  366. })
  367. }
  368. // The first element in the list has been handled, remove it from the list.
  369. affectableProperties = affectableProperties[1:]
  370. }
  371. }
  372. var typ reflect.Type
  373. if len(fields) > 0 {
  374. typ = reflect.StructOf(fields)
  375. }
  376. return affectableProperties, typ
  377. }
  378. affectableProperties, typ := recurse("", affectableProperties)
  379. if len(affectableProperties) > 0 {
  380. panic(fmt.Errorf("didn't handle all affectable properties"))
  381. }
  382. if typ != nil {
  383. return reflect.PtrTo(typ)
  384. }
  385. return nil
  386. }
  387. func typeForPropertyFromPropertyStructs(psList []interface{}, property string) reflect.Type {
  388. for _, ps := range psList {
  389. if typ := typeForPropertyFromPropertyStruct(ps, property); typ != nil {
  390. return typ
  391. }
  392. }
  393. return nil
  394. }
  395. func typeForPropertyFromPropertyStruct(ps interface{}, property string) reflect.Type {
  396. v := reflect.ValueOf(ps)
  397. for len(property) > 0 {
  398. if !v.IsValid() {
  399. return nil
  400. }
  401. if v.Kind() == reflect.Interface {
  402. if v.IsNil() {
  403. return nil
  404. } else {
  405. v = v.Elem()
  406. }
  407. }
  408. if v.Kind() == reflect.Ptr {
  409. if v.IsNil() {
  410. v = reflect.Zero(v.Type().Elem())
  411. } else {
  412. v = v.Elem()
  413. }
  414. }
  415. if v.Kind() != reflect.Struct {
  416. return nil
  417. }
  418. if index := strings.IndexRune(property, '.'); index >= 0 {
  419. prefix := property[:index]
  420. property = property[index+1:]
  421. v = v.FieldByName(proptools.FieldNameForProperty(prefix))
  422. } else {
  423. f := v.FieldByName(proptools.FieldNameForProperty(property))
  424. if !f.IsValid() {
  425. return nil
  426. }
  427. return f.Type()
  428. }
  429. }
  430. return nil
  431. }
  432. // PropertiesToApply returns the applicable properties from a ModuleType that should be applied
  433. // based on SoongConfig values.
  434. // Expects that props contains a struct field with name soong_config_variables. The fields within
  435. // soong_config_variables are expected to be in the same order as moduleType.Variables.
  436. func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
  437. var ret []interface{}
  438. props = props.Elem().FieldByName(SoongConfigProperty)
  439. for i, c := range moduleType.Variables {
  440. if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
  441. return nil, err
  442. } else if ps != nil {
  443. ret = append(ret, ps)
  444. }
  445. }
  446. return ret, nil
  447. }
  448. type ModuleType struct {
  449. BaseModuleType string
  450. ConfigNamespace string
  451. Variables []soongConfigVariable
  452. affectableProperties []string
  453. variableNames []string
  454. }
  455. func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
  456. mt := &ModuleType{
  457. affectableProperties: props.Properties,
  458. ConfigNamespace: props.Config_namespace,
  459. BaseModuleType: props.Module_type,
  460. variableNames: props.Variables,
  461. }
  462. for _, name := range props.Bool_variables {
  463. if err := checkVariableName(name); err != nil {
  464. return nil, []error{fmt.Errorf("bool_variables %s", err)}
  465. }
  466. mt.Variables = append(mt.Variables, newBoolVariable(name))
  467. }
  468. for _, name := range props.Value_variables {
  469. if err := checkVariableName(name); err != nil {
  470. return nil, []error{fmt.Errorf("value_variables %s", err)}
  471. }
  472. mt.Variables = append(mt.Variables, &valueVariable{
  473. baseVariable: baseVariable{
  474. variable: name,
  475. },
  476. })
  477. }
  478. return mt, nil
  479. }
  480. func checkVariableName(name string) error {
  481. if name == "" {
  482. return fmt.Errorf("name must not be blank")
  483. } else if name == conditionsDefault {
  484. return fmt.Errorf("%q is reserved", conditionsDefault)
  485. }
  486. return nil
  487. }
  488. type soongConfigVariable interface {
  489. // variableProperty returns the name of the variable.
  490. variableProperty() string
  491. // conditionalValuesType returns a reflect.Type that contains an interface{} for each possible value.
  492. variableValuesType() reflect.Type
  493. // initializeProperties is passed a reflect.Value of the reflect.Type returned by conditionalValuesType and a
  494. // reflect.Type of the affectable properties, and should initialize each interface{} in the reflect.Value with
  495. // the zero value of the affectable properties type.
  496. initializeProperties(v reflect.Value, typ reflect.Type)
  497. // PropertiesToApply should return one of the interface{} values set by initializeProperties to be applied
  498. // to the module.
  499. PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error)
  500. }
  501. type baseVariable struct {
  502. variable string
  503. }
  504. func (c *baseVariable) variableProperty() string {
  505. return CanonicalizeToProperty(c.variable)
  506. }
  507. type stringVariable struct {
  508. baseVariable
  509. values []string
  510. }
  511. func (s *stringVariable) variableValuesType() reflect.Type {
  512. var fields []reflect.StructField
  513. var values []string
  514. values = append(values, s.values...)
  515. values = append(values, conditionsDefault)
  516. for _, v := range values {
  517. fields = append(fields, reflect.StructField{
  518. Name: proptools.FieldNameForProperty(v),
  519. Type: emptyInterfaceType,
  520. })
  521. }
  522. return reflect.StructOf(fields)
  523. }
  524. // initializeProperties initializes properties to zero value of typ for supported values and a final
  525. // conditions default field.
  526. func (s *stringVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
  527. for i := range s.values {
  528. v.Field(i).Set(reflect.Zero(typ))
  529. }
  530. v.Field(len(s.values)).Set(reflect.Zero(typ)) // conditions default is the final value
  531. }
  532. // Extracts an interface from values containing the properties to apply based on config.
  533. // If config does not match a value with a non-nil property set, the default value will be returned.
  534. func (s *stringVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
  535. configValue := config.String(s.variable)
  536. if configValue != "" && !InList(configValue, s.values) {
  537. return nil, fmt.Errorf("Soong config property %q must be one of %v, found %q", s.variable, s.values, configValue)
  538. }
  539. for j, v := range s.values {
  540. f := values.Field(j)
  541. if configValue == v && !f.Elem().IsNil() {
  542. return f.Interface(), nil
  543. }
  544. }
  545. // if we have reached this point, we have checked all valid values of string and either:
  546. // * the value was not set
  547. // * the value was set but that value was not specified in the Android.bp file
  548. return values.Field(len(s.values)).Interface(), nil
  549. }
  550. // Struct to allow conditions set based on a boolean variable
  551. type boolVariable struct {
  552. baseVariable
  553. }
  554. // newBoolVariable constructs a boolVariable with the given name
  555. func newBoolVariable(name string) *boolVariable {
  556. return &boolVariable{
  557. baseVariable{
  558. variable: name,
  559. },
  560. }
  561. }
  562. func (b boolVariable) variableValuesType() reflect.Type {
  563. return emptyInterfaceType
  564. }
  565. // initializeProperties initializes a property to zero value of typ with an additional conditions
  566. // default field.
  567. func (b boolVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
  568. initializePropertiesWithDefault(v, typ)
  569. }
  570. // initializePropertiesWithDefault, initialize with zero value, v to contain a field for each field
  571. // in typ, with an additional field for defaults of type typ. This should be used to initialize
  572. // boolVariable, valueVariable, or any future implementations of soongConfigVariable which support
  573. // one variable and a default.
  574. func initializePropertiesWithDefault(v reflect.Value, typ reflect.Type) {
  575. sTyp := typ.Elem()
  576. var fields []reflect.StructField
  577. for i := 0; i < sTyp.NumField(); i++ {
  578. fields = append(fields, sTyp.Field(i))
  579. }
  580. // create conditions_default field
  581. nestedFieldName := proptools.FieldNameForProperty(conditionsDefault)
  582. fields = append(fields, reflect.StructField{
  583. Name: nestedFieldName,
  584. Type: typ,
  585. })
  586. newTyp := reflect.PtrTo(reflect.StructOf(fields))
  587. v.Set(reflect.Zero(newTyp))
  588. }
  589. // conditionsDefaultField extracts the conditions_default field from v. This is always the final
  590. // field if initialized with initializePropertiesWithDefault.
  591. func conditionsDefaultField(v reflect.Value) reflect.Value {
  592. return v.Field(v.NumField() - 1)
  593. }
  594. // removeDefault removes the conditions_default field from values while retaining values from all
  595. // other fields. This allows
  596. func removeDefault(values reflect.Value) reflect.Value {
  597. v := values.Elem().Elem()
  598. s := conditionsDefaultField(v)
  599. // if conditions_default field was not set, there will be no issues extending properties.
  600. if !s.IsValid() {
  601. return v
  602. }
  603. // If conditions_default field was set, it has the correct type for our property. Create a new
  604. // reflect.Value of the conditions_default type and copy all fields (except for
  605. // conditions_default) based on values to the result.
  606. res := reflect.New(s.Type().Elem())
  607. for i := 0; i < res.Type().Elem().NumField(); i++ {
  608. val := v.Field(i)
  609. res.Elem().Field(i).Set(val)
  610. }
  611. return res
  612. }
  613. // PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
  614. // the module. If the value was not set, conditions_default interface will be returned; otherwise,
  615. // the interface in values, without conditions_default will be returned.
  616. func (b boolVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
  617. // If this variable was not referenced in the module, there are no properties to apply.
  618. if values.Elem().IsZero() {
  619. return nil, nil
  620. }
  621. if config.Bool(b.variable) {
  622. values = removeDefault(values)
  623. return values.Interface(), nil
  624. }
  625. v := values.Elem().Elem()
  626. if f := conditionsDefaultField(v); f.IsValid() {
  627. return f.Interface(), nil
  628. }
  629. return nil, nil
  630. }
  631. // Struct to allow conditions set based on a value variable, supporting string substitution.
  632. type valueVariable struct {
  633. baseVariable
  634. }
  635. func (s *valueVariable) variableValuesType() reflect.Type {
  636. return emptyInterfaceType
  637. }
  638. // initializeProperties initializes a property to zero value of typ with an additional conditions
  639. // default field.
  640. func (s *valueVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
  641. initializePropertiesWithDefault(v, typ)
  642. }
  643. // PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
  644. // the module. If the variable was not set, conditions_default interface will be returned;
  645. // otherwise, the interface in values, without conditions_default will be returned with all
  646. // appropriate string substitutions based on variable being set.
  647. func (s *valueVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
  648. // If this variable was not referenced in the module, there are no properties to apply.
  649. if !values.IsValid() || values.Elem().IsZero() {
  650. return nil, nil
  651. }
  652. if !config.IsSet(s.variable) {
  653. return conditionsDefaultField(values.Elem().Elem()).Interface(), nil
  654. }
  655. configValue := config.String(s.variable)
  656. values = removeDefault(values)
  657. propStruct := values.Elem()
  658. if !propStruct.IsValid() {
  659. return nil, nil
  660. }
  661. for i := 0; i < propStruct.NumField(); i++ {
  662. field := propStruct.Field(i)
  663. kind := field.Kind()
  664. if kind == reflect.Ptr {
  665. if field.IsNil() {
  666. continue
  667. }
  668. field = field.Elem()
  669. }
  670. switch kind {
  671. case reflect.String:
  672. err := printfIntoProperty(field, configValue)
  673. if err != nil {
  674. return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
  675. }
  676. case reflect.Slice:
  677. for j := 0; j < field.Len(); j++ {
  678. err := printfIntoProperty(field.Index(j), configValue)
  679. if err != nil {
  680. return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
  681. }
  682. }
  683. case reflect.Bool:
  684. // Nothing to do
  685. default:
  686. return nil, fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, propStruct.Type().Field(i).Name, kind)
  687. }
  688. }
  689. return values.Interface(), nil
  690. }
  691. func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
  692. s := propertyValue.String()
  693. count := strings.Count(s, "%")
  694. if count == 0 {
  695. return nil
  696. }
  697. if count > 1 {
  698. return fmt.Errorf("value variable properties only support a single '%%'")
  699. }
  700. if !strings.Contains(s, "%s") {
  701. return fmt.Errorf("unsupported %% in value variable property")
  702. }
  703. propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, configValue)))
  704. return nil
  705. }
  706. func CanonicalizeToProperty(v string) string {
  707. return strings.Map(func(r rune) rune {
  708. switch {
  709. case r >= 'A' && r <= 'Z',
  710. r >= 'a' && r <= 'z',
  711. r >= '0' && r <= '9',
  712. r == '_':
  713. return r
  714. default:
  715. return '_'
  716. }
  717. }, v)
  718. }
  719. func CanonicalizeToProperties(values []string) []string {
  720. ret := make([]string, len(values))
  721. for i, v := range values {
  722. ret[i] = CanonicalizeToProperty(v)
  723. }
  724. return ret
  725. }
  726. type emptyInterfaceStruct struct {
  727. i interface{}
  728. }
  729. var emptyInterfaceType = reflect.TypeOf(emptyInterfaceStruct{}).Field(0).Type
  730. // InList checks if the string belongs to the list
  731. func InList(s string, list []string) bool {
  732. for _, s2 := range list {
  733. if s2 == s {
  734. return true
  735. }
  736. }
  737. return false
  738. }