blob: 90b49eb192d63970e7b2c387ebb0c3eec77fda8f [file] [log] [blame]
Colin Cross9d34f352019-11-22 16:03:51 -08001// Copyright 2019 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
17// This file provides module types that implement wrapper module types that add conditionals on
18// Soong config variables.
19
20import (
21 "fmt"
22 "path/filepath"
Paul Duffine8b47682023-01-09 15:42:57 +000023 "reflect"
Colin Cross9d34f352019-11-22 16:03:51 -080024 "strings"
Paul Duffine8b47682023-01-09 15:42:57 +000025 "sync"
Colin Cross9d34f352019-11-22 16:03:51 -080026 "text/scanner"
27
28 "github.com/google/blueprint"
29 "github.com/google/blueprint/parser"
30 "github.com/google/blueprint/proptools"
31
32 "android/soong/android/soongconfig"
33)
34
35func init() {
Paul Duffin32299982023-01-09 14:02:06 +000036 RegisterSoongConfigModuleBuildComponents(InitRegistrationContext)
Colin Cross9d34f352019-11-22 16:03:51 -080037}
38
Paul Duffin32299982023-01-09 14:02:06 +000039func RegisterSoongConfigModuleBuildComponents(ctx RegistrationContext) {
40 ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
41 ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
42 ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
43 ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
Cole Faust97494b12024-01-12 14:02:47 -080044 ctx.RegisterModuleType("soong_config_value_variable", SoongConfigValueVariableDummyFactory)
Paul Duffin32299982023-01-09 14:02:06 +000045}
46
47var PrepareForTestWithSoongConfigModuleBuildComponents = FixtureRegisterWithContext(RegisterSoongConfigModuleBuildComponents)
48
Colin Cross9d34f352019-11-22 16:03:51 -080049type soongConfigModuleTypeImport struct {
50 ModuleBase
51 properties soongConfigModuleTypeImportProperties
52}
53
54type soongConfigModuleTypeImportProperties struct {
55 From string
56 Module_types []string
57}
58
59// soong_config_module_type_import imports module types with conditionals on Soong config
60// variables from another Android.bp file. The imported module type will exist for all
61// modules after the import in the Android.bp file.
62//
Liz Kammer432bd592020-12-16 12:42:02 -080063// Each soong_config_variable supports an additional value `conditions_default`. The properties
64// specified in `conditions_default` will only be used under the following conditions:
65// bool variable: the variable is unspecified or not set to a true value
66// value variable: the variable is unspecified
67// string variable: the variable is unspecified or the variable is set to a string unused in the
68// given module. For example, string variable `test` takes values: "a" and "b",
69// if the module contains a property `a` and `conditions_default`, when test=b,
70// the properties under `conditions_default` will be used. To specify that no
71// properties should be amended for `b`, you can set `b: {},`.
72//
Colin Cross9d34f352019-11-22 16:03:51 -080073// For example, an Android.bp file could have:
74//
75// soong_config_module_type_import {
Bill Peckhamc93258b2020-02-04 13:17:24 -080076// from: "device/acme/Android.bp",
Colin Cross9d34f352019-11-22 16:03:51 -080077// module_types: ["acme_cc_defaults"],
78// }
79//
80// acme_cc_defaults {
81// name: "acme_defaults",
82// cflags: ["-DGENERIC"],
83// soong_config_variables: {
84// board: {
85// soc_a: {
86// cflags: ["-DSOC_A"],
87// },
88// soc_b: {
89// cflags: ["-DSOC_B"],
90// },
Liz Kammer432bd592020-12-16 12:42:02 -080091// conditions_default: {
92// cflags: ["-DSOC_DEFAULT"],
93// },
Colin Cross9d34f352019-11-22 16:03:51 -080094// },
95// feature: {
96// cflags: ["-DFEATURE"],
Liz Kammer432bd592020-12-16 12:42:02 -080097// conditions_default: {
98// cflags: ["-DFEATURE_DEFAULT"],
99// },
Colin Cross9d34f352019-11-22 16:03:51 -0800100// },
Dan Willemsenb0935db2020-03-23 19:42:18 -0700101// width: {
102// cflags: ["-DWIDTH=%s"],
Liz Kammer432bd592020-12-16 12:42:02 -0800103// conditions_default: {
104// cflags: ["-DWIDTH=DEFAULT"],
105// },
Dan Willemsenb0935db2020-03-23 19:42:18 -0700106// },
Colin Cross9d34f352019-11-22 16:03:51 -0800107// },
108// }
109//
110// cc_library {
111// name: "libacme_foo",
112// defaults: ["acme_defaults"],
113// srcs: ["*.cpp"],
114// }
115//
116// And device/acme/Android.bp could have:
117//
118// soong_config_module_type {
119// name: "acme_cc_defaults",
120// module_type: "cc_defaults",
121// config_namespace: "acme",
Dan Willemsen2b8b89c2020-03-23 19:39:34 -0700122// variables: ["board"],
123// bool_variables: ["feature"],
Dan Willemsenb0935db2020-03-23 19:42:18 -0700124// value_variables: ["width"],
Colin Cross9d34f352019-11-22 16:03:51 -0800125// properties: ["cflags", "srcs"],
126// }
127//
128// soong_config_string_variable {
129// name: "board",
Liz Kammer432bd592020-12-16 12:42:02 -0800130// values: ["soc_a", "soc_b", "soc_c"],
Colin Cross9d34f352019-11-22 16:03:51 -0800131// }
132//
Colin Cross9d34f352019-11-22 16:03:51 -0800133// If an acme BoardConfig.mk file contained:
Sasha Smundak18fd0992021-08-24 14:05:19 -0700134// $(call add_sonng_config_namespace, acme)
135// $(call add_soong_config_var_value, acme, board, soc_a)
136// $(call add_soong_config_var_value, acme, feature, true)
137// $(call add_soong_config_var_value, acme, width, 200)
Colin Cross9d34f352019-11-22 16:03:51 -0800138//
Dan Willemsenb0935db2020-03-23 19:42:18 -0700139// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
Liz Kammer432bd592020-12-16 12:42:02 -0800140//
141// Alternatively, if acme BoardConfig.mk file contained:
142//
143// SOONG_CONFIG_NAMESPACES += acme
144// SOONG_CONFIG_acme += \
145// board \
146// feature \
147//
148// SOONG_CONFIG_acme_feature := false
149//
150// Then libacme_foo would build with cflags:
151// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
152//
153// Similarly, if acme BoardConfig.mk file contained:
154//
155// SOONG_CONFIG_NAMESPACES += acme
156// SOONG_CONFIG_acme += \
157// board \
158// feature \
159//
160// SOONG_CONFIG_acme_board := soc_c
161//
162// Then libacme_foo would build with cflags:
163// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
164
Jingwen Chena47f28d2021-11-02 16:43:57 +0000165func SoongConfigModuleTypeImportFactory() Module {
Colin Cross9d34f352019-11-22 16:03:51 -0800166 module := &soongConfigModuleTypeImport{}
167
168 module.AddProperties(&module.properties)
169 AddLoadHook(module, func(ctx LoadHookContext) {
170 importModuleTypes(ctx, module.properties.From, module.properties.Module_types...)
171 })
172
173 initAndroidModuleBase(module)
174 return module
175}
176
177func (m *soongConfigModuleTypeImport) Name() string {
Sasha Smundak116ec922020-03-10 16:10:06 -0700178 // The generated name is non-deterministic, but it does not
179 // matter because this module does not emit any rules.
180 return soongconfig.CanonicalizeToProperty(m.properties.From) +
181 "soong_config_module_type_import_" + fmt.Sprintf("%p", m)
Colin Cross9d34f352019-11-22 16:03:51 -0800182}
183
Colin Crossa6389e92022-06-22 16:44:07 -0700184func (*soongConfigModuleTypeImport) Namespaceless() {}
Colin Cross9d34f352019-11-22 16:03:51 -0800185func (*soongConfigModuleTypeImport) GenerateAndroidBuildActions(ModuleContext) {}
186
187// Create dummy modules for soong_config_module_type and soong_config_*_variable
188
189type soongConfigModuleTypeModule struct {
190 ModuleBase
191 properties soongconfig.ModuleTypeProperties
192}
193
194// soong_config_module_type defines module types with conditionals on Soong config
Bill Peckhamc93258b2020-02-04 13:17:24 -0800195// variables. The new module type will exist for all modules after the definition
196// in an Android.bp file, and can be imported into other Android.bp files using
197// soong_config_module_type_import.
Colin Cross9d34f352019-11-22 16:03:51 -0800198//
Liz Kammer432bd592020-12-16 12:42:02 -0800199// Each soong_config_variable supports an additional value `conditions_default`. The properties
200// specified in `conditions_default` will only be used under the following conditions:
Colin Crossd079e0b2022-08-16 10:27:33 -0700201//
202// bool variable: the variable is unspecified or not set to a true value
203// value variable: the variable is unspecified
204// string variable: the variable is unspecified or the variable is set to a string unused in the
205// given module. For example, string variable `test` takes values: "a" and "b",
206// if the module contains a property `a` and `conditions_default`, when test=b,
207// the properties under `conditions_default` will be used. To specify that no
208// properties should be amended for `b`, you can set `b: {},`.
Liz Kammer432bd592020-12-16 12:42:02 -0800209//
Colin Cross9d34f352019-11-22 16:03:51 -0800210// For example, an Android.bp file could have:
211//
Colin Crossd079e0b2022-08-16 10:27:33 -0700212// soong_config_module_type {
213// name: "acme_cc_defaults",
214// module_type: "cc_defaults",
215// config_namespace: "acme",
216// variables: ["board"],
217// bool_variables: ["feature"],
218// value_variables: ["width"],
219// properties: ["cflags", "srcs"],
220// }
Colin Cross9d34f352019-11-22 16:03:51 -0800221//
Colin Crossd079e0b2022-08-16 10:27:33 -0700222// soong_config_string_variable {
223// name: "board",
224// values: ["soc_a", "soc_b"],
225// }
Colin Cross9d34f352019-11-22 16:03:51 -0800226//
Colin Crossd079e0b2022-08-16 10:27:33 -0700227// acme_cc_defaults {
228// name: "acme_defaults",
229// cflags: ["-DGENERIC"],
230// soong_config_variables: {
231// board: {
232// soc_a: {
233// cflags: ["-DSOC_A"],
234// },
235// soc_b: {
236// cflags: ["-DSOC_B"],
237// },
238// conditions_default: {
239// cflags: ["-DSOC_DEFAULT"],
240// },
241// },
242// feature: {
243// cflags: ["-DFEATURE"],
244// conditions_default: {
245// cflags: ["-DFEATURE_DEFAULT"],
246// },
247// },
248// width: {
249// cflags: ["-DWIDTH=%s"],
250// conditions_default: {
251// cflags: ["-DWIDTH=DEFAULT"],
252// },
253// },
254// },
255// }
Colin Cross9d34f352019-11-22 16:03:51 -0800256//
Colin Crossd079e0b2022-08-16 10:27:33 -0700257// cc_library {
258// name: "libacme_foo",
259// defaults: ["acme_defaults"],
260// srcs: ["*.cpp"],
261// }
Colin Cross9d34f352019-11-22 16:03:51 -0800262//
Colin Cross9d34f352019-11-22 16:03:51 -0800263// If an acme BoardConfig.mk file contained:
264//
Colin Crossd079e0b2022-08-16 10:27:33 -0700265// SOONG_CONFIG_NAMESPACES += acme
266// SOONG_CONFIG_acme += \
267// board \
268// feature \
Colin Cross9d34f352019-11-22 16:03:51 -0800269//
Colin Crossd079e0b2022-08-16 10:27:33 -0700270// SOONG_CONFIG_acme_board := soc_a
271// SOONG_CONFIG_acme_feature := true
272// SOONG_CONFIG_acme_width := 200
Colin Cross9d34f352019-11-22 16:03:51 -0800273//
274// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
Jingwen Chena47f28d2021-11-02 16:43:57 +0000275func SoongConfigModuleTypeFactory() Module {
Colin Cross9d34f352019-11-22 16:03:51 -0800276 module := &soongConfigModuleTypeModule{}
277
278 module.AddProperties(&module.properties)
279
280 AddLoadHook(module, func(ctx LoadHookContext) {
281 // A soong_config_module_type module should implicitly import itself.
282 importModuleTypes(ctx, ctx.BlueprintsFile(), module.properties.Name)
283 })
284
285 initAndroidModuleBase(module)
286
287 return module
288}
289
290func (m *soongConfigModuleTypeModule) Name() string {
Colin Crossa6389e92022-06-22 16:44:07 -0700291 return m.properties.Name + fmt.Sprintf("%p", m)
Colin Cross9d34f352019-11-22 16:03:51 -0800292}
Colin Crossa6389e92022-06-22 16:44:07 -0700293func (*soongConfigModuleTypeModule) Namespaceless() {}
Colin Cross9d34f352019-11-22 16:03:51 -0800294func (*soongConfigModuleTypeModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
295
296type soongConfigStringVariableDummyModule struct {
297 ModuleBase
298 properties soongconfig.VariableProperties
299 stringProperties soongconfig.StringVariableProperties
300}
301
302type soongConfigBoolVariableDummyModule struct {
303 ModuleBase
304 properties soongconfig.VariableProperties
305}
306
Cole Faust97494b12024-01-12 14:02:47 -0800307type soongConfigValueVariableDummyModule struct {
308 ModuleBase
309 properties soongconfig.VariableProperties
310}
311
Colin Cross9d34f352019-11-22 16:03:51 -0800312// soong_config_string_variable defines a variable and a set of possible string values for use
313// in a soong_config_module_type definition.
Jingwen Chena47f28d2021-11-02 16:43:57 +0000314func SoongConfigStringVariableDummyFactory() Module {
Colin Cross9d34f352019-11-22 16:03:51 -0800315 module := &soongConfigStringVariableDummyModule{}
316 module.AddProperties(&module.properties, &module.stringProperties)
317 initAndroidModuleBase(module)
318 return module
319}
320
321// soong_config_string_variable defines a variable with true or false values for use
322// in a soong_config_module_type definition.
Jingwen Chena47f28d2021-11-02 16:43:57 +0000323func SoongConfigBoolVariableDummyFactory() Module {
Colin Cross9d34f352019-11-22 16:03:51 -0800324 module := &soongConfigBoolVariableDummyModule{}
325 module.AddProperties(&module.properties)
326 initAndroidModuleBase(module)
327 return module
328}
329
Cole Faust97494b12024-01-12 14:02:47 -0800330// soong_config_value_variable defines a variable whose value can be expanded into
331// the value of a string property.
332func SoongConfigValueVariableDummyFactory() Module {
333 module := &soongConfigValueVariableDummyModule{}
334 module.AddProperties(&module.properties)
335 initAndroidModuleBase(module)
336 return module
337}
338
Colin Cross9d34f352019-11-22 16:03:51 -0800339func (m *soongConfigStringVariableDummyModule) Name() string {
Colin Crossa6389e92022-06-22 16:44:07 -0700340 return m.properties.Name + fmt.Sprintf("%p", m)
Colin Cross9d34f352019-11-22 16:03:51 -0800341}
Colin Crossa6389e92022-06-22 16:44:07 -0700342func (*soongConfigStringVariableDummyModule) Namespaceless() {}
Colin Cross9d34f352019-11-22 16:03:51 -0800343func (*soongConfigStringVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
344
345func (m *soongConfigBoolVariableDummyModule) Name() string {
Colin Crossa6389e92022-06-22 16:44:07 -0700346 return m.properties.Name + fmt.Sprintf("%p", m)
Colin Cross9d34f352019-11-22 16:03:51 -0800347}
Colin Crossa6389e92022-06-22 16:44:07 -0700348func (*soongConfigBoolVariableDummyModule) Namespaceless() {}
Colin Cross9d34f352019-11-22 16:03:51 -0800349func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
350
Cole Faust97494b12024-01-12 14:02:47 -0800351func (m *soongConfigValueVariableDummyModule) Name() string {
352 return m.properties.Name + fmt.Sprintf("%p", m)
353}
354func (*soongConfigValueVariableDummyModule) Namespaceless() {}
355func (*soongConfigValueVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
356
Jingwen Chena47f28d2021-11-02 16:43:57 +0000357// importModuleTypes registers the module factories for a list of module types defined
358// in an Android.bp file. These module factories are scoped for the current Android.bp
359// file only.
Colin Cross9d34f352019-11-22 16:03:51 -0800360func importModuleTypes(ctx LoadHookContext, from string, moduleTypes ...string) {
361 from = filepath.Clean(from)
362 if filepath.Ext(from) != ".bp" {
363 ctx.PropertyErrorf("from", "%q must be a file with extension .bp", from)
364 return
365 }
366
367 if strings.HasPrefix(from, "../") {
368 ctx.PropertyErrorf("from", "%q must not use ../ to escape the source tree",
369 from)
370 return
371 }
372
373 moduleTypeDefinitions := loadSoongConfigModuleTypeDefinition(ctx, from)
374 if moduleTypeDefinitions == nil {
375 return
376 }
377 for _, moduleType := range moduleTypes {
378 if factory, ok := moduleTypeDefinitions[moduleType]; ok {
379 ctx.registerScopedModuleType(moduleType, factory)
380 } else {
381 ctx.PropertyErrorf("module_types", "module type %q not defined in %q",
382 moduleType, from)
383 }
384 }
385}
386
387// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
388// result so each file is only parsed once.
389func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[string]blueprint.ModuleFactory {
390 type onceKeyType string
391 key := NewCustomOnceKey(onceKeyType(filepath.Clean(from)))
392
393 reportErrors := func(ctx LoadHookContext, filename string, errs ...error) {
394 for _, err := range errs {
395 if parseErr, ok := err.(*parser.ParseError); ok {
396 ctx.Errorf(parseErr.Pos, "%s", parseErr.Err)
397 } else {
398 ctx.Errorf(scanner.Position{Filename: filename}, "%s", err)
399 }
400 }
401 }
402
403 return ctx.Config().Once(key, func() interface{} {
Colin Cross39e545c2020-02-05 16:26:19 -0800404 ctx.AddNinjaFileDeps(from)
Colin Cross9d34f352019-11-22 16:03:51 -0800405 r, err := ctx.Config().fs.Open(from)
406 if err != nil {
407 ctx.PropertyErrorf("from", "failed to open %q: %s", from, err)
408 return (map[string]blueprint.ModuleFactory)(nil)
409 }
Liz Kammer0fe123d2022-02-07 10:17:35 -0500410 defer r.Close()
Colin Cross9d34f352019-11-22 16:03:51 -0800411
412 mtDef, errs := soongconfig.Parse(r, from)
Colin Cross9d34f352019-11-22 16:03:51 -0800413 if len(errs) > 0 {
414 reportErrors(ctx, from, errs...)
415 return (map[string]blueprint.ModuleFactory)(nil)
416 }
417
418 globalModuleTypes := ctx.moduleFactories()
419
420 factories := make(map[string]blueprint.ModuleFactory)
421
422 for name, moduleType := range mtDef.ModuleTypes {
423 factory := globalModuleTypes[moduleType.BaseModuleType]
424 if factory != nil {
Colin Cross8ff10582023-12-07 13:10:56 -0800425 factories[name] = configModuleFactory(factory, moduleType)
Colin Cross9d34f352019-11-22 16:03:51 -0800426 } else {
427 reportErrors(ctx, from,
428 fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
429 }
430 }
431
432 if ctx.Failed() {
433 return (map[string]blueprint.ModuleFactory)(nil)
434 }
435
436 return factories
437 }).(map[string]blueprint.ModuleFactory)
438}
439
Inseob Kim81b00a82023-05-15 18:06:31 +0900440// tracingConfig is a wrapper to soongconfig.SoongConfig which records all accesses to SoongConfig.
441type tracingConfig struct {
442 config soongconfig.SoongConfig
443 boolSet map[string]bool
444 stringSet map[string]string
445 isSetSet map[string]bool
446}
447
448func (c *tracingConfig) Bool(name string) bool {
449 c.boolSet[name] = c.config.Bool(name)
450 return c.boolSet[name]
451}
452
453func (c *tracingConfig) String(name string) string {
454 c.stringSet[name] = c.config.String(name)
455 return c.stringSet[name]
456}
457
458func (c *tracingConfig) IsSet(name string) bool {
459 c.isSetSet[name] = c.config.IsSet(name)
460 return c.isSetSet[name]
461}
462
463func (c *tracingConfig) getTrace() soongConfigTrace {
464 ret := soongConfigTrace{}
465
466 for k, v := range c.boolSet {
467 ret.Bools = append(ret.Bools, fmt.Sprintf("%q:%t", k, v))
468 }
469 for k, v := range c.stringSet {
470 ret.Strings = append(ret.Strings, fmt.Sprintf("%q:%q", k, v))
471 }
472 for k, v := range c.isSetSet {
473 ret.IsSets = append(ret.IsSets, fmt.Sprintf("%q:%t", k, v))
474 }
475
476 return ret
477}
478
479func newTracingConfig(config soongconfig.SoongConfig) *tracingConfig {
480 c := tracingConfig{
481 config: config,
482 boolSet: make(map[string]bool),
483 stringSet: make(map[string]string),
484 isSetSet: make(map[string]bool),
485 }
486 return &c
487}
488
489var _ soongconfig.SoongConfig = (*tracingConfig)(nil)
490
Jingwen Chena47f28d2021-11-02 16:43:57 +0000491// configModuleFactory takes an existing soongConfigModuleFactory and a
492// ModuleType to create a new ModuleFactory that uses a custom loadhook.
Colin Cross8ff10582023-12-07 13:10:56 -0800493func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
Paul Duffine8b47682023-01-09 15:42:57 +0000494 // Defer creation of conditional properties struct until the first call from the factory
495 // method. That avoids having to make a special call to the factory to create the properties
496 // structs from which the conditional properties struct is created. This is needed in order to
497 // allow singleton modules to be customized by soong_config_module_type as the
498 // SingletonModuleFactoryAdaptor factory registers a load hook for the singleton module
499 // everytime that it is called. Calling the factory twice causes a build failure as the load
500 // hook is called twice, the first time it updates the singleton module to indicate that it has
501 // been registered as a module, and the second time it fails because it thinks it has been
502 // registered again and a singleton module can only be registered once.
503 //
504 // This is an issue for singleton modules because:
505 // * Load hooks are registered on the module object and are only called when the module object
506 // is created by Blueprint while processing the Android.bp file.
507 // * The module factory for a singleton module returns the same module object each time it is
508 // called, and registers its load hook on that same module object.
509 // * When the module factory is called by Blueprint it then calls all the load hooks that have
510 // been registered for every call to that module factory.
511 //
512 // It is not an issue for normal modules because they return a new module object each time the
513 // factory is called and so any load hooks registered on module objects which are discarded will
514 // not be run.
515 once := &sync.Once{}
516 conditionalFactoryProps := reflect.Value{}
517 getConditionalFactoryProps := func(props []interface{}) reflect.Value {
518 once.Do(func() {
519 conditionalFactoryProps = soongconfig.CreateProperties(props, moduleType)
520 })
521 return conditionalFactoryProps
Jingwen Chena47f28d2021-11-02 16:43:57 +0000522 }
Colin Cross9d34f352019-11-22 16:03:51 -0800523
Jingwen Chena47f28d2021-11-02 16:43:57 +0000524 return func() (blueprint.Module, []interface{}) {
525 module, props := factory()
Paul Duffine8b47682023-01-09 15:42:57 +0000526 conditionalFactoryProps := getConditionalFactoryProps(props)
527 if !conditionalFactoryProps.IsValid() {
528 return module, props
529 }
530
Jingwen Chena47f28d2021-11-02 16:43:57 +0000531 conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
532 props = append(props, conditionalProps.Interface())
Colin Cross9d34f352019-11-22 16:03:51 -0800533
Colin Cross8ff10582023-12-07 13:10:56 -0800534 // Regular Soong operation wraps the existing module factory with a
535 // conditional on Soong config variables by reading the product
536 // config variables from Make.
537 AddLoadHook(module, func(ctx LoadHookContext) {
538 tracingConfig := newTracingConfig(ctx.Config().VendorConfig(moduleType.ConfigNamespace))
539 newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, tracingConfig)
540 if err != nil {
541 ctx.ModuleErrorf("%s", err)
542 return
543 }
544 for _, ps := range newProps {
545 ctx.AppendProperties(ps)
546 }
Inseob Kim81b00a82023-05-15 18:06:31 +0900547
Colin Cross8ff10582023-12-07 13:10:56 -0800548 module.(Module).base().commonProperties.SoongConfigTrace = tracingConfig.getTrace()
549 })
Jingwen Chena47f28d2021-11-02 16:43:57 +0000550 return module, props
Colin Cross9d34f352019-11-22 16:03:51 -0800551 }
552}