blob: c13e737c09adec1ea744a992d20f1bdb05dfd044 [file] [log] [blame]
Jingwen Chen5d864492021-02-24 07:20:12 -05001package bp2build
2
Jingwen Chen91220d72021-03-24 02:18:33 -04003import (
4 "android/soong/android"
5 "android/soong/bazel"
6 "fmt"
7 "reflect"
8)
Jingwen Chen5d864492021-02-24 07:20:12 -05009
10// Configurability support for bp2build.
11
Jingwen Chenc1c26502021-04-05 10:35:13 +000012type selects map[string]reflect.Value
13
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040014func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +000015 value := reflect.ValueOf(list.Value)
16 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040017 return value, []selects{}
Jingwen Chen5d864492021-02-24 07:20:12 -050018 }
Jingwen Chen91220d72021-03-24 02:18:33 -040019
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040020 selectValues := make([]selects, 0)
Jingwen Chen91220d72021-03-24 02:18:33 -040021 archSelects := map[string]reflect.Value{}
22 for arch, selectKey := range bazel.PlatformArchMap {
Jingwen Chenc1c26502021-04-05 10:35:13 +000023 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
Jingwen Chen91220d72021-03-24 02:18:33 -040024 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040025 if len(archSelects) > 0 {
26 selectValues = append(selectValues, archSelects)
27 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000028
29 osSelects := map[string]reflect.Value{}
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040030 osArchSelects := make([]selects, 0)
31 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
32 selectKey := bazel.PlatformOsMap[os]
33 osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os))
34 archSelects := make(map[string]reflect.Value)
35 // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (not in AllArches)
36 for _, arch := range bazel.AllArches {
37 target := os + "_" + arch
38 selectKey := bazel.PlatformTargetMap[target]
39 archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch))
40 }
41 osArchSelects = append(osArchSelects, archSelects)
Jingwen Chenc1c26502021-04-05 10:35:13 +000042 }
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040043 if len(osSelects) > 0 {
44 selectValues = append(selectValues, osSelects)
45 }
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -040046 if len(osArchSelects) > 0 {
47 selectValues = append(selectValues, osArchSelects...)
48 }
Jingwen Chenc1c26502021-04-05 10:35:13 +000049
Liz Kammere3e4a5f2021-05-10 11:39:53 -040050 for _, pv := range list.SortedProductVariables() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040051 s := make(selects)
52 if len(pv.Values) > 0 {
53 s[pv.SelectKey()] = reflect.ValueOf(pv.Values)
54 s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{})
55 selectValues = append(selectValues, s)
56 }
57 }
58
59 return value, selectValues
Jingwen Chenc1c26502021-04-05 10:35:13 +000060}
61
Liz Kammer6fd7b3f2021-05-06 13:54:29 -040062func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040063 value := reflect.ValueOf(label.Value)
64 if !label.HasConfigurableValues() {
65 return value, []selects{}
Lukacs T. Berki56bb0832021-05-12 12:36:45 +020066 }
67
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -040068 // Keep track of which arches and oses have been used in case we need to raise a warning
69 usedArches := make(map[string]bool)
70 usedOses := make(map[string]bool)
71
72 archSelects := map[string]reflect.Value{}
73 for arch, selectKey := range bazel.PlatformArchMap {
74 archSelects[selectKey] = reflect.ValueOf(label.GetValueForArch(arch))
75 if archSelects[selectKey].IsValid() && !isZero(archSelects[selectKey]) {
76 usedArches[arch] = true
77 }
78 }
79
80 osSelects := map[string]reflect.Value{}
81 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
82 selectKey := bazel.PlatformOsMap[os]
83 osSelects[selectKey] = reflect.ValueOf(label.GetOsValueForTarget(os))
84 if osSelects[selectKey].IsValid() && !isZero(osSelects[selectKey]) {
85 usedOses[os] = true
86 }
87 }
88
89 osArchSelects := make([]selects, 0)
90 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
91 archSelects := make(map[string]reflect.Value)
92 // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (not in AllArches)
93 for _, arch := range bazel.AllArches {
94 target := os + "_" + arch
95 selectKey := bazel.PlatformTargetMap[target]
96 archSelects[selectKey] = reflect.ValueOf(label.GetOsArchValueForTarget(os, arch))
97 if archSelects[selectKey].IsValid() && !isZero(archSelects[selectKey]) {
98 if _, ok := usedArches[arch]; ok {
99 fmt.Printf("WARNING: Same arch used twice in LabelAttribute select: arch '%s'\n", arch)
100 }
101 if _, ok := usedOses[os]; ok {
102 fmt.Printf("WARNING: Same os used twice in LabelAttribute select: os '%s'\n", os)
103 }
104 }
105 }
106 osArchSelects = append(osArchSelects, archSelects)
107 }
108
109 // Because we have to return a single Label, we can only use one select statement
110 combinedSelects := map[string]reflect.Value{}
111 for k, v := range archSelects {
112 combinedSelects[k] = v
113 }
114 for k, v := range osSelects {
115 combinedSelects[k] = v
116 }
117 for _, osArchSelect := range osArchSelects {
118 for k, v := range osArchSelect {
119 combinedSelects[k] = v
120 }
121 }
122
123 return value, []selects{combinedSelects}
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200124}
125
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400126func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000127 value := reflect.ValueOf(list.Value.Includes)
128 if !list.HasConfigurableValues() {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400129 return value, []selects{}
Jingwen Chenc1c26502021-04-05 10:35:13 +0000130 }
131
132 archSelects := map[string]reflect.Value{}
133 for arch, selectKey := range bazel.PlatformArchMap {
134 archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
135 }
136
137 osSelects := map[string]reflect.Value{}
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400138 osArchSelects := make([]selects, 0)
139 for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
140 selectKey := bazel.PlatformOsMap[os]
141 osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os).Includes)
142 archSelects := make(map[string]reflect.Value)
143 // TODO(b/187530594): Should we also check arch=CONDITIOSN_DEFAULT? (not in AllArches)
144 for _, arch := range bazel.AllArches {
145 target := os + "_" + arch
146 selectKey := bazel.PlatformTargetMap[target]
147 archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch).Includes)
148 }
149 osArchSelects = append(osArchSelects, archSelects)
Jingwen Chenc1c26502021-04-05 10:35:13 +0000150 }
151
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400152 var selects []selects
153 selects = append(selects, archSelects)
154 selects = append(selects, osSelects)
155 selects = append(selects, osArchSelects...)
156 return value, selects
Jingwen Chenc1c26502021-04-05 10:35:13 +0000157}
158
159// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
160// select statements.
161func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
162 var value reflect.Value
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400163 var configurableAttrs []selects
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200164 var defaultSelectValue string
Jingwen Chenc1c26502021-04-05 10:35:13 +0000165 switch list := v.(type) {
166 case bazel.StringListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400167 value, configurableAttrs = getStringListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200168 defaultSelectValue = "[]"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000169 case bazel.LabelListAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400170 value, configurableAttrs = getLabelListValues(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200171 defaultSelectValue = "[]"
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200172 case bazel.LabelAttribute:
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400173 value, configurableAttrs = getLabelValue(list)
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200174 defaultSelectValue = "None"
Jingwen Chenc1c26502021-04-05 10:35:13 +0000175 default:
176 return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
177 }
178
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400179 var err error
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200180 ret := ""
181 if value.Kind() != reflect.Invalid {
182 s, err := prettyPrint(value, indent)
183 if err != nil {
184 return ret, err
185 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000186
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200187 ret += s
188 }
Jingwen Chen63930982021-03-24 10:04:33 -0400189 // Convenience function to append selects components to an attribute value.
190 appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
191 selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
192 if err != nil {
193 return "", err
194 }
195 if s != "" && selectMap != "" {
196 s += " + "
197 }
198 s += selectMap
199
200 return s, nil
201 }
202
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400203 for _, configurableAttr := range configurableAttrs {
204 ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
205 if err != nil {
206 return "", err
207 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400208 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400209
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400210 return ret, nil
Jingwen Chen91220d72021-03-24 02:18:33 -0400211}
212
213// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
214// to construct a select map for any kind of attribute type.
215func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
Jingwen Chenc1c26502021-04-05 10:35:13 +0000216 if selectMap == nil {
217 return "", nil
218 }
219
Jingwen Chene32e9e02021-04-23 09:17:24 +0000220 // addConditionsDefault := false
Jingwen Chene32e9e02021-04-23 09:17:24 +0000221
Jingwen Chen91220d72021-03-24 02:18:33 -0400222 var selects string
223 for _, selectKey := range android.SortedStringKeys(selectMap) {
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400224 if selectKey == bazel.ConditionsDefaultSelectKey {
Jingwen Chene32e9e02021-04-23 09:17:24 +0000225 // Handle default condition later.
226 continue
227 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400228 value := selectMap[selectKey]
229 if isZero(value) {
230 // Ignore zero values to not generate empty lists.
231 continue
232 }
233 s, err := prettyPrintSelectEntry(value, selectKey, indent)
234 if err != nil {
235 return "", err
236 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000237 // s could still be an empty string, e.g. unset slices of structs with
238 // length of 0.
239 if s != "" {
240 selects += s + ",\n"
241 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400242 }
243
244 if len(selects) == 0 {
245 // No conditions (or all values are empty lists), so no need for a map.
246 return "", nil
247 }
248
249 // Create the map.
Jingwen Chen63930982021-03-24 10:04:33 -0400250 ret := "select({\n"
Jingwen Chen91220d72021-03-24 02:18:33 -0400251 ret += selects
Jingwen Chene32e9e02021-04-23 09:17:24 +0000252
253 // Handle the default condition
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400254 s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000255 if err != nil {
256 return "", err
257 }
258 if s == "" {
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.
Liz Kammer6fd7b3f2021-05-06 13:54:29 -0400261 ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
Jingwen Chene32e9e02021-04-23 09:17:24 +0000262 } else {
263 // Print the custom default value.
264 ret += s
265 ret += ",\n"
266 }
267
Jingwen Chen91220d72021-03-24 02:18:33 -0400268 ret += makeIndent(indent)
269 ret += "})"
270
271 return ret, nil
272}
273
274// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
275// with a provided key.
276func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
277 s := makeIndent(indent + 1)
278 v, err := prettyPrint(value, indent+1)
279 if err != nil {
280 return "", err
281 }
Jingwen Chened9c17d2021-04-13 07:14:55 +0000282 if v == "" {
283 return "", nil
284 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400285 s += fmt.Sprintf("\"%s\": %s", key, v)
286 return s, nil
287}