• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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 android
16
17import (
18	"fmt"
19	"reflect"
20	"runtime"
21	"strings"
22
23	"github.com/google/blueprint/proptools"
24)
25
26func init() {
27	PreDepsMutators(func(ctx RegisterMutatorsContext) {
28		ctx.BottomUp("variable", variableMutator).Parallel()
29	})
30}
31
32type variableProperties struct {
33	Product_variables struct {
34		Platform_sdk_version struct {
35			Asflags []string
36			Cflags  []string
37		}
38
39		// unbundled_build is a catch-all property to annotate modules that don't build in one or
40		// more unbundled branches, usually due to dependencies missing from the manifest.
41		Unbundled_build struct {
42			Enabled *bool `android:"arch_variant"`
43		} `android:"arch_variant"`
44
45		Brillo struct {
46			Cflags         []string
47			Version_script *string `android:"arch_variant"`
48		} `android:"arch_variant"`
49
50		Malloc_not_svelte struct {
51			Cflags []string
52		}
53
54		Safestack struct {
55			Cflags []string `android:"arch_variant"`
56		} `android:"arch_variant"`
57
58		Binder32bit struct {
59			Cflags []string
60		}
61
62		Device_uses_hwc2 struct {
63			Cflags []string
64		}
65
66		Override_rs_driver struct {
67			Cflags []string
68		}
69
70		// treble is true when a build is a Treble compliant device.  This is automatically set when
71		// a build is shipped with Android O, but can be overriden.  This controls such things as
72		// the sepolicy split and enabling the Treble linker namespaces.
73		Treble struct {
74			Cflags []string
75		}
76
77		// debuggable is true for eng and userdebug builds, and can be used to turn on additional
78		// debugging features that don't significantly impact runtime behavior.  userdebug builds
79		// are used for dogfooding and performance testing, and should be as similar to user builds
80		// as possible.
81		Debuggable struct {
82			Cflags   []string
83			Cppflags []string
84			Init_rc  []string
85		}
86
87		// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
88		// features.
89		Eng struct {
90			Cflags   []string
91			Cppflags []string
92		}
93
94		Pdk struct {
95			Enabled *bool
96		}
97	} `android:"arch_variant"`
98}
99
100var zeroProductVariables variableProperties
101
102type productVariables struct {
103	// Suffix to add to generated Makefiles
104	Make_suffix *string `json:",omitempty"`
105
106	Platform_sdk_version           *int     `json:",omitempty"`
107	Platform_version_all_codenames []string `json:",omitempty"`
108
109	DeviceName        *string   `json:",omitempty"`
110	DeviceArch        *string   `json:",omitempty"`
111	DeviceArchVariant *string   `json:",omitempty"`
112	DeviceCpuVariant  *string   `json:",omitempty"`
113	DeviceAbi         *[]string `json:",omitempty"`
114	DeviceUsesClang   *bool     `json:",omitempty"`
115	DeviceVndkVersion *string   `json:",omitempty"`
116
117	DeviceSecondaryArch        *string   `json:",omitempty"`
118	DeviceSecondaryArchVariant *string   `json:",omitempty"`
119	DeviceSecondaryCpuVariant  *string   `json:",omitempty"`
120	DeviceSecondaryAbi         *[]string `json:",omitempty"`
121
122	HostArch          *string `json:",omitempty"`
123	HostSecondaryArch *string `json:",omitempty"`
124
125	CrossHost              *string `json:",omitempty"`
126	CrossHostArch          *string `json:",omitempty"`
127	CrossHostSecondaryArch *string `json:",omitempty"`
128
129	Allow_missing_dependencies *bool `json:",omitempty"`
130	Unbundled_build            *bool `json:",omitempty"`
131	Brillo                     *bool `json:",omitempty"`
132	Malloc_not_svelte          *bool `json:",omitempty"`
133	Safestack                  *bool `json:",omitempty"`
134	HostStaticBinaries         *bool `json:",omitempty"`
135	Binder32bit                *bool `json:",omitempty"`
136	UseGoma                    *bool `json:",omitempty"`
137	Debuggable                 *bool `json:",omitempty"`
138	Eng                        *bool `json:",omitempty"`
139	EnableCFI                  *bool `json:",omitempty"`
140	Device_uses_hwc2           *bool `json:",omitempty"`
141	Treble                     *bool `json:",omitempty"`
142	Pdk                        *bool `json:",omitempty"`
143
144	IntegerOverflowExcludePaths *[]string `json:",omitempty"`
145
146	VendorPath *string `json:",omitempty"`
147
148	ClangTidy  *bool   `json:",omitempty"`
149	TidyChecks *string `json:",omitempty"`
150
151	NativeCoverage       *bool     `json:",omitempty"`
152	CoveragePaths        *[]string `json:",omitempty"`
153	CoverageExcludePaths *[]string `json:",omitempty"`
154
155	DevicePrefer32BitExecutables *bool `json:",omitempty"`
156	HostPrefer32BitExecutables   *bool `json:",omitempty"`
157
158	SanitizeHost       []string `json:",omitempty"`
159	SanitizeDevice     []string `json:",omitempty"`
160	SanitizeDeviceDiag []string `json:",omitempty"`
161	SanitizeDeviceArch []string `json:",omitempty"`
162
163	ArtUseReadBarrier *bool `json:",omitempty"`
164
165	BtConfigIncludeDir *string `json:",omitempty"`
166
167	Override_rs_driver *string `json:",omitempty"`
168
169	DeviceKernelHeaders []string `json:",omitempty"`
170}
171
172func boolPtr(v bool) *bool {
173	return &v
174}
175
176func intPtr(v int) *int {
177	return &v
178}
179
180func stringPtr(v string) *string {
181	return &v
182}
183
184func (v *productVariables) SetDefaultConfig() {
185	*v = productVariables{
186		Platform_sdk_version:       intPtr(24),
187		HostArch:                   stringPtr("x86_64"),
188		HostSecondaryArch:          stringPtr("x86"),
189		DeviceName:                 stringPtr("flounder"),
190		DeviceArch:                 stringPtr("arm64"),
191		DeviceArchVariant:          stringPtr("armv8-a"),
192		DeviceCpuVariant:           stringPtr("denver64"),
193		DeviceAbi:                  &[]string{"arm64-v8a"},
194		DeviceUsesClang:            boolPtr(true),
195		DeviceSecondaryArch:        stringPtr("arm"),
196		DeviceSecondaryArchVariant: stringPtr("armv7-a-neon"),
197		DeviceSecondaryCpuVariant:  stringPtr("denver"),
198		DeviceSecondaryAbi:         &[]string{"armeabi-v7a"},
199		Malloc_not_svelte:          boolPtr(false),
200		Safestack:                  boolPtr(false),
201	}
202
203	if runtime.GOOS == "linux" {
204		v.CrossHost = stringPtr("windows")
205		v.CrossHostArch = stringPtr("x86")
206		v.CrossHostSecondaryArch = stringPtr("x86_64")
207	}
208}
209
210func variableMutator(mctx BottomUpMutatorContext) {
211	var module Module
212	var ok bool
213	if module, ok = mctx.Module().(Module); !ok {
214		return
215	}
216
217	// TODO: depend on config variable, create variants, propagate variants up tree
218	a := module.base()
219	variableValues := reflect.ValueOf(&a.variableProperties.Product_variables).Elem()
220	zeroValues := reflect.ValueOf(zeroProductVariables.Product_variables)
221
222	for i := 0; i < variableValues.NumField(); i++ {
223		variableValue := variableValues.Field(i)
224		zeroValue := zeroValues.Field(i)
225		name := variableValues.Type().Field(i).Name
226		property := "product_variables." + proptools.PropertyNameForField(name)
227
228		// Check that the variable was set for the product
229		val := reflect.ValueOf(mctx.Config().(Config).ProductVariables).FieldByName(name)
230		if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() {
231			continue
232		}
233
234		val = val.Elem()
235
236		// For bools, check that the value is true
237		if val.Kind() == reflect.Bool && val.Bool() == false {
238			continue
239		}
240
241		// Check if any properties were set for the module
242		if reflect.DeepEqual(variableValue.Interface(), zeroValue.Interface()) {
243			continue
244		}
245
246		a.setVariableProperties(mctx, property, variableValue, val.Interface())
247	}
248}
249
250func (a *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext,
251	prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) {
252
253	printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue)
254
255	err := proptools.AppendMatchingProperties(a.generalProperties,
256		productVariablePropertyValue.Addr().Interface(), nil)
257	if err != nil {
258		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
259			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
260		} else {
261			panic(err)
262		}
263	}
264}
265
266func printfIntoPropertiesError(ctx BottomUpMutatorContext, prefix string,
267	productVariablePropertyValue reflect.Value, i int, err error) {
268
269	field := productVariablePropertyValue.Type().Field(i).Name
270	property := prefix + "." + proptools.PropertyNameForField(field)
271	ctx.PropertyErrorf(property, "%s", err)
272}
273
274func printfIntoProperties(ctx BottomUpMutatorContext, prefix string,
275	productVariablePropertyValue reflect.Value, variableValue interface{}) {
276
277	for i := 0; i < productVariablePropertyValue.NumField(); i++ {
278		propertyValue := productVariablePropertyValue.Field(i)
279		kind := propertyValue.Kind()
280		if kind == reflect.Ptr {
281			if propertyValue.IsNil() {
282				continue
283			}
284			propertyValue = propertyValue.Elem()
285		}
286		switch propertyValue.Kind() {
287		case reflect.String:
288			err := printfIntoProperty(propertyValue, variableValue)
289			if err != nil {
290				printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err)
291			}
292		case reflect.Slice:
293			for j := 0; j < propertyValue.Len(); j++ {
294				err := printfIntoProperty(propertyValue.Index(j), variableValue)
295				if err != nil {
296					printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err)
297				}
298			}
299		case reflect.Bool:
300			// Nothing
301		case reflect.Struct:
302			printfIntoProperties(ctx, prefix, propertyValue, variableValue)
303		default:
304			panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind()))
305		}
306	}
307}
308
309func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) error {
310	s := propertyValue.String()
311
312	count := strings.Count(s, "%")
313	if count == 0 {
314		return nil
315	}
316
317	if count > 1 {
318		return fmt.Errorf("product variable properties only support a single '%%'")
319	}
320
321	if strings.Contains(s, "%d") {
322		switch v := variableValue.(type) {
323		case int:
324			// Nothing
325		case bool:
326			if v {
327				variableValue = 1
328			} else {
329				variableValue = 0
330			}
331		default:
332			return fmt.Errorf("unsupported type %T for %%d", variableValue)
333		}
334	} else if strings.Contains(s, "%s") {
335		switch variableValue.(type) {
336		case string:
337			// Nothing
338		default:
339			return fmt.Errorf("unsupported type %T for %%s", variableValue)
340		}
341	} else {
342		return fmt.Errorf("unsupported %% in product variable property")
343	}
344
345	propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, variableValue)))
346
347	return nil
348}
349