configurability.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package bp2build
  2. import (
  3. "fmt"
  4. "reflect"
  5. "android/soong/android"
  6. "android/soong/bazel"
  7. "android/soong/starlark_fmt"
  8. )
  9. // Configurability support for bp2build.
  10. type selects map[string]reflect.Value
  11. func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
  12. value := reflect.ValueOf(list.Value)
  13. if !list.HasConfigurableValues() {
  14. return value, []selects{}
  15. }
  16. var ret []selects
  17. for _, axis := range list.SortedConfigurationAxes() {
  18. configToLists := list.ConfigurableValues[axis]
  19. archSelects := map[string]reflect.Value{}
  20. for config, labels := range configToLists {
  21. selectKey := axis.SelectKey(config)
  22. archSelects[selectKey] = reflect.ValueOf(labels)
  23. }
  24. if len(archSelects) > 0 {
  25. ret = append(ret, archSelects)
  26. }
  27. }
  28. return value, ret
  29. }
  30. func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
  31. value := reflect.ValueOf(label.Value)
  32. if !label.HasConfigurableValues() {
  33. return value, []selects{}
  34. }
  35. ret := selects{}
  36. for _, axis := range label.SortedConfigurationAxes() {
  37. configToLabels := label.ConfigurableValues[axis]
  38. for config, labels := range configToLabels {
  39. selectKey := axis.SelectKey(config)
  40. ret[selectKey] = reflect.ValueOf(labels)
  41. }
  42. }
  43. // if there is a select, use the base value as the conditions default value
  44. if len(ret) > 0 {
  45. ret[bazel.ConditionsDefaultSelectKey] = value
  46. value = reflect.Zero(value.Type())
  47. }
  48. return value, []selects{ret}
  49. }
  50. func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
  51. value := reflect.ValueOf(boolAttr.Value)
  52. if !boolAttr.HasConfigurableValues() {
  53. return value, []selects{}
  54. }
  55. ret := selects{}
  56. for _, axis := range boolAttr.SortedConfigurationAxes() {
  57. configToBools := boolAttr.ConfigurableValues[axis]
  58. for config, bools := range configToBools {
  59. selectKey := axis.SelectKey(config)
  60. ret[selectKey] = reflect.ValueOf(bools)
  61. }
  62. }
  63. // if there is a select, use the base value as the conditions default value
  64. if len(ret) > 0 {
  65. ret[bazel.ConditionsDefaultSelectKey] = value
  66. value = reflect.Zero(value.Type())
  67. }
  68. return value, []selects{ret}
  69. }
  70. func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
  71. value := reflect.ValueOf(list.Value.Includes)
  72. var ret []selects
  73. for _, axis := range list.SortedConfigurationAxes() {
  74. configToLabels := list.ConfigurableValues[axis]
  75. if !configToLabels.HasConfigurableValues() {
  76. continue
  77. }
  78. archSelects := map[string]reflect.Value{}
  79. defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
  80. // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
  81. emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
  82. for config, labels := range configToLabels {
  83. // Omit any entries in the map which match the default value, for brevity.
  84. if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
  85. continue
  86. }
  87. selectKey := axis.SelectKey(config)
  88. if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
  89. archSelects[selectKey] = value
  90. }
  91. }
  92. if len(archSelects) > 0 {
  93. ret = append(ret, archSelects)
  94. }
  95. }
  96. return value, ret
  97. }
  98. func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
  99. if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
  100. return true, reflect.ValueOf(list.Includes)
  101. } else if len(list.Excludes) > 0 {
  102. // if there is still an excludes -- we need to have an empty list for this select & use the
  103. // value in conditions default Includes
  104. return true, reflect.ValueOf([]string{})
  105. }
  106. return false, reflect.Zero(reflect.TypeOf([]string{}))
  107. }
  108. var (
  109. emptyBazelList = "[]"
  110. bazelNone = "None"
  111. )
  112. // prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
  113. // select statements.
  114. func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
  115. var value reflect.Value
  116. var configurableAttrs []selects
  117. var defaultSelectValue *string
  118. var emitZeroValues bool
  119. // If true, print the default attribute value, even if the attribute is zero.
  120. shouldPrintDefault := false
  121. switch list := v.(type) {
  122. case bazel.StringListAttribute:
  123. value, configurableAttrs = getStringListValues(list)
  124. defaultSelectValue = &emptyBazelList
  125. case bazel.LabelListAttribute:
  126. value, configurableAttrs = getLabelListValues(list)
  127. emitZeroValues = list.EmitEmptyList
  128. defaultSelectValue = &emptyBazelList
  129. if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
  130. shouldPrintDefault = true
  131. }
  132. case bazel.LabelAttribute:
  133. if err := list.Collapse(); err != nil {
  134. return "", err
  135. }
  136. value, configurableAttrs = getLabelValue(list)
  137. defaultSelectValue = &bazelNone
  138. case bazel.BoolAttribute:
  139. if err := list.Collapse(); err != nil {
  140. return "", err
  141. }
  142. value, configurableAttrs = getBoolValue(list)
  143. defaultSelectValue = &bazelNone
  144. default:
  145. return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
  146. }
  147. var err error
  148. ret := ""
  149. if value.Kind() != reflect.Invalid {
  150. s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
  151. if err != nil {
  152. return ret, err
  153. }
  154. ret += s
  155. }
  156. // Convenience function to append selects components to an attribute value.
  157. appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
  158. selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
  159. if err != nil {
  160. return "", err
  161. }
  162. if s != "" && selectMap != "" {
  163. s += " + "
  164. }
  165. s += selectMap
  166. return s, nil
  167. }
  168. for _, configurableAttr := range configurableAttrs {
  169. ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
  170. if err != nil {
  171. return "", err
  172. }
  173. }
  174. if ret == "" && shouldPrintDefault {
  175. return *defaultSelectValue, nil
  176. }
  177. return ret, nil
  178. }
  179. // prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
  180. // to construct a select map for any kind of attribute type.
  181. func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
  182. if selectMap == nil {
  183. return "", nil
  184. }
  185. var selects string
  186. for _, selectKey := range android.SortedStringKeys(selectMap) {
  187. if selectKey == bazel.ConditionsDefaultSelectKey {
  188. // Handle default condition later.
  189. continue
  190. }
  191. value := selectMap[selectKey]
  192. if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
  193. // Ignore zero values to not generate empty lists. However, always note zero values if
  194. // the default value is non-zero.
  195. continue
  196. }
  197. s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
  198. if err != nil {
  199. return "", err
  200. }
  201. // s could still be an empty string, e.g. unset slices of structs with
  202. // length of 0.
  203. if s != "" {
  204. selects += s + ",\n"
  205. }
  206. }
  207. if len(selects) == 0 {
  208. // No conditions (or all values are empty lists), so no need for a map.
  209. return "", nil
  210. }
  211. // Create the map.
  212. ret := "select({\n"
  213. ret += selects
  214. // Handle the default condition
  215. s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
  216. if err != nil {
  217. return "", err
  218. }
  219. if s != "" {
  220. // Print the custom default value.
  221. ret += s
  222. ret += ",\n"
  223. } else if defaultValue != nil {
  224. // Print an explicit empty list (the default value) even if the value is
  225. // empty, to avoid errors about not finding a configuration that matches.
  226. ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
  227. }
  228. ret += starlark_fmt.Indention(indent)
  229. ret += "})"
  230. return ret, nil
  231. }
  232. // prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
  233. // with a provided key.
  234. func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
  235. s := starlark_fmt.Indention(indent + 1)
  236. v, err := prettyPrint(value, indent+1, emitZeroValues)
  237. if err != nil {
  238. return "", err
  239. }
  240. if v == "" {
  241. return "", nil
  242. }
  243. s += fmt.Sprintf("\"%s\": %s", key, v)
  244. return s, nil
  245. }