blob: c0e63eb08c85c982248706b8bcfaf49653972eee [file] [log] [blame]
Colin Cross3f40fa42015-01-30 17:27:36 -08001// Copyright 2015 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
15package common
16
17import (
Colin Cross3f40fa42015-01-30 17:27:36 -080018 "fmt"
19 "reflect"
20 "runtime"
21 "strings"
Colin Crossf6566ed2015-03-24 11:13:38 -070022
Colin Cross463a90e2015-06-17 14:20:06 -070023 "android/soong"
24
Colin Crossf6566ed2015-03-24 11:13:38 -070025 "github.com/google/blueprint"
26 "github.com/google/blueprint/proptools"
Colin Cross3f40fa42015-01-30 17:27:36 -080027)
28
Colin Cross463a90e2015-06-17 14:20:06 -070029func init() {
30 soong.RegisterEarlyMutator("host_or_device", HostOrDeviceMutator)
31 soong.RegisterEarlyMutator("arch", ArchMutator)
32}
33
Colin Cross3f40fa42015-01-30 17:27:36 -080034var (
Colin Crossec193632015-07-06 17:49:43 -070035 Arm = newArch("arm", "lib32")
36 Arm64 = newArch("arm64", "lib64")
37 Mips = newArch("mips", "lib32")
38 Mips64 = newArch("mips64", "lib64")
39 X86 = newArch("x86", "lib32")
40 X86_64 = newArch("x86_64", "lib64")
Colin Cross2fe66872015-03-30 17:20:39 -070041
42 Common = ArchType{
43 Name: "common",
44 }
Colin Cross3f40fa42015-01-30 17:27:36 -080045)
46
47/*
48Example blueprints file containing all variant property groups, with comment listing what type
49of variants get properties in that group:
50
51module {
52 arch: {
53 arm: {
54 // Host or device variants with arm architecture
55 },
56 arm64: {
57 // Host or device variants with arm64 architecture
58 },
59 mips: {
60 // Host or device variants with mips architecture
61 },
62 mips64: {
63 // Host or device variants with mips64 architecture
64 },
65 x86: {
66 // Host or device variants with x86 architecture
67 },
68 x86_64: {
69 // Host or device variants with x86_64 architecture
70 },
71 },
72 multilib: {
73 lib32: {
74 // Host or device variants for 32-bit architectures
75 },
76 lib64: {
77 // Host or device variants for 64-bit architectures
78 },
79 },
80 target: {
81 android: {
82 // Device variants
83 },
84 host: {
85 // Host variants
86 },
87 linux: {
88 // Linux host variants
89 },
90 darwin: {
91 // Darwin host variants
92 },
93 windows: {
94 // Windows host variants
95 },
96 not_windows: {
97 // Non-windows host variants
98 },
99 },
100}
101*/
Colin Cross7d5136f2015-05-11 13:39:40 -0700102
Colin Cross3f40fa42015-01-30 17:27:36 -0800103type archProperties struct {
Colin Cross7d5136f2015-05-11 13:39:40 -0700104 // Properties to vary by target architecture
Colin Cross3f40fa42015-01-30 17:27:36 -0800105 Arch struct {
Colin Cross7d5136f2015-05-11 13:39:40 -0700106 // Properties for module variants being built to run on arm (host or device)
107 Arm interface{} `blueprint:"filter(android:\"arch_variant\")"`
108 // Properties for module variants being built to run on arm64 (host or device)
109 Arm64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
110 // Properties for module variants being built to run on mips (host or device)
111 Mips interface{} `blueprint:"filter(android:\"arch_variant\")"`
112 // Properties for module variants being built to run on mips64 (host or device)
113 Mips64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
114 // Properties for module variants being built to run on x86 (host or device)
115 X86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
116 // Properties for module variants being built to run on x86_64 (host or device)
117 X86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Crossec193632015-07-06 17:49:43 -0700118
119 // Arm arch variants
120 Armv5te interface{} `blueprint:"filter(android:\"arch_variant\")"`
121 Armv7_a interface{} `blueprint:"filter(android:\"arch_variant\")"`
122 Armv7_a_neon interface{} `blueprint:"filter(android:\"arch_variant\")"`
123
124 // Arm cpu variants
125 Cortex_a7 interface{} `blueprint:"filter(android:\"arch_variant\")"`
126 Cortex_a8 interface{} `blueprint:"filter(android:\"arch_variant\")"`
127 Cortex_a9 interface{} `blueprint:"filter(android:\"arch_variant\")"`
128 Cortex_a15 interface{} `blueprint:"filter(android:\"arch_variant\")"`
129 Krait interface{} `blueprint:"filter(android:\"arch_variant\")"`
130 Denver interface{} `blueprint:"filter(android:\"arch_variant\")"`
131
132 // Arm64 cpu variants
133 Denver64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
134
135 // Mips arch variants
136 Mips_rev6 interface{} `blueprint:"filter(android:\"arch_variant\")"`
137
138 // X86 cpu variants
139 Atom interface{} `blueprint:"filter(android:\"arch_variant\")"`
140 Silvermont interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Cross3f40fa42015-01-30 17:27:36 -0800141 }
Colin Crossec193632015-07-06 17:49:43 -0700142
Colin Cross7d5136f2015-05-11 13:39:40 -0700143 // Properties to vary by 32-bit or 64-bit
Colin Cross3f40fa42015-01-30 17:27:36 -0800144 Multilib struct {
Colin Cross7d5136f2015-05-11 13:39:40 -0700145 // Properties for module variants being built to run on 32-bit devices
146 Lib32 interface{} `blueprint:"filter(android:\"arch_variant\")"`
147 // Properties for module variants being built to run on 64-bit devices
148 Lib64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Cross3f40fa42015-01-30 17:27:36 -0800149 }
Colin Cross7d5136f2015-05-11 13:39:40 -0700150 // Properties to vary by build target (host or device, os, os+archictecture)
Colin Cross3f40fa42015-01-30 17:27:36 -0800151 Target struct {
Colin Cross7d5136f2015-05-11 13:39:40 -0700152 // Properties for module variants being built to run on the host
153 Host interface{} `blueprint:"filter(android:\"arch_variant\")"`
154 // Properties for module variants being built to run on the device
155 Android interface{} `blueprint:"filter(android:\"arch_variant\")"`
156 // Properties for module variants being built to run on arm devices
157 Android_arm interface{} `blueprint:"filter(android:\"arch_variant\")"`
158 // Properties for module variants being built to run on arm64 devices
159 Android_arm64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
160 // Properties for module variants being built to run on mips devices
161 Android_mips interface{} `blueprint:"filter(android:\"arch_variant\")"`
162 // Properties for module variants being built to run on mips64 devices
163 Android_mips64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
164 // Properties for module variants being built to run on x86 devices
165 Android_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
166 // Properties for module variants being built to run on x86_64 devices
167 Android_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
168 // Properties for module variants being built to run on devices that support 64-bit
169 Android64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
170 // Properties for module variants being built to run on devices that do not support 64-bit
171 Android32 interface{} `blueprint:"filter(android:\"arch_variant\")"`
172 // Properties for module variants being built to run on linux hosts
173 Linux interface{} `blueprint:"filter(android:\"arch_variant\")"`
174 // Properties for module variants being built to run on linux x86 hosts
175 Linux_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
176 // Properties for module variants being built to run on linux x86_64 hosts
177 Linux_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
178 // Properties for module variants being built to run on darwin hosts
179 Darwin interface{} `blueprint:"filter(android:\"arch_variant\")"`
180 // Properties for module variants being built to run on darwin x86 hosts
181 Darwin_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
182 // Properties for module variants being built to run on darwin x86_64 hosts
183 Darwin_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
184 // Properties for module variants being built to run on windows hosts
185 Windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
186 // Properties for module variants being built to run on linux or darwin hosts
187 Not_windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Cross3f40fa42015-01-30 17:27:36 -0800188 }
189}
190
191// An Arch indicates a single CPU architecture.
192type Arch struct {
Colin Crossd3ba0392015-05-07 14:11:29 -0700193 ArchType ArchType
194 ArchVariant string
195 CpuVariant string
196 Abi string
Colin Cross3f40fa42015-01-30 17:27:36 -0800197}
198
199func (a Arch) String() string {
Colin Crossd3ba0392015-05-07 14:11:29 -0700200 s := a.ArchType.String()
Colin Cross3f40fa42015-01-30 17:27:36 -0800201 if a.ArchVariant != "" {
202 s += "_" + a.ArchVariant
203 }
204 if a.CpuVariant != "" {
205 s += "_" + a.CpuVariant
206 }
207 return s
208}
209
210type ArchType struct {
Colin Crossec193632015-07-06 17:49:43 -0700211 Name string
212 Multilib string
Colin Cross3f40fa42015-01-30 17:27:36 -0800213}
214
Colin Crossec193632015-07-06 17:49:43 -0700215func newArch(name, multilib string) ArchType {
Colin Cross3f40fa42015-01-30 17:27:36 -0800216 return ArchType{
Colin Crossec193632015-07-06 17:49:43 -0700217 Name: name,
218 Multilib: multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -0800219 }
220}
221
222func (a ArchType) String() string {
223 return a.Name
224}
225
226type HostOrDeviceSupported int
227
228const (
229 _ HostOrDeviceSupported = iota
230 HostSupported
231 DeviceSupported
232 HostAndDeviceSupported
233)
234
235type HostOrDevice int
236
237const (
238 _ HostOrDevice = iota
239 Host
240 Device
241)
242
243func (hod HostOrDevice) String() string {
244 switch hod {
245 case Device:
246 return "device"
247 case Host:
248 return "host"
249 default:
250 panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod))
251 }
252}
253
Colin Crossec193632015-07-06 17:49:43 -0700254func (hod HostOrDevice) Property() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800255 switch hod {
256 case Device:
257 return "android"
258 case Host:
259 return "host"
260 default:
261 panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod))
262 }
263}
264
Colin Cross3f40fa42015-01-30 17:27:36 -0800265func (hod HostOrDevice) Host() bool {
266 if hod == 0 {
267 panic("HostOrDevice unset")
268 }
269 return hod == Host
270}
271
272func (hod HostOrDevice) Device() bool {
273 if hod == 0 {
274 panic("HostOrDevice unset")
275 }
276 return hod == Device
277}
278
279var hostOrDeviceName = map[HostOrDevice]string{
280 Device: "device",
281 Host: "host",
282}
283
284var (
285 armArch = Arch{
Colin Crossd3ba0392015-05-07 14:11:29 -0700286 ArchType: Arm,
287 ArchVariant: "armv7-a-neon",
288 CpuVariant: "cortex-a15",
289 Abi: "armeabi-v7a",
Colin Cross3f40fa42015-01-30 17:27:36 -0800290 }
291 arm64Arch = Arch{
Colin Crossec193632015-07-06 17:49:43 -0700292 ArchType: Arm64,
293 CpuVariant: "denver64",
294 Abi: "arm64-v8a",
Colin Cross3f40fa42015-01-30 17:27:36 -0800295 }
Colin Crossd3ba0392015-05-07 14:11:29 -0700296 x86Arch = Arch{
297 ArchType: X86,
Colin Cross3f40fa42015-01-30 17:27:36 -0800298 }
Colin Crossd3ba0392015-05-07 14:11:29 -0700299 x8664Arch = Arch{
300 ArchType: X86_64,
Colin Cross3f40fa42015-01-30 17:27:36 -0800301 }
Colin Crossd3ba0392015-05-07 14:11:29 -0700302 commonArch = Arch{
303 ArchType: Common,
Colin Cross2fe66872015-03-30 17:20:39 -0700304 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800305)
306
Colin Crossd3ba0392015-05-07 14:11:29 -0700307func HostOrDeviceMutator(mctx blueprint.EarlyMutatorContext) {
308 var module AndroidModule
309 var ok bool
310 if module, ok = mctx.Module().(AndroidModule); !ok {
311 return
312 }
313
314 hods := []HostOrDevice{}
315
316 if module.base().HostSupported() {
317 hods = append(hods, Host)
318 }
319
320 if module.base().DeviceSupported() {
321 hods = append(hods, Device)
322 }
323
324 if len(hods) == 0 {
325 return
326 }
327
328 hodNames := []string{}
329 for _, hod := range hods {
330 hodNames = append(hodNames, hod.String())
331 }
332
333 modules := mctx.CreateVariations(hodNames...)
334 for i, m := range modules {
335 m.(AndroidModule).base().SetHostOrDevice(hods[i])
336 }
337}
338
Colin Cross3f40fa42015-01-30 17:27:36 -0800339func ArchMutator(mctx blueprint.EarlyMutatorContext) {
340 var module AndroidModule
341 var ok bool
342 if module, ok = mctx.Module().(AndroidModule); !ok {
343 return
344 }
345
346 // TODO: this is all hardcoded for arm64 primary, arm secondary for now
347 // Replace with a configuration file written by lunch or bootstrap
348
349 arches := []Arch{}
350
Colin Crossd3ba0392015-05-07 14:11:29 -0700351 if module.base().HostSupported() && module.base().HostOrDevice().Host() {
Colin Cross2fe66872015-03-30 17:20:39 -0700352 switch module.base().commonProperties.Compile_multilib {
353 case "common":
Colin Crossd3ba0392015-05-07 14:11:29 -0700354 arches = append(arches, commonArch)
Dan Willemsenffce3fc2015-07-08 13:02:19 -0700355 case "both":
356 arches = append(arches, x8664Arch, x86Arch)
357 case "first", "64":
358 arches = append(arches, x8664Arch)
359 case "32":
360 arches = append(arches, x86Arch)
Colin Cross2fe66872015-03-30 17:20:39 -0700361 default:
Colin Crossd3ba0392015-05-07 14:11:29 -0700362 arches = append(arches, x8664Arch)
Colin Cross2fe66872015-03-30 17:20:39 -0700363 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800364 }
365
Colin Crossd3ba0392015-05-07 14:11:29 -0700366 if module.base().DeviceSupported() && module.base().HostOrDevice().Device() {
Colin Cross3f40fa42015-01-30 17:27:36 -0800367 switch module.base().commonProperties.Compile_multilib {
Colin Cross2fe66872015-03-30 17:20:39 -0700368 case "common":
Colin Crossd3ba0392015-05-07 14:11:29 -0700369 arches = append(arches, commonArch)
Colin Cross3f40fa42015-01-30 17:27:36 -0800370 case "both":
371 arches = append(arches, arm64Arch, armArch)
372 case "first", "64":
373 arches = append(arches, arm64Arch)
374 case "32":
375 arches = append(arches, armArch)
376 default:
377 mctx.ModuleErrorf(`compile_multilib must be "both", "first", "32", or "64", found %q`,
378 module.base().commonProperties.Compile_multilib)
379 }
380 }
381
Colin Cross5049f022015-03-18 13:28:46 -0700382 if len(arches) == 0 {
383 return
384 }
385
Colin Cross3f40fa42015-01-30 17:27:36 -0800386 archNames := []string{}
387 for _, arch := range arches {
388 archNames = append(archNames, arch.String())
389 }
390
391 modules := mctx.CreateVariations(archNames...)
392
393 for i, m := range modules {
394 m.(AndroidModule).base().SetArch(arches[i])
Colin Crossd3ba0392015-05-07 14:11:29 -0700395 m.(AndroidModule).base().setArchProperties(mctx)
Colin Cross3f40fa42015-01-30 17:27:36 -0800396 }
397}
398
Colin Crossc472d572015-03-17 15:06:21 -0700399func InitArchModule(m AndroidModule, defaultMultilib Multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -0800400 propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
401
402 base := m.base()
403
Colin Crossc472d572015-03-17 15:06:21 -0700404 base.commonProperties.Compile_multilib = string(defaultMultilib)
Colin Cross3f40fa42015-01-30 17:27:36 -0800405
406 base.generalProperties = append(base.generalProperties,
Colin Cross3f40fa42015-01-30 17:27:36 -0800407 propertyStructs...)
408
409 for _, properties := range base.generalProperties {
410 propertiesValue := reflect.ValueOf(properties)
411 if propertiesValue.Kind() != reflect.Ptr {
412 panic("properties must be a pointer to a struct")
413 }
414
415 propertiesValue = propertiesValue.Elem()
416 if propertiesValue.Kind() != reflect.Struct {
417 panic("properties must be a pointer to a struct")
418 }
419
420 archProperties := &archProperties{}
421 forEachInterface(reflect.ValueOf(archProperties), func(v reflect.Value) {
Colin Cross3ab7d882015-05-19 13:03:01 -0700422 newValue := proptools.CloneEmptyProperties(propertiesValue)
Colin Cross3f40fa42015-01-30 17:27:36 -0800423 v.Set(newValue)
424 })
425
426 base.archProperties = append(base.archProperties, archProperties)
427 }
428
429 var allProperties []interface{}
430 allProperties = append(allProperties, base.generalProperties...)
431 for _, asp := range base.archProperties {
432 allProperties = append(allProperties, asp)
433 }
434
435 return m, allProperties
436}
437
Colin Crossec193632015-07-06 17:49:43 -0700438var dashToUnderscoreReplacer = strings.NewReplacer("-", "_")
439
Colin Cross3f40fa42015-01-30 17:27:36 -0800440// Rewrite the module's properties structs to contain arch-specific values.
Colin Crossd3ba0392015-05-07 14:11:29 -0700441func (a *AndroidModuleBase) setArchProperties(ctx blueprint.EarlyMutatorContext) {
442 arch := a.commonProperties.CompileArch
443 hod := a.commonProperties.CompileHostOrDevice
444
Colin Cross2fe66872015-03-30 17:20:39 -0700445 if arch.ArchType == Common {
446 return
447 }
448
Colin Cross3f40fa42015-01-30 17:27:36 -0800449 for i := range a.generalProperties {
450 generalPropsValue := reflect.ValueOf(a.generalProperties[i]).Elem()
451
452 // Handle arch-specific properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700453 // arch: {
454 // arm64: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800455 // key: value,
456 // },
457 // },
458 t := arch.ArchType
Colin Crossec193632015-07-06 17:49:43 -0700459 field := proptools.FieldNameForProperty(t.Name)
Colin Cross28d76592015-03-26 16:14:04 -0700460 a.extendProperties(ctx, "arch", t.Name, generalPropsValue,
Colin Crossec193632015-07-06 17:49:43 -0700461 reflect.ValueOf(a.archProperties[i].Arch).FieldByName(field).Elem().Elem())
462
463 // Handle arch-variant-specific properties in the form:
464 // arch: {
465 // variant: {
466 // key: value,
467 // },
468 // },
469 v := dashToUnderscoreReplacer.Replace(arch.ArchVariant)
470 if v != "" {
471 field := proptools.FieldNameForProperty(v)
472 a.extendProperties(ctx, "arch", v, generalPropsValue,
473 reflect.ValueOf(a.archProperties[i].Arch).FieldByName(field).Elem().Elem())
474 }
475
476 // Handle cpu-variant-specific properties in the form:
477 // arch: {
478 // variant: {
479 // key: value,
480 // },
481 // },
482 c := dashToUnderscoreReplacer.Replace(arch.CpuVariant)
483 if c != "" {
484 field := proptools.FieldNameForProperty(c)
485 a.extendProperties(ctx, "arch", c, generalPropsValue,
486 reflect.ValueOf(a.archProperties[i].Arch).FieldByName(field).Elem().Elem())
487 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800488
489 // Handle multilib-specific properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700490 // multilib: {
491 // lib32: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800492 // key: value,
493 // },
494 // },
Colin Crossec193632015-07-06 17:49:43 -0700495 multilibField := proptools.FieldNameForProperty(t.Multilib)
Colin Cross28d76592015-03-26 16:14:04 -0700496 a.extendProperties(ctx, "multilib", t.Multilib, generalPropsValue,
Colin Crossec193632015-07-06 17:49:43 -0700497 reflect.ValueOf(a.archProperties[i].Multilib).FieldByName(multilibField).Elem().Elem())
Colin Cross3f40fa42015-01-30 17:27:36 -0800498
499 // Handle host-or-device-specific properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700500 // target: {
501 // host: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800502 // key: value,
503 // },
504 // },
Colin Crossec193632015-07-06 17:49:43 -0700505 hodProperty := hod.Property()
506 hodField := proptools.FieldNameForProperty(hodProperty)
507 a.extendProperties(ctx, "target", hodProperty, generalPropsValue,
508 reflect.ValueOf(a.archProperties[i].Target).FieldByName(hodField).Elem().Elem())
Colin Cross3f40fa42015-01-30 17:27:36 -0800509
510 // Handle host target properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700511 // target: {
512 // linux: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800513 // key: value,
514 // },
Colin Crossb05bff22015-04-30 15:08:04 -0700515 // not_windows: {
516 // key: value,
517 // },
518 // linux_x86: {
519 // key: value,
520 // },
521 // linux_arm: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800522 // key: value,
523 // },
524 // },
525 var osList = []struct {
526 goos string
527 field string
528 }{
529 {"darwin", "Darwin"},
530 {"linux", "Linux"},
531 {"windows", "Windows"},
532 }
533
534 if hod.Host() {
535 for _, v := range osList {
536 if v.goos == runtime.GOOS {
Colin Cross28d76592015-03-26 16:14:04 -0700537 a.extendProperties(ctx, "target", v.goos, generalPropsValue,
Colin Cross3f40fa42015-01-30 17:27:36 -0800538 reflect.ValueOf(a.archProperties[i].Target).FieldByName(v.field).Elem().Elem())
Colin Crossb05bff22015-04-30 15:08:04 -0700539 t := arch.ArchType
540 a.extendProperties(ctx, "target", v.goos+"_"+t.Name, generalPropsValue,
541 reflect.ValueOf(a.archProperties[i].Target).FieldByName(v.field+"_"+t.Name).Elem().Elem())
Colin Cross3f40fa42015-01-30 17:27:36 -0800542 }
543 }
Colin Cross28d76592015-03-26 16:14:04 -0700544 a.extendProperties(ctx, "target", "not_windows", generalPropsValue,
Colin Cross3f40fa42015-01-30 17:27:36 -0800545 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Not_windows").Elem().Elem())
546 }
547
Colin Crossf8209412015-03-26 14:44:26 -0700548 // Handle 64-bit device properties in the form:
549 // target {
550 // android64 {
551 // key: value,
552 // },
553 // android32 {
554 // key: value,
555 // },
556 // },
557 // WARNING: this is probably not what you want to use in your blueprints file, it selects
558 // options for all targets on a device that supports 64-bit binaries, not just the targets
559 // that are being compiled for 64-bit. Its expected use case is binaries like linker and
560 // debuggerd that need to know when they are a 32-bit process running on a 64-bit device
561 if hod.Device() {
562 if true /* && target_is_64_bit */ {
Colin Cross28d76592015-03-26 16:14:04 -0700563 a.extendProperties(ctx, "target", "android64", generalPropsValue,
Colin Crossf8209412015-03-26 14:44:26 -0700564 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Android64").Elem().Elem())
565 } else {
Colin Cross28d76592015-03-26 16:14:04 -0700566 a.extendProperties(ctx, "target", "android32", generalPropsValue,
Colin Crossf8209412015-03-26 14:44:26 -0700567 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Android32").Elem().Elem())
568 }
569 }
Colin Crossb05bff22015-04-30 15:08:04 -0700570
571 // Handle device architecture properties in the form:
572 // target {
573 // android_arm {
574 // key: value,
575 // },
576 // android_x86 {
577 // key: value,
578 // },
579 // },
580 if hod.Device() {
581 t := arch.ArchType
582 a.extendProperties(ctx, "target", "android_"+t.Name, generalPropsValue,
583 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Android_"+t.Name).Elem().Elem())
584 }
585
Colin Cross3f40fa42015-01-30 17:27:36 -0800586 if ctx.Failed() {
587 return
588 }
589 }
590}
591
592func forEachInterface(v reflect.Value, f func(reflect.Value)) {
593 switch v.Kind() {
594 case reflect.Interface:
595 f(v)
596 case reflect.Struct:
597 for i := 0; i < v.NumField(); i++ {
598 forEachInterface(v.Field(i), f)
599 }
600 case reflect.Ptr:
601 forEachInterface(v.Elem(), f)
602 default:
603 panic(fmt.Errorf("Unsupported kind %s", v.Kind()))
604 }
605}
606
607// TODO: move this to proptools
Colin Cross28d76592015-03-26 16:14:04 -0700608func (a *AndroidModuleBase) extendProperties(ctx blueprint.EarlyMutatorContext, variationType, variationName string,
Colin Cross3f40fa42015-01-30 17:27:36 -0800609 dstValue, srcValue reflect.Value) {
Colin Cross28d76592015-03-26 16:14:04 -0700610 a.extendPropertiesRecursive(ctx, variationType, variationName, dstValue, srcValue, "")
Colin Cross3f40fa42015-01-30 17:27:36 -0800611}
612
Colin Cross28d76592015-03-26 16:14:04 -0700613func (a *AndroidModuleBase) extendPropertiesRecursive(ctx blueprint.EarlyMutatorContext, variationType, variationName string,
Colin Cross3f40fa42015-01-30 17:27:36 -0800614 dstValue, srcValue reflect.Value, recursePrefix string) {
615
616 typ := dstValue.Type()
617 if srcValue.Type() != typ {
618 panic(fmt.Errorf("can't extend mismatching types (%s <- %s)",
619 dstValue.Kind(), srcValue.Kind()))
620 }
621
622 for i := 0; i < srcValue.NumField(); i++ {
623 field := typ.Field(i)
624 if field.PkgPath != "" {
625 // The field is not exported so just skip it.
626 continue
627 }
628
629 srcFieldValue := srcValue.Field(i)
630 dstFieldValue := dstValue.Field(i)
631
632 localPropertyName := proptools.PropertyNameForField(field.Name)
633 propertyName := fmt.Sprintf("%s.%s.%s%s", variationType, variationName,
634 recursePrefix, localPropertyName)
635 propertyPresentInVariation := ctx.ContainsProperty(propertyName)
636
637 if !propertyPresentInVariation {
638 continue
639 }
640
641 tag := field.Tag.Get("android")
642 tags := map[string]bool{}
643 for _, entry := range strings.Split(tag, ",") {
644 if entry != "" {
645 tags[entry] = true
646 }
647 }
648
649 if !tags["arch_variant"] {
650 ctx.PropertyErrorf(propertyName, "property %q can't be specific to a build variant",
651 recursePrefix+proptools.PropertyNameForField(field.Name))
652 continue
653 }
654
Colin Cross28d76592015-03-26 16:14:04 -0700655 if !ctx.ContainsProperty(propertyName) {
656 continue
657 }
658 a.extendedProperties[localPropertyName] = struct{}{}
659
Colin Cross3f40fa42015-01-30 17:27:36 -0800660 switch srcFieldValue.Kind() {
661 case reflect.Bool:
662 // Replace the original value.
663 dstFieldValue.Set(srcFieldValue)
664 case reflect.String:
665 // Append the extension string.
666 dstFieldValue.SetString(dstFieldValue.String() +
667 srcFieldValue.String())
668 case reflect.Struct:
669 // Recursively extend the struct's fields.
670 newRecursePrefix := fmt.Sprintf("%s%s.", recursePrefix, strings.ToLower(field.Name))
Colin Cross28d76592015-03-26 16:14:04 -0700671 a.extendPropertiesRecursive(ctx, variationType, variationName,
Colin Cross3f40fa42015-01-30 17:27:36 -0800672 dstFieldValue, srcFieldValue,
673 newRecursePrefix)
674 case reflect.Slice:
Dan Willemsen2ef08f42015-06-30 18:15:24 -0700675 dstFieldValue.Set(reflect.AppendSlice(dstFieldValue, srcFieldValue))
Colin Cross3f40fa42015-01-30 17:27:36 -0800676 case reflect.Ptr, reflect.Interface:
677 // Recursively extend the pointed-to struct's fields.
678 if dstFieldValue.IsNil() != srcFieldValue.IsNil() {
679 panic(fmt.Errorf("can't extend field %q: nilitude mismatch"))
680 }
681 if dstFieldValue.Type() != srcFieldValue.Type() {
682 panic(fmt.Errorf("can't extend field %q: type mismatch"))
683 }
684 if !dstFieldValue.IsNil() {
685 newRecursePrefix := fmt.Sprintf("%s.%s", recursePrefix, field.Name)
Colin Cross28d76592015-03-26 16:14:04 -0700686 a.extendPropertiesRecursive(ctx, variationType, variationName,
Colin Cross3f40fa42015-01-30 17:27:36 -0800687 dstFieldValue.Elem(), srcFieldValue.Elem(),
688 newRecursePrefix)
689 }
690 default:
691 panic(fmt.Errorf("unexpected kind for property struct field %q: %s",
692 field.Name, srcFieldValue.Kind()))
693 }
694 }
695}