summaryrefslogtreecommitdiff
path: root/sdk/update.go
diff options
context:
space:
mode:
Diffstat (limited to 'sdk/update.go')
-rw-r--r--sdk/update.go244
1 files changed, 193 insertions, 51 deletions
diff --git a/sdk/update.go b/sdk/update.go
index 36b564fe6..b146b62c8 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -22,7 +22,6 @@ import (
"android/soong/apex"
"android/soong/cc"
-
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -114,8 +113,16 @@ func (gc *generatedContents) Dedent() {
gc.indentLevel--
}
-func (gc *generatedContents) Printfln(format string, args ...interface{}) {
- fmt.Fprintf(&(gc.content), strings.Repeat(" ", gc.indentLevel)+format+"\n", args...)
+// IndentedPrintf will add spaces to indent the line to the appropriate level before printing the
+// arguments.
+func (gc *generatedContents) IndentedPrintf(format string, args ...interface{}) {
+ fmt.Fprintf(&(gc.content), strings.Repeat(" ", gc.indentLevel)+format, args...)
+}
+
+// UnindentedPrintf does not add spaces to indent the line to the appropriate level before printing
+// the arguments.
+func (gc *generatedContents) UnindentedPrintf(format string, args ...interface{}) {
+ fmt.Fprintf(&(gc.content), format, args...)
}
func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
@@ -140,8 +147,8 @@ func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderC
// Collect all the members.
//
-// Updates the sdk module with a list of sdkMemberVariantDeps and details as to which multilibs
-// (32/64/both) are used by this sdk variant.
+// Updates the sdk module with a list of sdkMemberVariantDep instances and details as to which
+// multilibs (32/64/both) are used by this sdk variant.
func (s *sdk) collectMembers(ctx android.ModuleContext) {
s.multilibUsages = multilibNone
ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
@@ -149,6 +156,11 @@ func (s *sdk) collectMembers(ctx android.ModuleContext) {
if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
memberType := memberTag.SdkMemberType(child)
+ // If a nil SdkMemberType was returned then this module should not be added to the sdk.
+ if memberType == nil {
+ return false
+ }
+
// Make sure that the resolved module is allowed in the member list property.
if !memberType.IsInstance(child) {
ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
@@ -157,8 +169,15 @@ func (s *sdk) collectMembers(ctx android.ModuleContext) {
// Keep track of which multilib variants are used by the sdk.
s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
+ var exportedComponentsInfo android.ExportedComponentsInfo
+ if ctx.OtherModuleHasProvider(child, android.ExportedComponentsInfoProvider) {
+ exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
+ }
+
export := memberTag.ExportMember()
- s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{s, memberType, child.(android.SdkAware), export})
+ s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
+ s, memberType, child.(android.SdkAware), export, exportedComponentsInfo,
+ })
// Recurse down into the member's dependencies as it may have dependencies that need to be
// automatically added to the sdk.
@@ -245,26 +264,41 @@ func versionedSdkMemberName(ctx android.ModuleContext, memberName string, versio
// the contents (header files, stub libraries, etc) into the zip file.
func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) android.OutputPath {
- allMembersByName := make(map[string]struct{})
- exportedMembersByName := make(map[string]struct{})
+ // Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
hasLicenses := false
var memberVariantDeps []sdkMemberVariantDep
for _, sdkVariant := range sdkVariants {
memberVariantDeps = append(memberVariantDeps, sdkVariant.memberVariantDeps...)
+ }
- // Record the names of all the members, both explicitly specified and implicitly
- // included.
- for _, memberVariantDep := range sdkVariant.memberVariantDeps {
- name := memberVariantDep.variant.Name()
- allMembersByName[name] = struct{}{}
+ // Filter out any sdkMemberVariantDep that is a component of another.
+ memberVariantDeps = filterOutComponents(ctx, memberVariantDeps)
- if memberVariantDep.export {
- exportedMembersByName[name] = struct{}{}
- }
+ // Record the names of all the members, both explicitly specified and implicitly
+ // included.
+ allMembersByName := make(map[string]struct{})
+ exportedMembersByName := make(map[string]struct{})
- if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
- hasLicenses = true
- }
+ addMember := func(name string, export bool) {
+ allMembersByName[name] = struct{}{}
+ if export {
+ exportedMembersByName[name] = struct{}{}
+ }
+ }
+
+ for _, memberVariantDep := range memberVariantDeps {
+ name := memberVariantDep.variant.Name()
+ export := memberVariantDep.export
+
+ addMember(name, export)
+
+ // Add any components provided by the module.
+ for _, component := range memberVariantDep.exportedComponentsInfo.Components {
+ addMember(component, export)
+ }
+
+ if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
+ hasLicenses = true
}
}
@@ -423,6 +457,47 @@ be unnecessary as every module in the sdk already has its own licenses property.
return outputZipFile
}
+// filterOutComponents removes any item from the deps list that is a component of another item in
+// the deps list, e.g. if the deps list contains "foo" and "foo.stubs" which is component of "foo"
+// then it will remove "foo.stubs" from the deps.
+func filterOutComponents(ctx android.ModuleContext, deps []sdkMemberVariantDep) []sdkMemberVariantDep {
+ // Collate the set of components that all the modules added to the sdk provide.
+ components := map[string]*sdkMemberVariantDep{}
+ for i, _ := range deps {
+ dep := &deps[i]
+ for _, c := range dep.exportedComponentsInfo.Components {
+ components[c] = dep
+ }
+ }
+
+ // If no module provides components then return the input deps unfiltered.
+ if len(components) == 0 {
+ return deps
+ }
+
+ filtered := make([]sdkMemberVariantDep, 0, len(deps))
+ for _, dep := range deps {
+ name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(dep.variant))
+ if owner, ok := components[name]; ok {
+ // This is a component of another module that is a member of the sdk.
+
+ // If the component is exported but the owning module is not then the configuration is not
+ // supported.
+ if dep.export && !owner.export {
+ ctx.ModuleErrorf("Module %s is internal to the SDK but provides component %s which is used outside the SDK")
+ continue
+ }
+
+ // This module must not be added to the list of members of the sdk as that would result in a
+ // duplicate module in the sdk snapshot.
+ continue
+ }
+
+ filtered = append(filtered, dep)
+ }
+ return filtered
+}
+
// addSnapshotModule adds the sdk_snapshot/module_exports_snapshot module to the builder.
func (s *sdk) addSnapshotModule(ctx android.ModuleContext, builder *snapshotBuilder, sdkVariants []*sdk, memberVariantDeps []sdkMemberVariantDep) {
bpFile := builder.bpFile
@@ -742,13 +817,13 @@ func generateBpContents(contents *generatedContents, bpFile *bpFile) {
}
func generateFilteredBpContents(contents *generatedContents, bpFile *bpFile, moduleFilter func(module *bpModule) bool) {
- contents.Printfln("// This is auto-generated. DO NOT EDIT.")
+ contents.IndentedPrintf("// This is auto-generated. DO NOT EDIT.\n")
for _, bpModule := range bpFile.order {
if moduleFilter(bpModule) {
- contents.Printfln("")
- contents.Printfln("%s {", bpModule.moduleType)
+ contents.IndentedPrintf("\n")
+ contents.IndentedPrintf("%s {\n", bpModule.moduleType)
outputPropertySet(contents, bpModule.bpPropertySet)
- contents.Printfln("}")
+ contents.IndentedPrintf("}\n")
}
}
}
@@ -759,7 +834,7 @@ func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
addComment := func(name string) {
if text, ok := set.comments[name]; ok {
for _, line := range strings.Split(text, "\n") {
- contents.Printfln("// %s", line)
+ contents.IndentedPrintf("// %s\n", line)
}
}
}
@@ -776,29 +851,8 @@ func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
}
addComment(name)
- switch v := value.(type) {
- case []string:
- length := len(v)
- if length > 1 {
- contents.Printfln("%s: [", name)
- contents.Indent()
- for i := 0; i < length; i = i + 1 {
- contents.Printfln("%q,", v[i])
- }
- contents.Dedent()
- contents.Printfln("],")
- } else if length == 0 {
- contents.Printfln("%s: [],", name)
- } else {
- contents.Printfln("%s: [%q],", name, v[0])
- }
-
- case bool:
- contents.Printfln("%s: %t,", name, v)
-
- default:
- contents.Printfln("%s: %q,", name, value)
- }
+ reflectValue := reflect.ValueOf(value)
+ outputNamedValue(contents, name, reflectValue)
}
for _, name := range set.order {
@@ -808,15 +862,94 @@ func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
switch v := value.(type) {
case *bpPropertySet:
addComment(name)
- contents.Printfln("%s: {", name)
+ contents.IndentedPrintf("%s: {\n", name)
outputPropertySet(contents, v)
- contents.Printfln("},")
+ contents.IndentedPrintf("},\n")
}
}
contents.Dedent()
}
+// outputNamedValue outputs a value that has an associated name. The name will be indented, followed
+// by the value and then followed by a , and a newline.
+func outputNamedValue(contents *generatedContents, name string, value reflect.Value) {
+ contents.IndentedPrintf("%s: ", name)
+ outputUnnamedValue(contents, value)
+ contents.UnindentedPrintf(",\n")
+}
+
+// outputUnnamedValue outputs a single value. The value is not indented and is not followed by
+// either a , or a newline. With multi-line values, e.g. slices, all but the first line will be
+// indented and all but the last line will end with a newline.
+func outputUnnamedValue(contents *generatedContents, value reflect.Value) {
+ valueType := value.Type()
+ switch valueType.Kind() {
+ case reflect.Bool:
+ contents.UnindentedPrintf("%t", value.Bool())
+
+ case reflect.String:
+ contents.UnindentedPrintf("%q", value)
+
+ case reflect.Ptr:
+ outputUnnamedValue(contents, value.Elem())
+
+ case reflect.Slice:
+ length := value.Len()
+ if length == 0 {
+ contents.UnindentedPrintf("[]")
+ } else {
+ firstValue := value.Index(0)
+ if length == 1 && !multiLineValue(firstValue) {
+ contents.UnindentedPrintf("[")
+ outputUnnamedValue(contents, firstValue)
+ contents.UnindentedPrintf("]")
+ } else {
+ contents.UnindentedPrintf("[\n")
+ contents.Indent()
+ for i := 0; i < length; i++ {
+ itemValue := value.Index(i)
+ contents.IndentedPrintf("")
+ outputUnnamedValue(contents, itemValue)
+ contents.UnindentedPrintf(",\n")
+ }
+ contents.Dedent()
+ contents.IndentedPrintf("]")
+ }
+ }
+
+ case reflect.Struct:
+ // Avoid unlimited recursion by requiring every structure to implement android.BpPrintable.
+ v := value.Interface()
+ if _, ok := v.(android.BpPrintable); !ok {
+ panic(fmt.Errorf("property value %#v of type %T does not implement android.BpPrintable", v, v))
+ }
+ contents.UnindentedPrintf("{\n")
+ contents.Indent()
+ for f := 0; f < valueType.NumField(); f++ {
+ fieldType := valueType.Field(f)
+ if fieldType.Anonymous {
+ continue
+ }
+ fieldValue := value.Field(f)
+ fieldName := fieldType.Name
+ propertyName := proptools.PropertyNameForField(fieldName)
+ outputNamedValue(contents, propertyName, fieldValue)
+ }
+ contents.Dedent()
+ contents.IndentedPrintf("}")
+
+ default:
+ panic(fmt.Errorf("Unknown type: %T of value %#v", value, value))
+ }
+}
+
+// multiLineValue returns true if the supplied value may require multiple lines in the output.
+func multiLineValue(value reflect.Value) bool {
+ kind := value.Kind()
+ return kind == reflect.Slice || kind == reflect.Struct
+}
+
func (s *sdk) GetAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateBpContents(contents, s.builderForTests.bpFile)
@@ -1086,9 +1219,18 @@ func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.Sd
type sdkMemberVariantDep struct {
// The sdk variant that depends (possibly indirectly) on the member variant.
sdkVariant *sdk
+
+ // The type of sdk member the variant is to be treated as.
memberType android.SdkMemberType
- variant android.SdkAware
- export bool
+
+ // The variant that is added to the sdk.
+ variant android.SdkAware
+
+ // True if the member should be exported, i.e. accessible, from outside the sdk.
+ export bool
+
+ // The names of additional component modules provided by the variant.
+ exportedComponentsInfo android.ExportedComponentsInfo
}
var _ android.SdkMember = (*sdkMember)(nil)