diff --git a/android/mutator.go b/android/mutator.go index 9e99beeef..a06e0ee46 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -539,7 +539,7 @@ func (t *topDownMutatorContext) CreateBazelTargetModule( Name: &name, } - b := t.CreateModule(factory, &nameProp, attrs).(BazelTargetModule) + b := t.createModuleWithoutInheritance(factory, &nameProp, attrs).(BazelTargetModule) b.SetBazelTargetModuleProperties(bazelProps) return b } @@ -608,6 +608,11 @@ func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...int return module } +func (t *topDownMutatorContext) createModuleWithoutInheritance(factory ModuleFactory, props ...interface{}) Module { + module := t.bp.CreateModule(ModuleFactoryAdaptor(factory), props...).(Module) + return module +} + func (b *bottomUpMutatorContext) MutatorName() string { return b.bp.MutatorName() } diff --git a/android/variable.go b/android/variable.go index 2ab51c74a..dff48c289 100644 --- a/android/variable.go +++ b/android/variable.go @@ -448,6 +448,63 @@ func (v *productVariables) SetDefaultConfig() { } } +// ProductConfigContext requires the access to the Module to get product config properties. +type ProductConfigContext interface { + Module() Module +} + +// ProductConfigProperty contains the information for a single property (may be a struct) paired +// with the appropriate ProductConfigVariable. +type ProductConfigProperty struct { + ProductConfigVariable 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 +type ProductConfigProperties map[string][]ProductConfigProperty + +// ProductVariableProperties returns a ProductConfigProperties containing only the properties which +// have been set for the module in the given context. +func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties { + module := ctx.Module() + moduleBase := module.base() + + productConfigProperties := ProductConfigProperties{} + + if moduleBase.variableProperties == nil { + return productConfigProperties + } + + variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName("Product_variables") + for i := 0; i < variableValues.NumField(); i++ { + variableValue := variableValues.Field(i) + // Check if any properties were set for the module + if variableValue.IsZero() { + continue + } + // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc. + productVariableName := variableValues.Type().Field(i).Name + for j := 0; j < variableValue.NumField(); j++ { + property := variableValue.Field(j) + // If the property wasn't set, no need to pass it along + if property.IsZero() { + continue + } + + // e.g. Asflags, Cflags, Enabled, etc. + propertyName := variableValue.Type().Field(j).Name + productConfigProperties[propertyName] = append(productConfigProperties[propertyName], + ProductConfigProperty{ + ProductConfigVariable: productVariableName, + Property: property.Interface(), + }) + } + } + + return productConfigProperties +} + func VariableMutator(mctx BottomUpMutatorContext) { var module Module var ok bool diff --git a/bazel/properties.go b/bazel/properties.go index 25e110a67..1763f2dc0 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -16,6 +16,7 @@ package bazel import ( "fmt" + "regexp" "sort" ) @@ -31,6 +32,8 @@ type BazelTargetModuleProperties struct { const BazelTargetModuleNamePrefix = "__bp2build__" +var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)") + // Label is used to represent a Bazel compatible Label. Also stores the original bp text to support // string replacement. type Label struct { @@ -225,3 +228,23 @@ func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) { panic(fmt.Errorf("Unknown arch: %s", arch)) } } + +// TryVariableSubstitution, replace string substitution formatting within each string in slice with +// Starlark string.format compatible tag for productVariable. +func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) { + ret := make([]string, 0, len(slice)) + changesMade := false + for _, s := range slice { + newS, changed := TryVariableSubstitution(s, productVariable) + ret = append(ret, newS) + changesMade = changesMade || changed + } + return ret, changesMade +} + +// TryVariableSubstitution, replace string substitution formatting within s with Starlark +// string.format compatible tag for productVariable. +func TryVariableSubstitution(s string, productVariable string) (string, bool) { + sub := productVariableSubstitutionPattern.ReplaceAllString(s, "{"+productVariable+"}") + return sub, s != sub +} diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index b00703301..946173927 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -206,6 +206,34 @@ cc_object { srcs = [ "a/b/c.c", ], +)`, + }, + }, + { + description: "cc_object with product variable", + moduleTypeUnderTest: "cc_object", + moduleTypeUnderTestFactory: cc.ObjectFactory, + moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build, + blueprint: `cc_object { + name: "foo", + include_build_directory: false, + product_variables: { + platform_sdk_version: { + asflags: ["-DPLATFORM_SDK_VERSION=%d"], + }, + }, + + bazel_module: { bp2build_available: true }, +} +`, + expectedBazelTargets: []string{`cc_object( + name = "foo", + asflags = [ + "-DPLATFORM_SDK_VERSION={Platform_sdk_version}", + ], + copts = [ + "-fno-addrsig", + ], )`, }, }, diff --git a/cc/object.go b/cc/object.go index aa63323e2..ea8d7d3ec 100644 --- a/cc/object.go +++ b/cc/object.go @@ -115,6 +115,7 @@ type bazelObjectAttributes struct { Srcs bazel.LabelListAttribute Deps bazel.LabelListAttribute Copts bazel.StringListAttribute + Asflags []string Local_include_dirs []string } @@ -158,6 +159,7 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { var copts bazel.StringListAttribute var srcs bazel.LabelListAttribute var localIncludeDirs []string + var asFlags []string for _, props := range m.compiler.compilerProps() { if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { copts.Value = baseCompilerProps.Cflags @@ -183,6 +185,23 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { } } + productVariableProps := android.ProductVariableProperties(ctx) + if props, exists := productVariableProps["Asflags"]; exists { + // TODO(b/183595873): consider deduplicating handling of product variable properties + for _, prop := range props { + flags, ok := prop.Property.([]string) + if !ok { + ctx.ModuleErrorf("Could not convert product variable asflag property") + return + } + // TODO(b/183595873) handle other product variable usages -- as selects? + if newFlags, subbed := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable); subbed { + asFlags = append(asFlags, newFlags...) + } + } + } + // TODO(b/183595872) warn/error if we're not handling product variables + for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) { if cProps, ok := p.(*BaseCompilerProperties); ok { srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs)) @@ -194,6 +213,7 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { Srcs: srcs, Deps: deps, Copts: copts, + Asflags: asFlags, Local_include_dirs: localIncludeDirs, }