xref: /aosp_15_r20/build/soong/docs/selects.md (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker# Select statements
2*333d2b36SAndroid Build Coastguard Worker
3*333d2b36SAndroid Build Coastguard Worker## Introduction
4*333d2b36SAndroid Build Coastguard Worker
5*333d2b36SAndroid Build Coastguard WorkerSoong currently has the arch, target, product_variables, and soong config variable properties that all support changing the values of soong properties based on some condition. These are confusing for users, and particularly the soong config variable properties require a lot of boilerplate that is annoying to write.
6*333d2b36SAndroid Build Coastguard Worker
7*333d2b36SAndroid Build Coastguard WorkerIn addition, these properties are all implemented using reflection on property structs, and can combine in ways that the original authors did not expect. For example, soong config variables can be combined with arch/target by saying that they operate on "arch.arm.enabled" instead of just "enabled". But product variables do not have the same abilities.
8*333d2b36SAndroid Build Coastguard Worker
9*333d2b36SAndroid Build Coastguard WorkerThe goal here is to combine all these different configuration mechanisms into one, to reduce complexity and boilerplate both in Android.bp files and in soong code.
10*333d2b36SAndroid Build Coastguard Worker
11*333d2b36SAndroid Build Coastguard Worker## Usage
12*333d2b36SAndroid Build Coastguard Worker
13*333d2b36SAndroid Build Coastguard WorkerThe soong select statements take their name and inspiration from [bazel select statements](https://bazel.build/docs/configurable-attributes).
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Worker### Syntax
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Worker#### Basic
18*333d2b36SAndroid Build Coastguard Worker
19*333d2b36SAndroid Build Coastguard WorkerThe basic syntax for select statements looks like:
20*333d2b36SAndroid Build Coastguard Worker
21*333d2b36SAndroid Build Coastguard Worker```
22*333d2b36SAndroid Build Coastguard Workermy_module_type {
23*333d2b36SAndroid Build Coastguard Worker  name: "my_module",
24*333d2b36SAndroid Build Coastguard Worker  some_string_property: select(arch(), {
25*333d2b36SAndroid Build Coastguard Worker    "arm": "foo",
26*333d2b36SAndroid Build Coastguard Worker    "x86": "bar",
27*333d2b36SAndroid Build Coastguard Worker    default: "baz",
28*333d2b36SAndroid Build Coastguard Worker  }),
29*333d2b36SAndroid Build Coastguard Worker}
30*333d2b36SAndroid Build Coastguard Worker```
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard WorkerThat is, `select(` followed by a variable function, then a map of values of the variable to values to set the property to.
33*333d2b36SAndroid Build Coastguard Worker
34*333d2b36SAndroid Build Coastguard WorkerArguments can be passed to the "functions" that look up axes:
35*333d2b36SAndroid Build Coastguard Worker
36*333d2b36SAndroid Build Coastguard Worker```
37*333d2b36SAndroid Build Coastguard Workerselect(soong_config_variable("my_namespace", "my_variable"), {
38*333d2b36SAndroid Build Coastguard Worker  "value1": "foo",
39*333d2b36SAndroid Build Coastguard Worker  default: "bar",
40*333d2b36SAndroid Build Coastguard Worker})
41*333d2b36SAndroid Build Coastguard Worker```
42*333d2b36SAndroid Build Coastguard Worker
43*333d2b36SAndroid Build Coastguard Worker
44*333d2b36SAndroid Build Coastguard WorkerThe list of functions that can currently be selected on:
45*333d2b36SAndroid Build Coastguard Worker - `arch()`
46*333d2b36SAndroid Build Coastguard Worker - `os()`
47*333d2b36SAndroid Build Coastguard Worker - `soong_config_variable(namespace, variable)`
48*333d2b36SAndroid Build Coastguard Worker - `release_flag(flag)`
49*333d2b36SAndroid Build Coastguard Worker
50*333d2b36SAndroid Build Coastguard WorkerThe functions are [defined here](https://cs.android.com/android/platform/superproject/main/+/main:build/soong/android/module.go;l=2144;drc=3f01580c04bfe37c920e247015cce93cff2451c0), and it should be easy to add more.
51*333d2b36SAndroid Build Coastguard Worker
52*333d2b36SAndroid Build Coastguard Worker#### Multivariable
53*333d2b36SAndroid Build Coastguard Worker
54*333d2b36SAndroid Build Coastguard WorkerTo handle multivariable selects, multiple axes can be specified within parenthesis, to look like tuple destructuring. All of the variables being selected must match the corresponding value from the branch in order for the branch to be chosen.
55*333d2b36SAndroid Build Coastguard Worker
56*333d2b36SAndroid Build Coastguard Worker```
57*333d2b36SAndroid Build Coastguard Workerselect((arch(), os()), {
58*333d2b36SAndroid Build Coastguard Worker  ("arm", "linux"): "foo",
59*333d2b36SAndroid Build Coastguard Worker  (default, "windows"): "bar",
60*333d2b36SAndroid Build Coastguard Worker  (default, default): "baz",
61*333d2b36SAndroid Build Coastguard Worker})
62*333d2b36SAndroid Build Coastguard Worker```
63*333d2b36SAndroid Build Coastguard Worker
64*333d2b36SAndroid Build Coastguard Worker#### Unset
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard WorkerYou can have unset branches of selects using the "unset" keyword, which will act as if the property was not assigned to. This is only really useful if you’re using defaults modules.
67*333d2b36SAndroid Build Coastguard Worker
68*333d2b36SAndroid Build Coastguard Worker```
69*333d2b36SAndroid Build Coastguard Workercc_binary {
70*333d2b36SAndroid Build Coastguard Worker  name: "my_binary",
71*333d2b36SAndroid Build Coastguard Worker  enabled: select(os(), {
72*333d2b36SAndroid Build Coastguard Worker    "darwin": false,
73*333d2b36SAndroid Build Coastguard Worker    default: unset,
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#### Appending
79*333d2b36SAndroid Build Coastguard Worker
80*333d2b36SAndroid Build Coastguard WorkerYou can append select statements to both scalar values and other select statements:
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker```
83*333d2b36SAndroid Build Coastguard Workermy_module_type {
84*333d2b36SAndroid Build Coastguard Worker  name: "my_module",
85*333d2b36SAndroid Build Coastguard Worker  // string_property will be set to something like penguin-four, apple-two, etc.
86*333d2b36SAndroid Build Coastguard Worker  string_property: select(os(), {
87*333d2b36SAndroid Build Coastguard Worker    "linux_glibc": "penguin",
88*333d2b36SAndroid Build Coastguard Worker    "darwin": "apple",
89*333d2b36SAndroid Build Coastguard Worker    default: "unknown",
90*333d2b36SAndroid Build Coastguard Worker  }) + "-" + select(soong_config_variable("ANDROID", "favorite_vehicle"), {
91*333d2b36SAndroid Build Coastguard Worker    "car": "four",
92*333d2b36SAndroid Build Coastguard Worker    "tricycle": "three",
93*333d2b36SAndroid Build Coastguard Worker    "bike": "two",
94*333d2b36SAndroid Build Coastguard Worker     default: "unknown",
95*333d2b36SAndroid Build Coastguard Worker  })
96*333d2b36SAndroid Build Coastguard Worker}
97*333d2b36SAndroid Build Coastguard Worker```
98*333d2b36SAndroid Build Coastguard Worker
99*333d2b36SAndroid Build Coastguard Worker
100*333d2b36SAndroid Build Coastguard WorkerYou can also append a select with a value with another select that may not have a value, because some of its branches are "unset". If an unset branch was selected it will not append anything to the other select.
101*333d2b36SAndroid Build Coastguard Worker
102*333d2b36SAndroid Build Coastguard Worker#### Binding the selected value to a Blueprint variable and the "any" keyword
103*333d2b36SAndroid Build Coastguard Worker
104*333d2b36SAndroid Build Coastguard WorkerIn case you want to allow a selected value to have an unbounded number of possible values, you can bind its value to a blueprint variable and use it within the expression for that select branch.
105*333d2b36SAndroid Build Coastguard Worker
106*333d2b36SAndroid Build Coastguard Worker```
107*333d2b36SAndroid Build Coastguard Workermy_module_type {
108*333d2b36SAndroid Build Coastguard Worker  name: "my_module",
109*333d2b36SAndroid Build Coastguard Worker  my_string_property: select(soong_config_variable("my_namespace", "my_variable"), {
110*333d2b36SAndroid Build Coastguard Worker    "some_value": "baz",
111*333d2b36SAndroid Build Coastguard Worker    any @ my_var: "foo" + my_var,
112*333d2b36SAndroid Build Coastguard Worker    default: "bar",
113*333d2b36SAndroid Build Coastguard Worker  }),
114*333d2b36SAndroid Build Coastguard Worker}
115*333d2b36SAndroid Build Coastguard Worker```
116*333d2b36SAndroid Build Coastguard Worker
117*333d2b36SAndroid Build Coastguard WorkerThe syntax is `any @ my_variable_name: <expression using my_variable_name>`. `any` is currently the only pattern that can be bound to a variable, but we may add more in the future. `any` is equivalent to `default` except it will not match undefined select conditions.
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Worker#### Errors
120*333d2b36SAndroid Build Coastguard Worker
121*333d2b36SAndroid Build Coastguard WorkerIf a select statement does not have a "default" branch, and none of the other branches match the variable being selected on, it’s a compile-time error. This may be useful for enforcing a variable is 1 of only a few values.
122*333d2b36SAndroid Build Coastguard Worker
123*333d2b36SAndroid Build Coastguard Worker```
124*333d2b36SAndroid Build Coastguard Worker# in product config:
125*333d2b36SAndroid Build Coastguard Worker$(call soong_config_set,ANDROID,my_variable,foo)
126*333d2b36SAndroid Build Coastguard Worker
127*333d2b36SAndroid Build Coastguard Worker// in an Android.bp:
128*333d2b36SAndroid Build Coastguard Workermy_module_type {
129*333d2b36SAndroid Build Coastguard Worker  name: "my_module",
130*333d2b36SAndroid Build Coastguard Worker  // Will error out with: soong_config_variable("ANDROID", "my_variable") had value "foo", which was not handled by the select
131*333d2b36SAndroid Build Coastguard Worker  enabled: select(soong_config_variable("ANDROID", "my_variable"), {
132*333d2b36SAndroid Build Coastguard Worker    "bar": true,
133*333d2b36SAndroid Build Coastguard Worker    "baz": false,
134*333d2b36SAndroid Build Coastguard Worker  }),
135*333d2b36SAndroid Build Coastguard Worker}
136*333d2b36SAndroid Build Coastguard Worker```
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Worker### Changes to property structs to support selects
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard WorkerCurrently, the way configurable properties work is that there is secretly another property struct that has the `target`, `arch`, etc. properties, and then when the arch mutator (or other relevant mutator) runs, it copies the values of these properties onto the regular property structs. There’s nothing stopping you from accessing your properties from a mutator that runs before the one that updates the properties based on configurable values. This is a potential source of bugs, and we want to make sure that select statements don’t have the same pitfall. For that reason, you have to read property’s values through a getter which can do this check. This requires changing the code on a property-by-property basis to support selects.
141*333d2b36SAndroid Build Coastguard Worker
142*333d2b36SAndroid Build Coastguard WorkerTo make a property support selects, it must be of type [proptools.Configurable[T]](https://cs.android.com/android/platform/superproject/main/+/main:build/blueprint/proptools/configurable.go;l=341;drc=a52b058cccd2caa778d0f97077adcd4ef7ffb68a). T is the old type of the property. Currently we support bool, string, and []string. Configurable has a `Get(evaluator)` method to get the value of the property. The evaluator can be a ModuleContext, or if you’re in a situation where you only have a very limited context and a module, (such as in a singleton) you can use [ModuleBase.ConfigurableEvaluator](https://cs.android.com/android/platform/superproject/main/+/main:build/soong/android/module.go;l=2133;drc=e19f741052cce097da940d9083d3f29e668de5cb).
143*333d2b36SAndroid Build Coastguard Worker
144*333d2b36SAndroid Build Coastguard Worker`proptools.Configurable[T]` will handle unset properties for you, so you don’t need to make it a pointer type. However, there is a not-widely-known feature of property structs, where normally, properties are appended when squashing defaults. But if the property was a pointer property, later defaults replace earlier values instead of appending. With selects, to maintain this behavior, add the `android:"replace_instead_of_append"` struct tag. The "append" behavior for boolean values is to boolean OR them together, which is rarely what you want, so most boolean properties are pointers today.
145*333d2b36SAndroid Build Coastguard Worker
146*333d2b36SAndroid Build Coastguard WorkerOld:
147*333d2b36SAndroid Build Coastguard Worker```
148*333d2b36SAndroid Build Coastguard Workertype commonProperties struct {
149*333d2b36SAndroid Build Coastguard Worker  Enabled *bool `android:"arch_variant"`
150*333d2b36SAndroid Build Coastguard Worker}
151*333d2b36SAndroid Build Coastguard Worker
152*333d2b36SAndroid Build Coastguard Workerfunc (m *ModuleBase) Enabled() *bool {
153*333d2b36SAndroid Build Coastguard Worker  return m.commonProperties.Enabled
154*333d2b36SAndroid Build Coastguard Worker}
155*333d2b36SAndroid Build Coastguard Worker```
156*333d2b36SAndroid Build Coastguard Worker
157*333d2b36SAndroid Build Coastguard WorkerNew:
158*333d2b36SAndroid Build Coastguard Worker```
159*333d2b36SAndroid Build Coastguard Workertype commonProperties struct {
160*333d2b36SAndroid Build Coastguard Worker  Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
161*333d2b36SAndroid Build Coastguard Worker}
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Workerfunc (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) *bool {
164*333d2b36SAndroid Build Coastguard Worker  return m.commonProperties.Enabled.Get(m.ConfigurableEvaluator(ctx))
165*333d2b36SAndroid Build Coastguard Worker}
166*333d2b36SAndroid Build Coastguard Worker```
167*333d2b36SAndroid Build Coastguard Worker
168*333d2b36SAndroid Build Coastguard WorkerThe `android:"arch_variant"` tag is kept to support the old `target:` and `arch:` properties with this property, but if all their usages in bp files were replaced by selects, then that tag could be removed.
169*333d2b36SAndroid Build Coastguard Worker
170*333d2b36SAndroid Build Coastguard WorkerThe enabled property underwent this migration in https://r.android.com/3066188
171