bp2build: add support for soong_config_module_type.
Test: CI, go unit test Bug: 198556411 Change-Id: Idf862904d51d822f92af0c072341c31b7a02fc64
This commit is contained in:
parent
925942127a
commit
a47f28d28e
16 changed files with 710 additions and 96 deletions
|
@ -15,6 +15,7 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"android/soong/bazel"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
@ -24,34 +25,33 @@ import (
|
|||
"github.com/google/blueprint/proptools"
|
||||
)
|
||||
|
||||
type bazelModuleProperties struct {
|
||||
// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
|
||||
// will import the handcrafted build target into the autogenerated file. Note: this may result in
|
||||
// a conflict due to duplicate targets if bp2build_available is also set.
|
||||
Label *string
|
||||
|
||||
// If true, bp2build will generate the converted Bazel target for this module. Note: this may
|
||||
// cause a conflict due to the duplicate targets if label is also set.
|
||||
//
|
||||
// This is a bool pointer to support tristates: true, false, not set.
|
||||
//
|
||||
// To opt-in a module, set bazel_module: { bp2build_available: true }
|
||||
// To opt-out a module, set bazel_module: { bp2build_available: false }
|
||||
// To defer the default setting for the directory, do not set the value.
|
||||
Bp2build_available *bool
|
||||
}
|
||||
|
||||
// Properties contains common module properties for Bazel migration purposes.
|
||||
type properties struct {
|
||||
// In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
|
||||
// this Soong module.
|
||||
Bazel_module bazelModuleProperties
|
||||
Bazel_module bazel.BazelModuleProperties
|
||||
}
|
||||
|
||||
type namespacedVariableProperties map[string]interface{}
|
||||
|
||||
// BazelModuleBase contains the property structs with metadata for modules which can be converted to
|
||||
// Bazel.
|
||||
type BazelModuleBase struct {
|
||||
bazelProperties properties
|
||||
|
||||
// namespacedVariableProperties is used for soong_config_module_type support
|
||||
// in bp2build. Soong config modules allow users to set module properties
|
||||
// based on custom product variables defined in Android.bp files. These
|
||||
// variables are namespaced to prevent clobbering, especially when set from
|
||||
// Makefiles.
|
||||
namespacedVariableProperties namespacedVariableProperties
|
||||
|
||||
// baseModuleType is set when this module was created from a module type
|
||||
// defined by a soong_config_module_type. Every soong_config_module_type
|
||||
// "wraps" another module type, e.g. a soong_config_module_type can wrap a
|
||||
// cc_defaults to a custom_cc_defaults, or cc_binary to a custom_cc_binary.
|
||||
// This baseModuleType is set to the wrapped module type.
|
||||
baseModuleType string
|
||||
}
|
||||
|
||||
// Bazelable is specifies the interface for modules that can be converted to Bazel.
|
||||
|
@ -63,6 +63,12 @@ type Bazelable interface {
|
|||
ConvertWithBp2build(ctx BazelConversionContext) bool
|
||||
convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
|
||||
GetBazelBuildFileContents(c Config, path, name string) (string, error)
|
||||
|
||||
// For namespaced config variable support
|
||||
namespacedVariableProps() namespacedVariableProperties
|
||||
setNamespacedVariableProps(props namespacedVariableProperties)
|
||||
BaseModuleType() string
|
||||
SetBaseModuleType(string)
|
||||
}
|
||||
|
||||
// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
|
||||
|
@ -82,6 +88,22 @@ func (b *BazelModuleBase) bazelProps() *properties {
|
|||
return &b.bazelProperties
|
||||
}
|
||||
|
||||
func (b *BazelModuleBase) namespacedVariableProps() namespacedVariableProperties {
|
||||
return b.namespacedVariableProperties
|
||||
}
|
||||
|
||||
func (b *BazelModuleBase) setNamespacedVariableProps(props namespacedVariableProperties) {
|
||||
b.namespacedVariableProperties = props
|
||||
}
|
||||
|
||||
func (b *BazelModuleBase) BaseModuleType() string {
|
||||
return b.baseModuleType
|
||||
}
|
||||
|
||||
func (b *BazelModuleBase) SetBaseModuleType(baseModuleType string) {
|
||||
b.baseModuleType = baseModuleType
|
||||
}
|
||||
|
||||
// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
|
||||
func (b *BazelModuleBase) HasHandcraftedLabel() bool {
|
||||
return b.bazelProperties.Bazel_module.Label != nil
|
||||
|
@ -399,7 +421,15 @@ func (b *BazelModuleBase) convertWithBp2build(ctx BazelConversionContext, module
|
|||
// prevents mixed builds from using auto-converted modules just by matching
|
||||
// the package dir; it also has to have a bp2build mutator as well.
|
||||
if ctx.Config().bp2buildModuleTypeConfig[ctx.OtherModuleType(module)] == false {
|
||||
return false
|
||||
if b, ok := module.(Bazelable); ok && b.BaseModuleType() != "" {
|
||||
// For modules with custom types from soong_config_module_types,
|
||||
// check that their _base module type_ has a bp2build mutator.
|
||||
if ctx.Config().bp2buildModuleTypeConfig[b.BaseModuleType()] == false {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
packagePath := ctx.OtherModuleDir(module)
|
||||
|
|
|
@ -155,6 +155,7 @@ type config struct {
|
|||
fs pathtools.FileSystem
|
||||
mockBpList string
|
||||
|
||||
runningAsBp2Build bool
|
||||
bp2buildPackageConfig Bp2BuildConfig
|
||||
bp2buildModuleTypeConfig map[string]bool
|
||||
|
||||
|
|
|
@ -510,9 +510,9 @@ func registerTestPrebuiltModules(ctx RegistrationContext) {
|
|||
ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
|
||||
ctx.RegisterModuleType("source", newSourceModule)
|
||||
ctx.RegisterModuleType("override_source", newOverrideSourceModule)
|
||||
ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
|
||||
}
|
||||
|
||||
type prebuiltModule struct {
|
||||
|
|
|
@ -161,6 +161,10 @@ func NewContext(config Config) *Context {
|
|||
return ctx
|
||||
}
|
||||
|
||||
func (ctx *Context) SetRunningAsBp2build() {
|
||||
ctx.config.runningAsBp2Build = true
|
||||
}
|
||||
|
||||
// RegisterForBazelConversion registers an alternate shadow pipeline of
|
||||
// singletons, module types and mutators to register for converting Blueprint
|
||||
// files to semantically equivalent BUILD files.
|
||||
|
|
|
@ -31,10 +31,10 @@ import (
|
|||
)
|
||||
|
||||
func init() {
|
||||
RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
|
||||
RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
|
||||
RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
|
||||
RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
|
||||
RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
|
||||
RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
|
||||
RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
|
||||
RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
|
||||
}
|
||||
|
||||
type soongConfigModuleTypeImport struct {
|
||||
|
@ -153,7 +153,7 @@ type soongConfigModuleTypeImportProperties struct {
|
|||
// Then libacme_foo would build with cflags:
|
||||
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
|
||||
|
||||
func soongConfigModuleTypeImportFactory() Module {
|
||||
func SoongConfigModuleTypeImportFactory() Module {
|
||||
module := &soongConfigModuleTypeImport{}
|
||||
|
||||
module.AddProperties(&module.properties)
|
||||
|
@ -179,6 +179,7 @@ func (*soongConfigModuleTypeImport) GenerateAndroidBuildActions(ModuleContext) {
|
|||
|
||||
type soongConfigModuleTypeModule struct {
|
||||
ModuleBase
|
||||
BazelModuleBase
|
||||
properties soongconfig.ModuleTypeProperties
|
||||
}
|
||||
|
||||
|
@ -262,7 +263,7 @@ type soongConfigModuleTypeModule struct {
|
|||
// SOONG_CONFIG_acme_width := 200
|
||||
//
|
||||
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
|
||||
func soongConfigModuleTypeFactory() Module {
|
||||
func SoongConfigModuleTypeFactory() Module {
|
||||
module := &soongConfigModuleTypeModule{}
|
||||
|
||||
module.AddProperties(&module.properties)
|
||||
|
@ -296,7 +297,7 @@ type soongConfigBoolVariableDummyModule struct {
|
|||
|
||||
// soong_config_string_variable defines a variable and a set of possible string values for use
|
||||
// in a soong_config_module_type definition.
|
||||
func soongConfigStringVariableDummyFactory() Module {
|
||||
func SoongConfigStringVariableDummyFactory() Module {
|
||||
module := &soongConfigStringVariableDummyModule{}
|
||||
module.AddProperties(&module.properties, &module.stringProperties)
|
||||
initAndroidModuleBase(module)
|
||||
|
@ -305,7 +306,7 @@ func soongConfigStringVariableDummyFactory() Module {
|
|||
|
||||
// soong_config_string_variable defines a variable with true or false values for use
|
||||
// in a soong_config_module_type definition.
|
||||
func soongConfigBoolVariableDummyFactory() Module {
|
||||
func SoongConfigBoolVariableDummyFactory() Module {
|
||||
module := &soongConfigBoolVariableDummyModule{}
|
||||
module.AddProperties(&module.properties)
|
||||
initAndroidModuleBase(module)
|
||||
|
@ -324,6 +325,9 @@ func (m *soongConfigBoolVariableDummyModule) Name() string {
|
|||
func (*soongConfigBoolVariableDummyModule) Nameless() {}
|
||||
func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
|
||||
|
||||
// importModuleTypes registers the module factories for a list of module types defined
|
||||
// in an Android.bp file. These module factories are scoped for the current Android.bp
|
||||
// file only.
|
||||
func importModuleTypes(ctx LoadHookContext, from string, moduleTypes ...string) {
|
||||
from = filepath.Clean(from)
|
||||
if filepath.Ext(from) != ".bp" {
|
||||
|
@ -389,7 +393,7 @@ func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[s
|
|||
for name, moduleType := range mtDef.ModuleTypes {
|
||||
factory := globalModuleTypes[moduleType.BaseModuleType]
|
||||
if factory != nil {
|
||||
factories[name] = soongConfigModuleFactory(factory, moduleType)
|
||||
factories[name] = configModuleFactory(factory, moduleType, ctx.Config().runningAsBp2Build)
|
||||
} else {
|
||||
reportErrors(ctx, from,
|
||||
fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
|
||||
|
@ -404,20 +408,40 @@ func loadSoongConfigModuleTypeDefinition(ctx LoadHookContext, from string) map[s
|
|||
}).(map[string]blueprint.ModuleFactory)
|
||||
}
|
||||
|
||||
// soongConfigModuleFactory takes an existing soongConfigModuleFactory and a ModuleType and returns
|
||||
// a new soongConfigModuleFactory that wraps the existing soongConfigModuleFactory and adds conditional on Soong config
|
||||
// variables.
|
||||
func soongConfigModuleFactory(factory blueprint.ModuleFactory,
|
||||
moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
|
||||
|
||||
// configModuleFactory takes an existing soongConfigModuleFactory and a
|
||||
// ModuleType to create a new ModuleFactory that uses a custom loadhook.
|
||||
func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
|
||||
conditionalFactoryProps := soongconfig.CreateProperties(factory, moduleType)
|
||||
if conditionalFactoryProps.IsValid() {
|
||||
return func() (blueprint.Module, []interface{}) {
|
||||
module, props := factory()
|
||||
if !conditionalFactoryProps.IsValid() {
|
||||
return factory
|
||||
}
|
||||
useBp2buildHook := bp2build && proptools.BoolDefault(moduleType.Bp2buildAvailable, false)
|
||||
|
||||
conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
|
||||
props = append(props, conditionalProps.Interface())
|
||||
return func() (blueprint.Module, []interface{}) {
|
||||
module, props := factory()
|
||||
conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
|
||||
props = append(props, conditionalProps.Interface())
|
||||
|
||||
if useBp2buildHook {
|
||||
// The loadhook is different for bp2build, since we don't want to set a specific
|
||||
// set of property values based on a vendor var -- we want __all of them__ to
|
||||
// generate select statements, so we put the entire soong_config_variables
|
||||
// struct, together with the namespace representing those variables, while
|
||||
// creating the custom module with the factory.
|
||||
AddLoadHook(module, func(ctx LoadHookContext) {
|
||||
if m, ok := module.(Bazelable); ok {
|
||||
m.SetBaseModuleType(moduleType.BaseModuleType)
|
||||
// Instead of applying all properties, keep the entire conditionalProps struct as
|
||||
// part of the custom module so dependent modules can create the selects accordingly
|
||||
m.setNamespacedVariableProps(namespacedVariableProperties{
|
||||
moduleType.ConfigNamespace: conditionalProps.Interface(),
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Regular Soong operation wraps the existing module factory with a
|
||||
// conditional on Soong config variables by reading the product
|
||||
// config variables from Make.
|
||||
AddLoadHook(module, func(ctx LoadHookContext) {
|
||||
config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
|
||||
newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
|
||||
|
@ -429,10 +453,7 @@ func soongConfigModuleFactory(factory blueprint.ModuleFactory,
|
|||
ctx.AppendProperties(ps)
|
||||
}
|
||||
})
|
||||
|
||||
return module, props
|
||||
}
|
||||
} else {
|
||||
return factory
|
||||
return module, props
|
||||
}
|
||||
}
|
||||
|
|
|
@ -310,10 +310,10 @@ func TestSoongConfigModule(t *testing.T) {
|
|||
tc.preparer,
|
||||
PrepareForTestWithDefaults,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
|
||||
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
|
||||
ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
|
||||
}),
|
||||
|
@ -372,10 +372,10 @@ func TestNonExistentPropertyInSoongConfigModule(t *testing.T) {
|
|||
fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
|
||||
PrepareForTestWithDefaults,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
|
||||
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
|
||||
ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
|
||||
}),
|
||||
|
|
|
@ -9,6 +9,7 @@ bootstrap_go_package {
|
|||
"blueprint",
|
||||
"blueprint-parser",
|
||||
"blueprint-proptools",
|
||||
"soong-bazel",
|
||||
],
|
||||
srcs: [
|
||||
"config.go",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package soongconfig
|
||||
|
||||
import (
|
||||
"android/soong/bazel"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
@ -28,7 +29,7 @@ import (
|
|||
|
||||
const conditionsDefault = "conditions_default"
|
||||
|
||||
var soongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
|
||||
var SoongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
|
||||
|
||||
// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
|
||||
// result so each file is only parsed once.
|
||||
|
@ -120,6 +121,8 @@ type ModuleTypeProperties struct {
|
|||
|
||||
// the list of properties that this module type will extend.
|
||||
Properties []string
|
||||
|
||||
Bazel_module bazel.BazelModuleProperties
|
||||
}
|
||||
|
||||
func processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
|
||||
|
@ -271,12 +274,12 @@ func CreateProperties(factory blueprint.ModuleFactory, moduleType *ModuleType) r
|
|||
}
|
||||
|
||||
typ := reflect.StructOf([]reflect.StructField{{
|
||||
Name: soongConfigProperty,
|
||||
Name: SoongConfigProperty,
|
||||
Type: reflect.StructOf(fields),
|
||||
}})
|
||||
|
||||
props := reflect.New(typ)
|
||||
structConditions := props.Elem().FieldByName(soongConfigProperty)
|
||||
structConditions := props.Elem().FieldByName(SoongConfigProperty)
|
||||
|
||||
for i, c := range moduleType.Variables {
|
||||
c.initializeProperties(structConditions.Field(i), affectablePropertiesType)
|
||||
|
@ -415,7 +418,7 @@ func typeForPropertyFromPropertyStruct(ps interface{}, property string) reflect.
|
|||
// soong_config_variables are expected to be in the same order as moduleType.Variables.
|
||||
func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
|
||||
var ret []interface{}
|
||||
props = props.Elem().FieldByName(soongConfigProperty)
|
||||
props = props.Elem().FieldByName(SoongConfigProperty)
|
||||
for i, c := range moduleType.Variables {
|
||||
if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
|
||||
return nil, err
|
||||
|
@ -433,6 +436,7 @@ type ModuleType struct {
|
|||
|
||||
affectableProperties []string
|
||||
variableNames []string
|
||||
Bp2buildAvailable *bool
|
||||
}
|
||||
|
||||
func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
|
||||
|
@ -441,6 +445,7 @@ func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
|
|||
ConfigNamespace: props.Config_namespace,
|
||||
BaseModuleType: props.Module_type,
|
||||
variableNames: props.Variables,
|
||||
Bp2buildAvailable: props.Bazel_module.Bp2build_available,
|
||||
}
|
||||
|
||||
for _, name := range props.Bool_variables {
|
||||
|
|
|
@ -458,6 +458,7 @@ func (ctx *TestContext) Register() {
|
|||
|
||||
// RegisterForBazelConversion prepares a test context for bp2build conversion.
|
||||
func (ctx *TestContext) RegisterForBazelConversion() {
|
||||
ctx.SetRunningAsBp2build()
|
||||
RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildMutators)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"android/soong/android/soongconfig"
|
||||
"android/soong/bazel"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
@ -487,13 +489,97 @@ type ProductConfigContext interface {
|
|||
// ProductConfigProperty contains the information for a single property (may be a struct) paired
|
||||
// with the appropriate ProductConfigVariable.
|
||||
type ProductConfigProperty struct {
|
||||
// The name of the product variable, e.g. "safestack", "malloc_not_svelte",
|
||||
// "board"
|
||||
ProductConfigVariable string
|
||||
FullConfig string
|
||||
Property interface{}
|
||||
|
||||
// Namespace of the variable, if this is a soong_config_module_type variable
|
||||
// e.g. "acme", "ANDROID", "vendor_nae"
|
||||
Namespace string // for soong config variables
|
||||
|
||||
// Unique configuration to identify this product config property (i.e. a
|
||||
// primary key), as just using the product variable name is not sufficient.
|
||||
//
|
||||
// For product variables, this is the product variable name + optional
|
||||
// archvariant information. e.g.
|
||||
//
|
||||
// product_variables: {
|
||||
// foo: {
|
||||
// cflags: ["-Dfoo"],
|
||||
// },
|
||||
// },
|
||||
//
|
||||
// FullConfig would be "foo".
|
||||
//
|
||||
// target: {
|
||||
// android: {
|
||||
// product_variables: {
|
||||
// foo: {
|
||||
// cflags: ["-Dfoo-android"],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
//
|
||||
// FullConfig would be "foo-android".
|
||||
//
|
||||
// For soong config variables, this is the namespace + product variable name
|
||||
// + value of the variable, if applicable. The value can also be
|
||||
// conditions_default.
|
||||
//
|
||||
// e.g.
|
||||
//
|
||||
// soong_config_variables: {
|
||||
// feature1: {
|
||||
// conditions_default: {
|
||||
// cflags: ["-DDEFAULT1"],
|
||||
// },
|
||||
// cflags: ["-DFEATURE1"],
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// where feature1 is created in the "acme" namespace, so FullConfig would be
|
||||
// "acme__feature1" and "acme__feature1__conditions_default".
|
||||
//
|
||||
// e.g.
|
||||
//
|
||||
// soong_config_variables: {
|
||||
// board: {
|
||||
// soc_a: {
|
||||
// cflags: ["-DSOC_A"],
|
||||
// },
|
||||
// soc_b: {
|
||||
// cflags: ["-DSOC_B"],
|
||||
// },
|
||||
// soc_c: {},
|
||||
// conditions_default: {
|
||||
// cflags: ["-DSOC_DEFAULT"]
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// where board is created in the "acme" namespace, so FullConfig would be
|
||||
// "acme__board__soc_a", "acme__board__soc_b", and
|
||||
// "acme__board__conditions_default"
|
||||
FullConfig string
|
||||
|
||||
// The actual property value: list, bool, string..
|
||||
Property interface{}
|
||||
}
|
||||
|
||||
// ProductConfigProperties is a map of property name to a slice of ProductConfigProperty such that
|
||||
// all it all product variable-specific versions of a property are easily accessed together
|
||||
func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
|
||||
if p.Namespace == "" {
|
||||
return bazel.ProductVariableConfigurationAxis(p.FullConfig)
|
||||
} else {
|
||||
// Soong config variables can be uniquely identified by the namespace
|
||||
// (e.g. acme, android) and the product variable name (e.g. board, size)
|
||||
return bazel.ProductVariableConfigurationAxis(p.Namespace + "__" + p.ProductConfigVariable)
|
||||
}
|
||||
}
|
||||
|
||||
// ProductConfigProperties is a map of property name to a slice of
|
||||
// ProductConfigProperty such that all product variable-specific versions of a
|
||||
// property are easily accessed together
|
||||
type ProductConfigProperties map[string]map[string]ProductConfigProperty
|
||||
|
||||
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
|
||||
|
@ -504,36 +590,165 @@ func ProductVariableProperties(ctx BazelConversionPathContext) ProductConfigProp
|
|||
|
||||
productConfigProperties := ProductConfigProperties{}
|
||||
|
||||
if moduleBase.variableProperties == nil {
|
||||
return productConfigProperties
|
||||
if moduleBase.variableProperties != nil {
|
||||
productVariablesProperty := proptools.FieldNameForProperty("product_variables")
|
||||
productVariableValues(
|
||||
productVariablesProperty,
|
||||
moduleBase.variableProperties,
|
||||
"",
|
||||
"",
|
||||
&productConfigProperties)
|
||||
|
||||
for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
|
||||
for config, props := range configToProps {
|
||||
// GetArchVariantProperties is creating an instance of the requested type
|
||||
// and productVariablesValues expects an interface, so no need to cast
|
||||
productVariableValues(
|
||||
productVariablesProperty,
|
||||
props,
|
||||
"",
|
||||
config,
|
||||
&productConfigProperties)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
productVariableValues(moduleBase.variableProperties, "", &productConfigProperties)
|
||||
|
||||
for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
|
||||
for config, props := range configToProps {
|
||||
// GetArchVariantProperties is creating an instance of the requested type
|
||||
// and productVariablesValues expects an interface, so no need to cast
|
||||
productVariableValues(props, config, &productConfigProperties)
|
||||
if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
|
||||
for namespace, namespacedVariableProp := range m.namespacedVariableProps() {
|
||||
productVariableValues(
|
||||
soongconfig.SoongConfigProperty,
|
||||
namespacedVariableProp,
|
||||
namespace,
|
||||
"",
|
||||
&productConfigProperties)
|
||||
}
|
||||
}
|
||||
|
||||
return productConfigProperties
|
||||
}
|
||||
|
||||
func productVariableValues(variableProps interface{}, suffix string, productConfigProperties *ProductConfigProperties) {
|
||||
func (p *ProductConfigProperties) AddProductConfigProperty(
|
||||
propertyName, namespace, productVariableName, config string, property interface{}) {
|
||||
if (*p)[propertyName] == nil {
|
||||
(*p)[propertyName] = make(map[string]ProductConfigProperty)
|
||||
}
|
||||
|
||||
// Normalize config to be all lowercase. It's the "primary key" of this
|
||||
// unique property value. This can be the conditions_default value of the
|
||||
// product variable as well.
|
||||
config = strings.ToLower(config)
|
||||
(*p)[propertyName][config] = ProductConfigProperty{
|
||||
Namespace: namespace, // e.g. acme, android
|
||||
ProductConfigVariable: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
|
||||
FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
|
||||
Property: property, // e.g. ["-O3"]
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
conditionsDefaultField string = proptools.FieldNameForProperty(bazel.ConditionsDefaultConfigKey)
|
||||
)
|
||||
|
||||
// maybeExtractConfigVarProp attempts to read this value as a config var struct
|
||||
// wrapped by interfaces and ptrs. If it's not the right type, the second return
|
||||
// value is false.
|
||||
func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) {
|
||||
if v.Kind() == reflect.Interface {
|
||||
// The conditions_default value can be either
|
||||
// 1) an ptr to an interface of a struct (bool config variables and product variables)
|
||||
// 2) an interface of 1) (config variables with nested structs, like string vars)
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Ptr {
|
||||
return v, false
|
||||
}
|
||||
v = reflect.Indirect(v)
|
||||
if v.Kind() == reflect.Interface {
|
||||
// Extract the struct from the interface
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if !v.IsValid() {
|
||||
return v, false
|
||||
}
|
||||
|
||||
if v.Kind() != reflect.Struct {
|
||||
return v, false
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
|
||||
// productVariableValues uses reflection to convert a property struct for
|
||||
// product_variables and soong_config_variables to structs that can be generated
|
||||
// as select statements.
|
||||
func productVariableValues(
|
||||
fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties) {
|
||||
if suffix != "" {
|
||||
suffix = "-" + suffix
|
||||
}
|
||||
variableValues := reflect.ValueOf(variableProps).Elem().FieldByName("Product_variables")
|
||||
|
||||
// variableValues represent the product_variables or soong_config_variables
|
||||
// struct.
|
||||
variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
|
||||
|
||||
// Example of product_variables:
|
||||
//
|
||||
// product_variables: {
|
||||
// malloc_not_svelte: {
|
||||
// shared_libs: ["malloc_not_svelte_shared_lib"],
|
||||
// whole_static_libs: ["malloc_not_svelte_whole_static_lib"],
|
||||
// exclude_static_libs: [
|
||||
// "malloc_not_svelte_static_lib_excludes",
|
||||
// "malloc_not_svelte_whole_static_lib_excludes",
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
//
|
||||
// Example of soong_config_variables:
|
||||
//
|
||||
// soong_config_variables: {
|
||||
// feature1: {
|
||||
// conditions_default: {
|
||||
// ...
|
||||
// },
|
||||
// cflags: ...
|
||||
// },
|
||||
// feature2: {
|
||||
// cflags: ...
|
||||
// conditions_default: {
|
||||
// ...
|
||||
// },
|
||||
// },
|
||||
// board: {
|
||||
// soc_a: {
|
||||
// ...
|
||||
// },
|
||||
// soc_a: {
|
||||
// ...
|
||||
// },
|
||||
// soc_c: {},
|
||||
// conditions_default: {
|
||||
// ...
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
for i := 0; i < variableValues.NumField(); i++ {
|
||||
// e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
|
||||
productVariableName := variableValues.Type().Field(i).Name
|
||||
|
||||
variableValue := variableValues.Field(i)
|
||||
// Check if any properties were set for the module
|
||||
if variableValue.IsZero() {
|
||||
// e.g. feature1: {}, malloc_not_svelte: {}
|
||||
continue
|
||||
}
|
||||
// e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
|
||||
productVariableName := variableValues.Type().Field(i).Name
|
||||
|
||||
// Unlike product variables, config variables require a few more
|
||||
// indirections to extract the struct from the reflect.Value.
|
||||
if v, ok := maybeExtractConfigVarProp(variableValue); ok {
|
||||
variableValue = v
|
||||
}
|
||||
|
||||
for j := 0; j < variableValue.NumField(); j++ {
|
||||
property := variableValue.Field(j)
|
||||
// If the property wasn't set, no need to pass it along
|
||||
|
@ -543,14 +758,57 @@ func productVariableValues(variableProps interface{}, suffix string, productConf
|
|||
|
||||
// e.g. Asflags, Cflags, Enabled, etc.
|
||||
propertyName := variableValue.Type().Field(j).Name
|
||||
if (*productConfigProperties)[propertyName] == nil {
|
||||
(*productConfigProperties)[propertyName] = make(map[string]ProductConfigProperty)
|
||||
}
|
||||
config := productVariableName + suffix
|
||||
(*productConfigProperties)[propertyName][config] = ProductConfigProperty{
|
||||
ProductConfigVariable: productVariableName,
|
||||
FullConfig: config,
|
||||
Property: property.Interface(),
|
||||
|
||||
if v, ok := maybeExtractConfigVarProp(property); ok {
|
||||
// The field is a struct, which is used by:
|
||||
// 1) soong_config_string_variables
|
||||
//
|
||||
// soc_a: {
|
||||
// cflags: ...,
|
||||
// }
|
||||
//
|
||||
// soc_b: {
|
||||
// cflags: ...,
|
||||
// }
|
||||
//
|
||||
// 2) conditions_default structs for all soong config variable types.
|
||||
//
|
||||
// conditions_default: {
|
||||
// cflags: ...,
|
||||
// static_libs: ...
|
||||
// }
|
||||
field := v
|
||||
for k := 0; k < field.NumField(); k++ {
|
||||
// Iterate over fields of this struct prop.
|
||||
if field.Field(k).IsZero() {
|
||||
continue
|
||||
}
|
||||
productVariableValue := proptools.PropertyNameForField(propertyName)
|
||||
config := strings.Join([]string{namespace, productVariableName, productVariableValue}, "__")
|
||||
actualPropertyName := field.Type().Field(k).Name
|
||||
|
||||
productConfigProperties.AddProductConfigProperty(
|
||||
actualPropertyName, // e.g. cflags, static_libs
|
||||
namespace, // e.g. acme, android
|
||||
productVariableName, // e.g. size, feature1, FEATURE2, board
|
||||
config,
|
||||
field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Not a conditions_default or a struct prop, i.e. regular
|
||||
// product variables, or not a string-typed config var.
|
||||
config := productVariableName + suffix
|
||||
if namespace != "" {
|
||||
config = namespace + "__" + config
|
||||
}
|
||||
productConfigProperties.AddProductConfigProperty(
|
||||
propertyName,
|
||||
namespace,
|
||||
productVariableName,
|
||||
config,
|
||||
property.Interface(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,9 +158,9 @@ func (ct configurationType) validateConfig(config string) {
|
|||
}
|
||||
|
||||
// SelectKey returns the Bazel select key for a given configurationType and config string.
|
||||
func (ct configurationType) SelectKey(config string) string {
|
||||
ct.validateConfig(config)
|
||||
switch ct {
|
||||
func (ca ConfigurationAxis) SelectKey(config string) string {
|
||||
ca.validateConfig(config)
|
||||
switch ca.configurationType {
|
||||
case noConfig:
|
||||
panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
|
||||
case arch:
|
||||
|
@ -170,12 +170,13 @@ func (ct configurationType) SelectKey(config string) string {
|
|||
case osArch:
|
||||
return platformOsArchMap[config]
|
||||
case productVariables:
|
||||
if config == ConditionsDefaultConfigKey {
|
||||
if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
|
||||
// e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
|
||||
return ConditionsDefaultSelectKey
|
||||
}
|
||||
return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(config))
|
||||
return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
|
||||
default:
|
||||
panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
|
||||
panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,23 @@ import (
|
|||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
type BazelModuleProperties struct {
|
||||
// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
|
||||
// will import the handcrafted build target into the autogenerated file. Note: this may result in
|
||||
// a conflict due to duplicate targets if bp2build_available is also set.
|
||||
Label *string
|
||||
|
||||
// If true, bp2build will generate the converted Bazel target for this module. Note: this may
|
||||
// cause a conflict due to the duplicate targets if label is also set.
|
||||
//
|
||||
// This is a bool pointer to support tristates: true, false, not set.
|
||||
//
|
||||
// To opt-in a module, set bazel_module: { bp2build_available: true }
|
||||
// To opt-out a module, set bazel_module: { bp2build_available: false }
|
||||
// To defer the default setting for the directory, do not set the value.
|
||||
Bp2build_available *bool
|
||||
}
|
||||
|
||||
// BazelTargetModuleProperties contain properties and metadata used for
|
||||
// Blueprint to BUILD file conversion.
|
||||
type BazelTargetModuleProperties struct {
|
||||
|
|
257
bp2build/soong_config_module_type_conversion_test.go
Normal file
257
bp2build/soong_config_module_type_conversion_test.go
Normal file
|
@ -0,0 +1,257 @@
|
|||
// Copyright 2021 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bp2build
|
||||
|
||||
import (
|
||||
"android/soong/android"
|
||||
"android/soong/cc"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func runSoongConfigModuleTypeTest(t *testing.T, tc bp2buildTestCase) {
|
||||
t.Helper()
|
||||
runBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
|
||||
}
|
||||
|
||||
func registerSoongConfigModuleTypes(ctx android.RegistrationContext) {
|
||||
cc.RegisterCCBuildComponents(ctx)
|
||||
|
||||
ctx.RegisterModuleType("soong_config_module_type_import", android.SoongConfigModuleTypeImportFactory)
|
||||
ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
|
||||
ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
|
||||
ctx.RegisterModuleType("soong_config_bool_variable", android.SoongConfigBoolVariableDummyFactory)
|
||||
}
|
||||
|
||||
func TestSoongConfigModuleType(t *testing.T) {
|
||||
bp := `
|
||||
soong_config_module_type {
|
||||
name: "custom_cc_library_static",
|
||||
module_type: "cc_library_static",
|
||||
config_namespace: "acme",
|
||||
bool_variables: ["feature1"],
|
||||
properties: ["cflags"],
|
||||
bazel_module: { bp2build_available: true },
|
||||
}
|
||||
|
||||
custom_cc_library_static {
|
||||
name: "foo",
|
||||
bazel_module: { bp2build_available: true },
|
||||
soong_config_variables: {
|
||||
feature1: {
|
||||
conditions_default: {
|
||||
cflags: ["-DDEFAULT1"],
|
||||
},
|
||||
cflags: ["-DFEATURE1"],
|
||||
},
|
||||
},
|
||||
}
|
||||
`
|
||||
|
||||
runSoongConfigModuleTypeTest(t, bp2buildTestCase{
|
||||
description: "soong config variables - soong_config_module_type is supported in bp2build",
|
||||
moduleTypeUnderTest: "cc_library_static",
|
||||
moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
|
||||
moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
|
||||
blueprint: bp,
|
||||
expectedBazelTargets: []string{`cc_library_static(
|
||||
name = "foo",
|
||||
copts = select({
|
||||
"//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
|
||||
"//conditions:default": ["-DDEFAULT1"],
|
||||
}),
|
||||
local_includes = ["."],
|
||||
)`}})
|
||||
}
|
||||
|
||||
func TestSoongConfigModuleTypeImport(t *testing.T) {
|
||||
configBp := `
|
||||
soong_config_module_type {
|
||||
name: "custom_cc_library_static",
|
||||
module_type: "cc_library_static",
|
||||
config_namespace: "acme",
|
||||
bool_variables: ["feature1"],
|
||||
properties: ["cflags"],
|
||||
bazel_module: { bp2build_available: true },
|
||||
}
|
||||
`
|
||||
bp := `
|
||||
soong_config_module_type_import {
|
||||
from: "foo/bar/SoongConfig.bp",
|
||||
module_types: ["custom_cc_library_static"],
|
||||
}
|
||||
|
||||
custom_cc_library_static {
|
||||
name: "foo",
|
||||
bazel_module: { bp2build_available: true },
|
||||
soong_config_variables: {
|
||||
feature1: {
|
||||
conditions_default: {
|
||||
cflags: ["-DDEFAULT1"],
|
||||
},
|
||||
cflags: ["-DFEATURE1"],
|
||||
},
|
||||
},
|
||||
}
|
||||
`
|
||||
|
||||
runSoongConfigModuleTypeTest(t, bp2buildTestCase{
|
||||
description: "soong config variables - soong_config_module_type_import is supported in bp2build",
|
||||
moduleTypeUnderTest: "cc_library_static",
|
||||
moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
|
||||
moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
|
||||
filesystem: map[string]string{
|
||||
"foo/bar/SoongConfig.bp": configBp,
|
||||
},
|
||||
blueprint: bp,
|
||||
expectedBazelTargets: []string{`cc_library_static(
|
||||
name = "foo",
|
||||
copts = select({
|
||||
"//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
|
||||
"//conditions:default": ["-DDEFAULT1"],
|
||||
}),
|
||||
local_includes = ["."],
|
||||
)`}})
|
||||
}
|
||||
|
||||
func TestSoongConfigModuleType_StringVar(t *testing.T) {
|
||||
bp := `
|
||||
soong_config_string_variable {
|
||||
name: "board",
|
||||
values: ["soc_a", "soc_b", "soc_c"],
|
||||
}
|
||||
|
||||
soong_config_module_type {
|
||||
name: "custom_cc_library_static",
|
||||
module_type: "cc_library_static",
|
||||
config_namespace: "acme",
|
||||
variables: ["board"],
|
||||
properties: ["cflags"],
|
||||
bazel_module: { bp2build_available: true },
|
||||
}
|
||||
|
||||
custom_cc_library_static {
|
||||
name: "foo",
|
||||
bazel_module: { bp2build_available: true },
|
||||
soong_config_variables: {
|
||||
board: {
|
||||
soc_a: {
|
||||
cflags: ["-DSOC_A"],
|
||||
},
|
||||
soc_b: {
|
||||
cflags: ["-DSOC_B"],
|
||||
},
|
||||
soc_c: {},
|
||||
conditions_default: {
|
||||
cflags: ["-DSOC_DEFAULT"]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`
|
||||
|
||||
runSoongConfigModuleTypeTest(t, bp2buildTestCase{
|
||||
description: "soong config variables - generates selects for string vars",
|
||||
moduleTypeUnderTest: "cc_library_static",
|
||||
moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
|
||||
moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
|
||||
blueprint: bp,
|
||||
expectedBazelTargets: []string{`cc_library_static(
|
||||
name = "foo",
|
||||
copts = select({
|
||||
"//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
|
||||
"//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
|
||||
"//conditions:default": ["-DSOC_DEFAULT"],
|
||||
}),
|
||||
local_includes = ["."],
|
||||
)`}})
|
||||
}
|
||||
|
||||
func TestSoongConfigModuleType_StringAndBoolVar(t *testing.T) {
|
||||
bp := `
|
||||
soong_config_bool_variable {
|
||||
name: "feature1",
|
||||
}
|
||||
|
||||
soong_config_bool_variable {
|
||||
name: "feature2",
|
||||
}
|
||||
|
||||
soong_config_string_variable {
|
||||
name: "board",
|
||||
values: ["soc_a", "soc_b", "soc_c"],
|
||||
}
|
||||
|
||||
soong_config_module_type {
|
||||
name: "custom_cc_library_static",
|
||||
module_type: "cc_library_static",
|
||||
config_namespace: "acme",
|
||||
variables: ["feature1", "feature2", "board"],
|
||||
properties: ["cflags"],
|
||||
bazel_module: { bp2build_available: true },
|
||||
}
|
||||
|
||||
custom_cc_library_static {
|
||||
name: "foo",
|
||||
bazel_module: { bp2build_available: true },
|
||||
soong_config_variables: {
|
||||
feature1: {
|
||||
conditions_default: {
|
||||
cflags: ["-DDEFAULT1"],
|
||||
},
|
||||
cflags: ["-DFEATURE1"],
|
||||
},
|
||||
feature2: {
|
||||
cflags: ["-DFEATURE2"],
|
||||
conditions_default: {
|
||||
cflags: ["-DDEFAULT2"],
|
||||
},
|
||||
},
|
||||
board: {
|
||||
soc_a: {
|
||||
cflags: ["-DSOC_A"],
|
||||
},
|
||||
soc_b: {
|
||||
cflags: ["-DSOC_B"],
|
||||
},
|
||||
soc_c: {},
|
||||
conditions_default: {
|
||||
cflags: ["-DSOC_DEFAULT"]
|
||||
},
|
||||
},
|
||||
},
|
||||
}`
|
||||
|
||||
runSoongConfigModuleTypeTest(t, bp2buildTestCase{
|
||||
description: "soong config variables - generates selects for multiple variable types",
|
||||
moduleTypeUnderTest: "cc_library_static",
|
||||
moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
|
||||
moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
|
||||
blueprint: bp,
|
||||
expectedBazelTargets: []string{`cc_library_static(
|
||||
name = "foo",
|
||||
copts = select({
|
||||
"//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
|
||||
"//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
|
||||
"//conditions:default": ["-DSOC_DEFAULT"],
|
||||
}) + select({
|
||||
"//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
|
||||
"//conditions:default": ["-DDEFAULT1"],
|
||||
}) + select({
|
||||
"//build/bazel/product_variables:acme__feature2": ["-DFEATURE2"],
|
||||
"//conditions:default": ["-DDEFAULT2"],
|
||||
}),
|
||||
local_includes = ["."],
|
||||
)`}})
|
||||
}
|
|
@ -327,7 +327,7 @@ func (ca *compilerAttributes) convertProductVariables(ctx android.BazelConversio
|
|||
ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
|
||||
}
|
||||
newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
|
||||
attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.FullConfig), prop.FullConfig, newFlags)
|
||||
attr.SetSelectValue(prop.ConfigurationAxis(), prop.FullConfig, newFlags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionP
|
|||
ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
|
||||
}
|
||||
|
||||
dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes))
|
||||
dep.attribute.SetSelectValue(prop.ConfigurationAxis(), config, dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2358,9 +2358,6 @@ func ccSharedOrStaticBp2BuildMutator(ctx android.TopDownMutatorContext, modType
|
|||
if !module.ConvertWithBp2build(ctx) {
|
||||
return
|
||||
}
|
||||
if ctx.ModuleType() != modType {
|
||||
return
|
||||
}
|
||||
|
||||
ccSharedOrStaticBp2BuildMutatorInternal(ctx, module, modType)
|
||||
}
|
||||
|
@ -2498,7 +2495,15 @@ type bazelCcLibraryStaticAttributes struct {
|
|||
}
|
||||
|
||||
func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) {
|
||||
ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static")
|
||||
isLibraryStatic := ctx.ModuleType() == "cc_library_static"
|
||||
if b, ok := ctx.Module().(android.Bazelable); ok {
|
||||
// This is created by a custom soong config module type, so its ctx.ModuleType() is not
|
||||
// cc_library_static. Check its BaseModuleType.
|
||||
isLibraryStatic = isLibraryStatic || b.BaseModuleType() == "cc_library_static"
|
||||
}
|
||||
if isLibraryStatic {
|
||||
ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/199902614): Can this be factored to share with the other Attributes?
|
||||
|
@ -2529,5 +2534,13 @@ type bazelCcLibrarySharedAttributes struct {
|
|||
}
|
||||
|
||||
func CcLibrarySharedBp2Build(ctx android.TopDownMutatorContext) {
|
||||
ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared")
|
||||
isLibraryShared := ctx.ModuleType() == "cc_library_shared"
|
||||
if b, ok := ctx.Module().(android.Bazelable); ok {
|
||||
// This is created by a custom soong config module type, so its ctx.ModuleType() is not
|
||||
// cc_library_shared. Check its BaseModuleType.
|
||||
isLibraryShared = isLibraryShared || b.BaseModuleType() == "cc_library_shared"
|
||||
}
|
||||
if isLibraryShared {
|
||||
ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,6 +464,11 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
|
|||
// conversion for Bazel conversion.
|
||||
bp2buildCtx := android.NewContext(configuration)
|
||||
|
||||
// Soong internals like LoadHooks behave differently when running as
|
||||
// bp2build. This is the bit to differentiate between Soong-as-Soong and
|
||||
// Soong-as-bp2build.
|
||||
bp2buildCtx.SetRunningAsBp2build()
|
||||
|
||||
// Propagate "allow misssing dependencies" bit. This is normally set in
|
||||
// newContext(), but we create bp2buildCtx without calling that method.
|
||||
bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
|
||||
|
|
Loading…
Reference in a new issue