configurability.go 9.2 KB

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