blob: 6865904d44bf9a786791c74787216a7184ebd7df [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
23 "github.com/google/blueprint"
24 "github.com/google/blueprint/proptools"
Colin Cross3f40fa42015-01-30 17:27:36 -080025)
26
27var (
Colin Crossec193632015-07-06 17:49:43 -070028 Arm = newArch("arm", "lib32")
29 Arm64 = newArch("arm64", "lib64")
30 Mips = newArch("mips", "lib32")
31 Mips64 = newArch("mips64", "lib64")
32 X86 = newArch("x86", "lib32")
33 X86_64 = newArch("x86_64", "lib64")
Colin Cross2fe66872015-03-30 17:20:39 -070034
35 Common = ArchType{
36 Name: "common",
37 }
Colin Cross3f40fa42015-01-30 17:27:36 -080038)
39
40/*
41Example blueprints file containing all variant property groups, with comment listing what type
42of variants get properties in that group:
43
44module {
45 arch: {
46 arm: {
47 // Host or device variants with arm architecture
48 },
49 arm64: {
50 // Host or device variants with arm64 architecture
51 },
52 mips: {
53 // Host or device variants with mips architecture
54 },
55 mips64: {
56 // Host or device variants with mips64 architecture
57 },
58 x86: {
59 // Host or device variants with x86 architecture
60 },
61 x86_64: {
62 // Host or device variants with x86_64 architecture
63 },
64 },
65 multilib: {
66 lib32: {
67 // Host or device variants for 32-bit architectures
68 },
69 lib64: {
70 // Host or device variants for 64-bit architectures
71 },
72 },
73 target: {
74 android: {
75 // Device variants
76 },
77 host: {
78 // Host variants
79 },
80 linux: {
81 // Linux host variants
82 },
83 darwin: {
84 // Darwin host variants
85 },
86 windows: {
87 // Windows host variants
88 },
89 not_windows: {
90 // Non-windows host variants
91 },
92 },
93}
94*/
Colin Cross7d5136f2015-05-11 13:39:40 -070095
Colin Cross3f40fa42015-01-30 17:27:36 -080096type archProperties struct {
Colin Cross7d5136f2015-05-11 13:39:40 -070097 // Properties to vary by target architecture
Colin Cross3f40fa42015-01-30 17:27:36 -080098 Arch struct {
Colin Cross7d5136f2015-05-11 13:39:40 -070099 // Properties for module variants being built to run on arm (host or device)
100 Arm interface{} `blueprint:"filter(android:\"arch_variant\")"`
101 // Properties for module variants being built to run on arm64 (host or device)
102 Arm64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
103 // Properties for module variants being built to run on mips (host or device)
104 Mips interface{} `blueprint:"filter(android:\"arch_variant\")"`
105 // Properties for module variants being built to run on mips64 (host or device)
106 Mips64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
107 // Properties for module variants being built to run on x86 (host or device)
108 X86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
109 // Properties for module variants being built to run on x86_64 (host or device)
110 X86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Crossec193632015-07-06 17:49:43 -0700111
112 // Arm arch variants
113 Armv5te interface{} `blueprint:"filter(android:\"arch_variant\")"`
114 Armv7_a interface{} `blueprint:"filter(android:\"arch_variant\")"`
115 Armv7_a_neon interface{} `blueprint:"filter(android:\"arch_variant\")"`
116
117 // Arm cpu variants
118 Cortex_a7 interface{} `blueprint:"filter(android:\"arch_variant\")"`
119 Cortex_a8 interface{} `blueprint:"filter(android:\"arch_variant\")"`
120 Cortex_a9 interface{} `blueprint:"filter(android:\"arch_variant\")"`
121 Cortex_a15 interface{} `blueprint:"filter(android:\"arch_variant\")"`
122 Krait interface{} `blueprint:"filter(android:\"arch_variant\")"`
123 Denver interface{} `blueprint:"filter(android:\"arch_variant\")"`
124
125 // Arm64 cpu variants
126 Denver64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
127
128 // Mips arch variants
129 Mips_rev6 interface{} `blueprint:"filter(android:\"arch_variant\")"`
130
131 // X86 cpu variants
132 Atom interface{} `blueprint:"filter(android:\"arch_variant\")"`
133 Silvermont interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Cross3f40fa42015-01-30 17:27:36 -0800134 }
Colin Crossec193632015-07-06 17:49:43 -0700135
Colin Cross7d5136f2015-05-11 13:39:40 -0700136 // Properties to vary by 32-bit or 64-bit
Colin Cross3f40fa42015-01-30 17:27:36 -0800137 Multilib struct {
Colin Cross7d5136f2015-05-11 13:39:40 -0700138 // Properties for module variants being built to run on 32-bit devices
139 Lib32 interface{} `blueprint:"filter(android:\"arch_variant\")"`
140 // Properties for module variants being built to run on 64-bit devices
141 Lib64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Cross3f40fa42015-01-30 17:27:36 -0800142 }
Colin Cross7d5136f2015-05-11 13:39:40 -0700143 // Properties to vary by build target (host or device, os, os+archictecture)
Colin Cross3f40fa42015-01-30 17:27:36 -0800144 Target struct {
Colin Cross7d5136f2015-05-11 13:39:40 -0700145 // Properties for module variants being built to run on the host
146 Host interface{} `blueprint:"filter(android:\"arch_variant\")"`
147 // Properties for module variants being built to run on the device
148 Android interface{} `blueprint:"filter(android:\"arch_variant\")"`
149 // Properties for module variants being built to run on arm devices
150 Android_arm interface{} `blueprint:"filter(android:\"arch_variant\")"`
151 // Properties for module variants being built to run on arm64 devices
152 Android_arm64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
153 // Properties for module variants being built to run on mips devices
154 Android_mips interface{} `blueprint:"filter(android:\"arch_variant\")"`
155 // Properties for module variants being built to run on mips64 devices
156 Android_mips64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
157 // Properties for module variants being built to run on x86 devices
158 Android_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
159 // Properties for module variants being built to run on x86_64 devices
160 Android_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
161 // Properties for module variants being built to run on devices that support 64-bit
162 Android64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
163 // Properties for module variants being built to run on devices that do not support 64-bit
164 Android32 interface{} `blueprint:"filter(android:\"arch_variant\")"`
165 // Properties for module variants being built to run on linux hosts
166 Linux interface{} `blueprint:"filter(android:\"arch_variant\")"`
167 // Properties for module variants being built to run on linux x86 hosts
168 Linux_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
169 // Properties for module variants being built to run on linux x86_64 hosts
170 Linux_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
171 // Properties for module variants being built to run on darwin hosts
172 Darwin interface{} `blueprint:"filter(android:\"arch_variant\")"`
173 // Properties for module variants being built to run on darwin x86 hosts
174 Darwin_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
175 // Properties for module variants being built to run on darwin x86_64 hosts
176 Darwin_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
177 // Properties for module variants being built to run on windows hosts
178 Windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
179 // Properties for module variants being built to run on linux or darwin hosts
180 Not_windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
Colin Cross3f40fa42015-01-30 17:27:36 -0800181 }
182}
183
184// An Arch indicates a single CPU architecture.
185type Arch struct {
Colin Crossd3ba0392015-05-07 14:11:29 -0700186 ArchType ArchType
187 ArchVariant string
188 CpuVariant string
189 Abi string
Colin Cross3f40fa42015-01-30 17:27:36 -0800190}
191
192func (a Arch) String() string {
Colin Crossd3ba0392015-05-07 14:11:29 -0700193 s := a.ArchType.String()
Colin Cross3f40fa42015-01-30 17:27:36 -0800194 if a.ArchVariant != "" {
195 s += "_" + a.ArchVariant
196 }
197 if a.CpuVariant != "" {
198 s += "_" + a.CpuVariant
199 }
200 return s
201}
202
203type ArchType struct {
Colin Crossec193632015-07-06 17:49:43 -0700204 Name string
205 Multilib string
Colin Cross3f40fa42015-01-30 17:27:36 -0800206}
207
Colin Crossec193632015-07-06 17:49:43 -0700208func newArch(name, multilib string) ArchType {
Colin Cross3f40fa42015-01-30 17:27:36 -0800209 return ArchType{
Colin Crossec193632015-07-06 17:49:43 -0700210 Name: name,
211 Multilib: multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -0800212 }
213}
214
215func (a ArchType) String() string {
216 return a.Name
217}
218
219type HostOrDeviceSupported int
220
221const (
222 _ HostOrDeviceSupported = iota
223 HostSupported
224 DeviceSupported
225 HostAndDeviceSupported
226)
227
228type HostOrDevice int
229
230const (
231 _ HostOrDevice = iota
232 Host
233 Device
234)
235
236func (hod HostOrDevice) String() string {
237 switch hod {
238 case Device:
239 return "device"
240 case Host:
241 return "host"
242 default:
243 panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod))
244 }
245}
246
Colin Crossec193632015-07-06 17:49:43 -0700247func (hod HostOrDevice) Property() string {
Colin Cross3f40fa42015-01-30 17:27:36 -0800248 switch hod {
249 case Device:
250 return "android"
251 case Host:
252 return "host"
253 default:
254 panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod))
255 }
256}
257
Colin Cross3f40fa42015-01-30 17:27:36 -0800258func (hod HostOrDevice) Host() bool {
259 if hod == 0 {
260 panic("HostOrDevice unset")
261 }
262 return hod == Host
263}
264
265func (hod HostOrDevice) Device() bool {
266 if hod == 0 {
267 panic("HostOrDevice unset")
268 }
269 return hod == Device
270}
271
272var hostOrDeviceName = map[HostOrDevice]string{
273 Device: "device",
274 Host: "host",
275}
276
277var (
278 armArch = Arch{
Colin Crossd3ba0392015-05-07 14:11:29 -0700279 ArchType: Arm,
280 ArchVariant: "armv7-a-neon",
281 CpuVariant: "cortex-a15",
282 Abi: "armeabi-v7a",
Colin Cross3f40fa42015-01-30 17:27:36 -0800283 }
284 arm64Arch = Arch{
Colin Crossec193632015-07-06 17:49:43 -0700285 ArchType: Arm64,
286 CpuVariant: "denver64",
287 Abi: "arm64-v8a",
Colin Cross3f40fa42015-01-30 17:27:36 -0800288 }
Colin Crossd3ba0392015-05-07 14:11:29 -0700289 x86Arch = Arch{
290 ArchType: X86,
Colin Cross3f40fa42015-01-30 17:27:36 -0800291 }
Colin Crossd3ba0392015-05-07 14:11:29 -0700292 x8664Arch = Arch{
293 ArchType: X86_64,
Colin Cross3f40fa42015-01-30 17:27:36 -0800294 }
Colin Crossd3ba0392015-05-07 14:11:29 -0700295 commonArch = Arch{
296 ArchType: Common,
Colin Cross2fe66872015-03-30 17:20:39 -0700297 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800298)
299
Colin Crossd3ba0392015-05-07 14:11:29 -0700300func HostOrDeviceMutator(mctx blueprint.EarlyMutatorContext) {
301 var module AndroidModule
302 var ok bool
303 if module, ok = mctx.Module().(AndroidModule); !ok {
304 return
305 }
306
307 hods := []HostOrDevice{}
308
309 if module.base().HostSupported() {
310 hods = append(hods, Host)
311 }
312
313 if module.base().DeviceSupported() {
314 hods = append(hods, Device)
315 }
316
317 if len(hods) == 0 {
318 return
319 }
320
321 hodNames := []string{}
322 for _, hod := range hods {
323 hodNames = append(hodNames, hod.String())
324 }
325
326 modules := mctx.CreateVariations(hodNames...)
327 for i, m := range modules {
328 m.(AndroidModule).base().SetHostOrDevice(hods[i])
329 }
330}
331
Colin Cross3f40fa42015-01-30 17:27:36 -0800332func ArchMutator(mctx blueprint.EarlyMutatorContext) {
333 var module AndroidModule
334 var ok bool
335 if module, ok = mctx.Module().(AndroidModule); !ok {
336 return
337 }
338
339 // TODO: this is all hardcoded for arm64 primary, arm secondary for now
340 // Replace with a configuration file written by lunch or bootstrap
341
342 arches := []Arch{}
343
Colin Crossd3ba0392015-05-07 14:11:29 -0700344 if module.base().HostSupported() && module.base().HostOrDevice().Host() {
Colin Cross2fe66872015-03-30 17:20:39 -0700345 switch module.base().commonProperties.Compile_multilib {
346 case "common":
Colin Crossd3ba0392015-05-07 14:11:29 -0700347 arches = append(arches, commonArch)
Dan Willemsenffce3fc2015-07-08 13:02:19 -0700348 case "both":
349 arches = append(arches, x8664Arch, x86Arch)
350 case "first", "64":
351 arches = append(arches, x8664Arch)
352 case "32":
353 arches = append(arches, x86Arch)
Colin Cross2fe66872015-03-30 17:20:39 -0700354 default:
Colin Crossd3ba0392015-05-07 14:11:29 -0700355 arches = append(arches, x8664Arch)
Colin Cross2fe66872015-03-30 17:20:39 -0700356 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800357 }
358
Colin Crossd3ba0392015-05-07 14:11:29 -0700359 if module.base().DeviceSupported() && module.base().HostOrDevice().Device() {
Colin Cross3f40fa42015-01-30 17:27:36 -0800360 switch module.base().commonProperties.Compile_multilib {
Colin Cross2fe66872015-03-30 17:20:39 -0700361 case "common":
Colin Crossd3ba0392015-05-07 14:11:29 -0700362 arches = append(arches, commonArch)
Colin Cross3f40fa42015-01-30 17:27:36 -0800363 case "both":
364 arches = append(arches, arm64Arch, armArch)
365 case "first", "64":
366 arches = append(arches, arm64Arch)
367 case "32":
368 arches = append(arches, armArch)
369 default:
370 mctx.ModuleErrorf(`compile_multilib must be "both", "first", "32", or "64", found %q`,
371 module.base().commonProperties.Compile_multilib)
372 }
373 }
374
Colin Cross5049f022015-03-18 13:28:46 -0700375 if len(arches) == 0 {
376 return
377 }
378
Colin Cross3f40fa42015-01-30 17:27:36 -0800379 archNames := []string{}
380 for _, arch := range arches {
381 archNames = append(archNames, arch.String())
382 }
383
384 modules := mctx.CreateVariations(archNames...)
385
386 for i, m := range modules {
387 m.(AndroidModule).base().SetArch(arches[i])
Colin Crossd3ba0392015-05-07 14:11:29 -0700388 m.(AndroidModule).base().setArchProperties(mctx)
Colin Cross3f40fa42015-01-30 17:27:36 -0800389 }
390}
391
Colin Crossc472d572015-03-17 15:06:21 -0700392func InitArchModule(m AndroidModule, defaultMultilib Multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -0800393 propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
394
395 base := m.base()
396
Colin Crossc472d572015-03-17 15:06:21 -0700397 base.commonProperties.Compile_multilib = string(defaultMultilib)
Colin Cross3f40fa42015-01-30 17:27:36 -0800398
399 base.generalProperties = append(base.generalProperties,
Colin Cross3f40fa42015-01-30 17:27:36 -0800400 propertyStructs...)
401
402 for _, properties := range base.generalProperties {
403 propertiesValue := reflect.ValueOf(properties)
404 if propertiesValue.Kind() != reflect.Ptr {
405 panic("properties must be a pointer to a struct")
406 }
407
408 propertiesValue = propertiesValue.Elem()
409 if propertiesValue.Kind() != reflect.Struct {
410 panic("properties must be a pointer to a struct")
411 }
412
413 archProperties := &archProperties{}
414 forEachInterface(reflect.ValueOf(archProperties), func(v reflect.Value) {
Colin Cross3ab7d882015-05-19 13:03:01 -0700415 newValue := proptools.CloneEmptyProperties(propertiesValue)
Colin Cross3f40fa42015-01-30 17:27:36 -0800416 v.Set(newValue)
417 })
418
419 base.archProperties = append(base.archProperties, archProperties)
420 }
421
422 var allProperties []interface{}
423 allProperties = append(allProperties, base.generalProperties...)
424 for _, asp := range base.archProperties {
425 allProperties = append(allProperties, asp)
426 }
427
428 return m, allProperties
429}
430
Colin Crossec193632015-07-06 17:49:43 -0700431var dashToUnderscoreReplacer = strings.NewReplacer("-", "_")
432
Colin Cross3f40fa42015-01-30 17:27:36 -0800433// Rewrite the module's properties structs to contain arch-specific values.
Colin Crossd3ba0392015-05-07 14:11:29 -0700434func (a *AndroidModuleBase) setArchProperties(ctx blueprint.EarlyMutatorContext) {
435 arch := a.commonProperties.CompileArch
436 hod := a.commonProperties.CompileHostOrDevice
437
Colin Cross2fe66872015-03-30 17:20:39 -0700438 if arch.ArchType == Common {
439 return
440 }
441
Colin Cross3f40fa42015-01-30 17:27:36 -0800442 for i := range a.generalProperties {
443 generalPropsValue := reflect.ValueOf(a.generalProperties[i]).Elem()
444
445 // Handle arch-specific properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700446 // arch: {
447 // arm64: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800448 // key: value,
449 // },
450 // },
451 t := arch.ArchType
Colin Crossec193632015-07-06 17:49:43 -0700452 field := proptools.FieldNameForProperty(t.Name)
Colin Cross28d76592015-03-26 16:14:04 -0700453 a.extendProperties(ctx, "arch", t.Name, generalPropsValue,
Colin Crossec193632015-07-06 17:49:43 -0700454 reflect.ValueOf(a.archProperties[i].Arch).FieldByName(field).Elem().Elem())
455
456 // Handle arch-variant-specific properties in the form:
457 // arch: {
458 // variant: {
459 // key: value,
460 // },
461 // },
462 v := dashToUnderscoreReplacer.Replace(arch.ArchVariant)
463 if v != "" {
464 field := proptools.FieldNameForProperty(v)
465 a.extendProperties(ctx, "arch", v, generalPropsValue,
466 reflect.ValueOf(a.archProperties[i].Arch).FieldByName(field).Elem().Elem())
467 }
468
469 // Handle cpu-variant-specific properties in the form:
470 // arch: {
471 // variant: {
472 // key: value,
473 // },
474 // },
475 c := dashToUnderscoreReplacer.Replace(arch.CpuVariant)
476 if c != "" {
477 field := proptools.FieldNameForProperty(c)
478 a.extendProperties(ctx, "arch", c, generalPropsValue,
479 reflect.ValueOf(a.archProperties[i].Arch).FieldByName(field).Elem().Elem())
480 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800481
482 // Handle multilib-specific properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700483 // multilib: {
484 // lib32: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800485 // key: value,
486 // },
487 // },
Colin Crossec193632015-07-06 17:49:43 -0700488 multilibField := proptools.FieldNameForProperty(t.Multilib)
Colin Cross28d76592015-03-26 16:14:04 -0700489 a.extendProperties(ctx, "multilib", t.Multilib, generalPropsValue,
Colin Crossec193632015-07-06 17:49:43 -0700490 reflect.ValueOf(a.archProperties[i].Multilib).FieldByName(multilibField).Elem().Elem())
Colin Cross3f40fa42015-01-30 17:27:36 -0800491
492 // Handle host-or-device-specific properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700493 // target: {
494 // host: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800495 // key: value,
496 // },
497 // },
Colin Crossec193632015-07-06 17:49:43 -0700498 hodProperty := hod.Property()
499 hodField := proptools.FieldNameForProperty(hodProperty)
500 a.extendProperties(ctx, "target", hodProperty, generalPropsValue,
501 reflect.ValueOf(a.archProperties[i].Target).FieldByName(hodField).Elem().Elem())
Colin Cross3f40fa42015-01-30 17:27:36 -0800502
503 // Handle host target properties in the form:
Colin Crossb05bff22015-04-30 15:08:04 -0700504 // target: {
505 // linux: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800506 // key: value,
507 // },
Colin Crossb05bff22015-04-30 15:08:04 -0700508 // not_windows: {
509 // key: value,
510 // },
511 // linux_x86: {
512 // key: value,
513 // },
514 // linux_arm: {
Colin Cross3f40fa42015-01-30 17:27:36 -0800515 // key: value,
516 // },
517 // },
518 var osList = []struct {
519 goos string
520 field string
521 }{
522 {"darwin", "Darwin"},
523 {"linux", "Linux"},
524 {"windows", "Windows"},
525 }
526
527 if hod.Host() {
528 for _, v := range osList {
529 if v.goos == runtime.GOOS {
Colin Cross28d76592015-03-26 16:14:04 -0700530 a.extendProperties(ctx, "target", v.goos, generalPropsValue,
Colin Cross3f40fa42015-01-30 17:27:36 -0800531 reflect.ValueOf(a.archProperties[i].Target).FieldByName(v.field).Elem().Elem())
Colin Crossb05bff22015-04-30 15:08:04 -0700532 t := arch.ArchType
533 a.extendProperties(ctx, "target", v.goos+"_"+t.Name, generalPropsValue,
534 reflect.ValueOf(a.archProperties[i].Target).FieldByName(v.field+"_"+t.Name).Elem().Elem())
Colin Cross3f40fa42015-01-30 17:27:36 -0800535 }
536 }
Colin Cross28d76592015-03-26 16:14:04 -0700537 a.extendProperties(ctx, "target", "not_windows", generalPropsValue,
Colin Cross3f40fa42015-01-30 17:27:36 -0800538 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Not_windows").Elem().Elem())
539 }
540
Colin Crossf8209412015-03-26 14:44:26 -0700541 // Handle 64-bit device properties in the form:
542 // target {
543 // android64 {
544 // key: value,
545 // },
546 // android32 {
547 // key: value,
548 // },
549 // },
550 // WARNING: this is probably not what you want to use in your blueprints file, it selects
551 // options for all targets on a device that supports 64-bit binaries, not just the targets
552 // that are being compiled for 64-bit. Its expected use case is binaries like linker and
553 // debuggerd that need to know when they are a 32-bit process running on a 64-bit device
554 if hod.Device() {
555 if true /* && target_is_64_bit */ {
Colin Cross28d76592015-03-26 16:14:04 -0700556 a.extendProperties(ctx, "target", "android64", generalPropsValue,
Colin Crossf8209412015-03-26 14:44:26 -0700557 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Android64").Elem().Elem())
558 } else {
Colin Cross28d76592015-03-26 16:14:04 -0700559 a.extendProperties(ctx, "target", "android32", generalPropsValue,
Colin Crossf8209412015-03-26 14:44:26 -0700560 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Android32").Elem().Elem())
561 }
562 }
Colin Crossb05bff22015-04-30 15:08:04 -0700563
564 // Handle device architecture properties in the form:
565 // target {
566 // android_arm {
567 // key: value,
568 // },
569 // android_x86 {
570 // key: value,
571 // },
572 // },
573 if hod.Device() {
574 t := arch.ArchType
575 a.extendProperties(ctx, "target", "android_"+t.Name, generalPropsValue,
576 reflect.ValueOf(a.archProperties[i].Target).FieldByName("Android_"+t.Name).Elem().Elem())
577 }
578
Colin Cross3f40fa42015-01-30 17:27:36 -0800579 if ctx.Failed() {
580 return
581 }
582 }
583}
584
585func forEachInterface(v reflect.Value, f func(reflect.Value)) {
586 switch v.Kind() {
587 case reflect.Interface:
588 f(v)
589 case reflect.Struct:
590 for i := 0; i < v.NumField(); i++ {
591 forEachInterface(v.Field(i), f)
592 }
593 case reflect.Ptr:
594 forEachInterface(v.Elem(), f)
595 default:
596 panic(fmt.Errorf("Unsupported kind %s", v.Kind()))
597 }
598}
599
600// TODO: move this to proptools
Colin Cross28d76592015-03-26 16:14:04 -0700601func (a *AndroidModuleBase) extendProperties(ctx blueprint.EarlyMutatorContext, variationType, variationName string,
Colin Cross3f40fa42015-01-30 17:27:36 -0800602 dstValue, srcValue reflect.Value) {
Colin Cross28d76592015-03-26 16:14:04 -0700603 a.extendPropertiesRecursive(ctx, variationType, variationName, dstValue, srcValue, "")
Colin Cross3f40fa42015-01-30 17:27:36 -0800604}
605
Colin Cross28d76592015-03-26 16:14:04 -0700606func (a *AndroidModuleBase) extendPropertiesRecursive(ctx blueprint.EarlyMutatorContext, variationType, variationName string,
Colin Cross3f40fa42015-01-30 17:27:36 -0800607 dstValue, srcValue reflect.Value, recursePrefix string) {
608
609 typ := dstValue.Type()
610 if srcValue.Type() != typ {
611 panic(fmt.Errorf("can't extend mismatching types (%s <- %s)",
612 dstValue.Kind(), srcValue.Kind()))
613 }
614
615 for i := 0; i < srcValue.NumField(); i++ {
616 field := typ.Field(i)
617 if field.PkgPath != "" {
618 // The field is not exported so just skip it.
619 continue
620 }
621
622 srcFieldValue := srcValue.Field(i)
623 dstFieldValue := dstValue.Field(i)
624
625 localPropertyName := proptools.PropertyNameForField(field.Name)
626 propertyName := fmt.Sprintf("%s.%s.%s%s", variationType, variationName,
627 recursePrefix, localPropertyName)
628 propertyPresentInVariation := ctx.ContainsProperty(propertyName)
629
630 if !propertyPresentInVariation {
631 continue
632 }
633
634 tag := field.Tag.Get("android")
635 tags := map[string]bool{}
636 for _, entry := range strings.Split(tag, ",") {
637 if entry != "" {
638 tags[entry] = true
639 }
640 }
641
642 if !tags["arch_variant"] {
643 ctx.PropertyErrorf(propertyName, "property %q can't be specific to a build variant",
644 recursePrefix+proptools.PropertyNameForField(field.Name))
645 continue
646 }
647
Colin Cross28d76592015-03-26 16:14:04 -0700648 if !ctx.ContainsProperty(propertyName) {
649 continue
650 }
651 a.extendedProperties[localPropertyName] = struct{}{}
652
Colin Cross3f40fa42015-01-30 17:27:36 -0800653 switch srcFieldValue.Kind() {
654 case reflect.Bool:
655 // Replace the original value.
656 dstFieldValue.Set(srcFieldValue)
657 case reflect.String:
658 // Append the extension string.
659 dstFieldValue.SetString(dstFieldValue.String() +
660 srcFieldValue.String())
661 case reflect.Struct:
662 // Recursively extend the struct's fields.
663 newRecursePrefix := fmt.Sprintf("%s%s.", recursePrefix, strings.ToLower(field.Name))
Colin Cross28d76592015-03-26 16:14:04 -0700664 a.extendPropertiesRecursive(ctx, variationType, variationName,
Colin Cross3f40fa42015-01-30 17:27:36 -0800665 dstFieldValue, srcFieldValue,
666 newRecursePrefix)
667 case reflect.Slice:
Dan Willemsen2ef08f42015-06-30 18:15:24 -0700668 dstFieldValue.Set(reflect.AppendSlice(dstFieldValue, srcFieldValue))
Colin Cross3f40fa42015-01-30 17:27:36 -0800669 case reflect.Ptr, reflect.Interface:
670 // Recursively extend the pointed-to struct's fields.
671 if dstFieldValue.IsNil() != srcFieldValue.IsNil() {
672 panic(fmt.Errorf("can't extend field %q: nilitude mismatch"))
673 }
674 if dstFieldValue.Type() != srcFieldValue.Type() {
675 panic(fmt.Errorf("can't extend field %q: type mismatch"))
676 }
677 if !dstFieldValue.IsNil() {
678 newRecursePrefix := fmt.Sprintf("%s.%s", recursePrefix, field.Name)
Colin Cross28d76592015-03-26 16:14:04 -0700679 a.extendPropertiesRecursive(ctx, variationType, variationName,
Colin Cross3f40fa42015-01-30 17:27:36 -0800680 dstFieldValue.Elem(), srcFieldValue.Elem(),
681 newRecursePrefix)
682 }
683 default:
684 panic(fmt.Errorf("unexpected kind for property struct field %q: %s",
685 field.Name, srcFieldValue.Kind()))
686 }
687 }
688}