Merge "add the LOCAL_DISABLE_TEST_CONFIG variable"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..9f386ca
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "packages/modules/SdkExtensions"
+ }
+ ]
+}
diff --git a/android/Android.bp b/android/Android.bp
index 6124654..5d0f2b9 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -42,6 +42,7 @@
"image.go",
"license.go",
"license_kind.go",
+ "license_sdk_member.go",
"licenses.go",
"makefile_goal.go",
"makevars.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 590eceb..557e7ba 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -501,7 +501,7 @@
a.SetString("LOCAL_MODULE", name+a.SubName)
a.AddStrings("LOCAL_LICENSE_KINDS", amod.commonProperties.Effective_license_kinds...)
a.AddStrings("LOCAL_LICENSE_CONDITIONS", amod.commonProperties.Effective_license_conditions...)
- a.AddStrings("LOCAL_NOTICE_FILE", amod.commonProperties.Effective_license_text...)
+ a.AddStrings("LOCAL_NOTICE_FILE", amod.commonProperties.Effective_license_text.Strings()...)
// TODO(b/151177513): Does this code need to set LOCAL_MODULE_IS_CONTAINER ?
if amod.commonProperties.Effective_package_name != nil {
a.SetString("LOCAL_LICENSE_PACKAGE_NAME", *amod.commonProperties.Effective_package_name)
diff --git a/android/apex.go b/android/apex.go
index 60da45b..4618fe9 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -36,11 +36,16 @@
// Accessible via `ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)`
type ApexInfo struct {
// Name of the apex variation that this module (i.e. the apex variant of the module) is
- // mutated into, or "" for a platform (i.e. non-APEX) variant. Note that a module can be
- // included in multiple APEXes, in which case, the module is mutated into one or more
- // variants, each of which is for an APEX. The variants then can later be deduped if they
- // don't need to be compiled differently. This is an optimization done in
- // mergeApexVariations.
+ // mutated into, or "" for a platform (i.e. non-APEX) variant. Note that this name and the
+ // Soong module name of the APEX can be different. That happens when there is
+ // `override_apex` that overrides `apex`. In that case, both Soong modules have the same
+ // apex variation name which usually is `com.android.foo`. This name is also the `name`
+ // in the path `/apex/<name>` where this apex is activated on at runtime.
+ //
+ // Also note that a module can be included in multiple APEXes, in which case, the module is
+ // mutated into one or more variants, each of which is for an APEX. The variants then can
+ // later be deduped if they don't need to be compiled differently. This is an optimization
+ // done in mergeApexVariations.
ApexVariationName string
// ApiLevel that this module has to support at minimum.
@@ -52,11 +57,19 @@
// The list of SDK modules that the containing apexBundle depends on.
RequiredSdks SdkRefs
- // List of apexBundles that this apex variant of the module is associated with. Initially,
- // the size of this list is one because one apex variant is associated with one apexBundle.
- // When multiple apex variants are merged in mergeApexVariations, ApexInfo struct of the
- // merged variant holds the list of apexBundles that are merged together.
- InApexes []string
+ // List of Apex variant names that this module is associated with. This initially is the
+ // same as the `ApexVariationName` field. Then when multiple apex variants are merged in
+ // mergeApexVariations, ApexInfo struct of the merged variant holds the list of apexBundles
+ // that are merged together.
+ InApexVariants []string
+
+ // List of APEX Soong module names that this module is part of. Note that the list includes
+ // different variations of the same APEX. For example, if module `foo` is included in the
+ // apex `com.android.foo`, and also if there is an override_apex module
+ // `com.mycompany.android.foo` overriding `com.android.foo`, then this list contains both
+ // `com.android.foo` and `com.mycompany.android.foo`. If the APEX Soong module is a
+ // prebuilt, the name here doesn't have the `prebuilt_` prefix.
+ InApexModules []string
// Pointers to the ApexContents struct each of which is for apexBundle modules that this
// module is part of. The ApexContents gives information about which modules the apexBundle
@@ -93,23 +106,20 @@
return i.ApexVariationName == ""
}
-// InApex tells whether this apex variant of the module is part of the given apexBundle or not.
-func (i ApexInfo) InApex(apex string) bool {
- for _, a := range i.InApexes {
- if a == apex {
+// InApexVariant tells whether this apex variant of the module is part of the given apexVariant or
+// not.
+func (i ApexInfo) InApexVariant(apexVariant string) bool {
+ for _, a := range i.InApexVariants {
+ if a == apexVariant {
return true
}
}
return false
}
-// InApexByBaseName tells whether this apex variant of the module is part of the given APEX or not,
-// where the APEX is specified by its canonical base name, i.e. typically beginning with
-// "com.android.". In particular this function doesn't differentiate between source and prebuilt
-// APEXes, where the latter may have "prebuilt_" prefixes.
-func (i ApexInfo) InApexByBaseName(apex string) bool {
- for _, a := range i.InApexes {
- if RemoveOptionalPrebuiltPrefix(a) == apex {
+func (i ApexInfo) InApexModule(apexModuleName string) bool {
+ for _, a := range i.InApexModules {
+ if a == apexModuleName {
return true
}
}
@@ -203,6 +213,12 @@
// apex_available property of the module.
AvailableFor(what string) bool
+ // AlwaysRequiresPlatformApexVariant allows the implementing module to determine whether an
+ // APEX mutator should always be created for it.
+ //
+ // Returns false by default.
+ AlwaysRequiresPlatformApexVariant() bool
+
// Returns true if this module is not available to platform (i.e. apex_available property
// doesn't have "//apex_available:platform"), or shouldn't be available to platform, which
// is the case when this module depends on other module that isn't available to platform.
@@ -339,8 +355,21 @@
func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
m.apexInfosLock.Lock()
defer m.apexInfosLock.Unlock()
- for _, v := range m.apexInfos {
+ for i, v := range m.apexInfos {
if v.ApexVariationName == apex.ApexVariationName {
+ if len(apex.InApexModules) != 1 {
+ panic(fmt.Errorf("Newly created apexInfo must be for a single APEX"))
+ }
+ // Even when the ApexVariantNames are the same, the given ApexInfo might
+ // actually be for different APEX. This can happen when an APEX is
+ // overridden via override_apex. For example, there can be two apexes
+ // `com.android.foo` (from the `apex` module type) and
+ // `com.mycompany.android.foo` (from the `override_apex` module type), both
+ // of which has the same ApexVariantName `com.android.foo`. Add the apex
+ // name to the list so that it's not lost.
+ if !InList(apex.InApexModules[0], v.InApexModules) {
+ m.apexInfos[i].InApexModules = append(m.apexInfos[i].InApexModules, apex.InApexModules[0])
+ }
return
}
}
@@ -424,6 +453,11 @@
}
// Implements ApexModule
+func (m *ApexModuleBase) AlwaysRequiresPlatformApexVariant() bool {
+ return false
+}
+
+// Implements ApexModule
func (m *ApexModuleBase) NotAvailableForPlatform() bool {
return m.ApexProperties.NotAvailableForPlatform
}
@@ -485,21 +519,23 @@
// Merge the ApexInfo together. If a compatible ApexInfo exists then merge the information from
// this one into it, otherwise create a new merged ApexInfo from this one and save it away so
// other ApexInfo instances can be merged into it.
- apexName := apexInfo.ApexVariationName
+ variantName := apexInfo.ApexVariationName
mergedName := apexInfo.mergedName(ctx)
if index, exists := seen[mergedName]; exists {
// Variants having the same mergedName are deduped
- merged[index].InApexes = append(merged[index].InApexes, apexName)
+ merged[index].InApexVariants = append(merged[index].InApexVariants, variantName)
+ merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
} else {
seen[mergedName] = len(merged)
apexInfo.ApexVariationName = mergedName
- apexInfo.InApexes = CopyOf(apexInfo.InApexes)
+ apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
+ apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
merged = append(merged, apexInfo)
}
- aliases = append(aliases, [2]string{apexName, mergedName})
+ aliases = append(aliases, [2]string{variantName, mergedName})
}
return merged, aliases
}
@@ -572,15 +608,15 @@
// in the same APEX have unique APEX variations so that the module can link against the right
// variant.
func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) {
- // anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes
- // list in common. It is used instead of DepIsInSameApex because it needs to determine if
- // the dep is in the same APEX due to being directly included, not only if it is included
- // _because_ it is a dependency.
+ // anyInSameApex returns true if the two ApexInfo lists contain any values in an
+ // InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to
+ // determine if the dep is in the same APEX due to being directly included, not only if it
+ // is included _because_ it is a dependency.
anyInSameApex := func(a, b []ApexInfo) bool {
collectApexes := func(infos []ApexInfo) []string {
var ret []string
for _, info := range infos {
- ret = append(ret, info.InApexes...)
+ ret = append(ret, info.InApexVariants...)
}
return ret
}
@@ -620,8 +656,8 @@
mctx.VisitDirectDeps(func(dep Module) {
if _, ok := mctx.OtherModuleDependencyTag(dep).(CopyDirectlyInAnyApexTag); ok {
depBase := dep.(ApexModule).apexModuleBase()
- base.ApexProperties.DirectlyInAnyApex = depBase.ApexProperties.DirectlyInAnyApex
- base.ApexProperties.InAnyApex = depBase.ApexProperties.InAnyApex
+ depBase.ApexProperties.DirectlyInAnyApex = base.ApexProperties.DirectlyInAnyApex
+ depBase.ApexProperties.InAnyApex = base.ApexProperties.InAnyApex
}
})
diff --git a/android/apex_test.go b/android/apex_test.go
index 109b1c8..e112369 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -45,11 +45,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, nil, false}},
+ {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
wantAliases: [][2]string{
{"bar", "apex10000_baz_1"},
{"foo", "apex10000_baz_1"},
@@ -58,12 +58,12 @@
{
name: "don't merge version",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -73,11 +73,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -87,12 +87,12 @@
{
name: "don't merge sdks",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000_baz_2"},
@@ -102,15 +102,15 @@
{
name: "don't merge when for prebuilt_apex",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
// This one should not be merged in with the others because it is for
// a prebuilt_apex.
- {"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+ {"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
- {"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
diff --git a/android/api_levels.go b/android/api_levels.go
index 9bc7e83..84ab27c 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -158,6 +158,21 @@
// The first version that introduced 64-bit ABIs.
var FirstLp64Version = uncheckedFinalApiLevel(21)
+// Android has had various kinds of packed relocations over the years
+// (http://b/187907243).
+//
+// API level 30 is where the now-standard SHT_RELR is available.
+var FirstShtRelrVersion = uncheckedFinalApiLevel(30)
+
+// API level 28 introduced SHT_RELR when it was still Android-only, and used an
+// Android-specific relocation.
+var FirstAndroidRelrVersion = uncheckedFinalApiLevel(28)
+
+// API level 23 was when we first had the Chrome relocation packer, which is
+// obsolete and has been removed, but lld can now generate compatible packed
+// relocations itself.
+var FirstPackedRelocationsVersion = uncheckedFinalApiLevel(23)
+
// The first API level that does not require NDK code to link
// libandroid_support.
var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21)
diff --git a/android/arch.go b/android/arch.go
index c1b2c33..9ff439c 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -897,7 +897,7 @@
// Add the OS/Arch combinations, e.g. "android_arm64".
for _, archType := range osArchTypeMap[os] {
- targets = append(targets, os.Field+"_"+archType.Name)
+ targets = append(targets, GetCompoundTargetName(os, archType))
// Also add the special "linux_<arch>" and "bionic_<arch>" property structs.
if os.Linux() {
@@ -1025,7 +1025,7 @@
}
// Merges the property struct in srcValue into dst.
-func mergePropertyStruct(ctx BaseMutatorContext, dst interface{}, srcValue reflect.Value) {
+func mergePropertyStruct(ctx ArchVariantContext, dst interface{}, srcValue reflect.Value) {
src := maybeBlueprintEmbed(srcValue).Interface()
// order checks the `android:"variant_prepend"` tag to handle properties where the
@@ -1054,25 +1054,29 @@
// Returns the immediate child of the input property struct that corresponds to
// the sub-property "field".
-func getChildPropertyStruct(ctx BaseMutatorContext,
- src reflect.Value, field, userFriendlyField string) reflect.Value {
+func getChildPropertyStruct(ctx ArchVariantContext,
+ src reflect.Value, field, userFriendlyField string) (reflect.Value, bool) {
// Step into non-nil pointers to structs in the src value.
if src.Kind() == reflect.Ptr {
if src.IsNil() {
- return src
+ return reflect.Value{}, false
}
src = src.Elem()
}
// Find the requested field in the src struct.
- src = src.FieldByName(proptools.FieldNameForProperty(field))
- if !src.IsValid() {
+ child := src.FieldByName(proptools.FieldNameForProperty(field))
+ if !child.IsValid() {
ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
- return src
+ return reflect.Value{}, false
}
- return src
+ if child.IsZero() {
+ return reflect.Value{}, false
+ }
+
+ return child, true
}
// Squash the appropriate OS-specific property structs into the matching top level property structs
@@ -1099,8 +1103,9 @@
if os.Class == Host {
field := "Host"
prefix := "target.host"
- hostProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, hostProperties)
+ if hostProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, hostProperties)
+ }
}
// Handle target OS generalities of the form:
@@ -1112,15 +1117,17 @@
if os.Linux() {
field := "Linux"
prefix := "target.linux"
- linuxProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, linuxProperties)
+ if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, linuxProperties)
+ }
}
if os.Bionic() {
field := "Bionic"
prefix := "target.bionic"
- bionicProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, bionicProperties)
+ if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, bionicProperties)
+ }
}
// Handle target OS properties in the form:
@@ -1137,14 +1144,16 @@
// },
field := os.Field
prefix := "target." + os.Name
- osProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, osProperties)
+ if osProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, osProperties)
+ }
if os.Class == Host && os != Windows {
field := "Not_windows"
prefix := "target.not_windows"
- notWindowsProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, notWindowsProperties)
+ if notWindowsProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, notWindowsProperties)
+ }
}
// Handle 64-bit device properties in the form:
@@ -1164,13 +1173,15 @@
if ctx.Config().Android64() {
field := "Android64"
prefix := "target.android64"
- android64Properties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, android64Properties)
+ if android64Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, android64Properties)
+ }
} else {
field := "Android32"
prefix := "target.android32"
- android32Properties := getChildPropertyStruct(ctx, targetProp, field, prefix)
- mergePropertyStruct(ctx, genProps, android32Properties)
+ if android32Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+ mergePropertyStruct(ctx, genProps, android32Properties)
+ }
}
}
}
@@ -1186,12 +1197,11 @@
// },
// This struct will also contain sub-structs containing to the architecture/CPU
// variants and features that themselves contain properties specific to those.
-func getArchTypeStruct(ctx BaseMutatorContext, archProperties interface{}, archType ArchType) reflect.Value {
+func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
archPropValues := reflect.ValueOf(archProperties).Elem()
archProp := archPropValues.FieldByName("Arch").Elem()
prefix := "arch." + archType.Name
- archStruct := getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
- return archStruct
+ return getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
}
// Returns the struct containing the properties specific to a given multilib
@@ -1201,11 +1211,14 @@
// key: value,
// },
// },
-func getMultilibStruct(ctx BaseMutatorContext, archProperties interface{}, archType ArchType) reflect.Value {
+func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
archPropValues := reflect.ValueOf(archProperties).Elem()
multilibProp := archPropValues.FieldByName("Multilib").Elem()
- multilibProperties := getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
- return multilibProperties
+ return getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
+}
+
+func GetCompoundTargetName(os OsType, arch ArchType) string {
+ return os.Field + "_" + arch.Name
}
// Returns the structs corresponding to the properties specific to the given
@@ -1219,58 +1232,64 @@
archType := arch.ArchType
if arch.ArchType != Common {
- archStruct := getArchTypeStruct(ctx, archProperties, arch.ArchType)
- result = append(result, archStruct)
+ archStruct, ok := getArchTypeStruct(ctx, archProperties, arch.ArchType)
+ if ok {
+ result = append(result, archStruct)
- // Handle arch-variant-specific properties in the form:
- // arch: {
- // arm: {
- // variant: {
- // key: value,
- // },
- // },
- // },
- v := variantReplacer.Replace(arch.ArchVariant)
- if v != "" {
- prefix := "arch." + archType.Name + "." + v
- variantProperties := getChildPropertyStruct(ctx, archStruct, v, prefix)
- result = append(result, variantProperties)
- }
+ // Handle arch-variant-specific properties in the form:
+ // arch: {
+ // arm: {
+ // variant: {
+ // key: value,
+ // },
+ // },
+ // },
+ v := variantReplacer.Replace(arch.ArchVariant)
+ if v != "" {
+ prefix := "arch." + archType.Name + "." + v
+ if variantProperties, ok := getChildPropertyStruct(ctx, archStruct, v, prefix); ok {
+ result = append(result, variantProperties)
+ }
+ }
- // Handle cpu-variant-specific properties in the form:
- // arch: {
- // arm: {
- // variant: {
- // key: value,
- // },
- // },
- // },
- if arch.CpuVariant != arch.ArchVariant {
- c := variantReplacer.Replace(arch.CpuVariant)
- if c != "" {
- prefix := "arch." + archType.Name + "." + c
- cpuVariantProperties := getChildPropertyStruct(ctx, archStruct, c, prefix)
- result = append(result, cpuVariantProperties)
+ // Handle cpu-variant-specific properties in the form:
+ // arch: {
+ // arm: {
+ // variant: {
+ // key: value,
+ // },
+ // },
+ // },
+ if arch.CpuVariant != arch.ArchVariant {
+ c := variantReplacer.Replace(arch.CpuVariant)
+ if c != "" {
+ prefix := "arch." + archType.Name + "." + c
+ if cpuVariantProperties, ok := getChildPropertyStruct(ctx, archStruct, c, prefix); ok {
+ result = append(result, cpuVariantProperties)
+ }
+ }
+ }
+
+ // Handle arch-feature-specific properties in the form:
+ // arch: {
+ // arm: {
+ // feature: {
+ // key: value,
+ // },
+ // },
+ // },
+ for _, feature := range arch.ArchFeatures {
+ prefix := "arch." + archType.Name + "." + feature
+ if featureProperties, ok := getChildPropertyStruct(ctx, archStruct, feature, prefix); ok {
+ result = append(result, featureProperties)
+ }
}
}
- // Handle arch-feature-specific properties in the form:
- // arch: {
- // arm: {
- // feature: {
- // key: value,
- // },
- // },
- // },
- for _, feature := range arch.ArchFeatures {
- prefix := "arch." + archType.Name + "." + feature
- featureProperties := getChildPropertyStruct(ctx, archStruct, feature, prefix)
- result = append(result, featureProperties)
+ if multilibProperties, ok := getMultilibStruct(ctx, archProperties, archType); ok {
+ result = append(result, multilibProperties)
}
- multilibProperties := getMultilibStruct(ctx, archProperties, archType)
- result = append(result, multilibProperties)
-
// Handle combined OS-feature and arch specific properties in the form:
// target: {
// bionic_x86: {
@@ -1280,15 +1299,17 @@
if os.Linux() {
field := "Linux_" + arch.ArchType.Name
userFriendlyField := "target.linux_" + arch.ArchType.Name
- linuxProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
- result = append(result, linuxProperties)
+ if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
+ result = append(result, linuxProperties)
+ }
}
if os.Bionic() {
field := "Bionic_" + archType.Name
userFriendlyField := "target.bionic_" + archType.Name
- bionicProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
- result = append(result, bionicProperties)
+ if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
+ result = append(result, bionicProperties)
+ }
}
// Handle combined OS and arch specific properties in the form:
@@ -1306,10 +1327,11 @@
// key: value,
// },
// },
- field := os.Field + "_" + archType.Name
+ field := GetCompoundTargetName(os, archType)
userFriendlyField := "target." + os.Name + "_" + archType.Name
- osArchProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
- result = append(result, osArchProperties)
+ if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
+ result = append(result, osArchProperties)
+ }
}
// Handle arm on x86 properties in the form:
@@ -1326,21 +1348,24 @@
hasArmAndroidArch(ctx.Config().Targets[Android])) {
field := "Arm_on_x86"
userFriendlyField := "target.arm_on_x86"
- armOnX86Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
- result = append(result, armOnX86Properties)
+ if armOnX86Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
+ result = append(result, armOnX86Properties)
+ }
}
if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Android])) {
field := "Arm_on_x86_64"
userFriendlyField := "target.arm_on_x86_64"
- armOnX8664Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
- result = append(result, armOnX8664Properties)
+ if armOnX8664Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
+ result = append(result, armOnX8664Properties)
+ }
}
if os == Android && nativeBridgeEnabled {
userFriendlyField := "Native_bridge"
prefix := "target.native_bridge"
- nativeBridgeProperties := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix)
- result = append(result, nativeBridgeProperties)
+ if nativeBridgeProperties, ok := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix); ok {
+ result = append(result, nativeBridgeProperties)
+ }
}
}
@@ -1851,6 +1876,12 @@
return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
}
+// ArchVariantContext defines the limited context necessary to retrieve arch_variant properties.
+type ArchVariantContext interface {
+ ModuleErrorf(fmt string, args ...interface{})
+ PropertyErrorf(property, fmt string, args ...interface{})
+}
+
// GetArchProperties returns a map of architectures to the values of the
// properties of the 'propertySet' struct that are specific to that architecture.
//
@@ -1863,7 +1894,9 @@
// For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }`
// will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given
// propertyset contains `Foo []string`.
-func (m *ModuleBase) GetArchProperties(ctx BaseMutatorContext, propertySet interface{}) map[ArchType]interface{} {
+//
+// Implemented in a way very similar to GetTargetProperties().
+func (m *ModuleBase) GetArchProperties(ctx ArchVariantContext, propertySet interface{}) map[ArchType]interface{} {
// Return value of the arch types to the prop values for that arch.
archToProp := map[ArchType]interface{}{}
@@ -1897,9 +1930,14 @@
// input one that contains the data specific to that arch.
propertyStructs := make([]reflect.Value, 0)
for _, archProperty := range archProperties {
- archTypeStruct := getArchTypeStruct(ctx, archProperty, arch)
- multilibStruct := getMultilibStruct(ctx, archProperty, arch)
- propertyStructs = append(propertyStructs, archTypeStruct, multilibStruct)
+ archTypeStruct, ok := getArchTypeStruct(ctx, archProperty, arch)
+ if ok {
+ propertyStructs = append(propertyStructs, archTypeStruct)
+ }
+ multilibStruct, ok := getMultilibStruct(ctx, archProperty, arch)
+ if ok {
+ propertyStructs = append(propertyStructs, multilibStruct)
+ }
}
// Create a new instance of the requested property set
@@ -1916,89 +1954,104 @@
return archToProp
}
+// Returns a struct matching the propertySet interface, containing properties specific to the targetName
+// For example, given these arguments:
+// propertySet = BaseCompilerProperties
+// targetName = "android_arm"
+// And given this Android.bp fragment:
+// target:
+// android_arm: {
+// srcs: ["foo.c"],
+// }
+// android_arm64: {
+// srcs: ["bar.c"],
+// }
+// }
+// This would return a BaseCompilerProperties with BaseCompilerProperties.Srcs = ["foo.c"]
+func getTargetStruct(ctx ArchVariantContext, propertySet interface{}, archProperties []interface{}, targetName string) interface{} {
+ propertyStructs := make([]reflect.Value, 0)
+ for _, archProperty := range archProperties {
+ archPropValues := reflect.ValueOf(archProperty).Elem()
+ targetProp := archPropValues.FieldByName("Target").Elem()
+ targetStruct, ok := getChildPropertyStruct(ctx, targetProp, targetName, targetName)
+ if ok {
+ propertyStructs = append(propertyStructs, targetStruct)
+ }
+ }
+
+ // Create a new instance of the requested property set
+ value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
+
+ // Merge all the structs together
+ for _, propertyStruct := range propertyStructs {
+ mergePropertyStruct(ctx, value, propertyStruct)
+ }
+
+ return value
+}
+
+// Properties corresponds to e.g. Target: android: {...}
+// ArchProperties corresponds to e.g. Target: android_arm: {...}, android_arm64: {...}, ...
+type TargetProperties struct {
+ Properties interface{}
+ ArchProperties map[ArchType]interface{}
+}
+
// GetTargetProperties returns a map of OS target (e.g. android, windows) to the
-// values of the properties of the 'dst' struct that are specific to that OS
-// target.
+// values of the properties of the 'propertySet' struct that are specific to
+// that OS target.
//
// For example, passing a struct { Foo bool, Bar string } will return an
// interface{} that can be type asserted back into the same struct, containing
// the os-specific property value specified by the module if defined.
//
-// While this looks similar to GetArchProperties, the internal representation of
-// the properties have a slightly different layout to warrant a standalone
-// lookup function.
-func (m *ModuleBase) GetTargetProperties(dst interface{}) map[OsType]interface{} {
- // Return value of the arch types to the prop values for that arch.
- osToProp := map[OsType]interface{}{}
+// Implemented in a way very similar to GetArchProperties().
+//
+// NOTE: "Target" == OS
+func (m *ModuleBase) GetTargetProperties(ctx ArchVariantContext, propertySet interface{}) map[OsType]TargetProperties {
+ // Return value of the target types to the prop values for that target.
+ targetToProp := map[OsType]TargetProperties{}
- // Nothing to do for non-OS/arch-specific modules.
+ // Nothing to do for non-target-specific modules.
if !m.ArchSpecific() {
- return osToProp
+ return targetToProp
}
- // archProperties has the type of [][]interface{}. Looks complicated, so
- // let's explain this step by step.
- //
- // Loop over the outer index, which determines the property struct that
- // contains a matching set of properties in dst that we're interested in.
- // For example, BaseCompilerProperties or BaseLinkerProperties.
- for i := range m.archProperties {
- if m.archProperties[i] == nil {
+ dstType := reflect.ValueOf(propertySet).Type()
+ var archProperties []interface{}
+
+ // First find the property set in the module that corresponds to the requested
+ // one. m.archProperties[i] corresponds to m.generalProperties[i].
+ for i, generalProp := range m.generalProperties {
+ srcType := reflect.ValueOf(generalProp).Type()
+ if srcType == dstType {
+ archProperties = m.archProperties[i]
+ break
+ }
+ }
+
+ if archProperties == nil {
+ // This module does not have the property set requested
+ return targetToProp
+ }
+
+ // For android, linux, ...
+ for _, os := range osTypeList {
+ if os == CommonOS {
+ // It looks like this OS value is not used in Blueprint files
continue
}
-
- // Iterate over the supported OS types
- for _, os := range osTypeList {
- // e.g android, linux_bionic
- field := os.Field
-
- // If it's not nil, loop over the inner index, which determines the arch variant
- // of the prop type. In an Android.bp file, this is like looping over:
- //
- // target: { android: { key: value, ... }, linux_bionic: { key: value, ... } }
- for _, archProperties := range m.archProperties[i] {
- archPropValues := reflect.ValueOf(archProperties).Elem()
-
- // This is the archPropRoot struct. Traverse into the Targetnested struct.
- src := archPropValues.FieldByName("Target").Elem()
-
- // Step into non-nil pointers to structs in the src value.
- if src.Kind() == reflect.Ptr {
- if src.IsNil() {
- continue
- }
- src = src.Elem()
- }
-
- // Find the requested field (e.g. android, linux_bionic) in the src struct.
- src = src.FieldByName(field)
-
- // Validation steps. We want valid non-nil pointers to structs.
- if !src.IsValid() || src.IsNil() {
- continue
- }
-
- if src.Kind() != reflect.Ptr || src.Elem().Kind() != reflect.Struct {
- continue
- }
-
- // Clone the destination prop, since we want a unique prop struct per arch.
- dstClone := reflect.New(reflect.ValueOf(dst).Elem().Type()).Interface()
-
- // Copy the located property struct into the cloned destination property struct.
- err := proptools.ExtendMatchingProperties([]interface{}{dstClone}, src.Interface(), nil, proptools.OrderReplace)
- if err != nil {
- // This is fine, it just means the src struct doesn't match.
- continue
- }
-
- // Found the prop for the os, you have.
- osToProp[os] = dstClone
-
- // Go to the next prop.
- break
- }
+ targetProperties := TargetProperties{
+ Properties: getTargetStruct(ctx, propertySet, archProperties, os.Field),
+ ArchProperties: make(map[ArchType]interface{}),
}
+ // For arm, x86, ...
+ for _, arch := range osArchTypeMap[os] {
+ targetName := GetCompoundTargetName(os, arch)
+ targetProperties.ArchProperties[arch] = getTargetStruct(ctx, propertySet, archProperties, targetName)
+ }
+ targetToProp[os] = targetProperties
}
- return osToProp
+
+ return targetToProp
}
diff --git a/android/bazel.go b/android/bazel.go
index 6c476a7..4967b12 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -126,40 +126,20 @@
)
var (
- // Do not write BUILD files for these directories
- // NOTE: this is not recursive
- bp2buildDoNotWriteBuildFileList = []string{
- // Don't generate these BUILD files - because external BUILD files already exist
- "external/boringssl",
- "external/brotli",
- "external/dagger2",
- "external/flatbuffers",
- "external/gflags",
- "external/google-fruit",
- "external/grpc-grpc",
- "external/grpc-grpc/test/core/util",
- "external/grpc-grpc/test/cpp/common",
- "external/grpc-grpc/third_party/address_sorting",
- "external/nanopb-c",
- "external/nos/host/generic",
- "external/nos/host/generic/libnos",
- "external/nos/host/generic/libnos/generator",
- "external/nos/host/generic/libnos_datagram",
- "external/nos/host/generic/libnos_transport",
- "external/nos/host/generic/nugget/proto",
- "external/perfetto",
- "external/protobuf",
- "external/rust/cxx",
- "external/rust/cxx/demo",
- "external/ruy",
- "external/tensorflow",
- "external/tensorflow/tensorflow/lite",
- "external/tensorflow/tensorflow/lite/java",
- "external/tensorflow/tensorflow/lite/kernels",
- "external/tflite-support",
- "external/tinyalsa_new",
- "external/wycheproof",
- "external/libyuv",
+ // Keep any existing BUILD files (and do not generate new BUILD files) for these directories
+ bp2buildKeepExistingBuildFile = map[string]bool{
+ // This is actually build/bazel/build.BAZEL symlinked to ./BUILD
+ ".":/*recrusive = */ false,
+
+ "build/bazel":/* recursive = */ true,
+ "build/pesto":/* recursive = */ true,
+
+ // external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
+ // e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
+ "external/bazelbuild-rules_android":/* recursive = */ true,
+
+ "prebuilts/sdk":/* recursive = */ false,
+ "prebuilts/sdk/tools":/* recursive = */ false,
}
// Configure modules in these directories to enable bp2build_available: true or false by default.
@@ -173,19 +153,13 @@
"external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
+ "external/scudo": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
}
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
// Things that transitively depend on unconverted libc_* modules.
- "libc_nopthread", // http://b/186821550, cc_library_static, depends on //bionic/libc:libc_bionic_ndk (http://b/186822256)
- // also depends on //bionic/libc:libc_tzcode (http://b/186822591)
- // also depends on //bionic/libc:libstdc++ (http://b/186822597)
- "libc_common", // http://b/186821517, cc_library_static, depends on //bionic/libc:libc_nopthread (http://b/186821550)
- "libc_common_static", // http://b/186824119, cc_library_static, depends on //bionic/libc:libc_common (http://b/186821517)
- "libc_common_shared", // http://b/186824118, cc_library_static, depends on //bionic/libc:libc_common (http://b/186821517)
- "libc_nomalloc", // http://b/186825031, cc_library_static, depends on //bionic/libc:libc_common (http://b/186821517)
-
"libbionic_spawn_benchmark", // http://b/186824595, cc_library_static, depends on //external/google-benchmark (http://b/186822740)
// also depends on //system/logging/liblog:liblog (http://b/186822772)
@@ -204,13 +178,10 @@
"liblinker_malloc", // http://b/186826466, cc_library_static, depends on //external/zlib:libz (http://b/186823782)
// also depends on //system/libziparchive:libziparchive (http://b/186823656)
// also depends on //system/logging/liblog:liblog (http://b/186822772)
- "libc_jemalloc_wrapper", // http://b/187012490, cc_library_static, depends on //external/jemalloc_new:libjemalloc5 (http://b/186828626)
- "libc_ndk", // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
- "libc", // http://b/183064430, cc_library, depends on //external/jemalloc_new:libjemalloc5 (http://b/186828626)
- "libc_tzcode", // http://b/186822591, cc_library_static, localtime.c:84:46: error: expected expression
- "libc_bionic_ndk", // http://b/186822256, cc_library_static, signal.cpp:186:52: error: ISO C++ requires field designators to be specified in declaration order
- "libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
- "libm", // http://b/183064661, cc_library, math.h:25:16: error: unexpected token in argument list
+ "libc_ndk", // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
+ "libc", // http://b/183064430, cc_library, depends on //external/jemalloc_new:libjemalloc5 (http://b/186828626)
+ "libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
+ "libm", // http://b/183064661, cc_library, math.h:25:16: error: unexpected token in argument list
// http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx
// c++_static
@@ -218,6 +189,7 @@
// libcxx
"libBionicBenchmarksUtils", // cc_library_static, fatal error: 'map' file not found, from libcxx
"fmtlib", // cc_library_static, fatal error: 'cassert' file not found, from libcxx
+ "fmtlib_ndk", // cc_library_static, fatal error: 'cassert' file not found
"libbase", // http://b/186826479, cc_library, fatal error: 'memory' file not found, from libcxx
// http://b/186024507: Includes errors because of the system_shared_libs default value.
@@ -229,6 +201,8 @@
"note_memtag_heap_async", // http://b/185127353: cc_library_static, error: feature.h not found
"note_memtag_heap_sync", // http://b/185127353: cc_library_static, error: feature.h not found
+ "gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
+
// Tests. Handle later.
"libbionic_tests_headers_posix", // http://b/186024507, cc_library_static, sched.h, time.h not found
"libjemalloc5_integrationtest",
@@ -239,32 +213,24 @@
// Per-module denylist of cc_library modules to only generate the static
// variant if their shared variant isn't ready or buildable by Bazel.
bp2buildCcLibraryStaticOnlyList = []string{
- "libstdc++", // http://b/186822597, cc_library, ld.lld: error: undefined symbol: __errno
+ "libstdc++", // http://b/186822597, cc_library, ld.lld: error: undefined symbol: __errno
+ "libjemalloc5", // http://b/188503688, cc_library, `target: { android: { enabled: false } }` for android targets.
}
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
mixedBuildsDisabledList = []string{
- "libc_netbsd", // lberki@, cc_library_static, version script assignment of 'LIBC_PRIVATE' to symbol 'SHA1Final' failed: symbol not defined
- "libc_openbsd", // ruperts@, cc_library_static, OK for bp2build but error: duplicate symbol: strcpy for mixed builds
- "libsystemproperties", // cparsons@, cc_library_static, wrong include paths
- "libpropertyinfoparser", // cparsons@, cc_library_static, wrong include paths
- "libarm-optimized-routines-string", // jingwen@, cc_library_static, OK for bp2build but b/186615213 (asflags not handled in bp2build), version script assignment of 'LIBC' to symbol 'memcmp' failed: symbol not defined (also for memrchr, strnlen)
- "fmtlib_ndk", // http://b/187040371, cc_library_static, OK for bp2build but format-inl.h:11:10: fatal error: 'cassert' file not found for mixed builds
+ "libc_common_shared", // cparsons@ cc_library_static, breaks module `libc`.
+ "libc_nomalloc", // cparsons@ cc_library_static, breaks module `linker`
}
// Used for quicker lookups
- bp2buildDoNotWriteBuildFile = map[string]bool{}
bp2buildModuleDoNotConvert = map[string]bool{}
bp2buildCcLibraryStaticOnly = map[string]bool{}
mixedBuildsDisabled = map[string]bool{}
)
func init() {
- for _, moduleName := range bp2buildDoNotWriteBuildFileList {
- bp2buildDoNotWriteBuildFile[moduleName] = true
- }
-
for _, moduleName := range bp2buildModuleDoNotConvertList {
bp2buildModuleDoNotConvert[moduleName] = true
}
@@ -282,12 +248,21 @@
return bp2buildCcLibraryStaticOnly[ctx.Module().Name()]
}
-func ShouldWriteBuildFileForDir(dir string) bool {
- if _, ok := bp2buildDoNotWriteBuildFile[dir]; ok {
- return false
- } else {
+func ShouldKeepExistingBuildFileForDir(dir string) bool {
+ if _, ok := bp2buildKeepExistingBuildFile[dir]; ok {
+ // Exact dir match
return true
}
+ // Check if subtree match
+ for prefix, recursive := range bp2buildKeepExistingBuildFile {
+ if recursive {
+ if strings.HasPrefix(dir, prefix+"/") {
+ return true
+ }
+ }
+ }
+ // Default
+ return false
}
// MixedBuildsEnabled checks that a module is ready to be replaced by a
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 4598995..a1206dc 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -333,7 +333,7 @@
// The actual platform values here may be overridden by configuration
// transitions from the buildroot.
cmdFlags = append(cmdFlags,
- fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_x86_64"))
+ fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_arm"))
cmdFlags = append(cmdFlags,
fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
// This should be parameterized on the host OS, but let's restrict to linux
@@ -347,7 +347,10 @@
bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
- bazelCmd.Env = append(os.Environ(), "HOME="+paths.homeDir, pwdPrefix(),
+ bazelCmd.Env = append(os.Environ(),
+ "HOME="+paths.homeDir,
+ pwdPrefix(),
+ "BUILD_DIR="+absolutePath(paths.buildDir),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1")
@@ -564,7 +567,7 @@
// Returns the path where the contents of the @soong_injection repository live.
// It is used by Soong to tell Bazel things it cannot over the command line.
func (p *bazelPaths) injectedFilesDir() string {
- return filepath.Join(p.buildDir, "soong_injection")
+ return filepath.Join(p.buildDir, bazel.SoongInjectionDirName)
}
// Returns the path of the synthetic Bazel workspace that contains a symlink
@@ -583,8 +586,9 @@
var err error
soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
- if _, err := os.Stat(soongInjectionPath); os.IsNotExist(err) {
- err = os.Mkdir(soongInjectionPath, 0777)
+ mixedBuildsPath := filepath.Join(soongInjectionPath, "mixed_builds")
+ if _, err := os.Stat(mixedBuildsPath); os.IsNotExist(err) {
+ err = os.MkdirAll(mixedBuildsPath, 0777)
}
if err != nil {
return err
@@ -596,14 +600,14 @@
}
err = ioutil.WriteFile(
- filepath.Join(soongInjectionPath, "main.bzl"),
+ filepath.Join(mixedBuildsPath, "main.bzl"),
context.mainBzlFileContents(), 0666)
if err != nil {
return err
}
err = ioutil.WriteFile(
- filepath.Join(soongInjectionPath, "BUILD.bazel"),
+ filepath.Join(mixedBuildsPath, "BUILD.bazel"),
context.mainBuildFileContents(), 0666)
if err != nil {
return err
@@ -615,7 +619,7 @@
if err != nil {
return err
}
- buildrootLabel := "@soong_injection//:buildroot"
+ buildrootLabel := "@soong_injection//mixed_builds:buildroot"
cqueryOutput, cqueryErr, err = context.issueBazelCommand(
context.paths,
bazel.CqueryBuildRootRunName,
@@ -676,7 +680,7 @@
_, _, err = context.issueBazelCommand(
context.paths,
bazel.BazelBuildPhonyRootRunName,
- bazelCommand{"build", "@soong_injection//:phonyroot"})
+ bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"})
if err != nil {
return err
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index cb25fee..f1fabec 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -11,7 +11,7 @@
label := "//foo:bar"
arch := Arm64
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "cquery", expression: "kind(rule, deps(@soong_injection//:buildroot))"}: `//foo:bar|arm64>>out/foo/bar.txt`,
+ bazelCommand{command: "cquery", expression: "kind(rule, deps(@soong_injection//mixed_builds:buildroot))"}: `//foo:bar|arm64>>out/foo/bar.txt`,
})
g, ok := bazelContext.GetOutputFiles(label, arch)
if ok {
@@ -35,13 +35,13 @@
if err != nil {
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "main.bzl")); os.IsNotExist(err) {
+ if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "main.bzl")); os.IsNotExist(err) {
t.Errorf("Expected main.bzl to exist, but it does not")
} else if err != nil {
t.Errorf("Unexpected error stating main.bzl %s", err)
}
- if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "BUILD.bazel")); os.IsNotExist(err) {
+ if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "BUILD.bazel")); os.IsNotExist(err) {
t.Errorf("Expected BUILD.bazel to exist, but it does not")
} else if err != nil {
t.Errorf("Unexpected error stating BUILD.bazel %s", err)
@@ -56,7 +56,7 @@
func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "aquery", expression: "deps(@soong_injection//:buildroot)"}: `
+ bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: `
{
"artifacts": [{
"id": 1,
@@ -105,7 +105,7 @@
outputBase: "outputbase",
workspaceDir: "workspace_dir",
}
- aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//:buildroot)"}
+ aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}
if _, exists := bazelCommandResults[aqueryCommand]; !exists {
bazelCommandResults[aqueryCommand] = "{}\n"
}
diff --git a/android/config.go b/android/config.go
index 3db7980..da78c7a 100644
--- a/android/config.go
+++ b/android/config.go
@@ -35,6 +35,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android/soongconfig"
+ "android/soong/bazel"
"android/soong/remoteexec"
)
@@ -169,7 +170,7 @@
// loadFromConfigFile loads and decodes configuration options from a JSON file
// in the current working directory.
-func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
+func loadFromConfigFile(configurable *productVariables, filename string) error {
// Try to open the file
configFileReader, err := os.Open(filename)
defer configFileReader.Close()
@@ -194,13 +195,20 @@
}
}
- // No error
- return nil
+ if Bool(configurable.GcovCoverage) && Bool(configurable.ClangCoverage) {
+ return fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
+ }
+
+ configurable.Native_coverage = proptools.BoolPtr(
+ Bool(configurable.GcovCoverage) ||
+ Bool(configurable.ClangCoverage))
+
+ return saveToBazelConfigFile(configurable, filepath.Dir(filename))
}
// atomically writes the config file in case two copies of soong_build are running simultaneously
// (for example, docs generation and ninja manifest generation)
-func saveToConfigFile(config jsonConfigurable, filename string) error {
+func saveToConfigFile(config *productVariables, filename string) error {
data, err := json.MarshalIndent(&config, "", " ")
if err != nil {
return fmt.Errorf("cannot marshal config data: %s", err.Error())
@@ -229,6 +237,35 @@
return nil
}
+func saveToBazelConfigFile(config *productVariables, outDir string) error {
+ dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
+ err := createDirIfNonexistent(dir, os.ModePerm)
+ if err != nil {
+ return fmt.Errorf("Could not create dir %s: %s", dir, err)
+ }
+
+ data, err := json.MarshalIndent(&config, "", " ")
+ if err != nil {
+ return fmt.Errorf("cannot marshal config data: %s", err.Error())
+ }
+
+ bzl := []string{
+ bazel.GeneratedBazelFileWarning,
+ fmt.Sprintf(`_product_vars = json.decode("""%s""")`, data),
+ "product_vars = _product_vars\n",
+ }
+ err = ioutil.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
+ if err != nil {
+ return fmt.Errorf("Could not write .bzl config file %s", err)
+ }
+ err = ioutil.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
+ if err != nil {
+ return fmt.Errorf("Could not write BUILD config file %s", err)
+ }
+
+ return nil
+}
+
// NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
// use the android package.
func NullConfig(buildDir string) Config {
@@ -448,14 +485,6 @@
config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
}
- if Bool(config.productVariables.GcovCoverage) && Bool(config.productVariables.ClangCoverage) {
- return Config{}, fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
- }
-
- config.productVariables.Native_coverage = proptools.BoolPtr(
- Bool(config.productVariables.GcovCoverage) ||
- Bool(config.productVariables.ClangCoverage))
-
config.BazelContext, err = NewBazelContext(config)
config.bp2buildPackageConfig = bp2buildDefaultConfig
config.bp2buildModuleTypeConfig = make(map[string]bool)
@@ -1564,6 +1593,15 @@
return false
}
+// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
+// an empty string if not found.
+func (l *ConfiguredJarList) ApexOfJar(jar string) string {
+ if idx := IndexList(jar, l.jars); idx != -1 {
+ return l.Apex(IndexList(jar, l.jars))
+ }
+ return ""
+}
+
// IndexOfJar returns the first pair with the given jar name on the list, or -1
// if not found.
func (l *ConfiguredJarList) IndexOfJar(jar string) int {
@@ -1609,6 +1647,21 @@
return ConfiguredJarList{apexes, jars}
}
+// Filter keeps the entries if a jar appears in the given list of jars to keep; returns a new list.
+func (l *ConfiguredJarList) Filter(jarsToKeep []string) ConfiguredJarList {
+ var apexes []string
+ var jars []string
+
+ for i, jar := range l.jars {
+ if InList(jar, jarsToKeep) {
+ apexes = append(apexes, l.apexes[i])
+ jars = append(jars, jar)
+ }
+ }
+
+ return ConfiguredJarList{apexes, jars}
+}
+
// CopyOfJars returns a copy of the list of strings containing jar module name
// components.
func (l *ConfiguredJarList) CopyOfJars() []string {
diff --git a/android/defaults.go b/android/defaults.go
index aacfbac..be80cf1 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -104,6 +104,7 @@
EarlyModuleContext
CreateModule(ModuleFactory, ...interface{}) Module
+ AddMissingDependencies(missingDeps []string)
}
type DefaultableHook func(ctx DefaultableHookContext)
diff --git a/android/license.go b/android/license.go
index cb375a2..8bfd3ba 100644
--- a/android/license.go
+++ b/android/license.go
@@ -61,7 +61,17 @@
}
func (m *licenseModule) GenerateAndroidBuildActions(ctx ModuleContext) {
- // Nothing to do.
+ // license modules have no licenses, but license_kinds must refer to license_kind modules
+ mergeStringProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName())
+ mergePathProps(&m.base().commonProperties.Effective_license_text, PathsForModuleSrc(ctx, m.properties.License_text)...)
+ for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
+ if lk, ok := module.(*licenseKindModule); ok {
+ mergeStringProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...)
+ mergeStringProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module))
+ } else {
+ ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
+ }
+ }
}
func LicenseFactory() Module {
diff --git a/android/license_sdk_member.go b/android/license_sdk_member.go
new file mode 100644
index 0000000..cd36ed6
--- /dev/null
+++ b/android/license_sdk_member.go
@@ -0,0 +1,118 @@
+// 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 android
+
+import (
+ "path/filepath"
+
+ "github.com/google/blueprint"
+)
+
+// Contains support for adding license modules to an sdk.
+
+func init() {
+ RegisterSdkMemberType(LicenseModuleSdkMemberType)
+}
+
+// licenseSdkMemberType determines how a license module is added to the sdk.
+type licenseSdkMemberType struct {
+ SdkMemberTypeBase
+}
+
+func (l *licenseSdkMemberType) AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ // Add dependencies onto the license module from the sdk module.
+ mctx.AddDependency(mctx.Module(), dependencyTag, names...)
+}
+
+func (l *licenseSdkMemberType) IsInstance(module Module) bool {
+ // Verify that the module being added is compatible with this module type.
+ _, ok := module.(*licenseModule)
+ return ok
+}
+
+func (l *licenseSdkMemberType) AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule {
+ // Add the basics of a prebuilt module.
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "license")
+}
+
+func (l *licenseSdkMemberType) CreateVariantPropertiesStruct() SdkMemberProperties {
+ // Create the structure into which the properties of the license module that need to be output to
+ // the snapshot will be placed. The structure may be populated with information from a variant or
+ // may be used as the destination for properties that are common to a set of variants.
+ return &licenseSdkMemberProperties{}
+}
+
+// LicenseModuleSdkMemberType is the instance of licenseSdkMemberType
+var LicenseModuleSdkMemberType = &licenseSdkMemberType{
+ SdkMemberTypeBase{
+ PropertyName: "licenses",
+
+ // This should never be added directly to an sdk/module_exports, all license modules should be
+ // added indirectly as transitive dependencies of other sdk members.
+ BpPropertyNotRequired: true,
+
+ SupportsSdk: true,
+
+ // The snapshot of the license module is just another license module (not a prebuilt). They are
+ // internal modules only so will have an sdk specific name that will not clash with the
+ // originating source module.
+ UseSourceModuleTypeInSnapshot: true,
+ },
+}
+
+var _ SdkMemberType = (*licenseSdkMemberType)(nil)
+
+// licenseSdkMemberProperties is the set of properties that need to be added to the license module
+// in the snapshot.
+type licenseSdkMemberProperties struct {
+ SdkMemberPropertiesBase
+
+ // The kinds of licenses provided by the module.
+ License_kinds []string
+
+ // The source paths to the files containing license text.
+ License_text Paths
+}
+
+func (p *licenseSdkMemberProperties) PopulateFromVariant(_ SdkMemberContext, variant Module) {
+ // Populate the properties from the variant.
+ l := variant.(*licenseModule)
+ p.License_kinds = l.properties.License_kinds
+ p.License_text = l.base().commonProperties.Effective_license_text
+}
+
+func (p *licenseSdkMemberProperties) AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet) {
+ // Just pass any specified license_kinds straight through.
+ if len(p.License_kinds) > 0 {
+ propertySet.AddProperty("license_kinds", p.License_kinds)
+ }
+
+ // Copy any license test files to the snapshot into a module specific location.
+ if len(p.License_text) > 0 {
+ dests := []string{}
+ for _, path := range p.License_text {
+ // The destination path only uses the path of the license file in the source not the license
+ // module name. That ensures that if the same license file is used by multiple license modules
+ // that it only gets copied once as the snapshot builder will dedup copies where the source
+ // and destination match.
+ dest := filepath.Join("licenses", path.String())
+ dests = append(dests, dest)
+ ctx.SnapshotBuilder().CopyToSnapshot(path, dest)
+ }
+ propertySet.AddProperty("license_text", dests)
+ }
+}
+
+var _ SdkMemberProperties = (*licenseSdkMemberProperties)(nil)
diff --git a/android/license_test.go b/android/license_test.go
index 2b09a4f..26b33c3 100644
--- a/android/license_test.go
+++ b/android/license_test.go
@@ -8,7 +8,7 @@
var prepareForLicenseTest = GroupFixturePreparers(
// General preparers in alphabetical order.
PrepareForTestWithDefaults,
- prepareForTestWithLicenses,
+ PrepareForTestWithLicenses,
PrepareForTestWithOverrides,
PrepareForTestWithPackageModule,
PrepareForTestWithPrebuilts,
diff --git a/android/licenses.go b/android/licenses.go
index 2838f5d..464ba49 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -32,8 +32,23 @@
blueprint.BaseDependencyTag
}
+func (l licensesDependencyTag) SdkMemberType(Module) SdkMemberType {
+ // Add the supplied module to the sdk as a license module.
+ return LicenseModuleSdkMemberType
+}
+
+func (l licensesDependencyTag) ExportMember() bool {
+ // The license module will only every be referenced from within the sdk. This will ensure that it
+ // gets a unique name and so avoid clashing with the original license module.
+ return false
+}
+
var (
licensesTag = licensesDependencyTag{}
+
+ // License modules, i.e. modules depended upon via a licensesTag, must be automatically added to
+ // any sdk/module_exports to which their referencing module is a member.
+ _ SdkMemberTypeDependencyTag = licensesTag
)
// Describes the property provided by a module to reference applicable licenses.
@@ -140,7 +155,6 @@
}
licenses := getLicenses(ctx, m)
-
ctx.AddVariationDependencies(nil, licensesTag, licenses...)
}
@@ -187,34 +201,21 @@
return
}
- // license modules have no licenses, but license_kinds must refer to license_kind modules
- if l, ok := m.(*licenseModule); ok {
- mergeProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName())
- mergeProps(&m.base().commonProperties.Effective_license_text, PathsForModuleSrc(ctx, l.properties.License_text).Strings()...)
- for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
- if lk, ok := module.(*licenseKindModule); ok {
- mergeProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...)
- mergeProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module))
- } else {
- ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
- }
- }
- return
- }
-
if exemptFromRequiredApplicableLicensesProperty(m) {
return
}
+ var licenses []string
for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
if l, ok := module.(*licenseModule); ok {
+ licenses = append(licenses, ctx.OtherModuleName(module))
if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil {
m.base().commonProperties.Effective_package_name = l.properties.Package_name
}
- mergeProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
- mergeProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
- mergeProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
- mergeProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...)
+ mergeStringProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
+ mergePathProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
+ mergeStringProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
+ mergeStringProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...)
} else {
propertyName := "licenses"
primaryProperty := m.base().primaryLicensesProperty
@@ -224,19 +225,24 @@
ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
}
}
+
+ // Make the license information available for other modules.
+ licenseInfo := LicenseInfo{
+ Licenses: licenses,
+ }
+ ctx.SetProvider(LicenseInfoProvider, licenseInfo)
}
// Update a property string array with a distinct union of its values and a list of new values.
-func mergeProps(prop *[]string, values ...string) {
- s := make(map[string]bool)
- for _, v := range *prop {
- s[v] = true
- }
- for _, v := range values {
- s[v] = true
- }
- *prop = []string{}
- *prop = append(*prop, SortedStringKeys(s)...)
+func mergeStringProps(prop *[]string, values ...string) {
+ *prop = append(*prop, values...)
+ *prop = SortedUniqueStrings(*prop)
+}
+
+// Update a property Path array with a distinct union of its values and a list of new values.
+func mergePathProps(prop *Paths, values ...Path) {
+ *prop = append(*prop, values...)
+ *prop = SortedUniquePaths(*prop)
}
// Get the licenses property falling back to the package default.
@@ -293,3 +299,12 @@
}
return true
}
+
+// LicenseInfo contains information about licenses for a specific module.
+type LicenseInfo struct {
+ // The list of license modules this depends upon, either explicitly or through default package
+ // configuration.
+ Licenses []string
+}
+
+var LicenseInfoProvider = blueprint.NewProvider(LicenseInfo{})
diff --git a/android/licenses_test.go b/android/licenses_test.go
index 913dc88..8503310 100644
--- a/android/licenses_test.go
+++ b/android/licenses_test.go
@@ -6,18 +6,6 @@
"github.com/google/blueprint"
)
-var prepareForTestWithLicenses = GroupFixturePreparers(
- FixtureRegisterWithContext(RegisterLicenseKindBuildComponents),
- FixtureRegisterWithContext(RegisterLicenseBuildComponents),
- FixtureRegisterWithContext(registerLicenseMutators),
-)
-
-func registerLicenseMutators(ctx RegistrationContext) {
- ctx.PreArchMutators(RegisterLicensesPackageMapper)
- ctx.PreArchMutators(RegisterLicensesPropertyGatherer)
- ctx.PostDepsMutators(RegisterLicensesDependencyChecker)
-}
-
var licensesTests = []struct {
name string
fs MockFS
@@ -670,7 +658,7 @@
if base == nil {
return
}
- actualNotices[m.Name()] = base.commonProperties.Effective_license_text
+ actualNotices[m.Name()] = base.commonProperties.Effective_license_text.Strings()
})
for moduleName, expectedNotices := range effectiveNotices {
diff --git a/android/module.go b/android/module.go
index 99606d1..f745a4a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -165,13 +165,20 @@
// OtherModuleDependencyVariantExists returns true if a module with the
// specified name and variant exists. The variant must match the given
// variations. It must also match all the non-local variations of the current
- // module. In other words, it checks for the module AddVariationDependencies
+ // module. In other words, it checks for the module that AddVariationDependencies
// would add a dependency on with the same arguments.
OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
+ // OtherModuleFarDependencyVariantExists returns true if a module with the
+ // specified name and variant exists. The variant must match the given
+ // variations, but not the non-local variations of the current module. In
+ // other words, it checks for the module that AddFarVariationDependencies
+ // would add a dependency on with the same arguments.
+ OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool
+
// OtherModuleReverseDependencyVariantExists returns true if a module with the
// specified name exists with the same variations as the current module. In
- // other words, it checks for the module AddReverseDependency would add a
+ // other words, it checks for the module that AddReverseDependency would add a
// dependency on with the same argument.
OtherModuleReverseDependencyVariantExists(name string) bool
@@ -688,7 +695,7 @@
// Override of module name when reporting licenses
Effective_package_name *string `blueprint:"mutated"`
// Notice files
- Effective_license_text []string `blueprint:"mutated"`
+ Effective_license_text Paths `blueprint:"mutated"`
// License names
Effective_license_kinds []string `blueprint:"mutated"`
// License conditions
@@ -1500,7 +1507,7 @@
var installDeps []*installPathsDepSet
var packagingSpecs []*packagingSpecsDepSet
ctx.VisitDirectDeps(func(dep Module) {
- if IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) {
+ if IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) && !dep.IsHideFromMake() {
installDeps = append(installDeps, dep.base().installFilesDepSet)
packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
}
@@ -1809,8 +1816,8 @@
if m.Enabled() {
// ensure all direct android.Module deps are enabled
ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
- if _, ok := bm.(Module); ok {
- ctx.validateAndroidModule(bm, ctx.baseModuleContext.strictVisitDeps)
+ if m, ok := bm.(Module); ok {
+ ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps)
}
})
@@ -2022,6 +2029,9 @@
func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
return b.bp.OtherModuleDependencyVariantExists(variations, name)
}
+func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool {
+ return b.bp.OtherModuleFarDependencyVariantExists(variations, name)
+}
func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
return b.bp.OtherModuleReverseDependencyVariantExists(name)
}
@@ -2234,7 +2244,12 @@
}
}
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, strict bool) Module {
+type AllowDisabledModuleDependency interface {
+ blueprint.DependencyTag
+ AllowDisabledModuleDependency(target Module) bool
+}
+
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
aModule, _ := module.(Module)
if !strict {
@@ -2247,10 +2262,12 @@
}
if !aModule.Enabled() {
- if b.Config().AllowMissingDependencies() {
- b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
- } else {
- b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+ if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
+ if b.Config().AllowMissingDependencies() {
+ b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
+ } else {
+ b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+ }
}
return nil
}
@@ -2343,7 +2360,7 @@
func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
b.bp.VisitDirectDeps(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
visit(aModule)
}
})
@@ -2351,7 +2368,7 @@
func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
b.bp.VisitDirectDeps(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
if b.bp.OtherModuleDependencyTag(aModule) == tag {
visit(aModule)
}
@@ -2363,7 +2380,7 @@
b.bp.VisitDirectDepsIf(
// pred
func(module blueprint.Module) bool {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
return pred(aModule)
} else {
return false
@@ -2377,7 +2394,7 @@
func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
visit(aModule)
}
})
@@ -2387,7 +2404,7 @@
b.bp.VisitDepsDepthFirstIf(
// pred
func(module blueprint.Module) bool {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
return pred(aModule)
} else {
return false
diff --git a/android/packaging.go b/android/packaging.go
index 72c0c17..9065826 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -198,8 +198,8 @@
}
}
-// See PackageModule.CopyDepsToZip
-func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, zipOut WritablePath) (entries []string) {
+// Returns transitive PackagingSpecs from deps
+func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
m := make(map[string]PackagingSpec)
ctx.VisitDirectDeps(func(child Module) {
if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
@@ -211,7 +211,12 @@
}
}
})
+ return m
+}
+// See PackageModule.CopyDepsToZip
+func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, zipOut WritablePath) (entries []string) {
+ m := p.GatherPackagingSpecs(ctx)
builder := NewRuleBuilder(pctx, ctx)
dir := PathForModuleOut(ctx, ".zip")
diff --git a/android/paths.go b/android/paths.go
index 5d458cb..b192a35 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -287,6 +287,17 @@
return p.path
}
+// AsPaths converts the OptionalPath into Paths.
+//
+// It returns nil if this is not valid, or a single length slice containing the Path embedded in
+// this OptionalPath.
+func (p OptionalPath) AsPaths() Paths {
+ if !p.valid {
+ return nil
+ }
+ return Paths{p.path}
+}
+
// RelativeToTop returns an OptionalPath with the path that was embedded having been replaced by the
// result of calling Path.RelativeToTop on it.
func (p OptionalPath) RelativeToTop() OptionalPath {
@@ -1979,6 +1990,10 @@
func CreateOutputDirIfNonexistent(path WritablePath, perm os.FileMode) error {
dir := absolutePath(path.String())
+ return createDirIfNonexistent(dir, perm)
+}
+
+func createDirIfNonexistent(dir string, perm os.FileMode) error {
if _, err := os.Stat(dir); os.IsNotExist(err) {
return os.MkdirAll(dir, os.ModePerm)
} else {
@@ -1986,6 +2001,9 @@
}
}
+// absolutePath is deliberately private so that Soong's Go plugins can't use it to find and
+// read arbitrary files without going through the methods in the current package that track
+// dependencies.
func absolutePath(path string) string {
if filepath.IsAbs(path) {
return path
diff --git a/android/paths_test.go b/android/paths_test.go
index f8ccc77..6f5d79e 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -141,6 +141,9 @@
path = OptionalPathForPath(nil)
checkInvalidOptionalPath(t, path)
+
+ path = OptionalPathForPath(PathForTesting("path"))
+ checkValidOptionalPath(t, path, "path")
}
func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
@@ -151,6 +154,10 @@
if path.String() != "" {
t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
}
+ paths := path.AsPaths()
+ if len(paths) != 0 {
+ t.Errorf("Uninitialized OptionalPath AsPaths() should return empty Paths, not %q", paths)
+ }
defer func() {
if r := recover(); r == nil {
t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
@@ -159,6 +166,21 @@
path.Path()
}
+func checkValidOptionalPath(t *testing.T, path OptionalPath, expectedString string) {
+ t.Helper()
+ if !path.Valid() {
+ t.Errorf("Initialized OptionalPath should not be invalid")
+ }
+ if path.String() != expectedString {
+ t.Errorf("Initialized OptionalPath String() should return %q, not %q", expectedString, path.String())
+ }
+ paths := path.AsPaths()
+ if len(paths) != 1 {
+ t.Errorf("Initialized OptionalPath AsPaths() should return Paths with length 1, not %q", paths)
+ }
+ path.Path()
+}
+
func check(t *testing.T, testType, testString string,
got interface{}, err []error,
expected interface{}, expectedErr []error) {
diff --git a/android/sdk.go b/android/sdk.go
index 0adfd89..36c576d 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -284,11 +284,20 @@
// Add a property set with the specified name and return so that additional
// properties can be added.
AddPropertySet(name string) BpPropertySet
+
+ // Add comment for property (or property set).
+ AddCommentForProperty(name, text string)
}
// A .bp module definition.
type BpModule interface {
BpPropertySet
+
+ // ModuleType returns the module type of the module
+ ModuleType() string
+
+ // Name returns the name of the module or "" if no name has been specified.
+ Name() string
}
// An individual member of the SDK, includes all of the variants that the SDK
@@ -380,6 +389,10 @@
// The name of the member type property on an sdk module.
SdkPropertyName() string
+ // RequiresBpProperty returns true if this member type requires its property to be usable within
+ // an Android.bp file.
+ RequiresBpProperty() bool
+
// True if the member type supports the sdk/sdk_snapshot, false otherwise.
UsableWithSdkAndSdkSnapshot() bool
@@ -405,6 +418,10 @@
// the module is not allowed in whichever sdk property it was added.
IsInstance(module Module) bool
+ // UsesSourceModuleTypeInSnapshot returns true when the AddPrebuiltModule() method returns a
+ // source module type.
+ UsesSourceModuleTypeInSnapshot() bool
+
// Add a prebuilt module that the sdk will populate.
//
// The sdk module code generates the snapshot as follows:
@@ -448,15 +465,29 @@
// Base type for SdkMemberType implementations.
type SdkMemberTypeBase struct {
- PropertyName string
+ PropertyName string
+
+ // When set to true BpPropertyNotRequired indicates that the member type does not require the
+ // property to be specifiable in an Android.bp file.
+ BpPropertyNotRequired bool
+
SupportsSdk bool
HostOsDependent bool
+
+ // When set to true UseSourceModuleTypeInSnapshot indicates that the member type creates a source
+ // module type in its SdkMemberType.AddPrebuiltModule() method. That prevents the sdk snapshot
+ // code from automatically adding a prefer: true flag.
+ UseSourceModuleTypeInSnapshot bool
}
func (b *SdkMemberTypeBase) SdkPropertyName() string {
return b.PropertyName
}
+func (b *SdkMemberTypeBase) RequiresBpProperty() bool {
+ return !b.BpPropertyNotRequired
+}
+
func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
return b.SupportsSdk
}
@@ -465,6 +496,10 @@
return b.HostOsDependent
}
+func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool {
+ return b.UseSourceModuleTypeInSnapshot
+}
+
// Encapsulates the information about registered SdkMemberTypes.
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
diff --git a/android/testing.go b/android/testing.go
index ce27fca..191cb8d 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -74,6 +74,42 @@
ctx.PostDepsMutators(RegisterOverridePostDepsMutators)
})
+var PrepareForTestWithLicenses = GroupFixturePreparers(
+ FixtureRegisterWithContext(RegisterLicenseKindBuildComponents),
+ FixtureRegisterWithContext(RegisterLicenseBuildComponents),
+ FixtureRegisterWithContext(registerLicenseMutators),
+)
+
+func registerLicenseMutators(ctx RegistrationContext) {
+ ctx.PreArchMutators(RegisterLicensesPackageMapper)
+ ctx.PreArchMutators(RegisterLicensesPropertyGatherer)
+ ctx.PostDepsMutators(RegisterLicensesDependencyChecker)
+}
+
+var PrepareForTestWithLicenseDefaultModules = GroupFixturePreparers(
+ FixtureAddTextFile("build/soong/licenses/Android.bp", `
+ license {
+ name: "Android-Apache-2.0",
+ package_name: "Android",
+ license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+ copyright_notice: "Copyright (C) The Android Open Source Project",
+ license_text: ["LICENSE"],
+ }
+
+ license_kind {
+ name: "SPDX-license-identifier-Apache-2.0",
+ conditions: ["notice"],
+ url: "https://spdx.org/licenses/Apache-2.0.html",
+ }
+
+ license_kind {
+ name: "legacy_unencumbered",
+ conditions: ["unencumbered"],
+ }
+ `),
+ FixtureAddFile("build/soong/licenses/LICENSE", nil),
+)
+
// Test fixture preparer that will register most java build components.
//
// Singletons and mutators should only be added here if they are needed for a majority of java
diff --git a/android/variable.go b/android/variable.go
index e830845..7658cdd 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -282,7 +282,7 @@
NativeCoverageExcludePaths []string `json:",omitempty"`
// Set by NewConfig
- Native_coverage *bool
+ Native_coverage *bool `json:",omitempty"`
SanitizeHost []string `json:",omitempty"`
SanitizeDevice []string `json:",omitempty"`
@@ -467,7 +467,7 @@
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
// have been set for the module in the given context.
-func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties {
+func ProductVariableProperties(ctx BaseMutatorContext) ProductConfigProperties {
module := ctx.Module()
moduleBase := module.base()
@@ -477,7 +477,31 @@
return productConfigProperties
}
- variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName("Product_variables")
+ productVariableValues(moduleBase.variableProperties, "", &productConfigProperties)
+
+ for arch, targetProps := range moduleBase.GetArchProperties(ctx, moduleBase.variableProperties) {
+ // GetArchProperties is creating an instance of the requested type
+ // and productVariablesValues expects an interface, so no need to cast
+ productVariableValues(targetProps, arch.Name, &productConfigProperties)
+ }
+
+ for os, targetProps := range moduleBase.GetTargetProperties(ctx, moduleBase.variableProperties) {
+ // GetTargetProperties is creating an instance of the requested type
+ // and productVariablesValues expects an interface, so no need to cast
+ productVariableValues(targetProps.Properties, os.Name, &productConfigProperties)
+ for arch, archProperties := range targetProps.ArchProperties {
+ productVariableValues(archProperties, os.Name+"_"+arch.Name, &productConfigProperties)
+ }
+ }
+
+ return productConfigProperties
+}
+
+func productVariableValues(variableProps interface{}, suffix string, productConfigProperties *ProductConfigProperties) {
+ if suffix != "" {
+ suffix = "-" + suffix
+ }
+ variableValues := reflect.ValueOf(variableProps).Elem().FieldByName("Product_variables")
for i := 0; i < variableValues.NumField(); i++ {
variableValue := variableValues.Field(i)
// Check if any properties were set for the module
@@ -495,15 +519,13 @@
// e.g. Asflags, Cflags, Enabled, etc.
propertyName := variableValue.Type().Field(j).Name
- productConfigProperties[propertyName] = append(productConfigProperties[propertyName],
+ (*productConfigProperties)[propertyName] = append((*productConfigProperties)[propertyName],
ProductConfigProperty{
- ProductConfigVariable: productVariableName,
+ ProductConfigVariable: productVariableName + suffix,
Property: property.Interface(),
})
}
}
-
- return productConfigProperties
}
func VariableMutator(mctx BottomUpMutatorContext) {
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index f0f51bf..5316d7b 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -216,6 +216,8 @@
"LOCAL_JETIFIER_ENABLED": "jetifier",
"LOCAL_IS_UNIT_TEST": "unit_test",
+
+ "LOCAL_ENFORCE_USES_LIBRARIES": "enforce_uses_libs",
})
}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index f32ff2a..439f45d 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1446,6 +1446,23 @@
}
`,
},
+ {
+ desc: "LOCAL_ENFORCE_USES_LIBRARIES",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_ENFORCE_USES_LIBRARIES := false
+LOCAL_ENFORCE_USES_LIBRARIES := true
+include $(BUILD_PACKAGE)
+`,
+ expected: `
+android_app {
+ name: "foo",
+ enforce_uses_libs: false,
+ enforce_uses_libs: true,
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/Android.bp b/apex/Android.bp
index e234181..14c8771 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -32,6 +32,7 @@
"apex_test.go",
"bootclasspath_fragment_test.go",
"platform_bootclasspath_test.go",
+ "systemserver_classpath_fragment_test.go",
"vndk_test.go",
],
pluginFor: ["soong_build"],
diff --git a/apex/apex.go b/apex/apex.go
index d26c06d..926085b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -69,10 +69,12 @@
ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
ctx.BottomUp("apex_test_for_deps", apexTestForDepsMutator).Parallel()
ctx.BottomUp("apex_test_for", apexTestForMutator).Parallel()
+ // Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether
+ // it should create a platform variant.
+ ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
ctx.BottomUp("apex", apexMutator).Parallel()
ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
- ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
}
type apexBundleProperties struct {
@@ -100,6 +102,9 @@
// List of bootclasspath fragments that are embedded inside this APEX bundle.
Bootclasspath_fragments []string
+ // List of systemserverclasspath fragments that are embedded inside this APEX bundle.
+ Systemserverclasspath_fragments []string
+
// List of java libraries that are embedded inside this APEX bundle.
Java_libs []string
@@ -573,6 +578,7 @@
executableTag = dependencyTag{name: "executable", payload: true}
fsTag = dependencyTag{name: "filesystem", payload: true}
bcpfTag = dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true}
+ sscpfTag = dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true}
compatConfigTag = dependencyTag{name: "compatConfig", payload: true, sourceOnly: true}
javaLibTag = dependencyTag{name: "javaLib", payload: true}
jniLibTag = dependencyTag{name: "jniLib", payload: true}
@@ -735,24 +741,27 @@
}
}
- // For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
- // regardless of the TARGET_PREFER_* setting. See b/144532908
- archForPrebuiltEtc := config.Arches()[0]
- for _, arch := range config.Arches() {
- // Prefer 64-bit arch if there is any
- if arch.ArchType.Multilib == "lib64" {
- archForPrebuiltEtc = arch
- break
+ if prebuilts := a.properties.Prebuilts; len(prebuilts) > 0 {
+ // For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
+ // regardless of the TARGET_PREFER_* setting. See b/144532908
+ archForPrebuiltEtc := config.Arches()[0]
+ for _, arch := range config.Arches() {
+ // Prefer 64-bit arch if there is any
+ if arch.ArchType.Multilib == "lib64" {
+ archForPrebuiltEtc = arch
+ break
+ }
}
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {Mutator: "os", Variation: ctx.Os().String()},
+ {Mutator: "arch", Variation: archForPrebuiltEtc.String()},
+ }, prebuiltTag, prebuilts...)
}
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "os", Variation: ctx.Os().String()},
- {Mutator: "arch", Variation: archForPrebuiltEtc.String()},
- }, prebuiltTag, a.properties.Prebuilts...)
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
+ ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...)
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
@@ -899,12 +908,16 @@
// This is the main part of this mutator. Mark the collected dependencies that they need to
// be built for this apexBundle.
+
+ // Note that there are many different names.
+ // ApexVariationName: this is the name of the apex variation
apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(),
+ ApexVariationName: mctx.ModuleName(), // could be com.android.foo
MinSdkVersion: minSdkVersion,
RequiredSdks: a.RequiredSdks(),
Updatable: a.Updatable(),
- InApexes: []string{mctx.ModuleName()},
+ InApexVariants: []string{mctx.ModuleName()}, // could be com.android.foo
+ InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
ApexContents: []*android.ApexContents{apexContents},
}
mctx.WalkDeps(func(child, parent android.Module) bool {
@@ -1013,9 +1026,8 @@
}
})
- // Exception 1: stub libraries and native bridge libraries are always available to platform
- if cc, ok := mctx.Module().(*cc.Module); ok &&
- (cc.IsStubs() || cc.Target().NativeBridge == android.NativeBridgeEnabled) {
+ // Exception 1: check to see if the module always requires it.
+ if am.AlwaysRequiresPlatformApexVariant() {
availableToPlatform = true
}
@@ -1256,7 +1268,7 @@
}
// Implements cc.Coverage
-func (a *apexBundle) PreventInstall() {
+func (a *apexBundle) SetPreventInstall() {
a.properties.PreventInstall = true
}
@@ -1598,7 +1610,7 @@
}
ai := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
- externalDep := !android.InList(ctx.ModuleName(), ai.InApexes)
+ externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
// Visit actually
return do(ctx, parent, am, externalDep)
@@ -1714,6 +1726,15 @@
filesInfo = append(filesInfo, filesToAdd...)
return true
}
+ case sscpfTag:
+ {
+ if _, ok := child.(*java.SystemServerClasspathModule); !ok {
+ ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
+ return false
+ }
+ filesInfo = append(filesInfo, apexClasspathFragmentProtoFile(ctx, child))
+ return true
+ }
case javaLibTag:
switch child.(type) {
case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
@@ -1940,7 +1961,16 @@
default:
ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
}
-
+ } else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
+ // Add the contents of the systemserverclasspath fragment to the apex.
+ switch child.(type) {
+ case *java.Library, *java.SdkLibrary:
+ af := apexFileForJavaModule(ctx, child.(javaModule))
+ filesInfo = append(filesInfo, af)
+ return true // track transitive dependencies
+ default:
+ ctx.PropertyErrorf("systemserverclasspath_fragments", "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+ }
} else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
// nothing
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
@@ -1979,7 +2009,9 @@
// Sort to have consistent build rules
sort.Slice(filesInfo, func(i, j int) bool {
- return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
+ // Sort by destination path so as to ensure consistent ordering even if the source of the files
+ // changes.
+ return filesInfo[i].path() < filesInfo[j].path()
})
////////////////////////////////////////////////////////////////////////////////////////////
@@ -1988,7 +2020,7 @@
a.filesInfo = filesInfo
// Set suffix and primaryApexType depending on the ApexType
- buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuildApps()
+ buildFlattenedAsDefault := ctx.Config().FlattenApex()
switch a.properties.ApexType {
case imageApex:
if buildFlattenedAsDefault {
@@ -2102,9 +2134,20 @@
}
}
+ // Add classpaths.proto config.
+ filesToAdd = append(filesToAdd, apexClasspathFragmentProtoFile(ctx, module))
+
return filesToAdd
}
+// apexClasspathFragmentProtoFile returns apexFile structure defining the classpath.proto config that
+// the module contributes to the apex.
+func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) apexFile {
+ fragmentInfo := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
+ classpathProtoOutput := fragmentInfo.ClasspathFragmentProtoOutput
+ return newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), fragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
+}
+
// apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
// content module, i.e. a library that is part of the bootclasspath.
func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile {
@@ -2112,7 +2155,10 @@
// Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the
// hidden API encpding.
- dexBootJar := bootclasspathFragmentInfo.DexBootJarPathForContentModule(javaModule)
+ dexBootJar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(javaModule)
+ if err != nil {
+ ctx.ModuleErrorf("%s", err)
+ }
// Create an apexFile as for a normal java module but with the dex boot jar provided by the
// bootclasspath_fragment.
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 08d82e9..6a7c35c 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -709,6 +709,79 @@
}
}
+func TestApexManifestMinSdkVersion(t *testing.T) {
+ ctx := testApex(t, `
+ apex_defaults {
+ name: "my_defaults",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: ":my-file-contexts",
+ updatable: false,
+ }
+ apex {
+ name: "myapex_30",
+ min_sdk_version: "30",
+ defaults: ["my_defaults"],
+ }
+
+ apex {
+ name: "myapex_current",
+ min_sdk_version: "current",
+ defaults: ["my_defaults"],
+ }
+
+ apex {
+ name: "myapex_none",
+ defaults: ["my_defaults"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ filegroup {
+ name: "my-file-contexts",
+ srcs: ["product_specific_file_contexts"],
+ }
+ `, withFiles(map[string][]byte{
+ "product_specific_file_contexts": nil,
+ }), android.FixtureModifyProductVariables(
+ func(variables android.FixtureProductVariables) {
+ variables.Unbundled_build = proptools.BoolPtr(true)
+ variables.Always_use_prebuilt_sdks = proptools.BoolPtr(false)
+ }), android.FixtureMergeEnv(map[string]string{
+ "UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT": "true",
+ }))
+
+ testCases := []struct {
+ module string
+ minSdkVersion string
+ }{
+ {
+ module: "myapex_30",
+ minSdkVersion: "30",
+ },
+ {
+ module: "myapex_current",
+ minSdkVersion: "Q.$$(cat out/soong/api_fingerprint.txt)",
+ },
+ {
+ module: "myapex_none",
+ minSdkVersion: "Q.$$(cat out/soong/api_fingerprint.txt)",
+ },
+ }
+ for _, tc := range testCases {
+ module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module+"_image")
+ args := module.Rule("apexRule").Args
+ optFlags := args["opt_flags"]
+ if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) {
+ t.Errorf("%s: Expected min_sdk_version=%s, got: %s", tc.module, tc.minSdkVersion, optFlags)
+ }
+ }
+}
+
func TestBasicZipApex(t *testing.T) {
ctx := testApex(t, `
apex {
@@ -4542,11 +4615,16 @@
}
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
- preparer := java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar")
+ preparer := android.GroupFixturePreparers(
+ java.FixtureConfigureBootJars("myapex:libfoo", "myapex:libbar"),
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+ )
checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
t.Helper()
- s := ctx.SingletonForTests("dex_bootjars")
+ s := ctx.ModuleForTests("platform-bootclasspath", "android_common")
foundLibfooJar := false
base := stem + ".jar"
for _, output := range s.AllOutputs() {
@@ -4564,7 +4642,7 @@
checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) {
t.Helper()
platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common")
- indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index")
+ indexRule := platformBootclasspath.Rule("monolithic_hidden_API_index")
java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule)
}
@@ -4602,10 +4680,10 @@
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
- // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+ // Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
-.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
+.intermediates/libbar.stubs/android_common/combined/libbar.stubs.jar
+.intermediates/libfoo/android_common_myapex/combined/libfoo.jar
`)
})
@@ -4636,10 +4714,10 @@
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
- // Make sure that the dex file from the apex_set contributes to the hiddenapi index file.
+ // Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
-.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
+.intermediates/libbar.stubs/android_common/combined/libbar.stubs.jar
+.intermediates/libfoo/android_common_myapex/combined/libfoo.jar
`)
})
@@ -4743,10 +4821,10 @@
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
- // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+ // Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
-.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libbar.stubs/android_common/combined/libbar.stubs.jar
+.intermediates/prebuilt_libfoo/android_common_myapex/combined/libfoo.jar
`)
})
@@ -4810,10 +4888,10 @@
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")
- // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+ // Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/libbar/android_common_myapex/hiddenapi/index.csv
-.intermediates/libfoo/android_common_apex10000/hiddenapi/index.csv
+.intermediates/libbar/android_common_myapex/javac/libbar.jar
+.intermediates/libfoo/android_common_apex10000/javac/libfoo.jar
`)
})
@@ -4879,10 +4957,10 @@
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
- // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+ // Verify the correct module jars contribute to the hiddenapi index file.
checkHiddenAPIIndexInputs(t, ctx, `
-.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv
-.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
+.intermediates/prebuilt_libbar.stubs/android_common/combined/libbar.stubs.jar
+.intermediates/prebuilt_libfoo/android_common_myapex/combined/libfoo.jar
`)
})
}
@@ -7584,6 +7662,102 @@
}
}
+func TestHostApexInHostOnlyBuild(t *testing.T) {
+ testApex(t, `
+ apex {
+ name: "myapex",
+ host_supported: true,
+ key: "myapex.key",
+ updatable: false,
+ payload_type: "zip",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `,
+ android.FixtureModifyConfig(func(config android.Config) {
+ // We may not have device targets in all builds, e.g. in
+ // prebuilts/build-tools/build-prebuilts.sh
+ config.Targets[android.Android] = []android.Target{}
+ }))
+}
+
+func TestApexJavaCoverage(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: ["mylib"],
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "mylib",
+ srcs: ["mylib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: ["mybootclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "mybootclasspathlib",
+ srcs: ["mybootclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: ["mysystemserverclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "mysystemserverclasspathlib",
+ srcs: ["mysystemserverclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.FixtureWithRootAndroidBp(bp),
+ android.FixtureMergeEnv(map[string]string{
+ "EMMA_INSTRUMENT": "true",
+ }),
+ ).RunTest(t)
+
+ // Make sure jacoco ran on both mylib and mybootclasspathlib
+ if result.ModuleForTests("mylib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil {
+ t.Errorf("Failed to find jacoco rule for mylib")
+ }
+ if result.ModuleForTests("mybootclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil {
+ t.Errorf("Failed to find jacoco rule for mybootclasspathlib")
+ }
+ if result.ModuleForTests("mysystemserverclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil {
+ t.Errorf("Failed to find jacoco rule for mysystemserverclasspathlib")
+ }
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index e2b320c..7aecff6 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -62,6 +62,7 @@
apex {
name: "com.android.art",
key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
java_libs: [
"baz",
"quuz",
@@ -100,32 +101,12 @@
"com.android.art",
],
}
-
- bootclasspath_fragment {
- name: "framework-bootclasspath-fragment",
- image_name: "boot",
- }
`,
)
- // Make sure that the framework-bootclasspath-fragment is using the correct configuration.
- checkBootclasspathFragment(t, result, "framework-bootclasspath-fragment", "platform:foo,platform:bar", `
-test_device/dex_bootjars/android/system/framework/arm/boot-foo.art
-test_device/dex_bootjars/android/system/framework/arm/boot-foo.oat
-test_device/dex_bootjars/android/system/framework/arm/boot-foo.vdex
-test_device/dex_bootjars/android/system/framework/arm/boot-bar.art
-test_device/dex_bootjars/android/system/framework/arm/boot-bar.oat
-test_device/dex_bootjars/android/system/framework/arm/boot-bar.vdex
-test_device/dex_bootjars/android/system/framework/arm64/boot-foo.art
-test_device/dex_bootjars/android/system/framework/arm64/boot-foo.oat
-test_device/dex_bootjars/android/system/framework/arm64/boot-foo.vdex
-test_device/dex_bootjars/android/system/framework/arm64/boot-bar.art
-test_device/dex_bootjars/android/system/framework/arm64/boot-bar.oat
-test_device/dex_bootjars/android/system/framework/arm64/boot-bar.vdex
-`)
-
// Make sure that the art-bootclasspath-fragment is using the correct configuration.
- checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "com.android.art:baz,com.android.art:quuz", `
+ checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000",
+ "com.android.art:baz,com.android.art:quuz", `
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
@@ -141,10 +122,132 @@
`)
}
-func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
+func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ // Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
+ prepareForTestWithArtApex,
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo", "baz"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ java_sdk_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ test: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
+ contents: ["baz", "quuz"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "other-bootclasspath-fragment",
+ contents: ["foo", "bar"],
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ checkSdkKindStubs := func(message string, info java.HiddenAPIInfo, kind android.SdkKind, expectedPaths ...string) {
+ t.Helper()
+ android.AssertPathsRelativeToTopEquals(t, fmt.Sprintf("%s %s", message, kind), expectedPaths, info.TransitiveStubDexJarsByKind[kind])
+ }
+
+ // Check stub dex paths exported by art.
+ artFragment := result.Module("art-bootclasspath-fragment", "android_common")
+ artInfo := result.ModuleProvider(artFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+
+ bazPublicStubs := "out/soong/.intermediates/baz.stubs/android_common/dex/baz.stubs.jar"
+ bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar"
+ bazTestStubs := "out/soong/.intermediates/baz.stubs.test/android_common/dex/baz.stubs.test.jar"
+
+ checkSdkKindStubs("art", artInfo, android.SdkPublic, bazPublicStubs)
+ checkSdkKindStubs("art", artInfo, android.SdkSystem, bazSystemStubs)
+ checkSdkKindStubs("art", artInfo, android.SdkTest, bazTestStubs)
+ checkSdkKindStubs("art", artInfo, android.SdkCorePlatform)
+
+ // Check stub dex paths exported by other.
+ otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
+ otherInfo := result.ModuleProvider(otherFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+
+ fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar"
+ fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar"
+
+ checkSdkKindStubs("other", otherInfo, android.SdkPublic, bazPublicStubs, fooPublicStubs)
+ checkSdkKindStubs("other", otherInfo, android.SdkSystem, bazSystemStubs, fooSystemStubs)
+ checkSdkKindStubs("other", otherInfo, android.SdkTest, bazTestStubs, fooSystemStubs)
+ checkSdkKindStubs("other", otherInfo, android.SdkCorePlatform)
+}
+
+func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
t.Helper()
- bootclasspathFragment := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootclasspathFragmentModule)
+ bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule)
bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
modules := bootclasspathFragmentInfo.Modules()
@@ -279,6 +382,7 @@
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ "etc/classpaths/bootclasspath.pb",
"javalib/arm/boot.art",
"javalib/arm/boot.oat",
"javalib/arm/boot.vdex",
@@ -432,6 +536,14 @@
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithMyapex,
+ // Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+ java.FixtureConfigureBootJars("myapex:foo", "myapex:bar"),
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo"),
).RunTestWithBp(t, `
apex {
name: "myapex",
@@ -448,10 +560,11 @@
private_key: "testkey.pem",
}
- java_library {
+ java_sdk_library {
name: "foo",
srcs: ["b.java"],
- installable: true,
+ shared_library: false,
+ public: {enabled: true},
apex_available: [
"myapex",
],
@@ -481,6 +594,7 @@
ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
// This does not include art, oat or vdex files as they are only included for the art boot
// image.
+ "etc/classpaths/bootclasspath.pb",
"javalib/bar.jar",
"javalib/foo.jar",
})
@@ -489,6 +603,30 @@
`myapex.key`,
`mybootclasspathfragment`,
})
+
+ apex := result.ModuleForTests("myapex", "android_common_myapex_image")
+ apexRule := apex.Rule("apexRule")
+ copyCommands := apexRule.Args["copy_commands"]
+
+ // Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
+ fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
+
+ info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+
+ checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
+ module := result.Module(name, "android_common_apex10000")
+ dexJar, err := info.DexBootJarPathForContentModule(module)
+ if err != nil {
+ t.Error(err)
+ }
+ android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
+
+ expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
+ android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
+ }
+
+ checkFragmentExportedDexJar("foo", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/foo.jar")
+ checkFragmentExportedDexJar("bar", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/bar.jar")
}
// TODO(b/177892522) - add test for host apex.
diff --git a/apex/builder.go b/apex/builder.go
index da8841c..021e499 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -602,6 +602,11 @@
// codename
if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
+
+ if java.UseApiFingerprint(ctx) {
+ minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+ implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
+ }
}
// apex module doesn't have a concept of target_sdk_version, hence for the time
// being targetSdkVersion == default targetSdkVersion of the branch.
@@ -611,10 +616,6 @@
targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
}
- if java.UseApiFingerprint(ctx) {
- minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
- implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
- }
optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 52b1689..ce12f46 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/java"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
@@ -174,6 +175,141 @@
})
}
+// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
+// AlwaysUsePrebuiltSdk() returns true. The structure of the modules in this test matches what
+// currently exists in some places in the Android build but it is not the intended structure. It is
+// in fact an invalid structure that should cause build failures. However, fixing that structure
+// will take too long so in the meantime this tests the workarounds to avoid build breakages.
+//
+// The main issues with this structure are:
+// 1. There is no prebuilt_bootclasspath_fragment referencing the "foo" java_sdk_library_import.
+// 2. There is no prebuilt_apex/apex_set which makes the dex implementation jar available to the
+// prebuilt_bootclasspath_fragment and the "foo" java_sdk_library_import.
+//
+// Together these cause the following symptoms:
+// 1. The "foo" java_sdk_library_import does not have a dex implementation jar.
+// 2. The "foo" java_sdk_library_import does not have a myapex variant.
+//
+// TODO(b/179354495): Fix the structure in this test once the main Android build has been fixed.
+func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ prepareForTestWithMyapex,
+ // Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
+ // of AlwaysUsePrebuiltsSdk() but does not have an appropriate apex variant and does not provide
+ // a boot dex jar. The second is a normal library that is unaffected. The order matters because
+ // if the dependency on myapex:foo is filtered out because of either of those conditions then
+ // the dependencies resolved by the platform_bootclasspath will not match the configured list
+ // and so will fail the test.
+ java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
+ }),
+ java.FixtureWithPrebuiltApis(map[string][]string{
+ "current": {},
+ "30": {"foo"},
+ }),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspath-fragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {
+ enabled: true,
+ },
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ // A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
+ // because AlwaysUsePrebuiltSdks() is true.
+ java_sdk_library_import {
+ name: "foo",
+ prefer: false,
+ shared_library: false,
+ public: {
+ jars: ["sdk_library/public/foo-stubs.jar"],
+ stub_srcs: ["sdk_library/public/foo_stub_sources"],
+ current_api: "sdk_library/public/foo.txt",
+ removed_api: "sdk_library/public/foo-removed.txt",
+ sdk_version: "current",
+ },
+ apex_available: ["myapex"],
+ }
+
+ // This always depends on the source foo module, its dependencies are not affected by the
+ // AlwaysUsePrebuiltSdks().
+ bootclasspath_fragment {
+ name: "mybootclasspath-fragment",
+ apex_available: [
+ "myapex",
+ ],
+ contents: [
+ "foo", "bar",
+ ],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ }
+`,
+ )
+
+ java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
+ // The configured contents of BootJars.
+ "platform:prebuilt_foo", // Note: This is the platform not myapex variant.
+ "myapex:bar",
+ })
+
+ // Make sure that the myplatform-bootclasspath has the correct dependencies.
+ CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ // The following are stubs.
+ "platform:prebuilt_sdk_public_current_android",
+ "platform:prebuilt_sdk_system_current_android",
+ "platform:prebuilt_sdk_test_current_android",
+
+ // Not a prebuilt as no prebuilt existed when it was added.
+ "platform:legacy.core.platform.api.stubs",
+
+ // Needed for generating the boot image.
+ `platform:dex2oatd`,
+
+ // The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
+ // modules when available as it does not know which one will be preferred.
+ //
+ // The source module has an APEX variant but the prebuilt does not.
+ "myapex:foo",
+ "platform:prebuilt_foo",
+
+ // Only a source module exists.
+ "myapex:bar",
+ })
+}
+
// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
//
// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9d632a9..81bfc86 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -228,9 +228,11 @@
})
// Create an ApexInfo for the prebuilt_apex.
+ apexVariationName := android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName())
apexInfo := android.ApexInfo{
- ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()),
- InApexes: []string{mctx.ModuleName()},
+ ApexVariationName: apexVariationName,
+ InApexVariants: []string{apexVariationName},
+ InApexModules: []string{apexVariationName},
ApexContents: []*android.ApexContents{apexContents},
ForPrebuiltApex: true,
}
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
new file mode 100644
index 0000000..95b6e23
--- /dev/null
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -0,0 +1,78 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 apex
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+var prepareForTestWithSystemserverclasspathFragment = android.GroupFixturePreparers(
+ java.PrepareForTestWithDexpreopt,
+ PrepareForTestWithApexBuildComponents,
+)
+
+func TestSystemserverclasspathFragmentContents(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithSystemserverclasspathFragment,
+ prepareForTestWithMyapex,
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: [
+ "mysystemserverclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: [
+ "foo",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ `)
+
+ ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ "etc/classpaths/systemserverclasspath.pb",
+ "javalib/foo.jar",
+ })
+
+ java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ `myapex.key`,
+ `mysystemserverclasspathfragment`,
+ })
+}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 555f1dc..bda3a1a 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -81,23 +81,30 @@
Mnemonic string
}
-// AqueryBuildStatements returns an array of BuildStatements which should be registered (and output
-// to a ninja file) to correspond one-to-one with the given action graph json proto (from a bazel
-// aquery invocation).
-func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, error) {
- buildStatements := []BuildStatement{}
+// A helper type for aquery processing which facilitates retrieval of path IDs from their
+// less readable Bazel structures (depset and path fragment).
+type aqueryArtifactHandler struct {
+ // Maps middleman artifact Id to input artifact depset ID.
+ // Middleman artifacts are treated as "substitute" artifacts for mixed builds. For example,
+ // if we find a middleman action which has outputs [foo, bar], and output [baz_middleman], then,
+ // for each other action which has input [baz_middleman], we add [foo, bar] to the inputs for
+ // that action instead.
+ middlemanIdToDepsetIds map[int][]int
+ // Maps depset Id to depset struct.
+ depsetIdToDepset map[int]depSetOfFiles
+ // depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
+ // may be an expensive operation.
+ depsetIdToArtifactIdsCache map[int][]int
+ // Maps artifact Id to fully expanded path.
+ artifactIdToPath map[int]string
+}
- var aqueryResult actionGraphContainer
- err := json.Unmarshal(aqueryJsonProto, &aqueryResult)
-
- if err != nil {
- return nil, err
- }
-
+func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
pathFragments := map[int]pathFragment{}
for _, pathFragment := range aqueryResult.PathFragments {
pathFragments[pathFragment.Id] = pathFragment
}
+
artifactIdToPath := map[int]string{}
for _, artifact := range aqueryResult.Artifacts {
artifactPath, err := expandPathFragment(artifact.PathFragmentId, pathFragments)
@@ -112,22 +119,87 @@
depsetIdToDepset[depset.Id] = depset
}
- // depsetIdToArtifactIdsCache is a memoization of depset flattening, because flattening
- // may be an expensive operation.
- depsetIdToArtifactIdsCache := map[int][]int{}
-
// Do a pass through all actions to identify which artifacts are middleman artifacts.
- // These will be omitted from the inputs of other actions.
- // TODO(b/180945500): Handle middleman actions; without proper handling, depending on generated
- // headers may cause build failures.
- middlemanArtifactIds := map[int]bool{}
+ middlemanIdToDepsetIds := map[int][]int{}
for _, actionEntry := range aqueryResult.Actions {
if actionEntry.Mnemonic == "Middleman" {
for _, outputId := range actionEntry.OutputIds {
- middlemanArtifactIds[outputId] = true
+ middlemanIdToDepsetIds[outputId] = actionEntry.InputDepSetIds
}
}
}
+ return &aqueryArtifactHandler{
+ middlemanIdToDepsetIds: middlemanIdToDepsetIds,
+ depsetIdToDepset: depsetIdToDepset,
+ depsetIdToArtifactIdsCache: map[int][]int{},
+ artifactIdToPath: artifactIdToPath,
+ }, nil
+}
+
+func (a *aqueryArtifactHandler) getInputPaths(depsetIds []int) ([]string, error) {
+ inputPaths := []string{}
+
+ for _, inputDepSetId := range depsetIds {
+ inputArtifacts, err := a.artifactIdsFromDepsetId(inputDepSetId)
+ if err != nil {
+ return nil, err
+ }
+ for _, inputId := range inputArtifacts {
+ if middlemanInputDepsetIds, isMiddlemanArtifact := a.middlemanIdToDepsetIds[inputId]; isMiddlemanArtifact {
+ // Add all inputs from middleman actions which created middleman artifacts which are
+ // in the inputs for this action.
+ swappedInputPaths, err := a.getInputPaths(middlemanInputDepsetIds)
+ if err != nil {
+ return nil, err
+ }
+ inputPaths = append(inputPaths, swappedInputPaths...)
+ } else {
+ inputPath, exists := a.artifactIdToPath[inputId]
+ if !exists {
+ return nil, fmt.Errorf("undefined input artifactId %d", inputId)
+ }
+ inputPaths = append(inputPaths, inputPath)
+ }
+ }
+ }
+ return inputPaths, nil
+}
+
+func (a *aqueryArtifactHandler) artifactIdsFromDepsetId(depsetId int) ([]int, error) {
+ if result, exists := a.depsetIdToArtifactIdsCache[depsetId]; exists {
+ return result, nil
+ }
+ if depset, exists := a.depsetIdToDepset[depsetId]; exists {
+ result := depset.DirectArtifactIds
+ for _, childId := range depset.TransitiveDepSetIds {
+ childArtifactIds, err := a.artifactIdsFromDepsetId(childId)
+ if err != nil {
+ return nil, err
+ }
+ result = append(result, childArtifactIds...)
+ }
+ a.depsetIdToArtifactIdsCache[depsetId] = result
+ return result, nil
+ } else {
+ return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
+ }
+}
+
+// AqueryBuildStatements returns an array of BuildStatements which should be registered (and output
+// to a ninja file) to correspond one-to-one with the given action graph json proto (from a bazel
+// aquery invocation).
+func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, error) {
+ buildStatements := []BuildStatement{}
+
+ var aqueryResult actionGraphContainer
+ err := json.Unmarshal(aqueryJsonProto, &aqueryResult)
+ if err != nil {
+ return nil, err
+ }
+ aqueryHandler, err := newAqueryHandler(aqueryResult)
+ if err != nil {
+ return nil, err
+ }
for _, actionEntry := range aqueryResult.Actions {
if shouldSkipAction(actionEntry) {
@@ -136,7 +208,7 @@
outputPaths := []string{}
var depfile *string
for _, outputId := range actionEntry.OutputIds {
- outputPath, exists := artifactIdToPath[outputId]
+ outputPath, exists := aqueryHandler.artifactIdToPath[outputId]
if !exists {
return nil, fmt.Errorf("undefined outputId %d", outputId)
}
@@ -151,25 +223,11 @@
outputPaths = append(outputPaths, outputPath)
}
}
- inputPaths := []string{}
- for _, inputDepSetId := range actionEntry.InputDepSetIds {
- inputArtifacts, err :=
- artifactIdsFromDepsetId(depsetIdToDepset, depsetIdToArtifactIdsCache, inputDepSetId)
- if err != nil {
- return nil, err
- }
- for _, inputId := range inputArtifacts {
- if _, isMiddlemanArtifact := middlemanArtifactIds[inputId]; isMiddlemanArtifact {
- // Omit middleman artifacts.
- continue
- }
- inputPath, exists := artifactIdToPath[inputId]
- if !exists {
- return nil, fmt.Errorf("undefined input artifactId %d", inputId)
- }
- inputPaths = append(inputPaths, inputPath)
- }
+ inputPaths, err := aqueryHandler.getInputPaths(actionEntry.InputDepSetIds)
+ if err != nil {
+ return nil, err
}
+
buildStatement := BuildStatement{
Command: strings.Join(proptools.ShellEscapeList(actionEntry.Arguments), " "),
Depfile: depfile,
@@ -192,8 +250,9 @@
if a.Mnemonic == "Symlink" || a.Mnemonic == "SourceSymlinkManifest" || a.Mnemonic == "SymlinkTree" {
return true
}
- // TODO(b/180945500): Handle middleman actions; without proper handling, depending on generated
- // headers may cause build failures.
+ // Middleman actions are not handled like other actions; they are handled separately as a
+ // preparatory step so that their inputs may be relayed to actions depending on middleman
+ // artifacts.
if a.Mnemonic == "Middleman" {
return true
}
@@ -209,28 +268,6 @@
return false
}
-func artifactIdsFromDepsetId(depsetIdToDepset map[int]depSetOfFiles,
- depsetIdToArtifactIdsCache map[int][]int, depsetId int) ([]int, error) {
- if result, exists := depsetIdToArtifactIdsCache[depsetId]; exists {
- return result, nil
- }
- if depset, exists := depsetIdToDepset[depsetId]; exists {
- result := depset.DirectArtifactIds
- for _, childId := range depset.TransitiveDepSetIds {
- childArtifactIds, err :=
- artifactIdsFromDepsetId(depsetIdToDepset, depsetIdToArtifactIdsCache, childId)
- if err != nil {
- return nil, err
- }
- result = append(result, childArtifactIds...)
- }
- depsetIdToArtifactIdsCache[depsetId] = result
- return result, nil
- } else {
- return nil, fmt.Errorf("undefined input depsetId %d", depsetId)
- }
-}
-
func expandPathFragment(id int, pathFragmentsMap map[int]pathFragment) (string, error) {
labels := []string{}
currId := id
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index fa8810f..7b40dcd 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -718,6 +718,93 @@
assertBuildStatements(t, expectedBuildStatements, actualbuildStatements)
}
+func TestMiddlemenAction(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }, {
+ "id": 2,
+ "pathFragmentId": 2
+ }, {
+ "id": 3,
+ "pathFragmentId": 3
+ }, {
+ "id": 4,
+ "pathFragmentId": 4
+ }, {
+ "id": 5,
+ "pathFragmentId": 5
+ }, {
+ "id": 6,
+ "pathFragmentId": 6
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "middleinput_one"
+ }, {
+ "id": 2,
+ "label": "middleinput_two"
+ }, {
+ "id": 3,
+ "label": "middleman_artifact"
+ }, {
+ "id": 4,
+ "label": "maininput_one"
+ }, {
+ "id": 5,
+ "label": "maininput_two"
+ }, {
+ "id": 6,
+ "label": "output"
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [1, 2]
+ }, {
+ "id": 2,
+ "directArtifactIds": [3, 4, 5]
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "Middleman",
+ "arguments": ["touch", "foo"],
+ "inputDepSetIds": [1],
+ "outputIds": [3],
+ "primaryOutputId": 3
+ }, {
+ "targetId": 2,
+ "actionKey": "y",
+ "mnemonic": "Main action",
+ "arguments": ["touch", "foo"],
+ "inputDepSetIds": [2],
+ "outputIds": [6],
+ "primaryOutputId": 6
+ }]
+}`
+
+ actual, err := AqueryBuildStatements([]byte(inputString))
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+ if expected := 1; len(actual) != expected {
+ t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+ }
+
+ bs := actual[0]
+ expectedInputs := []string{"middleinput_one", "middleinput_two", "maininput_one", "maininput_two"}
+ if !reflect.DeepEqual(bs.InputPaths, expectedInputs) {
+ t.Errorf("Expected main action inputs %q, but got %q", expectedInputs, bs.InputPaths)
+ }
+
+ expectedOutputs := []string{"output"}
+ if !reflect.DeepEqual(bs.OutputPaths, expectedOutputs) {
+ t.Errorf("Expected main action outputs %q, but got %q", expectedOutputs, bs.OutputPaths)
+ }
+}
+
func assertError(t *testing.T, err error, expected string) {
if err == nil {
t.Errorf("expected error '%s', but got no error", expected)
diff --git a/bazel/constants.go b/bazel/constants.go
index 15c75cf..6beb496 100644
--- a/bazel/constants.go
+++ b/bazel/constants.go
@@ -18,6 +18,10 @@
// Run bazel as a ninja executer
BazelNinjaExecRunName = RunName("bazel-ninja-exec")
+
+ SoongInjectionDirName = "soong_injection"
+
+ GeneratedBazelFileWarning = "# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT"
)
// String returns the name of the run.
diff --git a/bazel/properties.go b/bazel/properties.go
index a71b12b..b2d68da 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -19,6 +19,7 @@
"path/filepath"
"regexp"
"sort"
+ "strings"
)
// BazelTargetModuleProperties contain properties and metadata used for
@@ -136,6 +137,62 @@
return strings
}
+// Return all needles in a given haystack, where needleFn is true for needles.
+func FilterLabelList(haystack LabelList, needleFn func(string) bool) LabelList {
+ var includes []Label
+ for _, inc := range haystack.Includes {
+ if needleFn(inc.Label) {
+ includes = append(includes, inc)
+ }
+ }
+ return LabelList{Includes: includes, Excludes: haystack.Excludes}
+}
+
+// Return all needles in a given haystack, where needleFn is true for needles.
+func FilterLabelListAttribute(haystack LabelListAttribute, needleFn func(string) bool) LabelListAttribute {
+ var result LabelListAttribute
+
+ result.Value = FilterLabelList(haystack.Value, needleFn)
+
+ for arch := range PlatformArchMap {
+ result.SetValueForArch(arch, FilterLabelList(haystack.GetValueForArch(arch), needleFn))
+ }
+
+ for os := range PlatformOsMap {
+ result.SetOsValueForTarget(os, FilterLabelList(haystack.GetOsValueForTarget(os), needleFn))
+
+ // TODO(b/187530594): Should we handle arch=CONDITIONS_DEFAULT here? (not in ArchValues)
+ for _, arch := range AllArches {
+ result.SetOsArchValueForTarget(os, arch, FilterLabelList(haystack.GetOsArchValueForTarget(os, arch), needleFn))
+ }
+ }
+
+ return result
+}
+
+// Subtract needle from haystack
+func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
+ var result LabelListAttribute
+
+ for arch := range PlatformArchMap {
+ result.SetValueForArch(arch,
+ SubtractBazelLabelList(haystack.GetValueForArch(arch), needle.GetValueForArch(arch)))
+ }
+
+ for os := range PlatformOsMap {
+ result.SetOsValueForTarget(os, SubtractBazelLabelList(haystack.GetOsValueForTarget(os), needle.GetOsValueForTarget(os)))
+
+ // TODO(b/187530594): Should we handle arch=CONDITIONS_DEFAULT here? (not in ArchValues)
+ for _, arch := range AllArches {
+ result.SetOsArchValueForTarget(os, arch, SubtractBazelLabelList(haystack.GetOsArchValueForTarget(os, arch), needle.GetOsArchValueForTarget(os, arch)))
+ }
+ }
+
+ result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
+
+ return result
+}
+
// Subtract needle from haystack
func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
// This is really a set
@@ -160,6 +217,14 @@
return labels
}
+// Appends two LabelLists, returning the combined list.
+func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
+ var result LabelList
+ result.Includes = append(a.Includes, b.Includes...)
+ result.Excludes = append(a.Excludes, b.Excludes...)
+ return result
+}
+
// Subtract needle from haystack
func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
var result LabelList
@@ -184,6 +249,21 @@
OS_LINUX_BIONIC = "linux_bionic"
OS_WINDOWS = "windows"
+ // Targets in arch.go
+ TARGET_ANDROID_ARM = "android_arm"
+ TARGET_ANDROID_ARM64 = "android_arm64"
+ TARGET_ANDROID_X86 = "android_x86"
+ TARGET_ANDROID_X86_64 = "android_x86_64"
+ TARGET_DARWIN_X86_64 = "darwin_x86_64"
+ TARGET_FUCHSIA_ARM64 = "fuchsia_arm64"
+ TARGET_FUCHSIA_X86_64 = "fuchsia_x86_64"
+ TARGET_LINUX_X86 = "linux_glibc_x86"
+ TARGET_LINUX_x86_64 = "linux_glibc_x86_64"
+ TARGET_LINUX_BIONIC_ARM64 = "linux_bionic_arm64"
+ TARGET_LINUX_BIONIC_X86_64 = "linux_bionic_x86_64"
+ TARGET_WINDOWS_X86 = "windows_x86"
+ TARGET_WINDOWS_X86_64 = "windows_x86_64"
+
// This is the string representation of the default condition wherever a
// configurable attribute is used in a select statement, i.e.
// //conditions:default for Bazel.
@@ -192,6 +272,10 @@
// config variable default key in an Android.bp file, although there's no
// integration with Soong config variables (yet).
CONDITIONS_DEFAULT = "conditions_default"
+
+ ConditionsDefaultSelectKey = "//conditions:default"
+
+ productVariableBazelPackage = "//build/bazel/product_variables"
)
var (
@@ -207,7 +291,7 @@
ARCH_ARM64: "//build/bazel/platforms/arch:arm64",
ARCH_X86: "//build/bazel/platforms/arch:x86",
ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
- CONDITIONS_DEFAULT: "//conditions:default", // The default condition of as arch select map.
+ CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of as arch select map.
}
// A map of target operating systems to the Bazel label of the
@@ -219,57 +303,202 @@
OS_LINUX: "//build/bazel/platforms/os:linux",
OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
OS_WINDOWS: "//build/bazel/platforms/os:windows",
- CONDITIONS_DEFAULT: "//conditions:default", // The default condition of an os select map.
+ CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
+
+ PlatformTargetMap = map[string]string{
+ TARGET_ANDROID_ARM: "//build/bazel/platforms/os_arch:android_arm",
+ TARGET_ANDROID_ARM64: "//build/bazel/platforms/os_arch:android_arm64",
+ TARGET_ANDROID_X86: "//build/bazel/platforms/os_arch:android_x86",
+ TARGET_ANDROID_X86_64: "//build/bazel/platforms/os_arch:android_x86_64",
+ TARGET_DARWIN_X86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
+ TARGET_FUCHSIA_ARM64: "//build/bazel/platforms/os_arch:fuchsia_arm64",
+ TARGET_FUCHSIA_X86_64: "//build/bazel/platforms/os_arch:fuchsia_x86_64",
+ TARGET_LINUX_X86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
+ TARGET_LINUX_x86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
+ TARGET_LINUX_BIONIC_ARM64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
+ TARGET_LINUX_BIONIC_X86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
+ TARGET_WINDOWS_X86: "//build/bazel/platforms/os_arch:windows_x86",
+ TARGET_WINDOWS_X86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
+ CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map.
+ }
+
+ // TODO(b/187530594): Should we add CONDITIONS_DEFAULT here?
+ AllArches = []string{ARCH_ARM, ARCH_ARM64, ARCH_X86, ARCH_X86_64}
)
type Attribute interface {
HasConfigurableValues() bool
}
-// Represents an attribute whose value is a single label
-type LabelAttribute struct {
- Value Label
+type labelArchValues struct {
X86 Label
X86_64 Label
Arm Label
Arm64 Label
+
+ ConditionsDefault Label
+}
+
+type labelTargetValue struct {
+ // E.g. for android
+ OsValue Label
+
+ // E.g. for android_arm, android_arm64, ...
+ ArchValues labelArchValues
+}
+
+type labelTargetValues struct {
+ Android labelTargetValue
+ Darwin labelTargetValue
+ Fuchsia labelTargetValue
+ Linux labelTargetValue
+ LinuxBionic labelTargetValue
+ Windows labelTargetValue
+
+ ConditionsDefault labelTargetValue
+}
+
+// Represents an attribute whose value is a single label
+type LabelAttribute struct {
+ Value Label
+
+ ArchValues labelArchValues
+
+ TargetValues labelTargetValues
}
func (attr *LabelAttribute) GetValueForArch(arch string) Label {
- switch arch {
- case ARCH_ARM:
- return attr.Arm
- case ARCH_ARM64:
- return attr.Arm64
- case ARCH_X86:
- return attr.X86
- case ARCH_X86_64:
- return attr.X86_64
- case CONDITIONS_DEFAULT:
- return attr.Value
- default:
- panic("Invalid arch type")
+ var v *Label
+ if v = attr.archValuePtrs()[arch]; v == nil {
+ panic(fmt.Errorf("Unknown arch: %s", arch))
}
+ return *v
}
func (attr *LabelAttribute) SetValueForArch(arch string, value Label) {
- switch arch {
- case ARCH_ARM:
- attr.Arm = value
- case ARCH_ARM64:
- attr.Arm64 = value
- case ARCH_X86:
- attr.X86 = value
- case ARCH_X86_64:
- attr.X86_64 = value
- default:
- panic("Invalid arch type")
+ var v *Label
+ if v = attr.archValuePtrs()[arch]; v == nil {
+ panic(fmt.Errorf("Unknown arch: %s", arch))
+ }
+ *v = value
+}
+
+func (attr *LabelAttribute) archValuePtrs() map[string]*Label {
+ return map[string]*Label{
+ ARCH_X86: &attr.ArchValues.X86,
+ ARCH_X86_64: &attr.ArchValues.X86_64,
+ ARCH_ARM: &attr.ArchValues.Arm,
+ ARCH_ARM64: &attr.ArchValues.Arm64,
+ CONDITIONS_DEFAULT: &attr.ArchValues.ConditionsDefault,
}
}
func (attr LabelAttribute) HasConfigurableValues() bool {
- return attr.Arm.Label != "" || attr.Arm64.Label != "" || attr.X86.Label != "" || attr.X86_64.Label != ""
+ for arch := range PlatformArchMap {
+ if attr.GetValueForArch(arch).Label != "" {
+ return true
+ }
+ }
+
+ for os := range PlatformOsMap {
+ if attr.GetOsValueForTarget(os).Label != "" {
+ return true
+ }
+ // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT (not in AllArches)
+ for _, arch := range AllArches {
+ if attr.GetOsArchValueForTarget(os, arch).Label != "" {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func (attr *LabelAttribute) getValueForTarget(os string) labelTargetValue {
+ var v *labelTargetValue
+ if v = attr.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ return *v
+}
+
+func (attr *LabelAttribute) GetOsValueForTarget(os string) Label {
+ var v *labelTargetValue
+ if v = attr.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ return v.OsValue
+}
+
+func (attr *LabelAttribute) GetOsArchValueForTarget(os string, arch string) Label {
+ var v *labelTargetValue
+ if v = attr.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ switch arch {
+ case ARCH_X86:
+ return v.ArchValues.X86
+ case ARCH_X86_64:
+ return v.ArchValues.X86_64
+ case ARCH_ARM:
+ return v.ArchValues.Arm
+ case ARCH_ARM64:
+ return v.ArchValues.Arm64
+ case CONDITIONS_DEFAULT:
+ return v.ArchValues.ConditionsDefault
+ default:
+ panic(fmt.Errorf("Unknown arch: %s\n", arch))
+ }
+}
+
+func (attr *LabelAttribute) setValueForTarget(os string, value labelTargetValue) {
+ var v *labelTargetValue
+ if v = attr.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ *v = value
+}
+
+func (attr *LabelAttribute) SetOsValueForTarget(os string, value Label) {
+ var v *labelTargetValue
+ if v = attr.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ v.OsValue = value
+}
+
+func (attr *LabelAttribute) SetOsArchValueForTarget(os string, arch string, value Label) {
+ var v *labelTargetValue
+ if v = attr.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ switch arch {
+ case ARCH_X86:
+ v.ArchValues.X86 = value
+ case ARCH_X86_64:
+ v.ArchValues.X86_64 = value
+ case ARCH_ARM:
+ v.ArchValues.Arm = value
+ case ARCH_ARM64:
+ v.ArchValues.Arm64 = value
+ case CONDITIONS_DEFAULT:
+ v.ArchValues.ConditionsDefault = value
+ default:
+ panic(fmt.Errorf("Unknown arch: %s\n", arch))
+ }
+}
+
+func (attr *LabelAttribute) targetValuePtrs() map[string]*labelTargetValue {
+ return map[string]*labelTargetValue{
+ OS_ANDROID: &attr.TargetValues.Android,
+ OS_DARWIN: &attr.TargetValues.Darwin,
+ OS_FUCHSIA: &attr.TargetValues.Fuchsia,
+ OS_LINUX: &attr.TargetValues.Linux,
+ OS_LINUX_BIONIC: &attr.TargetValues.LinuxBionic,
+ OS_WINDOWS: &attr.TargetValues.Windows,
+ CONDITIONS_DEFAULT: &attr.TargetValues.ConditionsDefault,
+ }
}
// Arch-specific label_list typed Bazel attribute values. This should correspond
@@ -279,20 +508,36 @@
X86_64 LabelList
Arm LabelList
Arm64 LabelList
- Common LabelList
ConditionsDefault LabelList
}
-type labelListOsValues struct {
- Android LabelList
- Darwin LabelList
- Fuchsia LabelList
- Linux LabelList
- LinuxBionic LabelList
- Windows LabelList
+type labelListTargetValue struct {
+ // E.g. for android
+ OsValue LabelList
- ConditionsDefault LabelList
+ // E.g. for android_arm, android_arm64, ...
+ ArchValues labelListArchValues
+}
+
+func (target *labelListTargetValue) Append(other labelListTargetValue) {
+ target.OsValue.Append(other.OsValue)
+ target.ArchValues.X86.Append(other.ArchValues.X86)
+ target.ArchValues.X86_64.Append(other.ArchValues.X86_64)
+ target.ArchValues.Arm.Append(other.ArchValues.Arm)
+ target.ArchValues.Arm64.Append(other.ArchValues.Arm64)
+ target.ArchValues.ConditionsDefault.Append(other.ArchValues.ConditionsDefault)
+}
+
+type labelListTargetValues struct {
+ Android labelListTargetValue
+ Darwin labelListTargetValue
+ Fuchsia labelListTargetValue
+ Linux labelListTargetValue
+ LinuxBionic labelListTargetValue
+ Windows labelListTargetValue
+
+ ConditionsDefault labelListTargetValue
}
// LabelListAttribute is used to represent a list of Bazel labels as an
@@ -309,7 +554,7 @@
// The os-specific attribute label list values. Optional. If used, these
// are generated in a select statement and appended to the non-os specific
// label list Value.
- OsValues labelListOsValues
+ TargetValues labelListTargetValues
}
// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
@@ -328,10 +573,10 @@
}
for os := range PlatformOsMap {
- this := attrs.GetValueForOS(os)
- that := other.GetValueForOS(os)
+ this := attrs.getValueForTarget(os)
+ that := other.getValueForTarget(os)
this.Append(that)
- attrs.SetValueForOS(os, this)
+ attrs.setValueForTarget(os, this)
}
attrs.Value.Append(other.Value)
@@ -347,9 +592,15 @@
}
for os := range PlatformOsMap {
- if len(attrs.GetValueForOS(os).Includes) > 0 {
+ if len(attrs.GetOsValueForTarget(os).Includes) > 0 {
return true
}
+ // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT (not in AllArches)
+ for _, arch := range AllArches {
+ if len(attrs.GetOsArchValueForTarget(os, arch).Includes) > 0 {
+ return true
+ }
+ }
}
return false
}
@@ -382,36 +633,92 @@
*v = value
}
-func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList {
- return map[string]*LabelList{
- OS_ANDROID: &attrs.OsValues.Android,
- OS_DARWIN: &attrs.OsValues.Darwin,
- OS_FUCHSIA: &attrs.OsValues.Fuchsia,
- OS_LINUX: &attrs.OsValues.Linux,
- OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
- OS_WINDOWS: &attrs.OsValues.Windows,
- CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault,
+func (attrs *LabelListAttribute) targetValuePtrs() map[string]*labelListTargetValue {
+ return map[string]*labelListTargetValue{
+ OS_ANDROID: &attrs.TargetValues.Android,
+ OS_DARWIN: &attrs.TargetValues.Darwin,
+ OS_FUCHSIA: &attrs.TargetValues.Fuchsia,
+ OS_LINUX: &attrs.TargetValues.Linux,
+ OS_LINUX_BIONIC: &attrs.TargetValues.LinuxBionic,
+ OS_WINDOWS: &attrs.TargetValues.Windows,
+ CONDITIONS_DEFAULT: &attrs.TargetValues.ConditionsDefault,
}
}
-// GetValueForOS returns the label_list attribute value for an OS target.
-func (attrs *LabelListAttribute) GetValueForOS(os string) LabelList {
- var v *LabelList
- if v = attrs.osValuePtrs()[os]; v == nil {
+func (attrs *LabelListAttribute) getValueForTarget(os string) labelListTargetValue {
+ var v *labelListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
panic(fmt.Errorf("Unknown os: %s", os))
}
return *v
}
-// SetValueForArch sets the label_list attribute value for an OS target.
-func (attrs *LabelListAttribute) SetValueForOS(os string, value LabelList) {
- var v *LabelList
- if v = attrs.osValuePtrs()[os]; v == nil {
+func (attrs *LabelListAttribute) GetOsValueForTarget(os string) LabelList {
+ var v *labelListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ return v.OsValue
+}
+
+func (attrs *LabelListAttribute) GetOsArchValueForTarget(os string, arch string) LabelList {
+ var v *labelListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ switch arch {
+ case ARCH_X86:
+ return v.ArchValues.X86
+ case ARCH_X86_64:
+ return v.ArchValues.X86_64
+ case ARCH_ARM:
+ return v.ArchValues.Arm
+ case ARCH_ARM64:
+ return v.ArchValues.Arm64
+ case CONDITIONS_DEFAULT:
+ return v.ArchValues.ConditionsDefault
+ default:
+ panic(fmt.Errorf("Unknown arch: %s\n", arch))
+ }
+}
+
+func (attrs *LabelListAttribute) setValueForTarget(os string, value labelListTargetValue) {
+ var v *labelListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
panic(fmt.Errorf("Unknown os: %s", os))
}
*v = value
}
+func (attrs *LabelListAttribute) SetOsValueForTarget(os string, value LabelList) {
+ var v *labelListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ v.OsValue = value
+}
+
+func (attrs *LabelListAttribute) SetOsArchValueForTarget(os string, arch string, value LabelList) {
+ var v *labelListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ switch arch {
+ case ARCH_X86:
+ v.ArchValues.X86 = value
+ case ARCH_X86_64:
+ v.ArchValues.X86_64 = value
+ case ARCH_ARM:
+ v.ArchValues.Arm = value
+ case ARCH_ARM64:
+ v.ArchValues.Arm64 = value
+ case CONDITIONS_DEFAULT:
+ v.ArchValues.ConditionsDefault = value
+ default:
+ panic(fmt.Errorf("Unknown arch: %s\n", arch))
+ }
+}
+
// StringListAttribute corresponds to the string_list Bazel attribute type with
// support for additional metadata, like configurations.
type StringListAttribute struct {
@@ -426,7 +733,11 @@
// The os-specific attribute string list values. Optional. If used, these
// are generated in a select statement and appended to the non-os specific
// label list Value.
- OsValues stringListOsValues
+ TargetValues stringListTargetValues
+
+ // list of product-variable string list values. Optional. if used, each will generate a select
+ // statement appended to the label list Value.
+ ProductValues []ProductVariableValues
}
// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
@@ -442,20 +753,48 @@
X86_64 []string
Arm []string
Arm64 []string
- Common []string
ConditionsDefault []string
}
-type stringListOsValues struct {
- Android []string
- Darwin []string
- Fuchsia []string
- Linux []string
- LinuxBionic []string
- Windows []string
+type stringListTargetValue struct {
+ // E.g. for android
+ OsValue []string
- ConditionsDefault []string
+ // E.g. for android_arm, android_arm64, ...
+ ArchValues stringListArchValues
+}
+
+func (target *stringListTargetValue) Append(other stringListTargetValue) {
+ target.OsValue = append(target.OsValue, other.OsValue...)
+ target.ArchValues.X86 = append(target.ArchValues.X86, other.ArchValues.X86...)
+ target.ArchValues.X86_64 = append(target.ArchValues.X86_64, other.ArchValues.X86_64...)
+ target.ArchValues.Arm = append(target.ArchValues.Arm, other.ArchValues.Arm...)
+ target.ArchValues.Arm64 = append(target.ArchValues.Arm64, other.ArchValues.Arm64...)
+ target.ArchValues.ConditionsDefault = append(target.ArchValues.ConditionsDefault, other.ArchValues.ConditionsDefault...)
+}
+
+type stringListTargetValues struct {
+ Android stringListTargetValue
+ Darwin stringListTargetValue
+ Fuchsia stringListTargetValue
+ Linux stringListTargetValue
+ LinuxBionic stringListTargetValue
+ Windows stringListTargetValue
+
+ ConditionsDefault stringListTargetValue
+}
+
+// Product Variable values for StringListAttribute
+type ProductVariableValues struct {
+ ProductVariable string
+
+ Values []string
+}
+
+// SelectKey returns the appropriate select key for the receiving ProductVariableValues.
+func (p ProductVariableValues) SelectKey() string {
+ return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(p.ProductVariable))
}
// HasConfigurableValues returns true if the attribute contains
@@ -468,11 +807,19 @@
}
for os := range PlatformOsMap {
- if len(attrs.GetValueForOS(os)) > 0 {
+ if len(attrs.GetOsValueForTarget(os)) > 0 {
return true
}
+ // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (Not in AllArches)
+ for _, arch := range AllArches {
+ if len(attrs.GetOsArchValueForTarget(os, arch)) > 0 {
+ return true
+ }
+
+ }
}
- return false
+
+ return len(attrs.ProductValues) > 0
}
func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
@@ -503,36 +850,98 @@
*v = value
}
-func (attrs *StringListAttribute) osValuePtrs() map[string]*[]string {
- return map[string]*[]string{
- OS_ANDROID: &attrs.OsValues.Android,
- OS_DARWIN: &attrs.OsValues.Darwin,
- OS_FUCHSIA: &attrs.OsValues.Fuchsia,
- OS_LINUX: &attrs.OsValues.Linux,
- OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
- OS_WINDOWS: &attrs.OsValues.Windows,
- CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault,
+func (attrs *StringListAttribute) targetValuePtrs() map[string]*stringListTargetValue {
+ return map[string]*stringListTargetValue{
+ OS_ANDROID: &attrs.TargetValues.Android,
+ OS_DARWIN: &attrs.TargetValues.Darwin,
+ OS_FUCHSIA: &attrs.TargetValues.Fuchsia,
+ OS_LINUX: &attrs.TargetValues.Linux,
+ OS_LINUX_BIONIC: &attrs.TargetValues.LinuxBionic,
+ OS_WINDOWS: &attrs.TargetValues.Windows,
+ CONDITIONS_DEFAULT: &attrs.TargetValues.ConditionsDefault,
}
}
-// GetValueForOS returns the string_list attribute value for an OS target.
-func (attrs *StringListAttribute) GetValueForOS(os string) []string {
- var v *[]string
- if v = attrs.osValuePtrs()[os]; v == nil {
+func (attrs *StringListAttribute) getValueForTarget(os string) stringListTargetValue {
+ var v *stringListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
panic(fmt.Errorf("Unknown os: %s", os))
}
return *v
}
-// SetValueForArch sets the string_list attribute value for an OS target.
-func (attrs *StringListAttribute) SetValueForOS(os string, value []string) {
- var v *[]string
- if v = attrs.osValuePtrs()[os]; v == nil {
+func (attrs *StringListAttribute) GetOsValueForTarget(os string) []string {
+ var v *stringListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ return v.OsValue
+}
+
+func (attrs *StringListAttribute) GetOsArchValueForTarget(os string, arch string) []string {
+ var v *stringListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ switch arch {
+ case ARCH_X86:
+ return v.ArchValues.X86
+ case ARCH_X86_64:
+ return v.ArchValues.X86_64
+ case ARCH_ARM:
+ return v.ArchValues.Arm
+ case ARCH_ARM64:
+ return v.ArchValues.Arm64
+ case CONDITIONS_DEFAULT:
+ return v.ArchValues.ConditionsDefault
+ default:
+ panic(fmt.Errorf("Unknown arch: %s\n", arch))
+ }
+}
+
+func (attrs *StringListAttribute) setValueForTarget(os string, value stringListTargetValue) {
+ var v *stringListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
panic(fmt.Errorf("Unknown os: %s", os))
}
*v = value
}
+func (attrs *StringListAttribute) SortedProductVariables() []ProductVariableValues {
+ vals := attrs.ProductValues[:]
+ sort.Slice(vals, func(i, j int) bool { return vals[i].ProductVariable < vals[j].ProductVariable })
+ return vals
+}
+
+func (attrs *StringListAttribute) SetOsValueForTarget(os string, value []string) {
+ var v *stringListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ v.OsValue = value
+}
+
+func (attrs *StringListAttribute) SetOsArchValueForTarget(os string, arch string, value []string) {
+ var v *stringListTargetValue
+ if v = attrs.targetValuePtrs()[os]; v == nil {
+ panic(fmt.Errorf("Unknown os: %s", os))
+ }
+ switch arch {
+ case ARCH_X86:
+ v.ArchValues.X86 = value
+ case ARCH_X86_64:
+ v.ArchValues.X86_64 = value
+ case ARCH_ARM:
+ v.ArchValues.Arm = value
+ case ARCH_ARM64:
+ v.ArchValues.Arm64 = value
+ case CONDITIONS_DEFAULT:
+ v.ArchValues.ConditionsDefault = value
+ default:
+ panic(fmt.Errorf("Unknown arch: %s\n", arch))
+ }
+}
+
// Append appends all values, including os and arch specific ones, from another
// StringListAttribute to this StringListAttribute
func (attrs *StringListAttribute) Append(other StringListAttribute) {
@@ -544,10 +953,25 @@
}
for os := range PlatformOsMap {
- this := attrs.GetValueForOS(os)
- that := other.GetValueForOS(os)
- this = append(this, that...)
- attrs.SetValueForOS(os, this)
+ this := attrs.getValueForTarget(os)
+ that := other.getValueForTarget(os)
+ this.Append(that)
+ attrs.setValueForTarget(os, this)
+ }
+
+ productValues := make(map[string][]string, 0)
+ for _, pv := range attrs.ProductValues {
+ productValues[pv.ProductVariable] = pv.Values
+ }
+ for _, pv := range other.ProductValues {
+ productValues[pv.ProductVariable] = append(productValues[pv.ProductVariable], pv.Values...)
+ }
+ attrs.ProductValues = make([]ProductVariableValues, 0, len(productValues))
+ for pv, vals := range productValues {
+ attrs.ProductValues = append(attrs.ProductValues, ProductVariableValues{
+ ProductVariable: pv,
+ Values: vals,
+ })
}
attrs.Value = append(attrs.Value, other.Value...)
@@ -569,6 +993,6 @@
// 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+"}")
+ sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
return sub, s != sub
}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index abd79f5..3abbc4c 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -20,6 +20,7 @@
"soong-android",
"soong-bazel",
"soong-cc",
+ "soong-cc-config",
"soong-genrule",
"soong-python",
"soong-sh",
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index cf6994f..ee36982 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -16,6 +16,7 @@
import (
"android/soong/android"
+ "android/soong/bazel"
"fmt"
"os"
)
@@ -24,22 +25,16 @@
// writing .bzl files that are equivalent to Android.bp files that are capable
// of being built with Bazel.
func Codegen(ctx *CodegenContext) CodegenMetrics {
- outputDir := android.PathForOutput(ctx, "bp2build")
- android.RemoveAllOutputDir(outputDir)
+ // This directory stores BUILD files that could be eventually checked-in.
+ bp2buildDir := android.PathForOutput(ctx, "bp2build")
+ android.RemoveAllOutputDir(bp2buildDir)
buildToTargets, metrics := GenerateBazelTargets(ctx, true)
+ bp2buildFiles := CreateBazelFiles(nil, buildToTargets, ctx.mode)
+ writeFiles(ctx, bp2buildDir, bp2buildFiles)
- filesToWrite := CreateBazelFiles(nil, buildToTargets, ctx.mode)
-
- generatedBuildFiles := []string{}
- for _, f := range filesToWrite {
- p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
- if err := writeFile(ctx, p, f.Contents); err != nil {
- panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
- }
- // if these generated files are modified, regenerate on next run.
- generatedBuildFiles = append(generatedBuildFiles, p.String())
- }
+ soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
+ writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles())
return metrics
}
@@ -51,6 +46,16 @@
return dirPath
}
+// writeFiles materializes a list of BazelFile rooted at outputDir.
+func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) {
+ for _, f := range files {
+ p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
+ if err := writeFile(ctx, p, f.Contents); err != nil {
+ panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
+ }
+ }
+}
+
func writeFile(ctx android.PathContext, pathToFile android.OutputPath, content string) error {
// These files are made editable to allow users to modify and iterate on them
// in the source tree.
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index bddc524..6bdfc0e 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -19,6 +19,7 @@
"android/soong/bazel"
"fmt"
"reflect"
+ "sort"
"strings"
"github.com/google/blueprint"
@@ -34,6 +35,7 @@
content string
ruleClass string
bzlLoadLocation string
+ handcrafted bool
}
// IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file,
@@ -45,12 +47,47 @@
// BazelTargets is a typedef for a slice of BazelTarget objects.
type BazelTargets []BazelTarget
+// HasHandcraftedTargetsreturns true if a set of bazel targets contain
+// handcrafted ones.
+func (targets BazelTargets) hasHandcraftedTargets() bool {
+ for _, target := range targets {
+ if target.handcrafted {
+ return true
+ }
+ }
+ return false
+}
+
+// sort a list of BazelTargets in-place, by name, and by generated/handcrafted types.
+func (targets BazelTargets) sort() {
+ sort.Slice(targets, func(i, j int) bool {
+ if targets[i].handcrafted != targets[j].handcrafted {
+ // Handcrafted targets will be generated after the bp2build generated targets.
+ return targets[j].handcrafted
+ }
+ // This will cover all bp2build generated targets.
+ return targets[i].name < targets[j].name
+ })
+}
+
// String returns the string representation of BazelTargets, without load
// statements (use LoadStatements for that), since the targets are usually not
// adjacent to the load statements at the top of the BUILD file.
func (targets BazelTargets) String() string {
var res string
for i, target := range targets {
+ // There is only at most 1 handcrafted "target", because its contents
+ // represent the entire BUILD file content from the tree. See
+ // build_conversion.go#getHandcraftedBuildContent for more information.
+ //
+ // Add a header to make it easy to debug where the handcrafted targets
+ // are in a generated BUILD file.
+ if target.handcrafted {
+ res += "# -----------------------------\n"
+ res += "# Section: Handcrafted targets. \n"
+ res += "# -----------------------------\n\n"
+ }
+
res += target.content
if i != len(targets)-1 {
res += "\n\n"
@@ -267,7 +304,8 @@
}
// TODO(b/181575318): once this is more targeted, we need to include name, rule class, etc
return BazelTarget{
- content: c,
+ content: c,
+ handcrafted: true,
}, nil
}
@@ -294,6 +332,7 @@
targetName,
attributes,
),
+ handcrafted: false,
}
}
@@ -406,7 +445,7 @@
return prettyPrint(propertyValue.Elem(), indent)
case reflect.Slice:
if propertyValue.Len() == 0 {
- return "", nil
+ return "[]", nil
}
if propertyValue.Len() == 1 {
@@ -529,6 +568,9 @@
return true
}
default:
+ if !value.IsValid() {
+ return true
+ }
zeroValue := reflect.Zero(value.Type())
result := value.Interface() == zeroValue.Interface()
return result
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 63a6c2e..b1c342c 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -324,11 +324,11 @@
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
- if Errored(t, "", errs) {
+ if errored(t, "", errs) {
continue
}
_, errs = ctx.ResolveDependencies(config)
- if Errored(t, "", errs) {
+ if errored(t, "", errs) {
continue
}
@@ -925,11 +925,11 @@
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
+ if errored(t, testCase.description, errs) {
continue
}
_, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
+ if errored(t, testCase.description, errs) {
continue
}
@@ -957,17 +957,6 @@
}
}
-func Errored(t *testing.T, desc string, errs []error) bool {
- t.Helper()
- if len(errs) > 0 {
- for _, err := range errs {
- t.Errorf("%s: %s", desc, err)
- }
- return true
- }
- return false
-}
-
type bp2buildMutator = func(android.TopDownMutatorContext)
func TestBp2BuildInlinesDefaults(t *testing.T) {
@@ -1463,53 +1452,61 @@
dir := "."
for _, testCase := range testCases {
- fs := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.fs {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
+ t.Run(testCase.description, func(t *testing.T) {
+ fs := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
}
- fs[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, fs)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
+ for f, content := range testCase.fs {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ fs[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, testCase.bp, fs)
+ ctx := android.NewTestContext(config)
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ for _, m := range testCase.depsMutators {
+ ctx.DepsBp2BuildMutators(m)
+ }
+ ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if errored(t, testCase.description, errs) {
+ return
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if errored(t, testCase.description, errs) {
+ return
+ }
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
- } else {
+ checkDir := dir
+ if testCase.dir != "" {
+ checkDir = testCase.dir
+ }
+ bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
+ bazelTargets.sort()
+ actualCount := len(bazelTargets)
+ expectedCount := len(testCase.expectedBazelTargets)
+ if actualCount != expectedCount {
+ t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets)
+ }
+ if !strings.Contains(bazelTargets.String(), "Section: Handcrafted targets. ") {
+ t.Errorf("Expected string representation of bazelTargets to contain handcrafted section header.")
+ }
for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+ actualContent := target.content
+ expectedContent := testCase.expectedBazelTargets[i]
+ if expectedContent != actualContent {
t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
+ "Expected generated Bazel target to be '%s', got '%s'",
+ expectedContent,
+ actualContent,
)
}
}
- }
+ })
}
}
@@ -1606,11 +1603,11 @@
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
+ if errored(t, testCase.description, errs) {
continue
}
_, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
+ if errored(t, testCase.description, errs) {
continue
}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 32b12e4..204c519 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -22,8 +22,6 @@
"testing"
)
-var buildDir string
-
func setUp() {
var err error
buildDir, err = ioutil.TempDir("", "bazel_queryview_test")
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index c543ef8..b87d713 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -40,43 +40,100 @@
}`
)
-func TestCcLibraryBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- depsMutators []android.RegisterMutatorFunc
- }{
- {
- description: "cc_library - simple example",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- filesystem: map[string]string{
- "android.cpp": "",
- "darwin.cpp": "",
- // Refer to cc.headerExts for the supported header extensions in Soong.
- "header.h": "",
- "header.hh": "",
- "header.hpp": "",
- "header.hxx": "",
- "header.h++": "",
- "header.inl": "",
- "header.inc": "",
- "header.ipp": "",
- "header.h.generic": "",
- "impl.cpp": "",
- "linux.cpp": "",
- "x86.cpp": "",
- "x86_64.cpp": "",
- "foo-dir/a.h": "",
- },
- bp: soongCcLibraryPreamble + `
+func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
+}
+
+func registerCcLibraryModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+}
+
+func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
+ t.Helper()
+ dir := "."
+ filesystem := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ for f, content := range tc.filesystem {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ filesystem[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, tc.blueprint, filesystem)
+ ctx := android.NewTestContext(config)
+
+ registerModuleTypes(ctx)
+ ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
+ ctx.RegisterBp2BuildConfig(bp2buildConfig)
+ for _, m := range tc.depsMutators {
+ ctx.DepsBp2BuildMutators(m)
+ }
+ ctx.RegisterBp2BuildMutator(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if errored(t, tc.description, errs) {
+ return
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if errored(t, tc.description, errs) {
+ return
+ }
+
+ checkDir := dir
+ if tc.dir != "" {
+ checkDir = tc.dir
+ }
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
+ if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("%s: Expected %d bazel target, got %d", tc.description, expectedCount, actualCount)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := tc.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ tc.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+}
+
+func TestCcLibrarySimple(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library - simple example",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "android.cpp": "",
+ "darwin.cpp": "",
+ // Refer to cc.headerExts for the supported header extensions in Soong.
+ "header.h": "",
+ "header.hh": "",
+ "header.hpp": "",
+ "header.hxx": "",
+ "header.h++": "",
+ "header.inl": "",
+ "header.inc": "",
+ "header.ipp": "",
+ "header.h.generic": "",
+ "impl.cpp": "",
+ "linux.cpp": "",
+ "x86.cpp": "",
+ "x86_64.cpp": "",
+ "foo-dir/a.h": "",
+ },
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "some-headers" }
cc_library {
name: "foo-lib",
@@ -108,13 +165,14 @@
},
}
`,
- expectedBazelTargets: []string{`cc_library(
+ expectedBazelTargets: []string{`cc_library(
name = "foo-lib",
copts = [
"-Wall",
"-I.",
+ "-I$(BINDIR)/.",
],
- deps = [":some-headers"],
+ implementation_deps = [":some-headers"],
includes = ["foo-dir"],
linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
"//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
@@ -131,21 +189,23 @@
"//build/bazel/platforms/os:linux": ["linux.cpp"],
"//conditions:default": [],
}),
-)`},
+)`}})
+}
+
+func TestCcLibraryTrimmedLdAndroid(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library - trimmed example of //bionic/linker:ld-android",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "ld-android.cpp": "",
+ "linked_list.h": "",
+ "linker.h": "",
+ "linker_block_allocator.h": "",
+ "linker_cfi.h": "",
},
- {
- description: "cc_library - trimmed example of //bionic/linker:ld-android",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- filesystem: map[string]string{
- "ld-android.cpp": "",
- "linked_list.h": "",
- "linker.h": "",
- "linker_block_allocator.h": "",
- "linker_cfi.h": "",
- },
- bp: soongCcLibraryPreamble + `
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "libc_headers" }
cc_library {
name: "fake-ld-android",
@@ -175,7 +235,7 @@
},
}
`,
- expectedBazelTargets: []string{`cc_library(
+ expectedBazelTargets: []string{`cc_library(
name = "fake-ld-android",
copts = [
"-Wall",
@@ -183,8 +243,9 @@
"-Wunused",
"-Werror",
"-I.",
+ "-I$(BINDIR)/.",
],
- deps = [":libc_headers"],
+ implementation_deps = [":libc_headers"],
linkopts = [
"-Wl,--exclude-libs=libgcc.a",
"-Wl,--exclude-libs=libgcc_stripped.a",
@@ -199,20 +260,23 @@
}),
srcs = ["ld_android.cpp"],
)`},
- },
- {
- description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "external",
- filesystem: map[string]string{
- "external/math/cosf.c": "",
- "external/math/erf.c": "",
- "external/math/erf_data.c": "",
- "external/math/erff.c": "",
- "external/math/erff_data.c": "",
- "external/Android.bp": `
+ })
+}
+
+func TestCcLibraryExcludeSrcs(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ dir: "external",
+ filesystem: map[string]string{
+ "external/math/cosf.c": "",
+ "external/math/erf.c": "",
+ "external/math/erf_data.c": "",
+ "external/math/erff.c": "",
+ "external/math/erff_data.c": "",
+ "external/Android.bp": `
cc_library {
name: "fake-libarm-optimized-routines-math",
exclude_srcs: [
@@ -238,54 +302,249 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "fake-libarm-optimized-routines-math",
- copts = ["-Iexternal"] + select({
+ copts = [
+ "-Iexternal",
+ "-I$(BINDIR)/external",
+ ] + select({
"//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
"//conditions:default": [],
}),
- srcs = ["math/cosf.c"],
+ srcs_c = ["math/cosf.c"],
)`},
- },
- {
- description: "cc_library shared/static props",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/a.cpp": "",
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibrarySharedStaticProps(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library shared/static props",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/both.cpp": "",
+ "foo/bar/sharedonly.cpp": "",
+ "foo/bar/staticonly.cpp": "",
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
- shared: { whole_static_libs: ["b"] },
- static: { srcs: ["a.cpp"] },
+ srcs: ["both.cpp"],
+ cflags: ["bothflag"],
+ shared_libs: ["shared_dep_for_both"],
+ static_libs: ["static_dep_for_both"],
+ whole_static_libs: ["whole_static_lib_for_both"],
+ static: {
+ srcs: ["staticonly.cpp"],
+ cflags: ["staticflag"],
+ shared_libs: ["shared_dep_for_static"],
+ static_libs: ["static_dep_for_static"],
+ whole_static_libs: ["whole_static_lib_for_static"],
+ },
+ shared: {
+ srcs: ["sharedonly.cpp"],
+ cflags: ["sharedflag"],
+ shared_libs: ["shared_dep_for_shared"],
+ static_libs: ["static_dep_for_shared"],
+ whole_static_libs: ["whole_static_lib_for_shared"],
+ },
bazel_module: { bp2build_available: true },
}
-cc_library_static { name: "b" }
+cc_library_static { name: "static_dep_for_shared" }
+
+cc_library_static { name: "static_dep_for_static" }
+
+cc_library_static { name: "static_dep_for_both" }
+
+cc_library_static { name: "whole_static_lib_for_shared" }
+
+cc_library_static { name: "whole_static_lib_for_static" }
+
+cc_library_static { name: "whole_static_lib_for_both" }
+
+cc_library { name: "shared_dep_for_shared" }
+
+cc_library { name: "shared_dep_for_static" }
+
+cc_library { name: "shared_dep_for_both" }
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["-Ifoo/bar"],
- srcs = ["a.cpp"],
- static_deps_for_shared = [":b"],
-)`},
},
- {
- description: "cc_library non-configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "bothflag",
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ dynamic_deps = [":shared_dep_for_both"],
+ dynamic_deps_for_shared = [":shared_dep_for_shared"],
+ dynamic_deps_for_static = [":shared_dep_for_static"],
+ implementation_deps = [":static_dep_for_both"],
+ shared_copts = ["sharedflag"],
+ shared_srcs = ["sharedonly.cpp"],
+ srcs = ["both.cpp"],
+ static_copts = ["staticflag"],
+ static_deps_for_shared = [":static_dep_for_shared"],
+ static_deps_for_static = [":static_dep_for_static"],
+ static_srcs = ["staticonly.cpp"],
+ whole_archive_deps = [":whole_static_lib_for_both"],
+ whole_archive_deps_for_shared = [":whole_static_lib_for_shared"],
+ whole_archive_deps_for_static = [":whole_static_lib_for_static"],
+)`},
+ })
+}
+
+func TestCcLibrarySharedStaticPropsInArch(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library shared/static props in arch",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/arm.cpp": "",
+ "foo/bar/x86.cpp": "",
+ "foo/bar/sharedonly.cpp": "",
+ "foo/bar/staticonly.cpp": "",
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "a",
+ arch: {
+ arm: {
+ shared: {
+ srcs: ["arm_shared.cpp"],
+ cflags: ["-DARM_SHARED"],
+ static_libs: ["arm_static_dep_for_shared"],
+ whole_static_libs: ["arm_whole_static_dep_for_shared"],
+ shared_libs: ["arm_shared_dep_for_shared"],
+ },
+ },
+ x86: {
+ static: {
+ srcs: ["x86_static.cpp"],
+ cflags: ["-DX86_STATIC"],
+ static_libs: ["x86_dep_for_static"],
+ },
+ },
+ },
+ target: {
+ android: {
+ shared: {
+ srcs: ["android_shared.cpp"],
+ cflags: ["-DANDROID_SHARED"],
+ static_libs: ["android_dep_for_shared"],
+ },
+ },
+ android_arm: {
+ shared: {
+ cflags: ["-DANDROID_ARM_SHARED"],
+ },
+ },
+ },
+ srcs: ["both.cpp"],
+ cflags: ["bothflag"],
+ static_libs: ["static_dep_for_both"],
+ static: {
+ srcs: ["staticonly.cpp"],
+ cflags: ["staticflag"],
+ static_libs: ["static_dep_for_static"],
+ },
+ shared: {
+ srcs: ["sharedonly.cpp"],
+ cflags: ["sharedflag"],
+ static_libs: ["static_dep_for_shared"],
+ },
+ bazel_module: { bp2build_available: true },
+}
+
+cc_library_static { name: "static_dep_for_shared" }
+cc_library_static { name: "static_dep_for_static" }
+cc_library_static { name: "static_dep_for_both" }
+
+cc_library_static { name: "arm_static_dep_for_shared" }
+cc_library_static { name: "arm_whole_static_dep_for_shared" }
+cc_library_static { name: "arm_shared_dep_for_shared" }
+
+cc_library_static { name: "x86_dep_for_static" }
+
+cc_library_static { name: "android_dep_for_shared" }
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "bothflag",
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ dynamic_deps_for_shared = select({
+ "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
+ "//conditions:default": [],
+ }),
+ implementation_deps = [":static_dep_for_both"],
+ shared_copts = ["sharedflag"] + select({
+ "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
+ "//conditions:default": [],
+ }),
+ shared_srcs = ["sharedonly.cpp"] + select({
+ "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["android_shared.cpp"],
+ "//conditions:default": [],
+ }),
+ srcs = ["both.cpp"],
+ static_copts = ["staticflag"] + select({
+ "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
+ "//conditions:default": [],
+ }),
+ static_deps_for_shared = [":static_dep_for_shared"] + select({
+ "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
+ "//conditions:default": [],
+ }),
+ static_deps_for_static = [":static_dep_for_static"] + select({
+ "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"],
+ "//conditions:default": [],
+ }),
+ static_srcs = ["staticonly.cpp"] + select({
+ "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
+ "//conditions:default": [],
+ }),
+ whole_archive_deps_for_shared = select({
+ "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
+
+func TestCcLibraryNonConfiguredVersionScript(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library non-configured version script",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
srcs: ["a.cpp"],
@@ -293,24 +552,73 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
- copts = ["-Ifoo/bar"],
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
srcs = ["a.cpp"],
version_script = "v.map",
)`},
+ })
+}
+
+func TestCcLibraryConfiguredVersionScript(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library configured version script",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+ cc_library {
+ name: "a",
+ srcs: ["a.cpp"],
+ arch: {
+ arm: {
+ version_script: "arm.map",
+ },
+ arm64: {
+ version_script: "arm64.map",
+ },
+ },
+
+ bazel_module: { bp2build_available: true },
+ }
+ `,
},
- {
- description: "cc_library shared_libs",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ srcs = ["a.cpp"],
+ version_script = select({
+ "//build/bazel/platforms/arch:arm": "arm.map",
+ "//build/bazel/platforms/arch:arm64": "arm64.map",
+ "//conditions:default": None,
+ }),
+)`},
+ })
+}
+
+func TestCcLibrarySharedLibs(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library shared_libs",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "mylib",
bazel_module: { bp2build_available: true },
@@ -322,26 +630,35 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
- copts = ["-Ifoo/bar"],
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
dynamic_deps = [":mylib"],
)`, `cc_library(
name = "mylib",
- copts = ["-Ifoo/bar"],
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
)`},
- },
- {
- description: "cc_library pack_relocations test",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibraryPackRelocations(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library pack_relocations test",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
srcs: ["a.cpp"],
@@ -370,16 +687,22 @@
},
bazel_module: { bp2build_available: true },
}`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
- copts = ["-Ifoo/bar"],
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
linkopts = ["-Wl,--pack-dyn-relocs=none"],
srcs = ["a.cpp"],
)`, `cc_library(
name = "b",
- copts = ["-Ifoo/bar"],
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
linkopts = select({
"//build/bazel/platforms/arch:x86_64": ["-Wl,--pack-dyn-relocs=none"],
"//conditions:default": [],
@@ -387,71 +710,144 @@
srcs = ["b.cpp"],
)`, `cc_library(
name = "c",
- copts = ["-Ifoo/bar"],
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
linkopts = select({
"//build/bazel/platforms/os:darwin": ["-Wl,--pack-dyn-relocs=none"],
"//conditions:default": [],
}),
srcs = ["c.cpp"],
)`},
+ })
+}
+
+func TestCcLibrarySpacesInCopts(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library spaces in copts",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "a",
+ cflags: ["-include header.h",],
+ bazel_module: { bp2build_available: true },
+}
+`,
},
- }
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "-include",
+ "header.h",
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+)`},
+ })
+}
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
+func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library cppflags usage",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `cc_library {
+ name: "a",
+ srcs: ["a.cpp"],
+ cflags: [
+ "-Wall",
+ ],
+ cppflags: [
+ "-fsigned-char",
+ "-pedantic",
+ ],
+ arch: {
+ arm64: {
+ cppflags: ["-DARM64=1"],
+ },
+ },
+ target: {
+ android: {
+ cppflags: ["-DANDROID=1"],
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "-Wall",
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ cppflags = [
+ "-fsigned-char",
+ "-pedantic",
+ ] + select({
+ "//build/bazel/platforms/arch:arm64": ["-DARM64=1"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["-DANDROID=1"],
+ "//conditions:default": [],
+ }),
+ srcs = ["a.cpp"],
+)`},
+ })
+}
- cc.RegisterCCBuildComponents(ctx)
- ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
- ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterForBazelConversion()
+func TestCcLibraryLabelAttributeGetTargetProperties(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library GetTargetProperties on a LabelAttribute",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+ cc_library {
+ name: "a",
+ srcs: ["a.cpp"],
+ target: {
+ android_arm: {
+ version_script: "android_arm.map",
+ },
+ linux_bionic_arm64: {
+ version_script: "linux_bionic_arm64.map",
+ },
+ },
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
+ bazel_module: { bp2build_available: true },
}
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
- }
+ `,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = [
+ "-Ifoo/bar",
+ "-I$(BINDIR)/foo/bar",
+ ],
+ srcs = ["a.cpp"],
+ version_script = select({
+ "//build/bazel/platforms/os_arch:android_arm": "android_arm.map",
+ "//build/bazel/platforms/os_arch:linux_bionic_arm64": "linux_bionic_arm64.map",
+ "//conditions:default": None,
+ }),
+)`},
+ })
}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 0905aba..264ba6b 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -15,10 +15,10 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/cc"
- "strings"
- "testing"
)
const (
@@ -40,6 +40,18 @@
}`
)
+type bp2buildTestCase struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ depsMutators []android.RegisterMutatorFunc
+ blueprint string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ dir string
+}
+
func TestCcLibraryHeadersLoadStatement(t *testing.T) {
testCases := []struct {
bazelTargets BazelTargets
@@ -64,41 +76,38 @@
t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
}
}
-
}
-func TestCcLibraryHeadersBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- preArchMutators []android.RegisterMutatorFunc
- depsMutators []android.RegisterMutatorFunc
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- }{
- {
- description: "cc_library_headers test",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- filesystem: map[string]string{
- "lib-1/lib1a.h": "",
- "lib-1/lib1b.h": "",
- "lib-2/lib2a.h": "",
- "lib-2/lib2b.h": "",
- "dir-1/dir1a.h": "",
- "dir-1/dir1b.h": "",
- "dir-2/dir2a.h": "",
- "dir-2/dir2b.h": "",
- "arch_arm64_exported_include_dir/a.h": "",
- "arch_x86_exported_include_dir/b.h": "",
- "arch_x86_64_exported_include_dir/c.h": "",
- },
- bp: soongCcLibraryHeadersPreamble + `
+func registerCcLibraryHeadersModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+}
+
+func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
+}
+
+func TestCcLibraryHeadersSimple(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers test",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ filesystem: map[string]string{
+ "lib-1/lib1a.h": "",
+ "lib-1/lib1b.h": "",
+ "lib-2/lib2a.h": "",
+ "lib-2/lib2b.h": "",
+ "dir-1/dir1a.h": "",
+ "dir-1/dir1b.h": "",
+ "dir-2/dir2a.h": "",
+ "dir-2/dir2b.h": "",
+ "arch_arm64_exported_include_dir/a.h": "",
+ "arch_x86_exported_include_dir/b.h": "",
+ "arch_x86_64_exported_include_dir/c.h": "",
+ },
+ blueprint: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "lib-1",
export_include_dirs: ["lib-1"],
@@ -129,10 +138,13 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "foo_headers",
- copts = ["-I."],
- deps = [
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ implementation_deps = [
":lib-1",
":lib-2",
],
@@ -147,22 +159,31 @@
}),
)`, `cc_library_headers(
name = "lib-1",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
includes = ["lib-1"],
)`, `cc_library_headers(
name = "lib-2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
includes = ["lib-2"],
)`},
- },
- {
- description: "cc_library_headers test with os-specific header_libs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryPreamble + `
+ })
+}
+
+func TestCcLibraryHeadersOSSpecificHeader(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers test with os-specific header_libs props",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "android-lib" }
cc_library_headers { name: "base-lib" }
cc_library_headers { name: "darwin-lib" }
@@ -183,19 +204,31 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "android-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "base-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "darwin-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "foo_headers",
- copts = ["-I."],
- deps = [":base-lib"] + select({
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ implementation_deps = [":base-lib"] + select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//build/bazel/platforms/os:darwin": [":darwin-lib"],
"//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"],
@@ -206,26 +239,41 @@
}),
)`, `cc_library_headers(
name = "fuchsia-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "linux-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "linux_bionic-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "windows-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`},
- },
- {
- description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryPreamble + `
+ })
+}
+
+func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "android-lib" }
cc_library_headers { name: "exported-lib" }
cc_library_headers {
@@ -234,32 +282,45 @@
android: { header_libs: ["android-lib"], export_header_lib_headers: ["exported-lib"] },
},
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "android-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "exported-lib",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
)`, `cc_library_headers(
name = "foo_headers",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
deps = select({
- "//build/bazel/platforms/os:android": [
- ":android-lib",
- ":exported-lib",
- ],
+ "//build/bazel/platforms/os:android": [":exported-lib"],
+ "//conditions:default": [],
+ }),
+ implementation_deps = select({
+ "//build/bazel/platforms/os:android": [":android-lib"],
"//conditions:default": [],
}),
)`},
- },
- {
- description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryPreamble + `cc_library_headers {
+ })
+}
+
+func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `cc_library_headers {
name: "foo_headers",
export_system_include_dirs: [
"shared_include_dir",
@@ -294,9 +355,12 @@
},
},
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "foo_headers",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
includes = ["shared_include_dir"] + select({
"//build/bazel/platforms/arch:arm": ["arm_include_dir"],
"//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"],
@@ -308,65 +372,5 @@
"//conditions:default": [],
}),
)`},
- },
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
-
- // TODO(jingwen): make this default for all bp2build tests
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
-
- cc.RegisterCCBuildComponents(ctx)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index bff9b07..da38adb 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -17,7 +17,8 @@
import (
"android/soong/android"
"android/soong/cc"
- "strings"
+ "android/soong/genrule"
+
"testing"
)
@@ -67,45 +68,45 @@
}
-func TestCcLibraryStaticBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- preArchMutators []android.RegisterMutatorFunc
- depsMutators []android.RegisterMutatorFunc
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- }{
- {
- description: "cc_library_static test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
- "include_dir_1/include_dir_1_a.h": "",
- "include_dir_1/include_dir_1_b.h": "",
- "include_dir_2/include_dir_2_a.h": "",
- "include_dir_2/include_dir_2_b.h": "",
- // NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
- "local_include_dir_1/local_include_dir_1_a.h": "",
- "local_include_dir_1/local_include_dir_1_b.h": "",
- "local_include_dir_2/local_include_dir_2_a.h": "",
- "local_include_dir_2/local_include_dir_2_b.h": "",
- // NOTE: export_include_dir headers *should* appear in Bazel hdrs later
- "export_include_dir_1/export_include_dir_1_a.h": "",
- "export_include_dir_1/export_include_dir_1_b.h": "",
- "export_include_dir_2/export_include_dir_2_a.h": "",
- "export_include_dir_2/export_include_dir_2_b.h": "",
- // NOTE: Soong implicitly includes headers in the current directory
- "implicit_include_1.h": "",
- "implicit_include_2.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+func registerCcLibraryStaticModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+ ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+}
+
+func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
+}
+
+func TestCcLibraryStaticSimple(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static test",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
+ "include_dir_1/include_dir_1_a.h": "",
+ "include_dir_1/include_dir_1_b.h": "",
+ "include_dir_2/include_dir_2_a.h": "",
+ "include_dir_2/include_dir_2_b.h": "",
+ // NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
+ "local_include_dir_1/local_include_dir_1_a.h": "",
+ "local_include_dir_1/local_include_dir_1_b.h": "",
+ "local_include_dir_2/local_include_dir_2_a.h": "",
+ "local_include_dir_2/local_include_dir_2_b.h": "",
+ // NOTE: export_include_dir headers *should* appear in Bazel hdrs later
+ "export_include_dir_1/export_include_dir_1_a.h": "",
+ "export_include_dir_1/export_include_dir_1_b.h": "",
+ "export_include_dir_2/export_include_dir_2_a.h": "",
+ "export_include_dir_2/export_include_dir_2_b.h": "",
+ // NOTE: Soong implicitly includes headers in the current directory
+ "implicit_include_1.h": "",
+ "implicit_include_2.h": "",
+ },
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_headers {
name: "header_lib_1",
export_include_dirs: ["header_lib_1"],
@@ -163,8 +164,8 @@
"local_include_dir_2",
],
export_include_dirs: [
- "export_include_dir_1",
- "export_include_dir_2"
+ "export_include_dir_1",
+ "export_include_dir_2"
],
header_libs: [
"header_lib_1",
@@ -173,24 +174,27 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Dflag1",
"-Dflag2",
"-Iinclude_dir_1",
+ "-I$(BINDIR)/include_dir_1",
"-Iinclude_dir_2",
+ "-I$(BINDIR)/include_dir_2",
"-Ilocal_include_dir_1",
+ "-I$(BINDIR)/local_include_dir_1",
"-Ilocal_include_dir_2",
+ "-I$(BINDIR)/local_include_dir_2",
"-I.",
+ "-I$(BINDIR)/.",
],
- deps = [
+ implementation_deps = [
":header_lib_1",
":header_lib_2",
":static_lib_1",
":static_lib_2",
- ":whole_static_lib_1",
- ":whole_static_lib_2",
],
includes = [
"export_include_dir_1",
@@ -201,48 +205,67 @@
"foo_static1.cc",
"foo_static2.cc",
],
+ whole_archive_deps = [
+ ":whole_static_lib_1",
+ ":whole_static_lib_2",
+ ],
)`, `cc_library_static(
name = "static_lib_1",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
srcs = ["static_lib_1.cc"],
)`, `cc_library_static(
name = "static_lib_2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
srcs = ["static_lib_2.cc"],
)`, `cc_library_static(
name = "whole_static_lib_1",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
srcs = ["whole_static_lib_1.cc"],
)`, `cc_library_static(
name = "whole_static_lib_2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
srcs = ["whole_static_lib_2.cc"],
)`},
+ })
+}
+
+func TestCcLibraryStaticSubpackage(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static subpackage test",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
+ // subsubpackage with subdirectory
+ "subpackage/subsubpackage/Android.bp": "",
+ "subpackage/subsubpackage/subsubpackage_header.h": "",
+ "subpackage/subsubpackage/subdirectory/subdirectory_header.h": "",
+ // subsubsubpackage with subdirectory
+ "subpackage/subsubpackage/subsubsubpackage/Android.bp": "",
+ "subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "",
+ "subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static subpackage test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- // subsubpackage with subdirectory
- "subpackage/subsubpackage/Android.bp": "",
- "subpackage/subsubpackage/subsubpackage_header.h": "",
- "subpackage/subsubpackage/subdirectory/subdirectory_header.h": "",
- // subsubsubpackage with subdirectory
- "subpackage/subsubpackage/subsubsubpackage/Android.bp": "",
- "subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "",
- "subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: [
@@ -251,70 +274,87 @@
"subpackage",
],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage",
+ "-I$(BINDIR)/subpackage",
"-I.",
+ "-I$(BINDIR)/.",
],
linkstatic = True,
)`},
+ })
+}
+
+func TestCcLibraryStaticExportIncludeDir(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static export include dir",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static export include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
export_include_dirs: ["subpackage"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
includes = ["subpackage"],
linkstatic = True,
)`},
+ })
+}
+
+func TestCcLibraryStaticExportSystemIncludeDir(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static export system include dir",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static export system include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
export_system_include_dirs: ["subpackage"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
includes = ["subpackage"],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- dir: "subpackage",
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": `
+ })
+}
+
+func TestCcLibraryStaticManyIncludeDirs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ dir: "subpackage",
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": `
cc_library_static {
name: "foo_static",
// include_dirs are workspace/root relative
@@ -328,161 +368,206 @@
include_build_directory: true,
bazel_module: { bp2build_available: true },
}`,
- "subpackage/subsubpackage/header.h": "",
- "subpackage/subsubpackage2/header.h": "",
- "subpackage/exported_subsubpackage/header.h": "",
- "subpackage2/header.h": "",
- "subpackage3/subsubpackage/header.h": "",
- },
- bp: soongCcLibraryStaticPreamble,
- expectedBazelTargets: []string{`cc_library_static(
+ "subpackage/subsubpackage/header.h": "",
+ "subpackage/subsubpackage2/header.h": "",
+ "subpackage/exported_subsubpackage/header.h": "",
+ "subpackage2/header.h": "",
+ "subpackage3/subsubpackage/header.h": "",
+ },
+ blueprint: soongCcLibraryStaticPreamble,
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage/subsubpackage",
+ "-I$(BINDIR)/subpackage/subsubpackage",
"-Isubpackage2",
+ "-I$(BINDIR)/subpackage2",
"-Isubpackage3/subsubpackage",
+ "-I$(BINDIR)/subpackage3/subsubpackage",
"-Isubpackage/subsubpackage2",
+ "-I$(BINDIR)/subpackage/subsubpackage2",
"-Isubpackage",
+ "-I$(BINDIR)/subpackage",
],
includes = ["./exported_subsubpackage"],
linkstatic = True,
)`},
+ })
+}
+
+func TestCcLibraryStaticIncludeBuildDirectoryDisabled(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static include_build_directory disabled",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static include_build_directory disabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
local_include_dirs: ["subpackage2"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage",
+ "-I$(BINDIR)/subpackage",
"-Isubpackage2",
+ "-I$(BINDIR)/subpackage2",
],
linkstatic = True,
)`},
+ })
+}
+
+func TestCcLibraryStaticIncludeBuildDirectoryEnabled(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static include_build_directory enabled",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage2/Android.bp": "",
+ "subpackage2/subpackage2_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static include_build_directory enabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage2/Android.bp": "",
- "subpackage2/subpackage2_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
local_include_dirs: ["subpackage2"],
include_build_directory: true,
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage",
+ "-I$(BINDIR)/subpackage",
"-Isubpackage2",
+ "-I$(BINDIR)/subpackage2",
"-I.",
+ "-I$(BINDIR)/.",
],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static arch-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static arch-specific static_libs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static { name: "static_dep2" }
cc_library_static {
name: "foo_static",
arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
- deps = select({
- "//build/bazel/platforms/arch:arm64": [
- ":static_dep",
- ":static_dep2",
- ],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ implementation_deps = select({
+ "//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
}),
linkstatic = True,
+ whole_archive_deps = select({
+ "//build/bazel/platforms/arch:arm64": [":static_dep2"],
+ "//conditions:default": [],
+ }),
)`, `cc_library_static(
name = "static_dep",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static os-specific static_libs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static { name: "static_dep2" }
cc_library_static {
name: "foo_static",
target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
- deps = select({
- "//build/bazel/platforms/os:android": [
- ":static_dep",
- ":static_dep2",
- ],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ implementation_deps = select({
+ "//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
}),
linkstatic = True,
+ whole_archive_deps = select({
+ "//build/bazel/platforms/os:android": [":static_dep2"],
+ "//conditions:default": [],
+ }),
)`, `cc_library_static(
name = "static_dep",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static base, arch and os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static base, arch and os-specific static_libs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static { name: "static_dep2" }
cc_library_static { name: "static_dep3" }
@@ -494,13 +579,13 @@
target: { android: { static_libs: ["static_dep3"] } },
arch: { arm64: { static_libs: ["static_dep4"] } },
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
- deps = [
- ":static_dep",
- ":static_dep2",
- ] + select({
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ implementation_deps = [":static_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":static_dep4"],
"//conditions:default": [],
}) + select({
@@ -508,90 +593,118 @@
"//conditions:default": [],
}),
linkstatic = True,
+ whole_archive_deps = [":static_dep2"],
)`, `cc_library_static(
name = "static_dep",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep3",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep4",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`},
+ })
+}
+
+func TestCcLibraryStaticSimpleExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static simple exclude_srcs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "foo-a.c": "",
+ "foo-excluded.c": "",
},
- {
- description: "cc_library_static simple exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "foo-a.c": "",
- "foo-excluded.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "foo-*.c"],
exclude_srcs: ["foo-excluded.c"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = [
+ srcs_c = [
"common.c",
"foo-a.c",
],
)`},
+ })
+}
+
+func TestCcLibraryStaticOneArchSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static one arch specific srcs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "foo-arm.c": "",
},
- {
- description: "cc_library_static one arch specific srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "foo-arm.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c"],
arch: { arm: { srcs: ["foo-arm.c"] } }
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["foo-arm.c"],
"//conditions:default": [],
}),
)`},
+ })
+}
+
+func TestCcLibraryStaticOneArchSrcsExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static one arch specific srcs and exclude_srcs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "not-for-arm.c": "",
+ "not-for-anything.c": "",
},
- {
- description: "cc_library_static one arch specific srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "not-for-arm.c": "",
- "not-for-anything.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -600,30 +713,36 @@
arm: { srcs: ["for-arm.c"], exclude_srcs: ["not-for-arm.c"] },
},
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-arm.c"],
"//conditions:default": ["not-for-arm.c"],
}),
)`},
+ })
+}
+
+func TestCcLibraryStaticTwoArchExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static arch specific exclude_srcs for 2 architectures",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "for-x86.c": "",
+ "not-for-arm.c": "",
+ "not-for-x86.c": "",
},
- {
- description: "cc_library_static arch specific exclude_srcs for 2 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "for-x86.c": "",
- "not-for-arm.c": "",
- "not-for-x86.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -633,11 +752,14 @@
x86: { srcs: ["for-x86.c"], exclude_srcs: ["not-for-x86.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-arm.c",
"not-for-x86.c",
@@ -652,26 +774,28 @@
],
}),
)`},
+ })
+}
+func TestCcLibraryStaticFourArchExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static arch specific exclude_srcs for 4 architectures",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "for-arm64.c": "",
+ "for-x86.c": "",
+ "for-x86_64.c": "",
+ "not-for-arm.c": "",
+ "not-for-arm64.c": "",
+ "not-for-x86.c": "",
+ "not-for-x86_64.c": "",
+ "not-for-everything.c": "",
},
- {
- description: "cc_library_static arch specific exclude_srcs for 4 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "for-arm64.c": "",
- "for-x86.c": "",
- "for-x86_64.c": "",
- "not-for-arm.c": "",
- "not-for-arm64.c": "",
- "not-for-x86.c": "",
- "not-for-x86_64.c": "",
- "not-for-everything.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -683,11 +807,14 @@
x86_64: { srcs: ["for-x86_64.c"], exclude_srcs: ["not-for-x86_64.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-arm.c",
"not-for-arm64.c",
@@ -720,44 +847,133 @@
],
}),
)`},
+ })
+}
+
+func TestCcLibraryStaticOneArchEmpty(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static one arch empty",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.cc": "",
+ "foo-no-arm.cc": "",
+ "foo-excluded.cc": "",
},
- {
- description: "cc_library_static multiple dep same name panic",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.cc", "foo-*.cc"],
+ exclude_srcs: ["foo-excluded.cc"],
+ arch: {
+ arm: { exclude_srcs: ["foo-no-arm.cc"] },
+ },
+}`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ srcs = ["common.cc"] + select({
+ "//build/bazel/platforms/arch:arm": [],
+ "//conditions:default": ["foo-no-arm.cc"],
+ }),
+)`},
+ })
+}
+
+func TestCcLibraryStaticOneArchEmptyOtherSet(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static one arch empty other set",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.cc": "",
+ "foo-no-arm.cc": "",
+ "x86-only.cc": "",
+ "foo-excluded.cc": "",
+ },
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.cc", "foo-*.cc"],
+ exclude_srcs: ["foo-excluded.cc"],
+ arch: {
+ arm: { exclude_srcs: ["foo-no-arm.cc"] },
+ x86: { srcs: ["x86-only.cc"] },
+ },
+}`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ srcs = ["common.cc"] + select({
+ "//build/bazel/platforms/arch:arm": [],
+ "//build/bazel/platforms/arch:x86": [
+ "foo-no-arm.cc",
+ "x86-only.cc",
+ ],
+ "//conditions:default": ["foo-no-arm.cc"],
+ }),
+)`},
+ })
+}
+
+func TestCcLibraryStaticMultipleDepSameName(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static multiple dep same name panic",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static {
name: "foo_static",
- static_libs: ["static_dep"],
- whole_static_libs: ["static_dep"],
+ static_libs: ["static_dep", "static_dep"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
- deps = [":static_dep"],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ implementation_deps = [":static_dep"],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
)`},
+ })
+}
+
+func TestCcLibraryStaticOneMultilibSrcsExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static 1 multilib srcs and exclude_srcs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-lib32.c": "",
+ "not-for-lib32.c": "",
},
- {
- description: "cc_library_static 1 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-lib32.c": "",
- "not-for-lib32.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -765,31 +981,37 @@
lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-lib32.c"],
"//build/bazel/platforms/arch:x86": ["for-lib32.c"],
"//conditions:default": ["not-for-lib32.c"],
}),
)`},
+ })
+}
+
+func TestCcLibraryStaticTwoMultilibSrcsExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static 2 multilib srcs and exclude_srcs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-lib32.c": "",
+ "for-lib64.c": "",
+ "not-for-lib32.c": "",
+ "not-for-lib64.c": "",
},
- {
- description: "cc_library_static 2 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-lib32.c": "",
- "for-lib64.c": "",
- "not-for-lib32.c": "",
- "not-for-lib64.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static2",
srcs: ["common.c", "not-for-*.c"],
@@ -798,11 +1020,14 @@
lib64: { srcs: ["for-lib64.c"], exclude_srcs: ["not-for-lib64.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static2",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-lib32.c",
"not-for-lib64.c",
@@ -825,30 +1050,33 @@
],
}),
)`},
+ })
+}
+
+func TestCcLibrarySTaticArchMultilibSrcsExcludeSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static arch and multilib srcs and exclude_srcs",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "for-arm64.c": "",
+ "for-x86.c": "",
+ "for-x86_64.c": "",
+ "for-lib32.c": "",
+ "for-lib64.c": "",
+ "not-for-arm.c": "",
+ "not-for-arm64.c": "",
+ "not-for-x86.c": "",
+ "not-for-x86_64.c": "",
+ "not-for-lib32.c": "",
+ "not-for-lib64.c": "",
+ "not-for-everything.c": "",
},
- {
- description: "cc_library_static arch and multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "for-arm64.c": "",
- "for-x86.c": "",
- "for-x86_64.c": "",
- "for-lib32.c": "",
- "for-lib64.c": "",
- "not-for-arm.c": "",
- "not-for-arm64.c": "",
- "not-for-x86.c": "",
- "not-for-x86_64.c": "",
- "not-for-lib32.c": "",
- "not-for-lib64.c": "",
- "not-for-everything.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static3",
srcs: ["common.c", "not-for-*.c"],
@@ -864,11 +1092,14 @@
lib64: { srcs: ["for-lib64.c"], exclude_srcs: ["not-for-lib64.c"] },
},
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static3",
- copts = ["-I."],
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
linkstatic = True,
- srcs = ["common.c"] + select({
+ srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-arm.c",
"for-lib32.c",
@@ -911,64 +1142,307 @@
],
}),
)`},
+ })
+}
+
+func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static arch srcs/exclude_srcs with generated files",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.cpp": "",
+ "for-x86.cpp": "",
+ "not-for-x86.cpp": "",
+ "not-for-everything.cpp": "",
+ "dep/Android.bp": `
+genrule {
+ name: "generated_src_other_pkg",
+ out: ["generated_src_other_pkg.cpp"],
+ cmd: "nothing to see here",
+}
+
+genrule {
+ name: "generated_hdr_other_pkg",
+ out: ["generated_hdr_other_pkg.cpp"],
+ cmd: "nothing to see here",
+}
+
+genrule {
+ name: "generated_hdr_other_pkg_x86",
+ out: ["generated_hdr_other_pkg_x86.cpp"],
+ cmd: "nothing to see here",
+}`,
},
- }
+ blueprint: soongCcLibraryStaticPreamble + `
+genrule {
+ name: "generated_src",
+ out: ["generated_src.cpp"],
+ cmd: "nothing to see here",
+}
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
+genrule {
+ name: "generated_src_x86",
+ out: ["generated_src_x86.cpp"],
+ cmd: "nothing to see here",
+}
- cc.RegisterCCBuildComponents(ctx)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
- ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+genrule {
+ name: "generated_hdr",
+ out: ["generated_hdr.h"],
+ cmd: "nothing to see here",
+}
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- ctx.RegisterForBazelConversion()
+cc_library_static {
+ name: "foo_static3",
+ srcs: ["common.cpp", "not-for-*.cpp"],
+ exclude_srcs: ["not-for-everything.cpp"],
+ generated_sources: ["generated_src", "generated_src_other_pkg"],
+ generated_headers: ["generated_hdr", "generated_hdr_other_pkg"],
+ arch: {
+ x86: {
+ srcs: ["for-x86.cpp"],
+ exclude_srcs: ["not-for-x86.cpp"],
+ generated_sources: ["generated_src_x86"],
+ generated_headers: ["generated_hdr_other_pkg_x86"],
+ },
+ },
+}
+`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static3",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ srcs = [
+ "//dep:generated_hdr_other_pkg",
+ "//dep:generated_src_other_pkg",
+ ":generated_hdr",
+ ":generated_src",
+ "common.cpp",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": [
+ "//dep:generated_hdr_other_pkg_x86",
+ ":generated_src_x86",
+ "for-x86.cpp",
+ ],
+ "//conditions:default": ["not-for-x86.cpp"],
+ }),
+)`},
+ })
+}
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
+func TestCcLibraryStaticGetTargetProperties(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
+ description: "cc_library_static complex GetTargetProperties",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ target: {
+ android: {
+ srcs: ["android_src.c"],
+ },
+ android_arm: {
+ srcs: ["android_arm_src.c"],
+ },
+ android_arm64: {
+ srcs: ["android_arm64_src.c"],
+ },
+ android_x86: {
+ srcs: ["android_x86_src.c"],
+ },
+ android_x86_64: {
+ srcs: ["android_x86_64_src.c"],
+ },
+ linux_bionic_arm64: {
+ srcs: ["linux_bionic_arm64_src.c"],
+ },
+ linux_bionic_x86_64: {
+ srcs: ["linux_bionic_x86_64_src.c"],
+ },
+ },
+}`,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ srcs_c = select({
+ "//build/bazel/platforms/os:android": ["android_src.c"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_arm_src.c"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_arm64_src.c"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_x86_src.c"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_x86_64_src.c"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os_arch:linux_bionic_arm64": ["linux_bionic_arm64_src.c"],
+ "//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
+
+func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static product variable selects",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.c"],
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wmalloc_not_svelte"],
+ },
+ malloc_zero_contents: {
+ cflags: ["-Wmalloc_zero_contents"],
+ },
+ binder32bit: {
+ cflags: ["-Wbinder32bit"],
+ },
+ },
+} `,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ] + select({
+ "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
+ "//conditions:default": [],
+ }),
+ linkstatic = True,
+ srcs_c = ["common.c"],
+)`},
+ })
+}
+
+func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static arch-specific product variable selects",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.c"],
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wmalloc_not_svelte"],
+ },
+ },
+ arch: {
+ arm64: {
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Warm64_malloc_not_svelte"],
+ },
+ },
+ },
+ },
+ multilib: {
+ lib32: {
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wlib32_malloc_not_svelte"],
+ },
+ },
+ },
+ },
+ target: {
+ android: {
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wandroid_malloc_not_svelte"],
+ },
+ },
}
- }
- }
- }
+ },
+} `,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ] + select({
+ "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
+ "//conditions:default": [],
+ }),
+ linkstatic = True,
+ srcs_c = ["common.c"],
+)`},
+ })
+}
+
+func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static product variable selects",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.c"],
+ product_variables: {
+ platform_sdk_version: {
+ asflags: ["-DPLATFORM_SDK_VERSION=%d"],
+ },
+ },
+} `,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ asflags = select({
+ "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
+ "//conditions:default": [],
+ }),
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ],
+ linkstatic = True,
+ srcs_c = ["common.c"],
+)`},
+ })
}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 9efdb53..57f75ea 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -15,35 +15,35 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/cc"
- "fmt"
- "strings"
- "testing"
)
-func TestCcObjectBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- }{
- {
- description: "simple cc_object generates cc_object with include header dep",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- filesystem: map[string]string{
- "a/b/foo.h": "",
- "a/b/bar.h": "",
- "a/b/exclude.c": "",
- "a/b/c.c": "",
- },
- blueprint: `cc_object {
+func registerCcObjectModuleTypes(ctx android.RegistrationContext) {
+ // Always register cc_defaults module factory
+ ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
+}
+
+func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
+}
+
+func TestCcObjectSimple(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "simple cc_object generates cc_object with include header dep",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ filesystem: map[string]string{
+ "a/b/foo.h": "",
+ "a/b/bar.h": "",
+ "a/b/exclude.c": "",
+ "a/b/c.c": "",
+ },
+ blueprint: `cc_object {
name: "foo",
local_include_dirs: ["include"],
cflags: [
@@ -57,7 +57,7 @@
exclude_srcs: ["a/b/exclude.c"],
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
copts = [
"-fno-addrsig",
@@ -65,18 +65,23 @@
"-Wall",
"-Werror",
"-Iinclude",
+ "-I$(BINDIR)/include",
"-I.",
+ "-I$(BINDIR)/.",
],
srcs = ["a/b/c.c"],
)`,
- },
},
- {
- description: "simple cc_object with defaults",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectDefaults(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "simple cc_object with defaults",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
local_include_dirs: ["include"],
srcs: [
@@ -101,7 +106,7 @@
],
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
copts = [
"-Wno-gcc-compat",
@@ -109,22 +114,26 @@
"-Werror",
"-fno-addrsig",
"-Iinclude",
+ "-I$(BINDIR)/include",
"-I.",
+ "-I$(BINDIR)/.",
],
srcs = ["a/b/c.c"],
)`,
- },
+ }})
+}
+
+func TestCcObjectCcObjetDepsInObjs(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object with cc_object deps in objs props",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ filesystem: map[string]string{
+ "a/b/c.c": "",
+ "x/y/z.c": "",
},
- {
- description: "cc_object with cc_object deps in objs props",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- filesystem: map[string]string{
- "a/b/c.c": "",
- "x/y/z.c": "",
- },
- blueprint: `cc_object {
+ blueprint: `cc_object {
name: "foo",
srcs: ["a/b/c.c"],
objs: ["bar"],
@@ -135,11 +144,12 @@
srcs: ["x/y/z.c"],
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "bar",
copts = [
"-fno-addrsig",
"-I.",
+ "-I$(BINDIR)/.",
],
srcs = ["x/y/z.c"],
)`, `cc_object(
@@ -147,40 +157,47 @@
copts = [
"-fno-addrsig",
"-I.",
+ "-I$(BINDIR)/.",
],
deps = [":bar"],
srcs = ["a/b/c.c"],
)`,
- },
},
- {
- description: "cc_object with include_build_dir: false",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- filesystem: map[string]string{
- "a/b/c.c": "",
- "x/y/z.c": "",
- },
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectIncludeBuildDirFalse(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object with include_build_dir: false",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ filesystem: map[string]string{
+ "a/b/c.c": "",
+ "x/y/z.c": "",
+ },
+ blueprint: `cc_object {
name: "foo",
srcs: ["a/b/c.c"],
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
copts = ["-fno-addrsig"],
srcs = ["a/b/c.c"],
)`,
- },
},
- {
- description: "cc_object with product variable",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectProductVariable(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ 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: {
@@ -190,82 +207,25 @@
},
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
- asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+ asflags = select({
+ "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
+ "//conditions:default": [],
+ }),
copts = ["-fno-addrsig"],
)`,
- },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
- ctx := android.NewTestContext(config)
- // Always register cc_defaults module factory
- ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- fmt.Println(bazelTargets)
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
- }
+ })
}
-func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- }{
- {
- description: "cc_object setting cflags for one arch",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+func TestCcObjectCflagsOneArch(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object setting cflags for one arch",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
srcs: ["a.cpp"],
arch: {
@@ -278,12 +238,13 @@
},
}
`,
- expectedBazelTargets: []string{
- `cc_object(
+ expectedBazelTargets: []string{
+ `cc_object(
name = "foo",
copts = [
"-fno-addrsig",
"-I.",
+ "-I$(BINDIR)/.",
] + select({
"//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
@@ -293,14 +254,17 @@
"//conditions:default": [],
}),
)`,
- },
},
- {
- description: "cc_object setting cflags for 4 architectures",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectCflagsFourArch(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object setting cflags for 4 architectures",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
arch: {
@@ -323,12 +287,13 @@
},
}
`,
- expectedBazelTargets: []string{
- `cc_object(
+ expectedBazelTargets: []string{
+ `cc_object(
name = "foo",
copts = [
"-fno-addrsig",
"-I.",
+ "-I$(BINDIR)/.",
] + select({
"//build/bazel/platforms/arch:arm": ["-Wall"],
"//build/bazel/platforms/arch:arm64": ["-Wall"],
@@ -344,14 +309,17 @@
"//conditions:default": [],
}),
)`,
- },
},
- {
- description: "cc_object setting cflags for multiple OSes",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectCflagsMultiOs(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object setting cflags for multiple OSes",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
target: {
@@ -367,12 +335,13 @@
},
}
`,
- expectedBazelTargets: []string{
- `cc_object(
+ expectedBazelTargets: []string{
+ `cc_object(
name = "foo",
copts = [
"-fno-addrsig",
"-I.",
+ "-I$(BINDIR)/.",
] + select({
"//build/bazel/platforms/os:android": ["-fPIC"],
"//build/bazel/platforms/os:darwin": ["-Wall"],
@@ -381,51 +350,6 @@
}),
srcs = ["base.cpp"],
)`,
- },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
- ctx := android.NewTestContext(config)
- // Always register cc_defaults module factory
- ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- fmt.Println(bazelTargets)
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 95a2747..7e1a298 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -11,69 +11,195 @@
type selects map[string]reflect.Value
-func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
+func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(list.Value)
if !list.HasConfigurableValues() {
- return value, nil, nil
+ return value, []selects{}
}
+ selectValues := make([]selects, 0)
archSelects := map[string]reflect.Value{}
for arch, selectKey := range bazel.PlatformArchMap {
archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
}
+ if len(archSelects) > 0 {
+ selectValues = append(selectValues, archSelects)
+ }
osSelects := map[string]reflect.Value{}
- for os, selectKey := range bazel.PlatformOsMap {
- osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
+ osArchSelects := make([]selects, 0)
+ for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
+ selectKey := bazel.PlatformOsMap[os]
+ osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os))
+ archSelects := make(map[string]reflect.Value)
+ // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (not in AllArches)
+ for _, arch := range bazel.AllArches {
+ target := os + "_" + arch
+ selectKey := bazel.PlatformTargetMap[target]
+ archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch))
+ }
+ osArchSelects = append(osArchSelects, archSelects)
+ }
+ if len(osSelects) > 0 {
+ selectValues = append(selectValues, osSelects)
+ }
+ if len(osArchSelects) > 0 {
+ selectValues = append(selectValues, osArchSelects...)
}
- return value, archSelects, osSelects
+ for _, pv := range list.SortedProductVariables() {
+ s := make(selects)
+ if len(pv.Values) > 0 {
+ s[pv.SelectKey()] = reflect.ValueOf(pv.Values)
+ s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{})
+ selectValues = append(selectValues, s)
+ }
+ }
+
+ return value, selectValues
}
-func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects) {
+func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(label.Value)
- return value, nil, nil
-}
-
-func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
- value := reflect.ValueOf(list.Value.Includes)
- if !list.HasConfigurableValues() {
- return value, nil, nil
+ if !label.HasConfigurableValues() {
+ return value, []selects{}
}
+ // Keep track of which arches and oses have been used in case we need to raise a warning
+ usedArches := make(map[string]bool)
+ usedOses := make(map[string]bool)
+
archSelects := map[string]reflect.Value{}
for arch, selectKey := range bazel.PlatformArchMap {
- archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
+ archSelects[selectKey] = reflect.ValueOf(label.GetValueForArch(arch))
+ if archSelects[selectKey].IsValid() && !isZero(archSelects[selectKey]) {
+ usedArches[arch] = true
+ }
}
osSelects := map[string]reflect.Value{}
- for os, selectKey := range bazel.PlatformOsMap {
- osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
+ for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
+ selectKey := bazel.PlatformOsMap[os]
+ osSelects[selectKey] = reflect.ValueOf(label.GetOsValueForTarget(os))
+ if osSelects[selectKey].IsValid() && !isZero(osSelects[selectKey]) {
+ usedOses[os] = true
+ }
}
- return value, archSelects, osSelects
+ osArchSelects := make([]selects, 0)
+ for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
+ archSelects := make(map[string]reflect.Value)
+ // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (not in AllArches)
+ for _, arch := range bazel.AllArches {
+ target := os + "_" + arch
+ selectKey := bazel.PlatformTargetMap[target]
+ archSelects[selectKey] = reflect.ValueOf(label.GetOsArchValueForTarget(os, arch))
+ if archSelects[selectKey].IsValid() && !isZero(archSelects[selectKey]) {
+ if _, ok := usedArches[arch]; ok {
+ fmt.Printf("WARNING: Same arch used twice in LabelAttribute select: arch '%s'\n", arch)
+ }
+ if _, ok := usedOses[os]; ok {
+ fmt.Printf("WARNING: Same os used twice in LabelAttribute select: os '%s'\n", os)
+ }
+ }
+ }
+ osArchSelects = append(osArchSelects, archSelects)
+ }
+
+ // Because we have to return a single Label, we can only use one select statement
+ combinedSelects := map[string]reflect.Value{}
+ for k, v := range archSelects {
+ combinedSelects[k] = v
+ }
+ for k, v := range osSelects {
+ combinedSelects[k] = v
+ }
+ for _, osArchSelect := range osArchSelects {
+ for k, v := range osArchSelect {
+ combinedSelects[k] = v
+ }
+ }
+
+ return value, []selects{combinedSelects}
+}
+
+func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
+ value := reflect.ValueOf(list.Value.Includes)
+ if !list.HasConfigurableValues() {
+ return value, []selects{}
+ }
+ var ret []selects
+
+ archSelects := map[string]reflect.Value{}
+ for arch, selectKey := range bazel.PlatformArchMap {
+ if use, value := labelListSelectValue(selectKey, list.GetValueForArch(arch)); use {
+ archSelects[selectKey] = value
+ }
+ }
+ if len(archSelects) > 0 {
+ ret = append(ret, archSelects)
+ }
+
+ osSelects := map[string]reflect.Value{}
+ osArchSelects := []selects{}
+ for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) {
+ selectKey := bazel.PlatformOsMap[os]
+ if use, value := labelListSelectValue(selectKey, list.GetOsValueForTarget(os)); use {
+ osSelects[selectKey] = value
+ }
+ selects := make(map[string]reflect.Value)
+ // TODO(b/187530594): Should we also check arch=CONDITIOSN_DEFAULT? (not in AllArches)
+ for _, arch := range bazel.AllArches {
+ target := os + "_" + arch
+ selectKey := bazel.PlatformTargetMap[target]
+ if use, value := labelListSelectValue(selectKey, list.GetOsArchValueForTarget(os, arch)); use {
+ selects[selectKey] = value
+ }
+ }
+ if len(selects) > 0 {
+ osArchSelects = append(osArchSelects, selects)
+ }
+ }
+ if len(osSelects) > 0 {
+ ret = append(ret, osSelects)
+ }
+ ret = append(ret, osArchSelects...)
+
+ return value, ret
+}
+
+func labelListSelectValue(selectKey string, list bazel.LabelList) (bool, reflect.Value) {
+ if selectKey == bazel.ConditionsDefaultSelectKey || len(list.Includes) > 0 {
+ return true, reflect.ValueOf(list.Includes)
+ } else if len(list.Excludes) > 0 {
+ // if there is still an excludes -- we need to have an empty list for this select & use the
+ // value in conditions default Includes
+ return true, reflect.ValueOf([]string{})
+ }
+ return false, reflect.Zero(reflect.TypeOf([]string{}))
}
// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
// select statements.
func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
var value reflect.Value
- var archSelects, osSelects selects
+ var configurableAttrs []selects
var defaultSelectValue string
switch list := v.(type) {
case bazel.StringListAttribute:
- value, archSelects, osSelects = getStringListValues(list)
+ value, configurableAttrs = getStringListValues(list)
defaultSelectValue = "[]"
case bazel.LabelListAttribute:
- value, archSelects, osSelects = getLabelListValues(list)
+ value, configurableAttrs = getLabelListValues(list)
defaultSelectValue = "[]"
case bazel.LabelAttribute:
- value, archSelects, osSelects = getLabelValue(list)
+ value, configurableAttrs = getLabelValue(list)
defaultSelectValue = "None"
default:
return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
}
+ var err error
ret := ""
if value.Kind() != reflect.Invalid {
s, err := prettyPrint(value, indent)
@@ -97,13 +223,14 @@
return s, nil
}
- ret, err := appendSelects(archSelects, defaultSelectValue, ret)
- if err != nil {
- return "", err
+ for _, configurableAttr := range configurableAttrs {
+ ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
+ if err != nil {
+ return "", err
+ }
}
- ret, err = appendSelects(osSelects, defaultSelectValue, ret)
- return ret, err
+ return ret, nil
}
// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
@@ -114,11 +241,10 @@
}
// addConditionsDefault := false
- conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT]
var selects string
for _, selectKey := range android.SortedStringKeys(selectMap) {
- if selectKey == conditionsDefaultKey {
+ if selectKey == bazel.ConditionsDefaultSelectKey {
// Handle default condition later.
continue
}
@@ -148,14 +274,14 @@
ret += selects
// Handle the default condition
- s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent)
+ s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
if err != nil {
return "", err
}
if s == "" {
// Print an explicit empty list (the default value) even if the value is
// empty, to avoid errors about not finding a configuration that matches.
- ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
+ ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
} else {
// Print the custom default value.
ret += s
diff --git a/bp2build/constants.go b/bp2build/constants.go
index 70f320e..4870dff 100644
--- a/bp2build/constants.go
+++ b/bp2build/constants.go
@@ -19,7 +19,10 @@
// be preferred for use within a Bazel build.
// The file name used for automatically generated files.
- GeneratedBuildFileName = "BUILD"
+ GeneratedBuildFileName = "BUILD.bazel"
+
// The file name used for hand-crafted build targets.
+ // NOTE: It is okay that this matches GeneratedBuildFileName, since we generate BUILD files in a different directory to source files
+ // FIXME: Because there are hundreds of existing BUILD.bazel files in the AOSP tree, we should pick another name here, like BUILD.android
HandcraftedBuildFileName = "BUILD.bazel"
)
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index d67ab3d..bced4c1 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -2,9 +2,9 @@
import (
"android/soong/android"
+ "android/soong/cc/config"
"fmt"
"reflect"
- "sort"
"strings"
"github.com/google/blueprint/proptools"
@@ -16,6 +16,15 @@
Contents string
}
+func CreateSoongInjectionFiles() []BazelFile {
+ var files []BazelFile
+
+ files = append(files, newFile("cc_toolchain", "BUILD", "")) // Creates a //cc_toolchain package.
+ files = append(files, newFile("cc_toolchain", "constants.bzl", config.BazelCcToolchainVars()))
+
+ return files
+}
+
func CreateBazelFiles(
ruleShims map[string]RuleShim,
buildToTargets map[string]BazelTargets,
@@ -49,27 +58,33 @@
func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
files := make([]BazelFile, 0, len(buildToTargets))
for _, dir := range android.SortedStringKeys(buildToTargets) {
- if mode == Bp2Build && !android.ShouldWriteBuildFileForDir(dir) {
+ if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
continue
}
targets := buildToTargets[dir]
- sort.Slice(targets, func(i, j int) bool {
- // this will cover all bp2build generated targets
- if targets[i].name < targets[j].name {
- return true
- }
- // give a strict ordering to content from hand-crafted targets
- return targets[i].content < targets[j].content
- })
- content := soongModuleLoad
+ targets.sort()
+
+ var content string
if mode == Bp2Build {
- content = `# This file was automatically generated by bp2build for the Bazel migration project.
-# Feel free to edit or test it, but do *not* check it into your version control system.`
- content += "\n\n"
- content += "package(default_visibility = [\"//visibility:public\"])"
- content += "\n\n"
+ content = `# READ THIS FIRST:
+# This file was automatically generated by bp2build for the Bazel migration project.
+# Feel free to edit or test it, but do *not* check it into your version control system.
+`
+ if targets.hasHandcraftedTargets() {
+ // For BUILD files with both handcrafted and generated targets,
+ // don't hardcode actual content, like package() declarations.
+ // Leave that responsibility to the checked-in BUILD file
+ // instead.
+ content += `# This file contains generated targets and handcrafted targets that are manually managed in the source tree.`
+ } else {
+ // For fully-generated BUILD files, hardcode the default visibility.
+ content += "package(default_visibility = [\"//visibility:public\"])"
+ }
+ content += "\n"
content += targets.LoadStatements()
+ } else if mode == QueryView {
+ content = soongModuleLoad
}
if content != "" {
// If there are load statements, add a couple of newlines.
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 262a488..0931ff7 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -29,7 +29,7 @@
expectedFilePaths := []bazelFilepath{
{
dir: "",
- basename: "BUILD",
+ basename: "BUILD.bazel",
},
{
dir: "",
@@ -37,7 +37,7 @@
},
{
dir: bazelRulesSubDir,
- basename: "BUILD",
+ basename: "BUILD.bazel",
},
{
dir: bazelRulesSubDir,
@@ -69,7 +69,7 @@
if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
- } else if actualFile.Basename == "BUILD" || actualFile.Basename == "WORKSPACE" {
+ } else if actualFile.Basename == "BUILD.bazel" || actualFile.Basename == "WORKSPACE" {
if actualFile.Contents != "" {
t.Errorf("Expected %s to have no content.", actualFile)
}
@@ -79,9 +79,33 @@
}
}
-func TestCreateBazelFiles_Bp2Build_CreatesNoFilesWithNoTargets(t *testing.T) {
- files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build)
- if len(files) != 0 {
- t.Errorf("Expected no files, got %d", len(files))
+func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
+ files := CreateSoongInjectionFiles()
+
+ expectedFilePaths := []bazelFilepath{
+ {
+ dir: "cc_toolchain",
+ basename: "BUILD",
+ },
+ {
+ dir: "cc_toolchain",
+ basename: "constants.bzl",
+ },
+ }
+
+ if len(files) != len(expectedFilePaths) {
+ t.Errorf("Expected %d file, got %d", len(expectedFilePaths), len(files))
+ }
+
+ for i := range files {
+ actualFile, expectedFile := files[i], expectedFilePaths[i]
+
+ if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
+ t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
+ }
+
+ if expectedFile.basename != "BUILD" && actualFile.Contents == "" {
+ t.Errorf("Contents of %s unexpected empty.", actualFile)
+ }
}
}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 2054e06..7bedf71 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -1,36 +1,31 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/python"
- "fmt"
- "strings"
- "testing"
)
-func TestPythonBinaryHost(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- }{
- {
- description: "simple python_binary_host converts to a native py_binary",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
- filesystem: map[string]string{
- "a.py": "",
- "b/c.py": "",
- "b/d.py": "",
- "b/e.py": "",
- "files/data.txt": "",
- },
- blueprint: `python_binary_host {
+func runPythonTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestPythonBinaryHostSimple(t *testing.T) {
+ runPythonTestCase(t, bp2buildTestCase{
+ description: "simple python_binary_host converts to a native py_binary",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ filesystem: map[string]string{
+ "a.py": "",
+ "b/c.py": "",
+ "b/d.py": "",
+ "b/e.py": "",
+ "files/data.txt": "",
+ },
+ blueprint: `python_binary_host {
name: "foo",
main: "a.py",
srcs: ["**/*.py"],
@@ -39,7 +34,7 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`py_binary(
+ expectedBazelTargets: []string{`py_binary(
name = "foo",
data = ["files/data.txt"],
main = "a.py",
@@ -49,14 +44,17 @@
"b/d.py",
],
)`,
- },
},
- {
- description: "py2 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
- blueprint: `python_binary_host {
+ })
+}
+
+func TestPythonBinaryHostPy2(t *testing.T) {
+ runPythonTestCase(t, bp2buildTestCase{
+ description: "py2 python_binary_host",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
version: {
@@ -71,19 +69,22 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`py_binary(
+ expectedBazelTargets: []string{`py_binary(
name = "foo",
python_version = "PY2",
srcs = ["a.py"],
)`,
- },
},
- {
- description: "py3 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
- blueprint: `python_binary_host {
+ })
+}
+
+func TestPythonBinaryHostPy3(t *testing.T) {
+ runPythonTestCase(t, bp2buildTestCase{
+ description: "py3 python_binary_host",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
version: {
@@ -98,60 +99,12 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- // python_version is PY3 by default.
- `py_binary(
+ expectedBazelTargets: []string{
+ // python_version is PY3 by default.
+ `py_binary(
name = "foo",
srcs = ["a.py"],
)`,
- },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
- ctx := android.NewTestContext(config)
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- fmt.Println(bazelTargets)
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 37f542e..82e0a14 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -15,10 +15,10 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/sh"
- "strings"
- "testing"
)
func TestShBinaryLoadStatement(t *testing.T) {
@@ -46,88 +46,27 @@
t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
}
}
-
}
-func TestShBinaryBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- preArchMutators []android.RegisterMutatorFunc
- depsMutators []android.RegisterMutatorFunc
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- }{
- {
- description: "sh_binary test",
- moduleTypeUnderTest: "sh_binary",
- moduleTypeUnderTestFactory: sh.ShBinaryFactory,
- moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
- bp: `sh_binary {
+func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestShBinarySimple(t *testing.T) {
+ runShBinaryTestCase(t, bp2buildTestCase{
+ description: "sh_binary test",
+ moduleTypeUnderTest: "sh_binary",
+ moduleTypeUnderTestFactory: sh.ShBinaryFactory,
+ moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
+ blueprint: `sh_binary {
name: "foo",
src: "foo.sh",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`sh_binary(
+ expectedBazelTargets: []string{`sh_binary(
name = "foo",
srcs = ["foo.sh"],
)`},
- },
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if Errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if Errored(t, testCase.description, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index b925682..e575bc6 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -1,6 +1,8 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/bazel"
)
@@ -10,6 +12,8 @@
bp2buildConfig = android.Bp2BuildConfig{
android.BP2BUILD_TOPLEVEL: android.Bp2BuildDefaultTrueRecursively,
}
+
+ buildDir string
)
type nestedProps struct {
@@ -39,6 +43,17 @@
props customProps
}
+func errored(t *testing.T, desc string, errs []error) bool {
+ t.Helper()
+ if len(errs) > 0 {
+ for _, err := range errs {
+ t.Errorf("%s: %s", desc, err)
+ }
+ return true
+ }
+ return false
+}
+
// OutputFiles is needed because some instances of this module use dist with a
// tag property which requires the module implements OutputFileProducer.
func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
diff --git a/build_kzip.bash b/build_kzip.bash
index a09335e..5655067 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -6,6 +6,8 @@
# The following environment variables affect the result:
# BUILD_NUMBER build number, used to generate unique ID (will use UUID if not set)
# SUPERPROJECT_SHA superproject sha, used to generate unique id (will use BUILD_NUMBER if not set)
+# SUPERPROJECT_REVISION superproject revision, used for unique id if defined as a sha
+# KZIP_NAME name of the output file (will use SUPERPROJECT_REVISION|SUPERPROJECT_SHA|BUILD_NUMBER|UUID if not set)
# DIST_DIR where the resulting all.kzip will be placed
# KYTHE_KZIP_ENCODING proto or json (proto is default)
# KYTHE_JAVA_SOURCE_BATCH_SIZE maximum number of the Java source files in a compilation unit
@@ -14,8 +16,16 @@
# TARGET_PRODUCT target device name, e.g., 'aosp_blueline'
# XREF_CORPUS source code repository URI, e.g., 'android.googlesource.com/platform/superproject'
-: ${BUILD_NUMBER:=$(uuidgen)}
-: ${SUPERPROJECT_SHA:=$BUILD_NUMBER}
+# If the SUPERPROJECT_REVISION is defined as a sha, use this as the default value if no
+# SUPERPROJECT_SHA is specified.
+if [[ ${SUPERPROJECT_REVISION:-} =~ [0-9a-f]{40} ]]; then
+ : ${KZIP_NAME:=${SUPERPROJECT_REVISION:-}}
+fi
+
+: ${KZIP_NAME:=${SUPERPROJECT_SHA:-}}
+: ${KZIP_NAME:=${BUILD_NUMBER:-}}
+: ${KZIP_NAME:=$(uuidgen)}
+
: ${KYTHE_JAVA_SOURCE_BATCH_SIZE:=500}
: ${KYTHE_KZIP_ENCODING:=proto}
: ${XREF_CORPUS:?should be set}
@@ -50,6 +60,6 @@
# Pack
# TODO(asmundak): this should be done by soong.
-declare -r allkzip="$SUPERPROJECT_SHA.kzip"
+declare -r allkzip="$KZIP_NAME.kzip"
"$out/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
diff --git a/build_test.bash b/build_test.bash
index 3230f2d..296a79c 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -49,6 +49,10 @@
esac
echo
+echo "Free disk space:"
+df -h
+
+echo
echo "Running Bazel smoke test..."
"${TOP}/tools/bazel" --batch --max_idle_secs=1 info
diff --git a/cc/Android.bp b/cc/Android.bp
index c32cca8..1fc8d9f 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -92,6 +92,7 @@
"object_test.go",
"prebuilt_test.go",
"proto_test.go",
+ "sanitize_test.go",
"test_data_test.go",
"vendor_public_library_test.go",
"vendor_snapshot_test.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 67f88e2..fed9936 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -14,9 +14,13 @@
package cc
import (
+ "path/filepath"
+ "strings"
+
"android/soong/android"
"android/soong/bazel"
- "path/filepath"
+
+ "github.com/google/blueprint/proptools"
)
// bp2build functions and helpers for converting cc_* modules to Bazel.
@@ -48,19 +52,51 @@
var allDeps []string
- for _, p := range module.GetTargetProperties(&BaseLinkerProperties{}) {
- // arch specific linker props
- if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+ for _, osProps := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) {
+ // os base compiler props
+ if baseCompilerProps, ok := osProps.Properties.(*BaseCompilerProperties); ok {
+ allDeps = append(allDeps, baseCompilerProps.Generated_headers...)
+ allDeps = append(allDeps, baseCompilerProps.Generated_sources...)
+ }
+ // os + arch base compiler props
+ for _, archProps := range osProps.ArchProperties {
+ if baseCompilerProps, ok := archProps.(*BaseCompilerProperties); ok {
+ allDeps = append(allDeps, baseCompilerProps.Generated_headers...)
+ allDeps = append(allDeps, baseCompilerProps.Generated_sources...)
+ }
+ }
+ }
+
+ for _, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) {
+ // arch specific compiler props
+ if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ allDeps = append(allDeps, baseCompilerProps.Generated_headers...)
+ allDeps = append(allDeps, baseCompilerProps.Generated_sources...)
+ }
+ }
+
+ for _, osProps := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) {
+ // os specific linker props
+ if baseLinkerProps, ok := osProps.Properties.(*BaseLinkerProperties); ok {
allDeps = append(allDeps, baseLinkerProps.Header_libs...)
allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...)
allDeps = append(allDeps, baseLinkerProps.Static_libs...)
allDeps = append(allDeps, baseLinkerProps.Whole_static_libs...)
}
+ // os + arch base compiler props
+ for _, archProps := range osProps.ArchProperties {
+ if baseLinkerProps, ok := archProps.(*BaseLinkerProperties); ok {
+ allDeps = append(allDeps, baseLinkerProps.Header_libs...)
+ allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...)
+ allDeps = append(allDeps, baseLinkerProps.Static_libs...)
+ allDeps = append(allDeps, baseLinkerProps.Whole_static_libs...)
+ }
+ }
}
- for _, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
+ for _, props := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
// arch specific linker props
- if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
+ if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok {
allDeps = append(allDeps, baseLinkerProps.Header_libs...)
allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...)
allDeps = append(allDeps, baseLinkerProps.Static_libs...)
@@ -70,76 +106,264 @@
// Deps in the static: { .. } and shared: { .. } props of a cc_library.
if lib, ok := module.compiler.(*libraryDecorator); ok {
- allDeps = append(allDeps, lib.SharedProperties.Shared.Static_libs...)
- allDeps = append(allDeps, lib.SharedProperties.Shared.Whole_static_libs...)
- allDeps = append(allDeps, lib.SharedProperties.Shared.Shared_libs...)
- allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
+ appendDeps := func(deps []string, p StaticOrSharedProperties) []string {
+ deps = append(deps, p.Static_libs...)
+ deps = append(deps, p.Whole_static_libs...)
+ deps = append(deps, p.Shared_libs...)
+ return deps
+ }
- allDeps = append(allDeps, lib.StaticProperties.Static.Static_libs...)
- allDeps = append(allDeps, lib.StaticProperties.Static.Whole_static_libs...)
- allDeps = append(allDeps, lib.StaticProperties.Static.Shared_libs...)
- allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+ allDeps = appendDeps(allDeps, lib.SharedProperties.Shared)
+ allDeps = appendDeps(allDeps, lib.StaticProperties.Static)
+
+ // TODO(b/186024507, b/186489250): Temporarily exclude adding
+ // system_shared_libs deps until libc and libm builds.
+ // allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
+ // allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+
+ // Deps in the target/arch nested static: { .. } and shared: { .. } props of a cc_library.
+ // target: { <target>: shared: { ... } }
+ for _, targetProps := range module.GetTargetProperties(ctx, &SharedProperties{}) {
+ if p, ok := targetProps.Properties.(*SharedProperties); ok {
+ allDeps = appendDeps(allDeps, p.Shared)
+ }
+ for _, archProperties := range targetProps.ArchProperties {
+ if p, ok := archProperties.(*SharedProperties); ok {
+ allDeps = appendDeps(allDeps, p.Shared)
+ }
+ }
+ }
+ // target: { <target>: static: { ... } }
+ for _, targetProps := range module.GetTargetProperties(ctx, &StaticProperties{}) {
+ if p, ok := targetProps.Properties.(*StaticProperties); ok {
+ allDeps = appendDeps(allDeps, p.Static)
+ }
+ for _, archProperties := range targetProps.ArchProperties {
+ if p, ok := archProperties.(*StaticProperties); ok {
+ allDeps = appendDeps(allDeps, p.Static)
+ }
+ }
+ }
+ // arch: { <arch>: shared: { ... } }
+ for _, properties := range module.GetArchProperties(ctx, &SharedProperties{}) {
+ if p, ok := properties.(*SharedProperties); ok {
+ allDeps = appendDeps(allDeps, p.Shared)
+ }
+ }
+ // arch: { <arch>: static: { ... } }
+ for _, properties := range module.GetArchProperties(ctx, &StaticProperties{}) {
+ if p, ok := properties.(*StaticProperties); ok {
+ allDeps = appendDeps(allDeps, p.Static)
+ }
+ }
}
ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
}
-type sharedAttributes struct {
- staticDeps bazel.LabelListAttribute
+// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
+// properties which apply to either the shared or static version of a cc_library module.
+type staticOrSharedAttributes struct {
+ copts bazel.StringListAttribute
+ srcs bazel.LabelListAttribute
+ staticDeps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
}
// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
-func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) sharedAttributes {
+func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes {
lib, ok := module.compiler.(*libraryDecorator)
if !ok {
- return sharedAttributes{}
+ return staticOrSharedAttributes{}
}
- var staticDeps bazel.LabelListAttribute
-
- staticDeps.Value = android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)
-
- return sharedAttributes{
- staticDeps: staticDeps,
- }
-}
-
-type staticAttributes struct {
- srcs bazel.LabelListAttribute
+ return bp2buildParseStaticOrSharedProps(ctx, module, lib, false)
}
// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
-func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticAttributes {
+func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes {
lib, ok := module.compiler.(*libraryDecorator)
if !ok {
- return staticAttributes{}
+ return staticOrSharedAttributes{}
}
- var srcs bazel.LabelListAttribute
- srcs.Value = android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)
+ return bp2buildParseStaticOrSharedProps(ctx, module, lib, true)
+}
- return staticAttributes{
- srcs: srcs,
+func bp2buildParseStaticOrSharedProps(ctx android.TopDownMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
+ var props StaticOrSharedProperties
+ if isStatic {
+ props = lib.StaticProperties.Static
+ } else {
+ props = lib.SharedProperties.Shared
+ }
+
+ attrs := staticOrSharedAttributes{
+ copts: bazel.StringListAttribute{Value: props.Cflags},
+ srcs: bazel.LabelListAttribute{Value: android.BazelLabelForModuleSrc(ctx, props.Srcs)},
+ staticDeps: bazel.LabelListAttribute{Value: android.BazelLabelForModuleDeps(ctx, props.Static_libs)},
+ dynamicDeps: bazel.LabelListAttribute{Value: android.BazelLabelForModuleDeps(ctx, props.Shared_libs)},
+ wholeArchiveDeps: bazel.LabelListAttribute{Value: android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs)},
+ }
+
+ setArchAttrs := func(arch string, props StaticOrSharedProperties) {
+ attrs.copts.SetValueForArch(arch, props.Cflags)
+ attrs.srcs.SetValueForArch(arch, android.BazelLabelForModuleSrc(ctx, props.Srcs))
+ attrs.staticDeps.SetValueForArch(arch, android.BazelLabelForModuleDeps(ctx, props.Static_libs))
+ attrs.dynamicDeps.SetValueForArch(arch, android.BazelLabelForModuleDeps(ctx, props.Shared_libs))
+ attrs.wholeArchiveDeps.SetValueForArch(arch, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs))
+ }
+
+ setTargetAttrs := func(target string, props StaticOrSharedProperties) {
+ attrs.copts.SetOsValueForTarget(target, props.Cflags)
+ attrs.srcs.SetOsValueForTarget(target, android.BazelLabelForModuleSrc(ctx, props.Srcs))
+ attrs.staticDeps.SetOsValueForTarget(target, android.BazelLabelForModuleDeps(ctx, props.Static_libs))
+ attrs.dynamicDeps.SetOsValueForTarget(target, android.BazelLabelForModuleDeps(ctx, props.Shared_libs))
+ attrs.wholeArchiveDeps.SetOsValueForTarget(target, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs))
+ }
+
+ setTargetArchAttrs := func(target, arch string, props StaticOrSharedProperties) {
+ attrs.copts.SetOsArchValueForTarget(target, arch, props.Cflags)
+ attrs.srcs.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleSrc(ctx, props.Srcs))
+ attrs.staticDeps.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleDeps(ctx, props.Static_libs))
+ attrs.dynamicDeps.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleDeps(ctx, props.Shared_libs))
+ attrs.wholeArchiveDeps.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs))
+ }
+
+ if isStatic {
+ for arch, properties := range module.GetArchProperties(ctx, &StaticProperties{}) {
+ if staticOrSharedProps, ok := properties.(*StaticProperties); ok {
+ setArchAttrs(arch.Name, staticOrSharedProps.Static)
+ }
+ }
+ for target, p := range module.GetTargetProperties(ctx, &StaticProperties{}) {
+ if staticOrSharedProps, ok := p.Properties.(*StaticProperties); ok {
+ setTargetAttrs(target.Name, staticOrSharedProps.Static)
+ }
+ for arch, archProperties := range p.ArchProperties {
+ if staticOrSharedProps, ok := archProperties.(*StaticProperties); ok {
+ setTargetArchAttrs(target.Name, arch.Name, staticOrSharedProps.Static)
+ }
+ }
+ }
+ } else {
+ for arch, p := range module.GetArchProperties(ctx, &SharedProperties{}) {
+ if staticOrSharedProps, ok := p.(*SharedProperties); ok {
+ setArchAttrs(arch.Name, staticOrSharedProps.Shared)
+ }
+ }
+ for target, p := range module.GetTargetProperties(ctx, &SharedProperties{}) {
+ if staticOrSharedProps, ok := p.Properties.(*SharedProperties); ok {
+ setTargetAttrs(target.Name, staticOrSharedProps.Shared)
+ }
+ for arch, archProperties := range p.ArchProperties {
+ if staticOrSharedProps, ok := archProperties.(*SharedProperties); ok {
+ setTargetArchAttrs(target.Name, arch.Name, staticOrSharedProps.Shared)
+ }
+ }
+ }
+ }
+
+ return attrs
+}
+
+// Convenience struct to hold all attributes parsed from prebuilt properties.
+type prebuiltAttributes struct {
+ Src bazel.LabelAttribute
+}
+
+func Bp2BuildParsePrebuiltLibraryProps(ctx android.TopDownMutatorContext, module *Module) prebuiltAttributes {
+ prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker)
+ prebuiltLinker := prebuiltLibraryLinker.prebuiltLinker
+
+ var srcLabelAttribute bazel.LabelAttribute
+
+ if len(prebuiltLinker.properties.Srcs) > 1 {
+ ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file\n")
+ }
+
+ if len(prebuiltLinker.properties.Srcs) == 1 {
+ srcLabelAttribute.Value = android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinker.properties.Srcs[0])
+ for arch, props := range module.GetArchProperties(ctx, &prebuiltLinkerProperties{}) {
+ if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok {
+ if len(prebuiltLinkerProperties.Srcs) > 1 {
+ ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for arch %s\n", arch.Name)
+ }
+ if len(prebuiltLinkerProperties.Srcs) == 1 {
+ srcLabelAttribute.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0]))
+ }
+ }
+ }
+ }
+
+ for os, targetProperties := range module.GetTargetProperties(ctx, &prebuiltLinkerProperties{}) {
+ if prebuiltLinkerProperties, ok := targetProperties.Properties.(*prebuiltLinkerProperties); ok {
+ if len(prebuiltLinkerProperties.Srcs) > 1 {
+ ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for os %s\n", os.Name)
+
+ }
+
+ if len(prebuiltLinkerProperties.Srcs) == 1 {
+ srcLabelAttribute.SetOsValueForTarget(os.Name, android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0]))
+ }
+ }
+ for arch, archProperties := range targetProperties.ArchProperties {
+ if prebuiltLinkerProperties, ok := archProperties.(*prebuiltLinkerProperties); ok {
+ if len(prebuiltLinkerProperties.Srcs) > 1 {
+ ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for os_arch %s_%s\n", os.Name, arch.Name)
+
+ }
+
+ if len(prebuiltLinkerProperties.Srcs) == 1 {
+ srcLabelAttribute.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0]))
+ }
+ }
+
+ }
+ }
+
+ return prebuiltAttributes{
+ Src: srcLabelAttribute,
}
}
// Convenience struct to hold all attributes parsed from compiler properties.
type compilerAttributes struct {
- copts bazel.StringListAttribute
+ // Options for all languages
+ copts bazel.StringListAttribute
+ // Assembly options and sources
+ asFlags bazel.StringListAttribute
+ asSrcs bazel.LabelListAttribute
+ // C options and sources
+ conlyFlags bazel.StringListAttribute
+ cSrcs bazel.LabelListAttribute
+ // C++ options and sources
+ cppFlags bazel.StringListAttribute
srcs bazel.LabelListAttribute
- includes bazel.StringListAttribute
}
// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes {
var srcs bazel.LabelListAttribute
var copts bazel.StringListAttribute
+ var asFlags bazel.StringListAttribute
+ var conlyFlags bazel.StringListAttribute
+ var cppFlags bazel.StringListAttribute
- // Creates the -I flag for a directory, while making the directory relative
+ // Creates the -I flags for a directory, while making the directory relative
// to the exec root for Bazel to work.
- includeFlag := func(dir string) string {
+ includeFlags := func(dir string) []string {
// filepath.Join canonicalizes the path, i.e. it takes care of . or .. elements.
- return "-I" + filepath.Join(ctx.ModuleDir(), dir)
+ moduleDirRootedPath := filepath.Join(ctx.ModuleDir(), dir)
+ return []string{
+ "-I" + moduleDirRootedPath,
+ // Include the bindir-rooted path (using make variable substitution). This most
+ // closely matches Bazel's native include path handling, which allows for dependency
+ // on generated headers in these directories.
+ // TODO(b/188084383): Handle local include directories in Bazel.
+ "-I$(BINDIR)/" + moduleDirRootedPath,
+ }
}
// Parse the list of module-relative include directories (-I).
@@ -149,11 +373,23 @@
return append(includeDirs, baseCompilerProps.Local_include_dirs...)
}
+ parseCommandLineFlags := func(soongFlags []string) []string {
+ var result []string
+ for _, flag := range soongFlags {
+ // Soong's cflags can contain spaces, like `-include header.h`. For
+ // Bazel's copts, split them up to be compatible with the
+ // no_copts_tokenization feature.
+ result = append(result, strings.Split(flag, " ")...)
+ }
+ return result
+ }
+
// Parse the list of copts.
parseCopts := func(baseCompilerProps *BaseCompilerProperties) []string {
- copts := append([]string{}, baseCompilerProps.Cflags...)
+ var copts []string
+ copts = append(copts, parseCommandLineFlags(baseCompilerProps.Cflags)...)
for _, dir := range parseLocalIncludeDirs(baseCompilerProps) {
- copts = append(copts, includeFlag(dir))
+ copts = append(copts, includeFlags(dir)...)
}
return copts
}
@@ -171,20 +407,31 @@
parseSrcs := func(baseCompilerProps *BaseCompilerProperties) bazel.LabelList {
// Combine the base srcs and arch-specific srcs
allSrcs := append(baseSrcs, baseCompilerProps.Srcs...)
+ // Add srcs-like dependencies such as generated files.
+ // First create a LabelList containing these dependencies, then merge the values with srcs.
+ generatedHdrsAndSrcs := baseCompilerProps.Generated_headers
+ generatedHdrsAndSrcs = append(generatedHdrsAndSrcs, baseCompilerProps.Generated_sources...)
+
+ generatedHdrsAndSrcsLabelList := android.BazelLabelForModuleDeps(ctx, generatedHdrsAndSrcs)
+
// Combine the base exclude_srcs and configuration-specific exclude_srcs
allExcludeSrcs := append(baseExcludeSrcs, baseCompilerProps.Exclude_srcs...)
- return android.BazelLabelForModuleSrcExcludes(ctx, allSrcs, allExcludeSrcs)
+ allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, allSrcs, allExcludeSrcs)
+ return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedHdrsAndSrcsLabelList)
}
for _, props := range module.compiler.compilerProps() {
if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
srcs.Value = parseSrcs(baseCompilerProps)
copts.Value = parseCopts(baseCompilerProps)
+ asFlags.Value = parseCommandLineFlags(baseCompilerProps.Asflags)
+ conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags)
+ cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags)
// Used for arch-specific srcs later.
baseSrcs = baseCompilerProps.Srcs
- baseExcludeSrcs = baseCompilerProps.Exclude_srcs
baseSrcsLabelList = parseSrcs(baseCompilerProps)
+ baseExcludeSrcs = baseCompilerProps.Exclude_srcs
break
}
}
@@ -193,9 +440,9 @@
// target has access to all headers recursively in the package, and has
// "-I<module-dir>" in its copts.
if c, ok := module.compiler.(*baseCompiler); ok && c.includeBuildDirectory() {
- copts.Value = append(copts.Value, includeFlag("."))
+ copts.Value = append(copts.Value, includeFlags(".")...)
} else if c, ok := module.compiler.(*libraryDecorator); ok && c.includeBuildDirectory() {
- copts.Value = append(copts.Value, includeFlag("."))
+ copts.Value = append(copts.Value, includeFlags(".")...)
}
for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) {
@@ -210,6 +457,9 @@
}
copts.SetValueForArch(arch.Name, parseCopts(baseCompilerProps))
+ asFlags.SetValueForArch(arch.Name, parseCommandLineFlags(baseCompilerProps.Asflags))
+ conlyFlags.SetValueForArch(arch.Name, parseCommandLineFlags(baseCompilerProps.Conlyflags))
+ cppFlags.SetValueForArch(arch.Name, parseCommandLineFlags(baseCompilerProps.Cppflags))
}
}
@@ -228,28 +478,89 @@
// TODO(b/186153868): handle the case with multiple variant types, e.g. when arch and os are both used.
srcs.SetValueForArch(bazel.CONDITIONS_DEFAULT, defaultsSrcs)
- // Handle OS specific props.
- for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
- if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ // Handle target specific properties.
+ for os, osProps := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) {
+ if baseCompilerProps, ok := osProps.Properties.(*BaseCompilerProperties); ok {
srcsList := parseSrcs(baseCompilerProps)
// TODO(b/186153868): add support for os-specific srcs and exclude_srcs
- srcs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList))
- copts.SetValueForOS(os.Name, parseCopts(baseCompilerProps))
+ if len(baseCompilerProps.Srcs) > 0 || len(baseCompilerProps.Exclude_srcs) > 0 {
+ srcs.SetOsValueForTarget(os.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList))
+ }
+ copts.SetOsValueForTarget(os.Name, parseCopts(baseCompilerProps))
+ asFlags.SetOsValueForTarget(os.Name, parseCommandLineFlags(baseCompilerProps.Asflags))
+ conlyFlags.SetOsValueForTarget(os.Name, parseCommandLineFlags(baseCompilerProps.Conlyflags))
+ cppFlags.SetOsValueForTarget(os.Name, parseCommandLineFlags(baseCompilerProps.Cppflags))
+ }
+ for arch, archProps := range osProps.ArchProperties {
+ if baseCompilerProps, ok := archProps.(*BaseCompilerProperties); ok {
+ srcsList := parseSrcs(baseCompilerProps)
+ // TODO(b/186153868): add support for os-specific srcs and exclude_srcs
+ if len(baseCompilerProps.Srcs) > 0 || len(baseCompilerProps.Exclude_srcs) > 0 {
+ srcs.SetOsArchValueForTarget(os.Name, arch.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList))
+ }
+ copts.SetOsArchValueForTarget(os.Name, arch.Name, parseCopts(baseCompilerProps))
+ asFlags.SetOsArchValueForTarget(os.Name, arch.Name, parseCommandLineFlags(baseCompilerProps.Asflags))
+ conlyFlags.SetOsArchValueForTarget(os.Name, arch.Name, parseCommandLineFlags(baseCompilerProps.Conlyflags))
+ cppFlags.SetOsArchValueForTarget(os.Name, arch.Name, parseCommandLineFlags(baseCompilerProps.Cppflags))
+ }
}
}
+ productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{
+ "Cflags": &copts,
+ "Asflags": &asFlags,
+ "CppFlags": &cppFlags,
+ }
+ productVariableProps := android.ProductVariableProperties(ctx)
+ for propName, attr := range productVarPropNameToAttribute {
+ if props, exists := productVariableProps[propName]; exists {
+ for _, prop := range props {
+ flags, ok := prop.Property.([]string)
+ if !ok {
+ ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
+ }
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
+ attr.ProductValues = append(attr.ProductValues, bazel.ProductVariableValues{
+ ProductVariable: prop.ProductConfigVariable,
+ Values: newFlags,
+ })
+ }
+ }
+ }
+
+ // Branch srcs into three language-specific groups.
+ // C++ is the "catch-all" group, and comprises generated sources because we don't
+ // know the language of these sources until the genrule is executed.
+ // TODO(b/): Handle language detection of sources in a Bazel rule.
+ isCSrc := func(s string) bool {
+ return strings.HasSuffix(s, ".c")
+ }
+ isAsmSrc := func(s string) bool {
+ return strings.HasSuffix(s, ".S") || strings.HasSuffix(s, ".s")
+ }
+ cSrcs := bazel.FilterLabelListAttribute(srcs, isCSrc)
+ asSrcs := bazel.FilterLabelListAttribute(srcs, isAsmSrc)
+ srcs = bazel.SubtractBazelLabelListAttribute(srcs, cSrcs)
+ srcs = bazel.SubtractBazelLabelListAttribute(srcs, asSrcs)
return compilerAttributes{
- srcs: srcs,
- copts: copts,
+ copts: copts,
+ srcs: srcs,
+ asFlags: asFlags,
+ asSrcs: asSrcs,
+ cSrcs: cSrcs,
+ conlyFlags: conlyFlags,
+ cppFlags: cppFlags,
}
}
// Convenience struct to hold all attributes parsed from linker properties.
type linkerAttributes struct {
- deps bazel.LabelListAttribute
- dynamicDeps bazel.LabelListAttribute
- linkopts bazel.StringListAttribute
- versionScript bazel.LabelAttribute
+ deps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
+ exportedDeps bazel.LabelListAttribute
+ linkopts bazel.StringListAttribute
+ versionScript bazel.LabelAttribute
}
// FIXME(b/187655838): Use the existing linkerFlags() function instead of duplicating logic here
@@ -265,20 +576,28 @@
// configurable attribute values.
func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
var deps bazel.LabelListAttribute
+ var exportedDeps bazel.LabelListAttribute
var dynamicDeps bazel.LabelListAttribute
+ var wholeArchiveDeps bazel.LabelListAttribute
var linkopts bazel.StringListAttribute
var versionScript bazel.LabelAttribute
+ getLibs := func(baseLinkerProps *BaseLinkerProperties) []string {
+ libs := baseLinkerProps.Header_libs
+ libs = append(libs, baseLinkerProps.Static_libs...)
+ libs = android.SortedUniqueStrings(libs)
+ return libs
+ }
+
for _, linkerProps := range module.linker.linkerProps() {
if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
- libs := baseLinkerProps.Header_libs
- libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
- libs = append(libs, baseLinkerProps.Static_libs...)
- libs = append(libs, baseLinkerProps.Whole_static_libs...)
- libs = android.SortedUniqueStrings(libs)
+ libs := getLibs(baseLinkerProps)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs))
-
+ exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs))
linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
+ wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
if baseLinkerProps.Version_script != nil {
versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
@@ -291,48 +610,72 @@
}
}
- for arch, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
- if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
- libs := baseLinkerProps.Header_libs
- libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
- libs = append(libs, baseLinkerProps.Static_libs...)
- libs = append(libs, baseLinkerProps.Whole_static_libs...)
- libs = android.SortedUniqueStrings(libs)
+ for arch, props := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
+ if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok {
+ libs := getLibs(baseLinkerProps)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
-
+ exportedDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs))
linkopts.SetValueForArch(arch.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+ wholeArchiveDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
if baseLinkerProps.Version_script != nil {
versionScript.SetValueForArch(arch.Name,
android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
+ }
+
+ sharedLibs := baseLinkerProps.Shared_libs
+ dynamicDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
+ }
+ }
+
+ for os, targetProperties := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) {
+ if baseLinkerProps, ok := targetProperties.Properties.(*BaseLinkerProperties); ok {
+ libs := getLibs(baseLinkerProps)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
+ wholeArchiveDeps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
+ deps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ exportedDeps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs))
+
+ linkopts.SetOsValueForTarget(os.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+
+ if baseLinkerProps.Version_script != nil {
+ versionScript.SetOsValueForTarget(os.Name, android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
+ }
+
+ sharedLibs := baseLinkerProps.Shared_libs
+ dynamicDeps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
+ }
+ for arch, archProperties := range targetProperties.ArchProperties {
+ if baseLinkerProps, ok := archProperties.(*BaseLinkerProperties); ok {
+ libs := getLibs(baseLinkerProps)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
+ wholeArchiveDeps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
+ deps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ exportedDeps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs))
+
+ linkopts.SetOsArchValueForTarget(os.Name, arch.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+
+ if baseLinkerProps.Version_script != nil {
+ versionScript.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
+ }
sharedLibs := baseLinkerProps.Shared_libs
- dynamicDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
+ dynamicDeps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
}
}
}
- for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) {
- if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
- libs := baseLinkerProps.Header_libs
- libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
- libs = append(libs, baseLinkerProps.Static_libs...)
- libs = append(libs, baseLinkerProps.Whole_static_libs...)
- libs = android.SortedUniqueStrings(libs)
- deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
-
- linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps))
-
- sharedLibs := baseLinkerProps.Shared_libs
- dynamicDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
- }
- }
-
return linkerAttributes{
- deps: deps,
- dynamicDeps: dynamicDeps,
- linkopts: linkopts,
- versionScript: versionScript,
+ deps: deps,
+ exportedDeps: exportedDeps,
+ dynamicDeps: dynamicDeps,
+ wholeArchiveDeps: wholeArchiveDeps,
+ linkopts: linkopts,
+ versionScript: versionScript,
}
}
@@ -359,11 +702,20 @@
return relativePaths
}
-// bp2BuildParseExportedIncludes creates a string list attribute contains the
-// exported included directories of a module.
func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
libraryDecorator := module.linker.(*libraryDecorator)
+ return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator)
+}
+func Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
+ prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker)
+ libraryDecorator := prebuiltLibraryLinker.libraryDecorator
+ return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator)
+}
+
+// bp2BuildParseExportedIncludes creates a string list attribute contains the
+// exported included directories of a module.
+func bp2BuildParseExportedIncludesHelper(ctx android.TopDownMutatorContext, module *Module, libraryDecorator *libraryDecorator) bazel.StringListAttribute {
// Export_system_include_dirs and export_include_dirs are already module dir
// relative, so they don't need to be relativized like include_dirs, which
// are root-relative.
@@ -371,32 +723,38 @@
includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
+ getVariantIncludeDirs := func(includeDirs []string, flagExporterProperties *FlagExporterProperties) []string {
+ variantIncludeDirs := flagExporterProperties.Export_system_include_dirs
+ variantIncludeDirs = append(variantIncludeDirs, flagExporterProperties.Export_include_dirs...)
+
+ // To avoid duplicate includes when base includes + arch includes are combined
+ // TODO: This doesn't take conflicts between arch and os includes into account
+ variantIncludeDirs = bazel.SubtractStrings(variantIncludeDirs, includeDirs)
+ return variantIncludeDirs
+ }
+
for arch, props := range module.GetArchProperties(ctx, &FlagExporterProperties{}) {
if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
- archIncludeDirs := flagExporterProperties.Export_system_include_dirs
- archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...)
-
- // To avoid duplicate includes when base includes + arch includes are combined
- // FIXME: This doesn't take conflicts between arch and os includes into account
- archIncludeDirs = bazel.SubtractStrings(archIncludeDirs, includeDirs)
-
+ archIncludeDirs := getVariantIncludeDirs(includeDirs, flagExporterProperties)
if len(archIncludeDirs) > 0 {
includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs)
}
}
}
- for os, props := range module.GetTargetProperties(&FlagExporterProperties{}) {
- if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
- osIncludeDirs := flagExporterProperties.Export_system_include_dirs
- osIncludeDirs = append(osIncludeDirs, flagExporterProperties.Export_include_dirs...)
-
- // To avoid duplicate includes when base includes + os includes are combined
- // FIXME: This doesn't take conflicts between arch and os includes into account
- osIncludeDirs = bazel.SubtractStrings(osIncludeDirs, includeDirs)
-
- if len(osIncludeDirs) > 0 {
- includeDirsAttribute.SetValueForOS(os.Name, osIncludeDirs)
+ for os, targetProperties := range module.GetTargetProperties(ctx, &FlagExporterProperties{}) {
+ if flagExporterProperties, ok := targetProperties.Properties.(*FlagExporterProperties); ok {
+ targetIncludeDirs := getVariantIncludeDirs(includeDirs, flagExporterProperties)
+ if len(targetIncludeDirs) > 0 {
+ includeDirsAttribute.SetOsValueForTarget(os.Name, targetIncludeDirs)
+ }
+ }
+ for arch, archProperties := range targetProperties.ArchProperties {
+ if flagExporterProperties, ok := archProperties.(*FlagExporterProperties); ok {
+ targetIncludeDirs := getVariantIncludeDirs(includeDirs, flagExporterProperties)
+ if len(targetIncludeDirs) > 0 {
+ includeDirsAttribute.SetOsArchValueForTarget(os.Name, arch.Name, targetIncludeDirs)
+ }
}
}
}
diff --git a/cc/builder.go b/cc/builder.go
index 29cde9d..fae9522 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -534,7 +534,7 @@
Implicits: cFlagsDeps,
OrderOnly: pathDeps,
Args: map[string]string{
- "windresCmd": gccCmd(flags.toolchain, "windres"),
+ "windresCmd": mingwCmd(flags.toolchain, "windres"),
"flags": flags.toolchain.WindresFlags(),
},
})
@@ -804,6 +804,7 @@
ImplicitOutputs: implicitOutputs,
Inputs: objFiles,
Implicits: deps,
+ OrderOnly: sharedLibs,
Args: args,
})
}
@@ -1068,6 +1069,6 @@
})
}
-func gccCmd(toolchain config.Toolchain, cmd string) string {
+func mingwCmd(toolchain config.Toolchain, cmd string) string {
return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
}
diff --git a/cc/cc.go b/cc/cc.go
index 16a49d3..91c4417 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -726,15 +726,8 @@
runtimeDepTag = installDependencyTag{name: "runtime lib"}
testPerSrcDepTag = dependencyTag{name: "test_per_src"}
stubImplDepTag = dependencyTag{name: "stub_impl"}
- llndkStubDepTag = dependencyTag{name: "llndk stub"}
)
-type copyDirectlyInAnyApexDependencyTag dependencyTag
-
-func (copyDirectlyInAnyApexDependencyTag) CopyDirectlyInAnyApex() {}
-
-var _ android.CopyDirectlyInAnyApexTag = copyDirectlyInAnyApexDependencyTag{}
-
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
ccLibDepTag, ok := depTag.(libraryDependencyTag)
return ok && ccLibDepTag.shared()
@@ -841,6 +834,10 @@
c.Properties.HideFromMake = true
}
+func (c *Module) HiddenFromMake() bool {
+ return c.Properties.HideFromMake
+}
+
func (c *Module) Toc() android.OptionalPath {
if c.linker != nil {
if library, ok := c.linker.(libraryInterface); ok {
@@ -1088,12 +1085,6 @@
return false
}
-// Returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
-// "product" and "vendor" variant modules return true for this function.
-// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
-// "soc_specific: true" and more vendor installed modules are included here.
-// When PRODUCT_PRODUCT_VNDK_VERSION is set, product variants of "product_available: true" or
-// "product_specific: true" modules are included here.
func (c *Module) UseVndk() bool {
return c.Properties.VndkVersion != ""
}
@@ -1141,6 +1132,18 @@
return c.VendorProperties.IsVendorPublicLibrary
}
+func (c *Module) HasLlndkStubs() bool {
+ lib := moduleLibraryInterface(c)
+ return lib != nil && lib.hasLLNDKStubs()
+}
+
+func (c *Module) StubsVersion() string {
+ if lib, ok := c.linker.(versionedInterface); ok {
+ return lib.stubsVersion()
+ }
+ panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", c.BaseModuleName()))
+}
+
// isImplementationForLLNDKPublic returns true for any variant of a cc_library that has LLNDK stubs
// and does not set llndk.vendor_available: false.
func (c *Module) isImplementationForLLNDKPublic() bool {
@@ -1185,7 +1188,7 @@
return false
}
-func (c *Module) isVndkSp() bool {
+func (c *Module) IsVndkSp() bool {
if vndkdep := c.vndkdep; vndkdep != nil {
return vndkdep.isVndkSp()
}
@@ -1204,7 +1207,7 @@
}
func (c *Module) MustUseVendorVariant() bool {
- return c.isVndkSp() || c.Properties.MustUseVendorVariant
+ return c.IsVndkSp() || c.Properties.MustUseVendorVariant
}
func (c *Module) getVndkExtendsModuleName() string {
@@ -1343,11 +1346,11 @@
}
func (ctx *moduleContextImpl) binary() bool {
- return ctx.mod.binary()
+ return ctx.mod.Binary()
}
func (ctx *moduleContextImpl) object() bool {
- return ctx.mod.object()
+ return ctx.mod.Object()
}
func (ctx *moduleContextImpl) canUseSdk() bool {
@@ -1445,7 +1448,7 @@
}
func (ctx *moduleContextImpl) isVndkSp() bool {
- return ctx.mod.isVndkSp()
+ return ctx.mod.IsVndkSp()
}
func (ctx *moduleContextImpl) IsVndkExt() bool {
@@ -1786,7 +1789,7 @@
// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or
// RECOVERY_SNAPSHOT_VERSION is current.
if i, ok := c.linker.(snapshotLibraryInterface); ok {
- if shouldCollectHeadersForSnapshot(ctx, c, apexInfo) {
+ if ShouldCollectHeadersForSnapshot(ctx, c, apexInfo) {
i.collectHeadersForSnapshot(ctx)
}
}
@@ -1799,7 +1802,7 @@
// modules can be hidden from make as some are needed for resolving make side
// dependencies.
c.HideFromMake()
- } else if !c.installable(apexInfo) {
+ } else if !installable(c, apexInfo) {
c.SkipInstall()
}
@@ -2451,7 +2454,7 @@
return true
}
- if to.isVndkSp() || to.IsLlndk() {
+ if to.IsVndkSp() || to.IsLlndk() {
return false
}
@@ -2823,7 +2826,7 @@
// Add the dependency to the APEX(es) providing the library so that
// m <module> can trigger building the APEXes as well.
depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
- for _, an := range depApexInfo.InApexes {
+ for _, an := range depApexInfo.InApexVariants {
c.Properties.ApexesProvidingSharedLibs = append(
c.Properties.ApexesProvidingSharedLibs, an)
}
@@ -3064,7 +3067,7 @@
return false
}
-func (c *Module) binary() bool {
+func (c *Module) Binary() bool {
if b, ok := c.linker.(interface {
binary() bool
}); ok {
@@ -3073,7 +3076,7 @@
return false
}
-func (c *Module) object() bool {
+func (c *Module) Object() bool {
if o, ok := c.linker.(interface {
object() bool
}); ok {
@@ -3155,18 +3158,25 @@
}
}
-// Return true if the module is ever installable.
func (c *Module) EverInstallable() bool {
return c.installer != nil &&
// Check to see whether the module is actually ever installable.
c.installer.everInstallable()
}
-func (c *Module) installable(apexInfo android.ApexInfo) bool {
+func (c *Module) PreventInstall() bool {
+ return c.Properties.PreventInstall
+}
+
+func (c *Module) Installable() *bool {
+ return c.Properties.Installable
+}
+
+func installable(c LinkableInterface, apexInfo android.ApexInfo) bool {
ret := c.EverInstallable() &&
// Check to see whether the module has been configured to not be installed.
- proptools.BoolDefault(c.Properties.Installable, true) &&
- !c.Properties.PreventInstall && c.outputFile.Valid()
+ proptools.BoolDefault(c.Installable(), true) &&
+ !c.PreventInstall() && c.OutputFile().Valid()
// The platform variant doesn't need further condition. Apex variants however might not
// be installable because it will likely to be included in the APEX and won't appear
@@ -3213,6 +3223,9 @@
return false
}
}
+ if cc.IsLlndk() {
+ return false
+ }
if isLibDepTag && c.static() && libDepTag.shared() {
// shared_lib dependency from a static lib is considered as crossing
// the APEX boundary because the dependency doesn't actually is
@@ -3224,8 +3237,8 @@
return false
}
}
- if depTag == stubImplDepTag || depTag == llndkStubDepTag {
- // We don't track beyond LLNDK or from an implementation library to its stubs.
+ if depTag == stubImplDepTag {
+ // We don't track from an implementation library to its stubs.
return false
}
if depTag == staticVariantTag {
@@ -3279,6 +3292,12 @@
return nil
}
+// Implements android.ApexModule
+func (c *Module) AlwaysRequiresPlatformApexVariant() bool {
+ // stub libraries and native bridge libraries are always available to platform
+ return c.IsStubs() || c.Target().NativeBridge == android.NativeBridgeEnabled
+}
+
//
// Defaults
//
diff --git a/cc/cc_test.go b/cc/cc_test.go
index e9daf33..7fc044d 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -381,8 +381,8 @@
if !mod.IsVndk() {
t.Errorf("%q IsVndk() must equal to true", name)
}
- if mod.isVndkSp() != isVndkSp {
- t.Errorf("%q isVndkSp() must equal to %t", name, isVndkSp)
+ if mod.IsVndkSp() != isVndkSp {
+ t.Errorf("%q IsVndkSp() must equal to %t", name, isVndkSp)
}
// Check VNDK extension properties.
@@ -554,6 +554,13 @@
}
}
+ cc_library {
+ name: "libclang_rt.hwasan-llndk",
+ llndk: {
+ symbol_file: "libclang_rt.hwasan.map.txt",
+ }
+ }
+
cc_library_headers {
name: "libllndk_headers",
llndk: {
@@ -661,7 +668,7 @@
"VNDK-product: libvndk_product.so",
"VNDK-product: libvndk_sp_product_private-x.so",
})
- checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"})
+ checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libclang_rt.hwasan-llndk.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"})
checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so", "libvndk_product.so"})
checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
@@ -2792,12 +2799,8 @@
}
}
expected := []string{
- "android_vendor.29_arm64_armv8-a_shared_1",
- "android_vendor.29_arm64_armv8-a_shared_2",
"android_vendor.29_arm64_armv8-a_shared_current",
"android_vendor.29_arm64_armv8-a_shared",
- "android_vendor.29_arm_armv7-a-neon_shared_1",
- "android_vendor.29_arm_armv7-a-neon_shared_2",
"android_vendor.29_arm_armv7-a-neon_shared_current",
"android_vendor.29_arm_armv7-a-neon_shared",
}
@@ -2806,9 +2809,6 @@
params := result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub")
android.AssertSame(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
- params = result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared_1").Description("generate stub")
- android.AssertSame(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
-
checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) {
t.Helper()
m := result.ModuleForTests(module, variant).Module()
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 5ef247d..e4a8b62 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -10,6 +10,7 @@
"soong-remoteexec",
],
srcs: [
+ "bp2build.go",
"clang.go",
"global.go",
"tidy.go",
@@ -31,6 +32,7 @@
"arm64_linux_host.go",
],
testSrcs: [
+ "bp2build_test.go",
"tidy_test.go",
],
}
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index a402f8f..439084e 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -163,56 +163,49 @@
)
const (
+ name = "arm"
armGccVersion = "4.9"
+ gccTriple = "arm-linux-androideabi"
+ clangTriple = "armv7a-linux-androideabi"
)
func init() {
pctx.StaticVariable("armGccVersion", armGccVersion)
- pctx.SourcePathVariable("ArmGccRoot",
- "prebuilts/gcc/${HostPrebuiltTag}/arm/arm-linux-androideabi-${armGccVersion}")
+ pctx.SourcePathVariable("ArmGccRoot", "prebuilts/gcc/${HostPrebuiltTag}/arm/arm-linux-androideabi-${armGccVersion}")
- pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
- pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
+ // Just exported. Not created as a Ninja static variable.
+ exportedStringVars.Set("ArmClangTriple", clangTriple)
+
+ exportStringListStaticVariable("ArmLdflags", armLdflags)
+ exportStringListStaticVariable("ArmLldflags", armLldflags)
// Clang cflags
- pctx.StaticVariable("ArmToolchainClangCflags", strings.Join(ClangFilterUnknownCflags(armToolchainCflags), " "))
- pctx.StaticVariable("ArmClangCflags", strings.Join(ClangFilterUnknownCflags(armCflags), " "))
- pctx.StaticVariable("ArmClangLdflags", strings.Join(ClangFilterUnknownCflags(armLdflags), " "))
- pctx.StaticVariable("ArmClangLldflags", strings.Join(ClangFilterUnknownCflags(armLldflags), " "))
- pctx.StaticVariable("ArmClangCppflags", strings.Join(ClangFilterUnknownCflags(armCppflags), " "))
+ exportStringListStaticVariable("ArmToolchainClangCflags", ClangFilterUnknownCflags(armToolchainCflags))
+ exportStringListStaticVariable("ArmClangCflags", ClangFilterUnknownCflags(armCflags))
+ exportStringListStaticVariable("ArmClangLdflags", ClangFilterUnknownCflags(armLdflags))
+ exportStringListStaticVariable("ArmClangLldflags", ClangFilterUnknownCflags(armLldflags))
+ exportStringListStaticVariable("ArmClangCppflags", ClangFilterUnknownCflags(armCppflags))
// Clang ARM vs. Thumb instruction set cflags
- pctx.StaticVariable("ArmClangArmCflags", strings.Join(ClangFilterUnknownCflags(armArmCflags), " "))
- pctx.StaticVariable("ArmClangThumbCflags", strings.Join(ClangFilterUnknownCflags(armThumbCflags), " "))
+ exportStringListStaticVariable("ArmClangArmCflags", ClangFilterUnknownCflags(armArmCflags))
+ exportStringListStaticVariable("ArmClangThumbCflags", ClangFilterUnknownCflags(armThumbCflags))
// Clang arch variant cflags
- pctx.StaticVariable("ArmClangArmv7ACflags",
- strings.Join(armClangArchVariantCflags["armv7-a"], " "))
- pctx.StaticVariable("ArmClangArmv7ANeonCflags",
- strings.Join(armClangArchVariantCflags["armv7-a-neon"], " "))
- pctx.StaticVariable("ArmClangArmv8ACflags",
- strings.Join(armClangArchVariantCflags["armv8-a"], " "))
- pctx.StaticVariable("ArmClangArmv82ACflags",
- strings.Join(armClangArchVariantCflags["armv8-2a"], " "))
+ exportStringListStaticVariable("ArmClangArmv7ACflags", armClangArchVariantCflags["armv7-a"])
+ exportStringListStaticVariable("ArmClangArmv7ANeonCflags", armClangArchVariantCflags["armv7-a-neon"])
+ exportStringListStaticVariable("ArmClangArmv8ACflags", armClangArchVariantCflags["armv8-a"])
+ exportStringListStaticVariable("ArmClangArmv82ACflags", armClangArchVariantCflags["armv8-2a"])
// Clang cpu variant cflags
- pctx.StaticVariable("ArmClangGenericCflags",
- strings.Join(armClangCpuVariantCflags[""], " "))
- pctx.StaticVariable("ArmClangCortexA7Cflags",
- strings.Join(armClangCpuVariantCflags["cortex-a7"], " "))
- pctx.StaticVariable("ArmClangCortexA8Cflags",
- strings.Join(armClangCpuVariantCflags["cortex-a8"], " "))
- pctx.StaticVariable("ArmClangCortexA15Cflags",
- strings.Join(armClangCpuVariantCflags["cortex-a15"], " "))
- pctx.StaticVariable("ArmClangCortexA53Cflags",
- strings.Join(armClangCpuVariantCflags["cortex-a53"], " "))
- pctx.StaticVariable("ArmClangCortexA55Cflags",
- strings.Join(armClangCpuVariantCflags["cortex-a55"], " "))
- pctx.StaticVariable("ArmClangKraitCflags",
- strings.Join(armClangCpuVariantCflags["krait"], " "))
- pctx.StaticVariable("ArmClangKryoCflags",
- strings.Join(armClangCpuVariantCflags["kryo"], " "))
+ exportStringListStaticVariable("ArmClangGenericCflags", armClangCpuVariantCflags[""])
+ exportStringListStaticVariable("ArmClangCortexA7Cflags", armClangCpuVariantCflags["cortex-a7"])
+ exportStringListStaticVariable("ArmClangCortexA8Cflags", armClangCpuVariantCflags["cortex-a8"])
+ exportStringListStaticVariable("ArmClangCortexA15Cflags", armClangCpuVariantCflags["cortex-a15"])
+ exportStringListStaticVariable("ArmClangCortexA53Cflags", armClangCpuVariantCflags["cortex-a53"])
+ exportStringListStaticVariable("ArmClangCortexA55Cflags", armClangCpuVariantCflags["cortex-a55"])
+ exportStringListStaticVariable("ArmClangKraitCflags", armClangCpuVariantCflags["krait"])
+ exportStringListStaticVariable("ArmClangKryoCflags", armClangCpuVariantCflags["kryo"])
}
var (
@@ -251,7 +244,7 @@
}
func (t *toolchainArm) Name() string {
- return "arm"
+ return name
}
func (t *toolchainArm) GccRoot() string {
@@ -259,7 +252,7 @@
}
func (t *toolchainArm) GccTriple() string {
- return "arm-linux-androideabi"
+ return gccTriple
}
func (t *toolchainArm) GccVersion() string {
@@ -272,7 +265,7 @@
func (t *toolchainArm) ClangTriple() string {
// http://b/72619014 work around llvm LTO bug.
- return "armv7a-linux-androideabi"
+ return clangTriple
}
func (t *toolchainArm) ndkTriple() string {
@@ -312,7 +305,7 @@
}
func (toolchainArm) LibclangRuntimeLibraryArch() string {
- return "arm"
+ return name
}
func armToolchainFactory(arch android.Arch) Toolchain {
diff --git a/cc/config/bp2build.go b/cc/config/bp2build.go
new file mode 100644
index 0000000..19571f1
--- /dev/null
+++ b/cc/config/bp2build.go
@@ -0,0 +1,169 @@
+// 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 config
+
+import (
+ "android/soong/android"
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// Helpers for exporting cc configuration information to Bazel.
+var (
+ // Map containing toolchain variables that are independent of the
+ // environment variables of the build.
+ exportedStringListVars = exportedStringListVariables{}
+ exportedStringVars = exportedStringVariables{}
+)
+
+type exportedStringVariables map[string]string
+type exportedStringListVariables map[string][]string
+
+func (m exportedStringVariables) Set(k string, v string) {
+ m[k] = v
+}
+
+// Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
+func exportStringStaticVariable(name string, value string) {
+ pctx.StaticVariable(name, value)
+ exportedStringVars.Set(name, value)
+}
+
+func (m exportedStringListVariables) Set(k string, v []string) {
+ m[k] = v
+}
+
+// Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
+func exportStringListStaticVariable(name string, value []string) {
+ pctx.StaticVariable(name, strings.Join(value, " "))
+ exportedStringListVars.Set(name, value)
+}
+
+// BazelCcToolchainVars generates bzl file content containing variables for
+// Bazel's cc_toolchain configuration.
+func BazelCcToolchainVars() string {
+ ret := "# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.\n\n"
+
+ // Ensure that string s has no invalid characters to be generated into the bzl file.
+ validateCharacters := func(s string) string {
+ for _, c := range []string{`\n`, `"`, `\`} {
+ if strings.Contains(s, c) {
+ panic(fmt.Errorf("%s contains illegal character %s", s, c))
+ }
+ }
+ return s
+ }
+
+ // For each exported variable, recursively expand elements in the variableValue
+ // list to ensure that interpolated variables are expanded according to their values
+ // in the variable scope.
+ for _, k := range android.SortedStringKeys(exportedStringListVars) {
+ variableValue := exportedStringListVars[k]
+ var expandedVars []string
+ for _, v := range variableValue {
+ expandedVars = append(expandedVars, expandVar(v, exportedStringVars, exportedStringListVars)...)
+ }
+ // Build the list for this variable.
+ list := "["
+ for _, flag := range expandedVars {
+ list += fmt.Sprintf("\n \"%s\",", validateCharacters(flag))
+ }
+ list += "\n]"
+ // Assign the list as a bzl-private variable; this variable will be exported
+ // out through a constants struct later.
+ ret += fmt.Sprintf("_%s = %s\n", k, list)
+ ret += "\n"
+ }
+
+ for _, k := range android.SortedStringKeys(exportedStringVars) {
+ variableValue := exportedStringVars[k]
+ expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
+ if len(expandedVar) > 1 {
+ panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
+ }
+ ret += fmt.Sprintf("_%s = \"%s\"\n", k, validateCharacters(expandedVar[0]))
+ ret += "\n"
+ }
+
+ // Build the exported constants struct.
+ ret += "constants = struct(\n"
+ for _, k := range android.SortedStringKeys(exportedStringVars) {
+ ret += fmt.Sprintf(" %s = _%s,\n", k, k)
+ }
+ for _, k := range android.SortedStringKeys(exportedStringListVars) {
+ ret += fmt.Sprintf(" %s = _%s,\n", k, k)
+ }
+ ret += ")"
+ return ret
+}
+
+// expandVar recursively expand interpolated variables in the exportedVars scope.
+//
+// We're using a string slice to track the seen variables to avoid
+// stackoverflow errors with infinite recursion. it's simpler to use a
+// string slice than to handle a pass-by-referenced map, which would make it
+// quite complex to track depth-first interpolations. It's also unlikely the
+// interpolation stacks are deep (n > 1).
+func expandVar(toExpand string, stringScope exportedStringVariables, stringListScope exportedStringListVariables) []string {
+ // e.g. "${ClangExternalCflags}"
+ r := regexp.MustCompile(`\${([a-zA-Z0-9_]+)}`)
+
+ // Internal recursive function.
+ var expandVarInternal func(string, map[string]bool) []string
+ expandVarInternal = func(toExpand string, seenVars map[string]bool) []string {
+ var ret []string
+ for _, v := range strings.Split(toExpand, " ") {
+ matches := r.FindStringSubmatch(v)
+ if len(matches) == 0 {
+ return []string{v}
+ }
+
+ if len(matches) != 2 {
+ panic(fmt.Errorf(
+ "Expected to only match 1 subexpression in %s, got %d",
+ v,
+ len(matches)-1))
+ }
+
+ // Index 1 of FindStringSubmatch contains the subexpression match
+ // (variable name) of the capture group.
+ variable := matches[1]
+ // toExpand contains a variable.
+ if _, ok := seenVars[variable]; ok {
+ panic(fmt.Errorf(
+ "Unbounded recursive interpolation of variable: %s", variable))
+ }
+ // A map is passed-by-reference. Create a new map for
+ // this scope to prevent variables seen in one depth-first expansion
+ // to be also treated as "seen" in other depth-first traversals.
+ newSeenVars := map[string]bool{}
+ for k := range seenVars {
+ newSeenVars[k] = true
+ }
+ newSeenVars[variable] = true
+ if unexpandedVars, ok := stringListScope[variable]; ok {
+ for _, unexpandedVar := range unexpandedVars {
+ ret = append(ret, expandVarInternal(unexpandedVar, newSeenVars)...)
+ }
+ } else if unexpandedVar, ok := stringScope[variable]; ok {
+ ret = append(ret, expandVarInternal(unexpandedVar, newSeenVars)...)
+ }
+ }
+ return ret
+ }
+
+ return expandVarInternal(toExpand, map[string]bool{})
+}
diff --git a/cc/config/bp2build_test.go b/cc/config/bp2build_test.go
new file mode 100644
index 0000000..a4745e6
--- /dev/null
+++ b/cc/config/bp2build_test.go
@@ -0,0 +1,117 @@
+// 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 config
+
+import (
+ "testing"
+)
+
+func TestExpandVars(t *testing.T) {
+ testCases := []struct {
+ description string
+ stringScope exportedStringVariables
+ stringListScope exportedStringListVariables
+ toExpand string
+ expectedValues []string
+ }{
+ {
+ description: "no expansion for non-interpolated value",
+ toExpand: "foo",
+ expectedValues: []string{"foo"},
+ },
+ {
+ description: "single level expansion for string var",
+ stringScope: exportedStringVariables{
+ "foo": "bar",
+ },
+ toExpand: "${foo}",
+ expectedValues: []string{"bar"},
+ },
+ {
+ description: "single level expansion string list var",
+ stringListScope: exportedStringListVariables{
+ "foo": []string{"bar"},
+ },
+ toExpand: "${foo}",
+ expectedValues: []string{"bar"},
+ },
+ {
+ description: "mixed level expansion for string list var",
+ stringScope: exportedStringVariables{
+ "foo": "${bar}",
+ "qux": "hello",
+ },
+ stringListScope: exportedStringListVariables{
+ "bar": []string{"baz", "${qux}"},
+ },
+ toExpand: "${foo}",
+ expectedValues: []string{"baz", "hello"},
+ },
+ {
+ description: "double level expansion",
+ stringListScope: exportedStringListVariables{
+ "foo": []string{"${bar}"},
+ "bar": []string{"baz"},
+ },
+ toExpand: "${foo}",
+ expectedValues: []string{"baz"},
+ },
+ {
+ description: "double level expansion with a literal",
+ stringListScope: exportedStringListVariables{
+ "a": []string{"${b}", "c"},
+ "b": []string{"d"},
+ },
+ toExpand: "${a}",
+ expectedValues: []string{"d", "c"},
+ },
+ {
+ description: "double level expansion, with two variables in a string",
+ stringListScope: exportedStringListVariables{
+ "a": []string{"${b} ${c}"},
+ "b": []string{"d"},
+ "c": []string{"e"},
+ },
+ toExpand: "${a}",
+ expectedValues: []string{"d", "e"},
+ },
+ {
+ description: "triple level expansion with two variables in a string",
+ stringListScope: exportedStringListVariables{
+ "a": []string{"${b} ${c}"},
+ "b": []string{"${c}", "${d}"},
+ "c": []string{"${d}"},
+ "d": []string{"foo"},
+ },
+ toExpand: "${a}",
+ expectedValues: []string{"foo", "foo", "foo"},
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.description, func(t *testing.T) {
+ output := expandVar(testCase.toExpand, testCase.stringScope, testCase.stringListScope)
+ if len(output) != len(testCase.expectedValues) {
+ t.Errorf("Expected %d values, got %d", len(testCase.expectedValues), len(output))
+ }
+ for i, actual := range output {
+ expectedValue := testCase.expectedValues[i]
+ if actual != expectedValue {
+ t.Errorf("Actual value '%s' doesn't match expected value '%s'", actual, expectedValue)
+ }
+ }
+ })
+ }
+}
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 5e46d5a..c484fc9 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -98,7 +98,7 @@
}
func init() {
- pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{
+ exportStringListStaticVariable("ClangExtraCflags", []string{
"-D__compiler_offsetof=__builtin_offsetof",
// Emit address-significance table which allows linker to perform safe ICF. Clang does
@@ -151,9 +151,9 @@
// This macro allows the bionic versioning.h to indirectly determine whether the
// option -Wunguarded-availability is on or not.
"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
- }, " "))
+ })
- pctx.StaticVariable("ClangExtraCppflags", strings.Join([]string{
+ exportStringListStaticVariable("ClangExtraCppflags", []string{
// -Wimplicit-fallthrough is not enabled by -Wall.
"-Wimplicit-fallthrough",
@@ -162,13 +162,11 @@
// libc++'s math.h has an #include_next outside of system_headers.
"-Wno-gnu-include-next",
- }, " "))
+ })
- pctx.StaticVariable("ClangExtraTargetCflags", strings.Join([]string{
- "-nostdlibinc",
- }, " "))
+ exportStringListStaticVariable("ClangExtraTargetCflags", []string{"-nostdlibinc"})
- pctx.StaticVariable("ClangExtraNoOverrideCflags", strings.Join([]string{
+ exportStringListStaticVariable("ClangExtraNoOverrideCflags", []string{
"-Werror=address-of-temporary",
// Bug: http://b/29823425 Disable -Wnull-dereference until the
// new cases detected by this warning in Clang r271374 are
@@ -203,11 +201,11 @@
"-Wno-non-c-typedef-for-linkage", // http://b/161304145
// New warnings to be fixed after clang-r407598
"-Wno-string-concatenation", // http://b/175068488
- }, " "))
+ })
// Extra cflags for external third-party projects to disable warnings that
// are infeasible to fix in all the external projects and their upstream repos.
- pctx.StaticVariable("ClangExtraExternalCflags", strings.Join([]string{
+ exportStringListStaticVariable("ClangExtraExternalCflags", []string{
"-Wno-enum-compare",
"-Wno-enum-compare-switch",
@@ -228,7 +226,7 @@
// http://b/165945989
"-Wno-psabi",
- }, " "))
+ })
}
func ClangFilterUnknownCflags(cflags []string) []string {
diff --git a/cc/config/global.go b/cc/config/global.go
index 23106ec..d458311 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -165,13 +165,25 @@
commonGlobalCflags = append(commonGlobalCflags, "-fdebug-prefix-map=/proc/self/cwd=")
}
- pctx.StaticVariable("CommonGlobalConlyflags", strings.Join(commonGlobalConlyflags, " "))
- pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " "))
- pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " "))
- pctx.StaticVariable("DeviceGlobalLldflags", strings.Join(deviceGlobalLldflags, " "))
- pctx.StaticVariable("HostGlobalCppflags", strings.Join(hostGlobalCppflags, " "))
- pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
- pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
+ exportStringListStaticVariable("CommonGlobalConlyflags", commonGlobalConlyflags)
+ exportStringListStaticVariable("DeviceGlobalCppflags", deviceGlobalCppflags)
+ exportStringListStaticVariable("DeviceGlobalLdflags", deviceGlobalLdflags)
+ exportStringListStaticVariable("DeviceGlobalLldflags", deviceGlobalLldflags)
+ exportStringListStaticVariable("HostGlobalCppflags", hostGlobalCppflags)
+ exportStringListStaticVariable("HostGlobalLdflags", hostGlobalLdflags)
+ exportStringListStaticVariable("HostGlobalLldflags", hostGlobalLldflags)
+
+ // Export the static default CommonClangGlobalCflags to Bazel.
+ // TODO(187086342): handle cflags that are set in VariableFuncs.
+ commonClangGlobalCFlags := append(
+ ClangFilterUnknownCflags(commonGlobalCflags),
+ []string{
+ "${ClangExtraCflags}",
+ // Default to zero initialization.
+ "-ftrivial-auto-var-init=zero",
+ "-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang",
+ }...)
+ exportedStringListVars.Set("CommonClangGlobalCflags", commonClangGlobalCFlags)
pctx.VariableFunc("CommonClangGlobalCflags", func(ctx android.PackageVarContext) string {
flags := ClangFilterUnknownCflags(commonGlobalCflags)
@@ -190,41 +202,42 @@
// Default to zero initialization.
flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
}
-
return strings.Join(flags, " ")
})
+ // Export the static default DeviceClangGlobalCflags to Bazel.
+ // TODO(187086342): handle cflags that are set in VariableFuncs.
+ deviceClangGlobalCflags := append(ClangFilterUnknownCflags(deviceGlobalCflags), "${ClangExtraTargetCflags}")
+ exportedStringListVars.Set("DeviceClangGlobalCflags", deviceClangGlobalCflags)
+
pctx.VariableFunc("DeviceClangGlobalCflags", func(ctx android.PackageVarContext) string {
if ctx.Config().Fuchsia() {
return strings.Join(ClangFilterUnknownCflags(deviceGlobalCflags), " ")
} else {
- return strings.Join(append(ClangFilterUnknownCflags(deviceGlobalCflags), "${ClangExtraTargetCflags}"), " ")
+ return strings.Join(deviceClangGlobalCflags, " ")
}
})
- pctx.StaticVariable("HostClangGlobalCflags",
- strings.Join(ClangFilterUnknownCflags(hostGlobalCflags), " "))
- pctx.StaticVariable("NoOverrideClangGlobalCflags",
- strings.Join(append(ClangFilterUnknownCflags(noOverrideGlobalCflags), "${ClangExtraNoOverrideCflags}"), " "))
- pctx.StaticVariable("CommonClangGlobalCppflags",
- strings.Join(append(ClangFilterUnknownCflags(commonGlobalCppflags), "${ClangExtraCppflags}"), " "))
-
- pctx.StaticVariable("ClangExternalCflags", "${ClangExtraExternalCflags}")
+ exportStringListStaticVariable("HostClangGlobalCflags", ClangFilterUnknownCflags(hostGlobalCflags))
+ exportStringListStaticVariable("NoOverrideClangGlobalCflags", append(ClangFilterUnknownCflags(noOverrideGlobalCflags), "${ClangExtraNoOverrideCflags}"))
+ exportStringListStaticVariable("CommonClangGlobalCppflags", append(ClangFilterUnknownCflags(commonGlobalCppflags), "${ClangExtraCppflags}"))
+ exportStringListStaticVariable("ClangExternalCflags", []string{"${ClangExtraExternalCflags}"})
// Everything in these lists is a crime against abstraction and dependency tracking.
// Do not add anything to this list.
- pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I",
- []string{
- "system/core/include",
- "system/logging/liblog/include",
- "system/media/audio/include",
- "hardware/libhardware/include",
- "hardware/libhardware_legacy/include",
- "hardware/ril/include",
- "frameworks/native/include",
- "frameworks/native/opengl/include",
- "frameworks/av/include",
- })
+ commonGlobalIncludes := []string{
+ "system/core/include",
+ "system/logging/liblog/include",
+ "system/media/audio/include",
+ "hardware/libhardware/include",
+ "hardware/libhardware_legacy/include",
+ "hardware/ril/include",
+ "frameworks/native/include",
+ "frameworks/native/opengl/include",
+ "frameworks/av/include",
+ }
+ exportedStringListVars.Set("CommonGlobalIncludes", commonGlobalIncludes)
+ pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
pctx.VariableFunc("ClangBase", func(ctx android.PackageVarContext) string {
diff --git a/cc/coverage.go b/cc/coverage.go
index 5b5ccf2..baf4226 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -96,7 +96,8 @@
// flags that the module may use.
flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
} else if clangCoverage {
- flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, "-fcoverage-mapping", "-Wno-pass-failed")
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag,
+ "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__")
}
}
@@ -203,7 +204,7 @@
type Coverage interface {
android.Module
IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool
- PreventInstall()
+ SetPreventInstall()
HideFromMake()
MarkAsCoverageVariant(bool)
EnableCoverageIfNeeded()
@@ -236,7 +237,7 @@
// to an APEX via 'data' property.
m := mctx.CreateVariations("", "cov")
m[0].(Coverage).MarkAsCoverageVariant(false)
- m[0].(Coverage).PreventInstall()
+ m[0].(Coverage).SetPreventInstall()
m[0].(Coverage).HideFromMake()
m[1].(Coverage).MarkAsCoverageVariant(true)
diff --git a/cc/gen.go b/cc/gen.go
index b152e02..3a1a0e2 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -204,7 +204,7 @@
headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h")
rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc")
- windmcCmd := gccCmd(flags.toolchain, "windmc")
+ windmcCmd := mingwCmd(flags.toolchain, "windmc")
ctx.Build(pctx, android.BuildParams{
Rule: windmc,
diff --git a/cc/image.go b/cc/image.go
index 5d41717..c6b209f 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -430,6 +430,16 @@
recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
recoverySnapshotVersion != ""
+ needVndkVersionVendorVariantForLlndk := false
+ if boardVndkVersion != "" {
+ boardVndkApiLevel, err := android.ApiLevelFromUser(mctx, boardVndkVersion)
+ if err == nil && !boardVndkApiLevel.IsPreview() {
+ // VNDK snapshot newer than v30 has LLNDK stub libraries.
+ // Only the VNDK version less than or equal to v30 requires generating the vendor
+ // variant of the VNDK version from the source tree.
+ needVndkVersionVendorVariantForLlndk = boardVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, "30"))
+ }
+ }
if boardVndkVersion == "current" {
boardVndkVersion = platformVndkVersion
}
@@ -446,7 +456,9 @@
vendorVariants = append(vendorVariants, platformVndkVersion)
productVariants = append(productVariants, platformVndkVersion)
}
- if boardVndkVersion != "" {
+ // Generate vendor variants for boardVndkVersion only if the VNDK snapshot does not
+ // provide the LLNDK stub libraries.
+ if needVndkVersionVendorVariantForLlndk {
vendorVariants = append(vendorVariants, boardVndkVersion)
}
if productVndkVersion != "" {
@@ -567,7 +579,7 @@
// If using a snapshot, the recovery variant under AOSP directories is not needed,
// except for kernel headers, which needs all variants.
- if m.KernelHeadersDecorator() &&
+ if !m.KernelHeadersDecorator() &&
!m.IsSnapshotPrebuilt() &&
usingRecoverySnapshot &&
!isRecoveryProprietaryModule(mctx) {
diff --git a/cc/library.go b/cc/library.go
index 7e960a7..5e70c51 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -220,16 +220,40 @@
// For bp2build conversion.
type bazelCcLibraryAttributes struct {
- Srcs bazel.LabelListAttribute
- Hdrs bazel.LabelListAttribute
- Copts bazel.StringListAttribute
- Linkopts bazel.StringListAttribute
- Deps bazel.LabelListAttribute
- Dynamic_deps bazel.LabelListAttribute
- User_link_flags bazel.StringListAttribute
- Includes bazel.StringListAttribute
- Static_deps_for_shared bazel.LabelListAttribute
- Version_script bazel.LabelAttribute
+ // Attributes pertaining to both static and shared variants.
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+ Linkopts bazel.StringListAttribute
+
+ Cppflags bazel.StringListAttribute
+ Srcs_c bazel.LabelListAttribute
+ Conlyflags bazel.StringListAttribute
+ Srcs_as bazel.LabelListAttribute
+ Asflags bazel.StringListAttribute
+
+ // Attributes pertaining to shared variant.
+ Shared_copts bazel.StringListAttribute
+ Shared_srcs bazel.LabelListAttribute
+ Exported_deps_for_shared bazel.LabelListAttribute
+ Static_deps_for_shared bazel.LabelListAttribute
+ Dynamic_deps_for_shared bazel.LabelListAttribute
+ Whole_archive_deps_for_shared bazel.LabelListAttribute
+ User_link_flags bazel.StringListAttribute
+ Version_script bazel.LabelAttribute
+
+ // Attributes pertaining to static variant.
+ Static_copts bazel.StringListAttribute
+ Static_srcs bazel.LabelListAttribute
+ Exported_deps_for_static bazel.LabelListAttribute
+ Static_deps_for_static bazel.LabelListAttribute
+ Dynamic_deps_for_static bazel.LabelListAttribute
+ Whole_archive_deps_for_static bazel.LabelListAttribute
}
type bazelCcLibrary struct {
@@ -276,17 +300,34 @@
var srcs bazel.LabelListAttribute
srcs.Append(compilerAttrs.srcs)
- srcs.Append(staticAttrs.srcs)
attrs := &bazelCcLibraryAttributes{
- Srcs: srcs,
- Copts: compilerAttrs.copts,
- Linkopts: linkerAttrs.linkopts,
- Deps: linkerAttrs.deps,
- Dynamic_deps: linkerAttrs.dynamicDeps,
- Version_script: linkerAttrs.versionScript,
- Static_deps_for_shared: sharedAttrs.staticDeps,
- Includes: exportedIncludes,
+ Srcs: srcs,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
+ Dynamic_deps: linkerAttrs.dynamicDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Copts: compilerAttrs.copts,
+ Includes: exportedIncludes,
+ Linkopts: linkerAttrs.linkopts,
+ Cppflags: compilerAttrs.cppFlags,
+ Srcs_c: compilerAttrs.cSrcs,
+ Conlyflags: compilerAttrs.conlyFlags,
+ Srcs_as: compilerAttrs.asSrcs,
+ Asflags: compilerAttrs.asFlags,
+
+ Shared_copts: sharedAttrs.copts,
+ Shared_srcs: sharedAttrs.srcs,
+ Static_deps_for_shared: sharedAttrs.staticDeps,
+ Whole_archive_deps_for_shared: sharedAttrs.wholeArchiveDeps,
+ Dynamic_deps_for_shared: sharedAttrs.dynamicDeps,
+ Version_script: linkerAttrs.versionScript,
+
+ Static_copts: staticAttrs.copts,
+ Static_srcs: staticAttrs.srcs,
+ Static_deps_for_static: staticAttrs.staticDeps,
+ Whole_archive_deps_for_static: staticAttrs.wholeArchiveDeps,
+ Dynamic_deps_for_static: staticAttrs.dynamicDeps,
}
props := bazel.BazelTargetModuleProperties{
@@ -1404,11 +1445,10 @@
}
}
-func processLLNDKHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) android.Path {
+func processLLNDKHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) (timestamp android.Path, installPaths android.WritablePaths) {
srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
- var installPaths []android.WritablePath
for _, header := range srcFiles {
headerDir := filepath.Dir(header.String())
relHeaderDir, err := filepath.Rel(srcDir.String(), headerDir)
@@ -1421,7 +1461,7 @@
installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
}
- return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths)
+ return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths), installPaths
}
// link registers actions to link this library, and sets various fields
@@ -1437,7 +1477,9 @@
var timestampFiles android.Paths
for _, dir := range library.Properties.Llndk.Export_preprocessed_headers {
- timestampFiles = append(timestampFiles, processLLNDKHeaders(ctx, dir, genHeaderOutDir))
+ timestampFile, installPaths := processLLNDKHeaders(ctx, dir, genHeaderOutDir)
+ timestampFiles = append(timestampFiles, timestampFile)
+ library.addExportedGeneratedHeaders(installPaths.Paths()...)
}
if Bool(library.Properties.Llndk.Export_headers_as_system) {
@@ -1771,6 +1813,11 @@
return nil
}
+ if library.hasLLNDKStubs() && ctx.Module().(*Module).UseVndk() {
+ // LLNDK libraries only need a single stubs variant.
+ return []string{android.FutureApiLevel.String()}
+ }
+
// Future API level is implicitly added if there isn't
vers := library.Properties.Stubs.Versions
if inList(android.FutureApiLevel.String(), vers) {
@@ -2112,8 +2159,7 @@
return nil
}
-// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions,
-// and propagates the value from implementation libraries to llndk libraries with the same name.
+// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions.
func versionSelectorMutator(mctx android.BottomUpMutatorContext) {
if library := moduleLibraryInterface(mctx.Module()); library != nil && CanBeVersionVariant(mctx.Module().(*Module)) {
if library.buildShared() {
@@ -2127,15 +2173,6 @@
// depend on the implementation library and haven't been mutated yet.
library.setAllStubsVersions(versions)
}
-
- if mctx.Module().(*Module).UseVndk() && library.hasLLNDKStubs() {
- // Propagate the version to the llndk stubs module.
- mctx.VisitDirectDepsWithTag(llndkStubDepTag, func(stubs android.Module) {
- if stubsLib := moduleLibraryInterface(stubs); stubsLib != nil {
- stubsLib.setAllStubsVersions(library.allStubsVersions())
- }
- })
- }
}
}
}
@@ -2194,13 +2231,21 @@
}
type bazelCcLibraryStaticAttributes struct {
- Copts bazel.StringListAttribute
- Srcs bazel.LabelListAttribute
- Deps bazel.LabelListAttribute
- Linkopts bazel.StringListAttribute
- Linkstatic bool
- Includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Srcs bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Linkopts bazel.StringListAttribute
+ Linkstatic bool
+ Includes bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
+
+ Cppflags bazel.StringListAttribute
+ Srcs_c bazel.LabelListAttribute
+ Conlyflags bazel.StringListAttribute
+ Srcs_as bazel.LabelListAttribute
+ Asflags bazel.StringListAttribute
}
type bazelCcLibraryStatic struct {
@@ -2221,12 +2266,21 @@
exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
attrs := &bazelCcLibraryStaticAttributes{
- Copts: compilerAttrs.copts,
- Srcs: compilerAttrs.srcs,
- Deps: linkerAttrs.deps,
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+
Linkopts: linkerAttrs.linkopts,
Linkstatic: true,
Includes: exportedIncludes,
+
+ Cppflags: compilerAttrs.cppFlags,
+ Srcs_c: compilerAttrs.cSrcs,
+ Conlyflags: compilerAttrs.conlyFlags,
+ Srcs_as: compilerAttrs.asSrcs,
+ Asflags: compilerAttrs.asFlags,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 0aba8de..2065929 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -109,10 +109,11 @@
}
type bazelCcLibraryHeadersAttributes struct {
- Copts bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
- Includes bazel.StringListAttribute
- Deps bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
+ Includes bazel.StringListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
}
type bazelCcLibraryHeaders struct {
@@ -147,9 +148,10 @@
linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
attrs := &bazelCcLibraryHeadersAttributes{
- Copts: compilerAttrs.copts,
- Includes: exportedIncludes,
- Deps: linkerAttrs.deps,
+ Copts: compilerAttrs.copts,
+ Includes: exportedIncludes,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/linkable.go b/cc/linkable.go
index 40a9d8b..b583b69 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -48,6 +48,20 @@
// SanitizerSupported returns true if a sanitizer type is supported by this modules compiler.
SanitizerSupported(t SanitizerType) bool
+ // MinimalRuntimeDep returns true if this module needs to link the minimal UBSan runtime,
+ // either because it requires it or because a dependent module which requires it to be linked in this module.
+ MinimalRuntimeDep() bool
+
+ // UbsanRuntimeDep returns true if this module needs to link the full UBSan runtime,
+ // either because it requires it or because a dependent module which requires it to be linked in this module.
+ UbsanRuntimeDep() bool
+
+ // UbsanRuntimeNeeded returns true if the full UBSan runtime is required by this module.
+ UbsanRuntimeNeeded() bool
+
+ // MinimalRuntimeNeeded returns true if the minimal UBSan runtime is required by this module
+ MinimalRuntimeNeeded() bool
+
// SanitizableDepTagChecker returns a SantizableDependencyTagChecker function type.
SanitizableDepTagChecker() SantizableDependencyTagChecker
}
@@ -60,14 +74,42 @@
// implementation should handle tags from both.
type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool
+// Snapshottable defines those functions necessary for handling module snapshots.
+type Snapshottable interface {
+ // SnapshotHeaders returns a list of header paths provided by this module.
+ SnapshotHeaders() android.Paths
+
+ // ExcludeFromVendorSnapshot returns true if this module should be otherwise excluded from the vendor snapshot.
+ ExcludeFromVendorSnapshot() bool
+
+ // ExcludeFromRecoverySnapshot returns true if this module should be otherwise excluded from the recovery snapshot.
+ ExcludeFromRecoverySnapshot() bool
+
+ // SnapshotLibrary returns true if this module is a snapshot library.
+ IsSnapshotLibrary() bool
+
+ // SnapshotRuntimeLibs returns a list of libraries needed by this module at runtime but which aren't build dependencies.
+ SnapshotRuntimeLibs() []string
+
+ // SnapshotSharedLibs returns the list of shared library dependencies for this module.
+ SnapshotSharedLibs() []string
+
+ // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt.
+ IsSnapshotPrebuilt() bool
+}
+
// LinkableInterface is an interface for a type of module that is linkable in a C++ library.
type LinkableInterface interface {
android.Module
+ Snapshottable
Module() android.Module
CcLibrary() bool
CcLibraryInterface() bool
+ // BaseModuleName returns the android.ModuleBase.BaseModuleName() value for this module.
+ BaseModuleName() string
+
OutputFile() android.OptionalPath
CoverageFiles() android.Paths
@@ -79,9 +121,6 @@
BuildSharedVariant() bool
SetStatic()
SetShared()
- Static() bool
- Shared() bool
- Header() bool
IsPrebuilt() bool
Toc() android.OptionalPath
@@ -106,13 +145,29 @@
// IsLlndkPublic returns true only for LLNDK (public) libs.
IsLlndkPublic() bool
+ // HasLlndkStubs returns true if this library has a variant that will build LLNDK stubs.
+ HasLlndkStubs() bool
+
// NeedsLlndkVariants returns true if this module has LLNDK stubs or provides LLNDK headers.
NeedsLlndkVariants() bool
// NeedsVendorPublicLibraryVariants returns true if this module has vendor public library stubs.
NeedsVendorPublicLibraryVariants() bool
+ //StubsVersion returns the stubs version for this module.
+ StubsVersion() string
+
+ // UseVndk returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
+ // "product" and "vendor" variant modules return true for this function.
+ // When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
+ // "soc_specific: true" and more vendor installed modules are included here.
+ // When PRODUCT_PRODUCT_VNDK_VERSION is set, product variants of "vendor_available: true" or
+ // "product_specific: true" modules are included here.
UseVndk() bool
+
+ // IsVndkSp returns true if this is a VNDK-SP module.
+ IsVndkSp() bool
+
MustUseVendorVariant() bool
IsVndk() bool
IsVndkExt() bool
@@ -140,6 +195,51 @@
// KernelHeadersDecorator returns true if this is a kernel headers decorator module.
// This is specific to cc and should always return false for all other packages.
KernelHeadersDecorator() bool
+
+ // HiddenFromMake returns true if this module is hidden from Make.
+ HiddenFromMake() bool
+
+ // RelativeInstallPath returns the relative install path for this module.
+ RelativeInstallPath() string
+
+ // Binary returns true if this is a binary module.
+ Binary() bool
+
+ // Object returns true if this is an object module.
+ Object() bool
+
+ // Rlib returns true if this is an rlib module.
+ Rlib() bool
+
+ // Dylib returns true if this is an dylib module.
+ Dylib() bool
+
+ // Static returns true if this is a static library module.
+ Static() bool
+
+ // Shared returns true if this is a shared library module.
+ Shared() bool
+
+ // Header returns true if this is a library headers module.
+ Header() bool
+
+ // EverInstallable returns true if the module is ever installable
+ EverInstallable() bool
+
+ // PreventInstall returns true if this module is prevented from installation.
+ PreventInstall() bool
+
+ // InstallInData returns true if this module is installed in data.
+ InstallInData() bool
+
+ // Installable returns a bool pointer to the module installable property.
+ Installable() *bool
+
+ // Symlinks returns a list of symlinks that should be created for this module.
+ Symlinks() []string
+
+ // VndkVersion returns the VNDK version string for this module.
+ VndkVersion() string
}
var (
diff --git a/cc/linker.go b/cc/linker.go
index 73fc4f0..5bd21ed 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -18,7 +18,6 @@
"android/soong/android"
"android/soong/cc/config"
"fmt"
- "strconv"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -390,17 +389,17 @@
}
// Check whether the SDK version is not older than the specific one
-func CheckSdkVersionAtLeast(ctx ModuleContext, SdkVersion int) bool {
- if ctx.sdkVersion() == "current" {
+func CheckSdkVersionAtLeast(ctx ModuleContext, SdkVersion android.ApiLevel) bool {
+ if ctx.minSdkVersion() == "current" {
return true
}
- parsedSdkVersion, err := strconv.Atoi(ctx.sdkVersion())
+ parsedSdkVersion, err := nativeApiLevelFromUser(ctx, ctx.minSdkVersion())
if err != nil {
- ctx.PropertyErrorf("sdk_version",
- "Invalid sdk_version value (must be int or current): %q",
- ctx.sdkVersion())
+ ctx.PropertyErrorf("min_sdk_version",
+ "Invalid min_sdk_version value (must be int or current): %q",
+ ctx.minSdkVersion())
}
- if parsedSdkVersion < SdkVersion {
+ if parsedSdkVersion.LessThan(SdkVersion) {
return false
}
return true
@@ -421,13 +420,17 @@
if !BoolDefault(linker.Properties.Pack_relocations, true) {
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none")
} else if ctx.Device() {
- // The SHT_RELR relocations is only supported by API level >= 28.
- // Do not turn this on if older version NDK is used.
- if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, 28) {
+ // SHT_RELR relocations are only supported at API level >= 30.
+ // ANDROID_RELR relocations were supported at API level >= 28.
+ // Relocation packer was supported at API level >= 23.
+ // Do the best we can...
+ if (!ctx.useSdk() && ctx.minSdkVersion() == "") || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr")
+ } else if CheckSdkVersionAtLeast(ctx, android.FirstAndroidRelrVersion) {
flags.Global.LdFlags = append(flags.Global.LdFlags,
"-Wl,--pack-dyn-relocs=android+relr",
"-Wl,--use-android-relr-tags")
- } else if CheckSdkVersionAtLeast(ctx, 23) {
+ } else if CheckSdkVersionAtLeast(ctx, android.FirstPackedRelocationsVersion) {
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android")
}
}
diff --git a/cc/makevars.go b/cc/makevars.go
index da5f1fd..2b326ef 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -288,9 +288,7 @@
ctx.Strict(makePrefix+"OBJCOPY", "${config.ClangBin}/llvm-objcopy")
ctx.Strict(makePrefix+"LD", "${config.ClangBin}/lld")
ctx.Strict(makePrefix+"NDK_TRIPLE", config.NDKTriple(toolchain))
- // TODO: work out whether to make this "${config.ClangBin}/llvm-", which
- // should mostly work, or remove it.
- ctx.Strict(makePrefix+"TOOLS_PREFIX", gccCmd(toolchain, ""))
+ ctx.Strict(makePrefix+"TOOLS_PREFIX", "${config.ClangBin}/llvm-")
// TODO: GCC version is obsolete now that GCC has been removed.
ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion())
}
diff --git a/cc/object.go b/cc/object.go
index d8f1aba..39fc43d 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -116,7 +116,7 @@
Hdrs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Copts bazel.StringListAttribute
- Asflags []string
+ Asflags bazel.StringListAttribute
}
type bazelObject struct {
@@ -157,8 +157,6 @@
// Set arch-specific configurable attributes
compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
- var asFlags []string
-
var deps bazel.LabelListAttribute
for _, props := range m.linker.linkerProps() {
if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok {
@@ -167,28 +165,17 @@
}
}
- 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
+ // Don't split cc_object srcs across languages. Doing so would add complexity,
+ // and this isn't typically done for cc_object.
+ srcs := compilerAttrs.srcs
+ srcs.Append(compilerAttrs.cSrcs)
+ srcs.Append(compilerAttrs.asSrcs)
attrs := &bazelObjectAttributes{
- Srcs: compilerAttrs.srcs,
+ Srcs: srcs,
Deps: deps,
Copts: compilerAttrs.copts,
- Asflags: asFlags,
+ Asflags: compilerAttrs.asFlags,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/sabi.go b/cc/sabi.go
index c0eb57c..384dcc1 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -84,7 +84,7 @@
return "LLNDK"
}
if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate() {
- if m.isVndkSp() {
+ if m.IsVndkSp() {
if m.IsVndkExt() {
return "VNDK-SP-ext"
} else {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 397121e..f486ee4 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -902,7 +902,7 @@
if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
!d.SanitizeNever() &&
!d.IsSanitizerExplicitlyDisabled(t) {
- if t == cfi || t == Hwasan || t == scs {
+ if t == cfi || t == Hwasan || t == scs || t == Asan {
if d.StaticallyLinked() && d.SanitizerSupported(t) {
// Rust does not support some of these sanitizers, so we need to check if it's
// supported before setting this true.
@@ -1075,7 +1075,7 @@
sanitizers = append(sanitizers, "shadow-call-stack")
}
- if Bool(c.sanitize.Properties.Sanitize.Memtag_heap) && c.binary() {
+ if Bool(c.sanitize.Properties.Sanitize.Memtag_heap) && c.Binary() {
noteDep := "note_memtag_heap_async"
if Bool(c.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
noteDep = "note_memtag_heap_sync"
@@ -1208,6 +1208,14 @@
AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
}
+func (c *Module) MinimalRuntimeDep() bool {
+ return c.sanitize.Properties.MinimalRuntimeDep
+}
+
+func (c *Module) UbsanRuntimeDep() bool {
+ return c.sanitize.Properties.UbsanRuntimeDep
+}
+
func (c *Module) SanitizePropDefined() bool {
return c.sanitize != nil
}
@@ -1253,7 +1261,7 @@
modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
} else if c.IsSanitizerEnabled(t) || c.SanitizeDep() {
isSanitizerEnabled := c.IsSanitizerEnabled(t)
- if c.StaticallyLinked() || c.Header() || t == Asan || t == Fuzzer {
+ if c.StaticallyLinked() || c.Header() || t == Fuzzer {
// Static and header libs are split into non-sanitized and sanitized variants.
// Shared libs are not split. However, for asan and fuzzer, we split even for shared
// libs because a library sanitized for asan/fuzzer can't be linked from a library
@@ -1441,6 +1449,14 @@
return false
}
+func (m *Module) UbsanRuntimeNeeded() bool {
+ return enableUbsanRuntime(m.sanitize)
+}
+
+func (m *Module) MinimalRuntimeNeeded() bool {
+ return enableMinimalRuntime(m.sanitize)
+}
+
func enableUbsanRuntime(sanitize *sanitize) bool {
return Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
new file mode 100644
index 0000000..f126346
--- /dev/null
+++ b/cc/sanitize_test.go
@@ -0,0 +1,204 @@
+// 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 cc
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
+ cc_library_shared {
+ name: "libclang_rt.asan-aarch64-android",
+ }
+
+ cc_library_shared {
+ name: "libclang_rt.asan-arm-android",
+ }
+`))
+
+func TestAsan(t *testing.T) {
+ bp := `
+ cc_binary {
+ name: "bin_with_asan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ "libasan",
+ ],
+ static_libs: [
+ "libstatic",
+ "libnoasan",
+ ],
+ sanitize: {
+ address: true,
+ }
+ }
+
+ cc_binary {
+ name: "bin_no_asan",
+ host_supported: true,
+ shared_libs: [
+ "libshared",
+ "libasan",
+ ],
+ static_libs: [
+ "libstatic",
+ "libnoasan",
+ ],
+ }
+
+ cc_library_shared {
+ name: "libshared",
+ host_supported: true,
+ shared_libs: ["libtransitive"],
+ }
+
+ cc_library_shared {
+ name: "libasan",
+ host_supported: true,
+ shared_libs: ["libtransitive"],
+ sanitize: {
+ address: true,
+ }
+ }
+
+ cc_library_shared {
+ name: "libtransitive",
+ host_supported: true,
+ }
+
+ cc_library_static {
+ name: "libstatic",
+ host_supported: true,
+ }
+
+ cc_library_static {
+ name: "libnoasan",
+ host_supported: true,
+ sanitize: {
+ address: false,
+ }
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ prepareForAsanTest,
+ ).RunTestWithBp(t, bp)
+
+ check := func(t *testing.T, result *android.TestResult, variant string) {
+ asanVariant := variant + "_asan"
+ sharedVariant := variant + "_shared"
+ sharedAsanVariant := sharedVariant + "_asan"
+ staticVariant := variant + "_static"
+ staticAsanVariant := staticVariant + "_asan"
+
+ // The binaries, one with asan and one without
+ binWithAsan := result.ModuleForTests("bin_with_asan", asanVariant)
+ binNoAsan := result.ModuleForTests("bin_no_asan", variant)
+
+ // Shared libraries that don't request asan
+ libShared := result.ModuleForTests("libshared", sharedVariant)
+ libTransitive := result.ModuleForTests("libtransitive", sharedVariant)
+
+ // Shared library that requests asan
+ libAsan := result.ModuleForTests("libasan", sharedAsanVariant)
+
+ // Static library that uses an asan variant for bin_with_asan and a non-asan variant
+ // for bin_no_asan.
+ libStaticAsanVariant := result.ModuleForTests("libstatic", staticAsanVariant)
+ libStaticNoAsanVariant := result.ModuleForTests("libstatic", staticVariant)
+
+ // Static library that never uses asan.
+ libNoAsan := result.ModuleForTests("libnoasan", staticVariant)
+
+ // expectSharedLinkDep verifies that the from module links against the to module as a
+ // shared library.
+ expectSharedLinkDep := func(from, to android.TestingModule) {
+ t.Helper()
+ fromLink := from.Description("link")
+ toLink := to.Description("strip")
+
+ if g, w := fromLink.OrderOnly.Strings(), toLink.Output.String(); !android.InList(w, g) {
+ t.Errorf("%s should link against %s, expected %q, got %q",
+ from.Module(), to.Module(), w, g)
+ }
+ }
+
+ // expectStaticLinkDep verifies that the from module links against the to module as a
+ // static library.
+ expectStaticLinkDep := func(from, to android.TestingModule) {
+ t.Helper()
+ fromLink := from.Description("link")
+ toLink := to.Description("static link")
+
+ if g, w := fromLink.Implicits.Strings(), toLink.Output.String(); !android.InList(w, g) {
+ t.Errorf("%s should link against %s, expected %q, got %q",
+ from.Module(), to.Module(), w, g)
+ }
+
+ }
+
+ // expectInstallDep verifies that the install rule of the from module depends on the
+ // install rule of the to module.
+ expectInstallDep := func(from, to android.TestingModule) {
+ t.Helper()
+ fromInstalled := from.Description("install")
+ toInstalled := to.Description("install")
+
+ // combine implicits and order-only dependencies, host uses implicit but device uses
+ // order-only.
+ got := append(fromInstalled.Implicits.Strings(), fromInstalled.OrderOnly.Strings()...)
+ want := toInstalled.Output.String()
+ if !android.InList(want, got) {
+ t.Errorf("%s installation should depend on %s, expected %q, got %q",
+ from.Module(), to.Module(), want, got)
+ }
+ }
+
+ expectSharedLinkDep(binWithAsan, libShared)
+ expectSharedLinkDep(binWithAsan, libAsan)
+ expectSharedLinkDep(libShared, libTransitive)
+ expectSharedLinkDep(libAsan, libTransitive)
+
+ expectStaticLinkDep(binWithAsan, libStaticAsanVariant)
+ expectStaticLinkDep(binWithAsan, libNoAsan)
+
+ expectInstallDep(binWithAsan, libShared)
+ expectInstallDep(binWithAsan, libAsan)
+ expectInstallDep(binWithAsan, libTransitive)
+ expectInstallDep(libShared, libTransitive)
+ expectInstallDep(libAsan, libTransitive)
+
+ expectSharedLinkDep(binNoAsan, libShared)
+ expectSharedLinkDep(binNoAsan, libAsan)
+ expectSharedLinkDep(libShared, libTransitive)
+ expectSharedLinkDep(libAsan, libTransitive)
+
+ expectStaticLinkDep(binNoAsan, libStaticNoAsanVariant)
+ expectStaticLinkDep(binNoAsan, libNoAsan)
+
+ expectInstallDep(binNoAsan, libShared)
+ expectInstallDep(binNoAsan, libAsan)
+ expectInstallDep(binNoAsan, libTransitive)
+ expectInstallDep(libShared, libTransitive)
+ expectInstallDep(libAsan, libTransitive)
+ }
+
+ t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
+ t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
+}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 885a0ce..a7351a9 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -35,12 +35,12 @@
// Function that returns true if the module is included in this image.
// Using a function return instead of a value to prevent early
// evalution of a function that may be not be defined.
- inImage(m *Module) func() bool
+ inImage(m LinkableInterface) func() bool
// Returns true if the module is private and must not be included in the
// snapshot. For example VNDK-private modules must return true for the
// vendor snapshots. But false for the recovery snapshots.
- private(m *Module) bool
+ private(m LinkableInterface) bool
// Returns true if a dir under source tree is an SoC-owned proprietary
// directory, such as device/, vendor/, etc.
@@ -56,7 +56,7 @@
// Whether a given module has been explicitly excluded from the
// snapshot, e.g., using the exclude_from_vendor_snapshot or
// exclude_from_recovery_snapshot properties.
- excludeFromSnapshot(m *Module) bool
+ excludeFromSnapshot(m LinkableInterface) bool
// Returns true if the build is using a snapshot for this image.
isUsingSnapshot(cfg android.DeviceConfig) bool
@@ -125,11 +125,11 @@
return ctx.DeviceConfig().VndkVersion() == "current"
}
-func (vendorSnapshotImage) inImage(m *Module) func() bool {
+func (vendorSnapshotImage) inImage(m LinkableInterface) func() bool {
return m.InVendor
}
-func (vendorSnapshotImage) private(m *Module) bool {
+func (vendorSnapshotImage) private(m LinkableInterface) bool {
return m.IsVndkPrivate()
}
@@ -159,7 +159,7 @@
return true
}
-func (vendorSnapshotImage) excludeFromSnapshot(m *Module) bool {
+func (vendorSnapshotImage) excludeFromSnapshot(m LinkableInterface) bool {
return m.ExcludeFromVendorSnapshot()
}
@@ -206,12 +206,12 @@
return ctx.DeviceConfig().RecoverySnapshotVersion() == "current"
}
-func (recoverySnapshotImage) inImage(m *Module) func() bool {
+func (recoverySnapshotImage) inImage(m LinkableInterface) func() bool {
return m.InRecovery
}
// recovery snapshot does not have private libraries.
-func (recoverySnapshotImage) private(m *Module) bool {
+func (recoverySnapshotImage) private(m LinkableInterface) bool {
return false
}
@@ -224,7 +224,7 @@
return false
}
-func (recoverySnapshotImage) excludeFromSnapshot(m *Module) bool {
+func (recoverySnapshotImage) excludeFromSnapshot(m LinkableInterface) bool {
return m.ExcludeFromRecoverySnapshot()
}
@@ -454,13 +454,30 @@
}
func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleContext) {
- if ctx.OtherModuleDependencyVariantExists([]blueprint.Variation{
- {Mutator: "image", Variation: android.CoreVariation},
- }, ctx.Module().(*Module).BaseModuleName()) {
+ coreVariations := append(ctx.Target().Variations(), blueprint.Variation{
+ Mutator: "image",
+ Variation: android.CoreVariation})
+
+ if ctx.OtherModuleFarDependencyVariantExists(coreVariations, ctx.Module().(*Module).BaseModuleName()) {
p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
- } else {
- p.baseProperties.Androidmk_suffix = ""
+ return
}
+
+ // If there is no matching core variation, there could still be a
+ // product variation, for example if a module is product specific and
+ // vendor available. In that case, we also want to add the androidmk
+ // suffix.
+
+ productVariations := append(ctx.Target().Variations(), blueprint.Variation{
+ Mutator: "image",
+ Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()})
+
+ if ctx.OtherModuleFarDependencyVariantExists(productVariations, ctx.Module().(*Module).BaseModuleName()) {
+ p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix()
+ return
+ }
+
+ p.baseProperties.Androidmk_suffix = ""
}
// Call this with a module suffix after creating a snapshot module, such as
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index c32fa36..8eb6164 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -23,6 +23,36 @@
headerExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
)
+func (m *Module) IsSnapshotLibrary() bool {
+ if _, ok := m.linker.(snapshotLibraryInterface); ok {
+ return true
+ }
+ return false
+}
+
+func (m *Module) SnapshotHeaders() android.Paths {
+ if m.IsSnapshotLibrary() {
+ return m.linker.(snapshotLibraryInterface).snapshotHeaders()
+ }
+ return android.Paths{}
+}
+
+func (m *Module) Dylib() bool {
+ return false
+}
+
+func (m *Module) Rlib() bool {
+ return false
+}
+
+func (m *Module) SnapshotRuntimeLibs() []string {
+ return m.Properties.SnapshotRuntimeLibs
+}
+
+func (m *Module) SnapshotSharedLibs() []string {
+ return m.Properties.SnapshotSharedLibs
+}
+
// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots.
type snapshotLibraryInterface interface {
libraryInterface
@@ -68,14 +98,14 @@
return snapshot, found
}
-// shouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot.
+// ShouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot.
// If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions.
-func shouldCollectHeadersForSnapshot(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool {
+func ShouldCollectHeadersForSnapshot(ctx android.ModuleContext, m LinkableInterface, apexInfo android.ApexInfo) bool {
if ctx.DeviceConfig().VndkVersion() != "current" &&
ctx.DeviceConfig().RecoverySnapshotVersion() != "current" {
return false
}
- if _, _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok {
+ if _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok {
return ctx.Config().VndkSnapshotBuildArtifacts()
}
diff --git a/cc/test.go b/cc/test.go
index d4c23d7..047a69e 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -48,12 +48,19 @@
Unit_test *bool
// Add ShippingApiLevelModuleController to auto generated test config. If the device properties
- // for the shipping api level is less than the test_min_api_level, skip this module.
- Test_min_api_level *int64
+ // for the shipping api level is less than the min_shipping_api_level, skip this module.
+ Min_shipping_api_level *int64
+
+ // Add ShippingApiLevelModuleController to auto generated test config. If any of the device
+ // shipping api level and vendor api level properties are less than the
+ // vsr_min_shipping_api_level, skip this module.
+ // As this includes the shipping api level check, it is not allowed to define
+ // min_shipping_api_level at the same time with this property.
+ Vsr_min_shipping_api_level *int64
// Add MinApiLevelModuleController with ro.vndk.version property. If ro.vndk.version has an
- // integer value and the value is less than the test_min_vndk_version, skip this module.
- Test_min_vndk_version *int64
+ // integer value and the value is less than the min_vndk_version, skip this module.
+ Min_vndk_version *int64
}
type TestBinaryProperties struct {
@@ -97,7 +104,7 @@
// Add ShippingApiLevelModuleController to auto generated test config. If the device properties
// for the shipping api level is less than the test_min_api_level, skip this module.
- // Deprecated (b/187258404). Use test_options.test_min_api_level instead.
+ // Deprecated (b/187258404). Use test_options.min_shipping_api_level instead.
Test_min_api_level *int64
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
@@ -404,19 +411,30 @@
for _, tag := range test.Properties.Test_options.Test_suite_tag {
configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
}
- if test.Properties.Test_options.Test_min_api_level != nil {
+ if test.Properties.Test_options.Min_shipping_api_level != nil {
+ if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
+ ctx.PropertyErrorf("test_options.min_shipping_api_level", "must not be set at the same time as 'vsr_min_shipping_api_level'.")
+ }
var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Test_min_api_level), 10)})
+ options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Min_shipping_api_level), 10)})
configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
} else if test.Properties.Test_min_api_level != nil {
// TODO: (b/187258404) Remove test.Properties.Test_min_api_level
+ if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
+ ctx.PropertyErrorf("test_min_api_level", "must not be set at the same time as 'vsr_min_shipping_api_level'.")
+ }
var options []tradefed.Option
options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)})
configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
}
- if test.Properties.Test_options.Test_min_vndk_version != nil {
+ if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Test_min_vndk_version), 10)})
+ options = append(options, tradefed.Option{Name: "vsr-min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Vsr_min_shipping_api_level), 10)})
+ configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
+ }
+ if test.Properties.Test_options.Min_vndk_version != nil {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Min_vndk_version), 10)})
options = append(options, tradefed.Option{Name: "api-level-prop", Value: "ro.vndk.version"})
configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
}
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 9ad51ad..4e59a95 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -115,7 +115,7 @@
// still be a vendor proprietary module. This happens for cc modules
// that are excluded from the vendor snapshot, and it means that the
// vendor has assumed control of the framework-provided module.
- if c, ok := ctx.Module().(*Module); ok {
+ if c, ok := ctx.Module().(LinkableInterface); ok {
if c.ExcludeFromVendorSnapshot() {
return true
}
@@ -137,7 +137,7 @@
// that are excluded from the recovery snapshot, and it means that the
// vendor has assumed control of the framework-provided module.
- if c, ok := ctx.Module().(*Module); ok {
+ if c, ok := ctx.Module().(LinkableInterface); ok {
if c.ExcludeFromRecoverySnapshot() {
return true
}
@@ -147,8 +147,8 @@
}
// Determines if the module is a candidate for snapshot.
-func isSnapshotAware(cfg android.DeviceConfig, m *Module, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshotImage) bool {
- if !m.Enabled() || m.Properties.HideFromMake {
+func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshotImage) bool {
+ if !m.Enabled() || m.HiddenFromMake() {
return false
}
// When android/prebuilt.go selects between source and prebuilt, it sets
@@ -177,51 +177,51 @@
return false
}
// skip kernel_headers which always depend on vendor
- if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ if m.KernelHeadersDecorator() {
return false
}
- // skip LLNDK libraries which are backward compatible
+
if m.IsLlndk() {
return false
}
// Libraries
- if l, ok := m.linker.(snapshotLibraryInterface); ok {
- if m.sanitize != nil {
+ if sanitizable, ok := m.(PlatformSanitizeable); ok && sanitizable.IsSnapshotLibrary() {
+ if sanitizable.SanitizePropDefined() {
// scs and hwasan export both sanitized and unsanitized variants for static and header
// Always use unsanitized variants of them.
for _, t := range []SanitizerType{scs, Hwasan} {
- if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
+ if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(t) {
return false
}
}
// cfi also exports both variants. But for static, we capture both.
// This is because cfi static libraries can't be linked from non-cfi modules,
// and vice versa. This isn't the case for scs and hwasan sanitizers.
- if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) {
+ if !sanitizable.Static() && !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(cfi) {
return false
}
}
- if l.static() {
- return m.outputFile.Valid() && !image.private(m)
+ if sanitizable.Static() {
+ return sanitizable.OutputFile().Valid() && !image.private(m)
}
- if l.shared() {
- if !m.outputFile.Valid() {
+ if sanitizable.Shared() {
+ if !sanitizable.OutputFile().Valid() {
return false
}
if image.includeVndk() {
- if !m.IsVndk() {
+ if !sanitizable.IsVndk() {
return true
}
- return m.IsVndkExt()
+ return sanitizable.IsVndkExt()
}
}
return true
}
// Binaries and Objects
- if m.binary() || m.object() {
- return m.outputFile.Valid()
+ if m.Binary() || m.Object() {
+ return m.OutputFile().Valid()
}
return false
@@ -323,7 +323,7 @@
// installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
// For executables, init_rc and vintf_fragments files are also copied.
- installSnapshot := func(m *Module, fake bool) android.Paths {
+ installSnapshot := func(m LinkableInterface, fake bool) android.Paths {
targetArch := "arch-" + m.Target().Arch.ArchType.String()
if m.Target().Arch.ArchVariant != "" {
targetArch += "-" + m.Target().Arch.ArchVariant
@@ -337,7 +337,7 @@
prop.ModuleName = ctx.ModuleName(m)
if c.supportsVndkExt && m.IsVndkExt() {
// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
- if m.isVndkSp() {
+ if m.IsVndkSp() {
prop.RelativeInstallPath = "vndk-sp"
} else {
prop.RelativeInstallPath = "vndk"
@@ -345,7 +345,7 @@
} else {
prop.RelativeInstallPath = m.RelativeInstallPath()
}
- prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
+ prop.RuntimeLibs = m.SnapshotRuntimeLibs()
prop.Required = m.RequiredModuleNames()
for _, path := range m.InitRc() {
prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
@@ -365,8 +365,8 @@
var propOut string
- if l, ok := m.linker.(snapshotLibraryInterface); ok {
- exporterInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
+ if m.IsSnapshotLibrary() {
+ exporterInfo := ctx.ModuleProvider(m.Module(), FlagExporterInfoProvider).(FlagExporterInfo)
// library flags
prop.ExportedFlags = exporterInfo.Flags
@@ -376,19 +376,22 @@
for _, dir := range exporterInfo.SystemIncludeDirs {
prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
}
+
// shared libs dependencies aren't meaningful on static or header libs
- if l.shared() {
- prop.SharedLibs = m.Properties.SnapshotSharedLibs
+ if m.Shared() {
+ prop.SharedLibs = m.SnapshotSharedLibs()
}
- if l.static() && m.sanitize != nil {
- prop.SanitizeMinimalDep = m.sanitize.Properties.MinimalRuntimeDep || enableMinimalRuntime(m.sanitize)
- prop.SanitizeUbsanDep = m.sanitize.Properties.UbsanRuntimeDep || enableUbsanRuntime(m.sanitize)
+ if sanitizable, ok := m.(PlatformSanitizeable); ok {
+ if sanitizable.Static() && sanitizable.SanitizePropDefined() {
+ prop.SanitizeMinimalDep = sanitizable.MinimalRuntimeDep() || sanitizable.MinimalRuntimeNeeded()
+ prop.SanitizeUbsanDep = sanitizable.UbsanRuntimeDep() || sanitizable.UbsanRuntimeNeeded()
+ }
}
var libType string
- if l.static() {
+ if m.Static() {
libType = "static"
- } else if l.shared() {
+ } else if m.Shared() {
libType = "shared"
} else {
libType = "header"
@@ -398,16 +401,18 @@
// install .a or .so
if libType != "header" {
- libPath := m.outputFile.Path()
+ libPath := m.OutputFile().Path()
stem = libPath.Base()
- if l.static() && m.sanitize != nil && m.sanitize.isSanitizerEnabled(cfi) {
- // both cfi and non-cfi variant for static libraries can exist.
- // attach .cfi to distinguish between cfi and non-cfi.
- // e.g. libbase.a -> libbase.cfi.a
- ext := filepath.Ext(stem)
- stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
- prop.Sanitize = "cfi"
- prop.ModuleName += ".cfi"
+ if sanitizable, ok := m.(PlatformSanitizeable); ok {
+ if sanitizable.Static() && sanitizable.SanitizePropDefined() && sanitizable.IsSanitizerEnabled(cfi) {
+ // both cfi and non-cfi variant for static libraries can exist.
+ // attach .cfi to distinguish between cfi and non-cfi.
+ // e.g. libbase.a -> libbase.cfi.a
+ ext := filepath.Ext(stem)
+ stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
+ prop.Sanitize = "cfi"
+ prop.ModuleName += ".cfi"
+ }
}
snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake))
@@ -416,20 +421,20 @@
}
propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json")
- } else if m.binary() {
+ } else if m.Binary() {
// binary flags
prop.Symlinks = m.Symlinks()
- prop.SharedLibs = m.Properties.SnapshotSharedLibs
+ prop.SharedLibs = m.SnapshotSharedLibs()
// install bin
- binPath := m.outputFile.Path()
+ binPath := m.OutputFile().Path()
snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake))
propOut = snapshotBinOut + ".json"
- } else if m.object() {
+ } else if m.Object() {
// object files aren't installed to the device, so their names can conflict.
// Use module name as stem.
- objPath := m.outputFile.Path()
+ objPath := m.OutputFile().Path()
snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake))
@@ -450,7 +455,7 @@
}
ctx.VisitAllModules(func(module android.Module) {
- m, ok := module.(*Module)
+ m, ok := module.(LinkableInterface)
if !ok {
return
}
@@ -484,8 +489,8 @@
// installSnapshot installs prebuilts and json flag files
snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...)
// just gather headers and notice files here, because they are to be deduplicated
- if l, ok := m.linker.(snapshotLibraryInterface); ok {
- headers = append(headers, l.snapshotHeaders()...)
+ if m.IsSnapshotLibrary() {
+ headers = append(headers, m.SnapshotHeaders()...)
}
if len(m.NoticeFiles()) > 0 {
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index fddd72a..c3b5e8c 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -309,6 +309,13 @@
compile_multilib: "64",
}
+ cc_library {
+ name: "libllndk",
+ llndk: {
+ symbol_file: "libllndk.map.txt",
+ },
+ }
+
cc_binary {
name: "bin",
vendor: true,
@@ -332,7 +339,7 @@
vndkBp := `
vndk_prebuilt_shared {
name: "libvndk",
- version: "30",
+ version: "31",
target_arch: "arm64",
vendor_available: true,
product_available: true,
@@ -376,7 +383,7 @@
// different arch snapshot which has to be ignored
vndk_prebuilt_shared {
name: "libvndk",
- version: "30",
+ version: "31",
target_arch: "arm",
vendor_available: true,
product_available: true,
@@ -390,6 +397,22 @@
},
},
}
+
+ vndk_prebuilt_shared {
+ name: "libllndk",
+ version: "31",
+ target_arch: "arm64",
+ vendor_available: true,
+ product_available: true,
+ arch: {
+ arm64: {
+ srcs: ["libllndk.so"],
+ },
+ arm: {
+ srcs: ["libllndk.so"],
+ },
+ },
+ }
`
vendorProprietaryBp := `
@@ -409,7 +432,7 @@
no_libcrt: true,
stl: "none",
system_shared_libs: [],
- shared_libs: ["libvndk", "libvendor_available"],
+ shared_libs: ["libvndk", "libvendor_available", "libllndk"],
static_libs: ["libvendor", "libvendor_without_snapshot"],
arch: {
arm64: {
@@ -449,16 +472,17 @@
vendor_snapshot {
name: "vendor_snapshot",
- version: "30",
+ version: "31",
arch: {
arm64: {
vndk_libs: [
"libvndk",
+ "libllndk",
],
static_libs: [
"libc++_static",
"libc++demangle",
- "libgcc_stripped",
+ "libunwind",
"libvendor",
"libvendor_available",
"libvndk",
@@ -476,6 +500,7 @@
arm: {
vndk_libs: [
"libvndk",
+ "libllndk",
],
static_libs: [
"libvendor",
@@ -497,7 +522,7 @@
vendor_snapshot_static {
name: "libvndk",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -515,7 +540,7 @@
vendor_snapshot_shared {
name: "libvendor",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -538,7 +563,7 @@
vendor_snapshot_static {
name: "lib32",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
@@ -551,7 +576,7 @@
vendor_snapshot_shared {
name: "lib32",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
@@ -564,7 +589,7 @@
vendor_snapshot_static {
name: "lib64",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -577,7 +602,7 @@
vendor_snapshot_shared {
name: "lib64",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -590,7 +615,7 @@
vendor_snapshot_static {
name: "libvendor",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -616,7 +641,7 @@
vendor_snapshot_shared {
name: "libvendor_available",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -634,7 +659,7 @@
vendor_snapshot_static {
name: "libvendor_available",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "both",
vendor: true,
@@ -652,7 +677,7 @@
vendor_snapshot_static {
name: "libc++_static",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -665,7 +690,7 @@
vendor_snapshot_static {
name: "libc++demangle",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -677,21 +702,21 @@
}
vendor_snapshot_static {
- name: "libgcc_stripped",
- version: "30",
+ name: "libunwind",
+ version: "31",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
arch: {
arm64: {
- src: "libgcc_stripped.a",
+ src: "libunwind.a",
},
},
}
vendor_snapshot_binary {
name: "bin",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "64",
vendor: true,
@@ -704,7 +729,7 @@
vendor_snapshot_binary {
name: "bin32",
- version: "30",
+ version: "31",
target_arch: "arm64",
compile_multilib: "32",
vendor: true,
@@ -732,7 +757,7 @@
// different arch snapshot which has to be ignored
vendor_snapshot_binary {
name: "bin",
- version: "30",
+ version: "31",
target_arch: "arm",
compile_multilib: "first",
vendor: true,
@@ -759,7 +784,7 @@
"vendor/include/libvendor_cfi/c.h": nil,
"vendor/libc++_static.a": nil,
"vendor/libc++demangle.a": nil,
- "vendor/libgcc_striped.a": nil,
+ "vendor/libunwind.a": nil,
"vendor/libvndk.a": nil,
"vendor/libvendor.a": nil,
"vendor/libvendor.cfi.a": nil,
@@ -771,11 +796,12 @@
"vndk/Android.bp": []byte(vndkBp),
"vndk/include/libvndk/a.h": nil,
"vndk/libvndk.so": nil,
+ "vndk/libllndk.so": nil,
}
config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
- config.TestProductVariables.DeviceVndkVersion = StringPtr("30")
- config.TestProductVariables.Platform_vndk_version = StringPtr("31")
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("31")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("32")
ctx := CreateTestContext(config)
ctx.Register()
@@ -784,17 +810,17 @@
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
- sharedVariant := "android_vendor.30_arm64_armv8-a_shared"
- staticVariant := "android_vendor.30_arm64_armv8-a_static"
- binaryVariant := "android_vendor.30_arm64_armv8-a"
+ sharedVariant := "android_vendor.31_arm64_armv8-a_shared"
+ staticVariant := "android_vendor.31_arm64_armv8-a_static"
+ binaryVariant := "android_vendor.31_arm64_armv8-a"
- sharedCfiVariant := "android_vendor.30_arm64_armv8-a_shared_cfi"
- staticCfiVariant := "android_vendor.30_arm64_armv8-a_static_cfi"
+ sharedCfiVariant := "android_vendor.31_arm64_armv8-a_shared_cfi"
+ staticCfiVariant := "android_vendor.31_arm64_armv8-a_static_cfi"
- shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared"
- binary32Variant := "android_vendor.30_arm_armv7-a-neon"
+ shared32Variant := "android_vendor.31_arm_armv7-a-neon_shared"
+ binary32Variant := "android_vendor.31_arm_armv7-a-neon"
- // libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
+ // libclient uses libvndk.vndk.31.arm64, libvendor.vendor_static.31.arm64, libvendor_without_snapshot
libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
for _, includeFlags := range []string{
"-Ivndk/include/libvndk", // libvndk
@@ -808,8 +834,9 @@
libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
for _, input := range [][]string{
- []string{sharedVariant, "libvndk.vndk.30.arm64"},
- []string{staticVariant, "libvendor.vendor_static.30.arm64"},
+ []string{sharedVariant, "libvndk.vndk.31.arm64"},
+ []string{sharedVariant, "libllndk.vndk.31.arm64"},
+ []string{staticVariant, "libvendor.vendor_static.31.arm64"},
[]string{staticVariant, "libvendor_without_snapshot"},
} {
outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
@@ -819,7 +846,7 @@
}
libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
- if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64"}; !reflect.DeepEqual(g, w) {
+ if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib64"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
}
@@ -829,11 +856,11 @@
}
libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
- if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32"}; !reflect.DeepEqual(g, w) {
+ if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib32"}; !reflect.DeepEqual(g, w) {
t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
}
- // libclient_cfi uses libvendor.vendor_static.30.arm64's cfi variant
+ // libclient_cfi uses libvendor.vendor_static.31.arm64's cfi variant
libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"]
if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") {
t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.",
@@ -841,12 +868,12 @@
}
libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"]
- libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.30.arm64"})
+ libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.31.arm64"})
if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) {
t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags)
}
- // bin_without_snapshot uses libvndk.vendor_static.30.arm64 (which reexports vndk's exported headers)
+ // bin_without_snapshot uses libvndk.vendor_static.31.arm64 (which reexports vndk's exported headers)
binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") {
t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
@@ -854,37 +881,37 @@
}
binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
- libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
+ libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.31.arm64"})
if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
}
- // libvendor.so is installed by libvendor.vendor_shared.30.arm64
- ctx.ModuleForTests("libvendor.vendor_shared.30.arm64", sharedVariant).Output("libvendor.so")
+ // libvendor.so is installed by libvendor.vendor_shared.31.arm64
+ ctx.ModuleForTests("libvendor.vendor_shared.31.arm64", sharedVariant).Output("libvendor.so")
- // lib64.so is installed by lib64.vendor_shared.30.arm64
- ctx.ModuleForTests("lib64.vendor_shared.30.arm64", sharedVariant).Output("lib64.so")
+ // lib64.so is installed by lib64.vendor_shared.31.arm64
+ ctx.ModuleForTests("lib64.vendor_shared.31.arm64", sharedVariant).Output("lib64.so")
- // lib32.so is installed by lib32.vendor_shared.30.arm64
- ctx.ModuleForTests("lib32.vendor_shared.30.arm64", shared32Variant).Output("lib32.so")
+ // lib32.so is installed by lib32.vendor_shared.31.arm64
+ ctx.ModuleForTests("lib32.vendor_shared.31.arm64", shared32Variant).Output("lib32.so")
- // libvendor_available.so is installed by libvendor_available.vendor_shared.30.arm64
- ctx.ModuleForTests("libvendor_available.vendor_shared.30.arm64", sharedVariant).Output("libvendor_available.so")
+ // libvendor_available.so is installed by libvendor_available.vendor_shared.31.arm64
+ ctx.ModuleForTests("libvendor_available.vendor_shared.31.arm64", sharedVariant).Output("libvendor_available.so")
// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
- // bin is installed by bin.vendor_binary.30.arm64
- ctx.ModuleForTests("bin.vendor_binary.30.arm64", binaryVariant).Output("bin")
+ // bin is installed by bin.vendor_binary.31.arm64
+ ctx.ModuleForTests("bin.vendor_binary.31.arm64", binaryVariant).Output("bin")
- // bin32 is installed by bin32.vendor_binary.30.arm64
- ctx.ModuleForTests("bin32.vendor_binary.30.arm64", binary32Variant).Output("bin32")
+ // bin32 is installed by bin32.vendor_binary.31.arm64
+ ctx.ModuleForTests("bin32.vendor_binary.31.arm64", binary32Variant).Output("bin32")
// bin_without_snapshot is installed by bin_without_snapshot
ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
- // libvendor, libvendor_available and bin don't have vendor.30 variant
+ // libvendor, libvendor_available and bin don't have vendor.31 variant
libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
if inList(sharedVariant, libvendorVariants) {
t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
diff --git a/cc/vndk.go b/cc/vndk.go
index 8b3788b..6a56c34 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -234,7 +234,6 @@
var (
llndkLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsLLNDK && !m.Header() })
- llndkLibrariesWithoutHWASAN = vndkModuleListRemover(llndkLibraries, "libclang_rt.hwasan-")
vndkSPLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKSP })
vndkCoreLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKCore })
vndkPrivateLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKPrivate })
@@ -372,7 +371,7 @@
if mctx.ModuleName() == "libz" {
return false
}
- return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.isVndkSp()
+ return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.IsVndkSp()
}
useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
@@ -419,10 +418,6 @@
}
func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
- // Make uses LLNDK_LIBRARIES to determine which libraries to install.
- // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
- // Therefore, by removing the library here, we cause it to only be installed if libc
- // depends on it.
ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
@@ -434,8 +429,9 @@
type vndkLibrariesTxt struct {
android.SingletonModuleBase
- lister moduleListerFunc
- makeVarName string
+ lister moduleListerFunc
+ makeVarName string
+ filterOutFromMakeVar string
properties VndkLibrariesTxtProperties
@@ -454,8 +450,12 @@
// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries
// generated by Soong but can be referenced by other modules.
// For example, apex_vndk can depend on these files as prebuilt.
+// Make uses LLNDK_LIBRARIES to determine which libraries to install.
+// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+// Therefore, by removing the library here, we cause it to only be installed if libc
+// depends on it.
func llndkLibrariesTxtFactory() android.SingletonModule {
- return newVndkLibrariesTxt(llndkLibrariesWithoutHWASAN, "LLNDK_LIBRARIES")
+ return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan-")
}
// vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries
@@ -493,16 +493,21 @@
return newVndkLibrariesTxt(vndkUsingCoreVariantLibraries, "VNDK_USING_CORE_VARIANT_LIBRARIES")
}
-func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule {
+func newVndkLibrariesWithMakeVarFilter(lister moduleListerFunc, makeVarName string, filter string) android.SingletonModule {
m := &vndkLibrariesTxt{
- lister: lister,
- makeVarName: makeVarName,
+ lister: lister,
+ makeVarName: makeVarName,
+ filterOutFromMakeVar: filter,
}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}
+func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule {
+ return newVndkLibrariesWithMakeVarFilter(lister, makeVarName, "")
+}
+
func insertVndkVersion(filename string, vndkVersion string) string {
if index := strings.LastIndex(filename, "."); index != -1 {
return filename[:index] + "." + vndkVersion + filename[index:]
@@ -542,8 +547,21 @@
}
func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) {
- ctx.Strict(txt.makeVarName, strings.Join(txt.moduleNames, " "))
-
+ filter := func(modules []string, prefix string) []string {
+ if prefix == "" {
+ return modules
+ }
+ var result []string
+ for _, module := range modules {
+ if strings.HasPrefix(module, prefix) {
+ continue
+ } else {
+ result = append(result, module)
+ }
+ }
+ return result
+ }
+ ctx.Strict(txt.makeVarName, strings.Join(filter(txt.moduleNames, txt.filterOutFromMakeVar), " "))
}
// PrebuiltEtcModule interface
@@ -574,38 +592,37 @@
vndkSnapshotZipFile android.OptionalPath
}
-func isVndkSnapshotAware(config android.DeviceConfig, m *Module,
- apexInfo android.ApexInfo) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
+func isVndkSnapshotAware(config android.DeviceConfig, m LinkableInterface,
+ apexInfo android.ApexInfo) (vndkType string, isVndkSnapshotLib bool) {
if m.Target().NativeBridge == android.NativeBridgeEnabled {
- return nil, "", false
+ return "", false
}
// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
// !installable: Snapshot only cares about "installable" modules.
// !m.IsLlndk: llndk stubs are required for building against snapshots.
// IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
// !outputFile.Valid: Snapshot requires valid output file.
- if !m.InVendor() || (!m.installable(apexInfo) && !m.IsLlndk()) || m.IsSnapshotPrebuilt() || !m.outputFile.Valid() {
- return nil, "", false
+ if !m.InVendor() || (!installable(m, apexInfo) && !m.IsLlndk()) || m.IsSnapshotPrebuilt() || !m.OutputFile().Valid() {
+ return "", false
}
- l, ok := m.linker.(snapshotLibraryInterface)
- if !ok || !l.shared() {
- return nil, "", false
+ if !m.IsSnapshotLibrary() || !m.Shared() {
+ return "", false
}
if m.VndkVersion() == config.PlatformVndkVersion() {
if m.IsVndk() && !m.IsVndkExt() {
- if m.isVndkSp() {
- return l, "vndk-sp", true
+ if m.IsVndkSp() {
+ return "vndk-sp", true
} else {
- return l, "vndk-core", true
+ return "vndk-core", true
}
- } else if l.hasLLNDKStubs() && l.stubsVersion() == "" {
+ } else if m.HasLlndkStubs() && m.StubsVersion() == "" {
// Use default version for the snapshot.
- return l, "llndk-stub", true
+ return "llndk-stub", true
}
}
- return nil, "", false
+ return "", false
}
func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -722,7 +739,7 @@
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
- l, vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
+ vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
if !ok {
return
}
@@ -761,7 +778,7 @@
}
if ctx.Config().VndkSnapshotBuildArtifacts() {
- headers = append(headers, l.snapshotHeaders()...)
+ headers = append(headers, m.SnapshotHeaders()...)
}
})
diff --git a/cmd/go2bp/Android.bp b/cmd/go2bp/Android.bp
new file mode 100644
index 0000000..53d70b6
--- /dev/null
+++ b/cmd/go2bp/Android.bp
@@ -0,0 +1,26 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "go2bp",
+ deps: [
+ "blueprint-proptools",
+ "bpfix-lib",
+ ],
+ srcs: ["go2bp.go"],
+}
diff --git a/cmd/go2bp/go2bp.go b/cmd/go2bp/go2bp.go
new file mode 100644
index 0000000..67138f1
--- /dev/null
+++ b/cmd/go2bp/go2bp.go
@@ -0,0 +1,361 @@
+// 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 main
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sort"
+ "strings"
+ "text/template"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/bpfix/bpfix"
+)
+
+type RewriteNames []RewriteName
+type RewriteName struct {
+ prefix string
+ repl string
+}
+
+func (r *RewriteNames) String() string {
+ return ""
+}
+
+func (r *RewriteNames) Set(v string) error {
+ split := strings.SplitN(v, "=", 2)
+ if len(split) != 2 {
+ return fmt.Errorf("Must be in the form of <prefix>=<replace>")
+ }
+ *r = append(*r, RewriteName{
+ prefix: split[0],
+ repl: split[1],
+ })
+ return nil
+}
+
+func (r *RewriteNames) GoToBp(name string) string {
+ ret := name
+ for _, r := range *r {
+ prefix := r.prefix
+ if name == prefix {
+ ret = r.repl
+ break
+ }
+ prefix += "/"
+ if strings.HasPrefix(name, prefix) {
+ ret = r.repl + "-" + strings.TrimPrefix(name, prefix)
+ }
+ }
+ return strings.ReplaceAll(ret, "/", "-")
+}
+
+var rewriteNames = RewriteNames{}
+
+type Exclude map[string]bool
+
+func (e Exclude) String() string {
+ return ""
+}
+
+func (e Exclude) Set(v string) error {
+ e[v] = true
+ return nil
+}
+
+var excludes = make(Exclude)
+var excludeDeps = make(Exclude)
+var excludeSrcs = make(Exclude)
+
+type GoModule struct {
+ Dir string
+}
+
+type GoPackage struct {
+ Dir string
+ ImportPath string
+ Name string
+ Imports []string
+ GoFiles []string
+ TestGoFiles []string
+ TestImports []string
+
+ Module *GoModule
+}
+
+func (g GoPackage) IsCommand() bool {
+ return g.Name == "main"
+}
+
+func (g GoPackage) BpModuleType() string {
+ if g.IsCommand() {
+ return "blueprint_go_binary"
+ }
+ return "bootstrap_go_package"
+}
+
+func (g GoPackage) BpName() string {
+ if g.IsCommand() {
+ return filepath.Base(g.ImportPath)
+ }
+ return rewriteNames.GoToBp(g.ImportPath)
+}
+
+func (g GoPackage) BpDeps(deps []string) []string {
+ var ret []string
+ for _, d := range deps {
+ // Ignore stdlib dependencies
+ if !strings.Contains(d, ".") {
+ continue
+ }
+ if _, ok := excludeDeps[d]; ok {
+ continue
+ }
+ name := rewriteNames.GoToBp(d)
+ ret = append(ret, name)
+ }
+ return ret
+}
+
+func (g GoPackage) BpSrcs(srcs []string) []string {
+ var ret []string
+ prefix, err := filepath.Rel(g.Module.Dir, g.Dir)
+ if err != nil {
+ panic(err)
+ }
+ for _, f := range srcs {
+ f = filepath.Join(prefix, f)
+ if _, ok := excludeSrcs[f]; ok {
+ continue
+ }
+ ret = append(ret, f)
+ }
+ return ret
+}
+
+// AllImports combines Imports and TestImports, as blueprint does not differentiate these.
+func (g GoPackage) AllImports() []string {
+ imports := append([]string(nil), g.Imports...)
+ imports = append(imports, g.TestImports...)
+
+ if len(imports) == 0 {
+ return nil
+ }
+
+ // Sort and de-duplicate
+ sort.Strings(imports)
+ j := 0
+ for i := 1; i < len(imports); i++ {
+ if imports[i] == imports[j] {
+ continue
+ }
+ j++
+ imports[j] = imports[i]
+ }
+ return imports[:j+1]
+}
+
+var bpTemplate = template.Must(template.New("bp").Parse(`
+{{.BpModuleType}} {
+ name: "{{.BpName}}",
+ {{- if not .IsCommand}}
+ pkgPath: "{{.ImportPath}}",
+ {{- end}}
+ {{- if .BpDeps .AllImports}}
+ deps: [
+ {{- range .BpDeps .AllImports}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+ {{- if .BpSrcs .GoFiles}}
+ srcs: [
+ {{- range .BpSrcs .GoFiles}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+ {{- if .BpSrcs .TestGoFiles}}
+ testSrcs: [
+ {{- range .BpSrcs .TestGoFiles}}
+ "{{.}}",
+ {{- end}}
+ ],
+ {{- end}}
+}
+`))
+
+func rerunForRegen(filename string) error {
+ buf, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+
+ scanner := bufio.NewScanner(bytes.NewBuffer(buf))
+
+ // Skip the first line in the file
+ for i := 0; i < 2; i++ {
+ if !scanner.Scan() {
+ if scanner.Err() != nil {
+ return scanner.Err()
+ } else {
+ return fmt.Errorf("unexpected EOF")
+ }
+ }
+ }
+
+ // Extract the old args from the file
+ line := scanner.Text()
+ if strings.HasPrefix(line, "// go2bp ") {
+ line = strings.TrimPrefix(line, "// go2bp ")
+ } else {
+ return fmt.Errorf("unexpected second line: %q", line)
+ }
+ args := strings.Split(line, " ")
+ lastArg := args[len(args)-1]
+ args = args[:len(args)-1]
+
+ // Append all current command line args except -regen <file> to the ones from the file
+ for i := 1; i < len(os.Args); i++ {
+ if os.Args[i] == "-regen" || os.Args[i] == "--regen" {
+ i++
+ } else {
+ args = append(args, os.Args[i])
+ }
+ }
+ args = append(args, lastArg)
+
+ cmd := os.Args[0] + " " + strings.Join(args, " ")
+ // Re-exec pom2bp with the new arguments
+ output, err := exec.Command("/bin/sh", "-c", cmd).Output()
+ if exitErr, _ := err.(*exec.ExitError); exitErr != nil {
+ return fmt.Errorf("failed to run %s\n%s", cmd, string(exitErr.Stderr))
+ } else if err != nil {
+ return err
+ }
+
+ return ioutil.WriteFile(filename, output, 0666)
+}
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, `go2bp, a tool to create Android.bp files from go modules
+
+The tool will extract the necessary information from Go files to create an Android.bp that can
+compile them. This needs to be run from the same directory as the go.mod file.
+
+Usage: %s [--rewrite <pkg-prefix>=<replace>] [-exclude <package>] [-regen <file>]
+
+ -rewrite <pkg-prefix>=<replace>
+ rewrite can be used to specify mappings between go package paths and Android.bp modules. The -rewrite
+ option can be specified multiple times. When determining the Android.bp module for a given Go
+ package, mappings are searched in the order they were specified. The first <pkg-prefix> matching
+ either the package directly, or as the prefix '<pkg-prefix>/' will be replaced with <replace>.
+ After all replacements are finished, all '/' characters are replaced with '-'.
+ -exclude <package>
+ Don't put the specified go package in the Android.bp file.
+ -exclude-deps <package>
+ Don't put the specified go package in the dependency lists.
+ -exclude-srcs <module>
+ Don't put the specified source files in srcs or testSrcs lists.
+ -regen <file>
+ Read arguments from <file> and overwrite it.
+
+`, os.Args[0])
+ }
+
+ var regen string
+
+ flag.Var(&excludes, "exclude", "Exclude go package")
+ flag.Var(&excludeDeps, "exclude-dep", "Exclude go package from deps")
+ flag.Var(&excludeSrcs, "exclude-src", "Exclude go file from source lists")
+ flag.Var(&rewriteNames, "rewrite", "Regex(es) to rewrite artifact names")
+ flag.StringVar(®en, "regen", "", "Rewrite specified file")
+ flag.Parse()
+
+ if regen != "" {
+ err := rerunForRegen(regen)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+ os.Exit(0)
+ }
+
+ if flag.NArg() != 0 {
+ fmt.Fprintf(os.Stderr, "Unused argument detected: %v\n", flag.Args())
+ os.Exit(1)
+ }
+
+ if _, err := os.Stat("go.mod"); err != nil {
+ fmt.Fprintln(os.Stderr, "go.mod file not found")
+ os.Exit(1)
+ }
+
+ cmd := exec.Command("go", "list", "-json", "./...")
+ output, err := cmd.Output()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to dump the go packages: %v\n", err)
+ os.Exit(1)
+ }
+ decoder := json.NewDecoder(bytes.NewReader(output))
+
+ pkgs := []GoPackage{}
+ for decoder.More() {
+ pkg := GoPackage{}
+ err := decoder.Decode(&pkg)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to parse json: %v\n", err)
+ os.Exit(1)
+ }
+ pkgs = append(pkgs, pkg)
+ }
+
+ buf := &bytes.Buffer{}
+
+ fmt.Fprintln(buf, "// Automatically generated with:")
+ fmt.Fprintln(buf, "// go2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+
+ for _, pkg := range pkgs {
+ if excludes[pkg.ImportPath] {
+ continue
+ }
+ if len(pkg.BpSrcs(pkg.GoFiles)) == 0 && len(pkg.BpSrcs(pkg.TestGoFiles)) == 0 {
+ continue
+ }
+ err := bpTemplate.Execute(buf, pkg)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "Error writing", pkg.Name, err)
+ os.Exit(1)
+ }
+ }
+
+ out, err := bpfix.Reformat(buf.String())
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "Error formatting output", err)
+ os.Exit(1)
+ }
+
+ os.Stdout.WriteString(out)
+}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index e0f8caa..20f146a 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -433,7 +433,7 @@
config := build.NewConfig(ctx, args...)
config.Environment().Set("OUT_DIR", outDir)
if !*keepArtifacts {
- config.Environment().Set("EMPTY_NINJA_FILE", "true")
+ config.SetEmptyNinjaFile(true)
}
build.FindSources(ctx, config, mpctx.Finder)
config.Lunch(ctx, product, *buildVariant)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 044689e..0336fb6 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -174,6 +174,9 @@
writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir())
}
+// doChosenActivity runs Soong for a specific activity, like bp2build, queryview
+// or the actual Soong build for the build.ninja file. Returns the top level
+// output file of the specific activity.
func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
bazelConversionRequested := bp2buildMarker != ""
mixedModeBuild := configuration.BazelContext.BazelEnabled()
@@ -186,11 +189,7 @@
// Run the alternate pipeline of bp2build mutators and singleton to convert
// Blueprint to BUILD files before everything else.
runBp2Build(configuration, extraNinjaDeps)
- if bp2buildMarker != "" {
- return bp2buildMarker
- } else {
- return bootstrap.CmdlineArgs.OutFile
- }
+ return bp2buildMarker
}
ctx := newContext(configuration, prepareBuildActions)
@@ -326,13 +325,13 @@
ninjaFileName := "build.ninja"
ninjaFile := shared.JoinPath(topDir, buildDir, ninjaFileName)
- ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName)
+ ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName+".d")
// A workaround to create the 'nothing' ninja target so `m nothing` works,
// since bp2build runs without Kati, and the 'nothing' target is declared in
// a Makefile.
ioutil.WriteFile(ninjaFile, []byte("build nothing: phony\n phony_output = true\n"), 0666)
ioutil.WriteFile(ninjaFileD,
- []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)),
+ []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFile, extraNinjaDepsString)),
0666)
}
@@ -357,6 +356,83 @@
}
}
+// Find BUILD files in the srcDir which...
+//
+// - are not on the allow list (android/bazel.go#ShouldKeepExistingBuildFileForDir())
+//
+// - won't be overwritten by corresponding bp2build generated files
+//
+// And return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
+func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string) []string {
+ paths := make([]string, 0)
+
+ for _, srcDirBazelFileRelativePath := range srcDirBazelFiles {
+ srcDirBazelFileFullPath := shared.JoinPath(topDir, srcDirBazelFileRelativePath)
+ fileInfo, err := os.Stat(srcDirBazelFileFullPath)
+ if err != nil {
+ // Warn about error, but continue trying to check files
+ fmt.Fprintf(os.Stderr, "WARNING: Error accessing path '%s', err: %s\n", srcDirBazelFileFullPath, err)
+ continue
+ }
+ if fileInfo.IsDir() {
+ // Don't ignore entire directories
+ continue
+ }
+ if !(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") {
+ // Don't ignore this file - it is not a build file
+ continue
+ }
+ srcDirBazelFileDir := filepath.Dir(srcDirBazelFileRelativePath)
+ if android.ShouldKeepExistingBuildFileForDir(srcDirBazelFileDir) {
+ // Don't ignore this existing build file
+ continue
+ }
+ correspondingBp2BuildFile := shared.JoinPath(topDir, generatedRoot, srcDirBazelFileRelativePath)
+ if _, err := os.Stat(correspondingBp2BuildFile); err == nil {
+ // If bp2build generated an alternate BUILD file, don't exclude this workspace path
+ // BUILD file clash resolution happens later in the symlink forest creation
+ continue
+ }
+ fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath)
+ paths = append(paths, srcDirBazelFileRelativePath)
+ }
+
+ return paths
+}
+
+// Returns temporary symlink forest excludes necessary for bazel build //external/... (and bazel build //frameworks/...) to work
+func getTemporaryExcludes() []string {
+ excludes := make([]string, 0)
+
+ // FIXME: 'autotest_lib' is a symlink back to external/autotest, and this causes an infinite symlink expansion error for Bazel
+ excludes = append(excludes, "external/autotest/venv/autotest_lib")
+
+ // FIXME: The external/google-fruit/extras/bazel_root/third_party/fruit dir is poison
+ // It contains several symlinks back to real source dirs, and those source dirs contain BUILD files we want to ignore
+ excludes = append(excludes, "external/google-fruit/extras/bazel_root/third_party/fruit")
+
+ // FIXME: 'frameworks/compile/slang' has a filegroup error due to an escaping issue
+ excludes = append(excludes, "frameworks/compile/slang")
+
+ return excludes
+}
+
+// Read the bazel.list file that the Soong Finder already dumped earlier (hopefully)
+// It contains the locations of BUILD files, BUILD.bazel files, etc. in the source dir
+func getExistingBazelRelatedFiles(topDir string) ([]string, error) {
+ bazelFinderFile := filepath.Join(filepath.Dir(bootstrap.CmdlineArgs.ModuleListFile), "bazel.list")
+ if !filepath.IsAbs(bazelFinderFile) {
+ // Assume this was a relative path under topDir
+ bazelFinderFile = filepath.Join(topDir, bazelFinderFile)
+ }
+ data, err := ioutil.ReadFile(bazelFinderFile)
+ if err != nil {
+ return nil, err
+ }
+ files := strings.Split(strings.TrimSpace(string(data)), "\n")
+ return files, nil
+}
+
// Run Soong in the bp2build mode. This creates a standalone context that registers
// an alternate pipeline of mutators and singletons specifically for generating
// Bazel BUILD files instead of Ninja files.
@@ -415,6 +491,17 @@
excludes = append(excludes, bootstrap.CmdlineArgs.NinjaBuildDir)
}
+ existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
+ os.Exit(1)
+ }
+
+ pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles)
+ excludes = append(excludes, pathsToIgnoredBuildFiles...)
+
+ excludes = append(excludes, getTemporaryExcludes()...)
+
symlinkForestDeps := bp2build.PlantSymlinkForest(
topDir, workspaceRoot, generatedRoot, configuration.SrcDir(), excludes)
@@ -433,9 +520,14 @@
os.Exit(1)
}
- if bp2buildMarker != "" {
- touch(shared.JoinPath(topDir, bp2buildMarker))
- } else {
- writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
- }
+ // Create an empty bp2build marker file.
+ touch(shared.JoinPath(topDir, bp2buildMarker))
+
+ // bp2build *always* writes a fake Ninja file containing just the nothing
+ // phony target if it ever re-runs. This allows bp2build to exit early with
+ // GENERATE_BAZEL_FILES=1 m nothing.
+ //
+ // If bp2build is invoked as part of an integrated mixed build, the fake
+ // build.ninja file will be rewritten later into the real file anyway.
+ writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
}
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index a69de6a..b7c260c 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -114,7 +114,10 @@
err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
}
- // Now, produce per-package module lists with detailed information.
+ // Now, produce per-package module lists with detailed information, and a list
+ // of keywords.
+ keywordsTmpl := template.Must(template.New("file").Parse(keywordsTemplate))
+ keywordsBuf := &bytes.Buffer{}
for _, pkg := range packages {
// We need a module name getter/setter function because I couldn't
// find a way to keep it in a variable defined within the template.
@@ -141,7 +144,17 @@
if err != nil {
return err
}
+ err = keywordsTmpl.Execute(keywordsBuf, data)
+ if err != nil {
+ return err
+ }
}
+
+ // Write out list of keywords. This includes all module and property names, which is useful for
+ // building syntax highlighters.
+ keywordsFilename := filepath.Join(filepath.Dir(filename), "keywords.txt")
+ err = ioutil.WriteFile(keywordsFilename, keywordsBuf.Bytes(), 0666)
+
return err
}
@@ -413,4 +426,9 @@
</script>
{{end}}
`
+
+ keywordsTemplate = `
+{{range $moduleType := .Modules}}{{$moduleType.Name}}:{{range $property := $moduleType.Properties}}{{$property.Name}},{{end}}
+{{end}}
+`
)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 1844bce..0bcec17 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -130,9 +130,11 @@
ProvidesUsesLibrary string // library name (usually the same as module name)
ClassLoaderContexts ClassLoaderContextMap
- Archs []android.ArchType
- DexPreoptImagesDeps []android.OutputPaths
- DexPreoptImageLocationsOnHost []string // boot image location on host (file path without the arch subdirectory)
+ Archs []android.ArchType
+ DexPreoptImagesDeps []android.OutputPaths
+
+ DexPreoptImageLocationsOnHost []string // boot image location on host (file path without the arch subdirectory)
+ DexPreoptImageLocationsOnDevice []string // boot image location on device (file path without the arch subdirectory)
PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files
PreoptBootClassPathDexLocations []string // virtual locations of boot class path files
@@ -370,6 +372,15 @@
func (d dex2oatDependencyTag) ExcludeFromApexContents() {
}
+func (d dex2oatDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
+ // RegisterToolDeps may run after the prebuilt mutators and hence register a
+ // dependency on the source module even when the prebuilt is to be used.
+ // dex2oatPathFromDep takes that into account when it retrieves the path to
+ // the binary, but we also need to disable the check for dependencies on
+ // disabled modules.
+ return target.IsReplacedByPrebuilt()
+}
+
// Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that
// needs dexpreopting and so it makes no sense for it to be checked for visibility or included in
// the apex.
@@ -377,6 +388,7 @@
var _ android.ExcludeFromVisibilityEnforcementTag = Dex2oatDepTag
var _ android.ExcludeFromApexContentsTag = Dex2oatDepTag
+var _ android.AllowDisabledModuleDependency = Dex2oatDepTag
// RegisterToolDeps adds the necessary dependencies to binary modules for tools
// that are required later when Get(Cached)GlobalSoongConfig is called. It
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 9d9234f..da015a3 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -499,11 +499,16 @@
// PathToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art
func PathToLocation(path android.Path, arch android.ArchType) string {
- pathArch := filepath.Base(filepath.Dir(path.String()))
+ return PathStringToLocation(path.String(), arch)
+}
+
+// PathStringToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art
+func PathStringToLocation(path string, arch android.ArchType) string {
+ pathArch := filepath.Base(filepath.Dir(path))
if pathArch != arch.String() {
panic(fmt.Errorf("last directory in %q must be %q", path, arch.String()))
}
- return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String()))
+ return filepath.Join(filepath.Dir(filepath.Dir(path)), filepath.Base(path))
}
func makefileMatch(pattern, s string) bool {
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index 32c4f84..7dbe74c 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -37,6 +37,12 @@
globalConfigPath = flag.String("global", "", "path to global configuration file")
moduleConfigPath = flag.String("module", "", "path to module configuration file")
outDir = flag.String("out_dir", "", "path to output directory")
+ // If uses_target_files is true, dexpreopt_gen will be running on extracted target_files.zip files.
+ // In this case, the tool replace output file path with $(basePath)/$(on-device file path).
+ // The flag is useful when running dex2oat on system image and vendor image which are built separately.
+ usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files")
+ // basePath indicates the path where target_files.zip is extracted.
+ basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
)
type builderContext struct {
@@ -134,32 +140,28 @@
}
}
}()
-
+ if *usesTargetFiles {
+ moduleConfig.ManifestPath = android.OptionalPath{}
+ prefix := "dex2oat_result"
+ moduleConfig.BuildPath = android.PathForOutput(ctx, filepath.Join(prefix, moduleConfig.DexLocation))
+ for i, location := range moduleConfig.PreoptBootClassPathDexLocations {
+ moduleConfig.PreoptBootClassPathDexFiles[i] = android.PathForSource(ctx, *basePath+location)
+ }
+ for i := range moduleConfig.ClassLoaderContexts {
+ for _, v := range moduleConfig.ClassLoaderContexts[i] {
+ v.Host = android.PathForSource(ctx, *basePath+v.Device)
+ }
+ }
+ moduleConfig.EnforceUsesLibraries = false
+ for i, location := range moduleConfig.DexPreoptImageLocationsOnDevice {
+ moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location
+ }
+ }
writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
}
func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig,
global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
- if err != nil {
- panic(err)
- }
-
- installDir := module.BuildPath.InSameDir(ctx, "dexpreopt_install")
-
- dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir.String())
- dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir.String())
-
- for _, install := range dexpreoptRule.Installs() {
- installPath := installDir.Join(ctx, strings.TrimPrefix(install.To, "/"))
- dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String()))
- dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
- }
- dexpreoptRule.Command().Tool(globalSoong.SoongZip).
- FlagWithArg("-o ", "$2").
- FlagWithArg("-C ", installDir.String()).
- FlagWithArg("-D ", installDir.String())
-
write := func(rule *android.RuleBuilder, file string) {
script := &bytes.Buffer{}
script.WriteString(scriptHeader)
@@ -195,6 +197,30 @@
panic(err)
}
}
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ if err != nil {
+ panic(err)
+ }
+ // When usesTargetFiles is true, only odex/vdex files are necessary.
+ // So skip redunant processes(such as copying the result to the artifact path, and zipping, and so on.)
+ if *usesTargetFiles {
+ write(dexpreoptRule, dexpreoptScriptPath)
+ return
+ }
+ installDir := module.BuildPath.InSameDir(ctx, "dexpreopt_install")
+
+ dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir.String())
+ dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir.String())
+
+ for _, install := range dexpreoptRule.Installs() {
+ installPath := installDir.Join(ctx, strings.TrimPrefix(install.To, "/"))
+ dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String()))
+ dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath)
+ }
+ dexpreoptRule.Command().Tool(globalSoong.SoongZip).
+ FlagWithArg("-o ", "$2").
+ FlagWithArg("-C ", installDir.String()).
+ FlagWithArg("-D ", installDir.String())
// The written scripts will assume the input is $1 and the output is $2
if module.DexPath.String() != "$1" {
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index a7c9143..1d24d6d 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -50,17 +50,19 @@
func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root android.OutputPath) android.OutputPath {
input := android.PathForModuleSrc(ctx, android.String(s.properties.Linker_config_src))
output := root.Join(ctx, "system", "etc", "linker.config.pb")
+
+ // we need "Module"s for packaging items
var otherModules []android.Module
+ deps := s.GatherPackagingSpecs(ctx)
ctx.WalkDeps(func(child, parent android.Module) bool {
- // Don't track direct dependencies that aren't not packaged
- if parent == s {
- if pi, ok := ctx.OtherModuleDependencyTag(child).(android.PackagingItem); !ok || !pi.IsPackagingItem() {
- return false
+ for _, ps := range child.PackagingSpecs() {
+ if _, ok := deps[ps.RelPathInPackage()]; ok {
+ otherModules = append(otherModules, child)
}
}
- otherModules = append(otherModules, child)
return true
})
+
builder := android.NewRuleBuilder(pctx, ctx)
linkerconfig.BuildLinkerConfig(ctx, builder, input, otherModules, output)
builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
diff --git a/java/Android.bp b/java/Android.bp
index 623a6c5..680f3a1 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -45,6 +45,7 @@
"genrule.go",
"hiddenapi.go",
"hiddenapi_modular.go",
+ "hiddenapi_monolithic.go",
"hiddenapi_singleton.go",
"jacoco.go",
"java.go",
diff --git a/java/app.go b/java/app.go
index 5695022..fc1ace0 100755
--- a/java/app.go
+++ b/java/app.go
@@ -893,7 +893,7 @@
return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
}
-func (a *AndroidApp) PreventInstall() {
+func (a *AndroidApp) SetPreventInstall() {
a.appProperties.PreventInstall = true
}
diff --git a/java/app_import.go b/java/app_import.go
index 839051e..6fe6204 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -99,6 +99,9 @@
// If set, create package-export.apk, which other packages can
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
Export_package_resources *bool
+
+ // Optional. Install to a subdirectory of the default install path for the module
+ Relative_install_path *string
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -263,20 +266,25 @@
jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
- var installDir android.InstallPath
+ var pathFragments []string
+ relInstallPath := String(a.properties.Relative_install_path)
if a.isPrebuiltFrameworkRes() {
// framework-res.apk is installed as system/framework/framework-res.apk
- installDir = android.PathForModuleInstall(ctx, "framework")
+ if relInstallPath != "" {
+ ctx.PropertyErrorf("relative_install_path", "Relative_install_path cannot be set for framework-res")
+ }
+ pathFragments = []string{"framework"}
a.preprocessed = true
} else if Bool(a.properties.Privileged) {
- installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName())
+ pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()}
} else if ctx.InstallInTestcases() {
- installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch())
+ pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()}
} else {
- installDir = android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+ pathFragments = []string{"app", relInstallPath, a.BaseModuleName()}
}
+ installDir := android.PathForModuleInstall(ctx, pathFragments...)
a.dexpreopter.isApp = true
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 147ae45..024a3df 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -493,6 +493,69 @@
}
}
+func TestAndroidAppImport_relativeInstallPath(t *testing.T) {
+ bp := `
+ android_app_import {
+ name: "no_relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ }
+
+ android_app_import {
+ name: "relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ relative_install_path: "my/path",
+ }
+
+ android_app_import {
+ name: "framework-res",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ prefer: true,
+ }
+
+ android_app_import {
+ name: "privileged_relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ privileged: true,
+ relative_install_path: "my/path"
+ }
+ `
+ testCases := []struct {
+ name string
+ expectedInstallPath string
+ errorMessage string
+ }{
+ {
+ name: "no_relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk",
+ errorMessage: "Install path is not correct when relative_install_path is missing",
+ },
+ {
+ name: "relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk",
+ errorMessage: "Install path is not correct for app when relative_install_path is present",
+ },
+ {
+ name: "prebuilt_framework-res",
+ expectedInstallPath: "out/soong/target/product/test_device/system/framework/framework-res.apk",
+ errorMessage: "Install path is not correct for framework-res",
+ },
+ {
+ name: "privileged_relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk",
+ errorMessage: "Install path is not correct for privileged app when relative_install_path is present",
+ },
+ }
+ for _, testCase := range testCases {
+ ctx, _ := testJava(t, bp)
+ mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport)
+ android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath)
+ }
+}
+
func TestAndroidTestImport(t *testing.T) {
ctx, _ := testJava(t, `
android_test_import {
diff --git a/java/base.go b/java/base.go
index 19c85cd..440b004 100644
--- a/java/base.go
+++ b/java/base.go
@@ -229,12 +229,6 @@
// otherwise provides defaults libraries to add to the bootclasspath.
System_modules *string
- // The name of the module as used in build configuration.
- //
- // Allows a library to separate its actual name from the name used in
- // build configuration, e.g.ctx.Config().BootJars().
- ConfigurationName *string `blueprint:"mutated"`
-
// set the name of the output
Stem *string
@@ -895,8 +889,8 @@
kotlincFlags := j.properties.Kotlincflags
CheckKotlincFlags(ctx, kotlincFlags)
- // Dogfood the JVM_IR backend.
- kotlincFlags = append(kotlincFlags, "-Xuse-ir")
+ // Workaround for KT-46512
+ kotlincFlags = append(kotlincFlags, "-Xsam-conversions=class")
// If there are kotlin files, compile them first but pass all the kotlin and java files
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
@@ -1177,8 +1171,14 @@
j.properties.Instrument = true
}
+ // enforce syntax check to jacoco filters for any build (http://b/183622051)
+ specs := j.jacocoModuleToZipCommand(ctx)
+ if ctx.Failed() {
+ return
+ }
+
if j.shouldInstrument(ctx) {
- outputFile = j.instrument(ctx, flags, outputFile, jarName)
+ outputFile = j.instrument(ctx, flags, outputFile, jarName, specs)
}
// merge implementation jar with resources if necessary
@@ -1217,10 +1217,6 @@
return
}
- // Hidden API CSV generation and dex encoding
- dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, j.implementationJarFile,
- proptools.Bool(j.dexProperties.Uncompress_dex))
-
// merge dex jar with resources if necessary
if j.resourceJar != nil {
jars := android.Paths{dexOutputFile, j.resourceJar}
@@ -1236,6 +1232,12 @@
}
}
+ // Initialize the hiddenapi structure.
+ j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex)
+
+ // Encode hidden API flags in dex file, if needed.
+ dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
+
j.dexJarFile = dexOutputFile
// Dexpreopting
@@ -1390,9 +1392,7 @@
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
- classesJar android.Path, jarName string) android.OutputPath {
-
- specs := j.jacocoModuleToZipCommand(ctx)
+ classesJar android.Path, jarName string, specs string) android.OutputPath {
jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco-report-classes", jarName)
instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName).OutputPath
@@ -1495,15 +1495,6 @@
return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
}
-// ConfigurationName returns the name of the module as used in build configuration.
-//
-// This is usually the same as BaseModuleName() except for the <x>.impl libraries created by
-// java_sdk_library in which case this is the BaseModuleName() without the ".impl" suffix,
-// i.e. just <x>.
-func (j *Module) ConfigurationName() string {
- return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName())
-}
-
func (j *Module) JacocoReportClassesFile() android.Path {
return j.jacocoReportClassesFile
}
@@ -1787,3 +1778,9 @@
func (j *Module) ProvidesUsesLib() *string {
return j.usesLibraryProperties.Provides_uses_lib
}
+
+type ModuleWithStem interface {
+ Stem() string
+}
+
+var _ ModuleWithStem = (*Module)(nil)
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 1fb3deb..7abda80 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -89,7 +89,7 @@
name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
if apex, ok := moduleToApex[name]; ok {
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
- if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexByBaseName(apex) {
+ if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexModule(apex) {
// The module name/apex variant should be unique in the system but double check
// just in case something has gone wrong.
if existing, ok := nameToApexVariant[name]; ok {
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 02833ab..eddcc83 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -29,7 +29,7 @@
func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
+ ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator).Parallel()
})
}
@@ -95,6 +95,15 @@
if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
ctx.AddVariationDependencies(variations, tag, prebuiltName)
addedDep = true
+ } else if ctx.Config().AlwaysUsePrebuiltSdks() && len(variations) > 0 {
+ // TODO(b/179354495): Remove this code path once the Android build has been fully migrated to
+ // use bootclasspath_fragment properly.
+ // Some prebuilt java_sdk_library modules do not yet have an APEX variations so try and add a
+ // dependency on the non-APEX variant.
+ if ctx.OtherModuleDependencyVariantExists(nil, prebuiltName) {
+ ctx.AddVariationDependencies(nil, tag, prebuiltName)
+ addedDep = true
+ }
}
// If no appropriate variant existing for this, so no dependency could be added, then it is an
@@ -226,12 +235,3 @@
m[android.SdkCorePlatform] = p.Core_platform_api.Stub_libs
return m
}
-
-// bootclasspathApiInfo contains paths resolved from BootclasspathAPIProperties
-type bootclasspathApiInfo struct {
- // stubJarsByKind maps from the android.SdkKind to the paths containing dex stub jars for each
- // kind.
- stubJarsByKind map[android.SdkKind]android.Paths
-}
-
-var bootclasspathApiInfoProvider = blueprint.NewProvider(bootclasspathApiInfo{})
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 6270b5b..792193f 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/dexpreopt"
+
"github.com/google/blueprint/proptools"
"github.com/google/blueprint"
@@ -61,8 +62,14 @@
}
// SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if
-// they were specified using java_boot_libs.
-func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType {
+// they were specified using java_boot_libs or java_sdk_libs.
+func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
+ // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs
+ // property, otherwise treat if it was specified in the java_boot_libs property.
+ if javaSdkLibrarySdkMemberType.IsInstance(child) {
+ return javaSdkLibrarySdkMemberType
+ }
+
return javaBootLibsSdkMemberType
}
@@ -70,12 +77,17 @@
return true
}
+// Contents of bootclasspath fragments in an apex are considered to be directly in the apex, as if
+// they were listed in java_libs.
+func (b bootclasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
+
// The tag used for the dependency between the bootclasspath_fragment module and its contents.
var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{}
var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag
var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag
var _ android.SdkMemberTypeDependencyTag = bootclasspathFragmentContentDepTag
+var _ android.CopyDirectlyInAnyApexTag = bootclasspathFragmentContentDepTag
func IsBootclasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool {
return tag == bootclasspathFragmentContentDepTag
@@ -85,6 +97,9 @@
type BootclasspathFragmentCoverageAffectedProperties struct {
// The contents of this bootclasspath_fragment, could be either java_library, or java_sdk_library.
//
+ // A java_sdk_library specified here will also be treated as if it was specified on the stub_libs
+ // property.
+ //
// The order of this list matters as it is the order that is used in the bootclasspath.
Contents []string
@@ -103,20 +118,39 @@
Coverage BootclasspathFragmentCoverageAffectedProperties
Hidden_api HiddenAPIFlagFileProperties
+
+ // Properties that allow a fragment to depend on other fragments. This is needed for hidden API
+ // processing as it needs access to all the classes used by a fragment including those provided
+ // by other fragments.
+ BootclasspathFragmentsDepsProperties
}
type BootclasspathFragmentModule struct {
android.ModuleBase
android.ApexModuleBase
android.SdkBase
+ ClasspathFragmentBase
+
properties bootclasspathFragmentProperties
}
+// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
+// bootclasspath fragment modules.
+type commonBootclasspathFragment interface {
+ // produceHiddenAPIAllFlagsFile produces the all-flags.csv and intermediate files.
+ //
+ // Updates the supplied hiddenAPIInfo with the paths to the generated files set.
+ produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput
+}
+
+var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil)
+
func bootclasspathFragmentFactory() android.Module {
m := &BootclasspathFragmentModule{}
m.AddProperties(&m.properties)
android.InitApexModule(m)
android.InitSdkAwareModule(m)
+ initClasspathFragment(m, BOOTCLASSPATH)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
@@ -140,61 +174,70 @@
// necessary.
func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
contents := m.properties.Contents
- if m.properties.Image_name == nil && len(contents) == 0 {
- ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
+ if len(contents) == 0 {
+ ctx.PropertyErrorf("contents", "required property is missing")
+ return
+ }
+
+ if m.properties.Image_name == nil {
+ // Nothing to do.
+ return
}
imageName := proptools.String(m.properties.Image_name)
- if imageName == "art" {
- // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
- if android.IsModuleInVersionedSdk(m) {
- // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
- // 1. There is no way to use this at the moment so ignoring it is safe.
- // 2. Attempting to initialize the contents property from the configuration will end up having
- // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
- // as the unversioned prebuilt could end up with an APEX variant created for the source
- // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
- // turn will prevent it from accessing the dex implementation jar from that which will
- // break hidden API processing, amongst others.
- return
- }
-
- // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
- // too early in the Soong processing for that to work.
- global := dexpreopt.GetGlobalConfig(ctx)
- modules := global.ArtApexJars
-
- // Make sure that the apex specified in the configuration is consistent and is one for which
- // this boot image is available.
- commonApex := ""
- for i := 0; i < modules.Len(); i++ {
- apex := modules.Apex(i)
- jar := modules.Jar(i)
- if apex == "platform" {
- ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar)
- continue
- }
- if !m.AvailableFor(apex) {
- ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q",
- apex, m.ApexAvailable())
- continue
- }
- if commonApex == "" {
- commonApex = apex
- } else if commonApex != apex {
- ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
- commonApex, apex)
- }
- }
-
- if len(contents) != 0 {
- // Nothing to do.
- return
- }
-
- // Store the jars in the Contents property so that they can be used to add dependencies.
- m.properties.Contents = modules.CopyOfJars()
+ if imageName != "art" {
+ ctx.PropertyErrorf("image_name", `unknown image name %q, expected "art"`, imageName)
+ return
}
+
+ // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
+ if android.IsModuleInVersionedSdk(m) {
+ // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
+ // 1. There is no way to use this at the moment so ignoring it is safe.
+ // 2. Attempting to initialize the contents property from the configuration will end up having
+ // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
+ // as the unversioned prebuilt could end up with an APEX variant created for the source
+ // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
+ // turn will prevent it from accessing the dex implementation jar from that which will
+ // break hidden API processing, amongst others.
+ return
+ }
+
+ // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
+ // too early in the Soong processing for that to work.
+ global := dexpreopt.GetGlobalConfig(ctx)
+ modules := global.ArtApexJars
+
+ // Make sure that the apex specified in the configuration is consistent and is one for which
+ // this boot image is available.
+ commonApex := ""
+ for i := 0; i < modules.Len(); i++ {
+ apex := modules.Apex(i)
+ jar := modules.Jar(i)
+ if apex == "platform" {
+ ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar)
+ continue
+ }
+ if !m.AvailableFor(apex) {
+ ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q",
+ apex, m.ApexAvailable())
+ continue
+ }
+ if commonApex == "" {
+ commonApex = apex
+ } else if commonApex != apex {
+ ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
+ commonApex, apex)
+ }
+ }
+
+ if len(contents) != 0 {
+ // Nothing to do.
+ return
+ }
+
+ // Store the jars in the Contents property so that they can be used to add dependencies.
+ m.properties.Contents = modules.CopyOfJars()
}
// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
@@ -242,41 +285,40 @@
// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
// apex contents.
type BootclasspathFragmentApexContentInfo struct {
- // The image config, internal to this module (and the dex_bootjars singleton).
- //
- // Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
- // when SkipDexpreoptBootJars(ctx) returns true.
- imageConfig *bootImageConfig
+ // The configured modules, will be empty if this is from a bootclasspath_fragment that does not
+ // set image_name: "art".
+ modules android.ConfiguredJarList
+
+ // Map from arch type to the boot image files.
+ bootImageFilesByArch map[android.ArchType]android.OutputPaths
+
+ // Map from the name of the context module (as returned by Name()) to the hidden API encoded dex
+ // jar path.
+ contentModuleDexJarPaths map[string]android.Path
}
func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
- return i.imageConfig.modules
+ return i.modules
}
// Get a map from ArchType to the associated boot image's contents for Android.
//
// Extension boot images only return their own files, not the files of the boot images they extend.
func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() map[android.ArchType]android.OutputPaths {
- files := map[android.ArchType]android.OutputPaths{}
- if i.imageConfig != nil {
- for _, variant := range i.imageConfig.variants {
- // We also generate boot images for host (for testing), but we don't need those in the apex.
- // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
- if variant.target.Os == android.Android {
- files[variant.target.Arch.ArchType] = variant.imagesDeps
- }
- }
- }
- return files
+ return i.bootImageFilesByArch
}
// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
//
// The dex boot jar is one which has had hidden API encoding performed on it.
-func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) android.Path {
- j := module.(UsesLibraryDependency)
- dexJar := j.DexJarBuildPath()
- return dexJar
+func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) {
+ name := module.Name()
+ if dexJar, ok := i.contentModuleDexJarPaths[name]; ok {
+ return dexJar, nil
+ } else {
+ return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s",
+ name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", "))
+ }
}
func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
@@ -331,6 +373,11 @@
dexpreopt.RegisterToolDeps(ctx)
}
+func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+ // Add dependencies on all the fragments.
+ b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
+}
+
func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Only perform a consistency check if this module is the active module. That will prevent an
// unused prebuilt that was created without instrumentation from breaking an instrumentation
@@ -339,30 +386,139 @@
b.bootclasspathImageNameContentsConsistencyCheck(ctx)
}
+ // Generate classpaths.proto config
+ b.generateClasspathProtoBuildActions(ctx)
+
+ // Gather the bootclasspath fragment's contents.
+ var contents []android.Module
+ ctx.VisitDirectDeps(func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ if IsBootclasspathFragmentContentDepTag(tag) {
+ contents = append(contents, module)
+ }
+ })
+
+ fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
+
// Perform hidden API processing.
- b.generateHiddenAPIBuildActions(ctx)
+ hiddenAPIFlagOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
- // Nothing to do if skipping the dexpreopt of boot image jars.
- if SkipDexpreoptBootJars(ctx) {
- return
- }
-
- // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
- // GenerateSingletonBuildActions method as it cannot create it for itself.
- dexpreopt.GetGlobalSoongConfig(ctx)
-
+ // Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
+ // prebuilt which will not use the image config.
imageConfig := b.getImageConfig(ctx)
- if imageConfig == nil {
- return
+
+ // A prebuilt fragment cannot contribute to the apex.
+ if !android.IsModulePrebuilt(ctx.Module()) {
+ // Provide the apex content info.
+ b.provideApexContentInfo(ctx, imageConfig, contents, hiddenAPIFlagOutput)
+ }
+}
+
+// provideApexContentInfo creates, initializes and stores the apex content info for use by other
+// modules.
+func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) {
+ // Construct the apex content info from the config.
+ info := BootclasspathFragmentApexContentInfo{}
+
+ // Populate the apex content info with paths to the dex jars.
+ b.populateApexContentInfoDexJars(ctx, &info, contents, hiddenAPIFlagOutput)
+
+ if imageConfig != nil {
+ info.modules = imageConfig.modules
+
+ if !SkipDexpreoptBootJars(ctx) {
+ // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+ // GenerateSingletonBuildActions method as it cannot create it for itself.
+ dexpreopt.GetGlobalSoongConfig(ctx)
+
+ // Only generate the boot image if the configuration does not skip it.
+ if b.generateBootImageBuildActions(ctx, contents, imageConfig) {
+ // Allow the apex to access the boot image files.
+ files := map[android.ArchType]android.OutputPaths{}
+ for _, variant := range imageConfig.variants {
+ // We also generate boot images for host (for testing), but we don't need those in the apex.
+ // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
+ if variant.target.Os == android.Android {
+ files[variant.target.Arch.ArchType] = variant.imagesDeps
+ }
+ }
+ info.bootImageFilesByArch = files
+ }
+ }
}
- // Construct the boot image info from the config.
- info := BootclasspathFragmentApexContentInfo{imageConfig: imageConfig}
-
- // Make it available for other modules.
+ // Make the apex content info available for other modules.
ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
}
+// populateApexContentInfoDexJars adds paths to the dex jars provided by this fragment to the
+// apex content info.
+func (b *BootclasspathFragmentModule) populateApexContentInfoDexJars(ctx android.ModuleContext, info *BootclasspathFragmentApexContentInfo, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) {
+
+ info.contentModuleDexJarPaths = map[string]android.Path{}
+ if hiddenAPIFlagOutput != nil {
+ // Hidden API encoding has been performed.
+ flags := hiddenAPIFlagOutput.AllFlagsPath
+ for _, m := range contents {
+ h := m.(hiddenAPIModule)
+ unencodedDex := h.bootDexJar()
+ if unencodedDex == nil {
+ // This is an error. Sometimes Soong will report the error directly, other times it will
+ // defer the error reporting to happen only when trying to use the missing file in ninja.
+ // Either way it is handled by extractBootDexJarsFromHiddenAPIModules which must have been
+ // called before this as it generates the flags that are used to encode these files.
+ continue
+ }
+
+ outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
+ encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, flags, *h.uncompressDex(), outputDir)
+ info.contentModuleDexJarPaths[m.Name()] = encodedDex
+ }
+ } else {
+ for _, m := range contents {
+ j := m.(UsesLibraryDependency)
+ dexJar := j.DexJarBuildPath()
+ info.contentModuleDexJarPaths[m.Name()] = dexJar
+ }
+ }
+}
+
+// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
+func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
+ var classpathJars []classpathJar
+ if "art" == proptools.String(b.properties.Image_name) {
+ // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
+ classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+ } else {
+ classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
+ }
+ b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+}
+
+func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+ if "art" == proptools.String(b.properties.Image_name) {
+ return b.getImageConfig(ctx).modules
+ }
+
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ // Convert content names to their appropriate stems, in case a test library is overriding an actual boot jar
+ var stems []string
+ for _, name := range b.properties.Contents {
+ dep := ctx.GetDirectDepWithTag(name, bootclasspathFragmentContentDepTag)
+ if m, ok := dep.(ModuleWithStem); ok {
+ stems = append(stems, m.Stem())
+ } else {
+ ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
+ }
+ }
+
+ // Only create configs for updatable boot jars. Non-updatable boot jars must be part of the
+ // platform_bootclasspath's classpath proto config to guarantee that they come before any
+ // updatable jars at runtime.
+ return global.UpdatableBootJars.Filter(stems)
+}
+
func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
// Get a map of the image configs that are supported.
imageConfigs := genBootImageConfigs(ctx)
@@ -383,19 +539,113 @@
}
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
-func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext) {
- // Resolve the properties to paths.
- flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
+func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIFlagOutput {
- // Store the information for use by platform_bootclasspath.
- ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
+ // Create hidden API input structure.
+ input := b.createHiddenAPIFlagInput(ctx, contents, fragments)
- // Convert the kind specific lists of modules into kind specific lists of jars.
- stubJarsByKind := hiddenAPIGatherStubLibDexJarPaths(ctx)
+ var output *HiddenAPIFlagOutput
- // Store the information for use by other modules.
- bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: stubJarsByKind}
- ctx.SetProvider(bootclasspathApiInfoProvider, bootclasspathApiInfo)
+ // Hidden API processing is conditional as a temporary workaround as not all
+ // bootclasspath_fragments provide the appropriate information needed for hidden API processing
+ // which leads to breakages of the build.
+ // TODO(b/179354495): Stop hidden API processing being conditional once all bootclasspath_fragment
+ // modules have been updated to support it.
+ if input.canPerformHiddenAPIProcessing(ctx, b.properties) {
+ // Get the content modules that contribute to the hidden API processing.
+ hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, contents)
+
+ // Delegate the production of the hidden API all-flags.csv file to a module type specific method.
+ common := ctx.Module().(commonBootclasspathFragment)
+ output = common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, input)
+ }
+
+ // Initialize a HiddenAPIInfo structure.
+ hiddenAPIInfo := HiddenAPIInfo{
+ // The monolithic hidden API processing needs access to the flag files that override the default
+ // flags from all the fragments whether or not they actually perform their own hidden API flag
+ // generation. That is because the monolithic hidden API processing uses those flag files to
+ // perform its own flag generation.
+ FlagFilesByCategory: input.FlagFilesByCategory,
+
+ // Other bootclasspath_fragments that depend on this need the transitive set of stub dex jars
+ // from this to resolve any references from their code to classes provided by this fragment
+ // and the fragments this depends upon.
+ TransitiveStubDexJarsByKind: input.transitiveStubDexJarsByKind(),
+ }
+
+ if output != nil {
+ // The monolithic hidden API processing also needs access to all the output files produced by
+ // hidden API processing of this fragment.
+ hiddenAPIInfo.HiddenAPIFlagOutput = *output
+ }
+
+ // Provide it for use by other modules.
+ ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
+
+ return output
+}
+
+// createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
+// from the properties on this module and its dependencies.
+func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
+
+ // Merge the HiddenAPIInfo from all the fragment dependencies.
+ dependencyHiddenApiInfo := newHiddenAPIInfo()
+ dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments)
+
+ // Create hidden API flag input structure.
+ input := newHiddenAPIFlagInput()
+
+ // Update the input structure with information obtained from the stub libraries.
+ input.gatherStubLibInfo(ctx, contents)
+
+ // Populate with flag file paths from the properties.
+ input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
+
+ // Store the stub dex jars from this module's fragment dependencies.
+ input.DependencyStubDexJarsByKind = dependencyHiddenApiInfo.TransitiveStubDexJarsByKind
+
+ return input
+}
+
+// produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files)
+// for the fragment.
+func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+ // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
+ // paths to the created files.
+ return hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, input)
+}
+
+// generateBootImageBuildActions generates ninja rules to create the boot image if required for this
+// module.
+//
+// Returns true if the boot image is created, false otherwise.
+func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, contents []android.Module, imageConfig *bootImageConfig) bool {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if !shouldBuildBootImages(ctx.Config(), global) {
+ return false
+ }
+
+ // Bootclasspath fragment modules that are for the platform do not produce a boot image.
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ if apexInfo.IsForPlatform() {
+ return false
+ }
+
+ // Bootclasspath fragment modules that are versioned do not produce a boot image.
+ if android.IsModuleInVersionedSdk(ctx.Module()) {
+ return false
+ }
+
+ // Copy the dex jars of this fragment's content modules to their predefined locations.
+ copyBootJarsToPredefinedLocations(ctx, contents, imageConfig.modules, imageConfig.dexPaths)
+
+ // Build a profile for the image config and then use that to build the boot image.
+ profile := bootImageProfileRule(ctx, imageConfig)
+ buildBootImage(ctx, imageConfig, profile)
+
+ return true
}
type bootclasspathFragmentMemberType struct {
@@ -437,7 +687,22 @@
Core_platform_stub_libs []string
// Flag files by *hiddenAPIFlagFileCategory
- Flag_files_by_category map[*hiddenAPIFlagFileCategory]android.Paths
+ Flag_files_by_category FlagFilesByCategory
+
+ // The path to the generated stub-flags.csv file.
+ Stub_flags_path android.OptionalPath
+
+ // The path to the generated annotation-flags.csv file.
+ Annotation_flags_path android.OptionalPath
+
+ // The path to the generated metadata.csv file.
+ Metadata_path android.OptionalPath
+
+ // The path to the generated index.csv file.
+ Index_path android.OptionalPath
+
+ // The path to the generated all-flags.csv file.
+ All_flags_path android.OptionalPath
}
func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -446,10 +711,17 @@
b.Image_name = module.properties.Image_name
b.Contents = module.properties.Contents
- // Get the flag file information from the module.
+ // Get the hidden API information from the module.
mctx := ctx.SdkModuleContext()
- flagFileInfo := mctx.OtherModuleProvider(module, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
- b.Flag_files_by_category = flagFileInfo.categoryToPaths
+ hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
+
+ // Copy all the generated file paths.
+ b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
+ b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath)
+ b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
+ b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
+ b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
// Copy stub_libs properties.
b.Stub_libs = module.properties.Api.Stub_libs
@@ -477,14 +749,17 @@
corePlatformApiPropertySet.AddPropertyWithTag("stub_libs", b.Core_platform_stub_libs, requiredMemberDependency)
}
+ hiddenAPISet := propertySet.AddPropertySet("hidden_api")
+ hiddenAPIDir := "hiddenapi"
+
+ // Copy manually curated flag files specified on the bootclasspath_fragment.
if b.Flag_files_by_category != nil {
- hiddenAPISet := propertySet.AddPropertySet("hidden_api")
for _, category := range hiddenAPIFlagFileCategories {
paths := b.Flag_files_by_category[category]
if len(paths) > 0 {
dests := []string{}
for _, p := range paths {
- dest := filepath.Join("hiddenapi", p.Base())
+ dest := filepath.Join(hiddenAPIDir, p.Base())
builder.CopyToSnapshot(p, dest)
dests = append(dests, dest)
}
@@ -492,10 +767,47 @@
}
}
}
+
+ copyOptionalPath := func(path android.OptionalPath, property string) {
+ if path.Valid() {
+ p := path.Path()
+ dest := filepath.Join(hiddenAPIDir, p.Base())
+ builder.CopyToSnapshot(p, dest)
+ hiddenAPISet.AddProperty(property, dest)
+ }
+ }
+
+ // Copy all the generated files, if available.
+ copyOptionalPath(b.Stub_flags_path, "stub_flags")
+ copyOptionalPath(b.Annotation_flags_path, "annotation_flags")
+ copyOptionalPath(b.Metadata_path, "metadata")
+ copyOptionalPath(b.Index_path, "index")
+ copyOptionalPath(b.All_flags_path, "all_flags")
}
var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil)
+// prebuiltBootclasspathFragmentProperties contains additional prebuilt_bootclasspath_fragment
+// specific properties.
+type prebuiltBootclasspathFragmentProperties struct {
+ Hidden_api struct {
+ // The path to the stub-flags.csv file created by the bootclasspath_fragment.
+ Stub_flags *string `android:"path"`
+
+ // The path to the annotation-flags.csv file created by the bootclasspath_fragment.
+ Annotation_flags *string `android:"path"`
+
+ // The path to the metadata.csv file created by the bootclasspath_fragment.
+ Metadata *string `android:"path"`
+
+ // The path to the index.csv file created by the bootclasspath_fragment.
+ Index *string `android:"path"`
+
+ // The path to the all-flags.csv file created by the bootclasspath_fragment.
+ All_flags *string `android:"path"`
+ }
+}
+
// A prebuilt version of the bootclasspath_fragment module.
//
// At the moment this is basically just a bootclasspath_fragment module that can be used as a
@@ -504,6 +816,9 @@
type prebuiltBootclasspathFragmentModule struct {
BootclasspathFragmentModule
prebuilt android.Prebuilt
+
+ // Additional prebuilt specific properties.
+ prebuiltProperties prebuiltBootclasspathFragmentProperties
}
func (module *prebuiltBootclasspathFragmentModule) Prebuilt() *android.Prebuilt {
@@ -514,9 +829,33 @@
return module.prebuilt.Name(module.ModuleBase.Name())
}
+// produceHiddenAPIAllFlagsFile returns a path to the prebuilt all-flags.csv or nil if none is
+// specified.
+func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, _ HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+ pathForOptionalSrc := func(src *string) android.Path {
+ if src == nil {
+ // TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
+ return nil
+ }
+ return android.PathForModuleSrc(ctx, *src)
+ }
+
+ output := HiddenAPIFlagOutput{
+ StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags),
+ AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags),
+ MetadataPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata),
+ IndexPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index),
+ AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags),
+ }
+
+ return &output
+}
+
+var _ commonBootclasspathFragment = (*prebuiltBootclasspathFragmentModule)(nil)
+
func prebuiltBootclasspathFragmentFactory() android.Module {
m := &prebuiltBootclasspathFragmentModule{}
- m.AddProperties(&m.properties)
+ m.AddProperties(&m.properties, &m.prebuiltProperties)
// This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs
// array.
android.InitPrebuiltModule(m, &[]string{"placeholder"})
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 32ed7ea..fba7d1a 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -29,38 +29,28 @@
dexpreopt.PrepareForTestByEnablingDexpreopt,
)
-func TestUnknownBootclasspathFragment(t *testing.T) {
+func TestBootclasspathFragment_UnknownImageName(t *testing.T) {
prepareForTestWithBootclasspathFragment.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ `\Qimage_name: unknown image name "unknown", expected "art"\E`)).
RunTestWithBp(t, `
bootclasspath_fragment {
name: "unknown-bootclasspath-fragment",
image_name: "unknown",
+ contents: ["foo"],
}
`)
}
-func TestUnknownBootclasspathFragmentImageName(t *testing.T) {
+func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) {
prepareForTestWithBootclasspathFragment.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
- RunTestWithBp(t, `
- bootclasspath_fragment {
- name: "unknown-bootclasspath-fragment",
- image_name: "unknown",
- }
- `)
-}
-
-func TestUnknownPrebuiltBootclasspathFragment(t *testing.T) {
- prepareForTestWithBootclasspathFragment.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ `\Qimage_name: unknown image name "unknown", expected "art"\E`)).
RunTestWithBp(t, `
prebuilt_bootclasspath_fragment {
name: "unknown-bootclasspath-fragment",
image_name: "unknown",
+ contents: ["foo"],
}
`)
}
@@ -76,6 +66,7 @@
bootclasspath_fragment {
name: "bootclasspath-fragment",
image_name: "art",
+ contents: ["foo", "bar"],
apex_available: [
"apex",
],
@@ -94,6 +85,7 @@
bootclasspath_fragment {
name: "bootclasspath-fragment",
image_name: "art",
+ contents: ["foo", "bar"],
apex_available: [
"apex1",
"apex2",
@@ -102,17 +94,6 @@
`)
}
-func TestBootclasspathFragmentWithoutImageNameOrContents(t *testing.T) {
- prepareForTestWithBootclasspathFragment.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qneither of the "image_name" and "contents" properties\E`)).
- RunTestWithBp(t, `
- bootclasspath_fragment {
- name: "bootclasspath-fragment",
- }
- `)
-}
-
func TestBootclasspathFragment_Coverage(t *testing.T) {
prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{
"EMMA_INSTRUMENT": "true",
@@ -204,7 +185,7 @@
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("mysdklibrary", "mycoreplatform"),
+ FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
).RunTestWithBp(t, `
bootclasspath_fragment {
name: "myfragment",
@@ -212,7 +193,7 @@
api: {
stub_libs: [
"mystublib",
- "mysdklibrary",
+ "myothersdklibrary",
],
},
core_platform_api: {
@@ -231,36 +212,50 @@
java_sdk_library {
name: "mysdklibrary",
srcs: ["a.java"],
- compile_dex: true,
+ shared_library: false,
public: {enabled: true},
system: {enabled: true},
}
java_sdk_library {
+ name: "myothersdklibrary",
+ srcs: ["a.java"],
+ shared_library: false,
+ public: {enabled: true},
+ }
+
+ java_sdk_library {
name: "mycoreplatform",
srcs: ["a.java"],
- compile_dex: true,
+ shared_library: false,
public: {enabled: true},
}
`)
fragment := result.Module("myfragment", "android_common")
- info := result.ModuleProvider(fragment, bootclasspathApiInfoProvider).(bootclasspathApiInfo)
+ info := result.ModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
- // Check that SdkPublic uses public stubs.
+ // Stubs jars for mysdklibrary
publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar"
- android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{stubsJar, publicStubsJar}, info.stubJarsByKind[android.SdkPublic])
-
- // Check that SdkSystem uses system stubs.
systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.system/android_common/dex/mysdklibrary.stubs.system.jar"
- android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{stubsJar, systemStubsJar}, info.stubJarsByKind[android.SdkSystem])
- // Check that SdkTest also uses system stubs as the mysdklibrary does not provide test stubs.
- android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{stubsJar, systemStubsJar}, info.stubJarsByKind[android.SdkTest])
+ // Stubs jars for myothersdklibrary
+ otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs/android_common/dex/myothersdklibrary.stubs.jar"
+
+ // Check that SdkPublic uses public stubs for all sdk libraries.
+ android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkPublic])
+
+ // Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary
+ // as it does not provide system stubs.
+ android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkSystem])
+
+ // Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs
+ // and public stubs for myothersdklibrary as it does not provide test stubs either.
+ android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkTest])
// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
- android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.stubJarsByKind[android.SdkCorePlatform])
+ android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByKind[android.SdkCorePlatform])
}
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 2e05823..0e14d24 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -18,6 +18,7 @@
import (
"fmt"
+ "github.com/google/blueprint"
"strings"
"android/soong/android"
@@ -104,7 +105,7 @@
}
func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
- outputFilename := ctx.ModuleName() + ".pb"
+ outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
@@ -120,6 +121,12 @@
FlagWithOutput("--output=", c.outputFilepath)
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
+
+ classpathProtoInfo := ClasspathFragmentProtoContentInfo{
+ ClasspathFragmentProtoInstallDir: c.installDirPath,
+ ClasspathFragmentProtoOutput: c.outputFilepath,
+ }
+ ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
}
func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
@@ -129,7 +136,7 @@
for idx, jar := range jars {
fmt.Fprintf(&content, "{\n")
- fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path)
+ fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
if idx < len(jars)-1 {
@@ -143,6 +150,8 @@
android.WriteFileRule(ctx, output, content.String())
}
+// Returns AndroidMkEntries objects to install generated classpath.proto.
+// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes.
func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{{
Class: "ETC",
@@ -155,3 +164,23 @@
},
}}
}
+
+var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
+
+type ClasspathFragmentProtoContentInfo struct {
+ // ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
+ //
+ // The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
+ // for more details.
+ ClasspathFragmentProtoOutput android.OutputPath
+
+ // ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
+ //
+ // The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
+ // for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
+ // use android.InstallPath#Rel().
+ //
+ // This is only relevant for APEX modules as they perform their own installation; while regular
+ // system files are installed via ClasspathFragmentBase#androidMkEntries().
+ ClasspathFragmentProtoInstallDir android.InstallPath
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 8d23ad6..2e46d74 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -184,7 +184,7 @@
imagesDeps = append(imagesDeps, variant.imagesDeps)
}
// The image locations for all Android variants are identical.
- hostImageLocations := bootImage.getAnyAndroidVariant().imageLocations()
+ hostImageLocations, deviceImageLocations := bootImage.getAnyAndroidVariant().imageLocations()
var profileClassListing android.OptionalPath
var profileBootListing android.OptionalPath
@@ -224,9 +224,10 @@
ProvidesUsesLibrary: providesUsesLib,
ClassLoaderContexts: d.classLoaderContexts,
- Archs: archs,
- DexPreoptImagesDeps: imagesDeps,
- DexPreoptImageLocationsOnHost: hostImageLocations,
+ Archs: archs,
+ DexPreoptImagesDeps: imagesDeps,
+ DexPreoptImageLocationsOnHost: hostImageLocations,
+ DexPreoptImageLocationsOnDevice: deviceImageLocations,
PreoptBootClassPathDexFiles: dexFiles.Paths(),
PreoptBootClassPathDexLocations: dexLocations,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ce68c48..e1a3650 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -244,6 +244,9 @@
// Subdirectory where the image files are installed.
installDirOnHost string
+ // Subdirectory where the image files on device are installed.
+ installDirOnDevice string
+
// A list of (location, jar) pairs for the Java modules in this image.
modules android.ConfiguredJarList
@@ -273,8 +276,9 @@
dexLocationsDeps []string // for the dependency images and in this image
// Paths to image files.
- imagePathOnHost android.OutputPath // first image file
- imagesDeps android.OutputPaths // all files
+ imagePathOnHost android.OutputPath // first image file path on host
+ imagePathOnDevice string // first image file path on device
+ imagesDeps android.OutputPaths // all files
// Only for extensions, paths to the primary boot images.
primaryImages android.OutputPath
@@ -361,11 +365,12 @@
// The location is passed as an argument to the ART tools like dex2oat instead of the real path.
// ART tools will then reconstruct the architecture-specific real path.
//
-func (image *bootImageVariant) imageLocations() (imageLocations []string) {
+func (image *bootImageVariant) imageLocations() (imageLocationsOnHost []string, imageLocationsOnDevice []string) {
if image.extends != nil {
- imageLocations = image.extends.getVariant(image.target).imageLocations()
+ imageLocationsOnHost, imageLocationsOnDevice = image.extends.getVariant(image.target).imageLocations()
}
- return append(imageLocations, dexpreopt.PathToLocation(image.imagePathOnHost, image.target.Arch.ArchType))
+ return append(imageLocationsOnHost, dexpreopt.PathToLocation(image.imagePathOnHost, image.target.Arch.ArchType)),
+ append(imageLocationsOnDevice, dexpreopt.PathStringToLocation(image.imagePathOnDevice, image.target.Arch.ArchType))
}
func dexpreoptBootJarsFactory() android.SingletonModule {
@@ -427,17 +432,10 @@
return
}
- // Generate the profile rule from the default boot image.
defaultImageConfig := defaultBootImageConfig(ctx)
- profile := bootImageProfileRule(ctx, defaultImageConfig)
-
- // Create the default boot image.
- d.defaultBootImage = buildBootImage(ctx, defaultImageConfig, profile)
-
- // Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
- d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx), profile))
-
- copyUpdatableBootJars(ctx)
+ d.defaultBootImage = defaultImageConfig
+ artBootImageConfig := artBootImageConfig(ctx)
+ d.otherImages = []*bootImageConfig{artBootImageConfig}
}
// shouldBuildBootImages determines whether boot images should be built.
@@ -452,77 +450,19 @@
return true
}
-// A copy of isModuleInConfiguredList created to work with singleton context.
-//
-// TODO(b/177892522): Remove this.
-func isModuleInConfiguredListForSingleton(ctx android.SingletonContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool {
- name := ctx.ModuleName(module)
-
- // Strip a prebuilt_ prefix so that this can match a prebuilt module that has not been renamed.
- name = android.RemoveOptionalPrebuiltPrefix(name)
-
- // Ignore any module that is not listed in the boot image configuration.
- index := configuredBootJars.IndexOfJar(name)
- if index == -1 {
- return false
- }
-
- // It is an error if the module is not an ApexModule.
- if _, ok := module.(android.ApexModule); !ok {
- ctx.Errorf("%s is configured in boot jars but does not support being added to an apex", ctx.ModuleName(module))
- return false
- }
-
- apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
-
- // Now match the apex part of the boot image configuration.
- requiredApex := configuredBootJars.Apex(index)
- if requiredApex == "platform" || requiredApex == "system_ext" {
- if len(apexInfo.InApexes) != 0 {
- // A platform variant is required but this is for an apex so ignore it.
- return false
- }
- } else if !apexInfo.InApexByBaseName(requiredApex) {
- // An apex variant for a specific apex is required but this is the wrong apex.
- return false
- }
-
- return true
-}
-
-// findBootJarModules finds the boot jar module variants specified in the bootjars parameter.
-//
-// It returns a list of modules such that the module at index i corresponds to the configured jar
-// at index i.
-func findBootJarModules(ctx android.SingletonContext, bootjars android.ConfiguredJarList) []android.Module {
- modules := make([]android.Module, bootjars.Len())
-
- // This logic is tested in the apex package to avoid import cycle apex <-> java.
- ctx.VisitAllModules(func(module android.Module) {
- if !isActiveModule(module) || !isModuleInConfiguredListForSingleton(ctx, module, bootjars) {
- return
- }
-
- name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
- index := bootjars.IndexOfJar(name)
- if existing := modules[index]; existing != nil {
- ctx.Errorf("Multiple boot jar modules found for %s:%s - %q and %q",
- bootjars.Apex(index), bootjars.Jar(index), existing, module)
- return
- }
- modules[index] = module
- })
- return modules
-}
-
// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to
// predefined paths in the global config.
-func copyBootJarsToPredefinedLocations(ctx android.SingletonContext, bootModules []android.Module, bootjars android.ConfiguredJarList, jarPathsPredefined android.WritablePaths) {
+func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, bootModules []android.Module, bootjars android.ConfiguredJarList, jarPathsPredefined android.WritablePaths) {
jarPaths := make(android.Paths, bootjars.Len())
for i, module := range bootModules {
if module != nil {
bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
jarPaths[i] = bootDexJar
+
+ name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(module))
+ if bootjars.Jar(i) != name {
+ ctx.ModuleErrorf("expected module %s at position %d but found %s", bootjars.Jar(i), i, name)
+ }
}
}
@@ -548,7 +488,7 @@
},
})
} else {
- ctx.Errorf("failed to find a dex jar path for module '%s'"+
+ ctx.ModuleErrorf("failed to find a dex jar path for module '%s'"+
", note that some jars may be filtered out by module constraints", module)
}
@@ -563,10 +503,7 @@
}
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
-func buildBootImage(ctx android.SingletonContext, image *bootImageConfig, profile android.WritablePath) *bootImageConfig {
- bootModules := findBootJarModules(ctx, image.modules)
- copyBootJarsToPredefinedLocations(ctx, bootModules, image.modules, image.dexPaths)
-
+func buildBootImage(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) {
var zipFiles android.Paths
for _, variant := range image.variants {
files := buildBootImageVariant(ctx, variant, profile)
@@ -585,19 +522,10 @@
rule.Build("zip_"+image.name, "zip "+image.name+" image")
}
-
- return image
-}
-
-// Generate commands that will copy updatable boot jars to predefined paths in the global config.
-func copyUpdatableBootJars(ctx android.SingletonContext) {
- config := GetUpdatableBootConfig(ctx)
- bootModules := findBootJarModules(ctx, config.modules)
- copyBootJarsToPredefinedLocations(ctx, bootModules, config.modules, config.dexPaths)
}
// Generate boot image build rules for a specific target.
-func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant, profile android.Path) android.WritablePaths {
+func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) android.WritablePaths {
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
@@ -747,7 +675,7 @@
It is likely that the boot classpath is inconsistent.
Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
-func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig) android.WritablePath {
+func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
@@ -838,7 +766,7 @@
if len(pp) > 0 {
updatablePackages = append(updatablePackages, pp...)
} else {
- ctx.ModuleErrorf("Missing permitted_packages")
+ ctx.OtherModuleErrorf(module, "Missing permitted_packages")
}
}
}
@@ -873,12 +801,12 @@
// Create a rule to call oatdump.
output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
rule := android.NewRuleBuilder(pctx, ctx)
+ imageLocationsOnHost, _ := image.imageLocations()
rule.Command().
- // TODO: for now, use the debug version for better error reporting
- BuiltTool("oatdumpd").
+ BuiltTool("oatdump").
FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
- FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()).
+ FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
rule.Build("dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
@@ -948,8 +876,8 @@
ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
}
- imageLocations := current.getAnyAndroidVariant().imageLocations()
- ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":"))
+ imageLocationsOnHost, _ := current.getAnyAndroidVariant().imageLocations()
+ ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocationsOnHost, ":"))
ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
}
ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 73f21d1..bc7a55e 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -20,7 +20,6 @@
"testing"
"android/soong/android"
- "android/soong/dexpreopt"
)
func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOutputs []string) {
@@ -42,17 +41,21 @@
name: "baz",
jars: ["a.jar"],
}
+
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ }
`
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("foo"),
- dexpreopt.FixtureSetBootJars("platform:foo", "system_ext:bar", "platform:baz"),
+ FixtureConfigureBootJars("platform:foo", "system_ext:bar", "platform:baz"),
).RunTestWithBp(t, bp)
- dexpreoptBootJars := result.SingletonForTests("dex_bootjars")
- rule := dexpreoptBootJars.Output(ruleFile)
+ platformBootclasspath := result.ModuleForTests("platform-bootclasspath", "android_common")
+ rule := platformBootclasspath.Output(ruleFile)
for i := range expectedInputs {
expectedInputs[i] = filepath.Join("out/soong/test_device", expectedInputs[i])
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 7fb0444..39a3e11 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,7 +15,6 @@
package java
import (
- "fmt"
"path/filepath"
"strings"
@@ -23,32 +22,6 @@
"android/soong/dexpreopt"
)
-// systemServerClasspath returns the on-device locations of the modules in the system server classpath. It is computed
-// once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
-// ctx.Config().
-func systemServerClasspath(ctx android.PathContext) []string {
- return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
- global := dexpreopt.GetGlobalConfig(ctx)
- var systemServerClasspathLocations []string
- nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global)
- // 1) Non-updatable jars.
- for _, m := range nonUpdatable {
- systemServerClasspathLocations = append(systemServerClasspathLocations,
- filepath.Join("/system/framework", m+".jar"))
- }
- // 2) The jars that are from an updatable apex.
- systemServerClasspathLocations = append(systemServerClasspathLocations,
- global.UpdatableSystemServerJars.DevicePaths(ctx.Config(), android.Android)...)
-
- if expectedLen := global.SystemServerJars.Len() + global.UpdatableSystemServerJars.Len(); expectedLen != len(systemServerClasspathLocations) {
- panic(fmt.Errorf("wrong number of system server jars, got %d, expected %d", len(systemServerClasspathLocations), expectedLen))
- }
- return systemServerClasspathLocations
- })
-}
-
-var systemServerClasspathKey = android.NewOnceKey("systemServerClasspath")
-
// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
// supported through native bridge.
func dexpreoptTargets(ctx android.PathContext) []android.Target {
@@ -84,25 +57,28 @@
frameworkModules := global.BootJars.RemoveList(artModules)
artDirOnHost := "apex/art_boot_images/javalib"
+ artDirOnDevice := "apex/com.android.art/javalib"
frameworkSubdir := "system/framework"
// ART config for the primary boot image in the ART apex.
// It includes the Core Libraries.
artCfg := bootImageConfig{
- name: artBootImageName,
- stem: "boot",
- installDirOnHost: artDirOnHost,
- modules: artModules,
+ name: artBootImageName,
+ stem: "boot",
+ installDirOnHost: artDirOnHost,
+ installDirOnDevice: artDirOnDevice,
+ modules: artModules,
}
// Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config.
frameworkCfg := bootImageConfig{
- extends: &artCfg,
- name: frameworkBootImageName,
- stem: "boot",
- installDirOnHost: frameworkSubdir,
- modules: frameworkModules,
+ extends: &artCfg,
+ name: frameworkBootImageName,
+ stem: "boot",
+ installDirOnHost: frameworkSubdir,
+ installDirOnDevice: frameworkSubdir,
+ modules: frameworkModules,
}
configs := map[string]*bootImageConfig{
@@ -131,11 +107,12 @@
arch := target.Arch.ArchType
imageDir := c.dir.Join(ctx, target.Os.String(), c.installDirOnHost, arch.String())
variant := &bootImageVariant{
- bootImageConfig: c,
- target: target,
- imagePathOnHost: imageDir.Join(ctx, imageName),
- imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
- dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os),
+ bootImageConfig: c,
+ target: target,
+ imagePathOnHost: imageDir.Join(ctx, imageName),
+ imagePathOnDevice: filepath.Join("/", c.installDirOnDevice, arch.String(), imageName),
+ imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
+ dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os),
}
variant.dexLocationsDeps = variant.dexLocations
c.variants = append(c.variants, variant)
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index a9e0773..b25dece 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -15,7 +15,12 @@
package java
import (
+ "fmt"
"testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/dexpreopt"
)
func TestDexpreoptEnabled(t *testing.T) {
@@ -166,3 +171,51 @@
return "disabled"
}
}
+
+func TestDex2oatToolDeps(t *testing.T) {
+ if android.BuildOs != android.Linux {
+ // The host binary paths checked below are build OS dependent.
+ t.Skipf("Unsupported build OS %s", android.BuildOs)
+ }
+
+ preparers := android.GroupFixturePreparers(
+ cc.PrepareForTestWithCcDefaultModules,
+ PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd,
+ dexpreopt.PrepareForTestByEnablingDexpreopt)
+
+ testDex2oatToolDep := func(sourceEnabled, prebuiltEnabled, prebuiltPreferred bool,
+ expectedDex2oatPath string) {
+ name := fmt.Sprintf("sourceEnabled:%t,prebuiltEnabled:%t,prebuiltPreferred:%t",
+ sourceEnabled, prebuiltEnabled, prebuiltPreferred)
+ t.Run(name, func(t *testing.T) {
+ result := preparers.RunTestWithBp(t, fmt.Sprintf(`
+ cc_binary {
+ name: "dex2oatd",
+ enabled: %t,
+ host_supported: true,
+ }
+ cc_prebuilt_binary {
+ name: "dex2oatd",
+ enabled: %t,
+ prefer: %t,
+ host_supported: true,
+ srcs: ["x86_64/bin/dex2oatd"],
+ }
+ java_library {
+ name: "myjavalib",
+ }
+ `, sourceEnabled, prebuiltEnabled, prebuiltPreferred))
+ pathContext := android.PathContextForTesting(result.Config)
+ dex2oatPath := dexpreopt.GetCachedGlobalSoongConfig(pathContext).Dex2oat
+ android.AssertStringEquals(t, "Testing "+name, expectedDex2oatPath, android.NormalizePathForTesting(dex2oatPath))
+ })
+ }
+
+ sourceDex2oatPath := "host/linux-x86/bin/dex2oatd"
+ prebuiltDex2oatPath := ".intermediates/prebuilt_dex2oatd/linux_glibc_x86_64/dex2oatd"
+
+ testDex2oatToolDep(true, false, false, sourceDex2oatPath)
+ testDex2oatToolDep(true, true, false, sourceDex2oatPath)
+ testDex2oatToolDep(true, true, true, prebuiltDex2oatPath)
+ testDex2oatToolDep(false, true, false, prebuiltDex2oatPath)
+}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 566f7e3..17c7a7b 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -51,7 +51,6 @@
lastReleasedApiXmlFile android.WritablePath
privateApiFile android.WritablePath
removedApiFile android.WritablePath
- removedDexApiFile android.WritablePath
nullabilityWarningsFile android.WritablePath
checkCurrentApiTimestamp android.WritablePath
@@ -79,9 +78,6 @@
// the generated removed API filename by Metalava, defaults to <module>_removed.txt
Removed_api_filename *string
- // the generated removed Dex API filename by Metalava.
- Removed_dex_api_filename *string
-
Check_api struct {
Last_released ApiToCheck
@@ -274,11 +270,6 @@
d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
}
- if String(d.properties.Removed_dex_api_filename) != "" {
- d.removedDexApiFile = android.PathForModuleOut(ctx, "metalava", String(d.properties.Removed_dex_api_filename))
- cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile)
- }
-
if Bool(d.properties.Write_sdk_values) {
d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
@@ -546,7 +537,8 @@
`\n` +
`If it is not possible to do so, there are workarounds:\n` +
`\n` +
- `1. You can suppress the errors with @SuppressLint("<id>")\n`
+ `1. You can suppress the errors with @SuppressLint("<id>")\n` +
+ ` where the <id> is given in brackets in the error message above.\n`
if baselineFile.Valid() {
cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index a34044f..e9693c6 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -26,27 +26,10 @@
}, "outFlag", "stubAPIFlags")
type hiddenAPI struct {
- // The name of the module as it would be used in the boot jars configuration, e.g. without any
- // prebuilt_ prefix (if it is a prebuilt) and without any ".impl" suffix if it is a
- // java_sdk_library implementation library.
- configurationName string
-
// True if the module containing this structure contributes to the hiddenapi information or has
// that information encoded within it.
active bool
- // Identifies the active module variant which will be used as the source of hiddenapi information.
- //
- // A class may be compiled into a number of different module variants each of which will need the
- // hiddenapi information encoded into it and so will be marked as active. However, only one of
- // them must be used as a source of information by hiddenapi otherwise it will end up with
- // duplicate entries. That module will have primary=true.
- //
- // Note, that modules <x>-hiddenapi that provide additional annotation information for module <x>
- // that is on the bootclasspath are marked as primary=true as they are the primary source of that
- // annotation information.
- primary bool
-
// The path to the dex jar that is in the boot class path. If this is nil then the associated
// module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional
// annotations for the <x> boot dex jar but which do not actually provide a boot dex jar
@@ -56,130 +39,82 @@
// this file so using the encoded dex jar here would result in a cycle in the ninja rules.
bootDexJarPath android.Path
- // The path to the CSV file that contains mappings from Java signature to various flags derived
- // from annotations in the source, e.g. whether it is public or the sdk version above which it
- // can no longer be used.
- //
- // It is created by the Class2NonSdkList tool which processes the .class files in the class
- // implementation jar looking for UnsupportedAppUsage and CovariantReturnType annotations. The
- // tool also consumes the hiddenAPISingletonPathsStruct.stubFlags file in order to perform
- // consistency checks on the information in the annotations and to filter out bridge methods
- // that are already part of the public API.
- flagsCSVPath android.Path
-
- // The path to the CSV file that contains mappings from Java signature to the value of properties
- // specified on UnsupportedAppUsage annotations in the source.
- //
- // Like the flagsCSVPath file this is also created by the Class2NonSdkList in the same way.
- // Although the two files could potentially be created in a single invocation of the
- // Class2NonSdkList at the moment they are created using their own invocation, with the behavior
- // being determined by the property that is used.
- metadataCSVPath android.Path
-
- // The path to the CSV file that contains mappings from Java signature to source location
- // information.
- //
- // It is created by the merge_csv tool which processes the class implementation jar, extracting
- // all the files ending in .uau (which are CSV files) and merges them together. The .uau files are
- // created by the unsupported app usage annotation processor during compilation of the class
- // implementation jar.
- indexCSVPath android.Path
-
// The paths to the classes jars that contain classes and class members annotated with
// the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API
// processing.
classesJarPaths android.Paths
-}
-func (h *hiddenAPI) flagsCSV() android.Path {
- return h.flagsCSVPath
-}
-
-func (h *hiddenAPI) metadataCSV() android.Path {
- return h.metadataCSVPath
+ // The compressed state of the dex file being encoded. This is used to ensure that the encoded
+ // dex file has the same state.
+ uncompressDexState *bool
}
func (h *hiddenAPI) bootDexJar() android.Path {
return h.bootDexJarPath
}
-func (h *hiddenAPI) indexCSV() android.Path {
- return h.indexCSVPath
-}
-
func (h *hiddenAPI) classesJars() android.Paths {
return h.classesJarPaths
}
+func (h *hiddenAPI) uncompressDex() *bool {
+ return h.uncompressDexState
+}
+
+// hiddenAPIModule is the interface a module that embeds the hiddenAPI structure must implement.
+type hiddenAPIModule interface {
+ android.Module
+ hiddenAPIIntf
+}
+
type hiddenAPIIntf interface {
bootDexJar() android.Path
- flagsCSV() android.Path
- indexCSV() android.Path
- metadataCSV() android.Path
classesJars() android.Paths
+ uncompressDex() *bool
}
var _ hiddenAPIIntf = (*hiddenAPI)(nil)
// Initialize the hiddenapi structure
-func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationName string) {
+//
+// uncompressedDexState should be nil when the module is a prebuilt and so does not require hidden
+// API encoding.
+func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar, classesJar android.Path, uncompressedDexState *bool) {
+
+ // Save the classes jars even if this is not active as they may be used by modular hidden API
+ // processing.
+ classesJars := android.Paths{classesJar}
+ ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
+ javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+ classesJars = append(classesJars, javaInfo.ImplementationJars...)
+ })
+ h.classesJarPaths = classesJars
+
+ // Save the unencoded dex jar so it can be used when generating the
+ // hiddenAPISingletonPathsStruct.stubFlags file.
+ h.bootDexJarPath = dexJar
+
+ h.uncompressDexState = uncompressedDexState
+
// If hiddenapi processing is disabled treat this as inactive.
if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
return
}
- h.configurationName = configurationName
+ // The context module must implement hiddenAPIModule.
+ module := ctx.Module().(hiddenAPIModule)
+
+ // If the frameworks/base directories does not exist and no prebuilt hidden API flag files have
+ // been configured then it is not possible to do hidden API encoding.
+ if !ctx.Config().FrameworksBaseDirExists(ctx) && ctx.Config().PrebuiltHiddenApiDir(ctx) == "" {
+ return
+ }
// It is important that hiddenapi information is only gathered for/from modules that are actually
// on the boot jars list because the runtime only enforces access to the hidden API for the
// bootclassloader. If information is gathered for modules not on the list then that will cause
// failures in the CtsHiddenApiBlocklist... tests.
- module := ctx.Module()
h.active = isModuleInBootClassPath(ctx, module)
- if !h.active {
- // The rest of the properties will be ignored if active is false.
- return
- }
-
- // Determine whether this module is the primary module or not.
- primary := true
-
- // A prebuilt module is only primary if it is preferred and conversely a source module is only
- // primary if it has not been replaced by a prebuilt module.
- if pi, ok := module.(android.PrebuiltInterface); ok {
- if p := pi.Prebuilt(); p != nil {
- primary = p.UsePrebuilt()
- }
- } else {
- // The only module that will pass a different configurationName to its module name to this
- // method is the implementation library of a java_sdk_library. It has a configuration name of
- // <x> the same as its parent java_sdk_library but a module name of <x>.impl. It is not the
- // primary module, the java_sdk_library with the name of <x> is.
- primary = configurationName == ctx.ModuleName()
-
- // A source module that has been replaced by a prebuilt can never be the primary module.
- if module.IsReplacedByPrebuilt() {
- if ctx.HasProvider(android.ApexInfoProvider) {
- // The source module is in an APEX but the prebuilt module on which it depends is not in an
- // APEX and so is not the one that will actually be used for hidden API processing. That
- // means it is not possible to check to see if it is a suitable replacement so just assume
- // that it is.
- primary = false
- } else {
- ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(prebuilt android.Module) {
- if h, ok := prebuilt.(hiddenAPIIntf); ok && h.bootDexJar() != nil {
- primary = false
- } else {
- ctx.ModuleErrorf(
- "hiddenapi has determined that the source module %q should be ignored as it has been"+
- " replaced by the prebuilt module %q but unfortunately it does not provide a"+
- " suitable boot dex jar", ctx.ModuleName(), ctx.OtherModuleName(prebuilt))
- }
- })
- }
- }
- }
- h.primary = primary
}
func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool {
@@ -191,84 +126,74 @@
return active
}
-// hiddenAPIExtractAndEncode is called by any module that could contribute to the hiddenapi
-// processing.
+// hiddenAPIEncodeDex is called by any module that needs to encode dex files.
//
// It ignores any module that has not had initHiddenApi() called on it and which is not in the boot
-// jar list.
+// jar list. In that case it simply returns the supplied dex jar path.
//
-// Otherwise, it generates ninja rules to do the following:
-// 1. Extract information needed for hiddenapi processing from the module and output it into CSV
-// files.
-// 2. Conditionally adds the supplied dex file to the list of files used to generate the
-// hiddenAPISingletonPathsStruct.stubsFlag file.
-// 3. Conditionally creates a copy of the supplied dex file into which it has encoded the hiddenapi
-// flags and returns this instead of the supplied dex jar, otherwise simply returns the supplied
-// dex jar.
-func (h *hiddenAPI) hiddenAPIExtractAndEncode(ctx android.ModuleContext, dexJar android.OutputPath,
- implementationJar android.Path, uncompressDex bool) android.OutputPath {
+// Otherwise, it creates a copy of the supplied dex file into which it has encoded the hiddenapi
+// flags and returns this instead of the supplied dex jar.
+func (h *hiddenAPI) hiddenAPIEncodeDex(ctx android.ModuleContext, dexJar android.OutputPath) android.OutputPath {
if !h.active {
return dexJar
}
- h.hiddenAPIExtractInformation(ctx, dexJar, implementationJar)
-
- hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", h.configurationName+".jar").OutputPath
+ // A nil uncompressDexState prevents the dex file from being encoded.
+ if h.uncompressDexState == nil {
+ ctx.ModuleErrorf("cannot encode dex file %s when uncompressDexState is nil", dexJar)
+ }
+ uncompressDex := *h.uncompressDexState
// Create a copy of the dex jar which has been encoded with hiddenapi flags.
- hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
+ flagsCSV := hiddenAPISingletonPaths(ctx).flags
+ outputDir := android.PathForModuleOut(ctx, "hiddenapi").OutputPath
+ encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, outputDir)
// Use the encoded dex jar from here onwards.
- dexJar = hiddenAPIJar
-
- return dexJar
+ return encodedDex
}
-// hiddenAPIExtractInformation generates ninja rules to extract the information from the classes
-// jar, and outputs it to the appropriate module specific CSV file.
+// buildRuleToGenerateAnnotationFlags builds a ninja rule to generate the annotation-flags.csv file
+// from the classes jars and stub-flags.csv files.
//
-// It also makes the dex jar available for use when generating the
-// hiddenAPISingletonPathsStruct.stubFlags.
-func (h *hiddenAPI) hiddenAPIExtractInformation(ctx android.ModuleContext, dexJar, classesJar android.Path) {
- if !h.active {
- return
- }
-
- // More than one library with the same classes may need to be encoded but only one should be
- // used as a source of information for hidden API processing otherwise it will result in
- // duplicate entries in the files.
- if !h.primary {
- return
- }
-
- classesJars := android.Paths{classesJar}
- ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
- javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
- classesJars = append(classesJars, javaInfo.ImplementationJars...)
- })
- h.classesJarPaths = classesJars
-
- stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
-
- flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
+// The annotation-flags.csv file contains mappings from Java signature to various flags derived from
+// annotations in the source, e.g. whether it is public or the sdk version above which it can no
+// longer be used.
+//
+// It is created by the Class2NonSdkList tool which processes the .class files in the class
+// implementation jar looking for UnsupportedAppUsage and CovariantReturnType annotations. The
+// tool also consumes the hiddenAPISingletonPathsStruct.stubFlags file in order to perform
+// consistency checks on the information in the annotations and to filter out bridge methods
+// that are already part of the public API.
+func buildRuleToGenerateAnnotationFlags(ctx android.ModuleContext, desc string, classesJars android.Paths, stubFlagsCSV android.Path, outputPath android.WritablePath) {
ctx.Build(pctx, android.BuildParams{
Rule: hiddenAPIGenerateCSVRule,
- Description: "hiddenapi flags",
+ Description: desc,
Inputs: classesJars,
- Output: flagsCSV,
+ Output: outputPath,
Implicit: stubFlagsCSV,
Args: map[string]string{
"outFlag": "--write-flags-csv",
"stubAPIFlags": stubFlagsCSV.String(),
},
})
- h.flagsCSVPath = flagsCSV
+}
- metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
+// buildRuleToGenerateMetadata builds a ninja rule to generate the metadata.csv file from
+// the classes jars and stub-flags.csv files.
+//
+// The metadata.csv file contains mappings from Java signature to the value of properties specified
+// on UnsupportedAppUsage annotations in the source.
+//
+// Like the annotation-flags.csv file this is also created by the Class2NonSdkList in the same way.
+// Although the two files could potentially be created in a single invocation of the
+// Class2NonSdkList at the moment they are created using their own invocation, with the behavior
+// being determined by the property that is used.
+func buildRuleToGenerateMetadata(ctx android.ModuleContext, desc string, classesJars android.Paths, stubFlagsCSV android.Path, metadataCSV android.WritablePath) {
ctx.Build(pctx, android.BuildParams{
Rule: hiddenAPIGenerateCSVRule,
- Description: "hiddenapi metadata",
+ Description: desc,
Inputs: classesJars,
Output: metadataCSV,
Implicit: stubFlagsCSV,
@@ -277,22 +202,27 @@
"stubAPIFlags": stubFlagsCSV.String(),
},
})
- h.metadataCSVPath = metadataCSV
+}
- indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv")
+// buildRuleToGenerateIndex builds a ninja rule to generate the index.csv file from the classes
+// jars.
+//
+// The index.csv file contains mappings from Java signature to source location information.
+//
+// It is created by the merge_csv tool which processes the class implementation jar, extracting
+// all the files ending in .uau (which are CSV files) and merges them together. The .uau files are
+// created by the unsupported app usage annotation processor during compilation of the class
+// implementation jar.
+func buildRuleToGenerateIndex(ctx android.ModuleContext, desc string, classesJars android.Paths, indexCSV android.WritablePath) {
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
BuiltTool("merge_csv").
Flag("--zip_input").
Flag("--key_field signature").
+ FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
FlagWithOutput("--output=", indexCSV).
Inputs(classesJars)
- rule.Build("merged-hiddenapi-index", "Merged Hidden API index")
- h.indexCSVPath = indexCSV
-
- // Save the unencoded dex jar so it can be used when generating the
- // hiddenAPISingletonPathsStruct.stubFlags file.
- h.bootDexJarPath = dexJar
+ rule.Build(desc, desc)
}
var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
@@ -303,7 +233,7 @@
echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})";
done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags &&
${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" &&
- ${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
+ ${config.MergeZipsCmd} -j -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
CommandDeps: []string{
"${config.HiddenAPI}",
"${config.SoongZipCmd}",
@@ -311,39 +241,37 @@
},
}, "flagsCsv", "hiddenapiFlags", "tmpDir", "soongZipFlags")
-func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, dexInput android.Path,
- uncompressDex bool) {
+// hiddenAPIEncodeDex generates the build rule that will encode the supplied dex jar and place the
+// encoded dex jar in a file of the same name in the output directory.
+//
+// The encode dex rule requires unzipping, encoding and rezipping the classes.dex files along with
+// all the resources from the input jar. It also ensures that if it was uncompressed in the input
+// it stays uncompressed in the output.
+func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, outputDir android.OutputPath) android.OutputPath {
- flagsCSV := hiddenAPISingletonPaths(ctx).flags
+ // The output file has the same name as the input file and is in the output directory.
+ output := outputDir.Join(ctx, dexInput.Base())
- // The encode dex rule requires unzipping and rezipping the classes.dex files, ensure that if it was uncompressed
- // in the input it stays uncompressed in the output.
+ // Create a jar specific temporary directory in which to do the work just in case this is called
+ // with the same output directory for multiple modules.
+ tmpDir := outputDir.Join(ctx, dexInput.Base()+"-tmp")
+
+ // If the input is uncompressed then generate the output of the encode rule to an intermediate
+ // file as the final output will need further processing after encoding.
soongZipFlags := ""
- hiddenapiFlags := ""
- tmpOutput := output
- tmpDir := android.PathForModuleOut(ctx, "hiddenapi", "dex")
+ encodeRuleOutput := output
if uncompressDex {
soongZipFlags = "-L 0"
- tmpOutput = android.PathForModuleOut(ctx, "hiddenapi", "unaligned", "unaligned.jar")
- tmpDir = android.PathForModuleOut(ctx, "hiddenapi", "unaligned")
+ encodeRuleOutput = outputDir.Join(ctx, "unaligned", dexInput.Base())
}
- enforceHiddenApiFlagsToAllMembers := true
- // If frameworks/base doesn't exist we must be building with the 'master-art' manifest.
- // Disable assertion that all methods/fields have hidden API flags assigned.
- if !ctx.Config().FrameworksBaseDirExists(ctx) {
- enforceHiddenApiFlagsToAllMembers = false
- }
// b/149353192: when a module is instrumented, jacoco adds synthetic members
// $jacocoData and $jacocoInit. Since they don't exist when building the hidden API flags,
// don't complain when we don't find hidden API flags for the synthetic members.
+ hiddenapiFlags := ""
if j, ok := ctx.Module().(interface {
shouldInstrument(android.BaseModuleContext) bool
}); ok && j.shouldInstrument(ctx) {
- enforceHiddenApiFlagsToAllMembers = false
- }
-
- if !enforceHiddenApiFlagsToAllMembers {
hiddenapiFlags = "--no-force-assign-all"
}
@@ -351,7 +279,7 @@
Rule: hiddenAPIEncodeDexRule,
Description: "hiddenapi encode dex",
Input: dexInput,
- Output: tmpOutput,
+ Output: encodeRuleOutput,
Implicit: flagsCSV,
Args: map[string]string{
"flagsCsv": flagsCSV.String(),
@@ -362,8 +290,10 @@
})
if uncompressDex {
- TransformZipAlign(ctx, output, tmpOutput)
+ TransformZipAlign(ctx, output, encodeRuleOutput)
}
+
+ return output
}
type hiddenApiAnnotationsDependencyTag struct {
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 335f5b8..f2649d3 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -15,8 +15,12 @@
package java
import (
+ "fmt"
+ "strings"
+
"android/soong/android"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// Contains support for processing hiddenAPI in a modular fashion.
@@ -63,6 +67,12 @@
// hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
// API processing.
+//
+// These are in order from narrowest API surface to widest. Widest means the API stubs with the
+// biggest API surface, e.g. test is wider than system is wider than public. Core platform is
+// considered wider than test even though it has no relationship with test because the libraries
+// that provide core platform API don't provide test. While the core platform API is being converted
+// to a system API the system API is still a subset of core platform.
var hiddenAPIRelevantSdkKinds = []android.SdkKind{
android.SdkPublic,
android.SdkSystem,
@@ -97,7 +107,12 @@
systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...)
testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...)
if config.IsEnvTrue("EMMA_INSTRUMENT") {
+ // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
+ // allows everyone access but it is needed to ensure consistent flags between the
+ // bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
publicStubModules = append(publicStubModules, "jacoco-stubs")
+ systemStubModules = append(systemStubModules, "jacoco-stubs")
+ testStubModules = append(testStubModules, "jacoco-stubs")
}
m := map[android.SdkKind][]string{}
@@ -119,23 +134,6 @@
}
}
-// hiddenAPIGatherStubLibDexJarPaths gathers the paths to the dex jars from the dependencies added
-// in hiddenAPIAddStubLibDependencies.
-func hiddenAPIGatherStubLibDexJarPaths(ctx android.ModuleContext) map[android.SdkKind]android.Paths {
- m := map[android.SdkKind]android.Paths{}
- ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
- tag := ctx.OtherModuleDependencyTag(module)
- if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
- kind := hiddenAPIStubsTag.sdkKind
- dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
- if dexJar != nil {
- m[kind] = append(m[kind], dexJar)
- }
- }
- })
- return m
-}
-
// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
// available, or reports an error.
func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
@@ -166,20 +164,36 @@
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
-func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.OutputPath, bootDexJars android.Paths, sdkKindToPathList map[android.SdkKind]android.Paths) *android.RuleBuilder {
+func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder {
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android.NewRuleBuilder(pctx, ctx)
tempPath := tempPathForRestat(ctx, outputPath)
+ // Find the widest API stubs provided by the fragments on which this depends, if any.
+ var dependencyStubDexJars android.Paths
+ for i := len(hiddenAPIRelevantSdkKinds) - 1; i >= 0; i-- {
+ kind := hiddenAPIRelevantSdkKinds[i]
+ stubsForKind := input.DependencyStubDexJarsByKind[kind]
+ if len(stubsForKind) != 0 {
+ dependencyStubDexJars = stubsForKind
+ break
+ }
+ }
+
command := rule.Command().
Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
Text("list").
+ FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
FlagForEachInput("--boot-dex=", bootDexJars)
// Iterate over the sdk kinds in a fixed order.
for _, sdkKind := range hiddenAPIRelevantSdkKinds {
- paths := sdkKindToPathList[sdkKind]
+ // Merge in the stub dex jar paths for this kind from the fragments on which it depends. They
+ // will be needed to resolve dependencies from this fragment's stubs to classes in the other
+ // fragment's APIs.
+ dependencyPaths := input.DependencyStubDexJarsByKind[sdkKind]
+ paths := append(dependencyPaths, input.StubDexJarsByKind[sdkKind]...)
if len(paths) > 0 {
option := sdkKindToHiddenapiListOption[sdkKind]
command.FlagWithInputList("--"+option+"=", paths, ":")
@@ -233,15 +247,6 @@
Unsupported_packages []string `android:"path"`
}
-func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo {
- info := hiddenAPIFlagFileInfo{categoryToPaths: map[*hiddenAPIFlagFileCategory]android.Paths{}}
- for _, category := range hiddenAPIFlagFileCategories {
- paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
- info.categoryToPaths[category] = paths
- }
- return info
-}
-
type hiddenAPIFlagFileCategory struct {
// propertyName is the name of the property for this category.
propertyName string
@@ -255,6 +260,22 @@
commandMutator func(command *android.RuleBuilderCommand, path android.Path)
}
+// The flag file category for removed members of the API.
+//
+// This is extracted from hiddenAPIFlagFileCategories as it is needed to add the dex signatures
+// list of removed API members that are generated automatically from the removed.txt files provided
+// by API stubs.
+var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
+ // See HiddenAPIFlagFileProperties.Removed
+ propertyName: "removed",
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Removed
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+ },
+}
+
var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
// See HiddenAPIFlagFileProperties.Unsupported
{
@@ -266,16 +287,7 @@
command.FlagWithInput("--unsupported ", path)
},
},
- // See HiddenAPIFlagFileProperties.Removed
- {
- propertyName: "removed",
- propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
- return properties.Removed
- },
- commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
- command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
- },
- },
+ hiddenAPIRemovedFlagFileCategory,
// See HiddenAPIFlagFileProperties.Max_target_r_low_priority
{
propertyName: "max_target_r_low_priority",
@@ -338,63 +350,445 @@
},
}
-// hiddenAPIFlagFileInfo contains paths resolved from HiddenAPIFlagFileProperties
-type hiddenAPIFlagFileInfo struct {
- // categoryToPaths maps from the flag file category to the paths containing information for that
- // category.
- categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths
-}
+// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
+type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
-func (i *hiddenAPIFlagFileInfo) append(other hiddenAPIFlagFileInfo) {
+// append appends the supplied flags files to the corresponding category in this map.
+func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
for _, category := range hiddenAPIFlagFileCategories {
- i.categoryToPaths[category] = append(i.categoryToPaths[category], other.categoryToPaths[category]...)
+ s[category] = append(s[category], other[category]...)
}
}
-var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{})
+// dedup removes duplicates in the flag files, while maintaining the order in which they were
+// appended.
+func (s FlagFilesByCategory) dedup() {
+ for category, paths := range s {
+ s[category] = android.FirstUniquePaths(paths)
+ }
+}
-// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
-// flags from all the modules, the stub flags, augmented with some additional configuration files.
+// HiddenAPIInfo contains information provided by the hidden API processing.
+//
+// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
+// processing.
+type HiddenAPIInfo struct {
+ // FlagFilesByCategory maps from the flag file category to the paths containing information for
+ // that category.
+ FlagFilesByCategory FlagFilesByCategory
+
+ // The paths to the stub dex jars for each of the android.SdkKind in hiddenAPIRelevantSdkKinds.
+ TransitiveStubDexJarsByKind StubDexJarsByKind
+
+ // The output from the hidden API processing needs to be made available to other modules.
+ HiddenAPIFlagOutput
+}
+
+func newHiddenAPIInfo() *HiddenAPIInfo {
+ info := HiddenAPIInfo{
+ FlagFilesByCategory: FlagFilesByCategory{},
+ TransitiveStubDexJarsByKind: StubDexJarsByKind{},
+ }
+ return &info
+}
+
+func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
+ // Merge all the information from the fragments. The fragments form a DAG so it is possible that
+ // this will introduce duplicates so they will be resolved after processing all the fragments.
+ for _, fragment := range fragments {
+ if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
+ info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ i.TransitiveStubDexJarsByKind.append(info.TransitiveStubDexJarsByKind)
+ }
+ }
+
+ // Dedup and sort paths.
+ i.TransitiveStubDexJarsByKind.dedupAndSort()
+}
+
+var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
+
+// StubDexJarsByKind maps an android.SdkKind to the paths to stub dex jars appropriate for that
+// level. See hiddenAPIRelevantSdkKinds for a list of the acceptable android.SdkKind values.
+type StubDexJarsByKind map[android.SdkKind]android.Paths
+
+// append appends the supplied kind specific stub dex jar pargs to the corresponding kind in this
+// map.
+func (s StubDexJarsByKind) append(other StubDexJarsByKind) {
+ for _, kind := range hiddenAPIRelevantSdkKinds {
+ s[kind] = append(s[kind], other[kind]...)
+ }
+}
+
+// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
+// deterministic order.
+func (s StubDexJarsByKind) dedupAndSort() {
+ for kind, paths := range s {
+ s[kind] = android.SortedUniquePaths(paths)
+ }
+}
+
+// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
+// needed for hidden API flag generation.
+type HiddenAPIFlagInput struct {
+ // FlagFilesByCategory contains the flag files that override the initial flags that are derived
+ // from the stub dex files.
+ FlagFilesByCategory FlagFilesByCategory
+
+ // StubDexJarsByKind contains the stub dex jars for different android.SdkKind and which determine
+ // the initial flags for each dex member.
+ StubDexJarsByKind StubDexJarsByKind
+
+ // DependencyStubDexJarsByKind contains the stub dex jars provided by the fragments on which this
+ // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByKind from each
+ // fragment on which this depends.
+ DependencyStubDexJarsByKind StubDexJarsByKind
+
+ // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
+ // specified in the bootclasspath_fragment's stub_libs and contents properties.
+ RemovedTxtFiles android.Paths
+}
+
+// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
+func newHiddenAPIFlagInput() HiddenAPIFlagInput {
+ input := HiddenAPIFlagInput{
+ FlagFilesByCategory: FlagFilesByCategory{},
+ StubDexJarsByKind: StubDexJarsByKind{},
+ }
+
+ return input
+}
+
+// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
+//
+// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
+// appropriate information needed for hidden API processing breaking the build.
+// TODO(b/179354495): Remove this workaround.
+func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
+ // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
+ // required as the whole point of adding something to the bootclasspath fragment is to add it to
+ // the bootclasspath in order to be used by something else in the system. Without any stubs it
+ // cannot do that.
+ if len(i.StubDexJarsByKind) == 0 {
+ return false
+ }
+
+ // Hidden API processing is always enabled in tests.
+ if ctx.Config().TestProductVariables != nil {
+ return true
+ }
+
+ // A module that has fragments should have access to the information it needs in order to perform
+ // hidden API processing.
+ if len(properties.Fragments) != 0 {
+ return true
+ }
+
+ // The art bootclasspath fragment does not depend on any other fragments but already supports
+ // hidden API processing.
+ imageName := proptools.String(properties.Image_name)
+ if imageName == "art" {
+ return true
+ }
+
+ // Disable it for everything else.
+ return false
+}
+
+// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
+// dependencies added in hiddenAPIAddStubLibDependencies.
+//
+// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
+func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
+ addFromModule := func(ctx android.ModuleContext, module android.Module, kind android.SdkKind) {
+ dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
+ if dexJar != nil {
+ i.StubDexJarsByKind[kind] = append(i.StubDexJarsByKind[kind], dexJar)
+ }
+
+ if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
+ removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, kind)
+ i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
+ }
+ }
+
+ // If the contents includes any java_sdk_library modules then add them to the stubs.
+ for _, module := range contents {
+ if _, ok := module.(SdkLibraryDependency); ok {
+ // Add information for every possible kind needed by hidden API. SdkCorePlatform is not used
+ // as the java_sdk_library does not have special support for core_platform API, instead it is
+ // implemented as a customized form of SdkPublic.
+ for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
+ addFromModule(ctx, module, kind)
+ }
+ }
+ }
+
+ ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
+ kind := hiddenAPIStubsTag.sdkKind
+ addFromModule(ctx, module, kind)
+ }
+ })
+
+ // Normalize the paths, i.e. remove duplicates and sort.
+ i.StubDexJarsByKind.dedupAndSort()
+ i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
+}
+
+// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
+// supplied properties and stores them in this struct.
+func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
+ for _, category := range hiddenAPIFlagFileCategories {
+ paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
+ i.FlagFilesByCategory[category] = paths
+ }
+}
+
+func (i *HiddenAPIFlagInput) transitiveStubDexJarsByKind() StubDexJarsByKind {
+ transitive := i.DependencyStubDexJarsByKind
+ transitive.append(i.StubDexJarsByKind)
+ return transitive
+}
+
+// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
+// bootclasspath_fragment module.
+type HiddenAPIFlagOutput struct {
+ // The path to the generated stub-flags.csv file.
+ StubFlagsPath android.Path
+
+ // The path to the generated annotation-flags.csv file.
+ AnnotationFlagsPath android.Path
+
+ // The path to the generated metadata.csv file.
+ MetadataPath android.Path
+
+ // The path to the generated index.csv file.
+ IndexPath android.Path
+
+ // The path to the generated all-flags.csv file.
+ AllFlagsPath android.Path
+}
+
+// pathForValidation creates a path of the same type as the supplied type but with a name of
+// <path>.valid.
+//
+// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
+// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
+func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
+ extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
+ return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
+}
+
+// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
+// the flags from all the modules, the stub flags, augmented with some additional configuration
+// files.
//
// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
// an entry for every single member in the dex implementation jars of the individual modules. Every
// signature in any of the other files MUST be included in this file.
//
-// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
-// information from the baseFlagsPath as well as from annotations within the source.
+// annotationFlags is the path to the annotation flags file generated from annotation information
+// in each module.
//
-// augmentationInfo is a struct containing paths to files that augment the information provided by
-// the moduleSpecificFlagsPaths.
-// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the
-// flags from all the modules, the stub flags, augmented with some additional configuration files.
-//
-// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
-// an entry for every single member in the dex implementation jars of the individual modules. Every
-// signature in any of the other files MUST be included in this file.
-//
-// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using
-// information from the baseFlagsPath as well as from annotations within the source.
-//
-// augmentationInfo is a struct containing paths to files that augment the information provided by
-// the moduleSpecificFlagsPaths.
-func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIFlagFileInfo) {
+// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
+// the annotationFlags.
+func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
+ outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlags android.Path,
+ flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
+
+ // The file which is used to record that the flags file is valid.
+ var validFile android.WritablePath
+
+ // If there are flag files that have been generated by fragments on which this depends then use
+ // them to validate the flag file generated by the rules created by this method.
+ if len(allFlagsPaths) > 0 {
+ // The flags file generated by the rule created by this method needs to be validated to ensure
+ // that it is consistent with the flag files generated by the individual fragments.
+
+ validFile = pathForValidation(ctx, outputPath)
+
+ // Create a rule to validate the output from the following rule.
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("verify_overlaps").
+ Input(outputPath).
+ Inputs(allFlagsPaths).
+ // If validation passes then update the file that records that.
+ Text("&& touch").Output(validFile)
+ rule.Build(name+"Validation", desc+" validation")
+ }
+
+ // Create the rule that will generate the flag files.
tempPath := tempPathForRestat(ctx, outputPath)
rule := android.NewRuleBuilder(pctx, ctx)
command := rule.Command().
BuiltTool("generate_hiddenapi_lists").
FlagWithInput("--csv ", baseFlagsPath).
- Inputs(moduleSpecificFlagsPaths).
+ Input(annotationFlags).
FlagWithOutput("--output ", tempPath)
// Add the options for the different categories of flag files.
for _, category := range hiddenAPIFlagFileCategories {
- paths := augmentationInfo.categoryToPaths[category]
+ paths := flagFilesByCategory[category]
for _, path := range paths {
category.commandMutator(command, path)
}
}
+ // If available then pass the automatically generated file containing dex signatures of removed
+ // API members to the rule so they can be marked as removed.
+ if generatedRemovedDexSignatures.Valid() {
+ hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
+ }
+
commitChangeForRestat(rule, tempPath, outputPath)
- rule.Build("hiddenAPIFlagsFile", "hiddenapi flags")
+ if validFile != nil {
+ // Add the file that indicates that the file generated by this is valid.
+ //
+ // This will cause the validation rule above to be run any time that the output of this rule
+ // changes but the validation will run in parallel with other rules that depend on this file.
+ command.Validation(validFile)
+ }
+
+ rule.Build(name, desc)
+}
+
+// hiddenAPIGenerateAllFlagsForBootclasspathFragment will generate all the flags for a fragment
+// of the bootclasspath.
+//
+// It takes:
+// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
+// * The list of modules that are the contents of the fragment.
+// * The additional manually curated flag files to use.
+//
+// It generates:
+// * stub-flags.csv
+// * annotation-flags.csv
+// * metadata.csv
+// * index.csv
+// * all-flags.csv
+func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+ hiddenApiSubDir := "modular-hiddenapi"
+
+ // Gather the dex files for the boot libraries provided by this fragment.
+ bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, contents)
+
+ // Generate the stub-flags.csv.
+ stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
+ rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, input)
+ rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
+
+ // Extract the classes jars from the contents.
+ classesJars := extractClassJarsFromHiddenAPIModules(ctx, contents)
+
+ // Generate the set of flags from the annotations in the source code.
+ annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
+ buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
+
+ // Generate the metadata from the annotations in the source code.
+ metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
+ buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
+
+ // Generate the index file from the CSV files in the classes jars.
+ indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
+ buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
+
+ // Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files
+ // containing dex signatures of all the removed APIs. In the monolithic files that is done by
+ // manually combining all the removed.txt files for each API and then converting them to dex
+ // signatures, see the combined-removed-dex module. This does that automatically by using the
+ // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
+ // stub_libs and contents properties of a bootclasspath_fragment.
+ removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
+
+ // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
+ // files.
+ outputPath := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
+ buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, annotationFlagsCSV, input.FlagFilesByCategory, nil, removedDexSignatures)
+
+ // Store the paths in the info for use by other modules and sdk snapshot generation.
+ output := HiddenAPIFlagOutput{
+ StubFlagsPath: stubFlagsCSV,
+ AnnotationFlagsPath: annotationFlagsCSV,
+ MetadataPath: metadataCSV,
+ IndexPath: indexCSV,
+ AllFlagsPath: outputPath,
+ }
+ return &output
+}
+
+func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
+ if len(removedTxtFiles) == 0 {
+ return android.OptionalPath{}
+ }
+
+ output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("metalava").
+ Flag("--no-banner").
+ Inputs(removedTxtFiles).
+ FlagWithOutput("--dex-api ", output)
+ rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
+ return android.OptionalPathForPath(output)
+}
+
+// gatherHiddenAPIModuleFromContents gathers the hiddenAPIModule from the supplied contents.
+func gatherHiddenAPIModuleFromContents(ctx android.ModuleContext, contents []android.Module) []hiddenAPIModule {
+ hiddenAPIModules := []hiddenAPIModule{}
+ for _, module := range contents {
+ if hiddenAPI, ok := module.(hiddenAPIModule); ok {
+ hiddenAPIModules = append(hiddenAPIModules, hiddenAPI)
+ } else if _, ok := module.(*DexImport); ok {
+ // Ignore this for the purposes of hidden API processing
+ } else {
+ ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
+ }
+ }
+ return hiddenAPIModules
+}
+
+// extractBootDexJarsFromHiddenAPIModules extracts the boot dex jars from the supplied modules.
+func extractBootDexJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []hiddenAPIModule) android.Paths {
+ bootDexJars := android.Paths{}
+ for _, module := range contents {
+ bootDexJar := module.bootDexJar()
+ if bootDexJar == nil {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ // TODO(b/179354495): Remove this work around when it is unnecessary.
+ // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
+ // create a fake one that will cause a build error only if it is used.
+ fake := android.PathForModuleOut(ctx, "fake/boot-dex/%s.jar", module.Name())
+
+ // Create an error rule that pretends to create the output file but will actually fail if it
+ // is run.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.ErrorRule,
+ Output: fake,
+ Args: map[string]string{
+ "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
+ },
+ })
+ bootDexJars = append(bootDexJars, fake)
+ } else {
+ ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+ }
+ } else {
+ bootDexJars = append(bootDexJars, bootDexJar)
+ }
+ }
+ return bootDexJars
+}
+
+// extractClassJarsFromHiddenAPIModules extracts the class jars from the supplied modules.
+func extractClassJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []hiddenAPIModule) android.Paths {
+ classesJars := android.Paths{}
+ for _, module := range contents {
+ classesJars = append(classesJars, module.classesJars()...)
+ }
+ return classesJars
}
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
new file mode 100644
index 0000000..a6bf8c7
--- /dev/null
+++ b/java/hiddenapi_monolithic.go
@@ -0,0 +1,102 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 java
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+// MonolithicHiddenAPIInfo contains information needed/provided by the hidden API generation of the
+// monolithic hidden API files.
+//
+// Each list of paths includes all the equivalent paths from each of the bootclasspath_fragment
+// modules that contribute to the platform-bootclasspath.
+type MonolithicHiddenAPIInfo struct {
+ // FlagsFilesByCategory maps from the flag file category to the paths containing information for
+ // that category.
+ FlagsFilesByCategory FlagFilesByCategory
+
+ // The paths to the generated stub-flags.csv files.
+ StubFlagsPaths android.Paths
+
+ // The paths to the generated annotation-flags.csv files.
+ AnnotationFlagsPaths android.Paths
+
+ // The paths to the generated metadata.csv files.
+ MetadataPaths android.Paths
+
+ // The paths to the generated index.csv files.
+ IndexPaths android.Paths
+
+ // The paths to the generated all-flags.csv files.
+ AllFlagsPaths android.Paths
+}
+
+// newMonolithicHiddenAPIInfo creates a new MonolithicHiddenAPIInfo from the flagFilesByCategory
+// plus information provided by each of the fragments.
+func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory FlagFilesByCategory, fragments []android.Module) MonolithicHiddenAPIInfo {
+ monolithicInfo := MonolithicHiddenAPIInfo{}
+
+ monolithicInfo.FlagsFilesByCategory = flagFilesByCategory
+
+ // Merge all the information from the fragments. The fragments form a DAG so it is possible that
+ // this will introduce duplicates so they will be resolved after processing all the fragments.
+ for _, fragment := range fragments {
+ if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
+ info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ monolithicInfo.append(&info)
+ }
+ }
+
+ // Dedup paths.
+ monolithicInfo.dedup()
+
+ return monolithicInfo
+}
+
+// append appends all the files from the supplied info to the corresponding files in this struct.
+func (i *MonolithicHiddenAPIInfo) append(other *HiddenAPIInfo) {
+ i.FlagsFilesByCategory.append(other.FlagFilesByCategory)
+
+ // The output may not be set if the bootclasspath_fragment has not yet been updated to support
+ // hidden API processing.
+ // TODO(b/179354495): Switch back to append once all bootclasspath_fragment modules have been
+ // updated to support hidden API processing properly.
+ appendIfNotNil := func(paths android.Paths, path android.Path) android.Paths {
+ if path == nil {
+ return paths
+ }
+ return append(paths, path)
+ }
+ i.StubFlagsPaths = appendIfNotNil(i.StubFlagsPaths, other.StubFlagsPath)
+ i.AnnotationFlagsPaths = appendIfNotNil(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
+ i.MetadataPaths = appendIfNotNil(i.MetadataPaths, other.MetadataPath)
+ i.IndexPaths = appendIfNotNil(i.IndexPaths, other.IndexPath)
+ i.AllFlagsPaths = appendIfNotNil(i.AllFlagsPaths, other.AllFlagsPath)
+}
+
+// dedup removes duplicates in all the paths, while maintaining the order in which they were
+// appended.
+func (i *MonolithicHiddenAPIInfo) dedup() {
+ i.FlagsFilesByCategory.dedup()
+ i.StubFlagsPaths = android.FirstUniquePaths(i.StubFlagsPaths)
+ i.AnnotationFlagsPaths = android.FirstUniquePaths(i.AnnotationFlagsPaths)
+ i.MetadataPaths = android.FirstUniquePaths(i.MetadataPaths)
+ i.IndexPaths = android.FirstUniquePaths(i.IndexPaths)
+ i.AllFlagsPaths = android.FirstUniquePaths(i.AllFlagsPaths)
+}
+
+var monolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index f6af501..52934a3 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -117,7 +117,6 @@
}
type hiddenAPISingleton struct {
- flags android.Path
}
// hiddenAPI singleton rules
@@ -136,24 +135,15 @@
// consistency.
if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" {
- h.flags = prebuiltFlagsRule(ctx)
+ prebuiltFlagsRule(ctx)
prebuiltIndexRule(ctx)
return
}
-
- // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
- if ctx.Config().FrameworksBaseDirExists(ctx) {
- h.flags = flagsRule(ctx)
- } else {
- h.flags = emptyFlagsRule(ctx)
- }
}
// Checks to see whether the supplied module variant is in the list of boot jars.
//
-// Apart from the context this is identical to isModuleInConfiguredListForSingleton.
-//
-// TODO(b/179354495): Avoid having to perform this type of check or if necessary dedup it.
+// TODO(b/179354495): Avoid having to perform this type of check.
func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool {
name := ctx.OtherModuleName(module)
@@ -177,11 +167,11 @@
// Now match the apex part of the boot image configuration.
requiredApex := configuredBootJars.Apex(index)
if requiredApex == "platform" || requiredApex == "system_ext" {
- if len(apexInfo.InApexes) != 0 {
+ if len(apexInfo.InApexVariants) != 0 {
// A platform variant is required but this is for an apex so ignore it.
return false
}
- } else if !apexInfo.InApexByBaseName(requiredApex) {
+ } else if !apexInfo.InApexVariant(requiredApex) {
// An apex variant for a specific apex is required but this is the wrong apex.
return false
}
@@ -189,7 +179,7 @@
return true
}
-func prebuiltFlagsRule(ctx android.SingletonContext) android.Path {
+func prebuiltFlagsRule(ctx android.SingletonContext) {
outputPath := hiddenAPISingletonPaths(ctx).flags
inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv")
@@ -198,8 +188,6 @@
Output: outputPath,
Input: inputPath,
})
-
- return outputPath
}
func prebuiltIndexRule(ctx android.SingletonContext) {
@@ -213,28 +201,6 @@
})
}
-// flagsRule is a placeholder that simply returns the location of the file, the generation of the
-// ninja rules is done in generateHiddenAPIBuildActions.
-func flagsRule(ctx android.SingletonContext) android.Path {
- outputPath := hiddenAPISingletonPaths(ctx).flags
- return outputPath
-}
-
-// emptyFlagsRule creates a rule to build an empty hiddenapi-flags.csv, which is needed by master-art-host builds that
-// have a partial manifest without frameworks/base but still need to build a boot image.
-func emptyFlagsRule(ctx android.SingletonContext) android.Path {
- rule := android.NewRuleBuilder(pctx, ctx)
-
- outputPath := hiddenAPISingletonPaths(ctx).flags
-
- rule.Command().Text("rm").Flag("-f").Output(outputPath)
- rule.Command().Text("touch").Output(outputPath)
-
- rule.Build("emptyHiddenAPIFlagsFile", "empty hiddenapi flags")
-
- return outputPath
-}
-
// tempPathForRestat creates a path of the same type as the supplied type but with a name of
// <path>.tmp.
//
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 3ab2277..dcd363c 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -60,10 +60,7 @@
}
func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) {
- expectedErrorMessage :=
- "hiddenapi has determined that the source module \"foo\" should be ignored as it has been" +
- " replaced by the prebuilt module \"prebuilt_foo\" but unfortunately it does not provide a" +
- " suitable boot dex jar"
+ expectedErrorMessage := "module prebuilt_foo{os:android,arch:common} does not provide a dex jar"
android.GroupFixturePreparers(
hiddenApiFixtureFactory,
@@ -277,3 +274,56 @@
android.AssertStringEquals(t, "hiddenapi encode dex rule flags csv", expectedFlagsCsv, actualFlagsCsv)
}
+
+func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) {
+
+ result := android.GroupFixturePreparers(
+ hiddenApiFixtureFactory,
+ FixtureConfigureBootJars("platform:foo"),
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ shared_library: false,
+ compile_dex: true,
+ public: {enabled: true},
+ }
+ `)
+
+ checkDexEncoded := func(t *testing.T, name, unencodedDexJar, encodedDexJar string) {
+ moduleForTests := result.ModuleForTests(name, "android_common")
+
+ encodeDexRule := moduleForTests.Rule("hiddenAPIEncodeDex")
+ actualUnencodedDexJar := encodeDexRule.Input
+
+ // Make sure that the module has its dex jar encoded.
+ android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String())
+
+ // Make sure that the encoded dex jar is the exported one.
+ exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath()
+ android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar)
+ }
+
+ // The java_library embedded with the java_sdk_library must be dex encoded.
+ t.Run("foo", func(t *testing.T) {
+ expectedUnencodedDexJar := "out/soong/.intermediates/foo/android_common/aligned/foo.jar"
+ expectedEncodedDexJar := "out/soong/.intermediates/foo/android_common/hiddenapi/foo.jar"
+ checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar)
+ })
+
+ // The dex jar of the child implementation java_library of the java_sdk_library is not currently
+ // dex encoded.
+ t.Run("foo.impl", func(t *testing.T) {
+ fooImpl := result.ModuleForTests("foo.impl", "android_common")
+ encodeDexRule := fooImpl.MaybeRule("hiddenAPIEncodeDex")
+ if encodeDexRule.Rule != nil {
+ t.Errorf("foo.impl is not expected to be encoded")
+ }
+ })
+}
diff --git a/java/java.go b/java/java.go
index d74bf68..2bbb5b1 100644
--- a/java/java.go
+++ b/java/java.go
@@ -57,6 +57,10 @@
ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
ctx.RegisterModuleType("dex_import", DexImportFactory)
+ // This mutator registers dependencies on dex2oat for modules that should be
+ // dexpreopted. This is done late when the final variants have been
+ // established, to not get the dependencies split into the wrong variants and
+ // to support the checks in dexpreoptDisabled().
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
})
@@ -481,11 +485,6 @@
}
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Initialize the hiddenapi structure. Pass in the configuration name rather than the module name
- // so the hidden api will encode the <x>.impl java_ library created by java_sdk_library just as it
- // would the <x> library if <x> was configured as a boot jar.
- j.initHiddenAPI(ctx, j.ConfigurationName())
-
j.sdkVersion = j.SdkVersion(ctx)
j.minSdkVersion = j.MinSdkVersion(ctx)
@@ -1222,6 +1221,13 @@
return LintDepSets{}
}
+func (j *Import) getStrictUpdatabilityLinting() bool {
+ return false
+}
+
+func (j *Import) setStrictUpdatabilityLinting(bool) {
+}
+
func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
@@ -1234,9 +1240,6 @@
j.sdkVersion = j.SdkVersion(ctx)
j.minSdkVersion = j.MinSdkVersion(ctx)
- // Initialize the hiddenapi structure.
- j.initHiddenAPI(ctx, j.BaseModuleName())
-
if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
j.hideApexVariantFromMake = true
}
@@ -1308,7 +1311,9 @@
di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
if dexOutputPath := di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar"); dexOutputPath != nil {
j.dexJarFile = dexOutputPath
- j.hiddenAPIExtractInformation(ctx, dexOutputPath, outputFile)
+
+ // Initialize the hiddenapi structure.
+ j.initHiddenAPI(ctx, dexOutputPath, outputFile, nil)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
// prebuilt_apex has been configured to export the java library dex file.
@@ -1339,9 +1344,11 @@
return
}
- // Hidden API CSV generation and dex encoding
- dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, outputFile,
- proptools.Bool(j.dexProperties.Uncompress_dex))
+ // Initialize the hiddenapi structure.
+ j.initHiddenAPI(ctx, dexOutputFile, outputFile, j.dexProperties.Uncompress_dex)
+
+ // Encode hidden API flags in dex file.
+ dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
j.dexJarFile = dexOutputFile
}
@@ -1545,6 +1552,13 @@
return true
}
+func (j *DexImport) getStrictUpdatabilityLinting() bool {
+ return false
+}
+
+func (j *DexImport) setStrictUpdatabilityLinting(bool) {
+}
+
func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(j.properties.Jars) != 1 {
ctx.PropertyErrorf("jars", "exactly one jar must be provided")
diff --git a/java/lint.go b/java/lint.go
index 5e39274..9f769df 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -103,6 +103,10 @@
type lintDepSetsIntf interface {
LintDepSets() LintDepSets
+
+ // Methods used to propagate strict_updatability_linting values.
+ getStrictUpdatabilityLinting() bool
+ setStrictUpdatabilityLinting(bool)
}
type LintDepSets struct {
@@ -153,6 +157,14 @@
return l.outputs.depSets
}
+func (l *linter) getStrictUpdatabilityLinting() bool {
+ return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
+}
+
+func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) {
+ l.properties.Lint.Strict_updatability_linting = &strictLinting
+}
+
var _ lintDepSetsIntf = (*linter)(nil)
var _ lintOutputsIntf = (*linter)(nil)
@@ -260,7 +272,7 @@
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
- if BoolDefault(l.properties.Lint.Strict_updatability_linting, false) {
+ if l.getStrictUpdatabilityLinting() {
// Verify the module does not baseline issues that endanger safe updatability.
if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
cmd.FlagWithInput("--baseline ", baselinePath.Path())
@@ -586,6 +598,14 @@
func init() {
android.RegisterSingletonType("lint",
func() android.Singleton { return &lintSingleton{} })
+
+ registerLintBuildComponents(android.InitRegistrationContext)
+}
+
+func registerLintBuildComponents(ctx android.RegistrationContext) {
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
+ })
}
func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
@@ -604,3 +624,15 @@
rule.Build(outputPath.Base(), outputPath.Base())
}
+
+// Enforce the strict updatability linting to all applicable transitive dependencies.
+func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
+ m := ctx.Module()
+ if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() {
+ ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
+ if a, ok := d.(lintDepSetsIntf); ok {
+ a.setStrictUpdatabilityLinting(true)
+ }
+ })
+ }
+}
diff --git a/java/lint_test.go b/java/lint_test.go
index a253df9..6d64de7 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -181,12 +181,22 @@
srcs: [
"a.java",
],
+ static_libs: ["bar"],
min_sdk_version: "29",
sdk_version: "current",
lint: {
strict_updatability_linting: true,
},
}
+
+ java_library {
+ name: "bar",
+ srcs: [
+ "a.java",
+ ],
+ min_sdk_version: "29",
+ sdk_version: "current",
+ }
`
fs := android.MockFS{
"lint-baseline.xml": nil,
@@ -201,4 +211,11 @@
"--baseline lint-baseline.xml --disallowed_issues NewApi") {
t.Error("did not restrict baselining NewApi")
}
+
+ bar := result.ModuleForTests("bar", "android_common")
+ sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
+ if !strings.Contains(*sboxProto.Commands[0].Command,
+ "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+ t.Error("did not restrict baselining NewApi")
+ }
}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 1caffe4..87c695c 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -196,24 +196,18 @@
return
}
- b.generateBootImageBuildActions(ctx, updatableModules)
+ b.generateBootImageBuildActions(ctx, nonUpdatableModules, updatableModules)
}
// Generate classpaths.proto config
func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
classpathJars := configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
- // TODO(satayev): remove updatable boot jars once each apex has its own fragment
- global := dexpreopt.GetGlobalConfig(ctx)
- classpathJars = append(classpathJars, configuredJarListToClasspathJars(ctx, global.UpdatableBootJars, BOOTCLASSPATH)...)
-
b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
}
func (b *platformBootclasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
- global := dexpreopt.GetGlobalConfig(ctx)
- // TODO(satayev): split ART apex jars into their own classpathFragment
- return global.BootJars
+ return b.getImageConfig(ctx).modules
}
// checkNonUpdatableModules ensures that the non-updatable modules supplied are not part of an
@@ -224,7 +218,7 @@
fromUpdatableApex := apexInfo.Updatable
if fromUpdatableApex {
// error: this jar is part of an updatable apex
- ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexes)
+ ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexVariants)
} else {
// ok: this jar is part of the platform or a non-updatable apex
}
@@ -241,8 +235,15 @@
} else {
name := ctx.OtherModuleName(m)
if apexInfo.IsForPlatform() {
- // error: this jar is part of the platform
- ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+ // If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will
+ // include platform variants of a prebuilt module due to workarounds elsewhere. In that case
+ // do not treat this as an error.
+ // TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment
+ // modules is complete.
+ if !ctx.Config().AlwaysUsePrebuiltSdks() {
+ // error: this jar is part of the platform
+ ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+ }
} else {
// TODO(b/177892522): Treat this as an error.
// Cannot do that at the moment because framework-wifi and framework-tethering are in the
@@ -256,17 +257,6 @@
return defaultBootImageConfig(ctx)
}
-// hiddenAPISupportingModule encapsulates the information provided by any module that contributes to
-// the hidden API processing.
-type hiddenAPISupportingModule struct {
- module android.Module
-
- bootDexJar android.Path
- flagsCSV android.Path
- indexCSV android.Path
- metadataCSV android.Path
-}
-
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) {
@@ -289,133 +279,82 @@
return
}
- // nilPathHandler will check the supplied path and if it is nil then it will either immediately
- // report an error, or it will defer the error reporting until it is actually used, depending
- // whether missing dependencies are allowed.
- var nilPathHandler func(path android.Path, name string, module android.Module) android.Path
- if ctx.Config().AllowMissingDependencies() {
- nilPathHandler = func(path android.Path, name string, module android.Module) android.Path {
- if path == nil {
- outputPath := android.PathForModuleOut(ctx, "missing", module.Name(), name)
- path = outputPath
+ monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, fragments)
- // Create an error rule that pretends to create the output file but will actually fail if it
- // is run.
- ctx.Build(pctx, android.BuildParams{
- Rule: android.ErrorRule,
- Output: outputPath,
- Args: map[string]string{
- "error": fmt.Sprintf("missing hidden API file: %s for %s", name, module),
- },
- })
- }
- return path
- }
- } else {
- nilPathHandler = func(path android.Path, name string, module android.Module) android.Path {
- if path == nil {
- ctx.ModuleErrorf("module %s does not provide a %s file", module, name)
- }
- return path
- }
- }
+ // Create the input to pass to ruleToGenerateHiddenAPIStubFlagsFile
+ input := newHiddenAPIFlagInput()
- hiddenAPISupportingModules := []hiddenAPISupportingModule{}
- for _, module := range modules {
- if h, ok := module.(hiddenAPIIntf); ok {
- hiddenAPISupportingModule := hiddenAPISupportingModule{
- module: module,
- bootDexJar: nilPathHandler(h.bootDexJar(), "bootDexJar", module),
- flagsCSV: nilPathHandler(h.flagsCSV(), "flagsCSV", module),
- indexCSV: nilPathHandler(h.indexCSV(), "indexCSV", module),
- metadataCSV: nilPathHandler(h.metadataCSV(), "metadataCSV", module),
- }
+ // Gather stub library information from the dependencies on modules provided by
+ // hiddenAPIComputeMonolithicStubLibModules.
+ input.gatherStubLibInfo(ctx, nil)
- // If any errors were reported when trying to populate the hiddenAPISupportingModule struct
- // then don't add it to the list.
- if ctx.Failed() {
- continue
- }
+ // Use the flag files from this module and all the fragments.
+ input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory
- hiddenAPISupportingModules = append(hiddenAPISupportingModules, hiddenAPISupportingModule)
- } else if _, ok := module.(*DexImport); ok {
- // Ignore this for the purposes of hidden API processing
- } else {
- ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module))
- }
- }
+ hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, modules)
- moduleSpecificFlagsPaths := android.Paths{}
- for _, module := range hiddenAPISupportingModules {
- moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV)
- }
+ // Generate the monolithic stub-flags.csv file.
+ bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, hiddenAPIModules)
+ stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
+ rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, input)
+ rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
- flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
- for _, fragment := range fragments {
- if ctx.OtherModuleHasProvider(fragment, hiddenAPIFlagFileInfoProvider) {
- info := ctx.OtherModuleProvider(fragment, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
- flagFileInfo.append(info)
- }
- }
+ // Extract the classes jars from the contents.
+ classesJars := extractClassJarsFromHiddenAPIModules(ctx, hiddenAPIModules)
+
+ // Generate the annotation-flags.csv file from all the module annotations.
+ annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags.csv")
+ buildRuleToGenerateAnnotationFlags(ctx, "monolithic hiddenapi flags", classesJars, stubFlags, annotationFlags)
+
+ // Generate the monotlithic hiddenapi-flags.csv file.
+ allFlags := hiddenAPISingletonPaths(ctx).flags
+ buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "hiddenapi flags", allFlags, stubFlags, annotationFlags, monolithicInfo.FlagsFilesByCategory, monolithicInfo.AllFlagsPaths, android.OptionalPath{})
+
+ // Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
+ // in the source code.
+ intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "intermediate-metadata.csv")
+ buildRuleToGenerateMetadata(ctx, "monolithic hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV)
+
+ // Reformat the intermediate file to add | quotes just in case that is important for the tools
+ // that consume the metadata file.
+ // TODO(b/179354495): Investigate whether it is possible to remove this reformatting step.
+ metadataCSV := hiddenAPISingletonPaths(ctx).metadata
+ b.buildRuleMergeCSV(ctx, "reformat monolithic hidden API metadata", android.Paths{intermediateMetadataCSV}, metadataCSV)
+
+ // Generate the monolithic hiddenapi-index.csv file directly from the CSV files in the classes
+ // jars.
+ indexCSV := hiddenAPISingletonPaths(ctx).index
+ buildRuleToGenerateIndex(ctx, "monolithic hidden API index", classesJars, indexCSV)
+}
+
+// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for
+// testing.
+func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, fragments []android.Module) MonolithicHiddenAPIInfo {
+ // Create a temporary input structure in which to collate information provided directly by this
+ // module, either through properties or direct dependencies.
+ temporaryInput := newHiddenAPIFlagInput()
+
+ // Create paths to the flag files specified in the properties.
+ temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
+
+ // Create the monolithic info, by starting with the flag files specified on this and then merging
+ // in information from all the fragment dependencies of this.
+ monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, fragments)
// Store the information for testing.
- ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
-
- outputPath := hiddenAPISingletonPaths(ctx).flags
- baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags
- ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, flagFileInfo)
-
- b.generateHiddenAPIStubFlagsRules(ctx, hiddenAPISupportingModules)
- b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules)
- b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules)
+ ctx.SetProvider(monolithicHiddenAPIInfoProvider, monolithicInfo)
+ return monolithicInfo
}
-func (b *platformBootclasspathModule) generateHiddenAPIStubFlagsRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
- bootDexJars := android.Paths{}
- for _, module := range modules {
- bootDexJars = append(bootDexJars, module.bootDexJar)
- }
-
- sdkKindToStubPaths := hiddenAPIGatherStubLibDexJarPaths(ctx)
-
- outputPath := hiddenAPISingletonPaths(ctx).stubFlags
- rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, outputPath, bootDexJars, sdkKindToStubPaths)
- rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
-}
-
-func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
- indexes := android.Paths{}
- for _, module := range modules {
- indexes = append(indexes, module.indexCSV)
- }
-
+func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) {
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
BuiltTool("merge_csv").
Flag("--key_field signature").
- FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
- FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
- Inputs(indexes)
- rule.Build("platform-bootclasspath-monolithic-hiddenapi-index", "monolithic hidden API index")
-}
-
-func (b *platformBootclasspathModule) generatedHiddenAPIMetadataRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) {
- metadataCSVFiles := android.Paths{}
- for _, module := range modules {
- metadataCSVFiles = append(metadataCSVFiles, module.metadataCSV)
- }
-
- rule := android.NewRuleBuilder(pctx, ctx)
-
- outputPath := hiddenAPISingletonPaths(ctx).metadata
-
- rule.Command().
- BuiltTool("merge_csv").
- Flag("--key_field signature").
FlagWithOutput("--output=", outputPath).
- Inputs(metadataCSVFiles)
+ Inputs(inputPaths)
- rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata")
+ rule.Build(desc, desc)
}
// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g.
@@ -429,7 +368,7 @@
}
// generateBootImageBuildActions generates ninja rules related to the boot image creation.
-func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, updatableModules []android.Module) {
+func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, nonUpdatableModules, updatableModules []android.Module) {
// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
// GenerateSingletonBuildActions method as it cannot create it for itself.
dexpreopt.GetGlobalSoongConfig(ctx)
@@ -450,5 +389,16 @@
// Generate the updatable bootclasspath packages rule.
generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
+ // Copy non-updatable module dex jars to their predefined locations.
+ copyBootJarsToPredefinedLocations(ctx, nonUpdatableModules, imageConfig.modules, imageConfig.dexPaths)
+
+ // Copy updatable module dex jars to their predefined locations.
+ config := GetUpdatableBootConfig(ctx)
+ copyBootJarsToPredefinedLocations(ctx, updatableModules, config.modules, config.dexPaths)
+
+ // Build a profile for the image config and then use that to build the boot image.
+ profile := bootImageProfileRule(ctx, imageConfig)
+ buildBootImage(ctx, imageConfig, profile)
+
dumpOatRules(ctx, imageConfig)
}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 98d4614..ed5549d 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -155,6 +155,8 @@
func TestPlatformBootclasspath_Fragments(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
android.FixtureWithRootAndroidBp(`
platform_bootclasspath {
name: "platform-bootclasspath",
@@ -192,6 +194,9 @@
bootclasspath_fragment {
name: "bar-fragment",
contents: ["bar"],
+ api: {
+ stub_libs: ["foo"],
+ },
hidden_api: {
unsupported: [
"bar-unsupported.txt",
@@ -227,19 +232,34 @@
sdk_version: "none",
compile_dex: true,
}
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ public: {
+ enabled: true,
+ },
+ compile_dex: true,
+ }
`),
).RunTest(t)
pbcp := result.Module("platform-bootclasspath", "android_common")
- info := result.ModuleProvider(pbcp, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
+ info := result.ModuleProvider(pbcp, monolithicHiddenAPIInfoProvider).(MonolithicHiddenAPIInfo)
for _, category := range hiddenAPIFlagFileCategories {
name := category.propertyName
message := fmt.Sprintf("category %s", name)
filename := strings.ReplaceAll(name, "_", "-")
expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
- android.AssertPathsRelativeToTopEquals(t, message, expected, info.categoryToPaths[category])
+ android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
}
+
+ android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
+ android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
+ android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
+ android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/index.csv"}, info.IndexPaths)
+ android.AssertPathsRelativeToTopEquals(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/all-flags.csv"}, info.AllFlagsPaths)
}
func TestPlatformBootclasspathVariant(t *testing.T) {
@@ -267,7 +287,7 @@
).RunTest(t)
p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
- android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base())
+ android.AssertStringEquals(t, "output filepath", "bootclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base())
android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
}
@@ -307,7 +327,7 @@
want := map[string][]string{
"LOCAL_MODULE": {"platform-bootclasspath"},
"LOCAL_MODULE_CLASS": {"ETC"},
- "LOCAL_INSTALLED_MODULE_STEM": {"platform-bootclasspath.pb"},
+ "LOCAL_INSTALLED_MODULE_STEM": {"bootclasspath.pb"},
// Output and Install paths are tested separately in TestPlatformBootclasspath_ClasspathFragmentPaths
}
@@ -407,20 +427,14 @@
}
`)
- platformBootclasspath := result.ModuleForTests("myplatform-bootclasspath", "android_common")
- indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index")
- CheckHiddenAPIRuleInputs(t, `
-.intermediates/bar/android_common/hiddenapi/index.csv
-.intermediates/foo/android_common/hiddenapi/index.csv
-`,
- indexRule)
-
// Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that
// creates the index.csv file.
- foo := result.ModuleForTests("foo", "android_common")
- indexParams := foo.Output("hiddenapi/index.csv")
+ platformBootclasspath := result.ModuleForTests("myplatform-bootclasspath", "android_common")
+ indexRule := platformBootclasspath.Rule("monolithic_hidden_API_index")
CheckHiddenAPIRuleInputs(t, `
+.intermediates/bar/android_common/javac/bar.jar
.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
.intermediates/foo/android_common/javac/foo.jar
-`, indexParams)
+`,
+ indexRule)
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index aff4539..8f36758 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -845,19 +845,7 @@
// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
- var apiScope *apiScope
- switch kind {
- case android.SdkSystem:
- apiScope = apiScopeSystem
- case android.SdkModule:
- apiScope = apiScopeModuleLib
- case android.SdkTest:
- apiScope = apiScopeTest
- case android.SdkSystemServer:
- apiScope = apiScopeSystemServer
- default:
- apiScope = apiScopePublic
- }
+ apiScope := sdkKindToApiScope(kind)
paths := c.findClosestScopePath(apiScope)
if paths == nil {
@@ -874,6 +862,24 @@
return paths
}
+// sdkKindToApiScope maps from android.SdkKind to apiScope.
+func sdkKindToApiScope(kind android.SdkKind) *apiScope {
+ var apiScope *apiScope
+ switch kind {
+ case android.SdkSystem:
+ apiScope = apiScopeSystem
+ case android.SdkModule:
+ apiScope = apiScopeModuleLib
+ case android.SdkTest:
+ apiScope = apiScopeTest
+ case android.SdkSystemServer:
+ apiScope = apiScopeSystemServer
+ default:
+ apiScope = apiScopePublic
+ }
+ return apiScope
+}
+
// to satisfy SdkLibraryDependency interface
func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path {
paths := c.selectScopePaths(ctx, kind)
@@ -884,6 +890,17 @@
return paths.stubsDexJarPath
}
+// to satisfy SdkLibraryDependency interface
+func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath {
+ apiScope := sdkKindToApiScope(kind)
+ paths := c.findScopePaths(apiScope)
+ if paths == nil {
+ return android.OptionalPath{}
+ }
+
+ return paths.removedApiFilePath
+}
+
func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
componentProps := &struct {
SdkLibraryToImplicitlyTrack *string
@@ -900,11 +917,17 @@
return componentProps
}
-// Check if this can be used as a shared library.
func (c *commonToSdkLibraryAndImport) sharedLibrary() bool {
return proptools.BoolDefault(c.commonSdkLibraryProperties.Shared_library, true)
}
+// Check if the stub libraries should be compiled for dex
+func (c *commonToSdkLibraryAndImport) stubLibrariesCompiledForDex() bool {
+ // Always compile the dex file files for the stub libraries if they will be used on the
+ // bootclasspath.
+ return !c.sharedLibrary()
+}
+
// Properties related to the use of a module as an component of a java_sdk_library.
type SdkLibraryComponentProperties struct {
@@ -958,7 +981,7 @@
var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
-// Provides access to sdk_version related header and implentation jars.
+// Provides access to sdk_version related files, e.g. header and implementation jars.
type SdkLibraryDependency interface {
SdkLibraryComponentDependency
@@ -978,6 +1001,12 @@
// SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing
// tool which processes dex files.
SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path
+
+ // SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
+ SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
+
+ // sharedLibrary returns true if this can be used as a shared library.
+ sharedLibrary() bool
}
type SdkLibrary struct {
@@ -1226,16 +1255,13 @@
// Creates the implementation java library
func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
- moduleNamePtr := proptools.StringPtr(module.BaseModuleName())
-
visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility)
props := struct {
- Name *string
- Visibility []string
- Instrument bool
- Libs []string
- ConfigurationName *string
+ Name *string
+ Visibility []string
+ Instrument bool
+ Libs []string
}{
Name: proptools.StringPtr(module.implLibraryModuleName()),
Visibility: visibility,
@@ -1244,9 +1270,6 @@
// Set the impl_only libs. Note that the module's "Libs" get appended as well, via the
// addition of &module.properties below.
Libs: module.sdkLibraryProperties.Impl_only_libs,
-
- // Make the created library behave as if it had the same name as this module.
- ConfigurationName: moduleNamePtr,
}
properties := []interface{}{
@@ -1309,9 +1332,13 @@
// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
// interop with older developer tools that don't support 1.9.
props.Java_version = proptools.StringPtr("1.8")
- if module.dexProperties.Compile_dex != nil {
- props.Compile_dex = module.dexProperties.Compile_dex
+
+ // The imports need to be compiled to dex if the java_sdk_library requests it.
+ compileDex := module.dexProperties.Compile_dex
+ if module.stubLibrariesCompiledForDex() {
+ compileDex = proptools.BoolPtr(true)
}
+ props.Compile_dex = compileDex
// Dist the class jar artifact for sdk builds.
if !Bool(module.sdkLibraryProperties.No_dist) {
@@ -1539,7 +1566,7 @@
func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
- return len(otherApexInfo.InApexes) > 0 && reflect.DeepEqual(apexInfo.InApexes, otherApexInfo.InApexes)
+ return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
}
func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
@@ -1622,8 +1649,12 @@
path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
p := android.ExistentPathForSource(mctx, path)
if !p.Valid() {
- mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
- missingCurrentApi = true
+ if mctx.Config().AllowMissingDependencies() {
+ mctx.AddMissingDependencies([]string{path})
+ } else {
+ mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
+ missingCurrentApi = true
+ }
}
}
}
@@ -1969,7 +2000,11 @@
props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
// The imports need to be compiled to dex if the java_sdk_library_import requests it.
- props.Compile_dex = module.properties.Compile_dex
+ compileDex := module.properties.Compile_dex
+ if module.stubLibrariesCompiledForDex() {
+ compileDex = proptools.BoolPtr(true)
+ }
+ props.Compile_dex = compileDex
mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
@@ -2110,8 +2145,7 @@
di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
if dexOutputPath := di.PrebuiltExportPath(module.BaseModuleName(), ".dexjar"); dexOutputPath != nil {
module.dexJarFile = dexOutputPath
- module.initHiddenAPI(ctx, module.configurationName)
- module.hiddenAPIExtractInformation(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0])
+ module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
// prebuilt_apex has been configured to export the java library dex file.
@@ -2195,6 +2229,20 @@
}
}
+func (module *SdkLibraryImport) getStrictUpdatabilityLinting() bool {
+ if module.implLibraryModule == nil {
+ return false
+ } else {
+ return module.implLibraryModule.getStrictUpdatabilityLinting()
+ }
+}
+
+func (module *SdkLibraryImport) setStrictUpdatabilityLinting(strictLinting bool) {
+ if module.implLibraryModule != nil {
+ module.implLibraryModule.setStrictUpdatabilityLinting(strictLinting)
+ }
+}
+
// to satisfy apex.javaDependency interface
func (module *SdkLibraryImport) Stem() string {
return module.BaseModuleName()
@@ -2468,11 +2516,18 @@
}
scopeSet.AddProperty("jars", jars)
- // Merge the stubs source jar into the snapshot zip so that when it is unpacked
- // the source files are also unpacked.
- snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
- ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
- scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
+ if ctx.SdkModuleContext().Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_USE_SRCJAR") {
+ // Copy the stubs source jar into the snapshot zip as is.
+ srcJarSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".srcjar")
+ ctx.SnapshotBuilder().CopyToSnapshot(properties.StubsSrcJar, srcJarSnapshotPath)
+ scopeSet.AddProperty("stub_srcs", []string{srcJarSnapshotPath})
+ } else {
+ // Merge the stubs source jar into the snapshot zip so that when it is unpacked
+ // the source files are also unpacked.
+ snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
+ ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
+ scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
+ }
if properties.CurrentApiFile != nil {
currentApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".txt")
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 82cdb89..7ffb056 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -17,6 +17,8 @@
import (
"android/soong/android"
"android/soong/dexpreopt"
+
+ "github.com/google/blueprint"
)
func init() {
@@ -24,8 +26,8 @@
}
func registerSystemserverClasspathBuildComponents(ctx android.RegistrationContext) {
- // TODO(satayev): add systemserver_classpath_fragment module
ctx.RegisterModuleType("platform_systemserverclasspath", platformSystemServerClasspathFactory)
+ ctx.RegisterModuleType("systemserverclasspath_fragment", systemServerClasspathFactory)
}
type platformSystemServerClasspathModule struct {
@@ -41,27 +43,99 @@
return m
}
-func (b *platformSystemServerClasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) {
- return b.classpathFragmentBase().androidMkEntries()
+func (p *platformSystemServerClasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) {
+ return p.classpathFragmentBase().androidMkEntries()
}
-func (b *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- configuredJars := configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
- b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars)
+func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ classpathJars := configuredJarListToClasspathJars(ctx, p.ClasspathFragmentToConfiguredJarList(ctx), p.classpathType)
+ p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
}
-var platformSystemServerClasspathKey = android.NewOnceKey("platform_systemserverclasspath")
+func (p *platformSystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ return global.SystemServerJars
+}
-func (b *platformSystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
- return ctx.Config().Once(platformSystemServerClasspathKey, func() interface{} {
- global := dexpreopt.GetGlobalConfig(ctx)
+type SystemServerClasspathModule struct {
+ android.ModuleBase
+ android.ApexModuleBase
- jars := global.SystemServerJars
+ ClasspathFragmentBase
- // TODO(satayev): split apex jars into separate configs.
- for i := 0; i < global.UpdatableSystemServerJars.Len(); i++ {
- jars = jars.Append(global.UpdatableSystemServerJars.Apex(i), global.UpdatableSystemServerJars.Jar(i))
+ properties systemServerClasspathFragmentProperties
+}
+
+func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
+ return nil
+}
+
+type systemServerClasspathFragmentProperties struct {
+ // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library.
+ //
+ // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
+ Contents []string
+}
+
+func systemServerClasspathFactory() android.Module {
+ m := &SystemServerClasspathModule{}
+ m.AddProperties(&m.properties)
+ android.InitApexModule(m)
+ initClasspathFragment(m, SYSTEMSERVERCLASSPATH)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+ return m
+}
+
+func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if len(s.properties.Contents) == 0 {
+ ctx.PropertyErrorf("contents", "empty contents are not allowed")
+ }
+
+ classpathJars := configuredJarListToClasspathJars(ctx, s.ClasspathFragmentToConfiguredJarList(ctx), s.classpathType)
+ s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+}
+
+func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ // Convert content names to their appropriate stems, in case a test library is overriding an actual boot jar
+ var stems []string
+ for _, name := range s.properties.Contents {
+ dep := ctx.GetDirectDepWithTag(name, systemServerClasspathFragmentContentDepTag)
+ if m, ok := dep.(ModuleWithStem); ok {
+ stems = append(stems, m.Stem())
+ } else {
+ ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
}
- return jars
- }).(android.ConfiguredJarList)
+ }
+
+ // Only create configs for updatable boot jars. Non-updatable system server jars must be part of the
+ // platform_systemserverclasspath's classpath proto config to guarantee that they come before any
+ // updatable jars at runtime.
+ return global.UpdatableSystemServerJars.Filter(stems)
+}
+
+type systemServerClasspathFragmentContentDependencyTag struct {
+ blueprint.BaseDependencyTag
+}
+
+// Contents of system server fragments in an apex are considered to be directly in the apex, as if
+// they were listed in java_libs.
+func (systemServerClasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
+
+var _ android.CopyDirectlyInAnyApexTag = systemServerClasspathFragmentContentDepTag
+
+// The tag used for the dependency between the systemserverclasspath_fragment module and its contents.
+var systemServerClasspathFragmentContentDepTag = systemServerClasspathFragmentContentDependencyTag{}
+
+func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool {
+ return tag == systemServerClasspathFragmentContentDepTag
+}
+
+func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+ module := ctx.Module()
+
+ for _, name := range s.properties.Contents {
+ ctx.AddDependency(module, systemServerClasspathFragmentContentDepTag, name)
+ }
}
diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go
index 6126d5e..9ad50dd 100644
--- a/java/systemserver_classpath_fragment_test.go
+++ b/java/systemserver_classpath_fragment_test.go
@@ -20,13 +20,13 @@
"android/soong/android"
)
-var prepareForTestWithSystemserverClasspath = android.GroupFixturePreparers(
+var prepareForTestWithSystemServerClasspath = android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
)
-func TestSystemserverClasspathVariant(t *testing.T) {
+func TestPlatformSystemServerClasspathVariant(t *testing.T) {
result := android.GroupFixturePreparers(
- prepareForTestWithSystemserverClasspath,
+ prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
platform_systemserverclasspath {
name: "platform-systemserverclasspath",
@@ -38,9 +38,9 @@
android.AssertIntEquals(t, "expect 1 variant", 1, len(variants))
}
-func TestSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) {
+func TestPlatformSystemServerClasspath_ClasspathFragmentPaths(t *testing.T) {
result := android.GroupFixturePreparers(
- prepareForTestWithSystemserverClasspath,
+ prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
platform_systemserverclasspath {
name: "platform-systemserverclasspath",
@@ -49,13 +49,13 @@
).RunTest(t)
p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule)
- android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base())
+ android.AssertStringEquals(t, "output filepath", "systemserverclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base())
android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
}
-func TestSystemserverClasspathModule_AndroidMkEntries(t *testing.T) {
+func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) {
preparer := android.GroupFixturePreparers(
- prepareForTestWithSystemserverClasspath,
+ prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
platform_systemserverclasspath {
name: "platform-systemserverclasspath",
@@ -78,8 +78,8 @@
want := map[string][]string{
"LOCAL_MODULE": {"platform-systemserverclasspath"},
"LOCAL_MODULE_CLASS": {"ETC"},
- "LOCAL_INSTALLED_MODULE_STEM": {"platform-systemserverclasspath.pb"},
- // Output and Install paths are tested separately in TestSystemserverClasspath_ClasspathFragmentPaths
+ "LOCAL_INSTALLED_MODULE_STEM": {"systemserverclasspath.pb"},
+ // Output and Install paths are tested separately in TestPlatformSystemServerClasspath_ClasspathFragmentPaths
}
p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule)
@@ -95,3 +95,14 @@
}
})
}
+
+func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) {
+ prepareForTestWithSystemServerClasspath.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qempty contents are not allowed\E`)).
+ RunTestWithBp(t, `
+ systemserverclasspath_fragment {
+ name: "systemserverclasspath-fragment",
+ }
+ `)
+}
diff --git a/java/testing.go b/java/testing.go
index 37e63f5..1fef337 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -24,6 +24,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/dexpreopt"
+
"github.com/google/blueprint"
)
@@ -55,8 +56,9 @@
}.AddToFixture(),
)
-// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
-var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
+// Test fixture preparer that will define all default java modules except the
+// fake_tool_binary for dex2oatd.
+var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers(
// Make sure that all the module types used in the defaults are registered.
PrepareForTestWithJavaBuildComponents,
// Additional files needed when test disallows non-existent source.
@@ -72,6 +74,11 @@
android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()),
// Add dexpreopt compat libs (android.test.base, etc.) and a fake dex2oatd module.
dexpreopt.PrepareForTestWithDexpreoptCompatLibs,
+)
+
+// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
+var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd,
dexpreopt.PrepareForTestWithFakeDex2oatd,
)
@@ -245,6 +252,7 @@
RegisterStubsBuildComponents(ctx)
RegisterSystemModulesBuildComponents(ctx)
registerSystemserverClasspathBuildComponents(ctx)
+ registerLintBuildComponents(ctx)
}
// gatherRequiredDepsForTest gathers the module definitions used by
@@ -370,7 +378,7 @@
if apexInfo.IsForPlatform() {
apex = "platform"
} else {
- apex = apexInfo.InApexes[0]
+ apex = apexInfo.InApexVariants[0]
}
return fmt.Sprintf("%s:%s", apex, name)
diff --git a/python/test.go b/python/test.go
index 6713189..7413782 100644
--- a/python/test.go
+++ b/python/test.go
@@ -15,6 +15,8 @@
package python
import (
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/tradefed"
)
@@ -102,6 +104,9 @@
binary.pythonInstaller = NewPythonInstaller("nativetest", "nativetest64")
test := &testDecorator{binaryDecorator: binary}
+ if hod == android.HostSupportedNoCross && test.testProperties.Test_options.Unit_test == nil {
+ test.testProperties.Test_options.Unit_test = proptools.BoolPtr(true)
+ }
module.bootstrapper = test
module.installer = test
diff --git a/rust/Android.bp b/rust/Android.bp
index f45404f..b611672 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -31,8 +31,9 @@
"protobuf.go",
"rust.go",
"sanitize.go",
- "strip.go",
"source_provider.go",
+ "snapshot_utils.go",
+ "strip.go",
"test.go",
"testing.go",
],
diff --git a/rust/compiler.go b/rust/compiler.go
index a3f02c0..1598ebf 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -341,6 +341,11 @@
return compiler.Properties.Crate_name
}
+func (compiler *baseCompiler) everInstallable() bool {
+ // Most modules are installable, so return true by default.
+ return true
+}
+
func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath {
dir := compiler.dir
if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 4eead32..c217959 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -82,3 +82,8 @@
func (procMacro *procMacroDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
return rlibAutoDep
}
+
+func (procMacro *procMacroDecorator) everInstallable() bool {
+ // Proc_macros are never installed
+ return false
+}
diff --git a/rust/rust.go b/rust/rust.go
index bb97142..46c8f25 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -97,6 +97,7 @@
PreventInstall bool
HideFromMake bool
+ Installable *bool
}
type Module struct {
@@ -143,6 +144,10 @@
mod.Properties.HideFromMake = true
}
+func (c *Module) HiddenFromMake() bool {
+ return c.Properties.HideFromMake
+}
+
func (mod *Module) SanitizePropDefined() bool {
// Because compiler is not set for some Rust modules where sanitize might be set, check that compiler is also not
// nil since we need compiler to actually sanitize.
@@ -210,6 +215,38 @@
return false
}
+func (mod *Module) Dylib() bool {
+ if mod.compiler != nil {
+ if library, ok := mod.compiler.(libraryInterface); ok {
+ return library.dylib()
+ }
+ }
+ return false
+}
+
+func (mod *Module) Rlib() bool {
+ if mod.compiler != nil {
+ if library, ok := mod.compiler.(libraryInterface); ok {
+ return library.rlib()
+ }
+ }
+ return false
+}
+
+func (mod *Module) Binary() bool {
+ if mod.compiler != nil {
+ if _, ok := mod.compiler.(*binaryDecorator); ok {
+ return true
+ }
+ }
+ return false
+}
+
+func (mod *Module) Object() bool {
+ // Rust has no modules which produce only object files.
+ return false
+}
+
func (mod *Module) Toc() android.OptionalPath {
if mod.compiler != nil {
if _, ok := mod.compiler.(libraryInterface); ok {
@@ -223,12 +260,13 @@
return false
}
-// Returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64.
-// "product" and "vendor" variant modules return true for this function.
-// When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true",
-// "soc_specific: true" and more vendor installed modules are included here.
-// When PRODUCT_PRODUCT_VNDK_VERSION is set, product variants of "vendor_available: true" or
-// "product_specific: true" modules are included here.
+func (mod *Module) RelativeInstallPath() string {
+ if mod.compiler != nil {
+ return mod.compiler.relativeInstallPath()
+ }
+ return ""
+}
+
func (mod *Module) UseVndk() bool {
return mod.Properties.VndkVersion != ""
}
@@ -250,6 +288,10 @@
return false
}
+func (mod *Module) IsVndkSp() bool {
+ return false
+}
+
func (c *Module) IsVndkPrivate() bool {
return false
}
@@ -274,6 +316,14 @@
return false
}
+func (mod *Module) HasLlndkStubs() bool {
+ return false
+}
+
+func (mod *Module) StubsVersion() string {
+ panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", mod.BaseModuleName()))
+}
+
func (mod *Module) SdkVersion() string {
return ""
}
@@ -362,6 +412,7 @@
inData() bool
install(ctx ModuleContext)
relativeInstallPath() string
+ everInstallable() bool
nativeCoverage() bool
@@ -423,8 +474,12 @@
return mod.coverage != nil && mod.coverage.Properties.NeedCoverageVariant
}
-func (mod *Module) PreventInstall() {
- mod.Properties.PreventInstall = true
+func (mod *Module) VndkVersion() string {
+ return mod.Properties.VndkVersion
+}
+
+func (mod *Module) PreventInstall() bool {
+ return mod.Properties.PreventInstall
}
func (mod *Module) HideFromMake() {
@@ -564,6 +619,10 @@
}
func (mod *Module) installable(apexInfo android.ApexInfo) bool {
+ if !mod.EverInstallable() {
+ return false
+ }
+
// The apex variant is not installable because it is included in the APEX and won't appear
// in the system partition as a standalone file.
if !apexInfo.IsForPlatform() {
@@ -676,6 +735,16 @@
return mod.compiler != nil && mod.compiler.nativeCoverage()
}
+func (mod *Module) EverInstallable() bool {
+ return mod.compiler != nil &&
+ // Check to see whether the module is actually ever installable.
+ mod.compiler.everInstallable()
+}
+
+func (mod *Module) Installable() *bool {
+ return mod.Properties.Installable
+}
+
func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
if mod.cachedToolchain == nil {
mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 0a53f98..3d14d51 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -189,6 +189,22 @@
}
}
+func (m *Module) UbsanRuntimeNeeded() bool {
+ return false
+}
+
+func (m *Module) MinimalRuntimeNeeded() bool {
+ return false
+}
+
+func (m *Module) UbsanRuntimeDep() bool {
+ return false
+}
+
+func (m *Module) MinimalRuntimeDep() bool {
+ return false
+}
+
// Check if the sanitizer is explicitly disabled (as opposed to nil by
// virtue of not being set).
func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t cc.SanitizerType) bool {
diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go
new file mode 100644
index 0000000..943c790
--- /dev/null
+++ b/rust/snapshot_utils.go
@@ -0,0 +1,54 @@
+// Copyright 2021 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+)
+
+func (mod *Module) ExcludeFromVendorSnapshot() bool {
+ // TODO Rust does not yet support snapshotting
+ return false
+}
+
+func (mod *Module) ExcludeFromRecoverySnapshot() bool {
+ // TODO Rust does not yet support snapshotting
+ return false
+}
+
+func (mod *Module) IsSnapshotLibrary() bool {
+ // TODO Rust does not yet support snapshotting
+ return false
+}
+
+func (mod *Module) SnapshotRuntimeLibs() []string {
+ // TODO Rust does not yet support a runtime libs notion similar to CC
+ return []string{}
+}
+
+func (mod *Module) SnapshotSharedLibs() []string {
+ // TODO Rust does not yet support snapshotting
+ return []string{}
+}
+
+func (mod *Module) Symlinks() []string {
+ // TODO update this to return the list of symlinks when Rust supports defining symlinks
+ return nil
+}
+
+func (m *Module) SnapshotHeaders() android.Paths {
+ // TODO Rust does not yet support snapshotting
+ return android.Paths{}
+}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index b0a8669..1c02bd0 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -265,22 +265,3 @@
"linker_config_proto",
],
}
-
-python_binary_host {
- name: "conv_classpaths_proto",
- srcs: [
- "conv_classpaths_proto.py",
- ],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- embedded_launcher: true,
- },
- },
- libs: [
- "classpaths_proto_python",
- ],
-}
diff --git a/scripts/build-rustdocs.sh b/scripts/build-rustdocs.sh
new file mode 100755
index 0000000..ad8ba16
--- /dev/null
+++ b/scripts/build-rustdocs.sh
@@ -0,0 +1,31 @@
+#!/bin/bash -ex
+
+# 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.
+
+# Builds the platform rustdocs and copies them to the dist directory to provide
+# online docs for each build.
+
+if [ -z "${OUT_DIR}" ]; then
+ echo Must set OUT_DIR
+ exit 1
+fi
+
+source build/envsetup.sh
+m rustdoc
+
+if [ -n "${DIST_DIR}" ]; then
+ mkdir -p ${DIST_DIR}
+ cp -r ${OUT_DIR}/soong/rustdoc $DIST_DIR/rustdoc
+fi
diff --git a/scripts/conv_classpaths_proto.py b/scripts/conv_classpaths_proto.py
deleted file mode 100644
index f49fbbb..0000000
--- a/scripts/conv_classpaths_proto.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (C) 2021 The Android Open Source Project
-#
-# 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.
-
-import argparse
-
-import classpaths_pb2
-
-import google.protobuf.json_format as json_format
-import google.protobuf.text_format as text_format
-
-
-def encode(args):
- pb = classpaths_pb2.ExportedClasspathsJars()
- if args.format == 'json':
- json_format.Parse(args.input.read(), pb)
- else:
- text_format.Parse(args.input.read(), pb)
- args.output.write(pb.SerializeToString())
- args.input.close()
- args.output.close()
-
-
-def decode(args):
- pb = classpaths_pb2.ExportedClasspathsJars()
- pb.ParseFromString(args.input.read())
- if args.format == 'json':
- args.output.write(json_format.MessageToJson(pb))
- else:
- args.output.write(text_format.MessageToString(pb).encode('utf_8'))
- args.input.close()
- args.output.close()
-
-
-def main():
- parser = argparse.ArgumentParser('Convert classpaths.proto messages between binary and '
- 'human-readable formats.')
- parser.add_argument('-f', '--format', default='textproto',
- help='human-readable format, either json or text(proto), '
- 'defaults to textproto')
- parser.add_argument('-i', '--input',
- nargs='?', type=argparse.FileType('rb'), default=sys.stdin.buffer)
- parser.add_argument('-o', '--output',
- nargs='?', type=argparse.FileType('wb'),
- default=sys.stdout.buffer)
-
- subparsers = parser.add_subparsers()
-
- parser_encode = subparsers.add_parser('encode',
- help='convert classpaths protobuf message from '
- 'JSON to binary format',
- parents=[parser], add_help=False)
-
- parser_encode.set_defaults(func=encode)
-
- parser_decode = subparsers.add_parser('decode',
- help='print classpaths config in JSON format',
- parents=[parser], add_help=False)
- parser_decode.set_defaults(func=decode)
-
- args = parser.parse_args()
- args.func(args)
-
-
-if __name__ == '__main__':
- main()
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index af7e7fe..7472f52 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -47,3 +47,18 @@
},
},
}
+
+python_binary_host {
+ name: "verify_overlaps",
+ main: "verify_overlaps.py",
+ srcs: ["verify_overlaps.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+}
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
new file mode 100755
index 0000000..c8e3879
--- /dev/null
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+"""
+Verify that one set of hidden API flags is a subset of another.
+"""
+
+import argparse
+import csv
+
+args_parser = argparse.ArgumentParser(description='Verify that one set of hidden API flags is a subset of another.')
+args_parser.add_argument('all', help='All the flags')
+args_parser.add_argument('subsets', nargs=argparse.REMAINDER, help='Subsets of the flags')
+args = args_parser.parse_args()
+
+
+def dict_reader(input):
+ return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
+
+# Read in all the flags into a dict indexed by signature
+allFlagsBySignature = {}
+with open(args.all, 'r') as allFlagsFile:
+ allFlagsReader = dict_reader(allFlagsFile)
+ for row in allFlagsReader:
+ signature = row['signature']
+ allFlagsBySignature[signature]=row
+
+failed = False
+for subsetPath in args.subsets:
+ mismatchingSignatures = []
+ with open(subsetPath, 'r') as subsetFlagsFile:
+ subsetReader = dict_reader(subsetFlagsFile)
+ for row in subsetReader:
+ signature = row['signature']
+ if signature in allFlagsBySignature:
+ allFlags = allFlagsBySignature.get(signature)
+ if allFlags != row:
+ mismatchingSignatures.append((signature, row[None], allFlags[None]))
+ else:
+ mismatchingSignatures.append((signature, row[None], []))
+
+
+ if mismatchingSignatures:
+ failed = True
+ print("ERROR: Hidden API flags are inconsistent:")
+ print("< " + subsetPath)
+ print("> " + args.all)
+ for mismatch in mismatchingSignatures:
+ print()
+ print("< " + mismatch[0] + "," + ",".join(mismatch[1]))
+ if mismatch[2] != None:
+ print("> " + mismatch[0] + "," + ",".join(mismatch[2]))
+ else:
+ print("> " + mismatch[0] + " - missing")
+
+if failed:
+ sys.exit(1)
diff --git a/sdk/Android.bp b/sdk/Android.bp
index 09a7286..368c03a 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -26,6 +26,7 @@
"compat_config_sdk_test.go",
"exports_test.go",
"java_sdk_test.go",
+ "license_sdk_test.go",
"sdk_test.go",
"testing.go",
],
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index e91546e..d9fe281 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -165,21 +165,33 @@
prepareForSdkTestWithJava,
java.PrepareForTestWithJavaDefaultModules,
java.PrepareForTestWithJavaSdkLibraryFiles,
- java.FixtureWithLastReleaseApis("mysdklibrary", "mycoreplatform"),
+ java.FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
android.FixtureWithRootAndroidBp(`
sdk {
name: "mysdk",
bootclasspath_fragments: ["mybootclasspathfragment"],
- java_sdk_libs: ["mysdklibrary", "mycoreplatform"],
+ java_sdk_libs: [
+ // This is not strictly needed as it should be automatically added to the sdk_snapshot as
+ // a java_sdk_libs module because it is used in the mybootclasspathfragment's
+ // api.stub_libs property. However, it is specified here to ensure that duplicates are
+ // correctly deduped.
+ "mysdklibrary",
+ ],
}
bootclasspath_fragment {
name: "mybootclasspathfragment",
- contents: ["mybootlib"],
+ contents: [
+ // This should be automatically added to the sdk_snapshot as a java_boot_libs module.
+ "mybootlib",
+ // This should be automatically added to the sdk_snapshot as a java_sdk_libs module.
+ "myothersdklibrary",
+ ],
api: {
stub_libs: ["mysdklibrary"],
},
core_platform_api: {
+ // This should be automatically added to the sdk_snapshot as a java_sdk_libs module.
stub_libs: ["mycoreplatform"],
},
}
@@ -195,14 +207,21 @@
java_sdk_library {
name: "mysdklibrary",
srcs: ["Test.java"],
- compile_dex: true,
+ shared_library: false,
+ public: {enabled: true},
+ }
+
+ java_sdk_library {
+ name: "myothersdklibrary",
+ srcs: ["Test.java"],
+ shared_library: false,
public: {enabled: true},
}
java_sdk_library {
name: "mycoreplatform",
srcs: ["Test.java"],
- compile_dex: true,
+ shared_library: false,
public: {enabled: true},
}
`),
@@ -217,13 +236,23 @@
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
- contents: ["mybootlib"],
+ contents: [
+ "mybootlib",
+ "myothersdklibrary",
+ ],
api: {
stub_libs: ["mysdklibrary"],
},
core_platform_api: {
stub_libs: ["mycoreplatform"],
},
+ hidden_api: {
+ stub_flags: "hiddenapi/stub-flags.csv",
+ annotation_flags: "hiddenapi/annotation-flags.csv",
+ metadata: "hiddenapi/metadata.csv",
+ index: "hiddenapi/index.csv",
+ all_flags: "hiddenapi/all-flags.csv",
+ },
}
java_import {
@@ -235,12 +264,26 @@
}
java_sdk_library_import {
+ name: "myothersdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ shared_library: false,
+ public: {
+ jars: ["sdk_library/public/myothersdklibrary-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myothersdklibrary_stub_sources"],
+ current_api: "sdk_library/public/myothersdklibrary.txt",
+ removed_api: "sdk_library/public/myothersdklibrary-removed.txt",
+ sdk_version: "current",
+ },
+}
+
+java_sdk_library_import {
name: "mysdklibrary",
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
- shared_library: true,
- compile_dex: true,
+ shared_library: false,
public: {
jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
@@ -255,8 +298,7 @@
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
- shared_library: true,
- compile_dex: true,
+ shared_library: false,
public: {
jars: ["sdk_library/public/mycoreplatform-stubs.jar"],
stub_srcs: ["sdk_library/public/mycoreplatform_stub_sources"],
@@ -265,7 +307,7 @@
sdk_version: "current",
},
}
-`),
+ `),
checkVersionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -274,13 +316,23 @@
sdk_member_name: "mybootclasspathfragment",
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
- contents: ["mysdk_mybootlib@current"],
+ contents: [
+ "mysdk_mybootlib@current",
+ "mysdk_myothersdklibrary@current",
+ ],
api: {
stub_libs: ["mysdk_mysdklibrary@current"],
},
core_platform_api: {
stub_libs: ["mysdk_mycoreplatform@current"],
},
+ hidden_api: {
+ stub_flags: "hiddenapi/stub-flags.csv",
+ annotation_flags: "hiddenapi/annotation-flags.csv",
+ metadata: "hiddenapi/metadata.csv",
+ index: "hiddenapi/index.csv",
+ all_flags: "hiddenapi/all-flags.csv",
+ },
}
java_import {
@@ -292,12 +344,26 @@
}
java_sdk_library_import {
+ name: "mysdk_myothersdklibrary@current",
+ sdk_member_name: "myothersdklibrary",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ shared_library: false,
+ public: {
+ jars: ["sdk_library/public/myothersdklibrary-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myothersdklibrary_stub_sources"],
+ current_api: "sdk_library/public/myothersdklibrary.txt",
+ removed_api: "sdk_library/public/myothersdklibrary-removed.txt",
+ sdk_version: "current",
+ },
+}
+
+java_sdk_library_import {
name: "mysdk_mysdklibrary@current",
sdk_member_name: "mysdklibrary",
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
- shared_library: true,
- compile_dex: true,
+ shared_library: false,
public: {
jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
@@ -312,8 +378,7 @@
sdk_member_name: "mycoreplatform",
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
- shared_library: true,
- compile_dex: true,
+ shared_library: false,
public: {
jars: ["sdk_library/public/mycoreplatform-stubs.jar"],
stub_srcs: ["sdk_library/public/mycoreplatform_stub_sources"],
@@ -329,13 +394,22 @@
bootclasspath_fragments: ["mysdk_mybootclasspathfragment@current"],
java_boot_libs: ["mysdk_mybootlib@current"],
java_sdk_libs: [
+ "mysdk_myothersdklibrary@current",
"mysdk_mysdklibrary@current",
"mysdk_mycoreplatform@current",
],
}
-`),
+ `),
checkAllCopyRules(`
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
@@ -350,6 +424,7 @@
android.GroupFixturePreparers(
prepareForSdkTestWithApex,
prepareForSdkTestWithJava,
+ android.FixtureAddFile("java/mybootlib.jar", nil),
android.FixtureWithRootAndroidBp(`
sdk {
name: "mysdk",
@@ -359,16 +434,27 @@
bootclasspath_fragment {
name: "mybootclasspathfragment",
image_name: "art",
+ contents: ["mybootlib"],
apex_available: ["myapex"],
}
+ java_library {
+ name: "mybootlib",
+ apex_available: ["myapex"],
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ min_sdk_version: "1",
+ compile_dex: true,
+ }
+
sdk_snapshot {
name: "mysdk@1",
- bootclasspath_fragments: ["mybootclasspathfragment_mysdk_1"],
+ bootclasspath_fragments: ["mysdk_mybootclasspathfragment@1"],
}
prebuilt_bootclasspath_fragment {
- name: "mybootclasspathfragment_mysdk_1",
+ name: "mysdk_mybootclasspathfragment@1",
sdk_member_name: "mybootclasspathfragment",
prefer: false,
visibility: ["//visibility:public"],
@@ -376,6 +462,15 @@
"myapex",
],
image_name: "art",
+ contents: ["mysdk_mybootlib@1"],
+ }
+
+ java_import {
+ name: "mysdk_mybootlib@1",
+ sdk_member_name: "mybootlib",
+ visibility: ["//visibility:public"],
+ apex_available: ["com.android.art"],
+ jars: ["java/mybootlib.jar"],
}
`),
).RunTest(t)
@@ -384,6 +479,10 @@
func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForSdkTestWithJava,
+ java.PrepareForTestWithJavaDefaultModules,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("mysdklibrary"),
+ prepareForSdkTestWithApex,
android.MockFS{
"my-blocked.txt": nil,
"my-max-target-o-low-priority.txt": nil,
@@ -400,9 +499,20 @@
bootclasspath_fragments: ["mybootclasspathfragment"],
}
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ min_sdk_version: "1",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ }
+
bootclasspath_fragment {
name: "mybootclasspathfragment",
+ apex_available: ["myapex"],
contents: ["mybootlib"],
+ api: {
+ stub_libs: ["mysdklibrary"],
+ },
hidden_api: {
unsupported: [
"my-unsupported.txt",
@@ -433,11 +543,20 @@
java_library {
name: "mybootlib",
+ apex_available: ["myapex"],
srcs: ["Test.java"],
system_modules: "none",
sdk_version: "none",
+ min_sdk_version: "1",
compile_dex: true,
}
+
+ java_sdk_library {
+ name: "mysdklibrary",
+ srcs: ["Test.java"],
+ compile_dex: true,
+ public: {enabled: true},
+ }
`),
).RunTest(t)
@@ -449,8 +568,11 @@
name: "mybootclasspathfragment",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
contents: ["mybootlib"],
+ api: {
+ stub_libs: ["mysdklibrary"],
+ },
hidden_api: {
unsupported: ["hiddenapi/my-unsupported.txt"],
removed: ["hiddenapi/my-removed.txt"],
@@ -460,6 +582,11 @@
max_target_o_low_priority: ["hiddenapi/my-max-target-o-low-priority.txt"],
blocked: ["hiddenapi/my-blocked.txt"],
unsupported_packages: ["hiddenapi/my-unsupported-packages.txt"],
+ stub_flags: "hiddenapi/stub-flags.csv",
+ annotation_flags: "hiddenapi/annotation-flags.csv",
+ metadata: "hiddenapi/metadata.csv",
+ index: "hiddenapi/index.csv",
+ all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -467,9 +594,25 @@
name: "mybootlib",
prefer: false,
visibility: ["//visibility:public"],
- apex_available: ["//apex_available:platform"],
+ apex_available: ["myapex"],
jars: ["java/mybootlib.jar"],
}
+
+java_sdk_library_import {
+ name: "mysdklibrary",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ shared_library: true,
+ compile_dex: true,
+ public: {
+ jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+ stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+ current_api: "sdk_library/public/mysdklibrary.txt",
+ removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+ sdk_version: "current",
+ },
+}
`),
checkAllCopyRules(`
my-unsupported.txt -> hiddenapi/my-unsupported.txt
@@ -480,7 +623,15 @@
my-max-target-o-low-priority.txt -> hiddenapi/my-max-target-o-low-priority.txt
my-blocked.txt -> hiddenapi/my-blocked.txt
my-unsupported-packages.txt -> hiddenapi/my-unsupported-packages.txt
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
.intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
`),
)
}
diff --git a/sdk/bp.go b/sdk/bp.go
index 11ec8c6..e2dace8 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -25,6 +25,7 @@
type bpPropertySet struct {
properties map[string]interface{}
tags map[string]android.BpPropertyTag
+ comments map[string]string
order []string
}
@@ -133,10 +134,22 @@
return s.properties[name]
}
+func (s *bpPropertySet) getOptionalValue(name string) (interface{}, bool) {
+ value, ok := s.properties[name]
+ return value, ok
+}
+
func (s *bpPropertySet) getTag(name string) interface{} {
return s.tags[name]
}
+func (s *bpPropertySet) AddCommentForProperty(name, text string) {
+ if s.comments == nil {
+ s.comments = map[string]string{}
+ }
+ s.comments[name] = strings.TrimSpace(text)
+}
+
func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
var newOrder []string
for _, name := range s.order {
@@ -188,6 +201,12 @@
}
}
+func (s *bpPropertySet) removeProperty(name string) {
+ delete(s.properties, name)
+ delete(s.tags, name)
+ _, s.order = android.RemoveFromList(name, s.order)
+}
+
func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
if s.properties[name] != nil {
panic("Property %q already exists in property set")
@@ -216,6 +235,19 @@
moduleType string
}
+func (m *bpModule) ModuleType() string {
+ return m.moduleType
+}
+
+func (m *bpModule) Name() string {
+ name, hasName := m.getOptionalValue("name")
+ if hasName {
+ return name.(string)
+ } else {
+ return ""
+ }
+}
+
var _ android.BpModule = (*bpModule)(nil)
type bpPropertyTransformer interface {
@@ -346,16 +378,26 @@
// is unique within this file.
func (f *bpFile) AddModule(module android.BpModule) {
m := module.(*bpModule)
- if name, ok := m.getValue("name").(string); ok {
- if f.modules[name] != nil {
- panic(fmt.Sprintf("Module %q already exists in bp file", name))
- }
-
- f.modules[name] = m
- f.order = append(f.order, m)
- } else {
- panic("Module does not have a name property, or it is not a string")
+ moduleType := module.ModuleType()
+ name := m.Name()
+ hasName := true
+ if name == "" {
+ // Use a prefixed module type as the name instead just in case this is something like a package
+ // of namespace module which does not require a name.
+ name = "#" + moduleType
+ hasName = false
}
+
+ if f.modules[name] != nil {
+ if hasName {
+ panic(fmt.Sprintf("Module %q already exists in bp file", name))
+ } else {
+ panic(fmt.Sprintf("Unnamed module type %q already exists in bp file", moduleType))
+ }
+ }
+
+ f.modules[name] = m
+ f.order = append(f.order, m)
}
func (f *bpFile) newModule(moduleType string) *bpModule {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index dc58d93..6f769a3 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1089,6 +1089,57 @@
)
}
+func TestSnapshotWithJavaSdkLibrary_UseSrcJar(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForSdkTestWithJavaSdkLibrary,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_USE_SRCJAR": "true",
+ }),
+ ).RunTestWithBp(t, `
+ sdk {
+ name: "mysdk",
+ java_sdk_libs: ["myjavalib"],
+ }
+
+ java_sdk_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ sdk_version: "current",
+ shared_library: false,
+ public: {
+ enabled: true,
+ },
+ }
+ `)
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ shared_library: false,
+ public: {
+ jars: ["sdk_library/public/myjavalib-stubs.jar"],
+ stub_srcs: ["sdk_library/public/myjavalib.srcjar"],
+ current_api: "sdk_library/public/myjavalib.txt",
+ removed_api: "sdk_library/public/myjavalib-removed.txt",
+ sdk_version: "current",
+ },
+}
+ `),
+ checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source-stubs.srcjar -> sdk_library/public/myjavalib.srcjar
+.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+ `),
+ )
+}
+
func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) {
result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
sdk {
diff --git a/sdk/license_sdk_test.go b/sdk/license_sdk_test.go
new file mode 100644
index 0000000..1ef6fe6
--- /dev/null
+++ b/sdk/license_sdk_test.go
@@ -0,0 +1,138 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 sdk
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestSnapshotWithPackageDefaultLicense(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForSdkTestWithJava,
+ android.PrepareForTestWithLicenses,
+ android.PrepareForTestWithLicenseDefaultModules,
+ android.MockFS{
+ "NOTICE1": nil,
+ "NOTICE2": nil,
+ }.AddToFixture(),
+ ).RunTestWithBp(t, `
+ package {
+ default_applicable_licenses: ["mylicense"],
+ }
+
+ license {
+ name: "mylicense",
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "NOTICE1",
+ "NOTICE2",
+ ],
+ }
+
+ sdk {
+ name: "mysdk",
+ java_header_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+ `)
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+package {
+ // A default list here prevents the license LSC from adding its own list which would
+ // be unnecessary as every module in the sdk already has its own licenses property.
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ licenses: ["mysdk_mylicense"],
+ jars: ["java/myjavalib.jar"],
+}
+
+license {
+ name: "mysdk_mylicense",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "licenses/NOTICE1",
+ "licenses/NOTICE2",
+ ],
+}
+ `),
+ checkVersionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+package {
+ // A default list here prevents the license LSC from adding its own list which would
+ // be unnecessary as every module in the sdk already has its own licenses property.
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ licenses: ["mysdk_mylicense@current"],
+ jars: ["java/myjavalib.jar"],
+}
+
+license {
+ name: "mysdk_mylicense@current",
+ sdk_member_name: "mylicense",
+ visibility: ["//visibility:private"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "licenses/NOTICE1",
+ "licenses/NOTICE2",
+ ],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ visibility: ["//visibility:public"],
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+ `),
+ checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/myjavalib.jar
+NOTICE1 -> licenses/NOTICE1
+NOTICE2 -> licenses/NOTICE2
+`),
+ )
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 624c0fa..b1c8aeb 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -169,23 +169,27 @@
var fields []reflect.StructField
// Iterate over the member types creating StructField and sdkMemberListProperty objects.
- for f, memberType := range sdkMemberTypes {
+ nextFieldIndex := 0
+ for _, memberType := range sdkMemberTypes {
+
p := memberType.SdkPropertyName()
- // Create a dynamic exported field for the member type's property.
- fields = append(fields, reflect.StructField{
- Name: proptools.FieldNameForProperty(p),
- Type: reflect.TypeOf([]string{}),
- Tag: `android:"arch_variant"`,
- })
+ var getter func(properties interface{}) []string
+ var setter func(properties interface{}, list []string)
+ if memberType.RequiresBpProperty() {
+ // Create a dynamic exported field for the member type's property.
+ fields = append(fields, reflect.StructField{
+ Name: proptools.FieldNameForProperty(p),
+ Type: reflect.TypeOf([]string{}),
+ Tag: `android:"arch_variant"`,
+ })
- // Copy the field index for use in the getter func as using the loop variable directly will
- // cause all funcs to use the last value.
- fieldIndex := f
+ // Copy the field index for use in the getter func as using the loop variable directly will
+ // cause all funcs to use the last value.
+ fieldIndex := nextFieldIndex
+ nextFieldIndex += 1
- // Create an sdkMemberListProperty for the member type.
- memberListProperty := &sdkMemberListProperty{
- getter: func(properties interface{}) []string {
+ getter = func(properties interface{}) []string {
// The properties is expected to be of the following form (where
// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
// properties *struct {<Module_types> []string, ....}
@@ -195,9 +199,9 @@
//
list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
return list
- },
+ }
- setter: func(properties interface{}, list []string) {
+ setter = func(properties interface{}, list []string) {
// The properties is expected to be of the following form (where
// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
// properties *struct {<Module_types> []string, ....}
@@ -206,8 +210,13 @@
// *properties.<Module_types> = list
//
reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list))
- },
+ }
+ }
+ // Create an sdkMemberListProperty for the member type.
+ memberListProperty := &sdkMemberListProperty{
+ getter: getter,
+ setter: setter,
memberType: memberType,
// Dependencies added directly from member properties are always exported.
@@ -402,6 +411,9 @@
// Add dependencies from enabled and non CommonOS variants to the sdk member variants.
if s.Enabled() && !s.IsCommonOSVariant() {
for _, memberListProperty := range s.memberListProperties() {
+ if memberListProperty.getter == nil {
+ continue
+ }
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
if len(names) > 0 {
tag := memberListProperty.dependencyTag
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 12545d6..a13b0d7 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -564,4 +564,101 @@
`),
)
})
+
+ t.Run("SOONG_SDK_SNAPSHOT_VERSION=unversioned", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_VERSION": "unversioned",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+ `),
+ )
+ })
+
+ t.Run("SOONG_SDK_SNAPSHOT_VERSION=current", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_VERSION": "current",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ visibility: ["//visibility:public"],
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+ `),
+ )
+ })
+
+ t.Run("SOONG_SDK_SNAPSHOT_VERSION=2", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_VERSION": "2",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-2.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@2",
+ sdk_member_name: "myjavalib",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@2",
+ visibility: ["//visibility:public"],
+ java_header_libs: ["mysdk_myjavalib@2"],
+}
+ `),
+ // A versioned snapshot cannot be used on its own so add the source back in.
+ snapshotTestPreparer(checkSnapshotWithoutSource, android.FixtureWithRootAndroidBp(bp)),
+ )
+ })
}
diff --git a/sdk/testing.go b/sdk/testing.go
index f4e85c0..3254cf9 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -131,6 +131,7 @@
info := &snapshotBuildInfo{
t: t,
r: result,
+ version: sdk.builderForTests.version,
androidBpContents: sdk.GetAndroidBpContentsForTests(),
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
@@ -236,8 +237,13 @@
if dir != "" {
dir = filepath.Clean(dir) + "/"
}
- android.AssertStringEquals(t, "Snapshot zip file in wrong place",
- fmt.Sprintf(".intermediates/%s%s/%s/%s-current.zip", dir, name, variant, name), actual)
+ suffix := ""
+ if snapshotBuildInfo.version != soongSdkSnapshotVersionUnversioned {
+ suffix = "-" + snapshotBuildInfo.version
+ }
+
+ expectedZipPath := fmt.Sprintf(".intermediates/%s%s/%s/%s%s.zip", dir, name, variant, name, suffix)
+ android.AssertStringEquals(t, "Snapshot zip file in wrong place", expectedZipPath, actual)
// Populate a mock filesystem with the files that would have been copied by
// the rules.
@@ -432,6 +438,11 @@
// The result from RunTest()
r *android.TestResult
+ // The version of the generated snapshot.
+ //
+ // See snapshotBuilder.version for more information about this field.
+ version string
+
// The contents of the generated Android.bp file
androidBpContents string
diff --git a/sdk/update.go b/sdk/update.go
index 853f6b0..36b564f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -36,6 +36,20 @@
// By default every unversioned module in the generated snapshot has prefer: false. Building it
// with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
//
+// SOONG_SDK_SNAPSHOT_VERSION
+// This provides control over the version of the generated snapshot.
+//
+// SOONG_SDK_SNAPSHOT_VERSION=current will generate unversioned and versioned prebuilts and a
+// versioned snapshot module. This is the default behavior. The zip file containing the
+// generated snapshot will be <sdk-name>-current.zip.
+//
+// SOONG_SDK_SNAPSHOT_VERSION=unversioned will generate unversioned prebuilts only and the zip
+// file containing the generated snapshot will be <sdk-name>.zip.
+//
+// SOONG_SDK_SNAPSHOT_VERSION=<number> will generate versioned prebuilts and a versioned
+// snapshot module only. The zip file containing the generated snapshot will be
+// <sdk-name>-<number>.zip.
+//
var pctx = android.NewPackageContext("android/soong/sdk")
@@ -69,6 +83,11 @@
})
)
+const (
+ soongSdkSnapshotVersionUnversioned = "unversioned"
+ soongSdkSnapshotVersionCurrent = "current"
+)
+
type generatedContents struct {
content strings.Builder
indentLevel int
@@ -228,6 +247,7 @@
allMembersByName := make(map[string]struct{})
exportedMembersByName := make(map[string]struct{})
+ hasLicenses := false
var memberVariantDeps []sdkMemberVariantDep
for _, sdkVariant := range sdkVariants {
memberVariantDeps = append(memberVariantDeps, sdkVariant.memberVariantDeps...)
@@ -241,6 +261,10 @@
if memberVariantDep.export {
exportedMembersByName[name] = struct{}{}
}
+
+ if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
+ hasLicenses = true
+ }
}
}
@@ -252,10 +276,26 @@
modules: make(map[string]*bpModule),
}
+ config := ctx.Config()
+ version := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_VERSION", "current")
+
+ // Generate versioned modules in the snapshot unless an unversioned snapshot has been requested.
+ generateVersioned := version != soongSdkSnapshotVersionUnversioned
+
+ // Generate unversioned modules in the snapshot unless a numbered snapshot has been requested.
+ //
+ // Unversioned modules are not required in that case because the numbered version will be a
+ // finalized version of the snapshot that is intended to be kept separate from the
+ generateUnversioned := version == soongSdkSnapshotVersionUnversioned || version == soongSdkSnapshotVersionCurrent
+ snapshotZipFileSuffix := ""
+ if generateVersioned {
+ snapshotZipFileSuffix = "-" + version
+ }
+
builder := &snapshotBuilder{
ctx: ctx,
sdk: s,
- version: "current",
+ version: version,
snapshotDir: snapshotDir.OutputPath,
copies: make(map[string]string),
filesToZip: []android.Path{bp.path},
@@ -266,8 +306,27 @@
}
s.builderForTests = builder
- // Create the prebuilt modules for each of the member modules.
+ // If the sdk snapshot includes any license modules then add a package module which has a
+ // default_applicable_licenses property. That will prevent the LSC license process from updating
+ // the generated Android.bp file to add a package module that includes all licenses used by all
+ // the modules in that package. That would be unnecessary as every module in the sdk should have
+ // their own licenses property specified.
+ if hasLicenses {
+ pkg := bpFile.newModule("package")
+ property := "default_applicable_licenses"
+ pkg.AddCommentForProperty(property, `
+A default list here prevents the license LSC from adding its own list which would
+be unnecessary as every module in the sdk already has its own licenses property.
+`)
+ pkg.AddProperty(property, []string{"Android-Apache-2.0"})
+ bpFile.AddModule(pkg)
+ }
+
+ // Group the variants for each member module together and then group the members of each member
+ // type together.
members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
+
+ // Create the prebuilt modules for each of the member modules.
for _, member := range members {
memberType := member.memberType
@@ -284,31 +343,32 @@
// to internal members with a unique module name and setting prefer: false.
unversionedTransformer := unversionedTransformation{
builder: builder,
- // Set the prefer based on the environment variable. This is a temporary work around to allow a
- // snapshot to be created that sets prefer: true.
- // TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
- // dynamically at build time not at snapshot generation time.
- prefer: ctx.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER"),
}
for _, unversioned := range builder.prebuiltOrder {
// Prune any empty property sets.
unversioned = unversioned.transform(pruneEmptySetTransformer{})
- // Copy the unversioned module so it can be modified to make it versioned.
- versioned := unversioned.deepCopy()
+ if generateVersioned {
+ // Copy the unversioned module so it can be modified to make it versioned.
+ versioned := unversioned.deepCopy()
- // Transform the unversioned module into a versioned one.
- versioned.transform(unversionedToVersionedTransformer)
- bpFile.AddModule(versioned)
+ // Transform the unversioned module into a versioned one.
+ versioned.transform(unversionedToVersionedTransformer)
+ bpFile.AddModule(versioned)
+ }
- // Transform the unversioned module to make it suitable for use in the snapshot.
- unversioned.transform(unversionedTransformer)
- bpFile.AddModule(unversioned)
+ if generateUnversioned {
+ // Transform the unversioned module to make it suitable for use in the snapshot.
+ unversioned.transform(unversionedTransformer)
+ bpFile.AddModule(unversioned)
+ }
}
- // Add the sdk/module_exports_snapshot module to the bp file.
- s.addSnapshotModule(ctx, builder, sdkVariants, memberVariantDeps)
+ if generateVersioned {
+ // Add the sdk/module_exports_snapshot module to the bp file.
+ s.addSnapshotModule(ctx, builder, sdkVariants, memberVariantDeps)
+ }
// generate Android.bp
bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
@@ -322,7 +382,8 @@
filesToZip := builder.filesToZip
// zip them all
- outputZipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
+ zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
outputDesc := "Building snapshot for " + ctx.ModuleName()
// If there are no zips to merge then generate the output zip directly.
@@ -334,7 +395,8 @@
zipFile = outputZipFile
desc = outputDesc
} else {
- zipFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.unmerged.zip").OutputPath
+ intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
desc = "Building intermediate snapshot for " + ctx.ModuleName()
}
@@ -518,15 +580,19 @@
}
combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
- memberTypeProperty := s.memberListProperty(memberVariantDep.memberType)
+ memberListProperty := s.memberListProperty(memberVariantDep.memberType)
memberName := ctx.OtherModuleName(memberVariantDep.variant)
+ if memberListProperty.getter == nil {
+ continue
+ }
+
// Append the member to the appropriate list, if it is not already present in the list.
- memberList := memberTypeProperty.getter(combined.dynamicProperties)
+ memberList := memberListProperty.getter(combined.dynamicProperties)
if !android.InList(memberName, memberList) {
memberList = append(memberList, memberName)
}
- memberTypeProperty.setter(combined.dynamicProperties, memberList)
+ memberListProperty.setter(combined.dynamicProperties, memberList)
}
return list
@@ -578,6 +644,9 @@
dynamicMemberTypeListProperties := combined.dynamicProperties
for _, memberListProperty := range s.memberListProperties() {
+ if memberListProperty.getter == nil {
+ continue
+ }
names := memberListProperty.getter(dynamicMemberTypeListProperties)
if len(names) > 0 {
propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
@@ -611,9 +680,11 @@
func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
// Use a versioned name for the module but remember the original name for the
// snapshot.
- name := module.getValue("name").(string)
+ name := module.Name()
module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
module.insertAfter("name", "sdk_member_name", name)
+ // Remove the prefer property if present as versioned modules never need marking with prefer.
+ module.removeProperty("prefer")
return module
}
@@ -629,20 +700,12 @@
type unversionedTransformation struct {
identityTransformation
builder *snapshotBuilder
- prefer bool
}
func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
// If the module is an internal member then use a unique name for it.
- name := module.getValue("name").(string)
+ name := module.Name()
module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
-
- // Set prefer. Setting this to false is not strictly required as that is the default but it does
- // provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to check
- // the behavior when a prebuilt is preferred. It also makes it explicit what the default behavior
- // is for the module.
- module.insertAfter("name", "prefer", t.prefer)
-
return module
}
@@ -693,12 +756,26 @@
func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
contents.Indent()
+ addComment := func(name string) {
+ if text, ok := set.comments[name]; ok {
+ for _, line := range strings.Split(text, "\n") {
+ contents.Printfln("// %s", line)
+ }
+ }
+ }
+
// Output the properties first, followed by the nested sets. This ensures a
// consistent output irrespective of whether property sets are created before
// or after the properties. This simplifies the creation of the module.
for _, name := range set.order {
value := set.getValue(name)
+ // Do not write property sets in the properties phase.
+ if _, ok := value.(*bpPropertySet); ok {
+ continue
+ }
+
+ addComment(name)
switch v := value.(type) {
case []string:
length := len(v)
@@ -719,9 +796,6 @@
case bool:
contents.Printfln("%s: %t,", name, v)
- case *bpPropertySet:
- // Do not write property sets in the properties phase.
-
default:
contents.Printfln("%s: %q,", name, value)
}
@@ -733,6 +807,7 @@
// Only write property sets in the sets phase.
switch v := value.(type) {
case *bpPropertySet:
+ addComment(name)
contents.Printfln("%s: {", name)
outputPropertySet(contents, v)
contents.Printfln("},")
@@ -751,7 +826,9 @@
func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
- return !strings.Contains(module.properties["name"].(string), "@")
+ name := module.Name()
+ // Include modules that are either unversioned or have no name.
+ return !strings.Contains(name, "@")
})
return contents.content.String()
}
@@ -759,15 +836,23 @@
func (s *sdk) GetVersionedAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
- return strings.Contains(module.properties["name"].(string), "@")
+ name := module.Name()
+ // Include modules that are either versioned or have no name.
+ return name == "" || strings.Contains(name, "@")
})
return contents.content.String()
}
type snapshotBuilder struct {
- ctx android.ModuleContext
- sdk *sdk
- version string
+ ctx android.ModuleContext
+ sdk *sdk
+
+ // The version of the generated snapshot.
+ //
+ // See the documentation of SOONG_SDK_SNAPSHOT_VERSION above for details of the valid values of
+ // this field.
+ version string
+
snapshotDir android.OutputPath
bpFile *bpFile
@@ -878,6 +963,13 @@
m.AddProperty("apex_available", apexAvailable)
}
+ // The licenses are the same for all variants.
+ mctx := s.ctx
+ licenseInfo := mctx.OtherModuleProvider(variant, android.LicenseInfoProvider).(android.LicenseInfo)
+ if len(licenseInfo.Licenses) > 0 {
+ m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag())
+ }
+
deviceSupported := false
hostSupported := false
@@ -905,6 +997,12 @@
}
func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) {
+ // If neither device or host is supported then this module does not support either so will not
+ // recognize the properties.
+ if !deviceSupported && !hostSupported {
+ return
+ }
+
if !deviceSupported {
bpModule.AddProperty("device_supported", false)
}
@@ -1381,6 +1479,21 @@
memberType := member.memberType
+ // Do not add the prefer property if the member snapshot module is a source module type.
+ if !memberType.UsesSourceModuleTypeInSnapshot() {
+ // Set the prefer based on the environment variable. This is a temporary work around to allow a
+ // snapshot to be created that sets prefer: true.
+ // TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
+ // dynamically at build time not at snapshot generation time.
+ prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
+
+ // Set prefer. Setting this to false is not strictly required as that is the default but it does
+ // provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
+ // check the behavior when a prebuilt is preferred. It also makes it explicit what the default
+ // behavior is for the module.
+ bpModule.insertAfter("name", "prefer", prefer)
+ }
+
// Group the variants by os type.
variantsByOsType := make(map[android.OsType][]android.Module)
variants := member.Variants()
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 42d5680..4805846 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -104,6 +104,12 @@
Recovery_available *bool
}
+// Test option struct.
+type TestOptions struct {
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
+}
+
type TestProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
@@ -143,6 +149,9 @@
// list of device library modules that should be installed alongside the test.
// Only available for host sh_test modules.
Data_device_libs []string `android:"path,arch_variant"`
+
+ // Test options.
+ Test_options TestOptions
}
type ShBinary struct {
@@ -440,6 +449,9 @@
dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
}
+ if Bool(s.testProperties.Test_options.Unit_test) {
+ entries.SetBool("LOCAL_IS_UNIT_TEST", true)
+ }
},
},
}}
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 9e7e594..20317d8 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -3,6 +3,7 @@
import (
"os"
"path/filepath"
+ "strconv"
"testing"
"android/soong/android"
@@ -148,6 +149,9 @@
"testdata/data1",
"testdata/sub/data2",
],
+ test_options: {
+ unit_test: true,
+ },
}
`)
@@ -156,6 +160,9 @@
if !mod.Host() {
t.Errorf("host bit is not set for a sh_test_host module.")
}
+ entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ actualData, _ := strconv.ParseBool(entries.EntryMap["LOCAL_IS_UNIT_TEST"][0])
+ android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData)
}
func TestShTestHost_dataDeviceModules(t *testing.T) {
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 3f51114..8c8dc82 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -7,6 +7,8 @@
source "$(dirname "$0")/lib.sh"
+readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
+
function test_smoke {
setup
run_soong
@@ -491,6 +493,21 @@
[[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
}
+function test_bp2build_generates_fake_ninja_file {
+ setup
+ create_mock_bazel
+
+ run_bp2build
+
+ if [[ ! -f "./out/soong/build.ninja" ]]; then
+ fail "./out/soong/build.ninja was not generated"
+ fi
+
+ if ! grep "build nothing: phony" "./out/soong/build.ninja"; then
+ fail "missing phony nothing target in out/soong/build.ninja"
+ fi
+}
+
function test_bp2build_add_android_bp {
setup
@@ -505,8 +522,8 @@
EOF
GENERATE_BAZEL_FILES=1 run_soong
- [[ -e out/soong/bp2build/a/BUILD ]] || fail "a/BUILD not created"
- [[ -L out/soong/workspace/a/BUILD ]] || fail "a/BUILD not symlinked"
+ [[ -e out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
+ [[ -L out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
mkdir -p b
touch b/b.txt
@@ -519,8 +536,8 @@
EOF
GENERATE_BAZEL_FILES=1 run_soong
- [[ -e out/soong/bp2build/b/BUILD ]] || fail "a/BUILD not created"
- [[ -L out/soong/workspace/b/BUILD ]] || fail "a/BUILD not symlinked"
+ [[ -e out/soong/bp2build/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
+ [[ -L out/soong/workspace/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
}
function test_bp2build_null_build {
@@ -551,11 +568,11 @@
EOF
GENERATE_BAZEL_FILES=1 run_soong
- grep -q a1.txt out/soong/bp2build/a/BUILD || fail "a1.txt not in BUILD file"
+ grep -q a1.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a1.txt not in ${GENERATED_BUILD_FILE_NAME} file"
touch a/a2.txt
GENERATE_BAZEL_FILES=1 run_soong
- grep -q a2.txt out/soong/bp2build/a/BUILD || fail "a2.txt not in BUILD file"
+ grep -q a2.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a2.txt not in ${GENERATED_BUILD_FILE_NAME} file"
}
function test_dump_json_module_graph() {
@@ -583,8 +600,8 @@
GENERATE_BAZEL_FILES=1 run_soong
[[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
[[ -d out/soong/workspace/a/b ]] || fail "module directory not a directory"
- [[ -L out/soong/workspace/a/b/BUILD ]] || fail "BUILD file not symlinked"
- [[ "$(readlink -f out/soong/workspace/a/b/BUILD)" =~ bp2build/a/b/BUILD$ ]] \
+ [[ -L "out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
+ [[ "$(readlink -f out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/b/${GENERATED_BUILD_FILE_NAME}"$ ]] \
|| fail "BUILD files symlinked at the wrong place"
[[ -L out/soong/workspace/a/b/b.txt ]] || fail "a/b/b.txt not symlinked"
[[ -L out/soong/workspace/a/a.txt ]] || fail "a/b/a.txt not symlinked"
@@ -616,7 +633,7 @@
mkdir -p a
touch a/a.txt
- touch a/BUILD
+ touch a/${GENERATED_BUILD_FILE_NAME}
cat > a/Android.bp <<EOF
filegroup {
name: "a",
@@ -626,15 +643,15 @@
EOF
GENERATE_BAZEL_FILES=1 run_soong
- [[ -L out/soong/workspace/a/BUILD ]] || fail "BUILD file not symlinked"
- [[ "$(readlink -f out/soong/workspace/a/BUILD)" =~ bp2build/a/BUILD$ ]] \
- || fail "BUILD files symlinked to the wrong place"
+ [[ -L "out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
+ [[ "$(readlink -f out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/${GENERATED_BUILD_FILE_NAME}"$ ]] \
+ || fail "${GENERATED_BUILD_FILE_NAME} files symlinked to the wrong place"
}
function test_bp2build_reports_multiple_errors {
setup
- mkdir -p a/BUILD
+ mkdir -p "a/${GENERATED_BUILD_FILE_NAME}"
touch a/a.txt
cat > a/Android.bp <<EOF
filegroup {
@@ -644,7 +661,7 @@
}
EOF
- mkdir -p b/BUILD
+ mkdir -p "b/${GENERATED_BUILD_FILE_NAME}"
touch b/b.txt
cat > b/Android.bp <<EOF
filegroup {
@@ -658,8 +675,8 @@
fail "Build should have failed"
fi
- grep -q "a/BUILD' exist" "$MOCK_TOP/errors" || fail "Error for a/BUILD not found"
- grep -q "b/BUILD' exist" "$MOCK_TOP/errors" || fail "Error for b/BUILD not found"
+ grep -q "a/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for a/${GENERATED_BUILD_FILE_NAME} not found"
+ grep -q "b/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for b/${GENERATED_BUILD_FILE_NAME} not found"
}
test_smoke
@@ -676,6 +693,7 @@
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
test_bp2build_smoke
+test_bp2build_generates_fake_ninja_file
test_bp2build_null_build
test_bp2build_add_android_bp
test_bp2build_add_to_glob
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 082cd06..e357710 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -6,6 +6,8 @@
source "$(dirname "$0")/lib.sh"
+readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
+
function test_bp2build_generates_all_buildfiles {
setup
create_mock_bazel
@@ -40,24 +42,24 @@
run_bp2build
- if [[ ! -f "./out/soong/workspace/foo/convertible_soong_module/BUILD" ]]; then
- fail "./out/soong/workspace/foo/convertible_soong_module/BUILD was not generated"
+ if [[ ! -f "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME}" ]]; then
+ fail "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME} was not generated"
fi
- if [[ ! -f "./out/soong/workspace/foo/unconvertible_soong_module/BUILD" ]]; then
- fail "./out/soong/workspace/foo/unconvertible_soong_module/BUILD was not generated"
+ if [[ ! -f "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}" ]]; then
+ fail "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME} was not generated"
fi
- if ! grep "the_answer" "./out/soong/workspace/foo/convertible_soong_module/BUILD"; then
- fail "missing BUILD target the_answer in convertible_soong_module/BUILD"
+ if ! grep "the_answer" "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
+ fail "missing BUILD target the_answer in convertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
fi
- if grep "not_the_answer" "./out/soong/workspace/foo/unconvertible_soong_module/BUILD"; then
- fail "found unexpected BUILD target not_the_answer in unconvertible_soong_module/BUILD"
+ if grep "not_the_answer" "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
+ fail "found unexpected BUILD target not_the_answer in unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
fi
- if ! grep "filegroup" "./out/soong/workspace/foo/unconvertible_soong_module/BUILD"; then
- fail "missing filegroup in unconvertible_soong_module/BUILD"
+ if ! grep "filegroup" "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
+ fail "missing filegroup in unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
fi
# NOTE: We don't actually use the extra BUILD file for anything here
diff --git a/tests/lib.sh b/tests/lib.sh
index e561a3d..35ccea9 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -114,6 +114,7 @@
symlink_directory prebuilts/jdk
symlink_file WORKSPACE
+ symlink_file BUILD
symlink_file tools/bazel
}
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go
index 9932c1b..46588d4 100644
--- a/third_party/zip/android_test.go
+++ b/third_party/zip/android_test.go
@@ -140,3 +140,83 @@
t.Errorf("Expected UnompressedSize64 %d, got %d", w, g)
}
}
+
+// Test for b/187485108: zip64 output can't be read by p7zip 16.02.
+func TestZip64P7ZipRecords(t *testing.T) {
+ if testing.Short() {
+ t.Skip("slow test; skipping")
+ }
+
+ const size = uint32max + 1
+ zipBytes := &bytes.Buffer{}
+ zip := NewWriter(zipBytes)
+ f, err := zip.CreateHeaderAndroid(&FileHeader{
+ Name: "large",
+ Method: Store,
+ UncompressedSize64: size,
+ CompressedSize64: size,
+ })
+ if err != nil {
+ t.Fatalf("Create: %v", err)
+ }
+ _, err = f.Write(make([]byte, size))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ err = zip.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+
+ buf := zipBytes.Bytes()
+ p := findSignatureInBlock(buf)
+ if p < 0 {
+ t.Fatalf("Missing signature")
+ }
+
+ b := readBuf(buf[p+4:]) // skip signature
+ d := &directoryEnd{
+ diskNbr: uint32(b.uint16()),
+ dirDiskNbr: uint32(b.uint16()),
+ dirRecordsThisDisk: uint64(b.uint16()),
+ directoryRecords: uint64(b.uint16()),
+ directorySize: uint64(b.uint32()),
+ directoryOffset: uint64(b.uint32()),
+ commentLen: b.uint16(),
+ }
+
+ // p7zip 16.02 wants regular end record directoryRecords to be accurate.
+ if g, w := d.directoryRecords, uint64(1); g != w {
+ t.Errorf("wanted directoryRecords %d, got %d", w, g)
+ }
+
+ if g, w := d.directorySize, uint64(uint32max); g != w {
+ t.Errorf("wanted directorySize %d, got %d", w, g)
+ }
+
+ if g, w := d.directoryOffset, uint64(uint32max); g != w {
+ t.Errorf("wanted directoryOffset %d, got %d", w, g)
+ }
+
+ r := bytes.NewReader(buf)
+
+ p64, err := findDirectory64End(r, int64(p))
+ if err != nil {
+ t.Fatalf("findDirectory64End: %v", err)
+ }
+ if p < 0 {
+ t.Fatalf("findDirectory64End: not found")
+ }
+ err = readDirectory64End(r, p64, d)
+ if err != nil {
+ t.Fatalf("readDirectory64End: %v", err)
+ }
+
+ if g, w := d.directoryRecords, uint64(1); g != w {
+ t.Errorf("wanted directoryRecords %d, got %d", w, g)
+ }
+
+ if g, w := d.directoryOffset, uint64(uint32max); g <= w {
+ t.Errorf("wanted directoryOffset > %d, got %d", w, g)
+ }
+}
diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go
index 8dd986e..f526838 100644
--- a/third_party/zip/writer.go
+++ b/third_party/zip/writer.go
@@ -155,7 +155,14 @@
// store max values in the regular end record to signal that
// that the zip64 values should be used instead
- records = uint16max
+ // BEGIN ANDROID CHANGE: only store uintmax for the number of entries in the regular
+ // end record if it doesn't fit. p7zip 16.02 rejects zip files where the number of
+ // entries in the regular end record is larger than the number of entries counted
+ // in the central directory.
+ if records > uint16max {
+ records = uint16max
+ }
+ // END ANDROID CHANGE
size = uint32max
offset = uint32max
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 1d1f71f..3ebde0d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -72,6 +72,9 @@
// During Bazel execution, Bazel cannot write outside OUT_DIR.
// So if DIST_DIR is set to an external dir (outside of OUT_DIR), we need to rig it temporarily and then migrate files at the end of the build.
riggedDistDirForBazel string
+
+ // Set by multiproduct_kati
+ emptyNinjaFile bool
}
const srcDirFileCheck = "build/soong/root.bp"
@@ -203,9 +206,6 @@
"ANDROID_DEV_SCRIPTS",
"ANDROID_EMULATOR_PREBUILTS",
"ANDROID_PRE_BUILD_PATHS",
-
- // Only set in multiproduct_kati after config generation
- "EMPTY_NINJA_FILE",
)
if ret.UseGoma() || ret.ForceUseGoma() {
@@ -1189,3 +1189,11 @@
func (c *configImpl) BazelMetricsDir() string {
return filepath.Join(c.LogsDir(), "bazel_metrics")
}
+
+func (c *configImpl) SetEmptyNinjaFile(v bool) {
+ c.emptyNinjaFile = v
+}
+
+func (c *configImpl) EmptyNinjaFile() bool {
+ return c.emptyNinjaFile
+}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index fe0aca9..54aeda0 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -162,6 +162,8 @@
"OUT_DIR",
"AUX_OS_VARIANT_LIST",
"PRODUCT_SOONG_NAMESPACES",
+ "SOONG_SDK_SNAPSHOT_PREFER",
+ "SOONG_SDK_SNAPSHOT_VERSION",
}
func Banner(make_vars map[string]string) string {
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 2eb84ca..09d53cc 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -76,6 +76,8 @@
"Blueprints",
// Bazel build definitions.
"BUILD.bazel",
+ // Bazel build definitions.
+ "BUILD",
// Kati clean definitions.
"CleanSpec.mk",
// Ownership definition.
@@ -102,7 +104,7 @@
func findBazelFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
matches := []string{}
for _, foundName := range entries.FileNames {
- if foundName == "BUILD.bazel" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") {
+ if foundName == "BUILD.bazel" || foundName == "BUILD" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") {
matches = append(matches, foundName)
}
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 06ec646..dad68fa 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -136,7 +136,7 @@
// information out with --empty_ninja_file.
//
// From https://github.com/google/kati/commit/87b8da7af2c8bea28b1d8ab17679453d859f96e5
- if config.Environment().IsEnvTrue("EMPTY_NINJA_FILE") {
+ if config.EmptyNinjaFile() {
args = append(args, "--empty_ninja_file")
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a41dbe1..7128414 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -119,6 +119,7 @@
args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
args.GlobFile = globFile
args.GeneratingPrimaryBuilder = true
+ args.EmptyNinjaFile = config.EmptyNinjaFile()
args.DelveListen = os.Getenv("SOONG_DELVE")
if args.DelveListen != "" {
@@ -155,9 +156,9 @@
Outputs: []string{bp2BuildMarkerFile},
Args: bp2buildArgs,
}
- args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{
- bp2buildInvocation,
- mainSoongBuildInvocation,
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{bp2buildInvocation}
+ if config.bazelBuildMode() == mixedBuild {
+ args.PrimaryBuilderInvocations = append(args.PrimaryBuilderInvocations, mainSoongBuildInvocation)
}
} else {
args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation}
diff --git a/zip/zip.go b/zip/zip.go
index 84e974b..6e412c9 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -656,9 +656,11 @@
UncompressedSize64: uint64(fileSize),
}
+ mode := os.FileMode(0600)
if executable {
- header.SetMode(0700)
+ mode = 0700
}
+ header.SetMode(mode)
err = createParentDirs(dest, src)
if err != nil {
diff --git a/zip/zip_test.go b/zip/zip_test.go
index a37ae41..441dea3 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -62,7 +62,7 @@
Method: method,
CRC32: crc32.ChecksumIEEE(contents),
UncompressedSize64: uint64(len(contents)),
- ExternalAttrs: 0,
+ ExternalAttrs: (syscall.S_IFREG | 0600) << 16,
}
}