xref: /aosp_15_r20/build/soong/sdk/bp.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2019 The Android Open Source Project
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 sdk
16
17import (
18	"fmt"
19	"reflect"
20	"strings"
21
22	"android/soong/android"
23)
24
25type bpPropertySet struct {
26	properties map[string]interface{}
27	tags       map[string]android.BpPropertyTag
28	comments   map[string]string
29	order      []string
30}
31
32var _ android.BpPropertySet = (*bpPropertySet)(nil)
33
34func (s *bpPropertySet) init() {
35	s.properties = make(map[string]interface{})
36	s.tags = make(map[string]android.BpPropertyTag)
37}
38
39// Converts the given value, which is assumed to be a struct, to a
40// bpPropertySet.
41func convertToPropertySet(value reflect.Value) *bpPropertySet {
42	res := newPropertySet()
43	structType := value.Type()
44
45	for i := 0; i < structType.NumField(); i++ {
46		field := structType.Field(i)
47		fieldVal := value.Field(i)
48
49		switch fieldVal.Type().Kind() {
50		case reflect.Ptr:
51			if fieldVal.IsNil() {
52				continue // nil pointer means the property isn't set.
53			}
54			fieldVal = fieldVal.Elem()
55		case reflect.Slice:
56			if fieldVal.IsNil() {
57				continue // Ignore a nil slice (but not one with length zero).
58			}
59		}
60
61		if fieldVal.Type().Kind() == reflect.Struct {
62			fieldVal = fieldVal.Addr() // Avoid struct copy below.
63		}
64		res.AddProperty(strings.ToLower(field.Name), fieldVal.Interface())
65	}
66
67	return res
68}
69
70// Converts the given value to something that can be set in a property.
71func coercePropertyValue(value interface{}) interface{} {
72	val := reflect.ValueOf(value)
73	switch val.Kind() {
74	case reflect.Struct:
75		// convertToPropertySet requires an addressable struct, and this is probably
76		// a mistake.
77		panic(fmt.Sprintf("Value is a struct, not a pointer to one: %v", value))
78	case reflect.Ptr:
79		if _, ok := value.(*bpPropertySet); !ok {
80			derefValue := reflect.Indirect(val)
81			if derefValue.Kind() != reflect.Struct {
82				panic(fmt.Sprintf("A pointer must be to a struct, got: %v", value))
83			}
84			return convertToPropertySet(derefValue)
85		}
86	}
87	return value
88}
89
90// Merges the fields of the given property set into s.
91func (s *bpPropertySet) mergePropertySet(propSet *bpPropertySet) {
92	for _, name := range propSet.order {
93		if tag, ok := propSet.tags[name]; ok {
94			s.AddPropertyWithTag(name, propSet.properties[name], tag)
95		} else {
96			s.AddProperty(name, propSet.properties[name])
97		}
98	}
99}
100
101func (s *bpPropertySet) AddProperty(name string, value interface{}) {
102	value = coercePropertyValue(value)
103
104	if propSetValue, ok := value.(*bpPropertySet); ok {
105		if curValue, ok := s.properties[name]; ok {
106			if curSet, ok := curValue.(*bpPropertySet); ok {
107				curSet.mergePropertySet(propSetValue)
108				return
109			}
110			// If the current value isn't a property set we got conflicting types.
111			// Continue down to the check below to complain about it.
112		}
113	}
114
115	if s.properties[name] != nil {
116		panic(fmt.Sprintf("Property %q already exists in property set", name))
117	}
118
119	s.properties[name] = value
120	s.order = append(s.order, name)
121}
122
123func (s *bpPropertySet) AddPropertyWithTag(name string, value interface{}, tag android.BpPropertyTag) {
124	s.AddProperty(name, value)
125	s.tags[name] = tag
126}
127
128func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
129	s.AddProperty(name, newPropertySet())
130	return s.properties[name].(android.BpPropertySet)
131}
132
133func (s *bpPropertySet) getValue(name string) interface{} {
134	return s.properties[name]
135}
136
137func (s *bpPropertySet) getOptionalValue(name string) (interface{}, bool) {
138	value, ok := s.properties[name]
139	return value, ok
140}
141
142func (s *bpPropertySet) getTag(name string) interface{} {
143	return s.tags[name]
144}
145
146func (s *bpPropertySet) AddCommentForProperty(name, text string) {
147	if s.comments == nil {
148		s.comments = map[string]string{}
149	}
150	s.comments[name] = strings.TrimSpace(text)
151}
152
153func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
154	var newOrder []string
155	for _, name := range s.order {
156		value := s.properties[name]
157		tag := s.tags[name]
158		var newValue interface{}
159		var newTag android.BpPropertyTag
160		if propertySet, ok := value.(*bpPropertySet); ok {
161			var newPropertySet *bpPropertySet
162			newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
163			if newPropertySet == nil {
164				newValue = nil
165			} else {
166				newValue = newPropertySet
167			}
168		} else {
169			newValue, newTag = transformer.transformProperty(name, value, tag)
170		}
171
172		if newValue == nil {
173			// Delete the property from the map and exclude it from the new order.
174			delete(s.properties, name)
175		} else {
176			// Update the property in the map and add the name to the new order list.
177			s.properties[name] = newValue
178			s.tags[name] = newTag
179			newOrder = append(newOrder, name)
180		}
181	}
182	s.order = newOrder
183}
184
185func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
186	newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
187	if newPropertySet != nil {
188		newPropertySet.transformContents(transformer)
189
190		newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
191	}
192	return newPropertySet, newTag
193}
194
195func (s *bpPropertySet) setProperty(name string, value interface{}) {
196	if s.properties[name] == nil {
197		s.AddProperty(name, value)
198	} else {
199		s.properties[name] = value
200		s.tags[name] = nil
201	}
202}
203
204func (s *bpPropertySet) removeProperty(name string) {
205	delete(s.properties, name)
206	delete(s.tags, name)
207	_, s.order = android.RemoveFromList(name, s.order)
208}
209
210func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
211	if s.properties[name] != nil {
212		panic("Property %q already exists in property set")
213	}
214
215	// Add the name to the end of the order, to ensure it has necessary capacity
216	// and to handle the case when the position does not exist.
217	s.order = append(s.order, name)
218
219	// Search through the order for the item that matches supplied position. If
220	// found then insert the name of the new property after it.
221	for i, v := range s.order {
222		if v == position {
223			// Copy the items after the one where the new property should be inserted.
224			copy(s.order[i+2:], s.order[i+1:])
225			// Insert the item in the list.
226			s.order[i+1] = name
227		}
228	}
229
230	s.properties[name] = value
231}
232
233type bpModule struct {
234	*bpPropertySet
235	moduleType string
236}
237
238func (m *bpModule) ModuleType() string {
239	return m.moduleType
240}
241
242func (m *bpModule) Name() string {
243	name, hasName := m.getOptionalValue("name")
244	if hasName {
245		return name.(string)
246	} else {
247		return ""
248	}
249}
250
251var _ android.BpModule = (*bpModule)(nil)
252
253type bpPropertyTransformer interface {
254	// Transform the property set, returning the new property set/tag to insert back into the
255	// parent property set (or module if this is the top level property set).
256	//
257	// This will be called before transforming the properties in the supplied set.
258	//
259	// The name will be "" for the top level property set.
260	//
261	// Returning (nil, ...) will cause the property set to be removed.
262	transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
263
264	// Transform the property set, returning the new property set/tag to insert back into the
265	// parent property set (or module if this is the top level property set).
266	//
267	// This will be called after transforming the properties in the supplied set.
268	//
269	// The name will be "" for the top level property set.
270	//
271	// Returning (nil, ...) will cause the property set to be removed.
272	transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
273
274	// Transform a property, return the new value/tag to insert back into the property set.
275	//
276	// Returning (nil, ...) will cause the property to be removed.
277	transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag)
278}
279
280// Interface for transforming bpModule objects.
281type bpTransformer interface {
282	// Transform the module, returning the result.
283	//
284	// The method can either create a new module and return that, or modify the supplied module
285	// in place and return that.
286	//
287	// After this returns the transformer is applied to the contents of the returned module.
288	transformModule(module *bpModule) *bpModule
289
290	bpPropertyTransformer
291}
292
293type identityTransformation struct{}
294
295var _ bpTransformer = (*identityTransformation)(nil)
296
297func (t identityTransformation) transformModule(module *bpModule) *bpModule {
298	return module
299}
300
301func (t identityTransformation) transformPropertySetBeforeContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
302	return propertySet, tag
303}
304
305func (t identityTransformation) transformPropertySetAfterContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
306	return propertySet, tag
307}
308
309func (t identityTransformation) transformProperty(_ string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
310	return value, tag
311}
312
313func (m *bpModule) deepCopy() *bpModule {
314	return transformModule(m, deepCopyTransformer)
315}
316
317func transformModule(m *bpModule, transformer bpTransformer) *bpModule {
318	transformedModule := transformer.transformModule(m)
319	if transformedModule != nil {
320		// Copy the contents of the returned property set into the module and then transform that.
321		transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
322	}
323	return transformedModule
324}
325
326type deepCopyTransformation struct {
327	identityTransformation
328}
329
330func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
331	// Take a shallow copy of the module. Any mutable property values will be copied by the
332	// transformer.
333	moduleCopy := *module
334	return &moduleCopy
335}
336
337func (t deepCopyTransformation) transformPropertySetBeforeContents(_ string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
338	// Create a shallow copy of the properties map. Any mutable property values will be copied by the
339	// transformer.
340	propertiesCopy := make(map[string]interface{})
341	for propertyName, value := range propertySet.properties {
342		propertiesCopy[propertyName] = value
343	}
344
345	// Ditto for tags map.
346	tagsCopy := make(map[string]android.BpPropertyTag)
347	for propertyName, propertyTag := range propertySet.tags {
348		tagsCopy[propertyName] = propertyTag
349	}
350
351	// Create a new property set.
352	return &bpPropertySet{
353		properties: propertiesCopy,
354		tags:       tagsCopy,
355		order:      append([]string(nil), propertySet.order...),
356	}, tag
357}
358
359func (t deepCopyTransformation) transformProperty(_ string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
360	// Copy string slice, otherwise return value.
361	if values, ok := value.([]string); ok {
362		valuesCopy := make([]string, len(values))
363		copy(valuesCopy, values)
364		return valuesCopy, tag
365	}
366	return value, tag
367}
368
369var deepCopyTransformer bpTransformer = deepCopyTransformation{}
370
371// A .bp file
372type bpFile struct {
373	modules map[string]*bpModule
374	order   []*bpModule
375}
376
377// AddModule adds a module to this.
378//
379// The module must have had its "name" property set to a string value that
380// is unique within this file.
381func (f *bpFile) AddModule(module android.BpModule) {
382	m := module.(*bpModule)
383	moduleType := module.ModuleType()
384	name := m.Name()
385	hasName := true
386	if name == "" {
387		// Use a prefixed module type as the name instead just in case this is something like a package
388		// of namespace module which does not require a name.
389		name = "#" + moduleType
390		hasName = false
391	}
392
393	if f.modules[name] != nil {
394		if hasName {
395			panic(fmt.Sprintf("Module %q already exists in bp file", name))
396		} else {
397			panic(fmt.Sprintf("Unnamed module type %q already exists in bp file", moduleType))
398		}
399	}
400
401	f.modules[name] = m
402	f.order = append(f.order, m)
403}
404
405func (f *bpFile) newModule(moduleType string) *bpModule {
406	return newModule(moduleType)
407}
408
409func newModule(moduleType string) *bpModule {
410	module := &bpModule{
411		moduleType:    moduleType,
412		bpPropertySet: newPropertySet(),
413	}
414	return module
415}
416
417func newPropertySet() *bpPropertySet {
418	set := &bpPropertySet{}
419	set.init()
420	return set
421}
422